Saqr/docs/DEPLOY.md

9.3 KiB

Saqr PPE Detection — Deployment Guide

Unitree G1 Robot + Intel RealSense D435I


Robot Details

Item Value
Robot Unitree G1 Humanoid
IP 192.168.123.164
User unitree
OS Ubuntu 20.04 (aarch64 / Jetson)
Python 3.10 (conda env: marcus, legacy: teleimager)
Camera Intel RealSense D435I
Serial 243622073459
Port USB 3.2 @ /dev/video0

Repo layout

saqr/           # python package (core/apps/gui/robot/utils)
scripts/        # deploy.sh, start_saqr.sh, run_local.sh, run_robot.sh, saqr-bridge.service
config/         # logging.json
data/           # dataset/, models/        (gitignored)
runtime/        # captures/, logs/, runs/  (gitignored)
docs/           # this file, start.md, use_case_catalogue.pdf
pyproject.toml  # installs the `saqr`, `saqr-bridge`, `saqr-gui`, ... scripts

Step 1: Train the Model (Dev Machine)

cd ~/Robotics_workspace/yslootahtech/Project/Saqr
conda activate AI_MSI_yolo
pip install -e .
saqr-train --dataset data/dataset --epochs 100 --batch 16

Verify model exists:

ls -lh data/models/saqr_best.pt
# Expected: ~5.3 MB

Step 2: Deploy to Robot (Dev Machine)

# From the project root:
scripts/deploy.sh                    # rsync the tree + pip install -e
scripts/deploy.sh --run              # ...and start the bridge
scripts/deploy.sh --ip 10.0.0.5      # custom robot IP

The script rsyncs saqr/, scripts/, config/, docs/, pyproject.toml, requirements.txt, and README.md to ~/Saqr on the robot, then runs pip install -e . inside the target conda env (default marcus).


Step 3: Install Dependencies (Robot, one-time)

If scripts/deploy.sh ran pip install -e . successfully, you're done. Otherwise, on the robot:

ssh unitree@192.168.123.164
source ~/miniconda3/etc/profile.d/conda.sh
conda activate marcus
cd ~/Saqr
pip install -e .

Jetson GPU PyTorch (JetPack 5.1 / CUDA 11.4)

pip uninstall torch torchvision -y
pip install --no-cache-dir \
  https://developer.download.nvidia.com/compute/redist/jp/v51/pytorch/torch-2.1.0a0+41361538.nv23.06-cp310-cp310-linux_aarch64.whl
pip install --no-cache-dir \
  https://developer.download.nvidia.com/compute/redist/jp/v51/pytorch/torchvision-0.16.1a0+5e8e2f1-cp310-cp310-linux_aarch64.whl

System clock (pip/SSL need a correct date)

sudo date -s "2026-04-10 15:00:00"

Verify

python -c "from ultralytics import YOLO; print('ultralytics OK')"
python -c "import torch; print('CUDA:', torch.cuda.is_available())"
python -c "import cv2; print('opencv OK')"
python -c "import saqr; print('saqr', saqr.__version__)"

Step 4: Run Saqr (Robot)

Production: bridge with R2+X / R2+Y

The bridge owns the DDS clients and spawns saqr on demand. On the robot:

cd ~/Saqr
scripts/start_saqr.sh                 # manual launch
sudo systemctl restart saqr-bridge    # systemd-managed (see start.md)

Or without the helper script:

conda activate marcus
python -m saqr.robot.bridge --iface eth0 --source realsense --headless -- --stream 8080

Plain saqr (no bridge)

# With display
scripts/run_robot.sh --stream 8080

# Headless
scripts/run_robot.sh --headless --stream 8080

# V4L2 fallback if RealSense SDK won't enumerate
scripts/run_robot.sh --source /dev/video2 --headless

Equivalent python -m forms:

python -m saqr.apps.saqr_cli --source realsense --model saqr_best.pt --headless
python -m saqr.apps.detect_cli --source /dev/video2 --model saqr_best.pt
python -m saqr.apps.manager_cli --export

Dev machine GUI

pip install -e ".[gui]"
python -m saqr.gui.app --source 0

Bridge behavior (R2+X / R2+Y)

Press Action
R2 + X Start saqr subprocess. Robot stays silent (no "Saqr activated." — see note below).
R2 + Y Stop saqr, robot says "Saqr deactivated." Bridge stays ready.
Ctrl+C in terminal Stop saqr (if running) and exit the bridge.

Per-detection behavior (while saqr is running)

