Hello, our team has an elevator(arm) for the game this year which has a potentiometer which we are using to bring it to setpoints. We use the standard wpilib PID(p = .34 I = 0, D = 0.03) to extend it to predetermined setpoints. 80 percent of the time, our arm moves well, with no jittering or rough extension. However, often times, our arm starts spasing and jittering while trying to go to its setpoint. (It still gets to the setpoint, but it’s very slow, and looks painful). I added the extension command in this post. Does anyone have any ideas why this phenomenon is happening once in a while. I don’t believe it’s battery because it happens even with a full battery. Also I think I could tune D higher but I’m not sure if that will fix the problem.
It’s very hard to tell if this is a mechanical problem (something sticking and loading then unloading) or a controls one. A mechanical problem might look like a controls problem. If you graphed the output command to the motor, and it’s a smooth value, then it’s likely mechanical. If you graph the output and it’s a very noisy value, you might have noise on your potentiometer line.
Do you have any logic to hold your elevator position? When we had logic like that, it was causing our elevator to spasm the same way. If not, another thing could be gear slip since you’re using a position PID. My team uses trapezoidal motion profiles for the elevator motion and it’s made it a lot smoother and accurate than it used to be when we used position PIDs.
First, if you are controlling position using just the potentiometer you will have a harder time holding a set point as all of the system “slop” will add to being unable to hit your setpoint. Think all of the gear lash in your gear reductions, chain stretch, cable stretch, constant force springs, or rope stretch. Think if you elevator misses the target, everything in the system has to reverse and you can end up in a bad feedback loop where you are bouncing back and forth past your setpoint because the controller keeps ramping command to swap back and forth between all the system backlash. If you have an encoder on your motor (using a neo, falcon, or venom) it might be better to use this to control to setpoints and using your absolute encoder (potentiometer) to help zero the system/ provide verifications that you moved to a set point.
I would consider adding some I gain (making it non zero) to your system tuning as that helps the system settle around your setpoint, however having a more robust mechanical system and more solid sensor strategy is always a better 1st move.
We don’t have anything to hold the position. For a trapezoid motion profile, do you mean instantiating the pid controller as (new ProfiledPidController(kp, ki, kd, Constraints(MaxV, MaxA). I thinking trying trapezoid might be worthwhile, but I never quite understood what those constraints did, because I never knew where they were getting those velocities and accelerations from.
So your PIDController normally calculates a position your encoders should be at at time t according to the PID Constants kP, kI, kD. Based on that, you can get a position versus time graph for your PIDController. With a position-time graph, you can get a velocity-time curve. The Trapezoidal motion profile constraints apply constraints to that velocity-time graph.
The constraints are in the encoder position unit per second. You could either use a feedforward calculator like @Bmongar suggests, or you could set whatever motor is controlling your elevator to position mode so you can just use .calculate as your output to send to your motor. I recommend using position mode on your motors.
If you’re using Falcon 500’s or some other CTRE motor, take a look at MotionMagic control. REV motors, then try checking out SmartMotion (I believe that’s the one but I’m not familiar with REV, don’t quote me). It does the same thing a ProfiledPIDController does for you, but runs it for you in the motor class.
The PIDController class makes the assumption that the time steps are fixed (default 0.02 seconds). The execute() might be irregularly executing sometimes due to garbage collection or other processes. Check for the loop overrun messages. CAN bus overload can also effect timing.
Logging the input and output of the PID contriller should be informative. I’d print everything - getpositionError(), getVelocityError(), setpoint, getExtendPot(), output, time.
Hi again, we found the problem to be a code problem. Our manual extension code seemed to interfere with our pid extension, since it uses joystick axis values. When the joystick wasn’t pressed, I think it was trying to stop extension during a pid loop, causing the arm to freak out. Since then, we fixed that manual extension code to not interfere and also switched to a Profiled PID controller, and haven’t had any issues since.