Arm and Wrist Setpoint Commands Help

Hi everyone, this is my first year doing programming, and I am the sole programmer on our team. I have been a mechanical member in previous years however I was forced to step up to this role due to a lack of programmers. Right now I have programmed the wrist and arm to move seperately but noticed that there are more setpoints then buttons. So what I want to do is have it so when I press one button both the arm and wrist moves to the correct setpoint at the same time. However, I have no idea how to do that and need help. This is the github. Here is a picture of the CAD of the robot if its helpful:

Thank you so much!

This is my first year doing programming so I’m new to this as well. However I’m fairly sure that you need to create a separate command with a parallel command group to get both subsystems to move at the same time. Don’t quote me on this though.

I’ve used team 2106’s GitHub from last year a lot to help me figure out code if this helps any.
https://github.com/WindingMotor/SwerveDrive

@ImpactTang is correct, what you’d want is a command group, or as they are calling it in more recent version of WPILIB Command Compositions. Check out the sequence and parallel sections on the page below for more information and some simple code examples.

1 Like

I am still a bit confused, Do I need to continue creating the WristCommand class like I have or do I just create something like this:

package frc.robot.commands;

import edu.wpi.first.wpilibj2.command.CommandBase;
import frc.robot.subsystems.WristSubsystem;
import frc.robot.subsystems.ArmSubsystem;

public class ConeSubstationCommand extends CommandBase {

public ConeSubstationCommand(WristSubsystem wrist, ArmSubsystem arm){
    addCommands(
            new WristSubsystem(wristSubstation),
            new ArmSubsystem(armSubstation)
    );
}

}

and call it in RobotContainer?

A command group is made up of other commands. For the old wpilib method, you can make the command extend CommandGroup (specifically ParallelCommandGroup) and you’d use addCommands() to add individual commands that make up the group. For example:

public ConeSubstationCommand extends ParallelCommandGroup {
public ConeSubStationCommand() {
addCommands( new ArmCommand(), new WristCommand());
}
}

ArmCommand and WristCommand being drop-ins for whatever commands you’re trying to use

With Command Groups/Command Compositions you still create the individual commands to use in the Group/Composition. So you’d have a “Wrist” command and an “Arm” command, and you use the Group/Composition to execute them on the same “Trigger” either in parallel or sequentially depending on what is safe for your mechanism design.

So what you wrote above should work, or something like one of the following directly in your RobotContainer:

Sequential

button.onTrue(new WristSubsystem(wristSubstation).andThen(new ArmSubsystem(armSubstation)));

Parallel

button.onTrue(Commands.parallel(new WristSubsystem(wristSubstation), new ArmSubsystem(armSubstation)));

Okay, so in commands I need to create an ArmCommand and a WristCommand? I think I understand how to call it with the

button.onTrue(Commands.parallel(new WristSubsystem(wristSubstation), new ArmSubsystem(armSubstation)));

Im struggling with how to write the ArmCommand class and WristCommand class. Do you know where I can find a good example to look at?

Thank you so much!

So to keep it high level. At minimum you should have some kind of PID Controller object in your Subsystem (be it through a CAN Motor Controller or the WPILIB native one) and some method to set a setpoint for the Subsystem’s PID Controller.

Then you need Command(s) to set the setpoint for the Subsystem’s PID Controller. You can create many Commands, one for each setpoint, but the way I do this personally is to write a Command class where I pass in the new setpoint so I can use the same single Command for all my PID setSetpoint stuff.

The tricky bit usually comes on how you want to handle “ending” your commands. Some people have commands end instantly after setting the setpoint in the subsystem, others use a static timeout and assume their mechanism will reach the position in time, but personally I go for the “check the sensor” approach. Adding a “Current Position” or “At Setpoint” methods to my Subsystem and checking against that in my Command’s end() method, applying my allowable error and such in this piece of logic (ie. abs(currentPosition - setPoint) <= allowedError).

I also usually pass my new set point to my commands as a DoubleSupplier so in addition to static setpoints, I can also hook it into a “Set Point feed” like from a camera, other sensor, joystick, and so on where the setpoint may change as the robot, an object, the goal, etc. moves.

Here is an example I wrote last year when I was also trying out a new “paradigm” of defining the commands in the subsystem as well. Check out the RearArm and ForeArm Subsystems for PID stuff, and then the RobotContainer for composing those commands together.

So, I already have this, does that mean I just need to call it in robotContainer?

You can combine the commands you’ve already written factories for in your subsystems, like so:

Commands.parallel(arm.armGround(), wrist.wristGround());

You can do this in RobotContainer, or in some other intermediate scope that holds both subsystems (you could call this a “system” or “supersystem”, but it doesn’t really need any particular abstract class representation since it just serves as a scope).

Consider removing the stuttering from your method names, since they’re instance methods and if your instance is descriptively named you don’t need to repeat it.

Ok, is this how I would name the command in RobotContainer:

And then for joystick I can just call
new JoystickButton(operator, 9).onTrue(cubeGround());

You need a return statement there, since you have to return the command from the factory method - otherwise, yeah, it should work just like that.

2 Likes