# Turning PID using gyro

I know how to make a robot drive exact distances and drive straight with out turn using a PID, but I don’t know how to make a PID for turning using gyros or something more accurate. If you have something that can make my robot turn exactly that would help loads anything will help.

1 Like

Using a Vex Inertial sensor along with a Drivetrain can give you accurate rotation without programming a PID - it has one built in. There is an Example Program in VEXcode Pro called Accurate Turns (Inertial Sensor) under the Sensing heading.

If you want to go with the PID route there are numerous threads on PID Turning

3 Likes

Making a pid for turning involves:
`//Declare Variables`
`double kp=.1; double kd=.1; int targetDist=1000; double lasterr=0;...` or whatever (don’t call me out for using double instead of short or long)
Also, you will need to calibrate your inertial sensor before operation.
Then within your main loop, you will want a function or code to be called every iteration (or even in its own thread) that is basically like :

How far away am I? Cool, drive the motors that much. Wait, what’s my heading? Cool, adjust the motors slightly.

Rinse and repeat
If you want to drive straight, you will need to get your starting heading…
`heading = inertial.heading(axis, deg)`
Do this once before your pid loop. Then do your pid loop as follows:
`avgDist = (motorL.position()+motorR.position())/2; ` //average of the two motors.
`err=targetDist-avgDist;`
`velocity=err-lasterr;` see how much err has changed
`lasterr=err;` update the lasterr value.
`rerr=heading-inertial.heading(axis, deg);`
`rvel=rerr-rlasterr; rlasterr=rerr;` might as well do velocity too just so we don’t get wild oscillations.
and now put everything together

`motorLval=kp*err+kd*velocity + rkp*rerr + rkd*rvel;`
`motorRval=kp*err+kd*velocity - rkp*rerr - rkd*rvel;`

`motorL.spin(forward, motorLval, volts);` and repeat for motorR

Use voltage instead of velocity to not have competing pids.

To tune: make start with kp=.1 and kd=0, rkp=0, and rkd=0. Make sure it Reaches its target without hideous oscillation. Double or halve kp and keep testing till you find the magnitude, then make smaller changes till you find just the right number.
Then set kd = kp, and begin the search. kd will result in oscillations if too high, or do nothing if too low. It should just help it slow down better at its target distance without oscillations.

Next, set rkp= something and try to adjust the direction of the robot as it drives. Keep tuning rkp until it properly adjusts the heading and results in mild oscillation.

Finally, set rkd=rkp and repeat until it correctly steers without oscillation.

Basically make a pid for forwards, and augment those values for a pid for rotation.

One issue with all of this is if you have a mod360 direction as your heading value and you are trying to go forwards @ 0 degrees. If you slightly turn to 359, things get wild and you need to address it. Otherwise, absolute heading might handle it.

If you do wind up with directional mod settings, then just use comparisons:
`if (rerr>180) {rerr-=360;}`
`else if (rerr<-180) {rerr+=360;}`
yep.

This simple pd controller (no i value is really required for drivetrains) can be slightly augmented and combined with navigation/localization functions to help your robot travel to waypoints. This is the “legs” of the code but does not have any “eyes” without tracking your x, y, theta around the arena, and setting your desired value to some x’, y’.

Hope you get this working. It is a great tool for auton, especially when getting pushed by other robots, which might mess up your heading.

2 Likes