Gradual (Quadratic) Acceleration

Is there a simple way to integrate some sort of gradual (quadratic) motor acceleration into RobotC code? I came up with a method in my own head which is rather complicated yet before I spend the time implementing that I was just wondering if there was a method that has already been established.

As of right now I have the right drive train mapped to Channel 1 (Right Joystick) and the left to Channel 3 (Left Joystick). The problem is, it is human nature to just want to floor the joysticks which causes a lot of stress especially when immediately changing directions.

Any help would be appreciated!

Thanks.

Do you really want to control acceleration or do you want to control velocity?

I want to control the velocity of the motors during acceleration so they are gradually increasing velocity. The way it works now is that the motors are basically given either a -127 or 127 value and they go from their but when you want to go in reverse it jerks the motors and the robot causing inconsistency, my thought is if you could implement some sort of quadratic acceleration it would reduce inconsistency and stress on the motors.

Hmmm… I’m not sure about quadratic acceleration, but I do know an easy way to gradually increase velocity is to perform a moving average.

For example, update the motor power once every 10th or 20th of a second. Store the past 5 joystick values in memory and average them. This will “slow” the change from +127 to -127.

I am not sure what you are looking to do with a quadratic equation. Quadratic equations create a parabolic curve:

An even simpler way to make the acceleration more gradual is to increment by a power of +/-1 every few milliseconds. This is what 24C has in its user control code (pseudo code):

while(1) //Repeat forever.
{
  if(vexRT[Ch3] > motor[leftDrive]) //Left joystick greater than left side motor power?
  {
    motor[leftDrive] += 1; //Add 1 to left side motor power.
  }
  else if(vexRT[Ch3] < motor[leftDrive]) //Left joystick less than left side motor power?
  {
    motor[leftDrive] -= 1; //Subtract 1 from left side motor power.
  }
  //Same thing for right side... .

  wait1Msec(2); //Wait for a couple milliseconds to allow motors to speed up gradually.
}

This is not quadratic velocity change, but it is gradual, which I believe is what you are looking for.

~Jordan

My thought behind calling it quadratic was the only parts of the transition that need to be slow is the initial power to the motor/transition period between forward and reverse, the rest could speed up as fast as it needed to; hence creating a partial parabolic shape in a speed vs. time situation.

I guess gradual acceleration would do the trick as well, thank you for the help.

I know a lot of teams have used ramp code so that after a few mili seconds the power could go up 1 and what you could do is between 0 and 40 increase 1 every 5 milliseconds and between 40 and 127 increase 5 every 5 milliseconds. This still wouldn’t be parabolic but I think it is the best way to get what you want.

We have posted about slew rate control of motors several times, here was one post from last year.

https://vexforum.com/showpost.php?p=225727&postcount=25

One other thing to bear in mind when thinking of more sophisticated control methods is that the control value vs motor speed is also a non linear function, see this post for an example.

Is this code how you almost never over heat your drive motors? is it really this simple?

No, not solely. But it certainly helps. You really have to be careful when picking the gear ratio for your drivetrain. I have tried to use mathematical equations, and they can get you a general idea, but mostly it comes from experience. You remember what has worked well before, and try out gear ratios based on that knowledge.

After what I like to consider my personal “exploration and disaster” year in Round Up, I realized the importance of a reasonably geared drivetrain, and that a higher gear ratio isn’t always better. Okay, maybe it took halfway through Gateway for me to really realize it, but I eventually did.

Right now we have a drivetrain that is meant to get into some pushing battles. But if it’s speed you’re looking for, do not ever ride right on the edge. Pick a reasonable gear ratio, based on your robot’s weight, and the number of motors you have assigned for your drive. If your drive stalls for a bit, you want to be able to continue. Not sit on the field, wasting half of your total match time.

Also, do implement this type of code into your drive code. You want it. It can’t be good for the motors on your drive to be going from 127 to -127 in a few milliseconds.

Hopefully this helped to show that while this code helps, it certainly won’t keep your drive motors from overheating in a competition match setting. It will only reduce unnecessary strain on the motors. (Strain caused when you are not pushing against anything.)

~Jordan

A simple way that we have used a few times is to go:

motor = (joystickvalue*joystickvalue)/127

This will give you an ever so slight acceleration, but it may not be enough to stop drives burning out :confused: it does give you more accuracy when driving in the lower ranges though.

