797 Commits

Author SHA1 Message Date
dd033b9827 feat(controls): IMU calibration routine (Issue #278)
Implements ROS2 IMU gyro + accel calibration node with:
- Service-triggered calibration via /saltybot/calibrate_imu
- Optional auto-calibration on startup (configurable)
- Collects N stationary samples (default 100)
- Computes mean bias offsets for gyro and accel
- Publishes bias-corrected IMU on /imu/calibrated
- Includes 10+ unit tests for calibration logic

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 17:35:30 -05:00
f5093ecd34 feat(perception): HSV color object segmenter — Issue #274
- Add ColorDetection.msg + ColorDetectionArray.msg to saltybot_scene_msgs
- Add _color_segmenter.py: HsvRange/ColorBlob types, COLOR_RANGES defaults,
  mask_for_color() (dual-band red wrap), find_color_blobs() with morph open,
  contour extraction, area filter and max-blob-per-color limit
- Add color_segment_node.py: subscribes /camera/color/image_raw (BEST_EFFORT),
  publishes /saltybot/color_objects (ColorDetectionArray) per frame;
  active_colors, min_area_px, max_blobs_per_color params
- Add saltybot_scene_msgs exec_depend to saltybot_bringup/package.xml
- Register color_segmenter console_script in setup.py
- 34/34 unit tests pass (no ROS2 required)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-02 17:32:41 -05:00
54bc37926b Merge pull request 'feat(webui): system log tail viewer (#275)' (#277) from sl-webui/issue-275-log-viewer into main 2026-03-02 17:31:01 -05:00
30ad71e7d8 Merge pull request 'feat(social): proximity-based greeting trigger (Issue #270)' (#272) from sl-jetson/issue-270-greeting-trigger 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 17:30:54 -05:00
b6104763c5 Merge pull request 'feat(controls): Wheel slip detector (Issue #262)' (#266) from sl-controls/issue-262-wheel-slip into main
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (push) Has been cancelled
social-bot integration tests / Core integration tests (mock sensors, no GPU) (push) Has been cancelled
social-bot integration tests / Latency profiling (GPU, Orin) (push) Has been cancelled
2026-03-02 17:30:52 -05:00
5108fa8fa1 feat(controls): Wheel slip detector (Issue #262)
Detect wheel slip by comparing commanded velocity vs actual encoder velocity.
Publishes Bool flag on /saltybot/wheel_slip_detected when slip detected >0.5s.

Features:
- Subscribe to /cmd_vel (commanded) and /odom (actual velocity)
- Compare velocity magnitudes with 0.1 m/s threshold
- Persistence: slip must persist >0.5s to trigger (debounces transients)
- Publish Bool on /saltybot/wheel_slip_detected with detection status
- 10Hz monitoring frequency, configurable parameters

Algorithm:
- Compute linear speed from x,y components
- Calculate velocity difference
- If exceeds threshold: increment slip duration
- If duration > timeout: declare slip detected

Benefits:
- Detects environmental slip (ice, mud, wet surfaces)
- Triggers speed reduction to maintain traction
- Prevents wheel spinning/rut digging
- Safety response for loss of grip

Topics:
- Subscribed: /cmd_vel (Twist), /odom (Odometry)
- Published: /saltybot/wheel_slip_detected (Bool)

Config: frequency=10Hz, slip_threshold=0.1 m/s, slip_timeout=0.5s

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 17:29:03 -05:00
5362536fb1 feat(webui): waypoint editor with click-to-navigate (Issue #261) 2026-03-02 17:29:03 -05:00
305ce6c971 feat(webui): system log tail viewer (Issue #275)
Real-time ROS log stream viewer with:
- Subscribes to /rosout (rcl_interfaces/Log)
- Severity-based color coding:
  DEBUG=grey | INFO=white | WARN=yellow | ERROR=red | FATAL=magenta
- Filter by severity level (multi-select toggle)
- Filter by node name (text input)
- Auto-scroll to latest logs
- Max 500 logs in history (configurable)
- Scrolling log output in monospace font
- Proper timestamp formatting (HH:MM:SS)

Integrated into MONITORING tab group as 'Logs' tab alongside 'Events'.
Follows established React/Tailwind patterns from other dashboard components.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 17:28:28 -05:00
c7dd07f9ed feat(social): proximity-based greeting trigger — Issue #270
Some checks failed
social-bot integration tests / Lint (flake8 + pep257) (pull_request) Failing after 12s
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 greeting_trigger_node to saltybot_social:
- Subscribes to /social/faces/detected (FaceDetectionArray) for face arrivals
- Subscribes to /social/person_states (PersonStateArray) to cache face_id→distance
- Fires greeting when face_id is within proximity_m (default 2m) and
  not in per-face_id cooldown window (default 300s)
- Publishes JSON on /saltybot/greeting_trigger:
  {face_id, person_name, distance_m, ts}
- unknown_distance param controls assumed distance for faces with no PersonState yet
- Thread-safe distance cache and greeted map
- 50/50 tests passing

Closes #270
2026-03-02 17:26:40 -05:00
0776003dd3 Merge pull request 'feat(webui): robot status dashboard header (#269)' (#273) from sl-webui/issue-269-status-header into main 2026-03-02 17:26:40 -05:00
01ee02f837 Merge pull request 'feat(bringup): D435i depth hole filler via bilateral interpolation (Issue #268)' (#271) from sl-perception/issue-268-depth-holes into main 2026-03-02 17:26:22 -05:00
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
201dea4c01 feat(webui): robot status dashboard header bar (Issue #269)
Persistent top bar showing real-time robot health indicators:
- Battery percentage and voltage (color-coded: green >60%, amber 30-60%, red <30%)
- WiFi signal strength (RSSI dBm with quality assessment)
- Motor status and current draw in Amperes
- Emergency state indicator (red highlight when active)
- System uptime in hours and minutes
- Current operational mode (idle/nav/social/docking)
- Connection status indicator

Component subscribes to relevant ROS topics and displays in compact
flex layout matching dashboard dark theme.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 14:19:03 -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
c348e093ef feat: Add cooling fan PWM speed controller (Issue #263)
Implements STM32F722 driver for brushless cooling fan on PA9 using TIM1_CH2 PWM.
Features:
- Temperature-based speed curve: off <40°C, 30% at 50°C, 100% at 70°C
- Smooth speed ramp transitions with configurable rate (default 0.05%/ms)
- Linear interpolation between curve points
- PWM duty cycle control (0-100%)
- State transitions and edge case handling

All 51 unit tests passing:
- Temperature curve verification (6 test zones)
- Speed boundaries and transitions
- Ramp timing and rate control
- PWM duty cycle calculation
- Temperature extremes and boundary conditions

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-02 13:29:18 -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