Lab 7 · Motor Lab
What This Lab Is
- The layer under everything you drove so far: the VESC motor controller, power and safety, and what eRPM means.
- This is where ROS2 gets introduced - the labs before this hid it behind the Racer API on purpose.
The VESC
The VESC 6 EDU is the muscle. It takes a command from the Jetson over USB, drives the brushless motor with field-oriented control, and reports back: motor speed, current, and battery voltage. It also runs a small program of its own (LispBM) that never depends on the Jetson - that is where the safety lives.
- Kill switch. An RF receiver on the VESC's ADC2 pin. DISARM on the remote cuts the motor at the controller, below any software. The Jetson cannot override it.
- Battery cutoff. The 2S LiPo is watched by the VESC itself: warning at 6.8 V, latched kill at 6.6 V. Under 6.6 V the car stops and stays stopped until you power-cycle it.
- Beeps. The motor windings double as the speaker. Each event has a cue; learn them and you can hear the car's state from across the room.
| Event | Cue |
|---|---|
| Powered, armed, above 6.8 V | low-mid-high, pause, low-high |
| Host command path ready | low-low-high |
| Armed / disarmed | mid-high / high-mid |
| At or below 6.8 V | three equal notes, repeated every 5 s |
| Latched cutoff at or below 6.6 V | immediate kill; low-high-low after stopping, repeated every 5 s |
One Stick, Three Meanings
A motor controller can hold three different things constant. The F710 picks which one with X, Y, or B, and the stick value in [-1, 1] scales to that mode's cap:
- X - current, up to 20 A. You command torque. The car surges off the line and coasts when you let go.
- Y - eRPM, up to 60,000. You command speed. The controller adds whatever current it takes to hold it - uphill, downhill, or into a wall. This is how the trained policy (the neural network from Lab 8) drives: it was trained on speed targets, so it commands speed.
eRPM and duty modes do not care what is in the way. A blocked wheel in eRPM mode pulls current to the limit and cooks the motor or the ESC. Use current mode when you are close to the car or to people.
- B - duty, up to 100%. You command raw voltage as a fraction of the battery. Speed then depends on load. The rawest mode, and the one that teaches you what the other two are hiding.
eRPM is electrical RPM: how fast the magnetic field spins, not the shaft. Divide by the motor's pole pairs to get shaft RPM, then through the gearing and wheel diameter to get ground speed. The VESC only ever sees eRPM; every speed number on the dashboard is derived from it. Under 100 eRPM the car counts as stopped - that is the number the cutoff logic waits for before it beeps.
Hello, ROS2
Every lab so far called racer.drive(steer, throttle) and the
plumbing was hidden. Here is the plumbing. On the car the command is a
message on a ROS2 topic. Exactly one process publishes it at a time:
goat-control-mode teleop- the F710 publishes (goat-teleop.service).goat-control-mode policy- the trained policy publishes. systemd stops the other producer first.goat-control-mode none- nobody publishes. Losing the producer commands coast, never the last value.
The motor bridge node sits between that topic and the VESC. It is the one place the [-1, 1] contract becomes amps. Change the mapping there and every commander - pad, policy, your code - changes with it.
// Next: Train Lab - hand the wheel to a policy and watch it publish on the same topic.
Follow the White Rabbit
- VESC project documentation - the controller, VESC Tool, and the LispBM scripting the kill switch runs on.
- ROS2: understanding topics - the
pub/sub model. Run
ros2 topic liston the car and find the motor command.
// One stick, three meanings. These are the same X / Y / B motor modes the F710 selects on the car, with the car's own caps. Current commands torque, eRPM commands speed, duty commands raw voltage - feel how differently the same stick value behaves.
- One stick, three meanings: X commands torque, Y commands speed, B commands raw voltage.
- Speed mode adds whatever current it takes - that is why a blocked wheel is dangerous.
- eRPM is electrical RPM. Every speed number on the dashboard is derived from it.
// what you should be able to do now. Each one traces to a knob or a view in this lab.
- Say what the stick commands in each mode: X, Y, and B.
- Explain why a blocked wheel is dangerous in speed mode and not in torque mode.
- Convert an eRPM reading on the dashboard to wheel speed, given the pole pairs and the gear ratio.
- Find the motor topic in ROS2 and read one message from it.
// the rest of the lab, file by file. Your file is the editor above; these are the exact files that run it. Enough to reproduce the lab outside this page.
app/static/js/motorsim.js
// motorsim.js - Motor Lab playground: what the three VESC control modes
// command. The caps are the wired teleop limits (goat_teleop README):
// X = current control up to 20 A, Y = eRPM control up to 60,000,
// B = duty control up to 100%. One stick input, three interpretations.
(function () {
const stick = document.getElementById("motor-stick");
if (!stick) return;
const bar = document.getElementById("motor-bar");
const out = document.getElementById("motor-readout");
const css = () => getComputedStyle(document.documentElement);
const MODES = {
current: { cap: 20, unit: "A", note: "torque - current is force at the wheel" },
erpm: { cap: 60000, unit: "eRPM", note: "speed - the controller holds electrical RPM" },
duty: { cap: 100, unit: "%", note: "raw voltage fraction - no regulation at all" },
};
function mode() {
return document.querySelector('input[name="motor-mode"]:checked').value;
}
function draw() {
const m = MODES[mode()];
const s = parseFloat(stick.value);
const cmd = s * m.cap;
const ctx = bar.getContext("2d");
const W = bar.width, H = bar.height;
ctx.clearRect(0, 0, W, H);
ctx.fillStyle = css().getPropertyValue("--bg-panel");
ctx.fillRect(0, 0, W, H);
ctx.strokeStyle = css().getPropertyValue("--line");
ctx.strokeRect(0, 0, W, H);
ctx.beginPath();
ctx.moveTo(W / 2, 0);
ctx.lineTo(W / 2, H);
ctx.stroke();
ctx.fillStyle = css().getPropertyValue("--brand");
const w = (Math.abs(s) * W) / 2;
ctx.fillRect(s >= 0 ? W / 2 : W / 2 - w, 6, w, H - 12);
out.textContent =
`stick ${(s >= 0 ? "+" : "") + s.toFixed(2)} → ` +
`${(cmd >= 0 ? "+" : "") + cmd.toFixed(mode() === "erpm" ? 0 : 1)} ${m.unit} (${m.note})`;
}
const tried = new Set();
stick.addEventListener("input", () => {
draw();
if (Math.abs(parseFloat(stick.value)) > 0.3) tried.add(mode());
if (tried.size === 3) window.goatLab?.finish(); // all three modes, stick actually moved
});
for (const r of document.querySelectorAll('input[name="motor-mode"]')) {
r.addEventListener("change", draw);
}
draw();
})();
Hints
Hint 1: the modes all look the same
Watch the readout, not the bar. The bar is the stick. The readout is what the VESC is asked to hold: amps, eRPM, or a duty fraction.
Hint 2: why does eRPM mode feel dangerous
Speed control adds current until the speed is met. Blocked wheel, same command: the controller pours in current up to its limit. Current mode caps the torque instead, so a blocked wheel just stalls.
Hint 3: from eRPM to km/h
eRPM / pole pairs = shaft RPM. Shaft RPM / gear ratio = wheel RPM. Wheel RPM x wheel circumference = distance per minute. Count the pole pairs on the motor label and measure the wheel; the gear ratio is printed on the drivetrain.