Oh, and it makes a quadratic graph with joystick value and output im pretty sure (after a long debate with Nick), so does that count? xD

The other option is to train your drivers so that they are careful with the controls, this is what we do. It means we have the control and speed when we need it as well as not overheating, having acceleration and fancy stuff in the code might get in the way sometimes - you never know.

Where i personally think acceleration is important is autonomous though, to eliminate any inaccuracies from wheel spin on takeoff.

I know my fellow teammates, including myself, spend a rather “considerable” amount of time killing anything in sight using a very similar controller, not to mention the fact that we all have the urge to win, taking to mind gradual acceleration is something I would much rather leave to the Cortex! :wink:

Thank you all for your help!

Yes, anyone who uses this, remember that this does not increase the amount of time it takes your robot to reach full speed (it actually does, but is so minimal it will not help you), all that this does is attempts to fix the natural “logarithmic-like” curve that the motors already have in their input speed/output speed graph. (For more information about that natural effect that the VEX motors have, check this out.) Using the data jpearman collected, I was able to create an array to try to invert the graph, and cause the input speed/output speed graph to be linear. In 24C’s drive task, we also incorporated the gradual speed increase code that I posted earlier in this thread, here.

Here is the code that we currently have for our drive task:


const int joy_threshold = 10; // maximum error +/- of joysticks when released

// compensates for non-linearity of control value vs speed curve
const unsigned int TrueSpeed[128] =
{
  0,  9,  9,  9, 10, 10, 10, 10, 11, 11,
 11, 11, 12, 12, 12, 12, 12, 13, 13, 13,
 13, 14, 14, 14, 14, 15, 15, 15, 15, 16,
 16, 16, 17, 17, 17, 18, 18, 18, 18, 19,
 19, 19, 20, 20, 20, 21, 21, 21, 22, 22,
 22, 23, 23, 23, 24, 24, 24, 25, 25, 26,
 26, 27, 27, 27, 28, 28, 28, 29, 29, 30,
 30, 31, 31, 32, 32, 33, 33, 34, 34, 35,
 36, 36, 37, 37, 38, 38, 39, 40, 40, 41,
 42, 43, 44, 45, 45, 46, 47, 48, 49, 50,
 51, 52, 54, 55, 55, 57, 59, 61, 63, 65,
 67, 70, 72, 74, 76, 80, 84, 88, 93, 97,
101,106,108,111,114,119,124,127
};

task UserDrive()
{
  float left_drive_pwr;
  float right_drive_pwr;

  while(1)
  {
    left_drive_pwr = vexRT[Ch3];
    right_drive_pwr = vexRT[Ch2];

    /////////////////////////////////////////
    // linear speed control with threshold //
    /////////////////////////////////////////

    // left
    if(left_drive_pwr > joy_threshold)
      left_drive_pwr = TrueSpeed[left_drive_pwr];
    else if(left_drive_pwr < -joy_threshold)
      left_drive_pwr = -TrueSpeed-left_drive_pwr];
    else
      left_drive_pwr = 0;

    // right
    if(right_drive_pwr > joy_threshold)
      right_drive_pwr = TrueSpeed[right_drive_pwr];
    else if(right_drive_pwr < -joy_threshold)
      right_drive_pwr = -TrueSpeed-right_drive_pwr];
    else
      right_drive_pwr = 0;

    // "precise control" buttons
    if(vexRT[Btn5D] + vexRT[Btn5U] + vexRT[Btn6D] + vexRT[Btn6U] > 0)
    {
      left_drive_pwr *= 0.7;
      right_drive_pwr *= 0.7;
    }

    /////////////////////////////////
    // "anti-jerk" gradual control //
    /////////////////////////////////

    // left
    if(left_drive_pwr > motor[mDriveL])
      motor[mDriveL] += 1;
    else if(left_drive_pwr < motor[mDriveL])
      motor[mDriveL] -= 1;
    motor[mDriveL2] = motor[mDriveL];

    // right
    if(right_drive_pwr > motor[mDriveR])
      motor[mDriveR] += 1;
    else if(right_drive_pwr < motor[mDriveR])
      motor[mDriveR] -= 1;
    motor[mDriveR2] = motor[mDriveR];

    wait1Msec(1);
  }
}

