Zum Inhalt springen

ROS 2 Jazzy ​

ROS 2 (Robot Operating System 2) ist kein Betriebssystem, sondern ein Framework: eine Sammlung von Bibliotheken und Werkzeugen, mit denen viele kleine Programme, sogenannte Nodes, typisierte Messages austauschen. Strido verwendet ROS 2 Jazzy, damit dieselben Nodes in Gazebo und auf dem echten Roboter laufen und damit Standardwerkzeuge (Teleop, RViz, Nav2, SLAM) ihn steuern können.

In Strido

  • Pakete (in ros2/): strido_description (aus dem CAD generiertes URDF/xacro, controllers.yaml, display.launch.py), strido_bringup (robot.launch.py, gazebo.launch.py, worlds/flat.sdf, udev-Regeln), strido_control (gait_node, policy_node, mcu_bridge, walk_smoke).
  • Gemeinsamer Kern: packages/strido-core (reines Python, kein ROS) enthält den Gait, die Kinematik, das MCU-Protokoll und die Policy-Laufzeit, die die Nodes aufrufen.
  • Schnittstelle: Topics und Gelenknamen im Stil des Unitree Go2, aufgeführt unter Software.
  • Läuft in: dem Docker-Image strido-ros:jazzy (Docker).

Warum Jazzy ​

Jazzy Jalisco (Mai 2024) ist eine Long-Term-Support-Version mit Unterstützung bis Mai 2029, und ihre Tier-1-Plattform ist Ubuntu 24.04, die Basis des Images ros:jazzy-ros-base. Sie ist auf Gazebo Harmonic abgestimmt, das das Repository für die Simulation nutzt. Eine LTS-Version bedeutet, dass der Software-Stack des Roboters nicht jedes Jahr einer neuen ROS-Version hinterherlaufen muss.

Der ROS-Graph dieses Roboters ​

Diagramm wird gezeichnet…

(policy_node abonniert /imu/data; gait_node nicht.)

Nodes ​

Ein Node ist ein Prozess (oder ein Objekt in einem Prozess) mit genau einer Aufgabe. Die Aufteilung des Roboters in Nodes bedeutet, dass Sie ein Teil austauschen können, ohne die anderen anzufassen: gait_node und policy_node sind austauschbar, weil beide /cmd_vel in /leg_controller/commands umsetzen.

Node (Paket strido_control)Aufgabe
gait_nodeGeschwindigkeitsbefehl → Trot-Gait → 12 Gelenkziele mit 100 Hz; veröffentlicht /odom und die Transformation odom→base_link durch Integration der befohlenen Geschwindigkeit
policy_nodeFührt eine gelernte Policy (policy.npz) mit 50 Hz aus /cmd_vel und /imu/data aus
mcu_bridgeÜbersetzt zwischen ROS-Topics und dem binären seriellen Protokoll des ESP32-S3
walk_smokeAutomatisierter Gazebo-Test: läuft und prüft die Ground Truth

Dazu kommen Standard-Nodes: robot_state_publisher, der Slamtec-Treiber sllidar_ros2, camera_ros (optional) und in der Simulation die Gazebo-Bridge und die ros2_control-Controller.

Jeder strido_control-Node ist eine von rclpy.node.Node abgeleitete Python-Klasse, registriert als Konsolenskript in setup.py, daher starten Sie ihn mit:

bash
ros2 run strido_control gait_node

Topics ​

Ein Topic ist ein benannter, typisierter Many-to-many-Datenstrom. Publisher wissen nicht, wer zuhört. Diese lose Kopplung ist der Grund, warum der Gait-Node zwischen Simulation und Hardware keine Änderung braucht: In Gazebo wird /leg_controller/commands vom leg_controller von ros2_control verarbeitet, auf dem Roboter von mcu_bridge.

Die Topics, die dieses Repository tatsächlich verwendet:

