Découverte du bras SO-101
Dans cette première partie, vous prenez en main le bras SO-101 : vous lisez sa
description (URDF), vous le visualisez dans RViz, puis vous le pilotez en
simulation Gazebo Ionic via ros2_control. À la fin, vous saurez bouger le
bras et la pince à la main — la seconde partie automatisera tout cela avec MoveIt 2.
Le SO-101 est un bras robotique open-source à 6 articulations motorisées (5 DOF pour positionner le poignet + 1 pour la pince) conçu par la communauté LeRobot / Hugging Face, motorisé par des servos Feetech STS3215. Il est suffisamment léger pour être posé sur une table ou monté sur la base mobile LeKiwi.
1. Anatomie
Section intitulée « 1. Anatomie »Le SO-101 enchaîne 6 axes en rotation :
| Joint | Type | Rôle |
|---|---|---|
shoulder_pan | revolute | Rotation horizontale de l’épaule (base) |
shoulder_lift | revolute | Levée verticale de l’épaule |
elbow_flex | revolute | Flexion du coude |
wrist_flex | revolute | Flexion du poignet |
wrist_roll | revolute | Rotation du poignet |
gripper | revolute | Ouverture/fermeture de la pince |
C’est une chaîne cinématique série (chaque joint dépend du précédent), classique pour un bras de manipulation.
2. URDF / Xacro
Section intitulée « 2. URDF / Xacro »Dans ROS 2, le robot est décrit par un URDF (XML). Le package
so101_description (dans
so_arm101_ros2) le découpe en
deux fichiers complémentaires :
so101.urdf— la description cinématique pure : les<link>et<joint>du bras, indépendante du contexte d’exécution ;so101.urdf.xacro— un wrapper Xacro qui assembleso101.urdf, la transmission et — selon les arguments — la configurationros2_control.
Générez l’URDF à plat (ici en mode visualisation) et vérifiez sa cohérence :
ros2 run xacro xacro \ $(ros2 pkg prefix --share so101_description)/urdf/so101.urdf.xacro \ joint_states_gui:=true \ > /tmp/so101.urdfcheck_urdf /tmp/so101.urdfcheck_urdf affiche l’arbre des liens : vous devez y retrouver la chaîne
base_link → … → gripper.
Ouvrez la description so101.urdf
et repérez-y les deux éléments de base :
| Élément | Rôle |
|---|---|
<link> | Un segment physique (épaule, avant-bras…) : géométrie visuelle, géométrie de collision, inertie |
<joint> | La liaison entre deux liens : axe de rotation, limites (lower/upper/effort/velocity), dynamique |

