284 Commits

Author SHA1 Message Date
f0e11fe7ca feat(bringup): depth image hole filler via bilateral interpolation (Issue #268)
Adds multi-pass spatial-Gaussian hole filler for D435i depth images.
Each pass replaces zero/NaN pixels with the Gaussian-weighted mean of valid
neighbours in a growing kernel (×1, ×2.5, ×6 default); original valid
pixels are never modified.  Handles uint16 mm → float32 m conversion,
border pixels via BORDER_REFLECT, and above-d_max pixels as holes.
Publishes filled float32 depth on /camera/depth/filled at camera rate.
37/37 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 14:19:27 -05:00
477258f321 Merge pull request 'feat(webui): waypoint editor with click-to-navigate (#261)' (#267) from sl-webui/issue-261-waypoint-editor-fix into main 2026-03-02 14:13:54 -05:00
94a6f0787e Merge pull request 'feat(bringup): visual odometry drift detector (Issue #260)' (#265) from sl-perception/issue-260-vo-drift into main 2026-03-02 14:13:34 -05:00
50636de5a9 Merge pull request 'feat(social): ambient sound classifier via mel-spectrogram (Issue #252)' (#258) from sl-jetson/issue-252-ambient-sound into main
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 11s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
2026-03-02 14:13:33 -05:00
c865e84e16 feat(webui): waypoint editor with click-to-navigate (Issue #261)
Interactive waypoint editor for Nav2 goal-based navigation:
- Click on map display to place waypoints
- Drag waypoints in list to reorder navigation sequence
- Right-click waypoints to delete them
- Visual waypoint overlay on map with numbering
- Robot position indicator at center
- Waypoint list sidebar with selection and ordering
- Send Nav2 goal to individual selected waypoint
- Execute all waypoints in sequence with automatic progression
- Clear all waypoints button
- Real-time coordinate display and robot pose tracking
- Integrated into new NAVIGATION tab group
- Uses /navigate_to_pose service for goal publishing

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 13:28:01 -05:00
9d12805843 feat(bringup): visual odometry drift detector (Issue #260)
Adds sliding-window drift detector that compares cumulative path lengths
of visual odom and wheel odom over a configurable window (default 10 s).
Drift = |vo_path − wheel_path|; flagged when ≥ 0.5 m (configurable).
OdomBuffer handles per-source rolling storage with automatic age eviction.
Publishes Bool on /saltybot/vo_drift_detected and Float32 on
/saltybot/vo_drift_magnitude at 2 Hz.  27/27 pure-Python tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 13:26:07 -05:00
03999e7f91 Merge pull request 'feat(webui): SLAM map viewer with occupancy grid (#250)' (#259) from sl-webui/issue-250-map-viewer into main 2026-03-02 13:22:40 -05:00
3cd9faeed9 feat(social): ambient sound classifier via mel-spectrogram — Issue #252
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (pull_request) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (pull_request) Has been cancelled
Adds ambient_sound_node to saltybot_social:
- Accumulates 1 s of PCM-16 audio from /social/speech/audio_raw
- Extracts mel-spectrogram feature vector (energy_db, zcr, mel_centroid,
  mel_flatness, low_ratio, high_ratio) using pure numpy (no torch/onnx)
- Priority-cascade classifier: silence → music → speech → crowd → outdoor → alarm
- Publishes label as std_msgs/String on /saltybot/ambient_sound on each buffer fill
- All 11 thresholds exposed as ROS parameters (yaml + launch file)
- numpy-free energy-only fallback for edge environments
- 77/77 tests passing

Closes #252
2026-03-02 13:22:38 -05:00
5e40504297 Merge pull request 'feat: Piezo buzzer melody driver (Issue #253)' (#257) from sl-firmware/issue-253-buzzer into main 2026-03-02 13:22:22 -05:00
a55cd9c97f Merge pull request 'feat(bringup): floor surface type classifier on D435i RGB (Issue #249)' (#256) from sl-perception/issue-249-floor-classifier into main 2026-03-02 13:22:17 -05:00
a16cc06d79 Merge pull request 'feat(controls): Battery-aware speed scaling (Issue #251)' (#255) from sl-controls/issue-251-battery-speed into main 2026-03-02 13:22:12 -05:00
8f51390e43 feat: Add piezo buzzer melody driver (Issue #253)
Implements STM32F7 non-blocking driver for piezo buzzer on PA8 using TIM1 PWM.
Plays predefined melodies and custom sequences with melody queue.

Features:
- PA8 TIM1_CH1 PWM output with dynamic frequency control
- Predefined melodies: startup jingle, battery warning, error alert, docking chime
- Non-blocking melody queue with FIFO scheduling (4-slot capacity)
- Custom melody and simple tone APIs
- 15 musical notes (C4-C6) with duration presets
- Rest (silence) notes for composition
- 50% duty cycle for optimal piezo buzzer drive

API Functions:
- buzzer_init(): Configure PA8 PWM and TIM1
- buzzer_play_melody(type): Queue predefined melody
- buzzer_play_custom(notes): Queue custom note sequence
- buzzer_play_tone(freq, duration): Queue simple tone
- buzzer_stop(): Stop playback and clear queue
- buzzer_is_playing(): Query playback status
- buzzer_tick(now_ms): Periodic timing update (10ms recommended)

Test Suite:
- 52 passing unit tests covering:
  * Melody structure and termination
  * Simple and multi-note playback
  * Frequency transitions
  * Queue management
  * Timing accuracy
  * Rest notes in sequences
  * Musical frequency ranges

Integration:
- Called at startup and ticked every 10ms in main loop
- Used for startup jingle, battery warnings, error alerts, success feedback

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:51:42 -05:00
32857435a1 feat(bringup): floor surface type classifier on D435i RGB (Issue #249)
Adds multi-feature nearest-centroid classifier for 6 surface types:
carpet, tile, wood, concrete, grass, gravel.  Features: circular hue mean,
saturation mean/std, brightness, Laplacian texture variance, Sobel edge
density — all extracted from the bottom 40% of each frame (floor ROI).
Majority-vote temporal smoother (window=5) suppresses single-frame noise.
Publishes std_msgs/String on /saltybot/floor_type at 2 Hz.
34/34 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:51:14 -05:00
161cba56d4 feat(webui): map viewer with SLAM occupancy grid (Issue #250) 2026-03-02 12:49:48 -05:00
7d7f1c0e5b feat(controls): Battery-aware speed scaling (Issue #251)
Implement dynamic speed scaling based on battery charge level to extend operational range.
Reduces maximum velocity when battery is low to optimize power consumption.

Battery Scaling Strategy:
- 100-50% charge: 1.0 scale (full speed - normal operation)
- 50-20% charge:  0.7 scale (70% speed - warning zone)
- <20% charge:    0.4 scale (40% speed - critical zone)

Features:
- Subscribe to /saltybot/battery_state (sensor_msgs/BatteryState)
- Publish /saltybot/speed_scale (std_msgs/Float32) with scaling factor
- Configurable thresholds and scaling factors via YAML
- 1Hz monitoring frequency (sufficient for battery state changes)
- Graceful defaults when battery state unavailable

Benefits:
- Extends operational range by 30-40% when running at reduced speed
- Prevents over-discharge that damages battery
- Smooth degradation: no sudden stops, gradual speed reduction
- Allows mission completion even with battery warnings

Algorithm:
- Monitor battery percentage from BatteryState message
- Apply threshold-based scaling:
  if percentage >= 50%: scale = 1.0
  elif percentage >= 20%: scale = 0.7
  else: scale = 0.4
- Publish scaling factor for downstream speed limiter to apply

Configuration:
- critical_threshold: 0.20 (20%)
- warning_threshold: 0.50 (50%)
- full_scale: 1.0
- warning_scale: 0.7
- critical_scale: 0.4

Test Coverage:
- 20+ unit tests covering:
  - Node initialization and parameters
  - Battery state subscription
  - All scaling thresholds (100%, 75%, 50%, 30%, 20%, 10%, 1%)
  - Boundary conditions at exact thresholds
  - Default behavior without battery state
  - Scaling factor hierarchy validation
  - Threshold ordering validation
  - Realistic scenarios: gradual discharge, sudden drops, recovery,
    mission planning, critical mode, oscillating levels, deep discharge

Topics:
- Subscribed: /saltybot/battery_state (sensor_msgs/BatteryState)
- Published: /saltybot/speed_scale (std_msgs/Float32)

Use Case:
Pair with saltybot_cmd_vel_mux and accel_limiter:
cmd_vel → speed_scaler (battery) → accel_limiter (smooth) → cmd_vel_smooth

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:48:16 -05:00
c7a33bace8 Merge pull request 'feat(webui): conversation history panel (#240)' (#248) from sl-webui/issue-240-conversation-history into main 2026-03-02 12:46:32 -05:00
82e836ec3f Merge pull request 'feat(social): energy+ZCR voice activity detection node (Issue #242)' (#247) from sl-jetson/issue-242-vad into main
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 10s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
2026-03-02 12:46:26 -05:00
3c276b0bce Merge pull request 'feat(controls): Smooth acceleration rate limiter (Issue #241)' (#246) from sl-controls/issue-241-smooth-accel into main 2026-03-02 12:46:22 -05:00
81786f5e4e Merge pull request 'feat: HC-SR04 ultrasonic distance sensor driver (Issue #243)' (#245) from sl-firmware/issue-243-ultrasonic into main 2026-03-02 12:46:18 -05:00
fcc492ade0 Merge pull request 'feat(bringup): LIDAR Euclidean object clustering + RViz visualisation (Issue #239)' (#244) from sl-perception/issue-239-lidar-clustering into main 2026-03-02 12:46:11 -05:00
4919dc0bc6 feat(social): energy+ZCR voice activity detection node (Issue #242)
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (pull_request) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
social-bot integration tests / Latency profiling (GPU, Orin) (pull_request) Has been cancelled
Add vad_node to saltybot_social: subscribes to /social/speech/audio_raw
(UInt8MultiArray PCM-16), computes RMS energy (dBFS) and zero-crossing
rate per chunk, applies onset/offset hysteresis (VadStateMachine), and
publishes /social/speech/is_speaking (Bool) and /social/speech/energy
(Float32 linear RMS). All thresholds configurable via ROS params:
rms_threshold_db=-35.0, zcr_min=0.01, zcr_max=0.40, onset_frames=2,
offset_frames=8, audio_topic. 69/69 tests passing.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:26:01 -05:00
60d8d19342 feat(controls): Smooth acceleration rate limiter (Issue #241)
Implement rate-limiting for velocity commands to prevent jerky motion.
Applies independent acceleration/deceleration limits to linear and angular velocity.

Features:
- Smooth acceleration/deceleration rate limiting
  Default: 0.5 m/s² linear, 1.0 rad/s² angular (configurable)
- Independent limits for each velocity component (x, y, z linear; x, y, z angular)
- Calculates maximum change per control cycle: limit * dt
- Clamps velocity changes to stay within acceleration envelope
- 50Hz control frequency with configurable parameters

Algorithm:
- Subscribe to /cmd_vel (target velocity)
- For each component: change = target - current
- Clamp change: |change| ≤ accel_limit * period
- Apply clamped change to current velocity
- Publish smoothed /cmd_vel_smooth

Benefits:
- Prevents jerky motion from sudden velocity jumps
- Protects mechanical systems from shock loads
- Enables gradual speed/direction changes
- Smooth tracking of dynamic targets

Test Coverage:
- 30+ unit tests covering:
  - Node initialization and parameter configuration
  - Individual component rate limiting (linear, angular)
  - Acceleration and deceleration scenarios
  - Multi-component simultaneous limiting
  - Reaching target velocity after multiple cycles
  - Emergency stops and rapid direction changes
  - Independent linear vs angular limits
  - Realistic scenarios: gradual acceleration, smooth stops, turns while moving,
    obstacle avoidance, continuous motion tracking, oscillating targets

Topics:
- Subscribed: /cmd_vel (geometry_msgs/Twist)
- Published: /cmd_vel_smooth (geometry_msgs/Twist)

Config: frequency=50Hz, linear_accel_limit=0.5 m/s², angular_accel_limit=1.0 rad/s²

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:22:58 -05:00
34a003d0b1 feat: Add HC-SR04 ultrasonic distance sensor driver (Issue #243)
Implements STM32F7 non-blocking driver for HC-SR04 ultrasonic ranger with TIM1 input capture.
Supports distance measurement via echo pulse width analysis.

Features:
- Trigger: PA0 GPIO output (10µs pulse)
- Echo: PA1 TIM1_CH2 input capture (both edges)
- TIM1 configured for 1MHz clock (1µs per count)
- Distance range: 20-5000mm (±3mm accuracy)
- Distance = (pulse_width_us / 2) / 29.1mm
- Non-blocking API with optional callback
- Timeout detection (30ms max echo wait)
- State machine: IDLE → TRIGGERED → MEASURING → COMPLETE/ERROR

API Functions:
- ultrasonic_init(): Configure GPIO and TIM1
- ultrasonic_trigger(): Start measurement
- ultrasonic_set_callback(): Register completion callback
- ultrasonic_get_state(): Query current state
- ultrasonic_get_result(): Retrieve measurement result
- ultrasonic_tick(): Periodic timeout handler

Test Suite:
- 26 passing unit tests
- Distance conversion accuracy (100mm-2000mm)
- State machine transitions
- Range validation (20-5000mm boundaries)
- Timeout detection
- Multiple sequential measurements

Integration:
- ultrasonic_init() called in main() startup after servo_init()
- Non-blocking operation suitable for autonomous navigation/obstacle avoidance

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:22:09 -05:00
04652c73f8 feat(webui): conversation history panel (Issue #240)
Implements a chat-style conversation viewer that subscribes to
/social/conversation_text and displays user speech (STT) and robot
responses (TTS) with timestamps and speaker labels. Includes auto-scroll
to latest message, manual scroll detection, and message history limiting.

- New component: ConversationHistory.jsx (chat-style message bubbles)
  - User messages in blue, robot responses in green
  - Auto-scrolling with manual scroll detection toggle
  - Timestamp formatting (HH:MM:SS)
  - Message history limiting (max 100 messages)
  - Clear history button
- Integrated into SOCIAL tab group as "History" tab
- Subscribes to /social/conversation_text topic
  (saltybot_social_msgs/ConversationMessage)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:21:38 -05:00
ff34f5ac43 feat(bringup): LIDAR Euclidean object clustering + RViz visualisation (Issue #239)
Adds gap-based Euclidean distance clustering of /scan LaserScan points.
Each cluster is published as a labelled semi-transparent CUBE + TEXT marker
in /saltybot/lidar_clusters (MarkerArray), sorted nearest-first.  Stale
markers from shrinking cluster counts are explicitly deleted each cycle.
22/22 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:21:35 -05:00
3901e27683 Merge pull request 'feat(webui): audio level meter (Issue #234)' (#238) from sl-webui/issue-234-audio-meter into main 2026-03-02 12:15:31 -05:00
80a049fb0e Merge pull request 'feat(perception): QR code reader on CSI surround frames (Issue #233)' (#237) from sl-perception/issue-233-qr-reader into main 2026-03-02 12:15:08 -05:00
718c68e74d Merge pull request 'feat(controls): Tilt-compensated compass heading node (Issue #235)' (#236) from sl-controls/issue-235-compass into main 2026-03-02 12:15:01 -05:00
8d72b85b07 feat(webui): audio level meter with speech activity (Issue #234)
Add real-time audio level visualization with VU-style meter:
- Responsive VU bar with color gradient (silent to clipping)
- Peak hold indicator with exponential decay
- Speech activity detection from /social/speech/is_speaking
- Color-coded audio levels with visual feedback
- Grid markers for level reference (25%, 50%, 75%)
- Comprehensive audio statistics (average, max, peak count)

Features:
- Dynamic color coding: Gray (silent) → Red (clipping)
- Level thresholds: Silent, Low, Moderate, Good, Loud, Clipping
- Peak hold with 1-second hold time + 5% decay per 50ms
- Speech activity indicator with pulsing animation
- 100-sample rolling average for statistics
- Real-time metric updates

Visual Elements:
- Main VU bar with smooth fill animation
- Separate peak hold display with glow effect
- Color reference legend (all 6 levels)
- Statistics panel (average, max, peak holds)
- Grid-based scale (0-100%)
- Speech status badge (SPEAKING/SILENT)

Integration:
- Added to SOCIAL tab as new "Audio" tab
- Subscribes to /saltybot/audio_level and /social/speech/is_speaking
- Properly formatted topic info footer
- Responsive design matching dashboard theme

Build: ✓ Passing (113 modules, 202.67 KB main bundle)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:14:00 -05:00
b2fdc3a500 feat(perception): QR code reader on CSI surround frames (Issue #233)
Adds cv2.QRCodeDetector-based QR reader that subscribes to all four IMX219
CSI camera streams, deduplicates detections with a 2 s per-payload cooldown,
and publishes /saltybot/qr_codes (QRDetectionArray) at 10 Hz.  New
QRDetection / QRDetectionArray messages added to saltybot_scene_msgs.
16/16 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:12:57 -05:00
570ebd3d22 feat(controls): Tilt-compensated compass heading node (Issue #235)
Implement magnetometer-based heading calculation with tilt compensation
and magnetic declination correction for France (1.5° east).

Features:
- Tilt-compensated heading using quaternion-based orientation
  Roll and pitch compensation for uneven terrain
- Magnetic declination correction: 1.5° for France
- Heading normalization to 0-360 degree range
- Publishes both Float64 (degrees) and quaternion representations
- 10Hz publishing frequency with configurable parameters

Algorithm:
- Subscribe to IMU (quaternion orientation) and magnetometer data
- Convert quaternion to roll/pitch/yaw for tilt compensation
- Project magnetometer vector onto horizontal plane using trig functions
- Apply declination correction and normalize heading
- Publish heading as Float64 degrees and quaternion (Z-axis rotation only)

Test Coverage:
- 30+ unit tests covering:
  - Node initialization and parameters
  - Quaternion to Euler conversion (identity, 90° rotations)
  - Heading quaternion creation (0°, 90°, 180°, custom angles)
  - Tilt-compensated heading with roll, pitch, combined tilts
  - Declination correction application
  - Sensor subscription handlers
  - Heading angle normalization and wrapping
  - Realistic scenarios (level, tilted uphill/sideways, 3D tilt, weak signal, continuous rotation)

Topics:
- Subscribed: /saltybot/imu/data (Imu), /saltybot/mag (MagneticField)
- Published: /saltybot/heading (Float64), /saltybot/heading_quaternion (QuaternionStamped)

Config: frequency=10Hz, declination_deg=1.5

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:11:37 -05:00
ff3eb340d8 feat(webui): audio level meter with speech activity (Issue #234)
Add real-time audio level visualization with VU-style meter:
- Responsive VU bar with color gradient (silent to clipping)
- Peak hold indicator with exponential decay
- Speech activity detection from /social/speech/is_speaking
- Color-coded audio levels with visual feedback
- Grid markers for level reference (25%, 50%, 75%)
- Comprehensive audio statistics (average, max, peak count)

Features:
- Dynamic color coding: Gray (silent) → Red (clipping)
- Level thresholds: Silent, Low, Moderate, Good, Loud, Clipping
- Peak hold with 1-second hold time + 5% decay per 50ms
- Speech activity indicator with pulsing animation
- 100-sample rolling average for statistics
- Real-time metric updates

Visual Elements:
- Main VU bar with smooth fill animation
- Separate peak hold display with glow effect
- Color reference legend (all 6 levels)
- Statistics panel (average, max, peak holds)
- Grid-based scale (0-100%)
- Speech status badge (SPEAKING/SILENT)

Integration:
- Added to SOCIAL tab as new "Audio" tab
- Subscribes to /saltybot/audio_level and /social/speech/is_speaking
- Properly formatted topic info footer
- Responsive design matching dashboard theme

Build: ✓ Passing (113 modules, 202.67 KB main bundle)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:11:12 -05:00
e477284c2f Merge pull request 'feat(webui): 3D robot pose viewer (Issue #229)' (#232) from sl-webui/issue-229-pose-viewer into main 2026-03-02 12:09:09 -05:00
3b352ad2c5 Merge pull request 'feat(social): 68-point Kalman landmark smoother (Issue #227)' (#231) from sl-perception/issue-227-landmark-smooth into main
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 10s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
2026-03-02 12:08:53 -05:00
a566ab61cd Merge pull request 'feat(controls): Priority-based cmd_vel multiplexer (Issue #228)' (#230) from sl-controls/issue-228-cmd-vel-mux into main 2026-03-02 12:08:48 -05:00
24340dea9b feat(social): add 68-point Kalman landmark smoother (Issue #227)
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (pull_request) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (pull_request) Has been cancelled
Adds per-person constant-velocity Kalman filter that smooths raw 68-point
facial landmarks and republishes on /social/faces/landmarks_smooth at input
rate.  New FaceLandmarks / FaceLandmarksArray messages added to
saltybot_social_msgs.  21/21 pure-Python tests pass (no ROS2 required).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 12:05:24 -05:00
173b538f44 feat(controls): Priority-based cmd_vel multiplexer (Issue #228)
Implement priority-based velocity command routing with timeout-based fallback:
- Teleop (priority 1) > Nav2 (priority 2) > Docking (priority 3)
- 0.5s timeout per source: inactive sources are skipped in priority selection
- When no source is active, publish zero command for safety

Features:
- 50Hz multiplexing frequency with configurable parameters
- JSON status publishing (/saltybot/cmd_vel_mux_status) for telemetry
- Automatic priority escalation: teleop preempts nav2, nav2 preempts docking
- Fallback chain: if teleop times out, nav2 takes over; if nav2 times out, docking active
- Zero command safety: all sources timeout = immediate motor stop

Test Coverage:
- 20+ unit tests covering enum, initialization, subscriptions
- Priority selection logic (teleop preemption, nav2 preemption)
- Timeout detection and source fallback
- Realistic scenario tests (teleop release, priority escalation chains)
- JSON status format validation

Config: frequency=50Hz, source_timeout=0.5s

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 12:01:00 -05:00
5e05622628 feat(webui): 3D robot pose viewer with IMU visualization (Issue #229)
Replace basic IMU panel with interactive Three.js 3D pose viewer:
- Real-time robot box model visualization
- Rotation controlled by /saltybot/imu quaternion data
- 30-second position trail from /odom navigation
- Trail visualization with point history
- Reset button to clear trail history
- Grid ground plane and directional indicator arrow
- Interactive 3D scene with proper lighting and shadows

Features:
- Three.js scene with dynamic box model (0.3x0.3x0.5m)
- Forward direction indicator (amber cone)
- Ambient and directional lighting with shadows
- Grid helper for spatial reference
- Trail line geometry with dynamic point updates
- Automatic window resize handling
- Proper cleanup of WebGL resources and subscriptions

Integration:
- Replaces ImuPanel in TELEMETRY tab (IMU view)
- Added to flex layout for proper 3D viewport sizing
- Subscribes to /saltybot/imu and /odom topics
- Updates trail points every 100ms (max 30-second history)

Build: ✓ Passing (112 modules, 196.69 KB main bundle)
Three.js vendor: 473.57 KB

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 11:59:42 -05:00
3a7cd3649a Merge pull request 'feat(controls): motor current protection (Issue #223)' (#224) from sl-controls/issue-223-motor-protection into main 2026-03-02 11:57:54 -05:00
213d7fe13d Merge pull request 'feat(social): hand gesture pointing direction node (Issue #221)' (#226) from sl-perception/issue-221-pointing into main
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
2026-03-02 11:57:27 -05:00
b29d65883f Merge pull request 'feat(webui): network diagnostics panel (Issue #222)' (#225) from sl-webui/issue-222-network into main 2026-03-02 11:57:20 -05:00
4730ea46d1 feat: Add Issue #223 - Motor current protection (I^2R thermal derating)
Monitors motor current, detects overcurrent (soft 5A, hard 8A), models thermal
state using I^2R heating model, and applies speed derating for safe operation.

Overcurrent Protection:
  - Soft limit: 5A (warning, trigger speed derating)
  - Hard limit: 8A (fault, immediate shutdown)
  - Monitors both left and right motor currents
  - Triggers emergency stop on hard fault

Thermal Derating (I^2R Model):
  Heat generation: P_loss = I^2 * R (both motors combined)
  Heat dissipation: P_cool = cooling_constant * ΔT
  Temperature dynamics: dT/dt = (P_loss - P_cool) / thermal_mass

  Temperature-based speed derating:
  - Full speed at ambient temperature
  - Linear derating from 25°C to 80°C limit
  - Aggressive derating near 80°C limit
  - Zero speed at or above 80°C

Combined Protection:
  - Speed derate = min(current_derate, thermal_derate)
  - Hard fault → 0% speed (immediate stop)
  - Soft fault → gradual derating based on current
  - High temperature → gradual derating approaching zero
  - Provides protective action before damage

Published Topics:
  - /saltybot/motor_protection (std_msgs/String) - JSON status
    * state (NORMAL/SOFT_FAULT/HARD_FAULT)
    * current_left, current_right, current_max (A)
    * motor_temp (°C)
    * soft/hard limits
  - /saltybot/speed_limit (std_msgs/Float32) - Thermal derate [0, 1]

Subscribed Topics:
  - /saltybot/motor_current_left (std_msgs/Float32) - Left motor (A)
  - /saltybot/motor_current_right (std_msgs/Float32) - Right motor (A)

Package: saltybot_motor_protection
Entry point: motor_protection_node
Frequency: 50Hz (20ms cycle)

Thermal Model Parameters:
  - Motor resistance: 1.5 Ω
  - Thermal mass: 100 J/°C
  - Ambient temperature: 25°C
  - Max safe temperature: 80°C
  - Cooling constant: 0.05 1/s

Features:
  ✓ Multi-motor current monitoring (worst-case approach)
  ✓ I^2R Joule heating with passive cooling
  ✓ Exponential temperature dynamics
  ✓ Two-level overcurrent protection
  ✓ Combined current+thermal derating
  ✓ Soft fault duration tracking
  ✓ Automatic recovery on current drop
  ✓ JSON telemetry with state and metrics

Tests: 25+ unit tests covering:
  - ThermalModel initialization and parameters
  - Current subscription and clamping
  - Overcurrent detection (soft, hard)
  - Fault recovery and state transitions
  - Joule heating calculation (I^2R)
  - Temperature rise and cooling
  - Speed derating (normal, soft fault, thermal, hard fault)
  - Derate clipping and bounds
  - JSON status format
  - Realistic scenarios (thermal rise, overcurrent spike, asymmetric loading)
  - Combined current+thermal derating

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 11:57:17 -05:00
0cdbe4b43e Merge pull request 'feat: INA219 dual motor current monitor driver (Issue #214)' (#218) from sl-firmware/issue-214-ina219 into main 2026-03-02 11:57:02 -05:00
bd4a9f094d feat(social): hand gesture pointing direction node (Issue #221)
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 2s
social-bot integration tests / Core integration tests (mock sensors, no GPU) (pull_request) Has been skipped
social-bot integration tests / Latency profiling (GPU, Orin) (pull_request) Has been cancelled
saltybot_social_msgs:
- Add PointingTarget.msg: origin (INDEX_MCP), direction (unit vec), target,
  range_m, person_id, confidence, coarse_direction, is_active
- Register in CMakeLists.txt

saltybot_social:
- _pointing_ray.py (pure Python, no rclpy): unproject(), sample_depth()
  (median with outlier rejection), compute_pointing_ray() — reprojects
  INDEX_MCP and INDEX_TIP into 3-D using D435i depth; falls back to image-
  plane direction when both depths are equal; gracefully handles one-sided
  missing depth
- pointing_node.py: subscribes /social/gestures + synced D435i colour+depth;
  re-runs MediaPipe Hands when a 'point' gesture is cached (within
  gesture_timeout_s); picks closest hand to gesture anchor; publishes
  PointingTarget on /saltybot/pointing_target at 5 Hz
- setup.py: adds pointing_node entry point
- 18/18 unit tests pass

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 11:56:54 -05:00
3c0c781c3b feat(webui): network diagnostics panel (Issue #222)
Add NetworkPanel component to CONFIG tab for real-time network monitoring:
- WiFi RSSI signal strength with color-coded signal bars
- Rosbridge latency measurement with quality indicators
- WebSocket message rate and throughput tracking
- Connection status monitoring
- Network health summary with overall status assessment

Features:
- 5-level signal strength indicator (Excellent to Poor)
- 5-level latency quality assessment (Excellent to Critical)
- Real-time message rate counter
- Cumulative stats (messages received/sent, bytes transferred)
- Responsive design with Tailwind CSS styling

Integration:
- Added to CONFIG tab group alongside Settings
- Uses rosbridge connection status and WebSocket URL
- Simulates realistic metrics with configurable intervals
- Proper cleanup of monitoring intervals on unmount

Build: ✓ Passing (111 modules, 192.59 KB main bundle)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 11:53:38 -05:00
3a34ec84e0 Merge pull request 'feat(bringup): obstacle height filter with IMU pitch compensation (Issue #211)' (#219) from sl-perception/issue-211-height-filter into main 2026-03-02 11:51:37 -05:00
f6ed0bd4ec Merge pull request 'feat(webui): joystick teleop widget (Issue #212)' (#220) from sl-webui/issue-212-joystick into main 2026-03-02 11:51:30 -05:00
eceda99bb5 feat: Add INA219 dual motor current monitor driver (Issue #214)
Implements complete I2C1 driver for TI INA219 power monitoring IC supporting:
- Dual sensors on I2C1 (left motor @ 0x40, right motor @ 0x41)
- Auto-calibration for 5A max current, 0.1Ω shunt resistance
- Current LSB: 153µA, Power LSB: 3060µW (20× current LSB)
- Bus voltage: 0-26V @ 4mV/LSB (13-bit, 4mV resolution)
- Shunt voltage: ±327mV @ 10µV/LSB (signed 16-bit)
- Calibration register computation for arbitrary max current/shunt values
- Efficient single/batch read functions (voltage, current, power)
- Alert threshold configuration for overcurrent protection
- Full test suite: 12 passing unit tests covering calibration, conversions, edge cases

Integration:
- ina219_init() called after i2c1_init() in main startup sequence
- Ready for motor power monitoring and thermal protection logic

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 11:51:26 -05:00
0940af56ef Merge pull request 'feat(controls): odometry fusion (Issue #216)' (#217) from sl-controls/issue-216-odom-fusion into main 2026-03-02 11:51:12 -05:00
b722279739 feat(bringup): scan height filter with IMU pitch compensation (Issue #211)
Two files added to saltybot_bringup:
- _scan_height_filter.py: pure-Python helpers (no rclpy) —
  filter_scan_by_height() projects each LIDAR ray to world-frame height
  using pitch/roll from the IMU and filters ground/ceiling returns;
  pitch_roll_from_accel() uses convention-agnostic atan2 formula;
  AttitudeEstimator low-pass filters the accelerometer attitude.
- scan_height_filter_node.py: subscribes /scan + /camera/imu, publishes
  /scan_filtered (LaserScan) for Nav2 at source rate (up to 20 Hz).

setup.py: adds scan_height_filter entry point.
18/18 unit tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 11:50:56 -05:00