Help with LemLib PID tuning

Hi Everyone

I have been hitting a brick wall in terms of tuning the angular PID in LemLib. The graph in the explanation on the docs is easy to understand, but I can’t seem to get it right.

In almost all tutorials I have seen on the matter, like this one Tuning a PID Loop - VEX V5 General Discussion / General Forum - VEX Forum Tuning Kp first will result in a motion with oscillation that slowly dampens to a stop.

Trying with my robot, I have been unable to find any Kp value that does this. I found to 3d the value where the robot has just enough power to turn, not stall. When it gets to the target, it starts a constant oscillation about 5 degrees in each direction forever.

Increasing the Kp, the same occurs simply faster, with a larger oscillation at the target.

At first, I thought I could solve this with some Kd, but I tried at a range of values, between just enough power and reasonable turn speed. But no luck. Any Kd was either too low or just made the robot spin in circles.

Has anybody encountered this before?

Maybe the Imu is a little too slow or imprecise for the final few degrees at the end. (But no one else seems to have issues with LemLib)
I’m running 6m blue 360rpm on 3.25, and the drivetrain has very minimal backlash. (Don’t think the problem is physical)

My Hail Mary is to try GitHub - EthanMik/mikLib: An easy to use odometry VEXcode template with UI support. As I can hopefully use the graph it generates to get a better understanding of the motion.

If anybody has any advice they can give, that would be great.

If it’s doing that, you might have reduced friction to the point where it’s extremely difficult to find that point. If that is the case, increase kD until the robot undershoots the turn by like 1-2 degrees.

  • Make integral (the result multiplied by kI) only activate if the robot is within like ±10 degrees from the target
  • You can add something where integral (or totalerror) resets to 0 if the robot passes 0 (if previous error is positive and current error is negative, or if previous error is negative and current error is positive, reset totalerror to 0).
  • After, tune kI such that the robot can snap to the desired target.

This is very similar to what I was told by a member of BNS when I talked to then years ago, when I saw how snappy their auton was.

In my experience, PID tuning is very finicky. However, my team switched from LemLib to MikLib this season, and I have spent half as much time tuning PIDs as I have in the past. Our whole organization loves MikLib and would definitely recommend it.

As far as the actual tuning is concerned, generally, the steps are to tune kP, then kD, then kI, but I am no expert on this and typically require other people’s input when tuning.

Can you confirm that drivetrain friction is not the issue here? How large of a turn are you using to test? etc.

I would try a very small turn, e.g. 20 degrees, at the lowest kp that makes your robot move at all. See if the oscillation is still there.

If that’s still giving you continuous oscillations, and ki and kd are set to zero, then I have absolutely no idea what could be causing issues here.

I setup everything with MikLib and still had the same issue. It’s way simpler to edit core code in Miklib so I added~some debug code to the pid compute function.

printf("Error:%.02f P:%.02f I:%.0f D:%.02f Output:%.02f\n", error, kp * error, ki * accumulated_error, kd * (error - previous_error), output);

What I found was during the turn_to_angle(20); the error was increaseing as it turned right. After changing the Inertia scale to -360 the error was working as expected and the ocilations and randomness went away.

I can’t be sure, but the very similar symptoms makes me think Lemlib is having the same issue. I can definitely use MikLib if needed. MikLib looks amazing, I just like to mess around with LVGL lots. I’ll do some experementing with Lemlib to see if I can replicate the same fix.

Thank you to all the people who decided to reply :slight_smile:
Might post an update when I’ve tested with Lemlib

Lemlib doesn’t have inertial scaling by default, but you can implement it by subclassing the inertial sensor. Something like this:

class CustomIMU : public pros::IMU {
public:
CustomIMU(int port, double scalar)
: pros::IMU(port),
m_port(port),
m_scalar(scalar) {}
virtual double get_rotation() const {
return pros::c::imu_get_rotation(m_port) * m_scalar;
}
private:
const int m_port;
const double m_scalar;
};

CustomIMU my_imu(14, -1); //flips inertial sensor reading

lemlib::OdomSensors sensors(nullptr, nullptr, nullptr, nullptr, &my_imu)

Update:

Thanks to this helpful forum post: LemLib IMU Scaling - Programming Support - VEX Forum

I was able to make a custom imu with a scaler of -1. Looking at chassis.getPos().theta shows the right is now positive. (How did I not notice the backwards angles) And PID issues are gone.

Hindsight 2020, this is most likely to do with my upside down mounted IMU. I didn’t think of it as I haven’t had issues with upside down imu before. Maybe the get heading command aligns with gravity when calibrated? While rotation doesn’t?

Anyway, thanks again for all the help. :slight_smile:

I’m curious.. Would a negative kP and kD value give the same effect, due to the inverted inertial sensor?