Setting a single motor to a set speed based on button press

Hello!
It is my first year as our lead programmer for team 4665 and we have just switched to command based programming (The new style). I currently have a driving robot based on x and y inputs using arcadeDrive. We have a sidedrive motor that needs to be toggled to go either a set speed forward or backwards based on a controller bumper input. My question is how would I go about setting the motor without using DifferentialDrive? Any help would be appreciated!

Stay warm,
Owen Peterson

Instead of invoking archadeDrive on the DifferentialDrive, you would invoke set(output) on the motor controller.

Tip: You’ll need to disable safety on the DifferentialDrive while you do this, but leave safety enabled on the motor controller.

When using DifferentialDrive it requires two motor inputs i.e left and right motor. Is there any way to use it with only a single motor?

Thanks for your response!

What exactly does the Differential Drive provide when used with a single motor that you want?

That doesn’t really make sense, why would you do that? It’s purpose is to drive a “tank drive”. If you only have one motor, you don’t have a tank drive.

What are you trying to do here?

I am attempting to turn a motor on based on a button press from my controller. We already have the tank drive part set up, its just that we have a separate motor that when turned on allows us to go left and right (Omni wheel setup). All I need to do is set that motor independent of the actual drivetrain.

In that case, don’t worry about DifferentialDrive at all. You will have a separate motor controller for that motor. It’s going to be something like this:

    // Left and right wheels with DifferentialDrive
    Spark left = new Spark(1);
    Spark right = new Spark(2);
    DifferentialDrive drive = new DifferentialDrive(m_left, m_right);
    drive.arcadeDrive(driverController.getY(Hand.kLeft), driverController.getX(Hand.kRight, true);

    // Side drive wheel
    Spark sideDrive = new Spark(3);
    double sideToSide = xboxController.getTriggerAxis(Hand.kLeft) - driverController.getTriggerAxis(Hand.kRight);
    sideDrive.set(sideToSide);
    

Notice I used the XBox controller triggers, not the bumpers. The bumpers are buttons, so you would only be able to run at full speed. The triggers are analog inputs.

If @gdefender’s comment does what you need it to then great. I would like to point out some variations in code that would be helpful to take into account depending on your motor controller and if you do want the motor run on a bumper press.

@gdefender’s comment is how you would do it with a spark motor controller. The key difference between that and something like a TalonSRX, TalonFX, VictorSPX, ect. would be that you need to set a control mode. Your .set command would look something like this:

    sideDrive.set(ControlMode.PercentOutput, sideToSide);

I would point out more, but I would need to know if you are using command-based programming or not. My team uses command-based, so If you use time-based I couldn’t give you a lot of other advice, except for some syntax stuff. If you are and are still confused I can help you out from there but I don’t want to give you useless information.

We are currently using command based programming, and it is our first year on command based. I am confused on the subsystem/command control scheme. For example say all I wanted to do was have a Differential drive of my 4 Spark motor controllers. If I am correct I would want a subsystem with my motor controllers and the DifferentialDrive. My question is how would I make a command to use this subsystem? Here is the code that I and a couple of mentors came up with, if you could look it over and look for some changes that would be great! : https://github.com/PredatorsRobotics/2020SeasonFRC

@Fe.Wall, WPI_TalonSRX also has the set(speed) method. It’s an overload that calls set(ControlMode.PercentOutput, speed); underneath. Interaction with motor controllers and differential drive are the same regardless of whether you’re using a timed robot or command-based.

@mdfae4564 You’re on the right track with your subsystem constructor to set up the controllers and different drive. But, you should not put your teleop logic in the subsystem. The subsystem should deal with how to make thing happen, but commands should deal with what you want to make happen.

You should:

  1. Add a public method to the Drivetrain subsystem that you can use to drive the bot.
  2. Create a command for reading input from the XBox controller and calling the drive subsystem. You will take the Drivetrain subsystem as a constructor argument, and be sure to call addRequirements(drivetrain). You’ll then basically move your XBox controller and your execute() method into the new command.
  3. Instantiate your new command in RobotContainer and call setDefaultCommand(command) on your subsystem. This way, when no other command is using the Drivetrain subsystem, this command will run.

Quick question. Are you trying to set an exact speed or set a power that the drive-train runs at?

Oh I didn’t know that about the WPI versions of the motor controllers; I haven’t used them but that is good to know. Also in regards to the interaction with the motor controllers, I know that those are the same, I was talking about if @mdfae4564 wanted to run the motor off of a command press, it would be different in regards to the actual code involved, I believe.

Getting your mind around Command-Based programming is not easy, we’ve been through that with our team before. The most important piece of the command-based framework that you’re not understanding is how the Scheduler interacts with the robot to organize what code is operating on the robot, and when.

That is the reason why the advice I quoted is correct, and necessary. if you have arcade drive with the controllers in the subsystem periodic method, what will happen when you assign a command to a button that also uses the DriveTrain? The drivetrain interaction will not be what you expect, since the periodic method will override what your command is doing.

So to modify the advice a bit to comply with the new command-based framework with Dependency Injection you need to do the following:

  1. In your robot container Instantiate the controller, the subsystem, and any commands that will interact with the subsystem.
  2. This requires that you also pass as arguments to the contstructors of the commands the components and subsystems that are used in the command.
  3. Set the Default Command for each subsystem. The Default Command is the command the scheduler will run when no other command is scheduled to run, in your case this would be the command that simply arcade drives your robot with the controller input
  4. Configure the button bindings for any of the other commands that use the subsystems.

Here is a link to our current year’s github that does exactly this. So far, the only things we’ve checked in are a drive train with a default command driving out robot, and a second button that when held flips the front of the robot so our drivers can more intuitively drive while going “backward”.

Hopefully it’s enough to get you where you need. Let me know if you have specific questions about it.

1 Like

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.