## Note: Adding some braking to the move_encoder(.) function

Most of the 599 teams are using gear ratios that increase speed and decrease motor drag force.    As a result, the move_encoder(…) function provides a lot of overshoot due to the robot momentum since it is not a PID loop.    Typically, a 24 in/s top speed can produce 6 to 9 in of overshoot.  So we need some braking that is also adjustable.  I will do a few calculations to estimate how long it takes a typical robot to slow down from the max speed when given a full reverse command.   The best way is to measure the deceleration response, however,  it can be estimated analytically by using  some assumed dynamics for the robot/motor system.

Analysis:

Robot assumptios:

wt = 10lb

max_tq = 26 inlb (2 393 motors per side with 13 inlb per side )

gr = 84/60= 7/5  (wheel speed to motor speed)

g = 12*32.2= 386.4 in/s/s  (gravity)

r_in = 2.  ( wheel radius)

max_accel = g*max_tq/(gr*r_in*wt) = 359 in/s/s or roughly 0.9 g’s

max_speed = 100rpm*2pi/60*gr*r_in= 29.3  in/s

tau = max_speed/max_accel =  .081 sec  (motor time constant)

Assuming that the motor is a first order lag,  the speed response  to a step reverse command  input  of  (v_0 – v_final)  follows the equation

v =  v_final + (v_0 -v_final)*exp(-t/tau)

where v_0 is the initial speed and v_final is the final steady state speed.

Here , v_0 = max_speed and v_final = -max_speed  and we want to solve for t that makes v= 0.

So substituting and solving for t

exp(-t/tau) = -v_final/(v_0-v_final)   or

t = -tau*ln(.5) = .69*tau

Thus the time to drop the speed to zero is   t =  .69*.081 = .056 sec

The average speed over this period is about max_speed/2 so the

stopping_dist  ~= max_speed*t/2= 29.3*.056/2 = .85 in

Discussion:

The robot can decelerate from max speed to zero speed in less than .06 sec  and  the over shoot should be less than .85 in.     We know that a heavier robot, e.g. 20 lbs , will have twice the tau, hence  for design purposes, I’ll assume  a max reverse brake command  with a nominal .1 second pulse and make the pulse duration adjustable  to accommodate different weight robots.    We can add enough time for the robot to back-up and have zero overshoot.     This tweeking  can also be done automatically by a PID controller with a high gain but the timed pulse technique  has the advantage of a minimum time controller since it uses maximum command rather than proportional commands.   The PID approach  will be a topic of future discussions.

The max_acceleration did not take in to account the dynamic friction of the drive train and we would expect the actual robot to slow a little faster since the 393 motors have about 1 inlb of drag torque.

Braking software code:

We require a parametric timed pulse (nominally .1 sec) of max motor reverse command (127).   A timer is needed to put in a signed pulse after the distance goal has been crossed in the Move_encoder (..) code.    When using Move_encoder(..) we would just set the goal distance and then tweek the brake time to minimize the overshoot without reversing.

If pwm_brake = o then braking calculations can be bypassed and the robot is free to coast with just motor drag to slow it.

Move_encoder(..)  with braking changes might look like this:

UPDATED 12/5 to add b_brake_done logic to keep output latched when using Move_encoder with other utility functions in the same step. Changed the name to Move_&brake_encoder(..)

int Move_&brake_encoder(int goal , int pwm_input , int brake_time10 = 10)
{
// test routine similar to what might be used for encoders
// goal is the incremental distance you want to go from where you are
// goal is + or – relative distance in dist_10in units (deci inches)
// brake_time10 is the reverse motor brake pulse time in hundredths of a sec
// pwm_fwd , dist_10in , bsys_reset, bauto_move are global
static int target_dist = 0;
static int target_time = 0;
static bool b_move_done = false;

static bool b_brake_done = false;
if(bsys_reset)
{
//initialize stuff for output
bauto_move = true; // take control of the motors that are used in this function
target_dist = dist_10in+goal; //compute goal in reference axis units.  Input goal is relative to where you are
if(goal<0)
{
pwm_fwd = -pwm_input;//move in direction of goal
}

else
{
pwm_fwd = pwm_input;
pwm_brake = -pwm_brake; //need to reverse brake sign
}
b_move_done = false;

b_brake_done = false;
return 0;
}
else
{
if( (goal<0 && dist_10in > target_dist || goal>0 && dist_10in < target_dist )&& !b_move_done) return 0;
else
{

// start braking
if(!b_move_done)
{
target_time = time10[T1] + brake_time10;
b_move_done = true; // keeps the target_time from being reset while we wait
pwm_fwd = pwm_brake; //brake in direction opposite of goal
}

else if(time10[T1]< target_time && brake_time10  !=0 && !b_brake_done) return 0; // wait for braking
else
{//done braking so exit

b_brake_done = true;

bauto_move = false; //return control to joystick
pwm_fwd = 0 ; //set the speed to zero again
return 1;// sets done = 1
}
}

}
}