Trying to finish up some the robot code before our competition this weekend. A few issues:
We are using two motors that should spin in opposite directions to shoot a note but the bottom shooter continues to spin inwards, despite us inverting the motor and passing negative speeds to the motor.
The .whileTrue() method appears to not work properly, as either the command is not cancelling or the command end() method is not stopping the motors as intended (this is for the chomp and shoot commands). Currently the configureBindings method holds run commands our coach put in. It works, but it deeply bothers me.
Lastly, I tried to implement a PID Subsystem and Command in Arm.java and SetArmAngle.java respectively. Currently the PID constants are all zero, but would the code I have in there now work if I set them to tuned gains? This is a position controller for a vertical arm rotating around an axis.
Try not inverting the second motor and see if it goes the right way.
Try setting a default command on your intake to stopIntake. That should make it stop when the whiletrue ends.
The P (proportional) value is multiplied by your values to get what the output should be. If you set it to 0 your output would always be 0. Set the P value to 1 if you want to just see how it works before tuning. Just be aware it might go fast and be ready on the e-stop. You could also try .1 if you want to be more careful or even .01.
In terms of the shoot command, you could try making multiple commands for multiple set voltages to ensure that it is the SparkMAX that refuses to turn one way is in fact behaving as you see. You can also use the REV app to spin the motors without using code - REV Hardware Client Overview - REV Hardware Client. We are using a similar setup for our indexer as we are using for our shooter - that can be referenced at robot-code-2024/src/main/java/frc/robot/subsystems/Manipulator/Indexer.java at main · FRC1466/robot-code-2024 · GitHub. Instead of using whileTrue, you could try switching to onTrue. I have had similar issues with WPILibs command scheduling software, but if it works, it works. For the arm, I would look into using the ArmPIDController instead of a PIDController. For this, it would be great if you had a throughbore encoder(if you are using a hexshaft for the arm) or some other kind of encoder so the PID is precise. We have pretty reliable arm code that should be easily followable for an ArmPIDController Example - robot-code-2024/src/main/java/frc/robot/subsystems/Manipulator/Dragonhead.java at main · FRC1466/robot-code-2024 · GitHub. Lastly, when tuning PID, TAKE IT SLOW. This year alone I have damaged the robot twice due to reckless PID tuning. Start very low, like .01, and double until you are close. When decently close, slowly increase and just use your best judgment. Do not rush the process, as PID tuning may be monotonous, but killing your robot is also not very enjoyable. Hope this helps, and please ask if you have any follow-up questions.
For the PID question, since it is a PID command, I’m pretty sure it would only work with tuned gains. This is because what it is doing is that it is taking the error between the setpoint angle and the measured angle, multiplying it in different forms by the gains, and returning a voltage in the form of “output” to set your arm to. If the gains are all 0, then you get 0 volts to the arm and it doesn’t move. If you want me to explain what the different gains do then just ask, though generally you want to slowly increase the P value from a low decimal value like the above post mentions until the arm starts to get to the setpoint angle fast, oscillate a bit, then stay at the setpoint. Then, you want to increase the D value, starting at a low decimal value like with the P value, to smooth out this curve so that the arm smooths into the setpoint without oscillation. Don’t increase the D value too much though because it can also cause oscillation if it is high enough. Finally you can leave the I term alone unless your angle is always off by a few degrees after smoothing out, in which you want to use a very small I gain to gently nudge the arm to the setpoint. I highly suggest using Shuffleboard to graph both the current angle of the arm as well as the setpoint angle so that you can see the curve oscillate and smooth.
It should be this. There should also be a more in-depth explanation somewhere on those docs about the calculus behind PID, but in general P just gets multiplied by the error, I gets multiplied by the sum of error over time, and D gets multiplied by the rate of change of error at a given moment in time.
Tried tuning it today. The arm goes to the set point with a p constant value of .1 with no overshoot, but it is a little fast for my liking. I tried increasing the d constant but the arm will just shake around at its resting position whether the d value is .1, 3.0, or .001. Any ideas for fixing this?
It should be noted how I am implementing this because I am sure it is unorthodox. I have the default arm command setting the arm to its resting position through a PID controller, and whenever the a button on our Xbox controller is held down it tries to move the arm to the arm up set point. This seems to work fine.
Other question- should the same PID loop be used to put the arm down? Right now the arm drops very quickly and it is damaging itself. I am setting the setpoint to the resting position to try and bring the arm down.
Honestly to get the arm down slow you could just have the arm run at a low velocity without any PID until the encoder reads the angle. It’ll be off a bit but if accuracy at rest isn’t an issue then it could probably work well.
As for the D constant oscillating, I’m not too sure what that could be but since the P term is getting to the setpoint fast then the D term just needs to be really small, smaller than .001. Honestly if the P term is getting it to the setpoint fast without oscillation like it is now then you might not need the D term.
Regarding the arm moving too fast, you can use something called a ProfiledPIDController in WPILib. It’s the same thing as the PIDController except you can set constraints for velocity and acceleration. The ProfiledPIDController returns the PID value with calculate like before. How the controller works is that it takes the setpoint and makes it the “goal” and then creates a series of setpoints along the way to the goal so that the PID is smooth. It allows you to get these incremental setpoints and even get the velocity to drive the arm at at that setpoint, to use for things like feedforward, however I’ve experimented with it this season for Swerve and it’s really finicky so just use the calculate method and PID only for the arm when using a ProfiledPIDController. Hope this helps!