Transition TTS (speaker_id=2, English) Arm action
→ UNSAFE "Please stop. Wear your proper safety equipment. You are missing {items}." reject (id=13) + auto release arm
→ SAFE "Safe to enter. Have a good day."
→ PARTIAL

Bridge startup announces "Saqr is running. Press R2 plus X to start.".

Note on speaker_id=2: TTS speaker_ids are locked to a language on the current G1 firmware. speaker_id=0 is Chinese regardless of input text. speaker_id=2 was confirmed English via Project/Sanad/voice_example.py 6.

Note on SIGINT traceback: when R2+Y stops saqr, Python may print a KeyboardInterrupt traceback from inside YOLO. The bridge catches the exit, announces "Saqr deactivated.", and stays alive.


Bridge CLI flags

Flag Default Description
--iface (default DDS) DDS network interface, e.g. eth0
--timeout 10.0 Arm/Audio/LowState client timeout (seconds)
--cooldown 8.0 Per-(track_id, status) seconds before re-triggering TTS/arm
--release-after 2.0 Seconds before auto release arm (0 = never)
--speaker-id 2 G1 TtsMaker speaker_id
--dry-run off Parse events but never call the SDK; implies --no-trigger
--no-trigger off Skip the R2+X/R2+Y loop and start saqr immediately
--source / --headless / --saqr-conf / --imgsz / --device Passed through to saqr
-- <extra> Everything after -- is forwarded raw to saqr (e.g. -- --stream 8080)

Step 5: Check Results

cat runtime/captures/result.csv     # current state per tracked person
cat runtime/captures/events.csv     # audit log
ls runtime/captures/{SAFE,PARTIAL,UNSAFE}/

saqr-manager --export               # quick CSV export

# Download to dev machine
scp -r unitree@192.168.123.164:~/Saqr/runtime/captures ./captures_from_robot

Camera sources

Source Flag Notes
RealSense SDK --source realsense Uses pyrealsense2; preferred
RealSense by serial --source realsense:243622073459
V4L2 RGB --source /dev/video2 OpenCV fallback; pure MJPG
First OpenCV camera --source 0
Video file --source path.mp4

G1 V4L2 map for the D435I:

/dev/video0  - Stereo module (infrared) — won't open with OpenCV
/dev/video1  - Stereo metadata
/dev/video2  - RGB camera (640x480)    ← USE THIS
/dev/video3  - RGB metadata
/dev/video4  - RGB camera (secondary stream)

Tuning parameters

Parameter Flag Default
Confidence --conf 0.35
Max missing frames --max-missing 90
Match distance (px) --match-distance 250
Confirm frames --status-confirm-frames 5

Recommended for G1 patrol:

saqr --source realsense --headless \
     --conf 0.30 --max-missing 120 --match-distance 300 --status-confirm-frames 7

Compliance rules

Status Condition Colour
SAFE Helmet AND vest, no violations Green
PARTIAL Only helmet OR only vest Yellow
UNSAFE no-helmet or no-vest, or nothing detected Red

Output files

File Location Description
result.csv runtime/captures/ Current state of tracked persons
events.csv runtime/captures/ Audit log (NEW / STATUS_CHANGE)
Person crops runtime/captures/{SAFE,PARTIAL,UNSAFE}/*.jpg Latest crop per track
Logs runtime/logs/Inference/*.log Module log output

Source map

Path Purpose
saqr/apps/saqr_cli.py Main PPE tracking entry (saqr)
saqr/robot/bridge.py Saqr → G1 bridge (R2+X/R2+Y)
saqr/robot/robot_controller.py G1 arm + audio + TTS worker
saqr/robot/controller.py G1 wireless-remote DDS reader
saqr/core/pipeline.py Per-frame detect + track + emit
saqr/core/tracking.py PersonTracker, Track
saqr/core/events.py Event-line format (contract with bridge)
saqr/apps/detect_cli.py Simple detection without tracking
saqr/apps/train_cli.py YOLO11n training
saqr/apps/manager_cli.py Capture CRUD + CSV export
saqr/gui/app.py PySide6 desktop GUI

Troubleshooting

RealSense not detected

lsusb | grep Intel
rs-enumerate-devices | head -10
sudo usbreset /dev/bus/usb/002/002   # if the USB is stuck

ModuleNotFoundError: saqr

# Make sure you're in the right env and the package is installed
which python
pip install -e ~/Saqr

System clock wrong (SSL errors)

sudo date -s "2026-04-10 15:00:00"

Model not found

ls ~/Saqr/data/models/       # should list saqr_best.pt

Too many duplicate track IDs

saqr --source realsense --max-missing 150 --match-distance 300 --headless