As a mentor, this is my first time dealing with a shooter. I’d like to get my head around PID and/or bang-bang controllers when it comes to shooters before providing assistance to students.
What I want: implement a command group to shoot a cargo using the following sequence
spin the wheels (motors are in coast mode)
feed a cargo
wait 1s. for the cargo to be shot
stop the wheels
The code to implement this command is provided below.
My questions:
What is supposed to maintain the velocity of the wheels once the BangBangController reaches its setpoint, and the spin command ends?
Should the spin command be a DefaultCommand of the shooter instead? This way the BangBangController would constantly maintain the velocity of the wheels throughout a match.
Is there any advantage in using a PID/banb-bang controller over a fixed output voltage for shooting?
Any help of this would be really appreciated. Thank you!
import edu.wpi.first.wpilibj2.command.InstantCommand;
import edu.wpi.first.wpilibj2.command.SequentialCommandGroup;
import edu.wpi.first.wpilibj2.command.WaitCommand;
import frc.robot.subsystems.Shooter;
public class BangBangShoot extends SequentialCommandGroup {
public BangBangShoot(Shooter shooter) {
addCommands(
new BangBangSpin(shooter),
new InstantCommand(shooter::feed, shooter),
new WaitCommand(1.0),
new InstantCommand(shooter::stop, shooter));
}
}
The way we usually do it is we keep the controller inside the Subsystem, there we update the PID in the Periodic functions and implement methods to change the setpoint and see if the goal has been reached.
This makes sure that the Shooter is constantly correcting its velocity. We then create commands that change the setpoint and finish whenever the target is reached.
For any closed loop control, the control loop needs to run as long as the output is controlled. So the spin command can’t end when the flywheel meets its desired velocity the first time.
That’s one option, but There’s plenty of ways to skin this cat. I typically like to be able to turn it off and only turn it on when needed. Doing the logic in the subystem periodic like mentioned earlier is another similar option, but I don’t like that because it makes it harder to switch out the logic for different cases (for example, if you need to revert to voltage control). I would instead move the BangBang controller to the Subsystem, but call it from the execute method of the command rather then the periodic method). I would then run the BangBangSpin command in parallel with the rest of your logic in the command group. Then I would write a wait for shooter at speed command that can be used to gate your intake logic.
Lets assume that your shooting percent is 75%. Assuming that your flywheel has a decent amount of inertia, it will take time to spin up to the nominal speed at 75%. You can decrease that time by increasing the voltage while it’s spinning up, like the bang bang controller does. Another issue is that if your battery is 12v, 75% is 9v. But if you’re also driving and running the compressor and doing other high current things then the battery might be at 10v, and 75% is only 7.5v. You can limit the effect of this by measuring the voltage and choosing the right percent to get the desired voltage. However, this won’t take into account device wear and other changes that might change what voltage creates a desired speed.
I’ve stumbled upon PIDSubsystem recently and was surprised since we exclusively used PID controllers in commands before (ie. PIDCommand). Thanks a lot @Darksainor and @Joe_Ross.
So using closed-loop control is mostly about consistency and not so much about about having a shorter cycle time when shooting (we still have to wait for the shooter to reach its setpoint before feeding a cargo).
Here are some follow-up questions:
Any good resource for computing the feed-forward for a shooter? I’m not sure what kA, kS and kV represent.
Can a feed-forward be determined empirically? So instead of having kA, kS and kV, the feed-forward would simply be a known constant that usually brings the wheels of the shooter near the desired setpoint?
Using ReCalc, what is the difference between a shooter wheel and a flywheel? (my background is purely about software development)
These are separate questions, but the answer to both is “yes” (though clearly the latter approach will only work if you’re trying to achieve a single constant setpoint).
I’m not sure what you mean by this? A well-tuned constant feedforward should be very close to the value of an accurate kS/kV/kA-style feedforward at the setpoint it’s tuned around - so it should not matter which you use, as long as you are only trying to achieve that particular setpoint.
I mean that even if a constant feed-forward is not necessarily tuned for a setpoint, as long as the feed-forward is set low enough to not overshoot, eventually the control-loop is going to reach its setpoint. It might simply require more time to do so.
With a bang bang controller, the ultimate behavior is oscillatory and the oscillation will be wider the further the feedforward is from the “correct” value.
If you use a proportional controller and your gain is small enough you can achieve a stable steady-state behavior, but the equilibrium point will be somewhere between the speed your feedforward is tuned around and the setpoint you are trying to achieve.