My team has been working on getting our arm working. We are driving it with two Neo’s, and there’s quite a lot of load. I’ve never programmed an arm before, and I first tried just using the spark max’s setReferance method and a PID loop on the spark.
That, unsurprisingly didn’t work very well, so after doing more research, I tried using Rev’s Smart Motion. but after playing around with the tuning parameters on that for a while, it was working even worse than just the PID loop had been.
So now we’re using WPILib’s ProfiledPIDController with an ArmFeedforward. In order to tune it, we’ve tried running SysId, first using 6328’s URCL to log the data from the Spark’s, and then by manually logging the output voltage from the spark, along with the velocity and position from our CANcoder, thinking we might not have had proper scaling factors to convert from the motor rotations to the radians of the arm. Both times SysId failed, giving us negative values.
Many hours have now been burned trying all this, so now I’m wondering if there’s something I’m doing wrong or if there’s a better way to do this. Should we just not bother with SysId, and just figure out the proper feedforward values through trial and error? When using SysId for an arm, does the 0 position need to be in a specific location (i.e. horizontal, straight down, straight up)?
Screenshots of SysId:
And our code is here
And if anyone knows how I can attach the wpilog I could add that too if that’s helpful.
It sounds like you are shotgunning it a bit, and not sticking with a single method and then working through it till it works correctly. That WILL waste a lot of time.
To start with, PID is an excellent way to control an arm. So when you say it “unsurprisingly” didn’t work well, I suspect your process more than the tool.
The correct way to tune a PID is to tune your feedforward using a cosine function (if the arm is a rotational arm) to account for gravity. Once the arm stays roughly in the position you place it in (i.e. - it counteracts gravity), then you can start tuning your P term. Once it reaches the setpoint, continue increasing P a bit until it oscillates, then increase D until it no longer oscillates. Your PiD is complete.
Our team has used PiD exclusively for the last 17 years. Only this year are we moving to Magic Motion expo, which is CTRE’s flavor of exponential motion profiling.
If you add a ramping function to this, you can even approximate a trapezoidal profile, poorly.
WPiLib’s profiled PID with arm feed forward is probably very similar. PID is not something you really need sysID to tune. If you are using CTRE, you can do the majority of the work in Phoenix Tuner X. If you are using Rev, I would think they have something comparable. These values can be directly saved to the hardware without using WPILib’s ProfiledPIDController.
I’m 100% certain that WPILib’s profiled PIDController will work well too. However, the benefit of having these computations done on the motors directly is that they can take advantage of the high sensor sampling rate that the Rio can not.
2 Likes
You should be able to upload a file with the upload button to the bottom right of the comment box. You can also upload the logs to pastebin, github, or similar.
I haven’t yet learned how to use the SysId API this year but I feel like you don’t need it except as a final touch. Experimentally tuning the arm is good enough.
A quick and dirty method I’ve come up with for tuning the feedforward is as follows.
-
Increase kG until the arm stops moving (with velocity and acceleration setpoints of 0). Set kG to the lowest value that accomplishes this.
-
If using setVoltage to drive your arm (which you should use), set kV to 12 / (max speed in rads/sec). If you’re using set, set kV to 1 / (max speed in rads/sec).
-
Increase kS until your arm starts moving (with velocity and acceleration setpoints of 0). Call this value x. Set kS to x / 2 and increase kG by x / 2.
-
kA is a little more complicated. You can just set kA to 0 and use PID (or in many cases, just P) to accomplish meeting the acceleration targets for most arms, I believe.
We did something similar last year but basically just stopped after the first two steps. kS and KA are not super necessary.
Remember that the angle you pass to the feedforward calculation should be 0 when the COG of the arm is horizontal in relation to the pivot point.
I can confirm that WPILibs profiled PIDController with a simple ArmFeedForward can work well. But it does rely on the mechanical system being well done too.