Build und Deployment¶
Fuer eine schrittweise Inbetriebnahme-Anleitung siehe benutzerhandbuch.md.
Firmware (PlatformIO, zwei getrennte Projekte)¶
Die MCU-Firmware besteht aus zwei getrennten PlatformIO-Projekten mit identischem Dual-Core-Pattern (Core 0: micro-ROS Executor, Core 1: Echtzeit-Datenerfassung + CAN).
Drive-Knoten (Antrieb, PID, Odometrie, LED)¶
cd amr/mcu_firmware/drive_node
pio run -e drive_node # Kompilieren
pio run -e drive_node -t upload -t monitor # Upload + Monitor
pio run -e led_test -t upload -t monitor # LED/MOSFET-Diagnose (~5s)
Sensor-Knoten (Ultraschall, Cliff, IMU, Batterie, Servo)¶
cd amr/mcu_firmware/sensor_node
pio run -e sensor_node # Kompilieren
pio run -e sensor_node -t upload -t monitor # Upload + Monitor
Erster Build pro Knoten: ~15 Min (micro-ROS aus Source). Folgebuilds gecached.
Firmware-Pruefung des Drive-Knoten¶
Falls unklar ist, ob die korrekte Firmware laeuft:
Kriterium:
- Binaere XRCE-DDS-Daten mit
0x7e-Header: korrekt - Text wie
duty= 255/1023: falsches Environment (led_test)
Falls die falsche Firmware aktiv ist:
ROS2 und Docker¶
ROS2 Humble laeuft auf dem Pi 5 im Docker-Container (amr_ros2). Das Docker-Image wird aus amr/docker/Dockerfile gebaut.
Einmalige Einrichtung¶
cd amr/docker/
sudo bash host_setup.sh # udev-Regeln, Gruppen, Kamera-Bridge, CAN-Service
docker compose build # Image bauen (~15-20 Min auf Pi 5)
Container-Wrapper run.sh¶
Der Convenience-Wrapper amr/docker/run.sh verwaltet den Container-Lebenszyklus:
cd amr/docker/
./run.sh # Interaktive Shell
./run.sh bash # Interaktive Shell (explizit)
./run.sh ros2 topic list # Einzelbefehl ausfuehren
./run.sh ros2 launch my_bot full_stack.launch.py # Full-Stack starten
./run.sh colcon build --packages-select my_bot --symlink-install # Build
./run.sh exec bash # Zweites Terminal im laufenden Container
run.sh erledigt automatisch:
- Container via
docker compose up -dstarten (falls nicht laufend) - udev-Symlinks (
/dev/amr_drive,/dev/amr_sensor) im Container anlegen - Kamera-Bridge-Pruefung bei
use_camera:=True
Colcon Build¶
Verifikation¶
Full-Stack Launch¶
Launch-Argumente¶
| Argument | Default | Beschreibung |
|---|---|---|
use_slam | True | SLAM Toolbox (async Modus) |
use_nav | True | Nav2 Navigation Stack |
use_rviz | False | RViz2 Visualisierung |
use_sensors | True | Sensor-Knoten ESP32-S3 |
use_dashboard | False | Dashboard-Bridge (WebSocket :9090, MJPEG :8082) |
use_camera | False | Kamera-Knoten (v4l2_camera_node) |
use_vision | False | Vision-Pipeline (Hailo UDP + Gemini) |
use_cliff_safety | True | Cliff-Safety cmd_vel-Multiplexer |
use_audio | False | Audio-Feedback (MAX98357A I2S, Docker-Volume asound.conf fuer softvol) |
use_can | False | CAN-to-ROS2 Bridge (SocketCAN) |
use_tts | False | TTS-Sprachausgabe (Gemini-Semantik via gTTS) |
use_respeaker | False | ReSpeaker Mic Array DoA/VAD |
use_voice | False | Sprachsteuerung (erfordert use_respeaker:=True, Gemini Audio-STT primaer / faster-whisper Fallback) |
drive_serial_port | /dev/amr_drive | Serieller Port Drive-Knoten |
sensor_serial_port | /dev/amr_sensor | Serieller Port Sensor-Knoten |
camera_device | /dev/video10 | Video-Device (v4l2loopback-Bridge) |
params_file | nav2_params.yaml | Nav2 Parameter-Datei |
slam_params_file | mapper_params_online_async.yaml | SLAM Toolbox Parameter-Datei |
Haeufige Startkombinationen¶
cd amr/docker/
# Nur SLAM (ohne Navigation)
./run.sh ros2 launch my_bot full_stack.launch.py use_nav:=false
# SLAM + Navigation + Dashboard (ohne RViz)
./run.sh ros2 launch my_bot full_stack.launch.py use_dashboard:=True use_rviz:=False
# Vollsystem mit Kamera und Vision
./run.sh ros2 launch my_bot full_stack.launch.py \
use_dashboard:=True use_camera:=True use_vision:=True use_rviz:=False
ESP32-Reset¶
Die ESP32-S3-Knoten besitzen keine eigenstaendige Reconnection-Logik fuer den micro-ROS-Agent. Ein Reset vor dem Containerstart stellt sicher, dass die Knoten beim Agent-Start in den Wartezustand eintreten.
python3 -c "
import serial, time
for name, port in [('Drive', '/dev/amr_drive'), ('Sensor', '/dev/amr_sensor')]:
try:
s = serial.Serial(port, 921600)
s.dtr = False
s.rts = True
time.sleep(0.1)
s.dtr = False
s.rts = False
time.sleep(0.1)
s.close()
print(f'{name} ({port}) reset OK')
except Exception as e:
print(f'{name} ({port}) reset FEHLER: {e}')
time.sleep(2)
print('Warte 2s auf Boot...')
"
Gemini API-Schluessel¶
Fuer Vision (Hailo + Gemini), TTS-Sprachausgabe und Sprachsteuerung wird ein Gemini API-Schluessel benoetigt.
# Neuen Gemini API-Schluessel erstellen unter https://aistudio.google.com/apikey
# Genutztes Modell: gemini-2.0-flash-lite (Semantic Vision und TTS; Voice nutzt Gemini Audio-STT primaer / faster-whisper Fallback)
# Schluessel anzeigen
cat ~/amr-projekt/scripts/.gemini_api.key
# Schluessel wird via docker-compose.yml als GEMINI_API_KEY in den Container durchgereicht
Vollstart (alle Subsysteme, vier Terminals)¶
Dieser Ablauf startet das Gesamtsystem fuer den Live-Betrieb mit SLAM, Kamera, Dashboard, Hailo-basierter Objekterkennung, CAN-Bus, Sprachsteuerung und semantischer Auswertung.
Voraussetzungen¶
- Das HEF-Modell liegt unter
hardware/models/yolov8s.hef. GEMINI_API_KEYist in der Host-Umgebung gesetzt (siehe oben).- Das Docker-Image ist aktuell (
docker compose build). - Kein anderer Prozess blockiert die seriellen Ports.
- Auf dem Drive-Knoten laeuft die korrekte Firmware, nicht
led_test.
Startsequenz¶
Der Live-Betrieb benoetigt vier Terminals. T1 ist einmalig (Reset + Pruefung), T2-T4 sind langlebige Prozesse.
T1: Reset beider ESP32-S3 via DTR/RTS (einmalig)¶
lsusb
ls /dev/ttyACM* /dev/ttyUSB* /dev/amr_*
cd ~/amr-projekt
python3 -c "import serial,time;[exec('s=serial.Serial(p,921600);s.dtr=False;s.rts=True;time.sleep(0.1);s.dtr=True;s.rts=False;s.close()') for p in ['/dev/amr_drive','/dev/amr_sensor']]"
T2: Full-Stack Launch mit allen Subsystemen¶
cd ~/amr-projekt/amr/docker
./run.sh ros2 launch my_bot full_stack.launch.py \
use_dashboard:=True use_camera:=True use_vision:=True \
use_audio:=True use_respeaker:=True use_tts:=True \
use_voice:=True use_can:=True
Erfolgsindikatoren:
micro_ros_agent_drive:session establishedmicro_ros_agent_sensor:session establishedslam_toolbox:Registering sensordashboard_bridge: WebSocket- und MJPEG-Server gestartetgemini_semantic_node: Modell konfigurierthailo_udp_receiver: wartet auf den Host-Runnercan_bridge_node: CAN-Bus verbunden
T3: Hailo-8L Vision auf dem Host (Python 3.13)¶
Falls keine Hailo-Hardware angeschlossen ist:
Kriterium:
- Der Runner verbindet sich mit dem MJPEG-Stream der
dashboard_bridge. - Erste Detektionen erscheinen nach erfolgreichem Stream-Zugriff.
T4: Vite-Dev-Server Dashboard¶
Die Benutzeroberflaeche ist danach erreichbar unter https://amr.local:5173/.
Verifikation¶
Im laufenden System ueber ein zweites Terminal pruefen:
Dann im Container:
ros2 topic list --no-daemon
timeout 5 ros2 topic hz /odom
timeout 5 ros2 topic hz /scan
ros2 topic echo /odom --once --no-daemon
ros2 topic echo /vision/detections --once --no-daemon
Erwartete Kerndaten:
/odomaktiv (~18 Hz)/scanaktiv (~7-8 Hz)/mapaktiv/camera/image_rawaktiv/vision/detectionsaktiv nach Start des Hailo-Runners
System herunterfahren¶
- Host-Runner und Benutzeroberflaeche mit
Ctrl+Cbeenden. - ROS2-Launch in Terminal 1 mit
Ctrl+Cbeenden. - Container und Ports bereinigen:
CAN-Bus (SocketCAN)¶
host_setup.sh Sektion 6 installiert can-utils und den can0.service (systemd, 1 Mbit/s, txqueuelen=1000). Nach Aenderungen an /boot/firmware/config.txt ist ein Reboot noetig.
# CAN-Status pruefen
ip -details link show can0
# CAN-Bridge Diagnostik-Knoten (im Docker)
ros2 launch my_bot full_stack.launch.py use_can:=True
# ReSpeaker DoA/VAD-Knoten (im Docker)
ros2 launch my_bot full_stack.launch.py use_respeaker:=True
# Standalone CAN-Validierung (ohne Docker)
python3 amr/scripts/can_validation_test.py --duration 30
Dashboard (React + Vite + TypeScript + Tailwind)¶
cd dashboard/
npm install && npm run dev -- --host 0.0.0.0 # Entwicklung (https://amr.local:5173)
npm run build # Produktion (tsc + vite build)
npm run lint # ESLint
npx tsc --noEmit # TypeScript Type-Check
Die Benutzeroberflaeche verbindet sich automatisch per WebSocket (wss://amr.local:9090) mit der dashboard_bridge im Container. SLAM-Kartenklick sendet ein Nav2 NavigateToPose Goal.
Wartungsskripte¶
# Projekt-Abhaengigkeiten aktualisieren (npm, pip, PlatformIO, Docker, ROS2-Image)
./scripts/update_dependencies.sh
# Systemwartung mit AMR-Diagnose (Temperatur, Speicher, Services, USB, EEPROM)
sudo ./scripts/rover_wartung.sh # Vollstaendig mit apt-Updates
sudo ./scripts/rover_wartung.sh --check # Nur Diagnose, keine Aenderungen
Typische Fehlerbilder¶
micro-ROS-Agent laeuft, aber keine Session¶
Ursachen:
- Falsche Drive-Knoten-Firmware (
led_teststattdrive_node) - ESP32 nach Neustart nicht resettet
Massnahmen:
drive_nodeexplizit flashen:cd amr/mcu_firmware/drive_node && pio run -e drive_node -t upload- DTR/RTS-Reset vor dem Containerstart erneut ausfuehren (siehe Abschnitt ESP32-Reset)
SLAM meldet Message Filter dropping message¶
Ursache:
odom -> base_linkTF fehlt, meist wegen fehlender Verbindung zum Drive-Knoten
Massnahme:
Falls keine Daten: Drive-Knoten Reset und micro-ROS-Agent-Verbindung pruefen.
Hailo meldet HAILO_OUT_OF_PHYSICAL_DEVICES¶
Ursache:
- Alter Runner-Prozess blockiert das Device
Massnahme:
Port-Konflikte bei Neustart¶
Massnahme:
Regel¶
Lange Kommandoablaeufe bleiben hier und nicht in CLAUDE.md.