Motor.rotation(rev) consistently printing 0

I’m trying to get basic pid control working on my robot. I followed the guide here: Guide

In order to keep calculating error, I have the robot calculating the average of the revolutions of the left and right motors and subtract that number from the initial error. The issue that pops up is that both motors continously print 0 for the total rotations no matter what I try.

At first I tried creating a constant variable to add up all of the rotations but that stayed 0

I then printed out the rotation at every loop and it was also always 0.

The drivetrain moves the specified distance but the loop never ends because the error stays what it initially was. This is because the motor.rotation(rev) command always prints 0. In driverControl, the command works perfectly fine but fails to in auton. Why is this?

//Constants
double kP = 120;
double kI = 0;
double kD = 0;
double inToRev = 4*M_PI; //Wheel has a diameter of 4in. so C=pi*D=pi*4 ; 1 rev = 4*pi inches

void pid(double dist, string direction) {
  double error = 0;
  double integral = 0;
  double derivative;
  double previous_error;
  double speed;
  int time = 0;

  rightdt.resetRotation();
  leftdt.resetRotation();

  while(abs(error) > 0.005 || time < 500) {
    error = (dist/inToRev) - (rightdt.rotation(rev) + leftdt.rotation(rev))/2;
    integral = integral + error;

    if(error == 0) {
      integral = 0;
    }

    if(abs(error) > 40) {
      integral = 0;
    }

    if(abs(error) < 0.005) {
      time++;
    }
    else {
      time = 0;
    }

    derivative = error - previous_error;
    previous_error = error;

    speed = kP*error + kI*integral + kD*derivative;

    rightdt.spin(directionType::fwd, speed, velocityUnits::pct);
    leftdt.spin(directionType::fwd, speed, velocityUnits::pct);

    cout << rightdt.rotation(rev) << endl;
    cout << error << "---" << time << endl;
    vex::task::sleep(20);
  }
  cout << "Done" << endl;
}

void autonomous( void ) {
  pid(-48, "straight"); //Drive forward 40in.
  //pid((18*M_PI)/4, "right"); //90 degrees = (1/4)(Circumference) = (1/4)(18*pi)
  //pid((18*M_PI)/4, "left"); //90 degrees = (1/4)(Circumference) = (1/4)(18*pi)
}

The problem is that the compiler is looking for “rotationUnits” type, and rev is a directionType. Just switch rev with deg and it should work fine.

Place [ code ] before your code, and [ /code ] after the code. (Without the spaces)

But revolutions printed fine when in driver control. Also, after trying that nothing happened, still printed 0.

Not sure why it isn’t printing (deg and rev should work) . You might try using rotationUnits::rev - I have found some cases where the natural language or brief version did not work.

Couple things about your PID. You have no wait in the while loop, so it will count to 500 very fast and do almost nothing. You are trying to get to 0 error in a calculation that will have a large decimal place precision, so 0 has very little chance of ever being true. There is no filter to cap speed at a reasonable number, so the first values will be max velocity and likely will make your wheels slip at the start of your motion. GL.

1 Like

Oh, looking again… you set error to 0 then check for !0 in your while loop. Loop will never run. Need to calculate the first error prior to the loop.

@Omerktosi, please, be so kind to include your full code wrapped in the [code]...[/code] tags next time instead of the screenshot.

Your kD and kI are zero and fast cycle should not affect result but, please, follow @DougMoyers advice and include vex::task::sleep(10) into your loop. Without timeout you overflow cout buffers even before robot starts to move.

After you add timeout , please, check first that your motors are not returning same size but opposite sign rotation values that always add up to zero.

If all fails, please, read this helpful topic about PID Exiting a PID loop - #31 by technik3k

That’s why I have the time variable. Once the error reaches 0 (which I should change to rounded to 0), the time variable begins counting up. As long as the time variable is less than 500, which it is for as long as the error exists, the loop will run.

The loop runs multiple times, the drive train moves where it should, but it never exits that loop because the error never decreases. This is because the right drive and left drive both print 0 the whole time for motor.revolution(rev) for some unknown reason.

Ok, I guess I missed what you were doing with the time variable. Time is the way you want to exit… as it is written, the loop exits 10 seconds after error < .005

As for not exiting, your .005 revolution tolerance is 1/16 of an inch (if my math is right), which is pretty optimistic. Might set a threshold global, put it in spots you want to check it, and dial it up until the loop exits. As it is, .0051 error will never exit.

A point that is not relevant to your problem, you are setting integral to 0 when error is > 40. Because your error is based on revolutions, the maximum error you could have on a field is ~10. That 40 represents the number of revolutions to target.

1 Like