Studio 360 pour Sirius (Studio 360) est un projet indépendant d'explorations360, sans lien ni affiliation avec Hengbot. Sirius et Hengbot sont des marques de leurs propriétaires respectifs. Ce kit est le fruit d'un travail de rétro-ingénierie de l'API du robot : il n'est ni fourni, ni approuvé, ni soutenu par le constructeur.
1En bref
Si votre Sirius reçoit vos commandes sans rien faire d'utile, la réponse est presque toujours dans cette liste. Chacun de ces pièges se reconnaît à son symptôme : un robot qui accuse réception et piétine, une commande qui revient en « Unknown request_type », une démarche bridée d'origine, un obstacle qui n'existe pas, une inclinaison qui pivote toute seule.
- 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. - Les noms de commandes : sur le fil WebSocket ils sont en majuscules. Les noms en minuscules que l'on trouve dans les binaires sont les handlers internes, pas ce qui circule.
- 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 position du capteur : le ToF n'est pas dans la tête mais sous le cou, et il voit son propre menton. Sans le savoir, on prend le robot lui-même pour un obstacle à 191 mm.
Deux autres causes classiques d'un robot inerte ne sont pas des pièges de protocole mais des règles de conduite : la priorité d'action, qu'il faut monter à 5 pour ne pas se faire écraser par le comportement autonome, et le sommeil, dont on ne sort qu'en jouant l'action de redressement. Les deux sont traitées dans Faire marcher le robot.
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.5 bêta, installée le 30/08/2026 | Vérifié : mise à jour effectuée puis pilotage, LED et API recontrôlés (auparavant 2.5.0, du 23/07/2026) |
| Dernière version stable | 2.4.8, 17/07/2026 | Vérifié : canal RELEASE de la même page |
| Versions au catalogue | 13 en bêta, 2 en stable | Vérifié : relevé du 30/08/2026 dans le Centre de mise à jour |
| 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.5, 3 août 2026 : reconnaissance de boîte englobante de main ajoutée à la vision, plus une page de débogage des règles de caractère et une API de changement d'état dans l'arbre de comportement. Ce que cette détection fait, et surtout ce qu'elle ne fait pas, est mesuré dans vision et gestes.
- 2.5.4, 1er août 2026 : pilotage à distance. Appairage et provisionnement réseau par QR, SoftAP ou Bluetooth, voix à distance en WebRTC avec serveur TURN, et MQTT pour le réveil, les accusés d'action et l'état en ligne. Autrement dit, le robot cesse d'être une machine strictement locale : il devient joignable depuis l'extérieur du réseau domestique. À savoir avant de le laisser allumé.
- 2.5.2 et 2.5.3, 31 juillet 2026 : éditeur d'arbre de comportement ajouté, puis fonctions d'arbre exposées au client web ; l'écran de la tête gagne l'appui long pour le menu et la tape sur le crâne pour revenir à l'accueil.
- 2.5.1, 27 juillet 2026 : le module de cinématique bas niveau est porté vers le calculateur bas, et un auto-équilibrage est introduit dans la démarche.
- 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 mode sol ou bureau.
- 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, le seul port ouvert | Streaming de poses Play_Keyframe, la voie Blender, et seule voie connue vers les LED | Vérifié |
| 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 | charge processeur, température du processeur, cœurs, mémoire, disque, temps de fonctionnement, signal Wi-Fi, processus |
network-status et hotspot-status | à l'événement | état du lien et du point d'accès |
lifecycle_update | ~0,1 Hz | tous les nœuds ROS et leur état |
Onze types d'événements en tout, poussés sans rien demander dès la connexion. C'est la source la plus complète du robot, et de loin la plus simple à exploiter : un seul canal ouvert, et tout arrive.
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 de la vitesse normalisée.
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 topics6L'API REST : ce que le constructeur documente, et ce qu'il livre
À côté du WebSocket, le robot sert une API REST sur http://<IP_DU_ROBOT>:8088/api/v1. Le constructeur en publie la spécification complète dans le bundle de sa console. Nous l'avons prise au mot et testé les routes une par une, sur la machine.
Les quatorze routes, testées en direct
| Route | Ce que la machine répond |
|---|---|
GET /ai/character | 200 — la fiche de personnage active (MBTI, background, persona) |
GET /ai/credentials/status | 200 — état des briques ASR, LLM et TTS |
GET /battery/status | 200 — la route la plus riche, et la plus piégeuse |
GET /battery/charging | 200 |
GET /motor/status | 200 — mais la température seule, pas l'état des moteurs |
GET /motor/temperature | 200 — 4 sondes de patte, muettes (0) |
GET /motor/mode | 503 « Motor mode data not yet received » |
GET /sensor/imu | 200 — orientation en quaternion, alors que la spec annonce des angles d'Euler |
GET /vision/faces | 200 ou 503 selon la présence d'un visage |
GET /vision/gestures | 200 — la route est servie, mais rien ne l'alimente |
GET /action/list | 200 — 184 actions relevées en 2.5.0, 224 depuis la 2.5.5, avec leur couple et leur caractère officiel |
GET /action/status | 200 |
GET /transform/status et /head | 200 — corps 6 axes, 4 pieds, tête |
GET /ping, /logs/, /skill/config | 404 — n'existent pas sur ce firmware |
Trois pièges mesurés
- L'enveloppe n'est pas celle de la spec. Le robot répond
{code, data, message, success}, et la documentation annonce un champstatusqui n'existe pas. Tout code écrit d'après la spec casse au premier appel. /motor/statuspromet plus qu'il ne donne. Annoncé comme « l'état détaillé des 12 moteurs », il ne renvoie que la température, sur quatre sondes muettes. Au passage, le robot en compte quatorze, pas douze.- La batterie se lit de travers. Le champ
chargeest une capacité en ampères-heures, sur 2,25 Ah au total ; le pourcentage, c'estpercentage. Confondre les deux donne un robot à 2 % de batterie en pleine forme.
Côté vision, la trame mesurée donne une image de 640 × 360, avec class_id, class_name, confidence et un rect{x, y, width, height} — là encore une structure différente de celle de la spécification.
7La 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.
8Les 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 |
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_*.
9Le 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.
10Le 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.
L'enquête du 1er septembre 2026 : le capteur est coupé par le firmware
Tout ce qui suit a été vérifié sur la machine, en lecture seule : aucun mouvement, aucune écriture.
La route GET /api/v1/sensor/tof répond 200 et sert une grille 4 × 4 entièrement vide : distance_mm: 0 et valid: false, seize fois. Nous avons relevé 118 trames en quatre phases — champ libre, obstacle à 40 cm, obstacle à 15 cm, balayage à la main. Aucune mesure valide, jamais. Le 25 juillet, la même machine sur le même topic donnait seize distances vivantes, avec 19 à 52 mm de dispersion et valid: true seize fois.
Nous avons remonté la chaîne maillon par maillon, et chaque maillon est innocent : le pont REST est abonné au bon topic avec la bonne qualité de service ; le nœud state_sensor_tof_node est actif et publie à 245 Hz sans une erreur au journal ; la source amont /device_modbus/read_buffer_view est pleine de données vivantes ; la liaison série tourne à 250 trames par seconde.
La cause est écrite en clair dans le binaire du pilote bas niveau, en deux messages que nous traduisons du chinois : « Évitement ToF par SLP désactivé (mode = OFF + porte de mouvement = 0) », et, si cette désactivation échoue, « l'évitement est peut-être encore actif ; quand le ToF est obstrué, le bas niveau bougera les pattes de lui-même ».
Daté à la minute : la ligne de désactivation apparaît sept fois au journal du pilote, toutes postérieures au dernier démarrage sain, et elle est totalement absente des sessions de juillet et du 1er août. Le basculement coïncide avec la mise à jour vers 2.5.5. Et c'est bien elle qui l'a apportée : la sauvegarde du firmware précédent est conservée sur le robot, et la comparaison binaire des deux pilotes montre que la fonction de désactivation n'existe pas en 2.4.8.
11L'inclinaison ne se lit pas sur le quaternion
La centrale inertielle publie l'orientation du robot sous forme de quaternion. En extraire le roulis et le tangage par décomposition d'Euler donne des valeurs qui paraissent justes et qui ne le sont pas.
L'inclinaison se lit sur l'accéléromètre, qui mesure la gravité et fournit donc une verticale absolue, insensible à la dérive. Avec une condition : seulement à l'arrêt. En mouvement, l'accélération propre du robot s'ajoute à la gravité et la lecture perd son sens.
Le quaternion garde son usage pour ce qui est relatif, une variation d'orientation entre deux instants proches. Ce qu'il ne peut pas fournir, c'est une inclinaison absolue tenable dans la durée.
12Ce que le ToF permet : la détection de vide
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.
La v13, celle qui est livrée avec l'outil, remplace la réaction unique par une réponse graduée. Au-delà de 300 mm, le robot esquive en continuant d'avancer, en braquant du côté le moins encombré : il compare l'encombrement cumulé à gauche et à droite, et réévalue à chaque cycle. En dessous de 300 mm, il pivote sur place. Il ne recule qu'en dessous de 200 mm, ou s'il est coincé, parce que le recul est aveugle : rien ne regarde derrière lui. C'est toute la raison de cette gradation. Elle expose aussi un service HTTP sur le port 8790 qui publie la grille, la décision et son motif, et accepte démarrer, arrêter et vitesse : c'est ce que l'onglet Déambulation affiche et commande, par un passe-plat du pont.
Deux itérations plus tard, la v15 corrige un défaut qui sautait aux yeux dès qu'on regardait le robot longtemps : à obstacle symétrique, il partait toujours du même côté. Ce biais à gauche est supprimé. Le recul déclenché par une détection de vide est désormais borné lui aussi, au lieu de courir jusqu'à ce qu'autre chose l'interrompe.
Ce que notre outil en a fait, maintenant que le capteur est coupé
L'onglet Déambulation n'a été ni retiré ni vidé. Il interroge le robot au chargement : si les seize canaux du télémètre reviennent invalides, il affiche un bandeau daté qui explique pourquoi, et désactive le bouton « Démarrer ». Le code de marche, lui, est intact. Il remarcherait tel quel.
Le mot juste est « suspendue », pas « supprimée ». C'est un choix éditorial autant que technique : on ne réécrit pas l'histoire d'une fonction qui a marché, et on ne fait pas disparaître des mesures parce qu'un firmware a changé d'avis.

