Moderating Acceleration / Deceleration

This is one of those problems that “should” be easy conceptually. For some reason though, we are really strugging with it. Yesterday we spent about 3 hours trying to write code that would moderate our acceleration and deceleration to prevent “rocking” the robot off the front and back wheels.

Here is our thought. From a dead stand-still, flooring the outputs in either forward or reverse does not cause a problem. However, if you are already moving forward or backward, flooring the outputs the opposite direction creates a “wheelie” followed by a slam as the robot comes down. (Yesterday we blew apart a muffin fan we came down so hard).

So we check to see if there is a difference in joysticks of more than 50, AND we check to see if the joysticks are pointing in the direction opposite of the old motion. But it doesn’t seem to work.

The code we are using is attached. Aside from the fact that this doesn’t work, it seems very kludgey. Can someone point us in the right direction, or perhaps take a quick look at the code and tell us where we might be going wrong?

anti-rock.txt (2.61 KB)


anti-rock.txt (2.61 KB)

Hi Tom, It’s a be-deviling problem, isn’t it :rolleyes:

Here’s a thread with a plot (from last year) that may shed some light on what you are dealing with:

pwm / voltage dat

and just a day or 2 ago, I saw a plot of a team’s wheel speeds vs joystick input that is also good data…but I’ll be darned if I can find it again :rolleyes:

Anyway, you might try something like a rate limiter. We’ve done this in the past, but just ended up in an argument among team members on robot handling qualities. You can also search on something like “exponential drivetrain” to see how some teams re-map the joystick to motor relationship.

Here’s a shot at some rate limit code that shows the general idea … it ain’t tested, so caveat cursor :ahh:


//
// a joy stick rate limiter
//
unsigned char RateLImitJoyStick(unsigned char* joy,   // current joystick
                                unsigned char* LPjoy,           // LastPass joystick
                                int            RateLimit)            // rate of change limit
{
   int speed ;
   unsigned char limited = 0;

   speed = (int)*joy - (int)*LPjoy ;
   if(speed > RateLimit)
   {
       speed = RateLImit;
       *joy = speed + (int)*LPjoy ;
       limited = 1 ;
   }
   else if(speed < -RateLImit)
   {
       speed = -RateLImit;
       *joy = speed + (int)*LPjoy ;
       limited = 1 ;
   }
   else{} 
   *LPjoy = *joy
   return(limited) ;
}

I’m sure there are others on this forum that can improve on these ideas.

Good Luck!
(not quite in panic mode)Eric

PS the fighting pi’s is a great name! Ha!

Look up digital low-pass filters. Low-pass filters are simple pieces of code that you can write that only allow the value to change by a certain percentage per cycle.

There’s a fairly detailed discussion of this code here:

We use it to minimize wear on the gearbox end plate.

A simple filter is one line of code. Here is a version that works with integer math:


  out = (((n-1)*out)+in)/n;

in = the input to the filter e.g. PWM value as commanded by the joystick code.
out = the filtered quantity e.g. PWM value to the wheel.
n sets the filter bandwidth. Higher values, lower bandwidth. Experiment!

Preserve the value of ‘out’ (make it global or static). Use separate variables for each wheel. That should get you started.

I actually posted about a problem with our code trying to achieve the same purpose…this code works, but is a little sloppy compared to others.

int Incrementation_Code(int motor_curr, int motor_prev, int padd, int max_step)
{
  int change = 0;
  int RetVal;

  change = motor_curr - motor_prev;

  if (change >= padd)
  {
    //Accelerate
	if (change > max_step)
    {
      RetVal = motor_prev + max_step;
      printf("Motor accelerated by MAX = %d.  ", max_step);
	}
    else
    {
      printf("Motor accelerated by %d.  ", change);
      RetVal = motor_curr;
    }
	
	if ( RetVal > 255 )
	{
      RetVal = 255;
      printf("Detected excess of 255!  ");
    }

  }
  else if (change <= -padd)
  {
    //Decelerate
    if (change < -max_step)
    {
      RetVal = motor_prev - max_step;
      printf("Motor decelerated by MAX = %d.  ", max_step);
    }
    else
    {
      printf("Motor decelerated by %d.  ", change);
      RetVal = motor_curr;
    }

    if (RetVal < 0)
    {
      RetVal = 0;
      printf("Detected below-zero condition!  ");
    }
  }
  else
  {
    //no change
    RetVal = motor_prev;
	printf("No change in motor output value.  ");
  }
  printf("
");
  return RetVal;
}


int last_p1x_val=128;
int last_p1y_val=128;


void Default_Routine(void)
{

	int maximum_step=10; /*change this to change how much the motor increments the speed by*/
	int padding=3;

 /*---------- Analog Inputs (Joysticks) to PWM Outputs-----------------------
  *--------------------------------------------------------------------------
  *   This maps the joystick axes to specific PWM outputs.    */

  p1_y = Incrementation_Code(p1_y, last_p1y_val, padding, maximum_step);
  last_p1y_val = p1_y;
  pwm01 = p1_y;
  pwm02 = p2_y;   
  pwm03 = p3_y;   
  pwm04 = p4_y;   
  p1_x = Incrementation_Code(p1_x, last_p1x_val, padding, maximum_step);
  last_p1x_val = p1_x;
  pwm05 = p1_x;  
  pwm06 = p2_x;   
  pwm07 = p3_x;   
  pwm08 = p4_x;   
  pwm09 = p1_wheel;
  pwm10 = p2_wheel;   
  pwm11 = p3_wheel;   
  pwm12 = p4_wheel;

EDIT: woops, forgot the semi-colons on some of the statements, fixed now

Here’s an Excel spreadsheet, illustrating a formula for moderating joystick values. With it, relatively large movements of the joystick near the centre of travel result in relatatively small movements of the output.

With it, drivers should find it less of a problem with the sudden direction change.

Joystick Curves.xls (77.5 KB)


Joystick Curves.xls (77.5 KB)

This might be a dumb idea, but what if you used a PID algorithm.
Use small extremely small values for P, I , D. Set your input (target) to be the joystick, the feedback/output would be the actual PWM. If the constants are small enough you should experience the same effects that you want. If the joystick is held in one place for a long time, the integral term will build up to the PWM value. You could actually change the D term to a negative value so that if the joystick is moved quickly it will have a smaller effect on changing the output.

I think this approach is better than a simple re-distribution of the joystick output, because it takes into account the dynamics of the joystick movement in many dimensions (Positon of the joystick, time it was held there, how quickly it was moved there).

This code should be extremely easy to implement, simply modify some existing PID code to fit these parameters
You will need to tweak it significantly to get it working perfect though.