Recently, my team has been looking into more accurate forms of motor control for skills autonomous, and stumbled across PID motor control. When attempting to implement our own controller, however, the program does several unexpected things. The lateral PID works well enough when driving forward and backwards, after tuning constants, but the turning fails to perform as expected, and I am failing to find error in my logic.
Our 6-motor drivetrain config
brain Thinky;
motor lm1(0, false);
motor lm2(1, false);
motor lm3(2, false);
motor rm1(7, true);
motor rm2(8, true);
motor rm3(9, true);
motor_group leftMotor(lm1, lm2, lm3);
motor_group rightMotor(rm1, rm2, rm3);
controller sticks;
encoder lquad = encoder(Thinky.ThreeWirePort.C);
encoder rquad = encoder(Thinky.ThreeWirePort.A);
our helper functions:
void reset(){
lquad.resetRotation();
rquad.resetRotation();
curDeg=0;
}
double inchtodegrees(double val){
double rotations = val/(4.125*PI); // calculations with wheel size
double degrees = rotations*360;
return degrees;
}
double degreestorad(double val){
return val*PI/180;
}
double radtodegrees(double val){
return val*180/PI;
}
our threads/tasks:
int getheading(){
while(true){
curDeg += ((lquad.position(degrees)-prevL) - (rquad.position(degrees)-prevR)) / (lWheelDist + rWheelDist);
prevL = lquad.position(degrees);
prevR = rquad.position(degrees);
task::sleep(20);
}
return 1;
}
int headingPID() {
while(enableDrivePID) {
// Heading correction logic
double headingError = targetDeg - curDeg;
// Basic PID for heading correction
turnTotalError += headingError;
if (headingError == 0 || abs(headingError) > 20) turnTotalError = 0;
double turnDerivative = headingError - turnPrevError;
turnPrevError = headingError;
// Adjust heading with PID terms
double turnPower = headingError * tkP + turnTotalError * tkI + turnDerivative * tkD;
// Clamp the turn power
if (turnPower < -12.0) turnPower = -12.0;
if (turnPower > 12.0) turnPower = 12.0;
// Use turn power to correct heading while driving
leftMotor.spin(forward, latpower + turnPower, voltageUnits::volt);
rightMotor.spin(forward, latpower - turnPower, voltageUnits::volt);
task::sleep(20);
}
return 1;
}
int drivePID(){
while(enableDrivePID){
double avgPos = (lquad.position(degrees)+rquad.position(degrees))/2;
error = avgPos-inchtodegrees(driveDist);
totalError += error;
if(error==0 || abs(error) > 20) totalError=0;
derivative = error-prevError;
prevError=error;
// Calculate drive power (forward movement)
latpower = error * kP + totalError * kI + derivative * kD;
if (latpower < -12.0) latpower = -12.0;
if (latpower > 12.0) latpower = 12.0;
// Let headingPID function handle heading correction
task::sleep(20);
}
return 1;
}
our main autonomous loop is pretty basic:
void autonomous(void) {
reset();
//driveDist=12;
//targetDeg=0;
targetDeg=90;
task odom(odometry);
task dpid(drivePID);
task hpid(headingPID);
}
yet when this portion runs, the drivetrain drives straight ahead instead of turning 90 degrees like I expected. I do not believe it is an encoder placement issue, and here’s a pictures of our encoder setup:
The encoders are directly attached to the wheels (for now) and are facing the same way, and they are attached to the brain correctly (top 3-wire first, then bottom 3-wire).
So I am wondering, what is the issue? If anybody could give any useful tips that would be amazing.