this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Continue rapport

+74 -15
+1 -1
pages_count
··· 1 - 41 1 + 42
+73 -14
rapport/gz-unitree.typ
··· 228 228 229 229 En pratique, on utilise `std::bind` @cpp-bind pour fixer l'instance d'`UnitreePlugin` et ainsi passer des méthodes de la classe comme des simples fonctions 230 230 231 - #figure( 231 + #grid( 232 + columns: 2, 233 + gutter: 1em, 234 + figure( 232 235 caption: [Création d'un _subscriber_ à `rt/lowcmd` dans `UnitreePlugin::Configure`], 233 - ```cpp 236 + text(size: 0.8em, ```cpp 234 237 auto subscriber = ChannelSubscriberPtr<LowCmd_>( 235 238 new ChannelSubscriber<LowCmd_>("rt/lowcmd") 236 239 ); ··· 242 245 ) 243 246 244 247 subscriber->InitChannel(handler, 1); 245 - ``` 246 - ) 247 248 248 - == Réception des commandes <receive-lowcmd> 249 + . 250 + ```) 251 + ), 249 252 250 - Lorsqu'un message, publié par $cal(P)$ (1A) et contenant des ordres pour les moteurs, arrive sur `rt/lowcmd`, `::CmdHandler` est appelé (2, 3), et modifie un _buffer_ (4) contenant la dernière commande reçue. 253 + figure( 254 + caption: [Création du _publisher_ pour `rt/lowstate` dans `UnitreePlugin::Configure`], 255 + text(size: 0.8em, ```cpp 256 + auto publisher = ChannelPublisherPtr<LowState_>( 257 + new ChannelPublisher<LowState_>("rt/lowstate") 258 + ); 251 259 260 + publisher->InitChannel(); 252 261 253 - Ensuite, Gazebo démarre un nouveau pas de simulation. Avant de faire ce pas, il appelle la méthode `::PreUpdate` sur notre plugin, qui vient chercher la commande stockée dans le _buffer_ (1B), et applique cette commande sur le modèle du robot, animé par le simulateur. 262 + this->publisher_thread = CreateRecurrentThreadEx( 263 + "low_state_writer", 264 + UT_CPU_ID_NONE, 265 + 500, 266 + &UnitreePlugin::LowStateWriter, 267 + this 268 + ); 269 + ```) 270 + ) 271 + ) 254 272 255 - Pour appliquer la commande, on calcule la force effective que le moteur doit appliquer: 273 + == `rt/lowcmd` 274 + 275 + === Calcul des nouvelles forces des moteurs 276 + 277 + Pour appliquer une commande à un moteur, on calcule la force effective que le moteur doit appliquer: 256 278 257 279 $ 258 280 tau = ··· 305 327 joint.SetForce(ecm, torque); 306 328 ``` 307 329 330 + === Réception des commandes <receive-lowcmd> 331 + 332 + Lorsqu'un message, publié par $cal(P)$ (1A) et contenant des ordres pour les moteurs, arrive sur `rt/lowcmd`, `::CmdHandler` est appelé (2, 3), et modifie un _buffer_ (4) contenant la dernière commande reçue. 333 + 334 + 335 + Ensuite, Gazebo démarre un nouveau pas de simulation. Avant de faire ce pas, il appelle la méthode `::PreUpdate` sur notre plugin, qui vient chercher la commande stockée dans le _buffer_ (1B), et applique cette commande sur le modèle du robot, animé par le simulateur. 336 + 337 + 308 338 #architecture([Phase de réception des commandes], { 309 339 edge(<policy>, (2, -1), (2, 0), "-->", label-pos: 10%)[(1A) publish] 310 340 edge(<policy>, (2, -1), (2, 0), stroke: none, label-pos: 60%, label-side: left)[(1A) subscription] ··· 383 413 // ] 384 414 385 415 386 - == Émission de l'état <send-lowstate> 416 + == `rt/lowstate` 417 + 418 + === Construction d'un message `rt/lowstate` 419 + 420 + La documentation d'Unitree liste l'ensemble des champs disponibles dans un message `rt/lowstate`, c'est-à-dire l'ensemble des données que l'on doit récupérer afin de construire nos messages d'état @h1-rt-lowstate: 421 + 422 + #table( 423 + columns: (1.5fr, 0.5fr, 3fr, 2fr), 424 + stroke: none, 425 + inset: 8pt, 426 + 427 + "Champ", "Type", "Description", "Où récupérer la valeur", 428 + table.hline(), 429 + 430 + `version`, $NN^2$, [Tuple représentation la version d'Unitree], [], 431 + `mode_pr`, ${0, 1}$, [Défini sur 0 par défaut], [], 432 + `mode_machine`, ${4, 6}$, [Défini sur 6 par défaut], [], 433 + `tick`, $NN$, [Non documenté], [], 434 + `wireless_remote`, ${0, 1}^(40)$, [Non documenté], [], 435 + `reserve`, $NN^4$, [Non documenté], [], 436 + `crc`, $NN$, [Somme de contrôle du message, utilisant _CRC32_. Une implémentation ad-hoc existe dans le code source de `unitree_sdk2` et de `unitree_mujoco` #todo[Mettre en annexe ?]], [Copié-collé de l'implémentation d'Unitree], 437 + `imu_state`, `IMUState`, [Valeurs des capteurs intertiels du robot], 438 + `imu_state.quaternion`, $RR^4$, [Posture dans l'espace du robot, dans l'ordre $(w, x, y, z)$], 439 + `imu_state.rpy`, $RR^3$, [Angle d'Euler du robot, dans l'ordre $(r, p, y)$], 440 + `imu_state.gyroscope`, $$ 441 + ) 442 + 443 + 444 + === Émission de l'état <send-lowstate> 387 445 388 446 Avant de démarrer un nouveau pas de simulation, la méthode `::PreUpdate` vient mettre à jour l'état du robot simulé en modifiant le _State buffer_ interne au plugin (1A). 389 447 390 - Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $cal(P)$ (4), qui (on le suppose) poss-de une subscription sur `rt/lowstate` 448 + Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $cal(P)$ (4), qui (on le suppose) possède une subscription sur `rt/lowstate` 449 + 391 450 392 451 #let transparent = luma(0).opacify(0%) 393 - 394 452 395 453 #architecture([Phase d'envoi de l'état], { 396 454 edge(<preupdate>, "d,d,r", <statebuf>, "->")[(1A)] ··· 418 476 ]) $cal(P)$ sera moins grande 419 477 / Si `::PreUpdate` est moins fréquente: $cal(P)$ reçevra plusieurs fois le même état, ce qui sera représentatif du fait que la simulation n'a pas encore avancé. 420 478 479 + 421 480 == Désynchronisations 422 481 423 482 Dans un même appel de `::PreUpdate`, on effectue d'abord la mise à jour du _State buffer_, puis on lit dans le _Commands buffer_. ··· 426 485 427 486 - Celle de la simulation (en bleu), qui doit englober l'entièreté d'un cycle 428 487 - Celle du `ChannelPublisher` (en rouge) 429 - - Celle de $cal(P)$ (en rose) 488 + - Celle de $cal(P)$ (en vert) 430 489 431 490 #architecture([Cycle complet. Un cycle commence avec la flèche "update" partant de `::PreUpdate`], { 432 491 let colored-edge = (color, label, ..args) => edge(stroke: color, label: text(fill: color, label), ..args) 433 492 let sim-edge = (label, ..args) => colored-edge(blue, label, ..args) 434 493 let publisher-edge = (label, ..args) => colored-edge(red, label, ..args) 435 - let policy-edge = (label, ..args) => colored-edge(fuchsia, label, ..args) 494 + let policy-edge = (label, ..args) => colored-edge(olive.darken(30%), label, ..args) 436 495 437 496 // Simulation loop 438 497 sim-edge("read", <preupdate>, "d,d,r,r", <cmdbuf>, "<-@") ··· 463 522 464 523 == Amélioration des performances <perf> 465 524 466 - Les premiers essais montrent un 525 + Les premiers essais affichent un 467 526 468 527 == Enregistrement de vidéos <video> 469 528