Battery Sizing for Small Mobile Robots: A Back-of-the-Envelope Method
Battery sizing gets treated as either a rounding error ("just double the nameplate capacity") or an over-engineered spreadsheet. A duty-cycle-based estimate, done properly, gets you within a reasonable margin without either extreme.
Start from the duty cycle, not the datasheet
The nameplate capacity of a cell (in mAh or Wh) is measured under close-to-ideal conditions. What actually matters is the average current draw across a real mission profile: idle/standby current, average driving current, and peak current during acceleration or a payload event, each weighted by how long the robot spends in that state.
For duty-cycle states, each drawing current for a duration , the time-weighted average current and the resulting required capacity for a target runtime with current margin are:
That is what actually drives capacity — not the peak current, which only matters for checking the pack's continuous discharge rating separately:
function SIZE_PACK(states, t_run, margin):
# states: list of (current_A, duration_s) for each duty-cycle segment
total_time ← sum(t for (I, t) in states)
I_avg ← sum(I * t for (I, t) in states) / total_time
C_required ← I_avg * (1 + margin) * t_run
I_peak ← max(I for (I, t) in states)
return C_required, I_peak # size capacity on C_required, check cell rating against I_peak
The margin belongs on current draw, not just capacity
A common mistake is applying a single blanket safety margin to the total capacity estimate. It's more useful to apply margin where the uncertainty actually lives: motor current under real load (which is usually higher than a datasheet stall-current estimate once friction, payload, and terrain are accounted for), and a state-of-charge cutoff that leaves the pack in a safe voltage range rather than assuming 100% of nameplate capacity is usable.
A simple sizing sequence
- Break the mission into states (idle, cruise, peak load) and estimate current draw and duration for each.
- Compute a time-weighted average current, then required capacity for the target runtime.
- Apply margin on the current estimate (15-25% is a reasonable starting point for an early design), not just the final capacity number.
- Check the result against the pack's continuous discharge rating, not just its capacity — a pack sized correctly for runtime can still be undersized for peak current.
Case study — autonomous warehouse robot runtime target
A warehouse robot needed a guaranteed 4-hour shift runtime with margin for a charging-dock queue. Averaging current draw across the robot's real duty cycle — mostly cruise at 1.2 A, frequent short stops near idle at 0.3 A, and brief peaks to 4.5 A during acceleration and lift events — gave a time-weighted average of roughly 1.6 A, notably lower than a naive estimate based on peak current.
Sizing the pack for a 1.6 A average over 4 hours plus a 20% current margin, and confirming the cell's continuous discharge rating comfortably covered the 4.5 A peaks, resulted in a pack about 30% smaller and lighter than the team's original estimate — which had been based on assuming near-peak current the whole shift. The lighter pack also reduced the robot's own power consumption, extending runtime further.
None of this replaces validating the final pack against a real logged current profile before committing to a design — but a duty-cycle estimate gets a first pass close enough to size cells, connectors, and charging infrastructure with confidence.