- ROS2 node for balance mode PID parameter management via pyvesc UART
- Tilt safety kill switch: ±45° pitch > 500ms triggers motor cutoff
- Startup ramp: gradual acceleration from 0 to full output over configurable duration
- IMU integration: subscribe to /imu/data for pitch/roll angle computation
- State publishing: /saltybot/balance_state with tilt angles, PID values, motor telemetry
- Data logging: /saltybot/balance_log publishes CSV-formatted IMU + motor data
- Configurable parameters: PID gains, tilt thresholds, ramp duration, control frequency
- Test suite: quaternion to Euler conversion, tilt safety checks, startup ramp
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Move camera viewer from TELEMETRY to new CAMERAS tab group (rose color).
Reorganizes tab structure to separate media capture from system telemetry.
CameraViewer.jsx already provides comprehensive MJPEG stream support:
- Multi-camera switching (7 total: front/left/rear/right CSI, D435i RGB/depth, panoramic)
- FPS counter per camera with quality badge (FULL/GOOD/LOW/NO SIGNAL)
- Resolution and camera info display
- Detection overlays (faces, gestures, scene objects)
- Picture-in-picture support (up to 3 pinned cameras)
- Video recording (MP4/WebM) and snapshot capture
- 360° panoramic viewer with mouse drag pan
- Color-coded quality indicators based on FPS
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Features:
- Subscribes to /saltybot/hands (21 landmarks per hand - MediaPipe format)
- Subscribes to /saltybot/hand_gesture (String gesture label)
- Canvas-based hand skeleton rendering with bone connections
- Support for dual hand tracking (left and right)
- Handedness indicators with color coding
* Left hand: green
* Right hand: yellow
- Real-time gesture display with confidence indicator
- Per-landmark confidence visualization
- Bone connections between all 21 joints
Hand Skeleton Features:
- 21 MediaPipe landmarks per hand
* Wrist (1)
* Thumb (4)
* Index finger (4)
* Middle finger (4)
* Ring finger (4)
* Pinky finger (4)
- 20 bone connections between joints
- Confidence-based rendering (only show high-confidence points)
- Scaling and normalization for viewport
- Joint type indicators (tips with ring outline)
- Glow effects around landmarks
Gesture Recognition:
- Real-time gesture label display
- Confidence percentage (0-100%)
- Color-coded confidence:
* Green: >80% (high confidence)
* Yellow: 50-80% (medium confidence)
* Blue: <50% (detecting)
Hand Status Display:
- Live detection status for both hands
- Visual indicators (✓ detected / ◯ not detected)
- Dual-hand canvas rendering
- Gesture info panel with confidence bar
Integration:
- Added to SOCIAL tab group as "Hands" tab
- Positioned after "Faces" tab
- Uses subscribe hook for real-time updates
- Dark theme with color-coded hands
- Canvas-based rendering for smooth visualization
Build: 125 modules, no errors
Main bundle: 270.08 KB
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Features:
- Subscribes to /diagnostics (diagnostic_msgs/DiagnosticArray)
- Hardware status cards per subsystem with color-coded health
- Real-time error and warning counts
- Expandable diagnostic cards with detailed key-value pairs
- Diagnostic status timeline with timestamps
- Aggregated system health summary
- Status indicators: OK (green), WARNING (yellow), ERROR (red), STALE (gray)
- Hardware Status Display
* Per-subsystem diagnostic cards
* Status level with color coding
* Expandable details with key values
* Hardware ID tracking
* Name and message display
- Health Summary Card
* Total diagnostic count
* OK/WARNING/ERROR/STALE breakdowns
* Overall system health status
* Visual status indicator
- Timeline and History
* Recent status timeline (10 latest events)
* Timestamp tracking
* Status transitions
* Scrollable history
- Status Legend
* Color-coded reference guide
* Status descriptions
* Quick status lookup
Integration:
- Added to MONITORING tab group as first tab (highest priority)
- Uses subscribe hook for real-time updates
- Dark theme with comprehensive status visualization
- Max 100 diagnostic events in history
Build: 124 modules, no errors
Main bundle: 264.31 KB
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Critical bug fix:
- Added missing StatusHeader import (used in JSX line 215)
- Added missing LogViewer import (used in JSX line 291)
- Added missing MotorCurrentGraph import (used in JSX line 264)
These imports were referenced in JSX but not imported, causing dashboard crashes on load.
Build verification:
- 122 modules, all compiled successfully
- No errors or warnings
- Bundle: 255.38 KB main
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Features:
- Virtual dual-stick gamepad interface
* Left stick: linear velocity (forward/backward)
* Right stick: angular velocity (turn left/right)
- Canvas-based rendering with real-time visual feedback
- Velocity vector visualization on sticks
- 10% deadzone on both axes for dead-stick detection
- WASD keyboard fallback for manual driving
* W/S: forward/backward
* A/D: turn left/right
* Smooth blending between gamepad and keyboard input
- Speed limiter slider (0-100%)
* Real-time control of max velocity
* Disabled during e-stop state
- Emergency stop button (e-stop)
* Immediate velocity zeroing
* Visual status indicator (red when active)
* Prevents accidental motion during e-stop
- ROS Integration
* Publishes geometry_msgs/Twist to /cmd_vel
* Max linear velocity: 0.5 m/s
* Max angular velocity: 1.0 rad/s
* 50ms update rate
- UI Features
* Real-time velocity display (m/s and rad/s)
* Status bar with control mode indicator
* Speed limit percentage display
* Control info with keyboard fallback guide
Integration:
- Replaces previous split-view control layout
- Enhanced TELEMETRY/control tab
- Comprehensive gamepad + keyboard control system
Build: 120 modules, no errors
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Features:
- Enumerate active ROS nodes from /rosout activity
- Real-time node status tracking (alive/dead based on heartbeat)
- Heartbeat timeout: 5 seconds without updates = dead
- Display node name, status, uptime, and last seen timestamp
- Color-coded status indicators (green=alive, gray=dead)
- Sortable table with node statistics
- Summary card showing alive/dead node counts
- Periodic status polling every 2 seconds
Integration:
- Added to MONITORING tab group as 'Nodes' tab
- Subscribes to /rosout (rcl_interfaces/Log) to detect active nodes
- Real-time updates with smooth transitions
Build: 119 modules, no errors
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Features:
- Circular gauge visualization for CPU and GPU temperatures
- Color-coded temperature zones: green <60°C, yellow 60-75°C, red >75°C
- Real-time needle pointer animation
- Fan speed percentage display for each sensor
- Peak temperature tracking and max reached indicator
- Thermal alert status (Normal/Caution/Critical)
- ROS subscription to /saltybot/thermal_status
- Integrated into TELEMETRY tab group
Build: 118 modules, no errors
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Real-time motor current visualization with:
- Subscribes to /saltybot/motor_currents for dual-motor current data
- Rolling 60-second history window with automatic data culling
- Dual-axis line chart for left (cyan) and right (amber) motor amps
- Canvas-based rendering for performance
- Thermal warning threshold line (25A, configurable)
- Real-time statistics:
* Current draw for left and right motors
* Peak current tracking over 60-second window
* Average current calculation
* Thermal status indicator with warning badge
- Color-coded thermal alerts:
* Red background when threshold exceeded
* Warning indicator and message
- Grid overlay, axis labels, time labels, legend
- Takes absolute value of currents (handles reverse direction)
Integrated into TELEMETRY tab group as 'Motor Current' tab.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Topic bandwidth tracking and visualization with:
- Tracks message rates for all subscribed ROS topics
- Estimates bandwidth based on message size and frequency
- Message size estimated from JSON serialization
- Updates every 1 second with rolling 30-second history window
- Sortable table display:
* Topic name with truncation for long names
* Message rate (messages per second)
* Average message size (bytes)
* Bandwidth estimate (B/s, KB/s, or MB/s)
* Sparkline mini-chart showing bandwidth trend
- Total bandwidth summary at top
- Click column headers to sort (ascending/descending toggle)
- Visual indicators with color-coded columns
Integrated into MONITORING tab group as 'Bandwidth' tab.
Component provides window.__trackRosMessage() hook for optional
bandwidth tracking integration with ROS bridge.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Real-time battery history visualization with:
- Subscribes to /saltybot/battery_state for continuous battery data
- Rolling 30-minute history window with automatic data culling
- Dual-axis line chart: voltage (left, cyan) and percentage (right, amber)
- Canvas-based rendering for performance
- Charge/discharge rate calculation (last 5-minute average):
* Voltage rate in mV/min with up/down/stable indicator
* Percentage rate in %/min with up/down/stable indicator
- Grid overlay, axis labels, time labels, and legend
- Current stats display: voltage, percentage, rates
- Responsive canvas sizing
Integrated into TELEMETRY tab group as 'Battery History' tab.
Follows established canvas rendering and data subscription patterns.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
Adds FleetPanel import and FLEET tab group (green) to the main
dashboard navigation. Fleet tab is self-contained via useFleet.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
React + Vite + TailwindCSS dashboard served on port 8080.
Connects to ROS2 via rosbridge_server WebSocket (default ws://localhost:9090).
Panels:
- StatusPanel: pipeline state (idle/listening/thinking/speaking/throttled)
with animated pulse indicator, GPU memory bar, per-stage latency stats
- FaceGallery: enrolled persons grid with enroll/delete via
/social/enrollment/* services; live detection indicator
- ConversationLog: real-time transcript with human/bot bubbles,
streaming partial support, auto-scroll
- PersonalityTuner: sass/humor/verbosity sliders (0–10) writing to
personality_node via rcl_interfaces/srv/SetParameters; live
PersonalityState display
- NavModeSelector: shadow/lead/side/orbit/loose/tight mode buttons
publishing to /social/nav/mode; voice command reference table
Usage:
cd ui/social-bot && npm install && npm run dev # dev server port 8080
npm run build && npm run preview # production preview
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace generic flat PCB with a standing two-wheeled balancing robot:
- Vertical navy body (1.2 tall) rising above wheel axle at y=0
- Two wheels with blue rim accents, aligned to axle
- Front display panel and status LED
- Sensor stem + head on top
Camera repositioned to frame the taller robot.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove erroneous negate on targetYaw — yaw was spinning opposite to
physical rotation. Update resetYaw() formula to match (+ instead of -).
Pitch and roll were unaffected.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add 'G' CDC command that disarms and re-runs gyro bias calibration.
safety_refresh() added to calibration loop (every 40ms) so IWDG
does not trip during the 1s blocking re-cal when watchdog is running.
GYRO CAL button in ui/index.html sends 'G' and shows status feedback.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- bmp280.c: detect BME280 (chip_id 0x60) vs BMP280 (0x58) at init
- bmp280.c: read humidity calibration (dig_H1–H6) from 0xA1 and 0xE1–0xE7
- bmp280.c: set ctrl_hum (0xF2, osrs_h=×16) before ctrl_meas — hardware req
- bmp280.c: add bmp280_read_humidity() — float compensation (FPv5-SP FPU),
returns %RH × 10; -1 if chip is BMP280 or not initialised
- bmp280.h: add bmp280_read_humidity() declaration + timeout note
- main.c: baro_ok → baro_chip (stores chip_id for BME280 detection)
- main.c: telemetry adds t (°C×10), pa (hPa×10) for all barometers;
adds h (%RH×10) for BME280 only; alt unchanged
- ui/index.html: hidden TEMP/HUMIDITY/PRESSURE rows, revealed on first
packet containing t/h/pa fields; values shown with 1 dp
I2C hang safety: all HAL_I2C_Mem_Read/Write use 100ms timeouts, so
missing hardware (NAK) returns in <1ms, not after a hang.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Shared I2C1 bus (i2c1.c/h, PB8=SCL PB9=SDA 100kHz):
- i2c1_init() called once in main() before sensor probes.
- hi2c1 exported globally; baro and mag drivers use it directly.
Barometer (bmp280.c):
- Probes I2C1 at 0x76 then 0x77 (covers both SDO options).
- bmp280_init() returns chip_id (0x58/0x60) on success, neg if absent.
- Added bmp280_pressure_to_alt_cm() — ISA barometric formula.
- Added bmp280.h (was missing).
Magnetometer (mag.c / mag.h):
- Auto-detects QMC5883L (0x0D, id=0xFF), HMC5883L (0x1E, id='H43'),
IST8310 (0x0E, id=0x10) in that order.
- mag_read_heading() returns degrees×10 (0–3599) or -1 if not ready.
- HMC5883L: correct XZY byte order applied.
- IST8310: single-measurement trigger mode.
main.c:
- i2c1_init() + bmp280_init() + mag_init() after all other inits.
- Both skip gracefully (baro_ok=0, mag_type=MAG_NONE) if not present.
- Telemetry JSON: incremental builder appends ",\"hd\":<n>" when mag
found and ",\"alt\":<n>" when baro found. No extra bytes when absent.
UI (index.html):
- HEADING and ALT rows hidden until first packet with that field.
- Heading shown in degrees, alt in metres (firmware sends cm).
Closes#24.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The MAMBA F722S mounts MPU6000 at CW270 (clockwise 270°) which applies
rotation matrix R = [[0,1,0],[-1,0,0],[0,0,1]] to transform sensor axes
to board axes (Betaflight convention).
Firmware (mpu6000.c):
- accel_pitch: was atan2(ax, az) → now atan2(ay, az)
board_forward = sensor_Y, so ay drives pitch not ax
- accel_roll: was atan2(ay, az) → now atan2(-ax, az)
board_right = -sensor_X, so -ax drives roll not ay
- gyro_pitch_rate: was +raw.gx → now -raw.gx
board_gy (pitch) = -sensor_gx after R_CW270 transform
- gyro_roll_rate: raw.gy unchanged (board_gx = sensor_gy ✓)
- gyro_yaw_rate: raw.gz unchanged ✓
UI (index.html) rotation sign fixes:
- roll → -rotation.z: Three.js +z = CCW from camera = left bank;
our convention is right-bank-positive so negate
- yaw → -rotation.y: Three.js +y = CCW from above; sensor_Z points
down on MAMBA (az ≈ +1g when level) so gz+ = CW physical; negate
- pitch → +rotation.x: correct as-is (Three.js +x tilts nose up ✓)
Closes#15.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Issue #12 — Roll displayed as pitch:
- Firmware was sending r=pitch_rate (wrong). Changed to r=roll_deg*10.
- mpu6000.c: add roll complementary filter (accel atan2(ay,az) +
gyro gy integration, same COMP_ALPHA=0.98 as pitch).
- IMUData: add roll and yaw fields.
- UI: updateIMU() now uses data.r/10 for roll (not client-side filter
that computed from ax/ay/az which firmware never sent).
- Three.js: roll -> rotation.z (banking), pitch -> rotation.x (tipping)
— axes were already correct, fix was the firmware data.
Issue #13 — Add yaw telemetry:
- Firmware: gyro Z integration (gz * dt) → s_yaw, sent as y=yaw_deg*10.
Gyro-only, drifts — no magnetometer.
- IMUData: yaw field added.
- UI: yaw -> rotation.y (spinning on vertical axis). Displayed in HUD.
- UI: YAW RESET button captures current yaw as new zero reference
(client-side offset, no new firmware command needed).
Closes#12, #13.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>