Let me know if you have any questions about this code.

~Jordan

Here’s another post about the same thing.

https://vexforum.com/showpost.php?p=317913&postcount=6

We actually did not use it as part of the driver code this year, decided it was better to modify joystick control if needed, however, we do use it to modify the output of PID control code as the thinking was that PID expected motor drive to be linear. We calculate the table using this function as part of an initialization process, I will document properly later as I do plan on releasing the PID library we use at some point.

void
PidControllerMakeLut()
{
    int   i;
    float x;

    for(i=0;i<PIDLIB_LUT_SIZE;i++)
        {
        // check for valid power base
        if( PIDLIB_LUT_FACTOR > 1 )
            {
            x = pow( PIDLIB_LUT_FACTOR, (float)i / (float)(PIDLIB_LUT_SIZE-1) );

            if(i >= (PIDLIB_LUT_OFFSET/2))
               PidDriveLut* = (((x - 1.0) / (PIDLIB_LUT_FACTOR - 1.0)) * (PIDLIB_LUT_SIZE-1-PIDLIB_LUT_OFFSET)) + PIDLIB_LUT_OFFSET;
            else
               PidDriveLut* = i * 2;
            }
        else
            {
            // Linear
            PidDriveLut* = i;
            }
        }
}

I understand the logic behind the rest of it yet this doesn’t really fall under my field of knowledge. Then again, this is only my second season of playing with RobotC.

That’s just an initialized array.

I understand it is an array but I don’t understand how you reached the integers you filled the array with.

Also, you reference the variable “joy_threshold” yet I don’t see any place it is defined as anything, which makes it a bit hard to follow.

I got those numbers by taking the positive values on the graph jpearman posted here, and modifying it slightly so that the highest “motor speed” it reached was 127 on the graph. I then went through the process of finding out which “motor control value” would yield the desired “motor speed” in order to get the graph of the actual speed to be linear from x=0 to x=127. Those are the values that you see in that array. In other words, to get a speed of “0”, you give the motors a value of 0, to get a speed of “1”, or “2”, or “3”, you give the motors a value of 9, and to get a speed of “4”, or “5”, or “6”, or “7”, you give the motors a value of 10. This goes on and on in the array, and eventually, near the end, you begin skipping a bunch of numbers, rather than repeating them, because, if you notice, from about a motor control value of 86 until 127, the motor speed doesn’t seem to change hardly at all. Hopefully I explained that well enough. Let me know if I didn’t.

I am so sorry for missing that when I was copying/pasting the small parts of code. I have edited my original post to include that variable. Basically, it was to create a threshold on the joystick, to keep a small error in the physical springs inside the joysticks, causing them to not zero out when released from making the drive move. Basically, you don’t want the drive moving while you have the joystick released, and the joysticks tend to sometimes have a small (usually between 1-5) amount of error, because they can’t always spring right back to 0. That is all that variable is used for.

~Jordan

Thank you again for the explanation. I think I understand the way you have set up the array; the one question that remains is that the graph that jpearman posted is for a motor with no load. Yet if I am understanding the point of this… it is to create a linear speed vs control graph. So, how can we correctly use this information in regards to the motors we have on our drive trains, they surely have far more load and by proxy a lower number of RPMs.

If I am correct the slope of your metaphorical line would be considerably less than a motor that has the honor of not bearing any form of load.

Some of the members of CD have done lots of testing on various speed controllers (as the non-linearity of the motor is due to the controller not the motor). The Victor 884 behaves in a very similar way to the MC29 and cortex, you can see it here compared to the new Victor 888 and a couple of other controllers.

http://www.fightingpi.org/Resources/Controls/Beta/2013_Pictures/pwm_vs_velocity_1_cim.png
Ignore the details of this graph but note that the red trace is similar to what we have found for the MC29. It’s true that the behavior is different when under load but also remember that this is an approximation and it does not matter that much. You could also use closed loop PID speed control, this is built into ROBOTC V3.60 and later (available as a public beta) and does allow much better low speed control, however, using the default constants I don’t like it’s response for “normal” driving and it needs more development before I would want to use it on a competition robot.

We’ve deviated from your original question so don’t get too hung up on the linearized control, the important part from earlier posts is to reduce stress on the motors by controlled acceleration and deceleration when dramatically changing the control input.