Zum Inhalt

AMR - Update-Strategie

Leitfrage: Wie laesst sich das AMR-System aktuell halten, ohne die validierte Funktionskette (ESP32-S3 → Pi5 ROS 2 → Hailo-8L) zu brechen?

Annahmen und Randbedingungen

  • Das System laeuft auf Debian 13 (trixie) — einer Testing-Distribution mit Rolling Updates, nicht dem stabilen Raspberry Pi OS. Das erhoeht das Risiko unerwarteter Paketaenderungen erheblich.
  • ROS 2 Humble laeuft containerisiert (Docker), was es teilweise vom Host-System entkoppelt.
  • Die Messwerte aus Kapitel 6 (Lateraldrift 2,1 cm, Heading Error 0,06° etc.) sind die Referenzbasis — jedes Update muss gegen diese Werte validiert werden.
  • Der Kernel ist ein RPi-spezifischer Build mit Custom-Overlays (imx296, mcp2515-can0, hifiberry-dac), die bei Kernel-Updates brechen koennen.

Risikobewertung der Komponenten

Die Abhaengigkeiten im Stack lassen sich in drei Risikokategorien einteilen:

Hohes Risiko (kann validierte Messwerte oder Hardwarezugriff brechen): Kernel-Updates betreffen direkt die Device-Tree-Overlays fuer CAN-Bus (mcp2515), Kamera (imx296) und Audio (hifiberry-dac). Ein neuer Kernel kann dazu fuehren, dass /dev/can0, die CSI-Kamera oder der HifiBerry-DAC nicht mehr erkannt werden. Ebenso kritisch ist HailoRT — Version 4.23.0 ist an den PCIe-Treiber im aktuellen Kernel gebunden. Ein Versionssprung erfordert, dass Kernel-Modul und Userspace-Library synchron bleiben. Python-Major-Updates (3.13 → 3.14) koennen OpenCV, NumPy und python3-hailort ueber ABI-Inkompatibilitaeten brechen.

Mittleres Risiko (kann Toolchain oder Workflow stoeren): Docker-Engine-Updates sind grundsaetzlich abwaertskompatibel, aber ein Major-Sprung kann das ROS-2-Image invalidieren. PlatformIO und die ESP32-Toolchain koennen bei Updates die platformio.ini-Konfiguration oder den Espressif-Framework-Build brechen. Die v4l2loopback-DKMS-Module werden bei Kernel-Updates neu kompiliert — wenn der Header-Match fehlt, faellt die Kamera-Bridge aus.

Niedriges Risiko (isoliert, unabhaengig vom Kernstack): Userspace-Tools wie rpicam-apps, Git, rsync und reine Python-Pakete innerhalb von virtualenvs.

Strategie: Vier-Schichten-Update-Modell

Die Grundidee: Je tiefer die Schicht, desto seltener und kontrollierter wird aktualisiert.

Schicht 1 — Kernel + Firmware (Freeze, manueller Trigger)

Kernel-Updates auf Debian trixie kommen haeufig und ungefragt. Die Empfehlung ist, den Kernel zu pinnen und nur gezielt zu aktualisieren:

# Aktuellen Kernel pinnen (apt hold) — Debian Trixie auf Pi 5
sudo apt-mark hold \
  linux-image-$(uname -r) \
  linux-image-rpi-2712 \
  linux-headers-$(uname -r) \
  linux-headers-rpi-2712 \
  linux-headers-rpi-v8 \
  linux-headers-6.12.62+rpt-rpi-v8 \
  linux-headers-6.12.62+rpt-common-rpi \
  linux-image-6.12.62+rpt-rpi-v8

# Status pruefen
apt-mark showhold

# Alte Kernel-Pakete entfernen
sudo apt autoremove

Ein Kernel-Update erfolgt nur, wenn ein konkreter Grund vorliegt (Sicherheitsluecke, neuer Treiber). Dann: auf einem separaten SD-Karten-Image testen, alle Overlays pruefen (dtoverlay -l), CAN-Bus-Frames senden/empfangen, Kamerabild verifizieren, Hailo-Inferenz laufen lassen.

Gepinnte Kernel-Pakete:

Paket Version
linux-image-6.12.62+rpt-rpi-2712 Laufender Kernel
linux-image-6.12.62+rpt-rpi-v8 v8-Variante
linux-image-rpi-2712 Meta-Paket
linux-headers-* (4 Pakete) Passende Headers

apt upgrade ueberspringt diese Pakete. Zum Entsperren bei Bedarf: sudo apt-mark unhold <paket>.

Schicht 2 — Systemnahe Pakete (monatlich, selektiv)

HailoRT, v4l2loopback und Python-Systempakete bilden die zweite Schicht. Diese werden nicht per apt upgrade pauschal aktualisiert, sondern einzeln:

# HailoRT und v4l2loopback pinnen
sudo apt-mark hold \
  hailort \
  hailort-pcie-driver \
  python3-hailort \
  v4l2loopback-dkms

# Status pruefen
apt-mark showhold

# Gezielte Einzelupdates mit Dry-Run (vor tatsaechlichem Update)
sudo apt update
sudo apt install --dry-run python3-hailort python3-opencv

# Wenn Dry-Run OK → ohne --dry-run ausfuehren

