Hi Everyone,
I’m going to start out by mentioning I’m kind of embarrassed to ask for help with this, but not sure where else to turn.
We are working on getting our robot programmed. We had a programming mentor for our team that ended up not working out. We are a small team, not a lot of resources locally, but as one of the mentors, i’m trying to help these kids. Oh and BTW, I’m not a programmer (i’m trying to learn). I’ve been reading, watching videos, looking at code on github for a few weeks.
Here’s where i’m at. I’ve used RobotBuilder to get us started. Where i’m hung up is how to finish the code. I’m just missing the concepts.
I’ve attached the code generated with robot builder.
This may be to much to ask, but I was wondering if someone could walk me through with some comments on how to finish the code so I can teach the kids some of these concepts? I only included our drivetrain subsystem/commands, a shooter subsystem/command and a Joystick.
Any help would be greatly appreciated. robot.zip (8.1 KB)
So I don’t know what paradigm the robotbuilder uses. Nonetheless there are a few things you should do. First have a method for driving with joysticks. Since you have mechanum drive the easiest thing would probably be a differential mechanum drive (I don’t know how to call it but the API has all the methods). Then for other systems you should have getters and setters. If you don’t know what those are search “smartherd getters and setters” (I also recommend his java fundamentals series - very well done). Other than that I can link to my GitHub.
I’m not overly familiar with the Command based framework, but if you have any specific questions I would be glad to help. The best I can offer you, at the moment, if you haven’t already found it is a link to the Command-Based Programming documentation from WPI.
Also, don’t be embarrassed to ask for help. There’s no shame in it.
[EDIT] Updated to old command based documentation as pointed out by @Oblarg
This documentation is for the 2020 command-based framework. RobotBuilder is still using the pre-2020 framework; you want to look at the documentation for that, instead.
I can’t give a ton of help, but this is what you should know:
You are using the 2019 command-based robot template (which is good but not the easiest to pick up, and I recommend using the 2020 Command-based template)
Essentially think of it like this:
A subsystem is a physical subsystem of the robot. It looks like you already understand this. In this subsystem, you will set motor speeds, pneumatic positions, servo positions, etc. The subsystem controls everything in that physical subsystem. You will put all your motor controllers, servos, pneumatic stuff, and encoders related to that physical subsystem.
//Small snippet
public class Shooter extends Subsystem {
CANTalon shooterMotor = new CANTalon(4);
public void TurnOnShooter() {
shooterMotor.set(1.0);
}
public void TurnOffShooter() {
shooterMotor.set(0.0);
}
//Other methods here
}
A command tells the subsystem what to do. Example: you will have a command to turn on the shooter. The shooter subsystem has the function to do it, and the command calls that function. A command can control multiple subsystems at once. Example: you have a command to deploy your intake and turn on your shooter. This is 1 command. It is common to have MANY commands (We have around 20)
public class TurnOnShooterCommand extends Command {
public TurnOnShooterCommand () {
requires(Robot.shooter);
}
@Override
protected void initialize() {
shooter.TurnOnShooter();
}
@Override
protected boolean isFinished() {
return true;
}
}
You bind commands to joystick values and buttons. Example: When you press “A” on the controller, you can bind that to turn on the intake using a command called TurnOnIntakeCommand. This is done in the OI.java file
b_shoot = new JoystickButton(joystick1, 1); b_shoot.whileHeld(new TurnOnShooterCommand());
The code is probably not valid code because I’m not at a programming laptop, but it’s close
That should be enough to get you started
I think that Chad’s advice is pretty solid, though I would add one sentiment to it.
For each Command that is written for a given Subsystem, make sure that the nature of the command is understood before you write it. Meaning, what should this command do, what subsystems are required to make this command work, and (in my opinion) MOST importantly, when is this command considered finished?
When a command is scheduled to run (as you can see by the generated comments when you create a new command), there are methods that need to be overriden.
Initialize - Called once by the scheduler, this method should setup any state required to successfully run the command. This includes resetting state variables, because commands can be scheduled to run multiple times. (e.g. A single command instantiated schedules the instance of that command every time a button is pressed, or whatever trigger is used to kick off the command)
Execute - Called once every scheduler loop (default is 50Hz, or every 20 milliseconds). This method does the work for the command.
isFinished - Called once every scheduler loop to determine whether or not this command should continue to run. Must return a boolean (true,false) to determine whether or not it should be taken from the scheduler stack.
end - Called once, after isFinished returns true.
And, in the pre-2020 framework (but different in 2020)
5) interruped - Called once if a different command requiring one of the required subsystems is scheduled to run. Typically, our code usually has just called end() in interrupted, but your circumstances may be different.
Here’s an augmentation to the prototype code that Chad had earlier:
I think your isFinished() method is a little confusing, especially for somebody that does not understand the framework very well. I would advocate for using the Timer.getFPGATimestamp() method instead as it uses a less “magic number”.
public class RunShooterForThreeSeconds extends Command {
private Timer timer = new Timer(); // WPILib Timer class
private double startTime;
public TurnOnShooterCommand () {
requires(Robot.shooter);
}
@Override
protected void initialize() {
startTime = this.timer.getFPGATimestamp();
}
@Override
protected boolean isFinished() {
return startTime + 3.0 <= this.timer.getFPGATimestamp();
}
}
I’m still a little confused looking at the drive train command. Looking through others code, I notice this method is referenced in the subsystem file, where as sometimes I see it referenced in the OI.
Also, If i’m understanding correctly, I should reference the joystick controls in the drive command? Using joystick.getY, joystick.getX, joystick.getZ then use those variables to populate driveCartesian(yspeed, xSpeed, zRotation)?
I’ve been teaching my kids modulus operations and counters to get things to run for a certain amount of time. It works, but man, stupid simple wins every time. Thanks for the pointer.