17 Commits

Author SHA1 Message Date
22d7b546f3 feat: prototype base plate with real hub motor measurements
Adds prototype_baseplate.scad — a laser-cuttable / CNC-routable flat
base plate for the self-balancing robot using caliper-verified axle
dimensions from the wiki (replaces placeholder values in PR #7):

  Axle base dia:     16.11 mm (was 14 mm)
  D-cut OD:          15.95 mm (new)
  D-cut flat chord:  13.00 mm (new)
  Total protrusion:  65.50 mm
  Bearing seat OD:   37.80 mm
  Tire OD:          254 mm (10x2.125")
  Axle CL height:   127 mm (was wrong 310 mm)

Design:
- Single flat plate (6 mm Al / 8 mm acrylic), 680x220 mm blank
- Open fork slots (16.51 mm, semicircular tip) at each axle end
- Bearing seat relief cutout prevents Ø37.8 mm collar binding on edge
- Two-piece dropout clamp: lower (round bore) + upper (D-cut bore)
- D-cut profile computed from chord geometry with 0.3 mm all-round clearance
- MAMBA F722S FC holes (30.5x30.5 mm M3), battery mount holes (M4)
- Lightening slots, corner radii via minkowski
- RENDER param switches between 3-D assembly and 2-D DXF projections
  for each of the three laser-cut parts

Updates BOM.md to Rev B: measurement delta table, prototype BOM section,
updated motor entry with verified axle spec.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 14:43:26 -05:00
909763494f Merge pull request 'feat(safety): IWDG watchdog, arm hold interlock, tilt alert (bd-3qh)' (#4) from sl-controls/bd-3qh-safety-systems into main 2026-02-28 13:12:18 -05:00
c719cf5467 Merge pull request 'feat(pid): runtime PID tuning via USB + telemetry (bd-18i)' (#3) from sl-controls/bd-18i-pid-tuning into main 2026-02-28 13:12:13 -05:00
098475a606 Merge pull request 'feat(imu): MPU6000 sensor fusion — complementary filter (bd-2dv)' (#2) from sl-controls/bd-2dv-imu-fusion into main 2026-02-28 13:12:09 -05:00
4dd52b47dc feat(safety): IWDG watchdog, arm hold interlock, tilt alert (bd-3qh)
Safety systems implementation:

IWDG Hardware Watchdog (50ms timeout, config.h WATCHDOG_TIMEOUT_MS):
- safety_init() configures IWDG at PSC/32 (0.8ms tick), reload=62
- safety_refresh() must be called every loop iteration
- Cannot be disabled once started — MCU resets if loop hangs
- Started after 3s USB init delay (avoids spurious startup reset)

Arm Hold Interlock (3s, config.h ARMING_HOLD_MS):
- Arm command starts a hold timer, not immediate motor enable
- Motors only enable after ARMING_HOLD_MS consecutive hold
- Disarm or tilt > 10° cancels pending arm
- Prevents accidental arm from single keypress

Tilt Fault Alert:
- safety_alert_tilt_fault() fires one-shot buzzer on TILT_FAULT edge
- Rider hears alarm when tilt cutoff triggers
- Edge-detected (buzzer only fires once per fault event)

RC Timeout (infrastructure):
- safety_rc_alive() checks crsf_state.last_rx_ms vs RC_TIMEOUT_MS
- RC disarm wired but guarded (no CRSF yet) — remove guard when wired
- Compatible with future CRSF implementation

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 13:11:43 -05:00
34fdb5d11b feat(pid): runtime PID tuning via USB + improved telemetry (bd-18i)
Add USB command interface for live PID gain adjustment without reflashing:
  P<kp>  I<ki>  D<kd>  T<setpoint_deg>  M<max_speed>  ?

Command parsing runs in main loop (sscanf-safe), not in USB IRQ.
USB IRQ copies command to shared volatile buffer (cdc_cmd_buf), sets flag.
Acknowledgement echoes current gains: {"kp":...,"ki":...,"kd":...}

Bounds checking: kp 0-500, ki/kd 0-50, setpoint ±20°, max_speed 0-1000.
Gains validated before write — silently ignored if out of range.

Telemetry updated from raw counts to physical tuning signals:
  pitch (°x10), pitch_rate (°/s x10), error (°x10),
  integral (x10 for windup monitoring), motor_cmd, state

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 13:10:32 -05:00
398cbb9a55 feat(imu): MPU6000 sensor fusion with complementary filter
Add src/mpu6000.c implementing a complementary filter (α=0.98) on top of
the existing icm42688 SPI driver. Fixes wrong scale factors in balance.c
(was ±250°/s / ±2g; hardware is configured ±2000°/s / ±16g). Fusion now
lives in the IMU driver layer; balance_update() consumes IMUData directly.

- mpu6000_init(): calls icm42688_init(), seeds filter state
- mpu6000_read(): reads raw SPI, applies complementary filter, returns
  fused pitch (degrees) + pitch_rate (°/s) + accel_x/z (g)
- balance.c: removes duplicated fusion code, uses IMUData.pitch
- main.c: switches to mpu6000_init()/mpu6000_read(), updates telemetry

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 13:09:18 -05:00
29a3030abb Merge pull request 'feat: Jetson Nano platform setup (bd-1hcg)' (#8) from sl-jetson/bd-1hcg-jetson-platform into main 2026-02-28 13:06:48 -05:00
ec54a9cb8f Merge pull request 'feat: Parametric chassis frame design (bd-1iy5)' (#7) from sl-mechanical/bd-1iy5-chassis-frame into main 2026-02-28 13:06:23 -05:00
6b92d7089e Merge pull request 'bd-wax: SLAM setup technical plan — Jetson Nano + RealSense D435i + RPLIDAR' (#1) from sl-perception/bd-wax-slam-setup into main 2026-02-28 13:06:19 -05:00
seb
bfb94fc169 Merge pull request 'fix(usb): resolve USB CDC TX failure — DCache coherency + buffer + IMU API (bd-1lo)' (#6) from sl-firmware/bd-1lo-usb-cdc-fix into main 2026-02-28 12:52:43 -05:00
c47ac41573 feat: Jetson Nano platform setup and Docker env (bd-1hcg)
- Dockerfile: L4T R32.6.1 (JetPack 4.6) base + ROS2 Humble + SLAM stack
  (slam_toolbox, Nav2, rplidar_ros, realsense2_camera, robot_localization)
- docker-compose.yml: multi-service stack (ROS2, RPLIDAR A1M8, D435i, STM32 bridge)
  with device passthrough, host networking for DDS, persistent map volume
- docs/pinout.md: full GPIO/I2C/UART pinout for STM32F722 bridge (USB CDC +
  UART fallback), RealSense D435i (USB3), RPLIDAR A1M8, udev rules
- docs/power-budget.md: 10W envelope analysis with per-component breakdown,
  mitigation strategies (RPLIDAR gating, D435i 640p, nvpmodel modes)
- scripts/setup-jetson.sh: host one-shot setup (Docker, nvidia-container-runtime,
  udev rules, MAXN power mode, swap)
- scripts/build-and-run.sh: build/up/down/shell/slam/status helper

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:46:14 -05:00
cd9299ded8 feat: parametric chassis frame design (bd-1iy5)
OpenSCAD parametric model for SaltyBot two-wheeled self-balancing robot chassis:
- 600mm wheelbase, 170mm hoverboard hub motor fork dropouts
- MAMBA F722S FC mount (30.5x30.5mm M3 pattern, 6mm nylon standoffs)
- Battery tray for 24V 4Ah pack (185x72x52mm) with strap slots + vent holes
- Jetson Nano B01 mount plate (58x58mm M3 pattern, 8mm standoffs)
- Front/rear bumper brackets with 22mm EMT conduit saddle clamps
- Longitudinal ribs, lightening holes, cable routing slots
- BOM (32 line items) and step-by-step assembly notes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:45:40 -05:00
0bfd617c44 fix(usb): resolve USB CDC TX failure caused by three independent bugs
Bug 1 (PRIMARY — DCache/USB coherency):
SCB_DisableDCache() was buried inside icm42688_init(), called ~3.5s
after USB starts. STM32F7 DCache/USB coherency issue: when DCache is
on (enabled by SystemInit()), CPU writes to TX buffers stay in cache
and the USB hardware reads stale SRAM data. Moved SCB_DisableDCache()
to main() before HAL_Init(), ensuring coherency for all USB transfers.

Bug 2 (USB TX corruption):
CDC_Transmit() passed the caller's stack-allocated buf pointer directly
to the USB stack. The USB TXFE interrupt fires asynchronously; by then
the stack buffer may have been modified by the next loop iteration.
CDC_Transmit() now copies into the static UserTxBuffer before handing
off to the USB hardware, ensuring the buffer is stable for the transfer.

Bug 3 (IMU type mismatch → wrong data to balance):
main.c called icm42688_init()/icm42688_read() directly, passing
icm42688_data_t* (raw int16 ax/ay/az/gx/gy/gz) to balance_update()
which expects IMUData* (float pitch/pitch_rate from complementary
filter). Type mismatch produced garbage balance values. Fixed by using
mpu6000_init()/mpu6000_read() which wraps icm42688 + sensor fusion.
Telemetry updated to report fused pitch/rate instead of raw ADC counts.

Also fix icm42688_init() returning 0 on who==0 (no SPI response),
which falsely indicated IMU success.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:37:24 -05:00
00d62a621e bd-wax: add SLAM setup technical plan for Jetson Nano + D435i + RPLIDAR
Scopes Phase 2 perception/SLAM integration:
- RTAB-Map (primary) + ORB-SLAM3 (fallback) recommendation with rationale
- Docker/Humble strategy on JetPack 4.6 (avoids OS reflash)
- ROS2 node graph, static TF frame, sensor params for Nano power budget
- Phased milestones: 2a SLAM bring-up, 2b Nav2 integration (separate bead)
- Power budget analysis and mitigation steps for 10W Nano constraint

Closes: bd-wax (scoping only — implementation tracking in Phase 2a checklist)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 12:17:19 -05:00
Sebastien Vayrette
0afdaea2e1 Add USB CDC bug doc and team requirements 2026-02-28 11:59:53 -05:00
Sebastien Vayrette
ba3e1161b9 Balance firmware + USB CDC bug 2026-02-28 11:58:23 -05:00