b91376663a0358d2cad8eded1c1ccf2063135137
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) fromMotorStatusMsg1are merged into the corresponding motor entry bynameID. - 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)
-
On the monitor server (PC on the same LAN):
pip install fastapi uvicorn python main_monitor.py -
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> -
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.shdeploy/xmonitor.env.exampledeploy/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> systemdrestarts the process after crashes, while logs go to bothjournalctland~/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=indeploy/xmonitor-sender.serviceWorkingDirectory=indeploy/xmonitor-sender.serviceExecStart=indeploy/xmonitor-sender.serviceAPP_DIR=andRUN_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_IPanswersping - Python process crash:
systemdrestarts 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
Description
Languages
Python
77%
Shell
23%