Zusammenfassung
- Installieren Sie ROS 2 Jazzy auf Ubuntu 24.04 mit
sudo apt install ros-jazzy-desktop - Kernkonzepte: Nodes (Prozesse), Topics (Pub/Sub), Services (RPC), Actions (langlaufende Aufgaben)
- Schreiben Sie einen Python/C++ Publisher/Subscriber in 5 Minuten
- Nutzen Sie
ros2 launchfür die Orchestrierung mehrerer Nodes - Debuggen Sie mit
rqt,ros2 bagundrviz2
1. ROS 2 (Jazzy) auf Ubuntu installieren
Voraussetzungen
- Ubuntu 24.04 (Noble Numbat) ROS 2 Jazzy-Anforderungen
- 64-Bit-System
- 20 GB+ Festplattenspeicher (für vollständige Desktop-Installation)
Schritt 1: Locale und Repositories 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
sudo apt install software-properties-common
sudo add-apt-repository universe
Schritt 2: ROS 2-Repository hinzufügen
sudo apt update && sudo apt install curl -y
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
sudo apt update
Schritt 3: ROS 2 Jazzy installieren
# Desktop-Installation (empfohlen): ROS, RViz, Demos, Tutorials
sudo apt install ros-jazzy-desktop
# Basis-Installation (minimal): nur ROS und Kommandozeilen-Tools
# sudo apt install ros-jazzy-ros-base
# Entwicklungstools (optional)
sudo apt install ros-dev-tools
Schritt 4: Umgebung einrichten
# ROS 2-Setup-Datei einbinden (für Persistenz zu ~/.bashrc hinzufügen)
source /opt/ros/jazzy/setup.bash
# Installation überprüfen
ros2 --version
# Erwartete Ausgabe: ros2 version 26.0.0 (oder höher)
Hinweise:
- Falls
ros2 --versionfehlschlägt, stellen Sie sicher, dass/opt/ros/jazzy/setup.basheingebunden ist. - Für Python-Pakete installieren Sie
python3-colcon-common-extensions, falls diese fehlen.
2. Nodes, Topics, Services und Actions
Kernkonzepte
| Konzept | Beschreibung | Mapping der Physical AI Stack |
|---|---|---|
| Node | Ein Prozess, der Berechnungen durchführt (z. B. Sensortreiber, Planer). | COMPUTE |
| Topic | Asynchrone Pub/Sub-Kommunikation (z. B. /scan für LiDAR-Daten). | CONNECT |
| Service | Synchrone Anfrage/Antwort (z. B. /reset_pose für Lokalisierung). | REASON |
| Action | Langlaufende Aufgabe mit Feedback (z. B. /navigate_to_pose für Navigation). | ACT |
CLI-Befehle
# Nodes auflisten
ros2 node list
# Topics auflisten
ros2 topic list
# Ein Topic ausgeben
ros2 topic echo /scan
# Einen Service aufrufen
ros2 service call /reset_pose std_srvs/srv/Empty
# Actions auflisten
ros2 action list
3. Ihr erster Publisher/Subscriber
Python-Beispiel
Publisher (publisher.py)
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # Sekunden
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = f'Hello ROS 2: {self.i}'
self.publisher_.publish(msg)
self.get_logger().info(f'Publishing: "{msg.data}"')
self.i += 1
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
minimal_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Subscriber (subscriber.py)
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
self.subscription # Verhindert Warnung für ungenutzte Variable
def listener_callback(self, msg):
self.get_logger().info(f'I heard: "{msg.data}"')
def main(args=None):
rclpy.init(args=args)
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
minimal_subscriber.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Beispiel ausführen
# Terminal 1: Publisher starten
python3 publisher.py
# Terminal 2: Subscriber starten
python3 subscriber.py
# Erwartete Ausgabe (Terminal 2):
# [INFO] [minimal_subscriber]: I heard: "Hello ROS 2: 0"
# [INFO] [minimal_subscriber]: I heard: "Hello ROS 2: 1"
C++-Beispiel
Publisher (publisher.cpp)
#include <chrono>
#include <memory>
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"
using namespace std::chrono_literals;
class MinimalPublisher : public rclcpp::Node {
public:
MinimalPublisher() : Node("minimal_publisher"), count_(0) {
publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10);
timer_ = this->create_wall_timer(
500ms, std::bind(&MinimalPublisher::timer_callback, this));
}
private:
void timer_callback() {
auto message = std_msgs::msg::String();
message.data = "Hello ROS 2: " + std::to_string(count_++);
RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str());
publisher_->publish(message);
}
rclcpp::TimerBase::SharedPtr timer_;
rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_;
size_t count_;
};
int main(int argc, char * argv[]) {
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalPublisher>());
rclcpp::shutdown();
return 0;
}
Bauen und Ausführen
# Arbeitsbereich erstellen
mkdir -p ~/ros2_ws/src
cd ~/ros2_ws/src
ros2 pkg create --build-type ament_cmake cpp_pubsub
# Ersetzen Sie die generierte Datei src/cpp_pubsub/src/publisher_member_function.cpp durch den obigen Code
# Bauen
cd ~/ros2_ws
colcon build --packages-select cpp_pubsub
# Arbeitsbereich einbinden
source install/setup.bash
# Publisher ausführen
ros2 run cpp_pubsub talker
4. Launch-Dateien und Parameter
Beispiel einer Launch-Datei (launch_example.py)
from launch import LaunchDescription
from launch_ros.actions import Node
def generate_launch_description():
return LaunchDescription([
Node(
package='cpp_pubsub',
executable='talker',
name='talker_node',
parameters=[{'use_sim_time': True}]
),
Node(
package='demo_nodes_py',
executable='listener',
name='listener_node'
)
])
Launch-Datei ausführen
ros2 launch launch_example.py
Parameter
# Parameter auflisten
ros2 param list
# Einen Parameter abrufen
ros2 param get /talker_node use_sim_time
# Einen Parameter setzen
ros2 param set /talker_node use_sim_time false
5. DDS, QoS und Echtzeit-Überlegungen
QoS-Profile
ROS 2 verwendet Quality of Service (QoS)-Richtlinien, um die Zuverlässigkeit, Kommunikation, Dauerhaftigkeit und Latenz zu konfigurieren.
| Richtlinie | Optionen | Anwendungsfall |
|---|---|---|
| Reliability | RELIABLE, BEST_EFFORT | Sensordaten (BEST_EFFORT), Befehle (RELIABLE) |
| Durability | VOLATILE, TRANSIENT_LOCAL | Kartendaten (TRANSIENT_LOCAL), Telemetrie (VOLATILE) |
| History | KEEP_LAST(n), KEEP_ALL | Begrenzter Puffer (KEEP_LAST), vollständige Wiedergabe (KEEP_ALL) |
Beispiel: QoS in Python konfigurieren
from rclpy.qos import QoSProfile, ReliabilityPolicy, HistoryPolicy
qos_profile = QoSProfile(
reliability=ReliabilityPolicy.RELIABLE,
history=HistoryPolicy.KEEP_LAST,
depth=10
)
self.publisher = self.create_publisher(
String,
'topic',
qos_profile
)
Echtzeit-Einrichtung
- Echtzeit-Kernel verwenden:
sudo apt install linux-image-rt-amd64 - DDS für Echtzeit konfigurieren:
- Verwenden Sie
rmw_connextddsoderrmw_cycloneddsmit Echtzeit-Einstellungen. - Beispiel
cyclonedds.xml:<CycloneDDS> <Domain> <General> <NetworkInterfaceAddress>lo</NetworkInterfaceAddress> <AllowMulticast>false</AllowMulticast> </General> <Tracing> <Verbosity>warning</Verbosity> </Tracing> </Domain> </CycloneDDS>
- Verwenden Sie
- Thread-Prioritäten setzen:
rclcpp::ExecutorOptions options; options.context = rclcpp::Context::make_shared(); options.context->init(0, nullptr, rclcpp::InitOptions().use_real_time()); rclcpp::executors::SingleThreadedExecutor executor(options);
6. ros2_control und Hardware-Schnittstellen
Übersicht
ros2_control ist ein Framework für die Echtzeit-Steuerung von Roboter-Hardware. Es trennt Hardware-Schnittstellen von Steuerungsalgorithmen.
Beispiel: URDF mit ros2_control
<robot name="my_robot">
<ros2_control name="MyRobotSystem" type="system">
<hardware>
<plugin>my_robot_hardware/MyRobotSystemHardware</plugin>
</hardware>
<joint name="joint1">
<command_interface name="position"/>
<state_interface name="position"/>
<state_interface name="velocity"/>
</joint>
</ros2_control>
</robot>
Launch-Datei für ros2_control
from launch import LaunchDescription
from launch_ros.actions import Node
from launch_ros.substitutions import FindPackageShare
from launch.substitutions import PathJoinSubstitution
def generate_launch_description():
return LaunchDescription([
Node(
package='controller_manager',
executable='ros2_control_node',
parameters=[PathJoinSubstitution([
FindPackageShare('my_robot_description'),
'config',
'my_robot_controllers.yaml'
])]
),
Node(
package='controller_manager',
executable='spawner',
arguments=['joint_state_broadcaster']
),
Node(
package='controller_manager',
executable='spawner',
arguments=['joint_trajectory_controller']
)
])
7. Debugging mit rqt, ros2 bag und rviz2
rqt (GUI-Tools)
# rqt starten
rqt
# Häufig verwendete Plugins:
# - Topic Monitor (/rqt_topic)
# - Service Caller (/rqt_service_caller)
# - Node Graph (/rqt_graph)
ros2 bag (Aufzeichnung/Wiedergabe)
# Topics aufzeichnen
ros2 bag record /scan /odom
# Wiedergabe
ros2 bag play rosbag2_2026_06_02-12_00_00
# Informationen
ros2 bag info rosbag2_2026_06_02-12_00_00
rviz2 (Visualisierung)
# RViz2 starten
rviz2
