"Drifting" issues regarding the vex quadrature encoder

I am using the quadrature encoder to measure the distance my robot drives, but when I use the encoder in the autonomous program, the actual distance my robot moves will be different from my manually recorded values.

Here are the steps to reproduce the error. I put a measure tape beside the robot to measure the metric distance the robot moves, all the values are recorded when the robot was completely stopped. I used two ways of both manually pushing & joystick controlling to record the encoder values (in the debugger in robotC). The calculated proportion of encoder ticks to metric distance in centimeters is about 10.6, which means 530 ticks for 50 cm. I used the code below to run the robot for multiple times for a certain speed, which is set in variable ‘s_drive_spd’. I set the speed to 127(full speed of), 80, 50, respectively. And here are the results I got.

Speed = 127:
drive(50) ----> LAST error (-32, -11), actual distance of about 57 cm
drive(-50) ----> LAST error (33, 53), actual distance of about -(57-6) cm

Speed = 80:
drive(50) ----> LAST error (-24, 7), actual distance of about 53 cm
drive(50) ----> LAST error (30, 28), actual distance of about -(53-2) cm

Speed = 50:
drive(50) ----> LAST error (10, 7), actual distance of about 49 cm
drive(50) ----> LAST error (-10, -4), actual distance of about -(49-0) cm

Note: the ‘LAST error (left_encoder_stop_err, right_encoder_stop_err)’ is an average from three independent runs the program prints.

As can be seen, when the speed is set to a higher value, the more error it would produce.

Since I have been stuck here for almost a week, I really appreciate if you can provide some hints for me to look for the error.


#pragma config(Sensor, in8,    gyro,           sensorGyro)
#pragma config(Sensor, dgtl1,  base_quad_r,    sensorQuadEncoder)
#pragma config(Sensor, dgtl3,  jump7,          sensorDigitalIn)
#pragma config(Sensor, dgtl4,  jump8,          sensorDigitalIn)
#pragma config(Sensor, dgtl5,  lift_quad,      sensorQuadEncoder)
#pragma config(Sensor, dgtl7,  base_quad_l,    sensorQuadEncoder)
#pragma config(Sensor, dgtl9,  arm_pump,       sensorDigitalOut)
#pragma config(Sensor, dgtl10, gripper_pump,   sensorDigitalOut)
#pragma config(Sensor, dgtl11, cube_pump,      sensorDigitalOut)
#pragma config(Motor,  port1,           frontLeftMotor, tmotorVex393HighSpeed_HBridge, openLoop, driveLeft)
#pragma config(Motor,  port2,           backLeftMotor, tmotorVex393HighSpeed_MC29, openLoop, driveLeft)
#pragma config(Motor,  port3,           lift1,         tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port4,           lift2,         tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port5,           lift3,         tmotorVex393_MC29, openLoop, reversed)
#pragma config(Motor,  port6,           lift4,         tmotorVex393_MC29, openLoop, reversed)
#pragma config(Motor,  port7,           lift5,         tmotorVex393_MC29, openLoop, reversed)
#pragma config(Motor,  port8,           lift6,         tmotorVex393_MC29, openLoop)
#pragma config(Motor,  port9,           frontRightMotor, tmotorVex393HighSpeed_MC29, openLoop, reversed, driveRight)
#pragma config(Motor,  port10,          backRightMotor, tmotorVex393HighSpeed_HBridge, openLoop, reversed, driveRight)
//*!!Code automatically generated by 'ROBOTC' configuration wizard               !!*//

void setTurnSpeed2(int left, int right)
{
   motor[frontLeftMotor] = left;
   motor[backLeftMotor]  = left;
   motor[frontRightMotor] = right;
   motor[backRightMotor]  = right;
}

void drive(int dist_cm)
{
   static int s_error_thres = 40;
   static int s_drive_spd = 50;
   float set_point = dist_cm * 10.6;
   SensorValue[base_quad_l] = 0;
   SensorValue[base_quad_r] = 0;
   float errorl = set_point - SensorValue[base_quad_l];
   float errorr = set_point - SensorValue[base_quad_r];
   float error_avg = (errorl + errorr) / 2;
   float drive_spd = error_avg >0? s_drive_spd:-s_drive_spd;
   setDriveSpeed(drive_spd);
   while (true)
   {
      float l_spd = drive_spd, r_spd = drive_spd;
      if (abs(errorl - errorr) > 10)
      {
       if (errorl > errorr)
          l_spd += 10;
       else
          r_spd += 10;
      }
      setTurnSpeed2(l_spd, r_spd);
      if (abs(error_avg) < s_error_thres)
      {
         // brake
         setDriveSpeed(set_point>0? -10:10);
         writeDebugStream("===> Drive MID error%d,%d], set point%.2f]\n", set_point - SensorValue[base_quad_l], set_point - SensorValue[base_quad_r], set_point);
         break;
      }
      writeDebugStreamLine("Drive in progress: error%.2f,%.2f], speed%.2f,%.2f]", errorl, errorr, l_spd, r_spd);
      wait1Msec(20);
      errorl = set_point - SensorValue[base_quad_l];
      errorr = set_point - SensorValue[base_quad_r];
      error_avg = (errorl + errorr) / 2;
   }
   wait1Msec(300);
   stopDriveMotors();
   writeDebugStreamLine("===> Drive LAST error%d,%d], set point%.2f]\n", set_point - SensorValue[base_quad_l], set_point - SensorValue[base_quad_r], set_point);
}