TopicTypVeröffentlicht vonHinweise
/cmd_velgeometry_msgs/TwistSie / Teleoplinear.x, linear.y [m/s], angular.z [rad/s]; der Gait begrenzt auf 0,30 / 0,15 / 1,0
/leg_controller/commandsstd_msgs/Float64MultiArrayGait- oder Policy-Node12 Winkel [rad], Reihenfolge FL, FR, RL, RR × Hüfte, Oberschenkel, Unterschenkel
/joint_statessensor_msgs/JointStatemcu_bridge (Roboter), joint_state_broadcaster (Gazebo)Namen FL_hip_joint …; auf dem Roboter sind dies die befohlenen Winkel nach der Begrenzung, da die Servos keine Rückmeldung haben
/imu/datasensor_msgs/Imumcu_bridge / Gazebo-IMUFrame imu_link; wird nicht veröffentlicht, solange die IMU einen Fehler meldet
/battery_statesensor_msgs/BatteryStatemcu_bridgeAkkupackspannung, Strom negativ = Entladen
/diagnosticsdiagnostic_msgs/DiagnosticArraymcu_bridgeFlags estop, relaxed, watchdog, imu_ok, power_ok, pwm_ok, clamped, calibration_mode
/odomnav_msgs/Odometrygait_nodeKoppelnavigation aus der befohlenen Geschwindigkeit
/scansensor_msgs/LaserScansllidar_ros2 / GazeboFrame lidar_link, 10 Hz
/camera/image_rawsensor_msgs/Imagecamera_ros / GazeboFrame camera_optical_frame
/strido/estopstd_msgs/BoolSietrue verriegelt einen Halt (Servoausgänge aus)
/strido/relaxstd_msgs/BoolSietrue macht die Servos kraftlos
/strido/facestd_msgs/UInt8SieID des LCD-Gesichtsausdrucks
/ground_truth/odomnav_msgs/Odometrynur Gazebowird von walk_smoke verwendet, um den tatsächlichen Fortschritt zu messen

/odom von gait_node ist reine Koppelnavigation: In jedem Schritt dreht der Node die befohlene Körpergeschwindigkeit mit dem aktuellen Kurs ψ in das Odometrie-Koordinatensystem und integriert sie,

(xy)k+1=(xy)k+(cos⁡ψk−sin⁡ψksin⁡ψkcos⁡ψk)(vxvy)Δt,ψk+1=ψk+ωzΔt

daher summiert sich jeder Unterschied zwischen befohlener und tatsächlicher Bewegung (Fußschlupf, eine Policy, die zu kurz tritt) unbegrenzt auf. Deshalb bewertet walk_smoke den Fortschritt mit /ground_truth/odom, und deshalb korrigiert SLAM die Pose anhand von /scan. Siehe Koordinatensysteme und Rotationen und State Estimation.

So erkunden Sie sie aus einer Shell im Container:

bash
ros2 node list
ros2 topic list -t
ros2 topic hz /leg_controller/commands          # ≈ 100 Hz from gait_node
ros2 topic echo /battery_state --once
ros2 topic echo /diagnostics
ros2 topic pub --once /strido/estop std_msgs/msg/Bool "{data: true}"    # stop
ros2 topic pub --once /strido/estop std_msgs/msg/Bool "{data: false}"   # release (a new joint command is needed to move again)

Services und Actions ​

Ein Service ist ein Request/Response-Aufruf (wie ein Funktionsaufruf über das Netzwerk); eine Action ist ein lang laufendes Ziel mit Rückmeldung und Abbruchmöglichkeit (wie „laufe zu dieser Pose“). Die Strido-Nodes definieren keines von beiden: Jeder Befehl, einschließlich Not-Halt und Relax, ist ein Topic. Das passt bewusst zu einem Roboter, dessen Firmware den Befehlsstrom selbst als Herzschlag behandelt (kein Befehl für 200 ms → halten, siehe Firmware).

Services begegnen Ihnen trotzdem über Standard-Nodes. Jeder Node stellt Parameter-Services bereit (ros2 param ... nutzt sie), und der spawner in gazebo.launch.py ruft die Services des controller_manager auf, um joint_state_broadcaster und leg_controller zu laden. Actions kommen hinzu, sobald Sie Nav2 ergänzen, dessen Action NavigateToPose /cmd_vel an diesen Roboter veröffentlichen würde.

Parameter ​

Parameter sind Node-spezifische Einstellungen, im Code mit Standardwerten deklariert und beim Start überschreibbar. Die tatsächlichen:

