1En bref
Si votre Sirius reçoit vos commandes sans rien faire d'utile, la réponse est presque toujours dans cette liste. Les quatre pièges ci-dessous produisent tous le même symptôme : un robot qui accuse réception, renvoie fidèlement la valeur reçue, et piétine.
- L'unité de vitesse : les consignes sont normalisées dans [-1, 1], ce ne sont pas des m/s. Demander
0.15revient à demander 15 % de la vitesse maximale, pas 0,15 m/s. - Le mode robot : sorti d'usine, le robot est en
desktop, un mode qui bride volontairement la démarche pour qu'il ne tombe pas de la table. - La priorité d'action : un
ACTION_PLAYjoué en priorité 1 se fait écraser par le comportement autonome en cours. Il faut la priorité 5. - Le sommeil : après inactivité, le robot s'accroupit et n'exécute plus rien d'utile. Jouer l'action de redressement le remet debout et opérant, à distance.
À quoi s'ajoute un cinquième piège, côté protocole : les noms de commandes du WebSocket sont en majuscules. Les noms en minuscules que l'on trouve dans les binaires sont les handlers internes, pas ce qui circule sur le fil.
Le sujet le plus inédit est le capteur ToF : sa position réelle, sa grille, ses unités et son auto-occultation ne sont publiées nulle part, et c'est de là que vient la détection de vide gratuite décrite plus bas.
2Ce qu'est le robot, vraiment
Sous la carrosserie, le Sirius est un mini-ordinateur Linux (puce D-Robotics RDK X3, environ 5 TOPS) qui fait tourner ROS 2 Humble. Tout son comportement est un ensemble de nœuds ROS 2 qui discutent entre eux. L'application vit dans /root/sirius_ros2 et démarre au boot via le service ros2_launch.service.
Il existe deux niveaux pour le piloter, et le choix engage la sécurité mécanique du robot.
| Niveau | Quoi | Pour quoi faire |
|---|---|---|
| Haut niveau | WebSocket :8765, services et topics ROS 2 | Marcher, jouer une action, lire les gestes et la vision. Passe par les protections du robot (modes cinématiques, couple par action, équilibre). |
| Bas niveau | UDP :8768 et suivants, paquets Play_Keyframe | Streamer des poses image par image, c'est la voie de l'add-on Blender. Court-circuite les protections : à réserver aux limites articulaires connues. |
Les nœuds qui tournent vraiment
ros2 node list renvoie 31 entrées, dont deux doublons (core_api_node et camera_publisher_node apparaissent deux fois) : 29 nœuds distincts. Ceux qui comptent :
core_api_node: le serveur WebSocket:8765, c'est lui qui répond aux 59 commandes.sirius_motion_control_node: le mouvement. C'est lui qui consomme/gait_generation_trot/cmd_velet publiefiltered_velocity, ainsi que les topics/kinematics/*.behavior_engine_node: le comportement autonome, les émotions, l'arbre de décision. Il a absorbé ce que le paquet 2.3.6 répartissait entrerobot_behavior_controlleretemotion_manager.perception_bridge_node,face_detection_bridge,camera_publisher_node: la perception visuelle.state_sensor_tof_node: le capteur de distance, sujet d'une section entière plus bas.imu_onbody,internal_sensor_battery_onbody: centrale inertielle et batterie.action_player_node: joue les actions nommées de/root/material/actions/.lvgl_gui_node: l'écran de la tête, y compris le tactile.sirius_gamepadetxbox_bluetooth_gamepadsur le topic/joy: la manette Xbox est gérée nativement, ce que la documentation ne dit nulle part.- Et le reste de la machinerie :
lifecycle_manager_node,ota_update_node,network_config_node,sync_manager_node,motor_torque_controller_node,fan_controller_node,modbus_driver,wmix_audio_player_node,ai_interaction_node,character_state_node,user_data_manager,user_interface_udp_server_node,production_test_node,sirius_bt,ble_control_server,robot_led_controller_node.
Fiche technique officielle
- Dimensions 250 x 130 x 250 mm, 960 g, charge utile 300 g.
- Autonomie annoncée 45 à 50 min en usage actif.
- Vitesse maximale annoncée 0,4 m/s (voir plus bas : trois valeurs contradictoires circulent).
- Aucun capteur n'est mentionné dans la section Spécifications. Ni ToF, ni centrale inertielle, ni caméra.
3Versions et firmware
Savoir sur quelle version vous êtes conditionne tout le reste : entre le paquet source que le constructeur distribue avec ses outils et le firmware réellement installé, l'architecture a changé.
| Élément | Valeur | Comment on le sait |
|---|---|---|
| Firmware de notre robot | 2.5.0 bêta, installée le 23/07/2026 | Vérifié : Centre de mise à jour du robot, « System is up to date » |
| Dernière version stable | 2.4.8, 17/07/2026 | Vérifié : canal RELEASE de la même page |
| API embarquée | Sirius Core API 4.0.0 | Vérifié : annoncée par le robot dans server_info au handshake |
| Paquet source livré avec les outils OTA | 2.3.6 | Vérifié : antérieur au firmware installé, et l'écart est documenté par le constructeur lui-même |
| Application citée dans la documentation officielle | 240726 | Documenté : soit une compilation de juillet 2024, ce qui date la documentation |
Ce que le journal nous a appris
- 2.5.0, 23 juillet 2026 : « les nœuds de comportement et d'émotion ont été supprimés, fusionnés dans un nœud unique de pilotage par arbre de comportement ». C'est l'explication exacte du décalage avec le paquet 2.3.6.
- 2.4.7, 2 juillet 2026 : passage au WebRTC pour le flux vidéo web, et ajout de la détection de squelette humain. La documentation qui annonce la caméra « non disponible » n'est donc pas fausse : elle est antérieure.
- 2.4.7 et 2.4.9 : balayage vers le haut = déverrouillage de l'écran, balayage vers le bas = mise en veille, décrits comme un « geste de réveil ». Cela tranche une question restée longtemps ouverte, voir le piège 3.
- 2.4.6, 10 juin 2026 : ajout d'une protection contre la surcharge de couple dans le firmware bas niveau. Un filet de plus, sous les écrêtages articulaires et sous tout coupe-circuit logiciel.
- 2.4.5, 3 juin 2026 : « protocole d'API mis à jour ». C'est probablement là que naît le protocole en majuscules décrit dans cette page, et l'écart avec l'API que documente le constructeur.
Relire la version depuis le robot, si vous préférez la ligne de commande à l'interface :
ssh root@<IP_DU_ROBOT>
source /opt/ros/humble/setup.bash
source /root/sirius_ros2/install/setup.bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
[ -f /root/cyclonedds.xml ] && export CYCLONEDDS_URI=file:///root/cyclonedds.xml
ros2 topic echo --once /esp32/firmware_version # version du microcontroleur
ros2 topic echo --once /ota/status # etat du systeme de mise a jourLa console du constructeur
Sa barre de navigation liste neuf outils, dont plusieurs ne sont documentés nulle part : Material Manager, Inner World, System Update, Node Management (gestion des nœuds ROS, avec journal depuis la 2.4.5), Gait Debug, Group Dance, Net Debug, Behavior Tree et Timeline Editor. Un retour arrière de firmware y est également disponible. Nous n'en avons exploré que deux : les autres sont des pistes ouvertes, pas du connu.
4Les sept canaux de communication
Le robot expose sept voies d'accès distinctes. Le WebSocket est le canal principal : il pousse l'état en continu et répond aux requêtes. Mais celui qui compte le plus pour un développeur est le dernier de la liste.
| Canal | Adresse | Rôle | Statut |
|---|---|---|---|
| WebSocket | ws://<IP>:8765?audience=web | Canal principal : état poussé et requêtes/réponses | Vérifié |
| WebSocket vidéo | ws://<IP>:8766 | Signalisation WebRTC de la caméra, sans paramètre d'URL | Vérifié |
| REST | http://<IP>:8088/api/v1/… | Configuration IA, identifiants, compétences, journaux | Vérifié |
| UDP | <IP>:8768 (mouvement et LED), :8770 (yeux) | Streaming de poses Play_Keyframe, la voie Blender | Documenté |
| MJPEG | http://<IP>:8080/video_stream | Flux image simple, alternative au WebRTC | À confirmer, crédit dspeers |
| SSH | root@<IP>:22 | Accès ROS 2 et déploiement | Vérifié |
| ROS 2 | à bord, RMW CycloneDDS | 29 nœuds, environ 130 topics : le seul accès aux capteurs | Vérifié |
Le paramètre ?audience=web figure dans l'URL de l'interface officielle. La connexion fonctionne sans, mais autant rester fidèle à ce que fait le robot.
Enveloppes du WebSocket
// handshake reçu à la connexion
{"type":"event","event_type":"connection_info",
"data":{"client_id":30,"status":"connected",
"server_info":{"name":"Sirius Core API","version":"4.0.0",
"architecture":"Service-based",
"capabilities":["play_motion","status_monitoring","factory_test","ota_update"]}}}
// requête
{"type":"request","request_type":"<NOM>","request_id":"<id>","data":{}}
// réponse
{"type":"response","request_id":"<id>","success":true,"code":"ok","data":{},"error":""}
// battement de cœur, émis par le client
{"type":"ping","data":{"timestamp":0}}Codes d'erreur observés : invalid_request, not_found (avec le message « Unknown request_type »), invalid_argument, service_unavailable. Sonder un nom de commande inconnu est sans effet sur le robot : on peut explorer l'API sans rien casser.
Le flux d'événements poussés
| Événement | Cadence | Contenu |
|---|---|---|
gait-trajectory | 10 Hz | filtered_velocity : ce que le générateur de démarche applique réellement |
motor-load | 1 Hz | 14 charges moteur, plage ±1000, unité pour mille de PWM |
motor-temperature | 1 Hz | 4 pattes, mais renvoie 0 sur ce firmware (sondes muettes) |
battery-status | 1 Hz | percentage est un ratio 0 à 1, plus tension, courant, température |
emotion-update | 1 Hz | état émotionnel, valence, éveil, satiété, fatigue |
behavior-status | 1 Hz | arbre de comportement actif, intention, événements récents (dont les tapes sur le crâne) |
vision-detection | ~30 Hz | détections et squelettes, voir la section vision |
system_metrics | 1 Hz | processeur, charge moyenne, disque |
lifecycle_update | ~0,1 Hz | tous les nœuds ROS et leur état |
5Se connecter au robot
Trouver son adresse IP
- Sur l'écran de la tête, menu Réseau.
- Depuis la liste des baux de votre routeur.
- Par le mode point d'accès du robot : SSID
sirius_xx, mot de passehengbot123(publié par le constructeur dans son manuel), passerelle192.168.233.1.
Votre machine et le robot doivent être sur le même réseau. L'interface de debug du constructeur est une page hébergée chez Hengbot, pas sur le robot : http://8.163.38.44:8082/connect?robot=<IP_DU_ROBOT>. Elle ouvre ensuite un WebSocket directement vers votre robot sur :8765. On y trouve le joystick virtuel, la lecture d'actions, la vision et le mode autonome. C'est le moyen le plus rapide de vérifier que tout répond avant d'écrire une ligne de code, et c'est ce test qui nous a mis sur la piste du piège 1.
Accès SSH
ssh root@<IP_DU_ROBOT>
# charger l'environnement ROS 2, sinon aucun nœud n'est visible
source /opt/ros/humble/setup.bash
source /root/sirius_ros2/install/setup.bash
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
[ -f /root/cyclonedds.xml ] && export CYCLONEDDS_URI=file:///root/cyclonedds.xml
ros2 node list # 31 nœuds
ros2 topic list # environ 130 topics6Piège 1 : la vitesse est normalisée, pas en m/s
Les champs linear_x, linear_y et angular_z attendent une valeur dans [-1, 1] : une fraction du débattement maximal, pas des mètres par seconde. La touche « avancer » de l'interface officielle envoie tout simplement linear_x: 1.
{"type":"request","request_type":"gait_control",
"data":{"linear_x":1,"linear_y":0,"angular_z":0}}Envoyer 0.15 en croyant demander 0,15 m/s revient donc à demander 15 % de la vitesse maximale : la foulée devient minuscule et le robot marche sur place. Les ordres de grandeur relevés en télémétrie :
| Consigne | Comportement observé |
|---|---|
| 0,10 | piétine sur place |
| 0,45 à 0,50 | marche franche |
Pour convertir une vitesse réelle en consigne, en s'appuyant sur le domaine de validité relevé sur le robot : linear_x = vx / 0.24 en marche avant, vx / 0.16 en marche arrière, linear_y = vy / 0.20, angular_z = wz / 1.20.
La preuve, côté ROS 2
entrée : /gait_generation_trot/cmd_vel geometry_msgs/msg/Twist
retour : /gait_generation_trot/filtered_velocity geometry_msgs/msg/Twist
consigne vx=+0.50 -> mesuré vx=+0.500 (rapport 1.00)La consigne ressort à l'identique sur filtered_velocity, or 0,50 dépasse la vitesse maximale déclarée du robot. Ce ne peut donc pas être des mètres par seconde. filtered_velocity fait foi : il dit ce que le générateur de démarche applique vraiment, et permet de distinguer « le robot refuse » de « on lui demande trop peu ».
Trois vitesses maximales contradictoires
| Source | Vitesse avant annoncée |
|---|---|
| Fiche technique officielle | 0,4 m/s |
| Documentation de l'API WebSocket | 0,28 m/s |
ros2 param dump sur le robot | 0,24 m/s |
C'est la dernière valeur qui gouverne le comportement réel, puisqu'elle vient des paramètres chargés par le nœud de contrôle. Domaine complet relevé sur la machine : avant 0,24 m/s, arrière 0,16 m/s, latéral ±0,20 m/s, rotation ±1,2 rad/s, tangage et roulis ±0,524 rad. Les garde-fous joint_clamp_enabled et ws_clamp_enabled sont actifs : une consigne hors domaine est écrêtée, pas poussée contre la butée.
7Piège 2 : les noms de commandes sont en majuscules
C'est le piège principal du protocole WebSocket. Le fil réseau utilise des clés en majuscules, par exemple BEHAVIOR_SET_PAUSE. Les noms en minuscules que l'on trouve en fouillant les binaires, comme set_behavior_pause, sont les handlers internes, pas ce qui circule.
Certaines commandes acceptent les deux formes, par alias hérité : play_motion, gait_control, get_status et get_actions répondent en minuscules. Mais les commandes de mode n'existent qu'en majuscules. Chercher set_behavior_pause sur le fil renvoie « Unknown request_type » et fait croire à tort que la fonction est inaccessible.
Le protocole complet compte 59 commandes, extraites du bundle officiel. Les plus utiles :
| Clé réseau | Handler interne | Usage |
|---|---|---|
ACTION_PLAY | play_motion | jouer une action nommée ou un fichier |
ACTION_STOP / ACTION_STOP_ALL | cancel_motion | interrompre |
ACTION_GET_LIST | get_actions | lister la bibliothèque d'actions du robot |
BEHAVIOR_SET_PAUSE | set_behavior_pause | mettre le comportement autonome en pause |
BEHAVIOR_SET_RANDOM_ACTION | enable_random_action | animations spontanées au repos |
USER_GET_ROBOT_MODE / USER_SET_ROBOT_MODE | get/set_robot_mode | mode sol ou bureau (piège 3) |
MOTOR_SET_TORQUE / MOTOR_SET_THERMAL_PROTECTION | … | couple et protection thermique |
VISION_SET_DETECTION | enable_detection | active la perception et le flux vidéo |
VISION_SET_FACE_TRACKING | face_tracking_control | suivi de visage |
BATTERY_GET_STATUS | get_battery_status | état de la batterie |
Familles complètes également présentes : EMOTION_*, USER_* (thème, MBTI, langue, paramètres de nœud), LIFECYCLE_*, NETWORK_*, OTA_*, SYNC_*, MATERIAL_*.
8Piège 3 : le mode sol ou bureau
Deuxième cause classique du « il piétine sans avancer », après l'unité de vitesse. Le robot possède deux modes de fonctionnement, et il sort d'usine dans celui qui bride la marche.
USER_GET_ROBOT_MODE {} -> {"robot_mode":"desktop"}
USER_SET_ROBOT_MODE {"robot_mode":"ground"} -> {"robot_mode":"ground"}desktop: selon le firmware, « limite les mouvements amples et la démarche pour empêcher le robot de tomber de la table ». Les pattes bougent sur place.ground: « active toutes les actions, y compris la démarche et les déplacements amples ».


L'écran de la tête affiche un état nommé « Ground », et le robot y bascule de lui-même après une période d'inactivité. Un balayage vertical sur l'écran « débraye » cet état, mais ce n'est pas un changement de mode robot. Les notes de version du constructeur sont explicites : le balayage vers le haut déverrouille l'écran et sert de geste de réveil (versions 2.4.7 et 2.4.9), le balayage vers le bas met en veille. Le mode sol ou bureau, lui, ne se change que par USER_SET_ROBOT_MODE, ou depuis une interface.
La documentation officielle décrit par ailleurs un mode Développeur sur l'écran de tête, qui « suspend l'interface pour permettre la programmation Python via les API ». Nous ne l'avons pas testé. La navigation dans cet écran se fait par les boutons d'oreille, la validation par une tape sur le crâne.
9Piège 4 : le capteur n'est pas là où on croit
Pendant dix sessions, notre robot en déambulation autonome s'arrêtait net devant un obstacle situé à 191 mm. Toujours 191 mm, avec 5 mm d'écart-type. Un obstacle qui n'existait pas : il fuyait sa propre mâchoire.
Le capteur ToF n'est pas dans la tête, comme la position de la « bouche » du robot le laisse croire. Il est sous le cou, en haut du poitrail. Placé si haut et si en avant, il voit son propre menton dans le haut de son champ, et ses propres pattes avant dans le bas.
La mesure qui tranche
Quand on bascule la tête de ±0,30 rad (17°) sur son axe de tangage, les distances ToF ne varient que de 1 à 2 mm. Un capteur logé dans la tête verrait ses distances au sol changer de plusieurs dizaines de millimètres pour un tel basculement.
| Axe de tête | Écart rangée basse | Écart rangée haute |
|---|---|---|
| x (tangage, la tête bouge de visu) | 1 mm | 2 mm |
| y (lacet) | 0 mm | 0 mm |
| z | 0 mm | 0 mm |
Les conséquences sont presque toutes favorables. La géométrie du ToF ne dépend que de l'assiette du corps, que le générateur de démarche régule déjà : il n'y a donc aucun angle de tête à suivre dans vos calculs. Et la tête peut regarder ailleurs, suivre un visage, sans perturber la navigation. En contrepartie, le champ est fixe par rapport au corps : impossible d'orienter le capteur pour balayer les côtés, c'est le corps entier qu'il faut tourner.
L'auto-occultation par les pattes
| Rangée | Au repos | Main devant | Chute |
|---|---|---|---|
| 12-15 (haut) | 866 mm | 168 mm | 79 % |
| 8-11 | 838 mm | 170 mm | 81 % |
| 4-7 | 334 mm | 211 mm | 37 % |
| 0-3 (bas) | 237 mm | 195 mm | 18 %, occultée |
Une main passée devant le capteur fait chuter les distances mesurées de 80 % sur les rangées hautes, mais de 18 % seulement sur la rangée basse : les pattes avant y occupent déjà le champ. Et en marchant, elles balancent, donc elles entrent et sortent du champ à chaque foulée. D'où deux règles de conception : ne jamais fonder une détection sur la seule rangée 0-3, et apprendre le fond en marchant, jamais à l'arrêt.
Caractérisation complète du ToF
| Grandeur | Valeur mesurée |
|---|---|
| Topic | /state_sensor/tof/distance_array |
| Type | state_sensor_tof/msg/ToFDistanceArray |
| Unité | millimètre |
| Plage | 11 à 2047 mm, où 2047 signifie pas de cible |
| Cadence | environ 38 Hz (384 trames en 10 s) |
| Zones | 16, en grille 4 x 4, toutes vivantes |
Le même relevé est aussi publié en image mono16 4 x 4 sur /state_sensor/tof/heatmap. Le champ raw_registers (11 valeurs, souvent 65535) est du débogage constructeur, sans intérêt.
haut [12] [13] [14] [15]
[ 8] [ 9] [10] [11]
[ 4] [ 5] [ 6] [ 7]
bas [ 0] [ 1] [ 2] [ 3]
gche drteSignature au repos
robot debout, tete au neutre, champ degage
.. 765 .. .. <- horizon : hors portee
780 786 .. .. <- sol lointain
304 295 291 298 <- sol a ~30 cm
198 219 218 201 <- sol a ~20 cm, juste devant les pattesLes rangées basses voient le plancher à distance croissante. C'est de là que découlent les deux lectures qui fondent toute navigation autonome, et la section suivante.
10La détection de vide, gratuite
C'est la trouvaille la plus utile de tout ce travail, et elle ne demande aucun matériel supplémentaire. Puisque les rangées basses du ToF voient en permanence le plancher, entre 20 et 30 cm devant elles, il suffit de surveiller sa disparition.
- Obstacle : les rangées hautes cessent de saturer et les basses raccourcissent.
- Vide (bord de table, marche, escalier) : les rangées basses, qui voyaient le sol, passent brutalement à 2047, c'est-à-dire « pas de cible ».
Le principe d'implémentation retenu : le nœud apprend son fond pendant cinq secondes de marche en ligne droite, sous forme d'enveloppe minimum et maximum par zone. Il ne réagit ensuite qu'aux écarts. Ce qui raccourcit est un obstacle, ce qui s'allonge est un vide.
Les garde-fous qui se sont révélés nécessaires
- Le vide l'emporte sur toute autre décision.
- Seules les rangées basses ont le droit de déclarer un vide, et seulement les zones qui voyaient le sol de près (moins de 50 cm) et presque toujours (80 % des trames).
- Toute décision doit persister trois cycles avant d'être appliquée : le trot fait tanguer le corps, une seule trame ne prouve rien.
- Le recul est bridé à la moitié de la vitesse d'avance et borné à 1,5 s, parce que le robot ne voit rien derrière lui.
- Une rotation sans issue de plus de 5 s déclenche un recul et un changement de sens, sinon le robot tourne indéfiniment.
- Le nœud publie dix consignes nulles à l'arrêt, y compris sur SIGHUP. Validé en réel lors d'une coupure Wi-Fi : le robot s'arrête proprement au lieu de continuer sur sa dernière consigne.
L'historique des versions dit tout du chemin parcouru : recul perpétuel en v1 (seules 8 zones apprises, les autres signalaient sans cesse un obstacle surgi de nulle part), vides fantômes en v6 (zones lointaines saturées prises pour des précipices), rotation sans fin en v7, et v8 qui a révélé le piège de la vitesse normalisée. La v9 se faufile et esquive. La v10 a tenu 11 s de marche rectiligne et survécu à une perte de SSH.
La v12 masque une bande étroite de 170 à 225 mm dans le haut du champ, la signature de la mâchoire, mais seulement si les rangées basses ne confirment pas la présence d'un obstacle, pour qu'une étagère basse reste visible. Elle remplace aussi la marge fixe de 120 mm par une marge proportionnelle au fond appris (30 %, plancher à 50 mm) : avec un fond à 200 mm, une marge fixe de 120 mm rendait les rangées basses incapables de déclencher quoi que ce soit. Trente-quatre tests hors ligne rejouent de vraies trames capturées sur le robot.
11Faire marcher le robot
Deux voies, selon que vous travaillez depuis votre machine (WebSocket) ou depuis le robot lui-même (ROS 2). Dans les deux cas, relisez d'abord les pièges 1 et 3 : ils expliquent la plupart des cas où le robot refuse d'avancer.
Par le WebSocket
| Commande | Charge utile | Effet |
|---|---|---|
gait_control | {linear_x, linear_y, angular_z} dans [-1, 1] | marche continue |
gait_step_move | {linear_x, linear_y, angular_z, steps} | marche sur un nombre de foulées donné, le robot les compte lui-même |
set_motion_mode | {mode, mode_name} | profils DEFAULT, SLOW, WALK, PRECISION, CLIMB, FAST_RUN |
self_recover | {} | redressement après chute |
Par ROS 2, depuis le robot
import rclpy
from rclpy.node import Node
from geometry_msgs.msg import Twist
# ATTENTION : linear.x est NORMALISE dans [-1, 1], pas des m/s.
# 0.10 fait pietiner sur place. 0.45 fait marcher.
rclpy.init()
node = Node('hello_move')
pub = node.create_publisher(Twist, '/gait_generation_trot/cmd_vel', 10)
cmd = Twist()
cmd.linear.x = 0.45
for _ in range(30):
pub.publish(cmd)
rclpy.spin_once(node, timeout_sec=0.1)
# toujours republier des zeros a l arret
cmd.linear.x = 0.0
for _ in range(10):
pub.publish(cmd)
rclpy.spin_once(node, timeout_sec=0.05)Le service /gait_generation_trot/step_move (type gait_generation_trot/srv/GaitStepMove, champs velocity et duration) fait un pas net et rend la main. C'est le plus simple pour un premier essai : une vitesse négative fait reculer.
Se relever, se coucher
ACTION_PLAY {
"file_path":"/root/material/actions/stand_default_returnPosition_brief.avi",
"loop":false,
"priority":5,
"torque":2047
}Trois détails comptent, et chacun a coûté du temps : l'action est returnPosition et non stand_default_idle ; la priorité 5 est indispensable, car en priorité 1 (la valeur par défaut) le comportement autonome en cours écrase l'action et le robot reste couché ; et le couple doit être au maximum.
Le sommeil
Après inactivité, le robot passe en état émotionnel sleeping, avec un éveil proche de zéro, et s'accroupit. Dans cet état, la marche ne produit rien d'utile. Pour le réveiller à distance, jouez l'action de redressement, celle de la sous-section précédente, en priorité 5. Vérifié sur le robot : il se relève et obéit de nouveau.
Ce qui ne se pilote pas à distance, c'est l'état émotionnel lui-même : EMOTION_SET_STATE répond service_unavailable sur ce firmware, et EMOTION_INTERACTION refuse tous les types tentés (touch_tap, touch, pet, dog_bone). La distinction compte : on ne peut pas changer son humeur, on peut parfaitement le remettre au travail.
12Gestes, vision et caméra
Les gestes de la main : à vérifier sur votre firmware
Un modèle de reconnaissance de gestes existe côté D-Robotics, et le paquet sirius_full_v2.3.6 référence le topic /hobot_hand_gesture_detection (ai_msgs/PerceptionTargets), avec un attribut gesture porteur d'une valeur entière.
| Valeur | Geste | Valeur | Geste |
|---|---|---|---|
| 2 | ThumbUp (pouce levé) | 11 | Okay |
| 3 | Victory (V) | 12 | Thumb Left |
| 4 | Mute (chut) | 13 | Thumb Right |
| 5 | Palm (main ouverte) | 14 | Awesome |
L'événement vision-detection
Une fois VISION_SET_DETECTION actif, le robot pousse sur le canal principal un événement à environ 30 Hz. C'est la sortie du modèle de perception, disponible sans toucher au flux vidéo : on peut donc faire du suivi sans jamais afficher d'image.
{"type":"event","event":"vision-detection","data":{
"detections":[
{"class_id":0,"class_name":"body","type":"body","confidence":1,
"rect":{"x":239,"y":1,"width":126,"height":192}},
{"class_name":"head","rect":{}},
{"class_name":"face","rect":{}}
],
"skeletons":[
{"track_id":1,"type":"body",
"points":[{"x":191,"y":3,"score":0.859}]}
],
"image_width":640,"image_height":360}}- Les coordonnées sont dans le repère 640 x 360 du modèle, pas dans celui de la vidéo affichée. Il faut les remettre à l'échelle, et tenir compte du letterboxing si la vidéo est en
object-fit: contain. track_idpersiste entre les trames : c'est du suivi, pas de la détection image par image.- Classes observées à ce jour :
body,head,face. Les objets « os, balle, peluche » du firmware sont des items virtuels du système d'émotions, pas des classes de vision. - À 30 Hz, ne jamais faire passer ces trames par l'état d'un composant React : les stocker dans une référence et dessiner dans un
requestAnimationFrame.

La caméra, en WebRTC
Ce n'est pas une image à récupérer : c'est un flux WebRTC négocié sur une seconde WebSocket. La vidéo circule ensuite directement entre le navigateur et le robot, en pair-à-pair. Un backend ne peut donc que relayer la signalisation, jamais servir le flux.
- Sur
:8765, envoyerVISION_SET_DETECTION {enabled: true}. Le robot répond « Web streaming enabled ». - Le navigateur ouvre
ws://<IP>:8766, sans paramètre d'URL. C'est le point qui nous a coûté le plus de temps : la signalisation vidéo ne vit pas sur le canal principal. - Le robot y envoie
{"type":"welcome","client_id":"ws_N"}. Cet identifiant est une chaîne, distincte duclient_idnumérique du handshake. Reconstruirews_<numéro>ne fonctionne pas. - Le navigateur envoie
webrtc_offeravec ceclient_id, le robot répondwebrtc_answer. - Échange de
webrtc_ice. Les candidats du robot arrivent préfixésa=, à retirer avantaddIceCandidate.
Si le pair-à-pair est bloqué par le réseau, il reste une voie plus simple : le service ROS /camera/capture_jpeg, en affichage par images successives. Services caméra côté ROS : /camera/capture_jpeg, /camera_publisher_node/enable_web_streaming, /camera_publisher_node/enable_yolo_shm.
13Commander la tête
Le canal confirmé sur le robot est un topic ROS d'entrée du nœud de cinématique inverse. Il reçoit une consigne et ne publie rien en retour.
topic : /kinematics/ik_subscriber/head_euler_follow
type : geometry_msgs/msg/Point
unite : RADIANS
x = tangage (haut / bas)
y = lacet (gauche / droite)
z = sans effet observablexcommande le tangage, confirmé de visu.ycommande le lacet.zn'a aucun effet observable : la tête n'a que deux degrés de liberté.- De 0,10 à 0,35 rad, les mouvements sont progressifs. Rester sous 0,35 rad : au-delà d'environ 1 rad, c'est la butée articulaire.
Rappel utile : puisque le ToF est dans le poitrail et non dans la tête, bouger la tête ne perturbe pas la navigation. La tête peut donc suivre un visage pendant que le corps se dirige avec ce même champ ToF, sans que l'un gêne l'autre.
14Ce qui n'existe pas, et ce que la doc omet
Cette section est là pour vous éviter de chercher pendant des heures quelque chose qui n'est pas dans la machine.
Ce qui n'existe pas
- Pas de retour d'angle de tête : les topics existent mais restent muets.
- Pas de température moteur : l'événement
motor-temperaturerenvoie 0 sur ce firmware, les sondes sont muettes. - Pas de réglage de l'état émotionnel à distance :
EMOTION_SET_STATErépondservice_unavailable. Le réveil, lui, passe très bien par l'action de redressement. - Pas de détection de clap native, ni de doigt pointé dans le modèle de gestes.
- Pas de classes de vision au-delà de body, head et face à ce jour. Le service
enable_yolo_shmlaisse penser qu'un modèle YOLO existe par ailleurs, non confirmé.
Ce qui existe, et que la documentation ignore aussi
La liste précédente a son pendant positif : la centrale inertielle est lisible, alors que la fiche technique ne la mentionne pas plus que le reste des capteurs.
/state_sensor/imu_onbody/imu_publisher/imu_data sensor_msgs/msg/Imu
/state_sensor/imu_onbody/imu_publisher/imu_angle geometry_msgs/msg/Vector3
/state_sensor/imu_onbody/imu_publisher/diagnostic "IMU sensor is operating normally"imu_angle sert de garde-fou dans notre déambulation : si l'assiette dérive de plus de 0,10 rad par rapport à celle apprise, la géométrie du ToF n'est plus valable et toute décision de vide est suspendue. C'est un exemple concret d'un capteur non documenté employé pour sécuriser un autre capteur non documenté.
Ce que la documentation officielle omet
| Sujet | Documenté par le constructeur ? |
|---|---|
| Lecture de capteurs, quelle qu'elle soit | Non |
| Le capteur ToF, y compris dans les spécifications | Non |
| La centrale inertielle, la caméra | Non |
| ROS 2, alors qu'une version EDU est vendue sur cet argument | Non |
| Le mode sol / bureau, la priorité d'action, le sommeil | Non |
| Le système d'émotions, la bibliothèque d'actions, l'interaction IA | Non |
| Le REST du port 8088, l'accès SSH | Non |
| Le protocole « Sirius Core API v4.0.0 » et ses 59 commandes | Non, il n'apparaît nulle part |
L'API WebSocket « keyframes » et l'API Python hengbot | Oui |
Les modes Emergency_Stop et Free_Mode | Oui, et nous les ignorions |
La documentation officielle existe et mérite d'être lue : elle décrit une API WebSocket différente de celle que nous avons cartographiée, la voie « keyframes » du port UDP 8768, avec les commandes Mode_Switch, Control_Move, Start_Record, Play_Keyframe, Get_Status, Set_Parameter. Elle documente aussi un mode Liberté et un mode Développeur sur l'écran de tête, et un auto-test matériel (IMU, boutons, batterie, Wi-Fi, servomoteurs).
L'écosystème indépendant, en juillet 2026
Le terrain est quasi vierge. Huit mois après les premières livraisons, le nombre de tutoriels développeur publiés sur YouTube, toutes langues confondues, est de zéro. Tout ce qui existe tient en deux dépôts, d'une seule personne :
- dspeers/sirius-control-panel : découvre le REST sur
:8088et un flux MJPEG sur:8080. Sontest_api.pyest la seule documentation d'API reconstituée publiquement disponible, et la seule source publique mentionnant la grille 4 x 4. - dspeers/sirius-voice-bridge : substitue une reconnaissance vocale locale à celle d'origine. Révèle au passage que la voix du Sirius transite par le cloud ByteDance / Volcano Engine, ce qu'aucune couverture presse ne mentionne.
mitchrk/sirius-osrdannonce un firmware open source et est entièrement vide.- Le paquet PyPI
hengbot-apiest un faux ami : il date de novembre 2024 et pilote le Sparky, le robot précédent.
15Piloter le robot depuis un navigateur
Le kit que nous utilisons pour tout ce travail est téléchargeable. Il n'a rien d'un produit : c'est un outil de rétro-ingénierie devenu utilisable, publié parce qu'il fait gagner des heures à qui veut commencer.

Ce qu'il fait : deux joysticks pour marcher et s'orienter, un troisième pour la tête, la vue caméra en direct avec les détections dessinées par-dessus, la bibliothèque d'actions du robot avec ses noms traduits du chinois, la télémétrie des 14 moteurs, le journal de tous les appels d'API, le sélecteur Sol / Bureau, et un coupe-circuit qui arrête le robot au-delà de 850 ‰ de charge moteur maintenus 0,8 s.
Comment il est fait : un pont Python tourne sur votre machine (FastAPI), il parle WebSocket au robot et sert une interface React à votre navigateur. La vidéo, elle, va directement du robot au navigateur en WebRTC : un backend ne peut relayer que la signalisation, jamais le flux.
L'interface est bilingue français et anglais : un bouton FR / EN dans la barre du haut, à côté du thème, et le choix est mémorisé. Le bouton de posture s'appelle Couché et non « Au sol », pour ne pas le confondre avec le mode Sol / Bureau, qui décrit l'environnement du robot et non sa posture. Depuis la v2.6, ce sélecteur reflète l'état réel du robot, y compris quand le comportement autonome agit seul : la posture est déduite de l'action jouée, signalée comme telle, et rien ne s'allume tant qu'elle n'est pas connue.
Ce qu'il vous faut
- Python 3 installé sur votre PC, avec la case « Add Python to PATH » cochée à l'installation. C'est la cause numéro un des échecs de démarrage.
- Un robot Sirius sur le même réseau Wi-Fi que votre PC.
- Un navigateur récent, la vidéo passe par WebRTC.
Aucune dépendance à installer à la main : le lanceur récupère fastapi, uvicorn, websockets et httpx à la première utilisation, une fois pour toutes, en une trentaine de secondes.
Se connecter, en trois étapes
- Allumez le robot et vérifiez qu'il est sur le même réseau Wi-Fi que votre PC. Son adresse IP s'affiche sur l'écran de sa tête, menu Réseau.
- Décompressez l'archive et double-cliquez
demarrer.bat. Une fenêtre noire s'ouvre, affiche le numéro de version, puis votre navigateur s'ouvre seul sur l'interface. Si ce n'est pas le cas, allez surhttp://127.0.0.1:8787. - Saisissez l'adresse IP du robot dans l'interface, puis cliquez « Connecter ». Elle est mémorisée : les fois suivantes, un clic sur l'adresse récente suffit.

S'il ne bouge pas
Par ordre de fréquence, et les deux premières causes sont les pièges 1 et 3 de cette page :
- Il bouge les pattes sans avancer : il est en mode Bureau, basculez sur Sol dans Modes et comportement. Ou la vitesse demandée est trop faible : montez le curseur.
- Il ne réagit à rien : soit il dort, jouez une action pour le réveiller, soit le mode autonome est actif et annule vos commandes, coupez-le.
- « Impossible de joindre le robot » : vérifiez l'adresse IP, et que le PC et le robot sont bien sur le même réseau.
- « Python introuvable » : réinstallez Python en cochant « Add Python to PATH ».
- Voir ce qui se passe : l'API du pont est documentée et testable sur
http://127.0.0.1:8787/docs.
Le kit est fourni sans garantie : il pilote du matériel qui peut tomber ou se coincer. Les lanceurs sont des fichiers .bat, donc Windows ; le pont Python est multiplateforme mais n'a été testé nulle part ailleurs. Un bug, une remarque, un résultat d'essai : écrivez-nous, c'est ainsi que cette page progresse.
16Sécurité
- Le robot ne voit rien derrière lui. Le ToF regarde vers l'avant et il n'existe aucun capteur arrière. Toute marche arrière est aveugle : vitesse réduite et durée bornée.
- Les moteurs chauffent. Évitez les sessions très longues en continu, d'autant que la remontée de température est muette sur ce firmware.
- Ne modifiez pas les fichiers du firmware sans sauvegarde. Travaillez avec vos propres scripts dans
/root/ou un dossier à vous. - Gardez un arrêt d'urgence sous la main, dans un terminal déjà ouvert. Publier des consignes nulles en boucle est le moyen le plus fiable de tout arrêter.
- La voie UDP
Play_Keyframecourt-circuite les protections du robot. Ne l'utilisez qu'après avoir relevé les limites articulaires, et jamais pour un premier essai.
Surveiller la charge moteur
L'événement motor-load remonte 14 charges à 1 Hz, en pour mille de PWM, sur une plage de ±1000. C'est le seul instrument fiable dont on dispose pour détecter une butée, puisque les sondes de température sont muettes. Mesures réelles :
| Condition | Pic observé |
|---|---|
| Repos | 120 à 162 ‰ |
| Marche 0,06 m/s | 540 ‰ |
| Marche à vitesse maximale | 530 ‰ |
| Rotation à vitesse maximale | 540 ‰ |
| Moteur en butée | 950 à 985 ‰, soutenus |
Le firmware applique par ailleurs ses propres garde-fous, actifs en permanence : écrêtage des angles articulaires, écrêtage de l'espace de travail, seuil de saut articulaire à 0,5 rad, régime moteur plafonné à 200 tr/min. Une consigne hors domaine est donc écrêtée plutôt que poussée contre la butée. Cela ne dispense d'aucune précaution, mais c'est un filet de plus.
Enfin, la documentation officielle mentionne un mode Emergency_Stop via Mode_Switch, que nous n'avons pas encore testé et que nous avions reconstruit à la main. Si vous le validez, écrivez-nous.