Gepinnte Versionen:

Paket Version
hailort 4.23.0
hailort-pcie-driver 4.23.0
python3-hailort 4.23.0-1
v4l2loopback-dkms 0.15.0-2

Schicht 3 — Docker / ROS 2 (quartalsweise oder bei Bedarf)

Der ROS-2-Humble-Container ist die am besten isolierte Komponente. Updates erfolgen durch Rebuild des Docker-Images. Wichtig: Das aktuelle Image taggen, bevor ein neues gebaut wird:

# Aktuelles Image sichern
# Stand 03.04.2026: amr-ros2-humble:latest, 3.9 GB
docker tag amr-ros2-humble:latest amr-ros2-humble:backup-$(date +%Y%m%d)

# Neues Image bauen
cd ~/amr-projekt/amr/docker
docker compose build --no-cache

# Validierung
./run.sh ros2 launch my_bot full_stack.launch.py use_nav:=false
# Odometrie, SLAM, Sensoren pruefen
# Dann Nav2, Docking, Dashboard testen

# Bei Regression: Rollback
docker tag amr-ros2-humble:backup-YYYYMMDD amr-ros2-humble:latest

ROS 2 Humble erreicht EOL im Mai 2027 — ein Migrationspfad zu Jazzy sollte mittelfristig geplant werden, ist aber fuer die Projektarbeit nicht zeitkritisch.

Schicht 4 — Toolchain / Entwicklungsumgebung (bei Bedarf)

PlatformIO und die ESP32-Toolchain werden nur aktualisiert, wenn ein Firmware-Feature es erfordert. Der aktuelle Stand (PlatformIO 6.1.19, espressif32 @ 6.13.0) ist stabil und fuer den ESP32-S3-Dual-Core-Build validiert.

# PlatformIO-Update (nur bewusst, nicht automatisch)
pio upgrade                     # PlatformIO Core
pio pkg update -g -p espressif32  # Platform global

# Projekt-Libraries aktualisieren (pro Projekt)
cd ~/amr-projekt/amr/mcu_firmware/drive_node && pio pkg update
cd ~/amr-projekt/amr/mcu_firmware/sensor_node && pio pkg update

# Validierung: beide Nodes kompilieren
cd ~/amr-projekt/amr/mcu_firmware/drive_node && pio run -e drive_node
cd ~/amr-projekt/amr/mcu_firmware/sensor_node && pio run -e sensor_node

# Dann flashen und gegen Kapitel-6-Referenzwerte testen

Nach jedem Toolchain-Update: pio run -e drive_node && pio run -e sensor_node, dann auf dem ESP32 flashen und gegen die Kapitel-6-Referenzwerte testen.

Backup-Strategie (Voraussetzung fuer jedes Update)

Bevor ein Update aus Schicht 1 oder 2 durchgefuehrt wird: Dateisystem-Backup ueber Ethernet erstellen.

Pi → Mac (Backup erstellen)

# tmux-Session starten (SSH-sicher)
sudo apt install -y tmux && tmux new -s backup

# Dateisystem-Snapshot ueber Ethernet (~25 GB, ca. 10-20 Min)
sudo rsync -avz \
  --exclude={"/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/swapfile","/lost+found"} \
  --exclude={"/var/cache/*","/var/tmp/*","/var/log/*"} \
  --exclude={"/home/pi/.cache/*","/home/pi/.local/share/Trash/*"} \
  --exclude={"*.img",".pio/",".venv/","__pycache__/","node_modules/",".docker/",".platformio/"} \
  --exclude={".claude.json.tmp.*",".vscode-server/",".hailo/","amr-projekt-backup.git"} \
  --exclude={"embedded_projekt/","selection-panel/"} \
  -e "ssh -i /home/pi/.ssh/id_ed25519" \
  / jan@192.168.1.210:~/amr-rootfs-$(date +%Y%m%d)/

tmux-Session trennen: Ctrl+B, dann D. Wieder verbinden: tmux attach -t backup.

Backup pruefen (auf dem Mac)

du -sh ~/amr-rootfs-20260403/

Mac → SD-Karte (Wiederherstellung)

SD-Karte aus dem Pi nehmen und in den Mac einlegen:

# 1. SD-Karte identifizieren
diskutil list
# Typisch: disk4s1 = boot (FAT32), disk4s2 = rootfs (ext4)

# 2. macOS kann kein ext4 schreiben — daher via Docker
docker run --rm -it --privileged \
  -v ~/amr-rootfs-20260403:/backup:ro \
  --pid=host \
  ubuntu bash

# 3. Im Container: Backup auf SD-Karte schreiben
apt-get update && apt-get install -y rsync
mkdir -p /mnt/rootfs
mount /dev/disk4s2 /mnt/rootfs
rsync -av --delete /backup/ /mnt/rootfs/
umount /mnt/rootfs
exit

Hinweis: --delete entfernt Dateien auf der SD-Karte, die nicht im Backup sind — damit wird der Zustand exakt wiederhergestellt. Device-Name (disk4s2) unbedingt mit diskutil list pruefen!

Alternative mit Paragon extFS for Mac (nativer ext4-Schreibzugriff):

rsync -av --delete ~/amr-rootfs-20260403/ /Volumes/rootfs/