Files
xMonitor/README.md
2026-04-14 22:06:16 +08:00

9.0 KiB

xMonitor — Robot Status Monitor

A real-time web dashboard for monitoring a ROS 2 robot's motor, arm, waist, and power status.
Data is streamed from the robot controller over WebSocket and displayed in a browser.


Architecture

Robot Controller (ROS 2)                  Monitor Server (PC / Server)
┌──────────────────────────┐              ┌──────────────────────────┐
│  monitor_sender.py       │   WebSocket  │  main_monitor.py         │
│  ─────────────────────── │─────────────▶│  (FastAPI + uvicorn)     │
│  Subscribes:             │  /ws/robot   │                          │
│  • /leg/status           │              │  Broadcasts to browsers  │
│  • /arm/status           │              │  via /ws                 │
│  • /waist/status         │              └────────────┬─────────────┘
│  • /power/battery/status │                           │ WebSocket /ws
│  • /leg/motor_status     │                           ▼
│  • /arm/motor_status     │              ┌──────────────────────────┐
│  • /waist/motor_status   │              │  Browser (any device)    │
│                          │              │  http://<server-ip>:8000 │
│  Sends JSON every 1 s    │              └──────────────────────────┘
└──────────────────────────┘

Requirements

Monitor Server (PC / any host)

Package Purpose
Python ≥ 3.9 Runtime
fastapi Web framework
uvicorn ASGI server
websockets (used by sender; not needed on server)
pip install fastapi uvicorn

Robot Controller (ROS 2 node)

Package Purpose
Python ≥ 3.9 Runtime
ROS 2 (Humble / Iron / …) Middleware
bodyctrl_msgs Custom message package
websockets WebSocket client
rclpy ROS 2 Python client
pip install websockets

Monitor Server — main_monitor.py

Start

# Default: listens on all interfaces, port 8000
python main_monitor.py

# Or with uvicorn directly (supports --reload for development)
uvicorn main_monitor:app --host 0.0.0.0 --port 8000

WebSocket endpoints

Endpoint Direction Description
GET / HTTP Returns the web dashboard HTML
WS /ws Server → Browser Pushes robot status to every connected browser
WS /ws/robot Robot → Server Receives JSON from monitor_sender.py

Web GUI

Open http://<server-ip>:8000 in any browser.

The dashboard shows:

  • Connection status indicator (green / red dot)
  • Last update timestamp
  • Power panel (two rows):
    • 主电池 (Master battery): voltage (V), current (A), SOC (%)
    • 副电池 (Secondary battery): voltage (V), current (A), SOC (%)
    • Cards turn orange (warn) or red (alert) when voltage / SOC drops low
  • Motor status table with columns:
    ID | Pos (rad) | Speed | Current (A) | Temp (°C) | Motor Temp | MOS Temp | Error
    • Groups: 左臂 11-14, 右臂 21-24, 腰部 31-33, 左腿 51-56, 右腿 61-66
    • Temperature cells turn yellow when > 100 °C, red when > 120 °C
    • Rows with errors are highlighted red; error column shows when OK
    • Browser auto-reconnects every 3 s if the WebSocket drops

Robot Sender — monitor_sender.py

Run this on the robot controller where ROS 2 is running.

Usage

python3 monitor_sender.py --ip <server-ip> [--port <port>]
Argument Default Description
--ip 10.11.24.86 IP address of the monitor server
--port 8000 TCP port of the monitor server

Examples

# Connect to server at 192.168.1.100 on default port 8000
python3 monitor_sender.py --ip 192.168.1.100

# Connect to server at 10.0.0.5 on port 9000
python3 monitor_sender.py --ip 10.0.0.5 --port 9000

Subscribed ROS 2 topics

Topic Message Type Description
/leg/status bodyctrl_msgs/MotorStatusMsg Leg motor status (pos / speed / current / temp / error)
/arm/status bodyctrl_msgs/MotorStatusMsg Arm motor status
/waist/status bodyctrl_msgs/MotorStatusMsg Waist motor status
/leg/motor_status bodyctrl_msgs/MotorStatusMsg1 Leg motor & MOS temperatures
/arm/motor_status bodyctrl_msgs/MotorStatusMsg1 Arm motor & MOS temperatures
/waist/motor_status bodyctrl_msgs/MotorStatusMsg1 Waist motor & MOS temperatures
/power/battery/status bodyctrl_msgs/PowerBatteryStatus Battery voltages, currents, SOC

