- Home
- openamr-platform-fw
- Firmware configuration and tuning
Experimental
Firmware configuration and tuning
Canonical source: openamr-platform-fw/docs/architecture/debug-telemetry.md
Applies to: the documented OpenAMRobot reference mobile base; verify repository revision before changing hardware or firmware.
Experimental project documentation
These instructions describe the current reference build and its measured behavior. Use physical safeguards, test with wheels clear of the floor, and revalidate after changing parts, wiring, firmware, battery chemistry, or geometry.
Applies to the Teensy 4.0 linorobot2_overlay firmware.
These topics are additions to upstream linorobot2, added for this robot. They were essential to diagnose the drivetrain and remain the live-tuning and commissioning interface. This page is the single source of truth for the debug interface; other docs link here.
Published telemetry (Teensy → host)
The debug topic flow is shown below.
All three are geometry_msgs/msg/Vector3, BEST_EFFORT QoS, published at the 50 Hz loop rate:
| Topic | x | y | z |
|---|---|---|---|
/debug/left |
target rpm (LEFT) | measured rpm (LEFT, corrected) | cumulative encoder counts (LEFT) |
/debug/right |
target rpm (RIGHT) | measured rpm (RIGHT, corrected) | cumulative encoder counts (RIGHT) |
/debug/pwm |
PWM LEFT | PWM RIGHT | 0 |
⚠️ The
yfield is the corrected rpm. The firmware runs the measured rpm through the small-window velocity estimator and the runtime ripple table (calib_rpm) before publishing (current_rpm1 → debug_cur_rpm1 → debug_left_msg.y). Until an encoder table is loaded, the ripple correction is unity passthrough, but the velocity-estimator smoothing is always applied. If you need the raw signal, use thezcounts. See encoder calibration.⚠️ BEST_EFFORT QoS: a subscriber must request best-effort too, otherwise it receives nothing:
Commands (host → Teensy)
/debug/openloop — raw open-loop PWM (geometry_msgs/msg/Vector3, RELIABLE)
Drives a fixed PWM, bypassing the PID, for hardware diagnosis (proving a motor/encoder channel independently of the closed loop).
- Only the
xfield is used, and it is applied to both motors (motor2 additionally scaled bymotor2_gain). Theyandzfields are ignored. - Active only when
|x| ≥ 1and a message arrived within the last 300 ms (its own staleness timeout, separate from the/cmd_velwatchdog). Otherwise the loop falls back to normal control. - Validated & bounded: NaN/Inf are rejected, and the value is clamped to
OPENLOOP_PWM_LIMIT = 0.7 · PWM_MAX ≈ ±716so a stray/huge command cannot slam the motors. - Production gate: driving motors from this path requires the
ENABLE_POWERED_DEBUGbuild flag (defined in the current commissioning build). In a production image with the flag removed, the subscriber still exists (executor count unchanged) but cannot move the motors.
# hold both wheels at PWM 200, republished to beat the 300 ms staleness timeout
ros2 topic pub -r 10 /debug/openloop geometry_msgs/msg/Vector3 "{x: 200.0, y: 0.0, z: 0.0}"
⚠️ A prior note described
/debug/openloopasx = left PWM, y = right PWM. That is not what the firmware does —yis ignored andxdrives both wheels. Usemotor2_gain(via/debug/tune) if you need to bias the right wheel.
/debug/tune — live gain tuning (geometry_msgs/msg/Twist, RELIABLE)
Updates the controller in RAM (compiled defaults are unchanged; a reflash restores them).
| Field | Target | Applied when |
|---|---|---|
linear.x / y / z |
K_P / K_I / K_D (both PIDs) |
always |
angular.x |
motor2_gain (right-wheel PWM scale) |
> 0 |
angular.y |
kff (feedforward gain, PWM/rpm) |
> 0 |
angular.z |
dither_amp (anti-stiction dither, PWM) |
≥ 0 |
⚠️ A code comment near the declaration lists
angular.z = ff_offset; the actual callback usesangular.z = dither_amp.ff_offsetis fixed at its tuned default.
# set K_P=2.0 K_I=0.1 K_D=0.1, motor2_gain=1.0, kff=7.87, dither=92 (the compiled defaults)
ros2 topic pub --once /debug/tune geometry_msgs/msg/Twist \
"{linear: {x: 2.0, y: 0.1, z: 0.1}, angular: {x: 1.0, y: 7.87, z: 92.0}}"
A field guarded by
> 0is left untouched when sent as0(so you can nudge one gain without disturbingmotor2_gain/kff);angular.z(dither) accepts0to disable it.
/debug/enc_cal — runtime encoder ripple table (std_msgs/msg/Float32MultiArray, RELIABLE)
72 floats = 36 LEFT_CAL bins then 36 RIGHT_CAL bins. Loaded into RAM and applied instantly.
Full explanation in encoder calibration.
Diagnostic recipes
- Motor/encoder health (wheels raised): publish equal
/debug/openloopon both wheels and compare/debug/left.yvs/debug/right.y— this is how the motors/encoders were proven healthy independently of the closed loop. - Step-response tuning: command a
/cmd_velstep and record/debug/left|right(xtarget,ymeasured) at ≥ 0.25 m/s (below that the rpm is too quantized to tune on). - All debug subscribers are RELIABLE; the telemetry publishers are BEST_EFFORT.
Engineering handoff
- Record the repository commit, hardware revision, supply voltage, and test configuration with every result.
- Stop if observed wiring, component labels, geometry, or topic behavior differs from this page; resolve the discrepancy in the owning repository first.
- Report documentation or implementation defects through the repository issue tracker.