NodeParameterStandard
gait_noderate_hz100.0
body_height0.17 m
stand_up_s3.0 s
cmd_timeout_s0,5 s (so lange kein /cmd_vel → stillstehen)
accel_limit0,5 m/s² bzw. rad/s²
publish_tftrue
policy_nodepolicy"" (erforderlich: Pfad zu policy.npz)
stand_up_s, cmd_timeout_s3.0 s, 0.5 s
mcu_bridgeport/dev/strido_mcu
walk_smokesettle_s, walk_s, vx, min_forward_m, timeout_s6.0, 8.0, 0.15, 0.4, 120.0

Die Nodes lesen ihre Parameter einmalig beim Start, setzen Sie sie daher auf der Kommandozeile statt mit ros2 param set während des Betriebs:

bash
ros2 run strido_control gait_node --ros-args -p body_height:=0.15 -p accel_limit:=0.3

use_sim_time:=true ist ein Parameter, den jeder Node hat: Er lässt die Uhr des Nodes dem Gazebo-Topic /clock statt der Echtzeit folgen. gazebo.launch.py setzt ihn für alle seine Nodes.

Launch-Dateien ​

Ein Launch-File startet eine Gruppe von Nodes mit ihren Parametern und Argumenten. Die von Strido sind in Python geschrieben (*.launch.py).

bash
ros2 launch strido_bringup robot.launch.py                       # on the robot
ros2 launch strido_bringup robot.launch.py lidar:=false          # without the LiDAR
ros2 launch strido_bringup robot.launch.py use_policy:=true policy:=/path/policy.npz
ros2 launch strido_bringup gazebo.launch.py headless:=true       # simulation
ros2 launch strido_description display.launch.py                 # model + joint sliders in RViz
Launch-DateiArgumente (Standard)
robot.launch.pymcu_port (/dev/strido_mcu), lidar_port (/dev/rplidar), lidar (true), camera (false), use_policy (false), policy ("")
gazebo.launch.pyworld (worlds/flat.sdf), headless (false), use_policy (false), policy ("")
display.launch.pyrviz (true)

robot.launch.py zeigt die wichtigsten Launch-Bausteine: DeclareLaunchArgument, Node(...), IfCondition/UnlessCondition zur Wahl zwischen gait_node und policy_node, IncludeLaunchDescription zur Wiederverwendung der Slamtec-Launch-Datei und Command(["xacro ", file]), um das xacro in den String robot_description umzuwandeln. gazebo.launch.py ergänzt Event-Handler (OnProcessExit), damit die Controller erst gestartet werden, wenn der Roboter im Simulator existiert.

tf2 und Koordinatensysteme ​

tf2 verfolgt Koordinatensysteme über die Zeit, sodass jeder Node fragen kann: „Wo war der LiDAR vor 50 ms relativ zum Odometrie-Ursprung?“ Die Koordinatensysteme folgen REP-103: base_link hat x nach vorne, y nach links, z nach oben.

Diagramm wird gezeichnet…

robot_state_publisher liest das URDF (vom CAD durch strido_cad.models generiert) und die /joint_states und veröffentlicht die Pose jedes Glieds. Auf dem Roboter sind die Gelenkzustände die befohlenen Winkel nach der Begrenzung: gut für die Visualisierung, aber sie können keinen blockierenden Servo zeigen.

Die Transformation odom→base_link entsteht durch Integration der befohlenen Geschwindigkeit, ohne Schlupfmodell. Sie reicht für die Fernsteuerung und als Startwert für SLAM; für die Navigation verwenden Sie eine LiDAR-Odometrie- oder SLAM-Quelle. policy_node veröffentlicht kein /odom.

Quality of Service (QoS) ​

QoS-Einstellungen bestimmen, wie Messages zugestellt werden: Zuverlässigkeit (reliable oder best effort), Verlaufstiefe, Dauerhaftigkeit (ob spät hinzukommende Abonnenten alte Messages erhalten) und Deadlines. Publisher und Subscriber müssen kompatible QoS haben, sonst verbinden sie sich stillschweigend nicht.