13Sé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.
14Faire 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 la vitesse normalisée et le mode sol ou bureau : 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.
15Le format d'action, et ce qu'il dit des postures
Les animations du robot sont rangées dans des fichiers .avi, un conteneur détourné de son usage vidéo. Chaque fichier porte la trajectoire du corps, celle des pieds, et souvent une piste sonore.
« Appuis constants » signifie jambes rigides sous le corps, et un saut passe ce filtre sans difficulté. La sûreté d'une posture vient des bornes imposées au corps, pas des pieds. Un contrôle qui surveille les pieds laisse passer un saut en le prenant pour une station immobile.
Ce que contient le répertoire
- Le conteneur a trois formes et non une : 56 fichiers à quatre flux, 43 à trois, 4 à deux. Un lecteur qui suppose une forme unique échoue sur un tiers du répertoire.
- 63 actions sur 103 portent du son, en RTP G.711 A-law.
- Cette piste audio est à 16 kHz dans un type de charge qui en annonce 8. L'écart se déduit des horodatages, sans avoir besoin de l'oreille.
Le format complet, sa réécriture et la relecture sur machine sont documentés dans le dépôt du projet, avec les relevés qui les étayent.
16Gestes, vision et caméra
Détection de main : oui. Reconnaissance de geste : non.
Et le robot sait suivre la main, avec sa propre cinématique
Détecter n'est pas suivre. Or le nœud face_tracker, que l'on croyait dédié au visage, gère en réalité deux cibles : il bascule de l'une à l'autre par une commande interne follow_face ou follow_hand sur le topic /face_tracker/control. Le mode « tient » : un seul envoi suffit, le robot garde la consigne.
Le mouvement est alors calculé à bord, par la cinématique du robot. Il est fluide et sans latence, ce qu'aucun suivi piloté depuis le PC ne peut égaler : la boucle ne traverse pas le réseau.
Reste, pour mémoire, ce que le constructeur avait prévu côté gestes. Un modèle de reconnaissance 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 :
body(0),head(1),face(2) et, depuis la 2.5.5,hand(3). S'y ajoute le squelette, jusqu'à 19 points. Les objets « os, balle, peluche » du firmware sont des items virtuels du système d'émotions, pas des classes de vision. - Attention à la numérotation : le REST
/vision/facesnumérote le visageclass_id5, là où le WebSocket le numérote 2. Les deux sources ne comptent pas pareil. - À 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.