Behaviour

  • All topics are sampled once per second (1 Hz) via a ROS 2 timer, reducing network overhead.
  • Data from all topics is merged into a single JSON payload and sent over WebSocket.
  • Motor temperature (motortemperature) and MOS temperature (mostemperature) from MotorStatusMsg1 are merged into the corresponding motor entry by name ID.
  • If the WebSocket connection to the server drops, the sender automatically retries every 3 s and clears the internal queue to avoid stale data.

JSON payload format

{
  "timestamp": "2026-04-05T10:00:00+00:00",
  "statuses": [
    {
      "name": 51,
      "pos": -0.2508,
      "speed": -0.0051,
      "current": -0.0488,
      "temperature": 30.0,
      "motor_temp": 28.5,
      "mos_temp": 31.2,
      "error": 0
    }
  ],
  "power": {
    "voltage": 52.30,
    "current": -2.60,
    "power": 100.0,
    "little_voltage": 53.10,
    "little_current": -0.10,
    "little_power": 94.0
  }
}

Quick-start (end-to-end)

  1. On the monitor server (PC on the same LAN):

    pip install fastapi uvicorn
    python main_monitor.py
    
  2. On the robot controller (source your ROS 2 workspace first):

    source /home/ubuntu/ros2ws/install/setup.bash
    python3 monitor_sender.py --ip <your-server-ip>
    
  3. Open browser: navigate to http://<your-server-ip>:8000


File Overview

File Description
main_monitor.py FastAPI server — hosts the web GUI and relays data to browsers
monitor_sender.py ROS 2 node — collects robot data and streams it to the server
README.md This file
scripts/start_monitor_sender.sh Bootstrap script for hotspot connect, environment setup, and sender launch
deploy/xmonitor.env.example Template for /etc/xmonitor/xmonitor.env
deploy/xmonitor-sender.service systemd service template for robot-side autostart

Robot Sender Autostart (Ubuntu + systemd)

For field deployment on the robot controller, this repo now includes:

  • scripts/start_monitor_sender.sh
  • deploy/xmonitor.env.example
  • deploy/xmonitor-sender.service

The design stays intentionally small:

  • the startup script keeps trying to join your phone hotspot with nmcli
  • it waits until the PC hotspot IP is reachable
  • it sources the ROS setup and .venv
  • it launches python3 monitor_sender.py --ip <server-ip> --port <port>
  • systemd restarts the process after crashes, while logs go to both journalctl and ~/xMonitor/logs/

Install on the Ubuntu robot device

Assuming the repo is deployed at /home/ubuntu/xMonitor:

cd /home/ubuntu/xMonitor

sudo install -d -m 700 /etc/xmonitor
sudo cp deploy/xmonitor.env.example /etc/xmonitor/xmonitor.env
sudo chmod 600 /etc/xmonitor/xmonitor.env
sudoedit /etc/xmonitor/xmonitor.env

chmod +x scripts/start_monitor_sender.sh
sudo cp deploy/xmonitor-sender.service /etc/systemd/system/xmonitor-sender.service

sudo systemctl daemon-reload
sudo systemctl enable --now xmonitor-sender.service

If you deploy the repo somewhere other than /home/ubuntu/xMonitor, update these together:

  • User= in deploy/xmonitor-sender.service
  • WorkingDirectory= in deploy/xmonitor-sender.service
  • ExecStart= in deploy/xmonitor-sender.service
  • APP_DIR= and RUN_USER= in /etc/xmonitor/xmonitor.env

Runtime checks

# Run the bootstrap script manually for troubleshooting
bash /home/ubuntu/xMonitor/scripts/start_monitor_sender.sh

# Service state
systemctl status xmonitor-sender.service

# Live logs from systemd
journalctl -u xmonitor-sender.service -f

# Per-run log files
ls /home/ubuntu/xMonitor/logs

Behavior

  • Hotspot connect retry: every 5 seconds until the target SSID is connected
  • Server reachability retry: every 5 seconds until SERVER_IP answers ping
  • Python process crash: systemd restarts after 5 seconds
  • WebSocket drop after startup: handled by monitor_sender.py, which already retries every 3 seconds
  • Per-run log files are pruned automatically; default retention is the latest 20 files via LOG_RETENTION_COUNT