Alle Publisher und Subscriber von Strido übergeben eine einfache ganzzahlige Tiefe (10; 50 für das IMU-Abonnement von policy_node). In rclpy bedeutet das das Standardprofil: keep last N, reliable, volatile. Zuverlässige Zustellung ist für Befehle auf derselben Maschine richtig. Wenn Sie einen Sensortreiber anbinden, der mit best effort veröffentlicht (üblich bei Kameras und einigen LiDAR-Treibern), empfängt ein zuverlässiger Subscriber nichts: Prüfen Sie das mit

bash
ros2 topic info /scan --verbose      # shows each endpoint's QoS

Fernsteuerung ​

Steuern Sie den Roboter (oder die Simulation) über die Tastatur. Das Image enthält teleop_twist_keyboard:

bash
# terminal 1 (on the Pi, robot lying in rest pose, loop key in)
docker compose -f docker/compose.yaml run --rm robot
# terminal 2
docker compose -f docker/compose.yaml run --rm ros ros2 run teleop_twist_keyboard teleop_twist_keyboard

teleop_twist_keyboard startet mit 0,5 m/s und 1,0 rad/s; gait_node begrenzt auf 0,30 m/s vorwärts, 0,15 m/s seitwärts und 1,0 rad/s und beschleunigt mit 0,5 m/s². Drücken Sie einige Male z (alle Geschwindigkeiten −10 %) oder x (nur linear), damit die Tastendrücke in den nutzbaren Bereich fallen. Die Teleop-Anwendung veröffentlicht pro Tastendruck eine Message (halten Sie eine Taste gedrückt, sorgt die automatische Tastenwiederholung für Nachschub); gait_node behandelt /cmd_vel, das älter als 0,5 s ist (cmd_timeout_s), als veraltet und bleibt stehen, daher hält der Roboter an, wenn die Messages ausbleiben. Beenden Sie den Gait-Node ganz, hält die Firmware die Pose 200 ms lang und entspannt dann 2 s später.

DANGER

Teleop ist kein Not-Halt. Das Ziehen des Servo-Loop-Keys ist die Hardware-Abschaltung; /strido/estop ist die Software-Abschaltung (Sicherheit).

Portierung von einem Unitree Go2 ​

Gelenknamen, Vorzeichen, Koordinatensysteme und /cmd_vel entsprechen der ROS-2-Beschreibung des Go2, daher laufen Stacks auf Geschwindigkeitsebene unverändert. Unterschiede: Die Reihenfolge im Befehlsarray ist FL, FR, RL, RR (das Unitree SDK verwendet FR, FL, RR, RL: nach Namen zuordnen), es gibt keine Topics für Fußkontakt oder Motordrehmoment, /joint_states sind befohlene Werte, und der Geschwindigkeitsbereich liegt bei etwa 0,3 m/s.

Selbsttest ​

  1. Warum kann gait_node unverändert in Gazebo und auf dem Roboter laufen?
  2. Welcher Strido-Node veröffentlicht odom→base_link, und was ist seine Schwäche?
  3. Nennen Sie einen Service, den der Roboter nutzt, obwohl strido_control keinen definiert.
  4. Sie führen ros2 param set /gait_node body_height 0.15 aus, und nichts ändert sich. Warum?
  5. Ein Kameratreiber mit best effort veröffentlicht /camera/image_raw, aber Ihr Standard-Subscriber erhält nichts. Was ist die wahrscheinliche Ursache?
Antworten
  1. Er veröffentlicht nur /leg_controller/commands; in Gazebo verarbeitet das der leg_controller von ros2_control, auf dem Roboter mcu_bridge.
  2. gait_node; er integriert die befohlene Geschwindigkeit (Koppelnavigation ohne Schlupf) und driftet daher von der Realität weg.
  3. Die Services des controller_manager, die spawner in gazebo.launch.py aufruft, oder die Parameter-Services, die jeder Node hat.
  4. Der Node liest seine Parameter nur beim Start; starten Sie ihn mit --ros-args -p body_height:=0.15 neu.
  5. Eine QoS-Unverträglichkeit: Ein zuverlässiger (reliable) Subscriber passt nicht zu einem Best-effort-Publisher.

Weiterführende Literatur ​

MIT-Lizenz. Mechanik abgeleitet von Yertle (Jerome Graves). CAD, Simulation und native Tests sind kein Hardware-Nachweis – siehe Verifikation.