Steering (CH1): omega was computed with the opposite sign from the
convention used everywhere else in this file (+omega=left,
-omega=right, per the LiDAR avoidance comments and the prior Xbox
joystick code), so pushing the stick left steered the robot right
and vice versa. Flipped the sign at the single point omega is
derived from the stick so curve-turn and spin-turn both inherit the
fix.
Throttle/steer anti-corruption filter: once a reading was rejected
for exceeding max_slew_per_tick, last_raw_throttle/last_raw_steer
never updated, so every subsequent real reading kept failing the
same slew check against that now-permanently-stale reference —
a livelock. Symptom: CH2 showing neutral (1500) on the HUD while the
robot kept driving forward regardless of stick input. Added a
max_reject_streak escape hatch: after a few consecutive rejections
in a row, treat it as a real fast stick movement rather than a
one-off corrupted frame and resync to the latest value.
Verified working on hardware.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Migrates the 4WD control input from SDL2/Xbox gamepad to a serial RC
receiver per doc/joystick.md's functional spec: CH1 steering, CH2
throttle, CH5 emergency brake (highest priority), CH7 speed mode
(0.3/0.6 m/s), with a 200ms fail-safe that forces an immediate stop
on signal loss. Channel mapping, deadzones, port, and baudrate are
all configurable via --rc_* CLI flags. LiDAR avoidance, jerk-limited
motion profile, and wheel-fault detection are unchanged.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Previously, once a wheel's airborne flag cleared, its target reverted
to the normal drive command but the actual RPM still had to ramp up
through the gentle standstill-launch accel_rate/jerk profile. Since
the chassis is already moving at that point (unlike a stop-start),
the wheel spent several hundred ms unable to match ground speed,
dragging/grinding against the surface and occasionally landing on a
momentarily negative curve-turn target, making it spin backward.
Track the airborne->grounded transition per wheel and, on the tick it
clears, snap cmd directly to target and reset the jerk accel state
instead of ramping, so the wheel rejoins the other three immediately.
Verified working on hardware.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Steering angular velocity (omega) was scaled by the constant max
speed (max_v) instead of the actual current forward speed (v_x).
This decoupled turn tightness from throttle position: at low/medium
throttle, a moderate left-stick steering input already produced an
omega large enough to flip the inner wheel's commanded velocity
negative, causing the robot to spin/reverse/lurch forward instead of
smoothly curving. Scaling by abs(v_x) keeps turn radius proportional
to speed as intended, matching prior full-throttle behavior while
fixing the reversal at partial throttle.
Also drops the stale committed x86-64 binary (built before this fix,
so its behavior no longer matched source). Build fresh on an x86
machine via `make`; run_4wd.sh already rebuilds automatically when
the binary is missing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reads 0x20A5/0x20A6 error codes alongside existing feedback poll to
diagnose overcurrent/overload alarms, and adds rated/max current
query and max current write helpers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds jerk-limited S-curve motion profiles, robust median-based
odometry to reject wheel-lift encoder spikes, per-wheel current-based
airborne/stall detection with pair-wise comparison to avoid false
positives during normal curve turns, curved-turn blending for spin
turns, and optional CSV telemetry logging. Fixes a bug where any
right-stick input while driving forward would override left-stick
curve steering. Raises max speed from 0.3 to 0.4 m/s.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>