291dd689f8
feat: remove all STM32/Mamba/BlackPill references — ESP32-S3 only
...
Archive STM32 firmware to legacy/stm32/:
- src/, include/, lib/USB_CDC/, platformio.ini, test stubs, flash_firmware.py
- test/test_battery_adc.c, test_hw_button.c, test_pid_schedule.c, test_vesc_can.c, test_can_watchdog.c
- USB_CDC_BUG.md
Rename: stm32_protocol → esp32_protocol, mamba_protocol → balance_protocol,
stm32_cmd_node → esp32_cmd_node, stm32_cmd_params → esp32_cmd_params,
stm32_cmd.launch.py → esp32_cmd.launch.py,
test_stm32_protocol → test_esp32_protocol, test_stm32_cmd_node → test_esp32_cmd_node
Content cleanup across all files:
- Mamba F722S → ESP32-S3 BALANCE
- BlackPill → ESP32-S3 IO
- STM32F722/F7xx → ESP32-S3
- stm32Mode/Version/Port → esp32Mode/Version/Port
- STM32 State/Mode labels → ESP32 State/Mode
- Jetson Nano → Jetson Orin Nano Super
- /dev/stm32 → /dev/esp32
- stm32_bridge → esp32_bridge
- STM32 HAL → ESP-IDF
docs/SALTYLAB.md:
- Update "Drone FC Details" to describe ESP32-S3 BALANCE board (Waveshare ESP32-S3 Touch LCD 1.28)
- Replace verbose "Self-Balancing Control" STM32 section with brief note pointing to SAUL-TEE-SYSTEM-REFERENCE.md
TEAM.md: Update Embedded Firmware Engineer role to ESP32-S3 / ESP-IDF
No new functionality — cleanup only.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 08:41:26 -04:00
7db6158ada
Merge pull request 'feat: Robot GPS live map panel (Issue #709 companion)' ( #711 ) from sl-webui/robot-gps-map into main
2026-04-03 22:43:56 -04:00
f0d9fead74
Merge pull request 'feat: Sul-Tee GPS live tracking dashboard (Issue #709 )' ( #710 ) from sl-webui/issue-709-gps-tracker into main
2026-04-03 22:43:55 -04:00
811a2ccc5c
fix(sultee-tracker): subscribe to proper ROS GPS topics for robot marker
...
Switch robot GPS subscription from custom saltybot/gps/* std_msgs/String
topics to the canonical /gps/fix (sensor_msgs/NavSatFix) and /gps/vel
(geometry_msgs/TwistStamped) published by the SIM7600X GPS driver node.
- /gps/fix: read msg.latitude/longitude/altitude/status.status directly
- /gps/vel: compute speed (sqrt(vx²+vy²) * 3.6 km/h) and heading
(angular.z radians → degrees) from ENU velocity components
Closes #709
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:41:47 -04:00
bb354336c3
feat(sultee-tracker): add dual device map — phone (blue) + robot (orange)
...
Previously showed only phone GPS. Now also subscribes via ROSLIB to
saltybot/gps/fix + saltybot/gps/vel on the same rosbridge URL for
robot (SAUL-TEE) position. Blue marker+trail for phone (raw WS
{type:gps}), orange marker+trail for robot (ROS topics). Sidebar shows
phone speed/alt/heading/accuracy + robot lat/lon/speed + distance
between the two. FIT ALL button auto-zooms to show both. Status bar
badges for phone staleness and robot fix/vel freshness.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:38:28 -04:00
6d047ca50c
feat(gps-map): add phone/user GPS as second marker on robot GPS map
...
Subscribes to saltybot/phone/gps (JSON: {ts, lat, lon, alt_m,
accuracy_m, speed_ms, bearing_deg, provider}) and renders a blue
Leaflet marker + blue breadcrumb trail alongside the robot's
orange/cyan marker. Status bar now shows PHONE badge with stale
detection. Sidebar adds phone lat/lon/speed/accuracy/provider section.
Clear button resets both trails.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:34:44 -04:00
f384cc4810
feat: Robot GPS live map panel (Issue #709 companion)
...
Adds gps_map_panel.html/css/js — standalone dashboard panel:
- Leaflet.js + OpenStreetMap with dark CSS filter (matches dashboard theme)
- Heading-aware SVG robot marker (orange arrow shows direction of travel)
- Orange breadcrumb trail polyline (up to 2000 pts, CLEAR button)
- FOLLOW mode auto-pan; drag map to switch to FREE mode
- Sidebar: speed (km/h, color-coded), altitude, heading compass rose,
fix status (0=NO FIX…4=RTK), fix count, lat/lon, trail log
- Exponential backoff auto-reconnect (2s→30s cap)
- Stale detection at 5s for fix + velocity badges
Subscribes via rosbridge to:
saltybot/gps/fix std_msgs/String JSON — {lat, lon, alt, stat, t}
saltybot/gps/vel std_msgs/String JSON — {spd, hdg, t}
index.html: new GPS MAP card (🛰️ , #709 ) before CAN MONITOR
dashboard.js: gpsWatch subscription + 'gps' panel entry
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 22:28:44 -04:00
2560718b39
feat: Sul-Tee GPS live tracking dashboard (Issue #709 )
...
Single-file vanilla JS dashboard at ui/sultee-tracker.html:
- Connects to ws://100.64.0.2:9090 (configurable, saved in localStorage)
- Parses {"type":"gps","data":{...},"timestamp":...} JSON frames from iPhone
- Leaflet.js + OpenStreetMap tiles with dark CSS filter
- Live position marker (cyan pulsing dot SVG icon)
- Orange polyline trail (up to 2000 points)
- Auto-centers on first GPS fix; FOLLOW/FREE toggle; drag disables follow
- Sidebar: speed (km/h, color-coded), altitude, heading, compass rose canvas,
h-accuracy bar (green/amber/red), coordinate display, fix count
- Scrollable trail log with timestamp + coords + speed per fix
- Exponential backoff auto-reconnect (2s→30s cap)
- CLEAR button resets trail, marker, log, fix count
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:12:37 -04:00
e220797c07
Merge pull request 'feat: CAN bus watchdog and error recovery (Issue #694 )' ( #708 ) from sl-firmware/issue-694-can-watchdog into main
2026-03-20 17:59:02 -04:00
b5354e1ac0
Merge pull request 'feat: PID tuning interface via CAN/ROS2 (Issue #693 )' ( #707 ) from sl-controls/issue-693-pid-tuning into main
2026-03-20 17:58:34 -04:00
f59bc9931e
feat: CAN bus watchdog and error recovery (Issue #694 )
...
- CAN1_SCE_IRQHandler: detects bus-off/error-passive/error-warning from ESR
- can_driver_watchdog_tick(): polls ESR each cycle, auto-restarts after CAN_WDOG_RESTART_MS (200ms)
- can_wdog_t: tracks restart_count, busoff_count, errpassive_count, errwarn_count, tec, rec
- JLink TLM code 0x8F (JLINK_TLM_CAN_WDOG) with jlink_send_can_wdog_tlm()
- main.c: calls watchdog_tick() each loop, sends CAN wdog TLM at 1 Hz
- TEST_HOST: inject_esr() stub + busoff_pending flag fixes t=0 sentinel ambiguity
- test/test_can_watchdog.c: 23 unit tests, all pass
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 17:39:01 -04:00
de4d1bbe3a
feat: PID tuning interface via CAN/ROS2 (Issue #693 )
...
- Mamba (STM32): add ORIN_CAN_ID_PID_SET (0x305) handler in orin_can.c.
Receives kp/ki/kd as uint16*100 (BE), applies to running balance loop,
replies with FC_PID_ACK (0x405) echoing clamped gains. Gains persist in
RAM until reboot; not saved to flash.
- Jetson: expose pid/kp, pid/ki, pid/kd as ROS2 parameters in
can_bridge_node. Parameter changes trigger encode_pid_set_cmd() and
send CAN frame 0x305 immediately. ACK frame 0x405 logged at DEBUG.
- mamba_protocol.py: add ORIN_CAN_ID_PID_SET / FC_PID_ACK IDs,
PidGains dataclass, encode_pid_set_cmd(), decode_pid_ack().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 17:39:00 -04:00
d235c414e0
Merge pull request 'feat: SLAM map persistence for AMCL (Issue #696 )' ( #705 ) from sl-perception/issue-696-slam-map-persistence into main
2026-03-20 17:38:29 -04:00
62d7525df7
Merge pull request 'feat: VESC dual ESC mount bracket for T-slot (Issue #699 )' ( #704 ) from sl-mechanical/issue-699-vesc-mount into main
2026-03-20 17:38:27 -04:00
2b3f3584a9
Merge pull request 'feat: End-to-end CAN integration tests (Issue #695 )' ( #703 ) from sl-jetson/issue-695-can-e2e-test into main
2026-03-20 17:38:25 -04:00
7a100b2d14
Merge pull request 'feat: WebSocket bridge for CAN monitor dashboard (Issue #697 )' ( #702 ) from sl-webui/issue-697-websocket-bridge into main
2026-03-20 17:38:23 -04:00
37b646780d
Merge pull request 'feat: Android BLE pairing UI for UWB tag (Issue #700 )' ( #701 ) from sl-android/issue-700-ble-pairing-ui into main
2026-03-20 17:38:22 -04:00
2d60aab79c
feat: SLAM map persistence for AMCL (Issue #696 )
...
- New map_persistence.launch.py: launches map_saver_server lifecycle node
(nav2_map_server) + saltybot_map_saver helper node + lifecycle_manager.
Configurable map_dir (default /mnt/nvme/saltybot/maps) and map_name.
- New map_saver_node.py: ROS2 node providing /saltybot/save_map (Trigger
service) that calls nav2_map_server map_saver_cli. On startup logs whether
a saved map is present. Auto-saves map on shutdown (auto_save_on_shutdown).
- New config/map_saver_params.yaml: map_saver_server params
(save_map_timeout=5s, free/occupied thresholds, transient-local QoS).
- nav2_slam_bringup.launch.py: adds map_dir + map_name args; includes
map_persistence.launch.py so map_saver_server runs during SLAM sessions.
- nav2_amcl_bringup.launch.py: adds map_dir arg; auto-detects saved map at
/mnt/nvme/saltybot/maps/saltybot_map.yaml at launch time and uses it as
the AMCL map; falls back to placeholder if not found.
- setup.py: registers map_persistence.launch.py, map_saver_params.yaml,
map_saver_node console_scripts entry point.
- test_nav2_amcl.py: 21 new tests covering params, launch syntax,
node service/shutdown behaviour, SLAM bringup inclusion, AMCL auto-detect.
Workflow:
1. ros2 launch saltybot_nav2_slam nav2_slam_bringup.launch.py (build map)
2. ros2 service call /saltybot/save_map std_srvs/srv/Trigger {} (save)
3. ros2 launch saltybot_nav2_slam nav2_amcl_bringup.launch.py (auto-loads)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:27:52 -04:00
af982bb575
feat: VESC dual ESC mount bracket (Issue #699 )
...
3D-printable PETG cradle for FSESC 6.7 Pro Mini Dual on 2020 T-slot rail.
4x M5 T-nut mounting, open-top heatsink exposure, XT60/XT30/CAN cutouts,
floor grille and side louvre ventilation, M3 heat-set insert posts for
board retention. No supports required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:26:07 -04:00
6d59baa30e
feat: End-to-end CAN integration tests (Issue #695 )
...
Add saltybot_can_e2e_test package with 64 tests covering the full
Orin↔Mamba↔VESC CAN pipeline: drive commands, heartbeat timeout,
e-stop escalation, mode switching, and FC_VESC status broadcasts.
Tests run with plain pytest — no ROS2 or real CAN hardware required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:25:23 -04:00
1ec4d3fc58
feat: WebSocket bridge for CAN monitor dashboard (Issue #697 )
...
rosbridge config:
- rosbridge_params.yaml: add /saltybot/barometer, /vesc/left/state,
/vesc/right/state to topics_glob whitelist (were missing, blocked
the CAN monitor panel from receiving data)
- can_monitor.launch.py: new lightweight launch — rosbridge only,
whitelist scoped to the 5 CAN monitor topics, port overridable via
launch arg (ros2 launch saltybot_bringup can_monitor.launch.py port:=9091)
can_monitor_panel.js auto-reconnect:
- Exponential backoff: 2s → 3s → 4.5s → ... → 30s cap (×1.5 factor)
- Countdown displayed in conn-label ("Retry in Xs…") during wait
- Backoff resets to 2s on successful connection
- Manual CONNECT / Enter resets backoff and cancels pending timer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:23:27 -04:00
sl-android
c6cf64217d
feat: Android BLE pairing UI for UWB tag (Issue #700 )
...
- UwbTagBleActivity: BLE scan filtered to 'UWB_TAG_XXXX' device names
- Connects to GATT service 12345678-1234-5678-1234-56789abcdef0
- Read/write JSON config char: sleep_timeout_s, display_brightness,
tag_name, uwb_channel, ranging_interval_ms, battery_report
- Subscribes to status + battery notification characteristics
- Material Design UI with scan list, config form, and live status
- Runtime BLE permission handling for API 26+ / API 31+
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 16:21:45 -04:00
5906af542b
Merge pull request 'feat: BME280 baro pressure & ambient temp (Issue #672 )' ( #673 ) from sl-firmware/issue-672-bme280-baro-temp into main
2026-03-18 08:27:39 -04:00
4318589496
feat: BME280 baro pressure & ambient temp driver (Issue #672 )
...
- New baro module (include/baro.h, src/baro.c): reads BME280/BMP280
at 1 Hz on I2C1, computes pressure altitude (ISA formula), publishes
JLINK_TLM_BARO (0x8D) telemetry to Orin. Runs entirely on Mamba F722S
with no Orin dependency. baro_get_alt_cm() exposes altitude to balance
PID slope compensation.
- New JLink telemetry frame 0x8D (jlink_tlm_baro_t, 12 bytes packed):
pressure_pa (int32), temp_x10 (int16), alt_cm (int32),
humidity_pct_x10 (int16; -1 = BMP280/absent).
- Wire into main.c: baro_init() after bmp280_init(), baro_tick(now)
each ms (self-rate-limits to 1 Hz).
- Unit tests (test/test_baro.c): 31 tests, all pass. Build:
gcc -I include -I test/stubs -DTEST_HOST -lm -o /tmp/test_baro test/test_baro.c
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 08:25:07 -04:00
441c56b1d9
Merge pull request 'feat: Hardware button park/disarm/re-arm (Issue #682 )' ( #688 ) from sl-firmware/issue-682-hw-button into main
2026-03-18 08:21:55 -04:00
334ab9249c
Merge pull request 'feat: CAN sensor remote monitor panel (Issue #681 )' ( #687 ) from sl-webui/issue-681-can-monitor into main
2026-03-18 08:10:41 -04:00
4affd6d0cb
feat: Hardware button park/disarm/re-arm (Issue #682 )
...
Add hw_button driver (PC2 active-low, 20ms debounce) with gesture detection:
- Single short press + 500ms quiet -> BTN_EVENT_PARK
- SHORT+SHORT+LONG combo (within 3s) -> BTN_EVENT_REARM_COMBO
New BALANCE_PARKED state: PID frozen, motors off, quick re-arm via button
combo without the 3-second arm interlock required from DISARMED.
FC_BTN (0x404) CAN frame sent to Orin on each event:
event_id 1=PARKED, 2=UNPARKED, 3=UNPARK_FAILED (pitch > 20 deg)
Includes 11 unit tests (1016 assertions) exercising debounce, bounce
rejection, short/long classification, sequence detection, and timeout.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 08:10:10 -04:00
fe979fdd1f
feat: CAN sensor remote monitor panel (Issue #681 )
...
Adds standalone vanilla JS/HTML/CSS panel for live CAN sensor monitoring:
- can_monitor_panel.html: 5-card dashboard grid with VESC L/R, Balance,
IMU Attitude (span-2), and Barometer cards
- can_monitor_panel.css: dark-theme styles matching existing panel suite;
bidirectional bars, live-dot flash, stat-grid, responsive layout
- can_monitor_panel.js: rosbridge subscriptions to
/vesc/left/state + /vesc/right/state (RPM bidir bar, current gauge,
voltage/duty/temp stats, fault badge, stale detection)
/saltybot/imu (quaternion→Euler, angular vel, lin accel, cal badge
from orientation_covariance[0], canvas artificial horizon + compass)
/saltybot/balance_state (state badge, motor_cmd bidir bar, PID grid)
/saltybot/barometer (altitude, pressure, temp)
Auto-connect from localStorage, 1 Hz stale checker, msg rate display
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 08:09:03 -04:00
9e8ea3c411
Merge pull request 'feat: VESC CAN health monitor (Issue #651 )' ( #666 ) from sl-jetson/issue-651-vesc-health into main
2026-03-18 08:03:32 -04:00
d57c0bd51d
feat: VESC CAN health monitor (Issue #651 )
...
New package: saltybot_vesc_health
- recovery_fsm.py: pure state machine (no ROS2/CAN deps; fully unit-tested)
- VescHealthState: HEALTHY → DEGRADED (>500 ms) → ESTOP (>2 s) / BUS_OFF
- VescMonitor.tick(): drives recovery sequence per VESC; startup-safe
- VescMonitor.on_frame(): resets state on CAN frame arrival
- VescMonitor.on_bus_off/on_bus_ok(): bus-off override + recovery
- HealthFsm: dual-VESC wrapper aggregating both monitors
- health_monitor_node.py: ROS2 node
- Subscribes /vesc/left/state + /vesc/right/state (JSON from vesc_telemetry)
- Sends GET_VALUES alive frames via SocketCAN on DEGRADED state
- Publishes /vesc/health (JSON, 10 Hz) — state, elapsed, recent faults
- Publishes /diagnostics (DiagnosticArray, OK/WARN/ERROR per VESC)
- Publishes /estop (JSON event) + zero /cmd_vel on e-stop trigger/clear
- Polls ip link for bus-off state (1 Hz)
- 200-entry fault event log included in /vesc/health
- test/test_vesc_health.py: 39 unit tests, all passing, no hardware needed
- config/vesc_health_params.yaml, launch/vesc_health.launch.py
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 08:03:19 -04:00
fdda6fe5ee
Merge pull request 'feat: Nav2 AMCL integration (Issue #655 )' ( #664 ) from sl-perception/issue-655-nav2-integration into main
2026-03-18 07:57:02 -04:00
3457919c7a
Merge pull request 'feat: UWB geofence speed limiting (Issue #657 )' ( #663 ) from sl-uwb/issue-657-geofence-speed-limit into main
2026-03-18 07:56:53 -04:00
cfdd74a9dc
Merge pull request 'feat: VESC motor dashboard panel (Issue #653 )' ( #662 ) from sl-webui/issue-653-vesc-panel into main
2026-03-18 07:56:43 -04:00
4f3a30d871
Merge pull request 'feat: Smooth velocity controller (Issue #652 )' ( #661 ) from sl-controls/issue-652-smooth-velocity into main
2026-03-18 07:56:26 -04:00
7eb3f187e2
feat: Smooth velocity controller (Issue #652 )
...
Adds velocity_smoother_node.py with configurable accel/decel ramps,
e-stop bypass, and optional jerk limiting. VESC driver updated to
subscribe /cmd_vel_smoothed instead of /cmd_vel.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 07:56:16 -04:00
sl-android
a50dbe7e56
feat: VESC CAN telemetry MQTT relay (Issue #656 )
...
Add vesc_mqtt_relay_node.py to saltybot_phone: subscribes to
/vesc/left/state, /vesc/right/state, /vesc/combined ROS2 topics and
publishes JSON telemetry to saltybot/phone/vesc_{left,right,combined}
MQTT topics at 5 Hz per motor. 32 unit tests, no ROS2/paho required.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 07:56:02 -04:00
6561e35fd6
Merge pull request 'feat: VESC MQTT telemetry relay (Issue #656 )' ( #660 ) from sl-android/issue-656-vesc-mqtt-relay into main
2026-03-18 07:55:42 -04:00
4dc75c8a70
Merge pull request 'feat: CANable 2.0 mount (Issue #654 )' ( #659 ) from sl-mechanical/issue-654-canable-mount into main
2026-03-18 07:55:31 -04:00
4d0a377cee
Merge pull request 'feat: VESC CAN odometry (Issue #646 )' ( #649 ) from sl-perception/issue-646-vesc-odometry into main
2026-03-18 07:55:17 -04:00
06101371ff
fix: Use correct VESC topic names /vesc/left|right/state (Issue #670 )
...
- VESCCANOdometryNode subscriptions now use left_state_topic/right_state_topic
params (defaulting to /vesc/left/state and /vesc/right/state) instead of
building /vesc/can_<id>/state from CAN IDs — those topics never existed
- Update right_can_id default: 79 → 68 (Mamba F722S architecture update)
- Update vesc_odometry_params.yaml: CAN IDs 61/79 → 56/68; add explicit
left_state_topic and right_state_topic entries; remove stale can_N comments
- All IDs remain fully configurable via ROS2 params
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 07:55:04 -04:00
cf0ceb4641
Merge pull request 'fix: Configurable VESC CAN IDs, default 56/68 (Issue #667 )' ( #668 ) from sl-controls/issue-667-configurable-can-ids into main
2026-03-18 07:50:33 -04:00
ee16bae9fb
fix: Make VESC CAN IDs configurable, default 56/68 (Issue #667 )
...
FSESC 6.7 Pro Mini Dual uses CAN IDs 56/68, not 61/79. Updates all
driver, telemetry, and odometry bridge files to use correct defaults.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-18 07:50:20 -04:00
70fa404437
Merge pull request 'fix: Standardize VESC topic naming (Issue #669 )' ( #671 ) from sl-jetson/issue-669-vesc-topic-fix into main
2026-03-18 07:49:20 -04:00
c11cbaf3e6
Merge pull request 'feat: IMU mount cal, CAN telemetry, LED CAN override (Issues #680 , #672 , #685 )' ( #686 ) from sl-jetson/issue-681-vesc-telemetry-publish into main
2026-03-18 07:49:12 -04:00
d132b74df0
Merge pull request 'fix: Move lines=[] above lock in _read_cb() (Issue #683 )' ( #684 ) from sl-jetson/issue-683-read-cb-fix into main
2026-03-18 07:49:02 -04:00
8985934f29
Merge pull request 'fix: Bump arm pitch threshold to 20° (Issue #678 )' ( #679 ) from sl-firmware/issue-678-pitch-threshold into main
2026-03-18 07:48:49 -04:00
9ed678ca35
feat: IMU mount angle cal, CAN telemetry, LED override (Issues #680 , #672 , #685 )
...
Issue #680 — IMU mount angle calibration:
- imu_cal_flash.h/.c: store pitch/roll offsets in flash sector 7
(0x0807FF00, 64 bytes; preserves PID records across sector erase)
- mpu6000_set_mount_offset(): subtracts offsets from pitch/roll output
- mpu6000_has_mount_offset(): reports cal_status=2 to Orin
- 'O' CDC command: capture current pitch/roll → save to flash → ACK JSON
- Load offsets on boot; report in printf log
CAN telemetry correction (Tee: production has no USB to Orin):
- FC_IMU (0x402): pitch/roll/yaw/cal_status/balance_state at 50 Hz
- orin_can_broadcast_imu() rate-limited to ORIN_IMU_TLM_HZ (50 Hz)
- FC_BARO (0x403): pressure_pa/temp_x10/alt_cm at 1 Hz (Issue #672 )
- orin_can_broadcast_baro() rate-limited to ORIN_BARO_TLM_HZ (1 Hz)
Issue #685 — LED CAN override:
- ORIN_CAN_ID_LED_CMD (0x304): pattern/brightness/duration_ms from Orin
- orin_can_led_override volatile state + orin_can_led_updated flag
- main.c: apply pattern to LED state machine on each LED_CMD received
Orin side:
- saltybot_can_node.py: production SocketCAN bridge — reads 0x400-0x403,
publishes /saltybot/imu, /saltybot/balance_state, /saltybot/barometer;
subscribes /cmd_vel → 0x301 DRIVE; /saltybot/leds → 0x304 LED_CMD;
sends 0x300 HEARTBEAT at 5 Hz; sends 0x303 ESTOP on shutdown
- setup.py: register saltybot_can_node entry point + uart_bridge launch
Fix: re-apply --defsym __stack_end=_estack-0x1000 linker fix to branch
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 22:49:21 -04:00
06db56103f
feat: Enable VESC driver telemetry publishing (Issue #681 )
...
vesc_driver_node.py:
- Add VescState dataclass with to_dict() serialization
- Add CAN_PACKET_STATUS/STATUS_4/STATUS_5 (9/16/27) RX constants
- Add FAULT_NAMES lookup (11 VESC FW 6.6 fault codes)
- Add background CAN RX thread (_rx_loop / _dispatch_frame) that
parses STATUS broadcast frames using struct.unpack
- Add publishers for /saltybot/vesc/left and /saltybot/vesc/right
(std_msgs/String JSON) at configurable telemetry_rate_hz (default 10 Hz)
- Combine watchdog + publish into single timer callback
- Proper thread cleanup in destroy_node()
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 22:49:06 -04:00
05ba557dca
fix: Move lines=[] above lock in _read_cb() (Issue #683 )
...
UnboundLocalError when _ser is None — lines was only assigned inside
the else branch. Move initialisation to function scope so the for-loop
outside the lock always has a valid list.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 22:36:20 -04:00
0a2f336eb8
Merge pull request 'feat: Orin CAN bus bridge — CANable 2.0 (Issue #674 )' ( #675 ) from sl-jetson/issue-674-can-bus-orin into main
2026-03-17 21:41:29 -04:00