#define LEN(array) sizeof(array)/sizeof(array[0])

void testBase()
{
   clearDebugStream();
   int dists] = {50, -50, 50, -50, 50, -50, 80, -80, 100, -100};
   for (unsigned int i = 0; i < LEN(dists); ++i)
   {
      while (true)
         if (vexRT[Btn7U] == 1)
            break;
      writeDebugStreamLine("Drive dist %d]", dists*);
      drive(dists*);
      //driveQuadPid(dists*);
      wait1Msec(500);
   }
}

How old are the encoders? I know my kids once had a similar situation that I think turned out to be self-made dust inside the encoder. The dust caused the encoder to miss counts and drive too far. It was apparently solved by opening up the encoder and cleaning it out. Check out the following:

https://vexforum.com/t/optical-encoder-failure-mode-self-made-dust/26404/1

Not sure you copied all the code, I don’t see a main task or the setDriveSpeed function, anyway, your problem is most likely wheel slip and overshoot due to acceleration and deceleration being too fast. If you send a step function to the motors ( ie send a value of 127 when they are not moving) you will probably get some wheel slip. Same with deceleration, send 0 at a given encoder count and the robot needs some time to decelerate and overshoot the target.

Yes, that’s a good point. I’d check for that first before anything else.

Thanks for pointing out, the encoders are quite new, but anyway I will check it out whether it’s the cause.

Sorry for losing the main task, the code in the main task is only a call to the testBase() function, and the setDriveSpeed is done in the setTurnSpeed2() function.

I also thought of wheel slip issue, but if the wheel slips against the ground, it means the encoder value will increase while the wheel does not really drive forward. But the outcome here is actually robot drives more than expected distance, which is different from the “slipping” situation…

But what if the slipping is occurring while stopping. The encoder would not read any more counts, but the wheel could skid a tad further. Not sure if that’s realistic though?

Have you tried testing it with some “dumb” code (where you tell it to drive until the encoders reach some value, then tell it to stop)? You are sure to get some overshoots, but it might be interesting to compare the results.

I dont think the robot can travel farther than the wheels when stopping unless you have a breaking system. (one of the teams in my club had one in gateway and round up). For slippage to be the problem, the wheels would need to lock up while the robot travels forward.

It sounds to me like there is something preventing the sensor from reading. I had a similar problem a few years ago.

Inside the encoders there is a disc with slots around the outside. The encoder measures distance by shining a light through the slots and measuring how many times the light shines through the slits.

If one of the slits is obstructed, the encoder will not read the slit. This will make it measure a distance shorter than the robot travels.

I would take the encoders apart, inspect the slots then get a can of canned air and spray any dust out.

The OP is using breaking.

         // brake
         setDriveSpeed(set_point>0? -10:10);

There may be an issue with a dirty encoder, however, the fact that the error reduces as the OP also reduces drive speed still make me think wheels are slipping. I’m going to try and run the code and see what happens.

I ran the code, you need to add some acceleration and deceleration on the motors, especially deceleration, you brake the motors and the robot skids slightly (well, mine does).

Thanks for your hint! I will check if it’s caused in the brake phase.

BTW, what is the best practice to do acceleration and deceleration in the auto program? In my former experience when the robot reaches the top speed 127, setting the motor speed to lower speed like 64 would have little effect.

I also tried the PID control code in your previous post, but the same issue occurred.

Link to your post: https://vexforum.com/t/a-pid-controller-in-robotc/20105/1

Yes you are right, it seems this is the root cause of the issue. But do you know how to prevent skid when I need the robot to run fast but precisely?

Thanks for the hint, I tried commenting out the brake code, and the robot moves much more further. Interestingly when I manually push it back to the 50 cm position, the encoder values are around 530. So as 4149G pointed out, the most possible issue should be skid.

I have checked the encoders and the dusts inside should not be a major issue. I cleaned them but nothing changes.

As I stated above the most possible issue should be slipping when the robot brakes with a rather high speed.

Use his slew rate to ramp up and down the motors. Adjust the increment of size per step to adjust the rate of accel/deaccel. You can get fancier and step differently based upon accel or deaccel too.
https://vexforum.com/showpost.php?p=225727&postcount=25

As FullMetalMentor suggested I tried commenting out the brake code, the robot moves much further, but when I pushes it back to the 50 cm distance, the encoder values are around 530, which means the encoders are working perfectly.

Could you please try again with your robot with my code, and change the set speed to 127 and see what happens? It’s in the drive() function of static variable s_drive_spd.

Do you have a second quad encoder to see if it is a defect with the one you have?

That would let you know if there is something whacked with that one encoder or if it is how all quads behave.

Yes, I forgot to say I have two quad encoders on both sides of the robot. There are some difference in the values but not much, I think it’s mostly caused by differ in friction of two sides.