Limit how fast the speed command can change.
What the message means
A sudden full-power command makes wheels slip, draws a current spike and can reset the board.
Fix it in this order
- Keep a current speed and a target speed.
- Each loop, move the current speed a small step towards the target.
- Use a larger step for stopping than for starting if you need quick braking.
- Tune the step size by watching the robot start.
- Check the battery voltage during the start.
- Combine with a minimum PWM start value.
Why it happens
A DC motor at standstill draws its stall current the instant full power is applied, so the battery voltage dips and the wheels get more torque than the floor can grip. The dip can pull the board supply below its brown-out level and reset it. Limiting how fast the command can change keeps the start current and the wheel torque inside what the battery and floor can handle.
Example: a simple ramp
int target = 0; // speed you ask for, -255..255
int current = 0; // speed actually sent to the motor driver
const int STEP_UP = 4; // PWM counts per loop when speeding up
const int STEP_DOWN = 12; // larger so braking is quick
void updateSpeed() {
if (current < target) current = min(current + STEP_UP, target);
else if (current > target) current = max(current - STEP_DOWN, target);
setMotor(current); // your function: direction pin plus analogWrite
}
// call updateSpeed() every 10 ms from loop() using millis(), not delay()Example sketch: change pins and values for your own wiring. It has not been bench-tested on your hardware.
How to tune it
Start with a small step and raise it until the robot starts briskly without the wheels spinning. At a 10 ms update, a step of 4 takes about 640 ms to reach full speed from rest. If the board still resets, the cause is the supply rather than the command: add a bulk capacitor near the motor driver and check the battery can supply the stall current.
If you see this, do this
| You see | Do this |
|---|---|
| Wheels spin on start | Ramp too steep. |
| Board resets when starting | Current spike. |
Related
Last reviewed: November 2026. These are the usual causes and the order that finds them fastest. Test on your own board; clones and cables differ.
Why this happens
A DC motor at rest has no back-EMF, so the only thing limiting current is the winding resistance. The stall current is the supply voltage divided by that resistance. As the motor speeds up it generates its own voltage opposite to the supply, and the current drops. Commanding full power at once puts the largest current and torque into the first fraction of a second.
That has two effects. The battery has internal resistance, so the pack voltage dips by the current times that resistance, which can pull the controller below its reset level. And the torque spike can exceed what the tyres grip, so the wheels spin or the front lifts. A ramp spreads the same speed change over time and lowers both peaks.
How to confirm the cause
- Start the robot at half power instead of full. If the jerk disappears, the problem is the size of the step, which a ramp fixes.
- Watch the controller supply during a start with a multimeter in min-hold mode, or print its voltage. A dip close to the reset threshold points to a supply problem.
- Check whether the board resets at the moment of start by printing millis() at startup. A counter returning to zero means a reset.
- Look at the wheels on a smooth floor. Spinning wheels mean the torque exceeds grip.
- Change only the ramp step and compare. If nothing changes, the cause is not the command.
Worked example
Choose the step from the ramp time you want. For a ramp of 0.5 s with a 10 ms update, there are 500 / 10 = 50 updates. Covering 255 counts in 50 updates needs a step of 255 / 50 = 5.1, so use 5. The example uses millis() so nothing blocks.
const unsigned long PERIOD = 10; // ms between updates
const int STEP = 5; // counts per update
unsigned long last = 0;
int current = 0, target = 255;
void loop() {
if (millis() - last >= PERIOD) {
last += PERIOD;
if (current < target) current = min(current + STEP, target);
analogWrite(5, current); // example motor PWM pin
}
}Reaching 255 takes 51 updates, about 0.51 s. For slowing down, use a larger step so the robot stops promptly.
Common mistakes
- Ramping with delay() and blocking the sensor loop.
- Reversing direction at speed without ramping through zero first, which gives the largest current spike.
- Ramping the output of a control loop without limiting its internal state, so the controller winds up.
- Choosing a step that rounds to zero when the update is fast.
If this did not fix it
- Battery too weak for the motors: measure its voltage under load and check its current rating.
- No capacitor near the driver: a bulk capacitor reduces the dip.
- Chassis weight too far back: the front lifts on hard starts and a ramp alone may not fix it.