<link>, relié au précédent par un <joint>.Côté Xacro (so101.urdf.xacro), observez plutôt la composition :
<xacro:include> pour assembler les fichiers, <xacro:arg> pour les paramètres
et <xacro:if> pour activer ros2_control selon le mode.
3. Visualiser le bras
Section intitulée « 3. Visualiser le bras »Le package fournit un launch prêt à l’emploi :
ros2 launch so101_description view.launch.pyUn launch démarre des nœuds (des exécutables ROS 2) ; ici trois :
robot_state_publisher— lit l’URDF et les/joint_states, publie latf;joint_state_publisher_gui— publie les/joint_statesà partir de sliders ;rviz2— le visualiseur 3D, chargé avec la configdisplay.rviz.
La fenêtre JointStatePublisher est l’interface de ce deuxième nœud : bougez ses sliders pour voir le bras se déplacer en temps réel.
Ce que publie le robot
Section intitulée « Ce que publie le robot »Pendant que le launch tourne, ouvrez un second terminal (workspace sourcé) et listez les topics apparus :
ros2 topic listOn y retrouve l’état des articulations et la chaîne tf. La description URDF
complète, elle, est publiée sur un topic dédié — inspectez-les :
ros2 topic echo /robot_description --once # le contenu de l'URDFros2 topic hz /joint_states # la fréquence des états de jointsInspecter le bras avec Foxglove
Section intitulée « Inspecter le bras avec Foxglove »RViz est notre outil d’interaction (planification MoveIt à la partie suivante), mais pour inspecter le bras — le voir en 3D et lire les valeurs des articulations — Foxglove est plus confortable (interface web, panneaux Raw Messages et Plot).
Gardez le launch de découverte du bras actif et démarrez le pont dans un autre terminal :
ros2 launch foxglove_bridge foxglove_bridge_launch.xml # ws://localhost:8765Connectez-vous à ws://localhost:8765 dans Foxglove (cf. Installation),
puis ajoutez :
- un panneau 3D : le bras et ses repères. Ajoutez une couche URDF (Custom layers → +
→ URDF) avec Source =
Parameter, Parameter =robot_description; - un panneau Raw Messages sur
/joint_states: les angles articulaires en direct.
Chaîne de transformations (tf)
Section intitulée « Chaîne de transformations (tf) »Quand vous publiez les joint_states, robot_state_publisher calcule
automatiquement la chaîne de transformations tf entre tous les frames
du robot (base_link → shoulder_link → upper_arm_link → … → gripper_link).
Cette chaîne est ce que MoveIt 2 utilisera dans la partie suivante pour planifier les trajectoires.
4. Piloter le bras avec ros2_control
Section intitulée « 4. Piloter le bras avec ros2_control »Jusqu’ici, le bras ne fait que suivre des sliders : aucune physique, aucun
contrôleur. Pour le commander comme un vrai robot (en simulation ou réel), ROS 2
utilise ros2_control, l’architecture standard pour piloter du matériel de
façon uniforme et temps réel.
Le triptyque
Section intitulée « Le triptyque »Comment lire ce schéma — suivez le trajet d’une commande, de gauche à droite, puis le retour :
- Vous envoyez une commande (action / topic) à un contrôleur (
arm_controller,gripper_controller). - Le controller manager orchestre les contrôleurs et transmet leurs ordres au matériel via les
command_interfaces(la flèche qui descend vers le hardware). - Le hardware interface applique ces ordres au robot (Gazebo en sim) et relit l’état réel des joints, qu’il renvoie au manager via les
state_interfaces(la flèche qui remonte). - En parallèle, le
joint_state_broadcasterpublie cet état sur/joint_states— c’est la boucle qui se referme.
Les trois briques, de bas en haut :
- Hardware interface : le pont bas-niveau. Il lit l’état (positions, vitesses)
et applique les commandes. En sim Gazebo Ionic (gz-sim 9), c’est
gz_ros2_controlqui le fait automatiquement ; sur le vrai robot, ce serait le driver Feetech. - Controller manager : le chef d’orchestre. Il charge / décharge les
contrôleurs et arbitre les accès aux
command_interfaces(deux contrôleurs ne peuvent pas commander le même joint en même temps). - Contrôleur : la politique de contrôle (suivre une trajectoire, maintenir
une position…). Pour le bras, un
joint_trajectory_controller(JTC) ; pour la pince, un contrôleur de gripper dédié.
La distinction clé :
command_interfaces= ce qu’on écrit vers le matériel (consignes),state_interfaces= ce qu’on lit du matériel (mesures). Toutros2_controltourne autour de cette boucle écrire / lire.
Les contrôleurs du SO-101
Section intitulée « Les contrôleurs du SO-101 »La sim charge trois contrôleurs (visibles via ros2 control list_controllers) :
joint_state_broadcaster— publie/joint_states; ce n’est pas un contrôleur de commande, juste un broadcaster d’état.arm_controller— unjoint_trajectory_controller/JointTrajectoryControllersur les 5 joints du bras :shoulder_pan,shoulder_lift,elbow_flex,wrist_flex,wrist_roll.gripper_controller— unparallel_gripper_action_controller/GripperActionControllersur le jointgripper.
Le arm_controller accepte des trajectoires (liste de points avec positions,
vitesses, temps) sur le topic / action :
/arm_controller/follow_joint_trajectory (action)/arm_controller/joint_trajectory (topic)Il interpole entre les points et envoie les commandes au hardware
interface à fréquence fixe (souvent 100 Hz ou plus). La pince, elle, se
pilote via l’action control_msgs/action/ParallelGripperCommand sur
/gripper_controller/gripper_cmd — ses champs name et position sont
des listes, cohérent avec le type parallel_gripper_action_controller.
Envoyer une trajectoire manuelle
Section intitulée « Envoyer une trajectoire manuelle »Pour tester sans MoveIt, on publie une trajectoire à la main. Le bras et la
pince se commandent séparément : le bras via le topic / action du
arm_controller (5 joints), la pince via l’action du gripper_controller.
ros2 launch so101_bringup gazebo.launch.py→ La fenêtre Gazebo Ionic s’ouvre, le bras SO-101 apparaît posé sur le sol. Attendez ~10-20 s (premier rendu) que les trois contrôleurs se chargent.
-
Vérifier les contrôleurs. Les trois doivent être
active:Fenêtre de terminal ros2 control list_controllers -
Bouger le bras (action, recommandé). L’action
follow_joint_trajectoryest bloquante : elle attend le résultat et remonte du feedback.Fenêtre de terminal ros2 action send_goal /arm_controller/follow_joint_trajectory \control_msgs/action/FollowJointTrajectory \"{trajectory: {joint_names: [shoulder_pan, shoulder_lift, elbow_flex, wrist_flex, wrist_roll], points: [{positions: [0.8, -0.5, 1.0, 0.0, 0.0], time_from_start: {sec: 2}}]}}"Variante « fire-and-forget » via le topic — envoyée sans retour (ni feedback ni résultat) :
Fenêtre de terminal ros2 topic pub --once /arm_controller/joint_trajectory \trajectory_msgs/msg/JointTrajectory "{joint_names: [shoulder_pan, shoulder_lift, elbow_flex, wrist_flex, wrist_roll],points: [{positions: [0.0, -0.5, 1.0, 0.0, 0.0], time_from_start: {sec: 2}}]}" -
Piloter la pince (
ParallelGripperCommand). Ouvrir, puis fermer :Fenêtre de terminal # Ouvrirros2 action send_goal /gripper_controller/gripper_cmd \control_msgs/action/ParallelGripperCommand "{command: {name: [gripper], position: [1.5]}}"# Fermerros2 action send_goal /gripper_controller/gripper_cmd \control_msgs/action/ParallelGripperCommand "{command: {name: [gripper], position: [0.0]}}"
Le bras doit rejoindre la position cible en 2 secondes (vous le voyez
bouger dans Gazebo) ; la pince s’ouvre ou se ferme selon la position
demandée.
Prochaine étape
Section intitulée « Prochaine étape »Vous savez décrire, visualiser et piloter le bras à la main. Place à la planification automatique de trajectoires : MoveIt & pick and place.
Cours conçu et animé par Etienne Schmitz