Tutorial · Einsteiger · 1 Stunde

ROS 2 auf einem Raspberry Pi installieren und Workspace bauen

ROS 2 auf einem Raspberry Pi starten: das richtige OS wählen, aus apt installieren, einen colcon-Workspace bauen und Laptop und Roboter im WLAN finden.

Einführung

Nichts an ROS 2 ist schwierig, bis man es auf einem Roboter installiert – dann gehen drei unverbundene Dinge zugleich schief: Das Betriebssystem ist das falsche, der Workspace baut nicht in den Pi-Speicher, und der Laptop sieht die Nodes des Roboters nicht. Keines davon ist exakt ein ROS-Problem – weshalb die offiziellen Tutorials davor nicht warnen.

Das bringt von leerer SD-Karte zu ros2 topic list, das vom Laptop aus gegen Nodes auf dem Roboter funktioniert.

Das Betriebssystem wählen, nicht nur das Board

ROS-2-Binärpakete werden für Ubuntu gebaut, nicht Raspberry Pi OS. Raspberry Pi OS ist Debian-basiert – die apt-Pakete sind schlicht nicht da, und jeder Workaround – aus Quellen bauen, Docker, Conda – kostet Stunden, bevor man Robotercode geschrieben hat.

Also Ubuntu Server 24.04 LTS (64-Bit) installieren und auf die ROS-2-Version abstimmen, die dagegen gebaut ist. Zum Schreibzeitpunkt heißt diese Paarung Jazzy Jalisco, supportet bis 2029; die Installationsseite prüfen für das jeweils Aktuelle beim Lesen und den Namen durchgehend ersetzen.

Drei Dinge beim Flashen richtig machen:

  • 64-Bit. ROS-2-arm64-Pakete existieren; armhf keine.
  • Server, nicht Desktop. Ein Roboter hat keinen Monitor – und die Desktopumgebung kostet RAM, das man für Vision will.
  • Pi 4 mit 4 GB oder Pi 5. Ein 2-GB-Board fährt ROS 2 gut, kompiliert es aber nicht bequem.

ROS 2 aus apt installieren

Die ROS-2-apt-Quelle hinzufügen, dann installieren. Das Repository-Setup ändert sich zwischen Releases – das hier ist also die Form statt Schnipsel zum Auswendiglernen:

sudo apt update && sudo apt install -y software-properties-common curl
sudo add-apt-repository universe