face_tracker tourne bel et bien, et il suit les deux cibles.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. La signalisation vidéo ne vit pas sur le canal principal : la chercher là est sans issue. - 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.

17Commander 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.
18Le volume, les LED, l'écran, et ce que les yeux acceptent
Trois réglages que la documentation constructeur ne mentionne pas, et une question qu'on nous pose souvent, tranchée par la négative avec sa preuve. Tout ce qui suit a été relevé sur la machine fin juillet 2026, firmware 2.5.0.
Le volume : un paramètre ROS, pas une commande dédiée
Le volume sonore est le paramètre ROS audio_volume, un entier de 0 à 100, porté par le nœud wmix_audio_player_node. On le règle par la commande WebSocket USER_SET_NODE_PARAMETER, avec pour charge utile node_name, parameter_name et parameter_value. La trame a été capturée sur l'interface officielle du constructeur, en écoutant le WebSocket 8765 pendant qu'on bougeait le curseur de volume.
{ "command": "USER_SET_NODE_PARAMETER",
"node_name": "wmix_audio_player_node",
"parameter_name": "audio_volume",
"parameter_value": 54 }Deux réserves. La lecture du volume n'est pas supportée : le GET symétrique est vraisemblablement USER_GET_NODE_PARAMETER, mais nous ne l'avons jamais capturé, et notre outil affiche donc un point d'interrogation à la place du niveau courant. Et sur l'interface officielle, changer le volume déclenche un aperçu sonore : le robot joue stand_default_littleBark_brief, se lève et aboie brièvement. Ce n'est pas un dysfonctionnement.
Les LED : uniquement par l'UDP
Le robot porte huit points lumineux colorables, deux à la tête et six sur le dos. Ils ne sont accessibles que par le canal UDP du port 8768, qui republie vers le topic /robot_led_controller/led_colors. Aucune autre voie connue : ni WebSocket, ni REST.
Ce décompte demande une précision, obtenue en poussant le pilotage plus loin : chacun des deux points de la tête est en réalité une oreille de six mini-LED disposées en cercle, adressables une par une, exactement comme les six LED du dos. Cela fait douze canaux à la tête et six au dos, soit dix-huit en tout, et non huit. La numérotation part du haut, 1 à midi, puis dans le sens horaire.

