Velocity profiles
The trapezoid, the triangle when there is no room to reach cruise, and what jerk costs you.
Do this lesson in the simulatorConstant speed is a time law with a corner in it: zero one instant and 12 cm/s the next. That demands infinite acceleration, which no machine has, so the machine ignores you and does something else. A velocity profile is the time law written so that the machine can actually follow it.
The trapezoid
Three phases: accelerate at a until you reach v, hold v, decelerate at a until you stop.
t_acc = v / a how long the ramp takes
d_acc = v * v / (2 * a) how far it covers
If 2 * d_acc fits inside the distance, there is a flat top in the middle, and it lasts (d - 2 * d_acc) / v. If it does not fit, there is no cruise phase at all: the profile is a triangle, the peak speed is sqrt(a * d) and it is reached exactly half way.
Forgetting the triangle case is the classic bug. It shows up as a short move that overshoots every time, because the profile promised a cruise phase that the distance had no room for.
The trapezoid is time optimal for a move with a speed limit and an acceleration limit. Nothing that respects both bounds gets there sooner, which is a satisfying thing to be able to say about something this simple.
from bugbot import *
connect()
D, A, V, DT = 80.0, 10.0, 15.0, 0.05
t_acc = V / A
d_acc = 0.5 * A * t_acc * t_acc
t_flat = (D - 2 * d_acc) / V
duration = 2 * t_acc + t_flat
s = 0.0
n = int(duration / DT)
for i in range(n):
t = (i + 0.5) * duration / n
if t < t_acc:
v = A * t
elif t < t_acc + t_flat:
v = V
else:
v = max(0.0, V - A * (t - t_acc - t_flat))
s += v * duration / n
plot("v", v)
plot("s", s)
print("duration", round(duration, 2), "s, area under v =", round(s, 1), "cm")
The area under the speed line is the distance. If it does not come out at the distance you asked for, the profile is wrong, and that check costs one accumulator.
The BugBot has no acceleration limit
This is worth being blunt about. The drive has no acceleration limit in it. Give it a step command and it does its best immediately, and the only thing that stops the velocity jumping is the first order lag, time constant about 0.25 s. A step to 20 cm/s is therefore an initial acceleration of roughly 20 / 0.25 = 80 cm/s/s.
So on this robot an acceleration limit is something you impose, not something the hardware imposes on you. Why bother?
- Traction. On a real surface, demanding more acceleration than friction can supply means slipping, and slip is the one thing dead reckoning cannot see.
- The payload. Anything carried, and anything on top, feels whatever you demand.
- Current. A step demand is a current spike, and on a small battery that is a voltage sag and sometimes a brownout reset.
- Predictability. A profile the machine can follow is a profile whose error you can reason about. A profile it cannot follow leaves an error you can only measure.
Jerk
Jerk is the rate of change of acceleration. A trapezoid has infinite jerk at each corner: the acceleration goes from 0 to a in no time at all.
Infinite jerk excites everything springy in the machine: the chassis, the mounting, the payload, the arm you bolted on last week. It shows up as a wobble that starts exactly at the corner of the profile and rings for as long as the structure takes to settle.
The fix is an S-curve: limit the jerk as well, so the acceleration itself ramps. The profile gains two more phases at each end, takes slightly longer, and is dramatically smoother. Industrial motion controllers do this by default, and for good reason. For a 7 cm robot on a mat it is over-engineering, but the vocabulary is worth having, because the first time a robot arm rings like a bell at the end of every move, jerk is the answer.
Choosing the numbers
vcomes from the machine, reduced by whatever margin the controller needs to have authority left. Cruising at 100 percent leaves nothing to correct with.acomes from traction, payload and taste. Start atv / 1(one second to cruise) and tighten it.- Check the profile against the machine before driving it: peak speed under the limit, peak acceleration under the limit, area equal to the distance.
Task: a trapezoidal profile
Build a trapezoidal profile that covers 80 cm with an acceleration limit of 10 cm/s/s and a cruise speed of 15 cm/s, sampled every 0.05 s. Plot v and s, and print peak:, duration: and distance:, the last being the area under your own speed profile.
from bugbot import *
connect()
DISTANCE, A_MAX, V_MAX, DT = 80.0, 10.0, 15.0, 0.05
Challenges
- Ask for 8 cm with the same limits. Does your code produce a triangle, and is the peak
sqrt(a * d)? - Work out the peak acceleration a step command to 20 cm/s really produces, using the 0.25 s lag.
- Add a jerk limit by ramping the acceleration over 0.3 s at each corner. How much longer does the move take?