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

}

}

}

}