# Fetch and install the package that registers the ROS 2 apt repository and key.
export ROS_APT_SOURCE_VERSION=$(curl -s \
  https://api.github.com/repos/ros-infrastructure/ros-apt-source/releases/latest \
  | grep -F "tag_name" | awk -F\" '{print $4}')
curl -L -o /tmp/ros2-apt-source.deb \
  "https://github.com/ros-infrastructure/ros-apt-source/releases/download/${ROS_APT_SOURCE_VERSION}/ros2-apt-source_${ROS_APT_SOURCE_VERSION}.$(. /etc/os-release && echo $VERSION_CODENAME)_all.deb"
sudo apt install -y /tmp/ros2-apt-source.deb

sudo apt update
sudo apt install -y ros-jazzy-ros-base ros-dev-tools

Beachte ros-base, nicht desktop. Das Desktop-Metapaket zieht RViz und Demo-GUIs heran, die ein headless Roboter nie fährt und deren Installation auf SD-Karte lange dauert. Visualisierung gehört auf deinen Laptop – dort das volle ros-jazzy-desktop installieren.

ros-dev-tools liefert colcon und rosdep. rosdep einmal initialisieren:

sudo rosdep init      # skip if it says the file already exists
rosdep update

Erst den Underlay sourcen, dann dein Overlay

ROS 2 tut nichts, bis seine Umgebung gesourct ist – und hier lebt die meiste frühe Verwirrung.

source /opt/ros/jazzy/setup.bash

Das ist der Underlay – die installierte Distribution. Der eigene Workspace, einmal gebaut, ist ein Overlay obendrauf. Ein Overlay zu sourcen zieht implizit den Underlay mit, gegen den es gebaut wurde.

echo "source /opt/ros/jazzy/setup.bash" >> ~/.bashrc

Den Underlay in .bashrc zu legen ist Standard und sicher. Dein Overlay dorthin zu legen ist eine Falle, die sich lohnt, früh zu meiden: An dem Tag, wo du zwei Workspaces hast oder gegen eine andere Distribution neu baust, startet jede neue Shell lautlos mit alter Umgebung – und du debuggst einen Nachmittag lang ein Phantom. Das Overlay explizit sourcen, pro Shell, im Terminal, das es braucht.

Einen Workspace und ein Paket erzeugen

Ein colcon-Workspace ist ein Verzeichnis mit src/ darin. Das ist die ganze Spezifikation.

mkdir -p ~/ros2_ws/src && cd ~/ros2_ws
ros2 pkg create --build-type ament_python --license Apache-2.0 my_robot

Dann bauen und darüberlegen:

cd ~/ros2_ws
rosdep install --from-paths src --ignore-src -y
colcon build --symlink-install
source install/setup.bash

--symlink-install verwenden. Es verlinkt deine Pythondateien in den Installationsraum statt sie zu kopieren – Codeeditieren wirkt also beim nächsten Start statt nach Neubau. Auf einem Pi, wo Neubau langsam ist, ist das der Unterschied zwischen Iterieren und Warten.

Nach dem Bau hält ~/ros2_ws build/, install/ und log/ neben src/. Nur src/ gehört in Versionskontrolle.

Bauen, ohne dem Pi den Speicher auszugehen

colcon build kompiliert Pakete parallel, ein Prozess pro Kern – und jedes C++-Kompilat kann den Großteil eines Gigabytes nehmen. Auf einem Vierkern-Pi sind das vier schwere Compiler zugleich – und der Bau stirbt mit Meldung über getöteten Prozess, oder das ganze Board hängt sich auf.

MAKEFLAGS="-j1" colcon build --parallel-workers 1 --symlink-install

Langsamer, und es beendet. Reine Pythonpakete haben dieses Problem nicht; es beißt, sobald man irgendetwas mit C++ darin baut. Ein paar Gigabyte Swap dazu funktionieren auch – auf SD-Karte allerdings quälend langsam.

Vom Laptop mit dem Roboter sprechen

ROS 2 hat keinen Master. Nodes finden sich per DDS-Discovery übers Netz – Laptop und Pi im selben LAN bilden also ohne Konfiguration überhaupt einen Graphen, wenn es funktioniert.

Dieselbe Domain auf beiden Rechnern setzen:

export ROS_DOMAIN_ID=42        # any value 0–101; the same on every machine

Die Domain partitioniert das Netz. Zwei Roboter im selben Raum auf Standarddomain hören die Topics des anderen und kämpfen darum – eine denkwürdige Art zu lernen, was diese Einstellung tut.

Diagramm eines Zwei-Rechner-ROS-2-Aufbaus: ein Raspberry Pi auf dem Roboter mit Kamera-, Detektor- und Antriebsnodes, und ein Laptop mit RViz und Kommandozeilenwerkzeugen, verbunden per WLAN-Wolke beschriftet DDS-Discovery über Multicast. Beide Rechner sind mit derselben ROS_DOMAIN_ID annotiert, und eine Notiz markiert den Access Point als die Komponente, die Multicast blockiert.
Ein ROS-2-Graph über zwei Rechner: Nodes auf dem Roboter, Visualisierung auf dem Laptop, und ein Discovery-Schritt dazwischen, der davon abhängt, dass der Access Point Multicast weiterleitet. SVG herunterladen

Vom Laptop verifizieren, bei laufendem Talker auf dem Pi:

ros2 topic list
ros2 node list
ros2 topic echo /chatter

Discovery WLAN-überlebensfähig machen

ros2 topic list, das nichts zeigt, während das Pi eindeutig publiziert, ist der häufigste einzelne ROS-2-Netzwerkfehler – und fast nie ROS’ Schuld.

Discovery nutzt Multicast, und viele Access Points leiten ihn nicht weiter. Consumer-WLAN-Router drosseln oder verwerfen Multicast häufig, und „Client-Isolation“- oder Gastnetzmodi blockieren Client-zu-Client-Verkehr glatt. Die Nodes laufen; die Pakete, die sie vorstellen würden, kommen nie an.

In dieser Reihenfolge durcharbeiten:

  1. Dasselbe Subnetz? Ein Laptop auf 5 GHz und ein Pi auf Gast-SSID sind nicht im selben Netz, wie ähnlich die Adressen aussehen.
  2. Dieselbe ROS_DOMAIN_ID, in der Shell, die die Node wirklich fährt? Ein export in einem Terminal erreicht kein anderes – und keinen systemd-Dienst.
  3. Kabelgebunden probieren. Funktioniert Ethernet und WLAN nicht, ist Multicast bewiesen, nicht ROS.
  4. Die Firewall prüfen. sudo ufw allow in proto udp from <Subnetz> an beiden Enden, oder zum Testen deaktivieren.
  5. Auf einen Discovery-Server zurückfallen. Fast DDS kann statt Multicast einen bekannten Endpunkt nutzen – ROS_DISCOVERY_SERVER auf beiden Rechnern auf die Roboteradresse setzen. Das ist die verlässliche Antwort in einem Netz, das man nicht kontrolliert.

Noch eines, und es ist ein leises: Die Uhren synchron halten. TF2 vergleicht Zeitstempel über Rechner – und ein Pi ohne RTC startet mit falscher Zeit. chrony an beiden Enden installieren, sonst scheitert jeder Transform-Lookup mit Extrapolationsfehler, der wie ein ROS-Fehler aussieht.

Die Nodes des Roboters beim Start starten

Ein Roboter, in den man sich per SSH einwählen muss, um zu starten, ist ein ausgeschalteter Roboter. Eine systemd-Unit behebt es:

# /etc/systemd/system/my-robot.service
[Unit]
Description=Robot bringup
After=network-online.target

[Service]
User=ubuntu
Environment=ROS_DOMAIN_ID=42
ExecStart=/bin/bash -lc 'source /opt/ros/jazzy/setup.bash && \
  source /home/ubuntu/ros2_ws/install/setup.bash && \
  ros2 launch my_robot bringup.launch.py'
Restart=on-failure

[Install]
WantedBy=multi-user.target
sudo systemctl enable --now my-robot
journalctl -u my-robot -f

Die Environment=-Zeile zählt mehr, als es aussieht. systemd liest deine .bashrc nicht – ein Dienst erbt also keine ROS-Variablen deiner interaktiven Shell: genau darum geht ein Roboter, der über SSH arbeitet, lautlos, wenn er sich selbst startet.

Wenn es schiefgeht

Symptom Meist
ros2: command not found Der Underlay wurde in dieser Shell nie gesourct
ros2 topic list leer vom Laptop Multicast blockiert oder ROS_DOMAIN_ID unpassend
Bau stirbt mittendrin ohne Fehler Speicher aus – parallele Worker begrenzen
Deine Codeänderung wirkte nicht Ohne --symlink-install gebaut oder Overlay nicht neu gesourct
Paket nach Bauen nicht gefunden Overlay nicht gesourct, oder vor Bauende gesourct
TF-Fehler über Extrapolation in die Zukunft Uhren zwischen Rechnern nicht synchronisiert
Über SSH in Ordnung, beim Start tot systemd-Dienst ohne ROS-Umgebung

Bei benimmender Umgebung ist die nächste Frage, was man hineintut – was ein Entwurfs- statt Installationsproblem ist. Nodes, Topics, Services und Actions deckt die Wahl zwischen Kommunikationsmustern ab, und TF2-Koordinatenframes den Teil, der danach Leute erwischt.

Den Graphen erkunden

Teil dieser Bauprojekte

Projekte und Lernpfade, die dieses Tutorial enthalten.

Weiterführende Literatur

Quellen