Ce canal UDP mérite qu'on s'y arrête, parce qu'il donne aussi un accès direct à la marche, à l'assiette du corps, à la tête et aux quatre pattes sans passer par le WebSocket. C'est la voie qu'emploie le script Blender du constructeur pour prévisualiser une animation en direct.
| Topic republié par le serveur UDP 8768 | Ce qu'il commande |
|---|---|
/gait_generation_trot/cmd_vel | La marche |
/kinematics/ik_subscriber/body_pose | L'assiette du corps |
/kinematics/ik_subscriber/head_quaternion | La tête |
/kinematics/ik_subscriber/…_point | Les quatre pattes, une par topic |
/robot_led_controller/led_colors | Les LED, seul accès connu |
/lvgl_layer | L'écran et les yeux, mais personne n'écoute (voir plus bas) |
/udp_server/status | L'état du serveur lui-même |
L'écran de la tête : par des services ROS
L'écran se pilote par des services ROS actifs sur la machine : /lvgl_gui_node/play_lottie et /play_gif pour les animations, /lvgl_gui/show_toast et /show_dialog pour les messages, /show_ip_address, et /camera_display/toggle. C'est ce que notre outil utilise pour afficher un texte ou rejouer une animation de la bibliothèque du robot.
On change l'expression des yeux, on ne les marionnettise pas
C'est la question qui revient le plus souvent, et la réponse sur ce point précis est non. Le serveur UDP comprend pourtant très bien les clés eye_iris, eye_upper et eye_lower : elles sont présentes dans son binaire, et il les republie consciencieusement sur le topic /lvgl_layer. Sauf que plus personne ne les écoute.
ros2 topic info /lvgl_layer
# Publisher count: 2
# Subscription count: 0Zéro abonné : lvgl_gui_node, qui dessine l'écran, ne figure pas parmi eux. Les paramètres hide_eye_layer des services d'écran confirment que la couche des yeux est gérée à l'intérieur de ce nœud. Et l'add-on Blender du constructeur montre où vivent réellement les yeux : leurs données sont embarquées dans les fichiers d'action eux-mêmes. L'écran est animé par le lecteur d'actions et le moteur d'émotion, pas par une commande venue de l'extérieur.
Le résultat tient maintenant sur trois canaux indépendants et deux firmwares : l'UDP 8768 sans abonné, la route POST /performance/ui qui répond 404 depuis le réseau comme en local sur la machine, et le SDK Python absent du robot. Recontrôlé après le passage en 2.5.5 : rien n'a changé.
L'autre porte : jouer un GIF ou un Lottie sur le visage
Le firmware a migré ses expressions vers le GIF — les notes de version 2.4.8 le disent : « Fully migrated to GIF emoji expressions ». Le rig de calques n'est plus consommé : la piste UI des fichiers d'action existe toujours, la route réseau qui la joue répond success: true… et il ne se passe rien. Aucun nœud d'écran ne journalise quoi que ce soit. C'est du code mort qui acquitte et qui jette.
Mais l'écran expose deux services ROS, play_gif et play_lottie, non documentés publiquement, qui acceptent un chemin absolu arbitraire. Et le constructeur l'a prévu explicitement : le commentaire de la signature dit « pour jouer un fichier temporaire comme /tmp/*.gif ». Ce n'est pas un détournement.
- Paramètres : position (−1 = centré), taille (0 = taille d'origine), boucle infinie, couleur et opacité de fond pour le Lottie, et un
hide_eye_layerqui masque le calque résiduel et allège le processeur. - Écran : 240 × 284 pixels. L'animation d'attente est rejouée en boucle dès qu'aucune animation ne tient le premier plan.
L'essai, réussi le 1er septembre 2026 : un GIF de 240 × 284 à 50 ms par image, fabriqué sur le PC, déposé dans /tmp du robot, joué en boucle. L'animation s'affiche sur le visage. Aucun moteur sollicité, aucun son.

/tmp, jouée en boucle par le service ROS.Notre outil en tire une nouvelle section « Visage — animations » dans l'onglet Yeux : liste des animations présentes sur le robot, boucle, masquage du calque, affichage et arrêt. Rien de tout cela n'existe dans l'application officielle.

Une piste reste ouverte, du côté de l'humeur cette fois : les services ROS /emotion_manager/set_emotion_state, /adjust_emotion et /adjust_satiety existent bel et bien sur la machine. La voie ROS pourrait rendre l'état émotionnel commandable, là où le WebSocket répond service_unavailable. Nous ne l'avons pas encore testée.
19Le robot n'a pas de mode veille
Allumé, un Sirius chauffe en permanence. Le firmware propose plusieurs postures allongées, mais aucune n'est un repos : envoyez lie_default_idle, la plus naturelle, et les quatorze moteurs continuent de travailler. Les charges vont de 10 à 172 ‰ selon les canaux, avec un pic à 307 ‰.
Dans cette posture, le robot tient ses deux pattes avant en l'air : ce n'est pas une position de repos, c'est une pose activement tenue. Le poids porte sur les épaules arrière, chaudes au toucher pendant que l'avant reste tiède. Une posture nommée « allongée » ne dit rien de l'effort qu'elle coûte.
Le levier, et ce que le kit en fait
Le service /device_modbus/set_motor_torque coupe le couple des quatorze moteurs. La carte Repos de l'onglet Vie du robot s'en sert : elle couche le robot, puis coupe le couple. La charge commandée tombe de 307 ‰ à 5 ‰.

- Éprouvez le réveil avant l'endormissement. Vérifiez que le robot se relève avant de le mettre au repos pour la première fois.
- Couchez le robot d'abord. Couper le couple d'un robot debout le fait s'effondrer.
- Coupez l'autonomie en premier. Sans cela, chaque animation d'attente renvoie le couple maximal, et la mise au repos part en boucle couché/debout.

Le détail de l'enquête, ses résultats négatifs compris, est publié dans Le Hengbot Sirius n'a pas de mode veille, et il ne sait pas vous dire ce qu'il consomme, disponible dans le dépôt du projet.
20Ce 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.
21Mettre à jour quand la mise à jour officielle échoue
Sur notre machine, le passage d'une version bêta à la suivante échouait systématiquement aux alentours de 70 %. Le journal du nœud de mise à jour donne la raison en une ligne : Download failed: Timeout was reached.
Le nœud de mise à jour du robot s'arrête au bout de 600 secondes. Le serveur de paquets du constructeur débitait environ 140 Ko/s vers le robot : à ce rythme, un paquet de 120 Mo ne peut pas finir dans le délai imparti. Ni le mot de passe du canal bêta ni la manipulation ne sont en cause. Le canal s'ouvre, le téléchargement démarre, il n'a simplement pas le temps d'aboutir. Trois essais, trois échecs au même point.
Le contournement : télécharger depuis le PC, appliquer par SSH
Un ordinateur n'a pas ce plafond de temps. Sur le nôtre, le même paquet est descendu en trois minutes trente, soit environ quatre fois plus vite que sur le robot. La méthode tient en trois temps.
- Télécharger le paquet sur le PC, depuis le serveur officiel du constructeur, avec la reprise activée pour survivre à une coupure. C'est le même fichier, à la même adresse, que celui que le robot va chercher lui-même : rien n'est fabriqué ni modifié.
- Vérifier l'archive avant de l'appliquer. Un simple test de lecture de l'archive suffit à écarter un téléchargement tronqué, et la taille doit correspondre à celle annoncée dans le journal de version. C'est l'étape qu'il ne faut pas sauter.
- Appliquer par SSH avec un outil de déploiement manuel, qui téléverse l'archive en local, la décompresse, lit son manifeste, arrête les services, pose les fichiers, écrit la nouvelle version, joue le script de post-installation et redémarre.
Le reste de la démarche ne dépend d'aucun outil particulier : un téléchargement, une vérification d'archive, un dépôt de fichiers par SSH.











