diff --git a/.claude/plans/floofy-forging-hellman.md b/.claude/plans/floofy-forging-hellman.md new file mode 100644 index 0000000..98efa39 --- /dev/null +++ b/.claude/plans/floofy-forging-hellman.md @@ -0,0 +1,208 @@ +# Issue #194 — Speed Limiter Node Implementation Plan + +## Context + +The SaltyBot control stack currently lacks a dedicated speed limiting aggregator. Individual subsystems publish speed scale factors: +- **TerrainAdaptationNode** → `/saltybot/terrain_speed_scale` (Float32, 0.15–1.0) +- **EmergencyNode** → `/saltybot/emergency` (EmergencyEvent with severity level) +- Hypothetical external source → `/saltybot/speed_limit` (to be determined) + +These must be unified into a single authoritative speed scale and applied to `/cmd_vel` before forwarding to the drive system. Currently, each subsystem is independent, creating potential conflicts and inconsistent behavior. + +## Goal + +Create `saltybot_speed_limiter` ROS2 package that: +1. Subscribes to terrain_speed_scale, speed_limit, and emergency signals +2. Computes effective minimum speed scale from all three inputs +3. Applies scale to /cmd_vel messages → /saltybot/cmd_vel_limited +4. Publishes diagnostic JSON on /saltybot/speed_limit_info +5. Operates at 50 Hz with proper message synchronization + +## Architecture + +### Subscriptions + +| Topic | Type | Source | Frequency | Use | +|-------|------|--------|-----------|-----| +| `/saltybot/terrain_speed_scale` | Float32 | TerrainAdaptationNode | 50Hz | Terrain-based scaling (0.15–1.0) | +| `/saltybot/speed_limit` | Float32 | External (TBD) | ≥10Hz | Global speed limit (0.0–1.0) | +| `/saltybot/emergency` | EmergencyEvent | EmergencyNode | 20Hz | Emergency severity level | +| `/cmd_vel` | Twist | SpeedControllerNode | ≥20Hz | Raw commanded velocity | + +### Outputs + +| Topic | Type | Frequency | Content | +|-------|------|-----------|---------| +| `/saltybot/cmd_vel_limited` | Twist | 50Hz | Scaled cmd_vel | +| `/saltybot/speed_limit_info` | String (JSON) | 50Hz | Diagnostic state | + +### Message Types + +**EmergencyEvent** (from saltybot_emergency_msgs): +``` +string severity # "CLEAR"|"MINOR"|"MAJOR"|"CRITICAL" +``` + +**speed_limit_info JSON**: +```json +{ + "terrain_scale": 0.638, + "speed_limit": 1.0, + "emergency_scale": 1.0, + "effective_scale": 0.638, + "cmd_vel_input": {"linear": 1.0, "angular": 0.5}, + "cmd_vel_limited": {"linear": 0.638, "angular": 0.319}, + "timestamp": 1740000000.123456 +} +``` + +### Control Logic + +```python +# Emergency severity → speed scale mapping +emergency_scale = { + "CLEAR": 1.0, + "MINOR": 0.95, # Yellow alert: slight caution + "MAJOR": 0.7, # Orange alert: significant slowdown + "CRITICAL": 0.3, # Red alert: severe limitation +} + +# Effective scale = minimum of all sources +effective_scale = min( + terrain_scale, # From /saltybot/terrain_speed_scale + speed_limit, # From /saltybot/speed_limit + emergency_scale, # From /saltybot/emergency severity +) + +# Apply to all cmd_vel components +cmd_vel_limited.linear.x *= effective_scale +cmd_vel_limited.linear.y *= effective_scale +cmd_vel_limited.linear.z *= effective_scale +cmd_vel_limited.angular.x *= effective_scale +cmd_vel_limited.angular.y *= effective_scale +cmd_vel_limited.angular.z *= effective_scale +``` + +## Implementation Details + +### Package Structure + +``` +saltybot_speed_limiter/ +├── CMakeLists.txt +├── package.xml +├── setup.py +├── README.md +├── launch/ +│ └── speed_limiter.launch.py +├── resource/ +│ └── saltybot_speed_limiter +├── saltybot_speed_limiter/ +│ ├── __init__.py +│ └── speed_limiter_node.py +├── config/ +│ └── speed_limiter_params.yaml +└── test/ + ├── __init__.py + └── test_speed_limiter.py +``` + +### Key Implementation Points + +1. **Message Synchronization**: Use `message_filters.ApproximateTimeSynchronizer` to align terrain_scale, speed_limit, emergency, and cmd_vel with small slop tolerance (50–100ms @ 50Hz) + +2. **State Management**: + - Store latest values for each input (timeout handling if stale) + - Fallback to safe defaults if messages stop arriving: + - terrain_scale → 1.0 (no scaling) + - speed_limit → 1.0 (no limit) + - emergency → "CLEAR" (no threat) + +3. **Parameters**: + - `publish_hz`: 50.0 (fixed, not tunable) + - `sync_slop_ms`: 100 (ApproximateTimeSynchronizer slop) + - `timeout_s`: 2.0 (signal timeout) + - `frame_id`: 'base_link' + - Emergency scale map (tunable per severity) + +4. **Performance**: + - Small package, minimal computation (3 float comparisons + geometry scaling) + - No heavy libraries (just numpy for Twist scaling) + +### Unit Tests + +Test file: `test/test_speed_limiter.py` + +Coverage: +- Min-of-three logic (all combinations) +- Twist scaling on all 6 components +- Emergency severity mapping (CLEAR, MINOR, MAJOR, CRITICAL) +- Timeout/stale handling (graceful fallback) +- JSON output structure and values +- Message synchronization edge cases + +### Integration Points + +**Upstream** (inputs): +- SpeedControllerNode → `/cmd_vel` +- TerrainAdaptationNode → `/saltybot/terrain_speed_scale` +- EmergencyNode → `/saltybot/emergency` + +**Downstream** (outputs): +- CmdVelBridgeNode ← `/saltybot/cmd_vel_limited` (replaces `/cmd_vel`) + +**Migration Path**: +1. CmdVelBridgeNode currently reads `/cmd_vel` +2. After speed_limiter is ready: modify CmdVelBridgeNode to read `/saltybot/cmd_vel_limited` instead +3. Or: use ROS2 topic remapping in launch files during transition + +## Files to Create + +1. **saltybot_speed_limiter/speed_limiter_node.py** (~200 lines) + - SpeedLimiterNode class + - Message synchronization with fallback logic + - Scale computation and Twist application + - JSON diagnostic publishing + +2. **test/test_speed_limiter.py** (~150 lines) + - Min-of-three logic tests + - Twist scaling verification + - Emergency map tests + - Timeout/stale handling tests + +3. **launch/speed_limiter.launch.py** (~40 lines) + - Configurable parameters + - QoS setup + +4. **config/speed_limiter_params.yaml** (~20 lines) + - Emergency severity scales + - Timeout and sync parameters + +5. **package.xml, setup.py, CMakeLists.txt, README.md, resource/** (~150 lines total) + - Standard ROS2 package boilerplate + +## Verification Plan + +1. **Unit Tests**: Run pytest on test_speed_limiter.py (expect 15+ tests, all pass) +2. **Package Build**: `colcon build --packages-select saltybot_speed_limiter` +3. **Node Launch**: `ros2 launch saltybot_speed_limiter speed_limiter.launch.py` +4. **Manual Testing** (hardware): + - Subscribe to /saltybot/cmd_vel_limited and verify scaling + - Inject different terrain_scale, speed_limit, emergency values + - Confirm effective_scale = min(all three) + - Verify JSON diagnostic content + +## Branch & Commit Strategy + +1. Branch: `sl-controls/issue-194-speed-limiter` from main +2. Commit: Single commit with all 10 files +3. PR: To main branch with detailed description +4. MQTT Report: Send status to max after merge + +## Key Decisions + +- **Min-of-three logic** (not weighted average): Ensures safety — most conservative limit wins +- **Separate topic output** (`/saltybot/cmd_vel_limited`): Preserves original /cmd_vel for debugging +- **Emergency severity levels** (CLEAR/MINOR/MAJOR/CRITICAL): Map to scales 1.0/0.95/0.7/0.3 (can tune) +- **ApproximateTimeSynchronizer**: Handles async inputs at different rates +- **JSON string output** (not typed message): Easy to parse in logging/MQTT system diff --git a/.claude/plans/humming-watching-toast.md b/.claude/plans/humming-watching-toast.md new file mode 100644 index 0000000..a6435d6 --- /dev/null +++ b/.claude/plans/humming-watching-toast.md @@ -0,0 +1,140 @@ +# Plan: SaltyRover STM32 Firmware Variant + +## Context +SaltyRover is the 4-wheel-drive variant of SaltyBot. It uses the same STM32F722 MCU, CRSF RC, USB CDC, safety systems, and IMU — but replaces the balance PID loop with direct 4-wheel independent motor commands. Two hoverboard ESCs are used: front axle on USART2 (same as balance bot), rear axle on UART5 (PC12/PD2). + +saltyrover-dev is 16 commits behind main and lacks: mode_manager, remote e-stop (PR #69), jetson_cmd updates, and some CDC additions. We'll apply all relevant current main-equivalent features on the new branch. + +## Branch +- Source: `origin/saltyrover-dev` +- Branch name: `sl-firmware/rover-firmware` +- PR target: `saltyrover-dev` + +## Files to Create + +### `include/rover_driver.h` +Public API for the 4-wheel rover motor layer: +```c +typedef struct { + int16_t fl, fr, rl, rr; /* last wheel commands (-1000..+1000) */ + bool armed; + bool estop; + uint32_t last_cmd_ms; /* HAL_GetTick() of last set_cmd() call */ +} rover_driver_t; + +void rover_driver_init(rover_driver_t *r); +void rover_driver_set_cmd(rover_driver_t *r, int16_t fl, int16_t fr, int16_t rl, int16_t rr, uint32_t now); +void rover_driver_update(rover_driver_t *r, uint32_t now); /* call at 50Hz */ +void rover_driver_arm(rover_driver_t *r); +void rover_driver_disarm(rover_driver_t *r); +void rover_driver_estop(rover_driver_t *r); +void rover_driver_estop_clear(rover_driver_t *r); +``` + +### `src/rover_driver.c` +Implementation — two hoverboard ESC control: +- `rover_driver_init()`: calls existing `hoverboard_init()` (USART2 front), adds UART5 init for rear (HAL_UART_Init at 115200, PC12/PD2) +- `rover_driver_update()` at 50Hz: + - estop or disarmed → send (0,0) to both ESCs + - armed → compute `front_spd=(fl+fr)/2`, `front_str=(fr-fl)/2`, `rear_spd=(rl+rr)/2`, `rear_str=(rr-rl)/2`; clamp each to ±ROVER_SPEED_MAX + - If `now - last_cmd_ms > ROVER_CMD_TIMEOUT_MS` → zero commands (safety fallback) + - Calls `hoverboard_send(front_spd, front_str)` for USART2 + - Calls local `hoverboard2_send(rear_spd, rear_str)` for UART5 (static function in rover_driver.c, same 8-byte protocol) + +## Files to Modify + +### `include/config.h` +Add rover-specific constants section: +```c +/* --- SaltyRover 4WD --- */ +#define ROVER_MAX_TILT_DEG 45.0f /* ESC estop angle (vs 25° balance cutoff) */ +#define ROVER_CMD_TIMEOUT_MS 500 /* Zero wheels if no Jetson cmd for 500ms */ +#define ROVER_SPEED_MAX 800 /* Max per-wheel command (ESC units) */ +``` + +### `include/safety.h` + `src/safety.c` +Apply PR #69 remote-estop additions (same as main): `EstopSource` enum, `safety_remote_estop/clear/get/active()`, `s_estop_source` static. These are already on main but not saltyrover-dev — include them here. + +### `lib/USB_CDC/src/usbd_cdc_if.c` + `include/usbd_cdc_if.h` +Apply PR #69 CDC additions: `cdc_estop_request`, `cdc_estop_clear_request`, cases 'E'/'F'/'Z'. + +Add rover JSON command handling: +```c +volatile uint8_t rover_json_ready = 0; +volatile char rover_json_buf[80]; +// In CDC_Receive: +case '{': { + uint32_t n = *len < 79 ? *len : 79; + for (uint32_t i = 0; i < n; i++) rover_json_buf[i] = (char)buf[i]; + rover_json_buf[n] = '\0'; + rover_json_ready = 1; + jetson_hb_tick = HAL_GetTick(); /* JSON cmd refreshes heartbeat */ + break; +} +``` + +Export in header: `extern volatile uint8_t rover_json_ready; extern volatile char rover_json_buf[80];` + +### `src/main.c` +Full replacement of the main loop. Keep all init (clock, USB, IMU, CRSF, I2C sensors, safety), strip `balance_t`, replace with `rover_driver_t`. Key loop logic: + +**Per-iteration (1ms):** +1. `safety_refresh()` — IWDG feed +2. `mpu6000_read(&imu)` — IMU read +3. `mode_manager_update(&mode, now)` — RC liveness + CH6 mode +4. Remote e-stop block (from PR #69): `cdc_estop_request` → `rover_driver_estop()` +5. Tilt watchdog: `if (fabsf(imu.pitch) > ROVER_MAX_TILT_DEG) rover_driver_estop()` +6. RC CH5 arm/disarm (same hold interlock; pitch check relaxed to `< ROVER_MAX_TILT_DEG`) +7. USB arm/disarm (A/D commands) +8. Parse `rover_json_ready`: `sscanf(rover_json_buf, ...)` for `drive4` cmd → `rover_driver_set_cmd()` +9. RC direct drive fallback (MANUAL mode): CH3→speed all 4 wheels, CH4→differential steer + +**50Hz ESC block:** +```c +if (rover.armed && !rover.estop) { + // If Jetson active: use stored fl/fr/rl/rr + // If RC MANUAL: compute fl=fr=rl=rr=speed, add steer diff + rover_driver_update(&rover, now); +} else { + rover_driver_update(&rover, now); // sends zeros +} +``` + +**50Hz telemetry:** +```json +{"p":,"r":,"s":,"fl":,"fr":,"rl":,"rr":,"md":,"es":,"txc":,"rxc":} +``` +Optional fields: heading, altitude/temp/pressure (same as balance bot). + +**Status LEDs:** Same `status_update(now, imu_ok, rover.armed, |pitch|>ROVER_MAX_TILT_DEG, safety_remote_estop_active())` + +**Arm guard:** `|pitch_deg| < ROVER_MAX_TILT_DEG` (45°) instead of `< 10.0f` + +## Key Architectural Differences vs Balance Bot + +| | Balance Bot | SaltyRover | +|---|---|---| +| PID loop | 1kHz balance PID | None | +| Motor cmd | `bal.motor_cmd` | Individual fl/fr/rl/rr | +| ESCs | 1× USART2 | 2× USART2 + UART5 | +| Tilt cutoff | 25° (balance state) | 45° (simple estop only) | +| Drive cmd | `C,\n` | `{"cmd":"drive4",...}` JSON | +| Arm pitch guard | `< 10°` | `< 45°` | +| State machine | DISARMED/ARMED/TILT_FAULT | armed bool + estop bool | + +## Test Plan +1. Build: `pio run -e saltyrover` (or equivalent) — confirms compile +2. Hardware: send `{"cmd":"drive4","fl":200,"fr":200,"rl":200,"rr":200}` → all 4 wheels spin forward +3. Estop: send `E\n` → wheels stop, LED fast-blinks 200ms; `Z\n` + RC arm → resumes +4. Tilt: tilt rover >45° → wheels cut immediately; no cut at 30° +5. RC manual: CH5 arm + CH3/CH4 → wheels respond; CH5 disarm → stop +6. Telemetry: verify `"fl"/"fr"/"rl"/"rr"` in JSON stream, `"es"` field changes on estop + +## Critical Files +- `src/main.c` — rover main loop (full rewrite of loop body) +- `include/rover_driver.h` — new file +- `src/rover_driver.c` — new file (UART5 init + two-ESC update) +- `include/config.h` — rover constants +- `include/safety.h` + `src/safety.c` — remote estop additions +- `lib/USB_CDC/src/usbd_cdc_if.c` — JSON '{' case + estop flags +- `lib/USB_CDC/include/usbd_cdc_if.h` — export new flags diff --git a/jetson/ros2_ws/src/saltybot_accel_limiter/saltybot_accel_limiter/__pycache__/accel_limiter_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_accel_limiter/saltybot_accel_limiter/__pycache__/accel_limiter_node.cpython-314.pyc new file mode 100644 index 0000000..3f5e3a4 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_accel_limiter/saltybot_accel_limiter/__pycache__/accel_limiter_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_accel_limiter/test/__pycache__/test_accel_limiter.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_accel_limiter/test/__pycache__/test_accel_limiter.cpython-314.pyc new file mode 100644 index 0000000..11b1f9d Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_accel_limiter/test/__pycache__/test_accel_limiter.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_battery_speed_scaler/saltybot_battery_speed_scaler/__pycache__/battery_speed_scaler_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_battery_speed_scaler/saltybot_battery_speed_scaler/__pycache__/battery_speed_scaler_node.cpython-314.pyc new file mode 100644 index 0000000..f59a046 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_battery_speed_scaler/saltybot_battery_speed_scaler/__pycache__/battery_speed_scaler_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_battery_speed_scaler/test/__pycache__/test_battery_speed_scaler.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_battery_speed_scaler/test/__pycache__/test_battery_speed_scaler.cpython-314.pyc new file mode 100644 index 0000000..d79caf5 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_battery_speed_scaler/test/__pycache__/test_battery_speed_scaler.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_cellular/test/__pycache__/test_cellular.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_cellular/test/__pycache__/test_cellular.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..5e287ad Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_cellular/test/__pycache__/test_cellular.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_compass/saltybot_compass/__pycache__/compass_heading_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_compass/saltybot_compass/__pycache__/compass_heading_node.cpython-314.pyc new file mode 100644 index 0000000..fbca056 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_compass/saltybot_compass/__pycache__/compass_heading_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_compass/test/__pycache__/test_compass_heading.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_compass/test/__pycache__/test_compass_heading.cpython-314.pyc new file mode 100644 index 0000000..73e4f45 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_compass/test/__pycache__/test_compass_heading.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_follower/test/__pycache__/test_person_follower.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_follower/test/__pycache__/test_person_follower.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..5334ef4 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_follower/test/__pycache__/test_person_follower.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_motor_protection/saltybot_motor_protection/__pycache__/motor_protection_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_motor_protection/saltybot_motor_protection/__pycache__/motor_protection_node.cpython-314.pyc new file mode 100644 index 0000000..3a88438 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_motor_protection/saltybot_motor_protection/__pycache__/motor_protection_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_motor_protection/test/__pycache__/test_motor_protection.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_motor_protection/test/__pycache__/test_motor_protection.cpython-314.pyc new file mode 100644 index 0000000..82642fe Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_motor_protection/test/__pycache__/test_motor_protection.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_odom_fusion/saltybot_odom_fusion/__pycache__/odom_fusion_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_odom_fusion/saltybot_odom_fusion/__pycache__/odom_fusion_node.cpython-314.pyc new file mode 100644 index 0000000..d8f4104 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_odom_fusion/saltybot_odom_fusion/__pycache__/odom_fusion_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_odom_fusion/test/__pycache__/test_odom_fusion.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_odom_fusion/test/__pycache__/test_odom_fusion.cpython-314.pyc new file mode 100644 index 0000000..9a7153d Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_odom_fusion/test/__pycache__/test_odom_fusion.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_pid_autotune/saltybot_pid_autotune/__pycache__/pid_autotune_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_pid_autotune/saltybot_pid_autotune/__pycache__/pid_autotune_node.cpython-314.pyc new file mode 100644 index 0000000..0217eaa Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_pid_autotune/saltybot_pid_autotune/__pycache__/pid_autotune_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_pid_autotune/test/__pycache__/test_pid_autotune.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_pid_autotune/test/__pycache__/test_pid_autotune.cpython-314.pyc new file mode 100644 index 0000000..1144e58 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_pid_autotune/test/__pycache__/test_pid_autotune.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/__init__.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..8694044 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/__init__.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/seg_utils.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/seg_utils.cpython-314.pyc new file mode 100644 index 0000000..7d007e6 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_segmentation/saltybot_segmentation/__pycache__/seg_utils.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_segmentation/test/__pycache__/test_seg_utils.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_segmentation/test/__pycache__/test_seg_utils.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..e49738e Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_segmentation/test/__pycache__/test_seg_utils.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/__init__.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..46a6b78 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/__init__.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/ambient_sound_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/ambient_sound_node.cpython-314.pyc new file mode 100644 index 0000000..85bad48 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/ambient_sound_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/emotion_classifier.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/emotion_classifier.cpython-314.pyc new file mode 100644 index 0000000..635e1a0 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/emotion_classifier.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/gesture_classifier.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/gesture_classifier.cpython-314.pyc new file mode 100644 index 0000000..5283524 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/gesture_classifier.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/greeting_trigger_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/greeting_trigger_node.cpython-314.pyc new file mode 100644 index 0000000..cd8c72c Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/greeting_trigger_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/llm_context.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/llm_context.cpython-314.pyc new file mode 100644 index 0000000..ad8d257 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/llm_context.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/speech_utils.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/speech_utils.cpython-314.pyc new file mode 100644 index 0000000..a58aae9 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/speech_utils.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/tts_utils.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/tts_utils.cpython-314.pyc new file mode 100644 index 0000000..b90826b Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/tts_utils.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/vad_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/vad_node.cpython-314.pyc new file mode 100644 index 0000000..fe0a9f1 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/vad_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/voice_command_parser.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/voice_command_parser.cpython-314.pyc new file mode 100644 index 0000000..5d96ee1 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/saltybot_social/__pycache__/voice_command_parser.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/__init__.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..663160c Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/__init__.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_ambient_sound.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_ambient_sound.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..309d884 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_ambient_sound.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_emotion_classifier.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_emotion_classifier.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..6892c22 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_emotion_classifier.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_gesture_classifier.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_gesture_classifier.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..37a1058 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_gesture_classifier.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_greeting_trigger.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_greeting_trigger.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..bd87d4c Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_greeting_trigger.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_llm_context.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_llm_context.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..eb40950 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_llm_context.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_mesh_comms.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_mesh_comms.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..3773ec5 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_mesh_comms.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_multilang.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_multilang.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..d4db86d Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_multilang.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_speech_utils.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_speech_utils.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..8ea7a80 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_speech_utils.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_vad_node.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_vad_node.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..122c9d9 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_vad_node.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_voice_command_parser.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_voice_command_parser.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..fa618fb Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social/test/__pycache__/test_voice_command_parser.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/mood_engine.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/mood_engine.cpython-314.pyc new file mode 100644 index 0000000..8dc840b Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/mood_engine.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/relationship_db.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/relationship_db.cpython-314.pyc new file mode 100644 index 0000000..46cef6e Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/relationship_db.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/soul_loader.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/soul_loader.cpython-314.pyc new file mode 100644 index 0000000..3148e0c Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social_personality/saltybot_social_personality/__pycache__/soul_loader.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_social_personality/test/__pycache__/test_personality.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_social_personality/test/__pycache__/test_personality.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..7738d6c Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_social_personality/test/__pycache__/test_personality.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_speed_controller/test/__pycache__/test_speed_controller.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_speed_controller/test/__pycache__/test_speed_controller.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..e4aeb07 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_speed_controller/test/__pycache__/test_speed_controller.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_speed_limiter/saltybot_speed_limiter/__pycache__/speed_limiter_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_speed_limiter/saltybot_speed_limiter/__pycache__/speed_limiter_node.cpython-314.pyc new file mode 100644 index 0000000..d90a148 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_speed_limiter/saltybot_speed_limiter/__pycache__/speed_limiter_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_speed_limiter/test/__pycache__/test_speed_limiter.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_speed_limiter/test/__pycache__/test_speed_limiter.cpython-314.pyc new file mode 100644 index 0000000..4b926b5 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_speed_limiter/test/__pycache__/test_speed_limiter.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_thermal/saltybot_thermal/__pycache__/thermal_node.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_thermal/saltybot_thermal/__pycache__/thermal_node.cpython-314.pyc new file mode 100644 index 0000000..5158ac5 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_thermal/saltybot_thermal/__pycache__/thermal_node.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_thermal/test/__pycache__/test_thermal.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_thermal/test/__pycache__/test_thermal.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..374b6f7 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_thermal/test/__pycache__/test_thermal.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/__init__.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..8145ba9 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/__init__.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/ranging_math.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/ranging_math.cpython-314.pyc new file mode 100644 index 0000000..24f3d57 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_uwb/saltybot_uwb/__pycache__/ranging_math.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_uwb/test/__pycache__/test_ranging_math.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_uwb/test/__pycache__/test_ranging_math.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..4c25b20 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_uwb/test/__pycache__/test_ranging_math.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/__init__.cpython-314.pyc b/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000..dc82f52 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/__init__.cpython-314.pyc differ diff --git a/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/test_wheel_odom.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/test_wheel_odom.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..86974a9 Binary files /dev/null and b/jetson/ros2_ws/src/saltybot_wheel_odom/test/__pycache__/test_wheel_odom.cpython-314-pytest-9.0.2.pyc differ diff --git a/jetson/ros2_ws/src/saltyrover_drive/test/__pycache__/test_rover_drive.cpython-314-pytest-9.0.2.pyc b/jetson/ros2_ws/src/saltyrover_drive/test/__pycache__/test_rover_drive.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..fbcee0d Binary files /dev/null and b/jetson/ros2_ws/src/saltyrover_drive/test/__pycache__/test_rover_drive.cpython-314-pytest-9.0.2.pyc differ diff --git a/scripts/__pycache__/flash_firmware.cpython-314.pyc b/scripts/__pycache__/flash_firmware.cpython-314.pyc new file mode 100644 index 0000000..c5fb187 Binary files /dev/null and b/scripts/__pycache__/flash_firmware.cpython-314.pyc differ diff --git a/test/__pycache__/test_audio.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_audio.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..55e9ea4 Binary files /dev/null and b/test/__pycache__/test_audio.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_bno055_data.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_bno055_data.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..d366685 Binary files /dev/null and b/test/__pycache__/test_bno055_data.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_buzzer.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_buzzer.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..0a30338 Binary files /dev/null and b/test/__pycache__/test_buzzer.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_crsf_frames.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_crsf_frames.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..57bde41 Binary files /dev/null and b/test/__pycache__/test_crsf_frames.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_ina219.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_ina219.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..fd0aa55 Binary files /dev/null and b/test/__pycache__/test_ina219.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_jlink_frames.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_jlink_frames.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..8f08626 Binary files /dev/null and b/test/__pycache__/test_jlink_frames.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_led.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_led.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..2471091 Binary files /dev/null and b/test/__pycache__/test_led.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_ota.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_ota.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..dac18b0 Binary files /dev/null and b/test/__pycache__/test_ota.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_power_mgmt.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_power_mgmt.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..86b8c80 Binary files /dev/null and b/test/__pycache__/test_power_mgmt.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/__pycache__/test_servo.cpython-314-pytest-9.0.2.pyc b/test/__pycache__/test_servo.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000..2ef3f3e Binary files /dev/null and b/test/__pycache__/test_servo.cpython-314-pytest-9.0.2.pyc differ diff --git a/test/test_buzzer b/test/test_buzzer new file mode 100755 index 0000000..afb2e11 Binary files /dev/null and b/test/test_buzzer differ diff --git a/test/test_fan b/test/test_fan new file mode 100755 index 0000000..1b28b6f Binary files /dev/null and b/test/test_fan differ diff --git a/test/test_ultrasonic b/test/test_ultrasonic new file mode 100755 index 0000000..4475850 Binary files /dev/null and b/test/test_ultrasonic differ diff --git a/test_fan b/test_fan new file mode 100755 index 0000000..00c6830 Binary files /dev/null and b/test_fan differ