Serie
- Erste Schritte mit ROS 2 für die Roboterentwicklung
- Verstärkendes Lernen in der Robotik: Ein umfassender Leitfaden für 2025
Erste Schritte mit ROS 2 für die Roboterentwicklung
Umfassender Leitfaden zu ROS 2 für die professionelle Roboterentwicklung
Nach jahrelanger Entwicklung von AMRs, AGVs und Robotermanipulatoren in Produktionsumgebungen habe ich gelernt, dass der Einstieg in ROS 2 mehr erfordert, als nur Installationsanleitungen zu befolgen. Dieser Leitfaden fasst praktisches Wissen für den Aufbau robuster, produktionsreifer Robotersysteme zusammen.
Warum ROS 2? Eine Perspektive aus der Praxis
Nachdem ich mehrere Produktionssysteme von ROS 1 migriert habe, kann ich Ihnen sagen, dass ROS 2 nicht nur ein Upgrade ist – es ist eine grundlegende Neugestaltung der Roboter-Middleware. Hier ist, worauf es in der Praxis ankommt:
Die DDS-Revolution
ROS 2 nutzt DDS (Data Distribution Service) als Middleware und ersetzt damit das benutzerdefinierte Protokoll von ROS 1 durch einen in der Industrie bewährten Standard, der in Kriegsschiffen und Raumfahrtsystemen zum Einsatz kommt. Das bedeutet:
- Kein Single Point of Failure: Der Master-Knoten von ROS 1 ist weg. Ihr Roboter kommt nicht zum Stillstand, wenn ein Prozess abstürzt.
- Echtzeitfähig: DDS bietet Quality-of-Service (QoS)-Profile für bessere Echtzeitkommunikation, Skalierbarkeit und Sicherheitsleistung
- Sicherheit durch Design: DDS bietet Sicherheitsgarantien, die in ROS 1 nicht vorhanden waren und für kommerzielle Einsätze entscheidend sind
- Plattformübergreifend: Einsatz auf Linux, Windows, macOS und eingebetteten Systemen ohne Codeänderungen
Was sich gegenüber ROS 1 geändert hat
Verbesserungen der Architektur:
- Mehrere Knoten können in einem einzigen Prozess laufen, was eine flexible Zusammensetzung zum Zeitpunkt der Bereitstellung ermöglicht
- Startdateien verwenden nun Python für komplexe Logik und Bedingungen
- Integriertes Lebenszyklusmanagement für Knoten
- Echte parallele Ausführung auf Multi-Core-Prozessoren
Kommunikationsmodell:
- Verteilte Erkennung (kein zentraler Master)
- Konfigurierbare QoS-Richtlinien pro Thema
- Unterstützung sowohl für zuverlässige (TCP-ähnliche) als auch für Best-Effort-Kommunikation (UDP-ähnlich)
Warum dies für AMRs/AGVs wichtig ist: Aus meiner Arbeit mit Lagerrobotern weiß ich, dass die deterministische Echtzeit-Reaktion und die verteilte Architektur bahnbrechend sind. Sie können nun zuverlässig Reaktionszeiten von 2–5 ms für kritische Regelkreise erzielen, was für eine sichere Mensch-Roboter-Zusammenarbeit unerlässlich ist.
Installation & Einrichten der Umgebung
Ubuntu 22.04 (für den Produktionsbetrieb empfohlen)
# Locale einrichten sudo apt update && sudo apt install locales sudo locale-gen en_US en_US.UTF-8 sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 export LANG=en_US.UTF-8 # ROS 2-Repository hinzufügen sudo apt install software-properties-common sudo add-apt-repository universe sudo apt update && sudo apt install curl -y sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null # ROS 2 Humble (LTS) installieren sudo apt update sudo apt install ros-humble-desktop # Entwicklungswerkzeuge installieren sudo apt install python3-colcon-common-extensions python3-rosdep # rosdep initialisieren sudo rosdep init rosdep update
Best Practices für die Einrichtung des Arbeitsbereichs
# Arbeitsbereichsstruktur erstellen mkdir -p ~/ros2_ws/src cd ~/ros2_ws # Mit Optimierungen kompilieren colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release # Zu .bashrc hinzufügen für automatisches Laden echo "source /opt/ros/humble/setup.bash" >> ~/.bashrc echo "source ~/ros2_ws/install/setup.bash" >> ~/.bashrc
Profi-Tipp: Verwenden Sie während der Entwicklung --symlink-install. Dadurch werden symbolische Links erstellt, anstatt Python-Dateien zu kopieren, sodass Sie Skripte bearbeiten können, ohne neu kompilieren zu müssen.
DDS-Middleware verstehen: Eine entscheidende Wahl
Die Standard-DDS-Implementierung seit ROS 2 Galactic ist CycloneDDS, aber auch FastDDS und RTI Connext werden unterstützt. Ihre Wahl hat erhebliche Auswirkungen auf die Leistung.
Vergleich der DDS-Middleware
CycloneDDS (Standard):
- Bietet im Allgemeinen eine bessere Leistung in Szenarien mit hohem Durchsatz und geringerer Latenz
- Sauberere Codebasis, aber weniger Funktionen
- Am besten geeignet für: Standard-Mobilroboter, Forschungsanwendungen
- Installation:
sudo apt install ros-humble-rmw-cyclonedds-cpp
FastDDS:
- Zeigt auf dem Raspberry Pi eine schnellere Leistung im Vergleich zu anderen Middlewares
- Mehr Konfigurationsoptionen und Funktionen
- Native Unterstützung für 5G-Netzwerkflüsse und Zero-Copy-Übertragung
- Am besten geeignet für: Industrielle Anwendungen, Multi-Roboter-Systeme, ressourcenbeschränkte Plattformen
- Installation:
sudo apt install ros-humble-rmw-fastrtps-cpp
Wechseln der DDS-Implementierungen:
# Umgebungsvariable setzen export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # oder export RMW_IMPLEMENTATION=rmw_fastrtps_cpp # Überprüfen ros2 doctor --report | grep middleware
DDS-Konfiguration für den Produktiveinsatz
Für Roboter mit mehreren Schnittstellen (WLAN + Ethernet):
CycloneDDS XML:
<CycloneDDS> <Domain> <General> <NetworkInterfaceAddress>eth0,wlan0</NetworkInterfaceAddress> </General> </Domain> </CycloneDDS>
Setzen: export CYCLONEDDS_URI=file:///path/to/cyclonedds.xml
FastDDS XML:
<profiles> <transport_descriptors> <transport_descriptor> <transport_id>udp_transport</transport_id> <type>UDPv4</type> </transport_descriptor> </transport_descriptors> <participant profile_name="default"> <rtps> <userTransports> <transport_id>udp_transport</transport_id> </userTransports> </rtps> </participant> </profiles>
Set: export FASTRTPS_DEFAULT_PROFILES_FILE=/path/to/fastdds.xml
Quality of Service (QoS): Das Geheimnis zuverlässiger Kommunikation
Bei den QoS-Profilen zeigt ROS 2 seine wahre Stärke. ROS 2 kann so zuverlässig wie TCP oder so „best-effort“ wie UDP sein, mit vielen möglichen Zuständen dazwischen.
Wesentliche QoS-Richtlinien
Zuverlässigkeit:
RELIABLE: Garantiert die Zustellung (wie TCP) – Verwendung für Befehle, KartenBEST_EFFORT: Schnell, kann Nachrichten verlieren (wie UDP) – Verwendung für Sensor-Streams
Beständigkeit:
TRANSIENT_LOCAL: Der Publisher speichert Samples für spät hinzukommende AbonnementsVOLATILE: Keine Persistenz, nur aktuelle Daten
Verlauf:
KEEP_LAST(n): Speichert die letzten n NachrichtenKEEP_ALL: Speichert alle Nachrichten (mit Bedacht verwenden!)
Praktische QoS-Muster
Für Sensordaten (Kamera, LiDAR):
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy sensor_qos = QoSProfile( reliability=ReliabilityPolicy.BEST_EFFORT, history=HistoryPolicy.KEEP_LAST, depth=1 # Nur der aktuellste Frame ist relevant ) subscription = self.create_subscription( Image, '/camera/image', callback, sensor_qos)
Für Karten (SLAM):
map_qos = QoSProfile( reliability=ReliabilityPolicy.RELIABLE, durability=DurabilityPolicy.TRANSIENT_LOCAL, history=HistoryPolicy.KEEP_LAST, depth=1 )
Für Steuerbefehle:
cmd_qos = QoSProfile( reliability=ReliabilityPolicy.RELIABLE, history=HistoryPolicy.KEEP_LAST, depth=1 # Nur der letzte Befehl )
Wichtiger Hinweis: Die Verwendung von „Reliable QoS“ mit tiefen Verlaufswarteschlangen führt zu Befehlsrückstau und Latenz. Verwenden Sie für die Fernsteuerung immer BEST_EFFORT mit depth=1.
Unverzichtbare ROS 2-Pakete
Navigations-Stack (Nav2)
Nav2 ist ein produktionsreifes Navigations-Framework, auf das weltweit über 100 Unternehmen vertrauen. Es bietet Wegplanung, Steuerung, Lokalisierung und Verhaltenskoordination.
Installation:
sudo apt install ros-humble-navigation2 ros-humble-nav2-bringup
Wichtige Funktionen:
- Verhaltensbäume für die Orchestrierung komplexer Aufgaben
- Unterstützung für holonomische, Differential-Drive-, beinebasierte und Ackermann-Basistypen
- Einbündelbare Planer, Steuerungen und Wiederherstellungsverhalten
- Dynamische Hindernisvermeidung
- Wegpunktverfolgung
Konfigurationsstruktur:
- Globale Costmap für die Pfadplanung
- Lokale Costmap für die dynamische Hindernisvermeidung
- Planer-Server (NavFn, Theta*, Smac Hybrid-A*)
- Regler-Server (DWB, TEB, Regulated Pure Pursuit)
- Wiederherstellungsverhalten (Drehen, Rückwärtsfahren, Warten)
Manipulation (MoveIt 2)
Für Roboterarme ist MoveIt 2 der Industriestandard:
sudo apt install ros-humble-moveit
Funktionen:
- Bewegungsplanung (OMPL, Pilz, CHOMP)
- Kollisionsprüfung
- Kinematik (KDL, IKFast, TRAC-IK)
- Trajektorienausführung
- Wahrnehmungseinbindung
SLAM-Toolbox
Für Kartierung und Lokalisierung:
sudo apt install ros-humble-slam-toolbox
Modi:
- Online-Async-SLAM (Echtzeit-Kartierung)
- Offline-SLAM (Nachbearbeitung)
- Lokalisierungsmodus (Karte bereits vorhanden)
- Lifelong-SLAM (kontinuierliche Kartenaktualisierungen)
Wichtige Debugging-Tools
RViz2 – 3D-Visualisierung:
ros2 run rviz2 rviz2
RQt – GUI-Plugins:
ros2 run rqt_console rqt_console # Log-Viewer ros2 run rqt_graph rqt_graph # Knotengrafik ros2 run rqt_plot rqt_plot # Echtzeit-Plotten
Befehlszeilen-Tools:
ros2 topic list # Alle Themen auflisten ros2 topic echo /topic_name # Nachrichten ausgeben ros2 topic hz /topic_name # Frequenz prüfen ros2 node info /node_name # Knotendetails ros2 param list # Parameter auflisten ros2 service list # Dienste auflisten ros2 bag record -a # Alle Themen aufzeichnen
Aufbau Ihres ersten Systems: Ein praktisches Beispiel
Lassen Sie uns ein vollständiges Publisher-Subscriber-System mit ordnungsgemäßer Fehlerbehandlung und QoS aufbauen:
Paketerstellung
cd ~/ros2_ws/src ros2 pkg create --build-type ament_python robot_control \ --dependencies rclpy std_msgs geometry_msgs sensor_msgs
Erweiterter Publisher-Knoten
import rclpy from rclpy.node import Node from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy from geometry_msgs.msg import Twist from sensor_msgs.msg import LaserScan import math class VelocityController(Node): """ Produktionsreifer Geschwindigkeitsregler mit Hindernisvermeidung """ def __init__(self): super().__init__('velocity_controller') # Parameter mit Standardwerten deklarieren self.declare_parameter('max_linear_vel', 0.5) self.declare_parameter('max_angular_vel', 1.0) self.declare_parameter('obstacle_distance', 0.5) # Parameter abrufen self.max_linear = self.get_parameter('max_linear_vel').value self.max_angular = self.get_parameter('max_angular_vel').value self.obstacle_dist = self.get_parameter('obstacle_distance').value # QoS für Sensordaten (Best-Effort, nur die neuesten) sensor_qos = QoSProfile( reliability=ReliabilityPolicy.BEST_EFFORT, history=HistoryPolicy.KEEP_LAST, depth=1 ) # QoS für Befehle (zuverlässig, nur die neuesten) cmd_qos = QoSProfile( reliability=ReliabilityPolicy.RELIABLE, history=HistoryPolicy.KEEP_LAST, depth=1 ) # Abonnenten self.scan_sub = self.create_subscription( LaserScan, '/scan', self.scan_callback, sensor_qos) # Publisher self.cmd_pub = self.create_publisher( Twist, '/cmd_vel', cmd_qos) # Status self.min_distance = float('inf') self.obstacle_detected = False # Timer für Regelkreis (10 Hz) self.timer = self.create_timer(0.1, self.control_loop) self.get_logger().info('Geschwindigkeitsregler initialisiert') def scan_callback(self, msg): """Laserscandaten verarbeiten""" try: # Minimalen Abstand im vorderen Sektor ermitteln (±30 Grad) front_angles = 30 start_idx = len(msg.ranges) // 2 - front_angles end_idx = len(msg.ranges) // 2 + front_angles front_ranges = msg.ranges[start_idx:end_idx] valid_ranges = [r for r in front_ranges if msg.range_min < r < msg.range_max] if valid_ranges: self.min_distance = min(valid_ranges) self.obstacle_detected = self.min_distance < self.obstacle_dist else: self.min_distance = float('inf') self.obstacle_detected = False except Exception as e: self.get_logger().error(f'Scan-Verarbeitungsfehler: {str(e)}') def control_loop(self): """Hauptregelkreis""" cmd = Twist() if self.obstacle_detected: # Not-Aus cmd.linear.x = 0.0 cmd.angular.z = 0.0 self.get_logger().warn( f'Hindernis erkannt bei {self.min_distance:.2f} m – STOPPEN') else: # Normalbetrieb – vorwärts fahren cmd.linear.x = self.max_linear * 0.5 cmd.angular.z = 0.0 self.cmd_pub.publish(cmd) def main(args=None): rclpy.init(args=args) try: controller = VelocityController() rclpy.spin(controller) except KeyboardInterrupt: pass except Exception as e: print(f'Fehler: {e}') finally: controller.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()
Startdatei (Python)
from launch import LaunchDescription from launch.actions import DeclareLaunchArgument, ExecuteProcess from launch.substitutions import LaunchConfiguration from launch_ros.actions import Node def generate_launch_description(): return LaunchDescription([ # Argumente deklarieren DeclareLaunchArgument( 'max_vel', default_value='0.5', description='Maximale lineare Geschwindigkeit' ), # Controller-Knoten starten Node( package='robot_control', executable='velocity_controller', name='velocity_controller', output='screen', parameters=[{ 'max_linear_vel': LaunchConfiguration('max_vel'), 'obstacle_distance': 0.5 }], remappings=[ ('/scan', '/robot/scan'), ('/cmd_vel', '/robot/cmd_vel') ] ), # RViz zur Visualisierung starten ExecuteProcess( cmd=['ros2', 'run', 'rviz2', 'rviz2'], output='screen' ) ])
Simulation mit Gazebo
Gazebo ist über das Paket ros_gz_bridge in ROS 2 integriert und ermöglicht realistische Physiksimulationen.
Installation
# Gazebo Garden (für Humble) sudo apt install ros-humble-ros-gz sudo apt install ros-humble-gazebo-ros-pkgs
Einfache mobile Robotersimulation
URDF/SDF-Modell (vereinfacht):
<?xml version="1.0"?> <robot name="simple_agv"> <link name="base_link"> <visual> <geometry> <box size="0.5 0.3 0.1"/> </geometry> </visual> <collision> <geometry> <box size="0.5 0.3 0.1"/> </geometry> </collision> <gazebo> <plugin name="differential_drive" filename="libgazebo_ros_diff_drive.so"> <update_rate>50</update_rate> <left_joint>left_wheel_joint</left_joint> <right_joint>right_wheel_joint</right_joint> <wheel_separation>0.3</wheel_separation> <wheel_diameter>0.1</wheel_diameter> <command_topic>/cmd_vel/</command_topic> <odometry_topic>odom</odometry_topic> <command_topic>/</command_topic> </plugin> <plugin name="lidar" filename="libgazebo_ros_ray_sensor.so"> <topic>scan</topic> <frame_name>lidar_link</frame_name> </plugin> </gazebo> </robot>
Simulation starten:
# Gazebo-Welt starten ros2 launch gazebo_ros gazebo.launch.py # Roboter erstellen ros2 run gazebo_ros spawn_entity.py \ -entity simple_agv -file simple_agv.urdf
Best Practices für die Systemarchitektur
Domänen-IDs
DDS-Domänen haben Teilnehmerbeschränkungen (120 für RTI Connext v4.2e+). Verwenden Sie unterschiedliche Domänen-IDs für:
- Mehrere Roboter:
export ROS_DOMAIN_ID=1,export ROS_DOMAIN_ID=2 - Entwicklung vs. Produktion:
export ROS_DOMAIN_ID=10(dev) - Netzwerkisolierung: Getrennte Domänen verhindern Übersprechen
Knotenzusammensetzung
Für leistungskritische Anwendungen:
from rclpy.node import Node import rclpy.executors class SensorNode(Node): pass class ControlNode(Node): pass def main(): rclpy.init() executor = rclpy.executors.MultiThreadedExecutor() # Mehrere Knoten in einem Prozess ausführen sensor = SensorNode() control = ControlNode() executor.add_node(sensor) executor.add_node(control) try: executor.spin() finally: executor.shutdown() sensor.destroy_node() control.destroy_node() rclpy.shutdown()
Lebenszyklusverwaltung
Für Produktionssysteme, die einen kontrollierten Start/Abschluss erfordern:
from rclpy.lifecycle import Node, State, TransitionCallbackReturn class LifecycleRobot(Node): def on_configure(self, state: State): self.get_logger().info('Konfigurieren...') # Ressourcen initialisieren return TransitionCallbackReturn.SUCCESS def on_activate(self, state: State): self.get_logger().info('Aktivierung...') # Operationen starten return TransitionCallbackReturn.SUCCESS def on_deactivate(self, state: State): self.get_logger().info('Deaktivieren...') # Vorgänge sicher beenden return TransitionCallbackReturn.SUCCESS def on_cleanup(self, state: State): self.get_logger().info('Aufräumen...') # Ressourcen freigeben return TransitionCallbackReturn.SUCCESS
VPN und Fernsteuerung
Für die Flottenverwaltung über Netzwerke hinweg:
VPN-Einrichtung mit WireGuard:
# WireGuard installieren sudo apt install wireguard # Schnittstelle konfigurieren sudo nano /etc/wireguard/wg0.conf
Konfiguration:
[Interface] PrivateKey = <robot_private_key>Address = 10.0.0.2/24 ListenPort = 51820 [Peer] PublicKey =<base_station_public_key> Endpoint = base.example.com:51820 AllowedIPs = 10.0.0.0/24 PersistentKeepalive = 25</base_station_public_key></robot_private_key>
DDS-Erkennung über VPN:
# Sicherstellen, dass DDS die VPN-Schnittstelle verwendet export CYCLONEDDS_URI='wg0'
Checkliste für die Produktionsbereitstellung
Leistungsoptimierung
-
Mit Optimierungen kompilieren:
colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release -
CPU-Pinning für Echtzeitknoten:
taskset -c 0,1 ros2 run my_pkg critical_node -
Speichersperre:
sudo setcap cap_ipc_lock+ep /path/to/node
Überwachung und Protokollierung
# Protokollierung konfigurieren self.get_logger().set_level(rclpy.logging.LoggingSeverity.INFO) # Strukturierte Protokollierung verwenden self.get_logger().info(f'Position: x={x:.3f}, y={y:.3f}') self.get_logger().warn(f'Batterie schwach: {battery_pct}%') self.get_logger().error(f'Motorfehler: {error_code}')
Testen
import unittest from launch import LaunchDescription from launch_ros.actions import Node import launch_testing class TestVelocityController(unittest.TestCase): def test_obstacle_avoidance(self): # Integrationstest pass
Sicherheit (SROS2)
# Sicherheitsschlüssel generieren ros2 security create_keystore demo_keys ros2 security create_key demo_keys /my_robot_node # Mit Sicherheit ausführen export ROS_SECURITY_KEYSTORE=demo_keys export ROS_SECURITY_ENABLE=true ros2 run my_pkg my_node
Häufige Fallstricke und Lösungen
-
QoS-Inkompatibilität: Publisher und Subscriber müssen über kompatible QoS-Profile verfügen. Überprüfen Sie dies mit
ros2 topic info -v /topic. -
DDS-Leistung: Wechseln Sie zwischen CycloneDDS und FastDDS, wenn Netzwerkprobleme auftreten.
-
Probleme mit Transform (TF): Veröffentlichen Sie immer mit >10 Hz. Verwenden Sie
ros2 run tf2_tools view_frameszur Fehlerbehebung. -
Speicherlecks: Löschen Sie Knoten in Shutdown-Handlern immer ordnungsgemäß.
-
Uhrensynchronisation: Verwenden Sie in der Simulation durchgehend
use_sim_time:=true.
Ressourcen und Community
- Offizielle Dokumentation: https://docs.ros.org/en/humble/
- Nav2-Dokumentation: https://navigation.ros.org/
- MoveIt 2: https://moveit.picknik.ai/
- ROS Discourse: https://discourse.ros.org/
- GitHub Issues: Überprüfen Sie die jeweiligen Paket-Repositorys
Fazit
ROS 2 stellt ein ausgereiftes, produktionsreifes Framework für moderne Robotik dar. Der Übergang von ROS 1 erfordert ein Überdenken Ihrer Architektur, aber die Vorteile – Echtzeitleistung, Sicherheit und Skalierbarkeit – machen es für jedes ernsthafte Robotikprojekt unverzichtbar.
Beginnen Sie mit einer Simulation, beherrschen Sie die QoS-Konfiguration und bauen Sie schrittweise auf. Das Ökosystem ist reichhaltig, die Community ist aktiv, und die Zukunft der Robotik basiert auf ROS 2.
Über den Autor: Dieser Leitfaden spiegelt mehr als 7 Jahre Erfahrung bei der Implementierung von ROS-basierten Systemen in den Bereichen Lagerautomatisierung, autonome Fahrzeuge und industrielle Handhabung wider. Die hier gewonnenen Erkenntnisse stammen aus realen Produktionsumgebungen, in denen Zuverlässigkeit, Leistung und Sicherheit unverzichtbar sind.
Mehr aus der Serie
- Erste Schritte mit ROS 2 für die Roboterentwicklung
- Verstärkendes Lernen in der Robotik: Ein umfassender Leitfaden für 2025
