···468468469469470470471471-La méthode TRPO définit la mise à jour de $Q$ avec un $Q'$ qui maximise le _surrogate advantage_ @trpo-openai, sous une contrainte limitant l'écart entre $Q$ et $Q'$
472472-473473-474474-L'idée de la _TRPO_ est de maximiser le _surrogate advantage_ du nouveau $Q$ tout en limitant l'ampleur des modifications apportées à $Q$, ce qui procure une stabilité à l'algorithme, et évite qu'un seul "faux pas" dégrade violemment la performance de la politique.
471471+La méthode TRPO définit la mise à jour de $Q$ avec un $Q'$ qui maximise le _surrogate advantage_ @trpo-openai, sous une contrainte limitant l'ampleur des modifications individuelles, ce qui procure une stabilité à l'algorithme, et évite qu'un seul "faux pas" dégrade violemment la performance de la politique.
475472476473$
477474 Q' = & cases(
···494491495492496493497497-Pour évaluer cette distance, on regarde la plus grande des distances entre des paires de distributions de probabilité de politiques $Q_Pi$ et $Q_Pi'$ pour $s in S$ fixé @trpo
494494+Pour évaluer cette distance, on regarde la plus grande des distances entre des paires de distributions de probabilité de politiques $Q_Pi$ et $Q_Pi'$, pour tout $s in S$ @trpo
498495499496$
500497 max_(s in S) D_"KL" (Q_Pi' (s, dot) || Q_Pi (s, dot)) < delta
···536533537534#let ddot = [ #sym.dot #h(-1em / 16) #sym.dot ]
538535539539-En pratique, l'optimisation sous cette contrainte est trop demandeuse en puissance de calcul, on utilise plutôt l'espérance @trpo
536536+#dontbreak[
537537+538538+En pratique, l'optimisation sous cette contrainte est trop demandeuse en puissance de calcul, on utilise plutôt l'espérance @trpo.
540539541540$
542541 overline(D_"KL") := bb(E)_(s in S) D_"KL" (Q(s, dot) || Q'(s, dot))
543542$
544543544544+]
545545546546547547···663663664664]
665665666666-== CaT (_Constraints as Terminations_)
667667-668668-// L'algorithme de mise à jour est le suivant @ppo-openai:
669669-//
670670-// 1. Mise à jour de la politique:
671671-//
672672-// $
673673-// Pi' = argmax_p 1/T sum_(t=1)^T L(s, a, Pi, p, R)
674674-// $
675675-676666677667== Application en robotique
678668679669680680-Dans le contexte de la robotique, le calcul de l'état post-action de l'environnement est le travail du _moteur de physique_.
681681-682682-Bien évidemment, ce sont des programmes complexes avec des résolutions souvent numériques d'équation physiques; il est presque inévitable que des bugs se glissent dans ces programmes.
683683-684684-Un environnement de RL#footnote[Reinforcement Learning] ne se résume pas à son moteur de physique: il faut également charger des modèles 3D, le modèle du robot (qui doit être contrôlable par les actions, on fait donc une émulation de la partie logicielle du robot), et également, pendant les phases de développement, avoir un moteur de rendu graphique, une interface et des outils de développement.
685685-686686-Cet ensemble s'appelle un _simulateur système_.
687687-688688-689670=== Spécification de la tâche
690671691672Le score (récompense ou coût) dépend de la tâche pour laquelle on veut entraîner l'agent.
···700681701682702683=== Inventaire des simulateurs en robotique
684684+685685+686686+Dans le contexte de la robotique, le calcul de l'état post-action de l'environnement est le travail du _moteur de physique_.
687687+688688+Bien évidemment, ce sont des programmes complexes avec des résolutions souvent numériques d'équation physiques; il est presque inévitable que des bugs se glissent dans ces programmes.
689689+690690+691691+692692+693693+Un environnement de RL#footnote[Reinforcement Learning] ne se résume pas à son moteur de physique: il faut également charger des modèles 3D, le modèle du robot (qui doit être contrôlable par les actions, on fait donc une émulation de la partie logicielle du robot), et également, pendant les phases de développement, avoir un moteur de rendu graphique, une interface et des outils de développement.
694694+695695+Cet ensemble s'appelle un _simulateur système_.
703696704697==== Isaac
705698···726719/ Bullet Featherstone: Plugin `gz-physics-bullet-featherstone-plugin`, également en beta @gazebo-physics-engines. Une variable de Bullet, utilisant l'algorithme de Featherstone @bullet-featherstone @featherstone
727720728721729729-== Le robot _H1v2_ d'Unitree
730730-731731-_H1v2_ est un modèle de robot humanoïde créé par la société Unitree.
732732-733733-Il possède plus de 26 degrés de liberté, dont
734734-735735-- 6 dans chaque jambe (3 à la hanche, 2 au talon et un au genou),
736736-- 7 dans chaque bras (3 à l'épaule, 3 au poignet et un au coude) @h1v2
737737-738738-739722== Reproductibilité logicielle
740723741724La reproductibilité est particulièrement complexe dans le champ du reinforcement learning @rl-reproducibility.
···747730 scale(7%, reflow: true, diagraph.render(read("./isaac-deptree.dot"))),
748731)
749732750750-Bien que toutes ces dépendances puissent être spécifiées à des versions strictes @lockfiles pour éviter des changements imprévus de comportement du code venant des bibliothèques, beaucoup celles-ci ont besoin de compiler du code C++ à l'installation pour des raisons de performance @cpp-python.
751751-752752-Des problèmes de reproductibilité peuvent donc subsister à l'installation des dépendances, étant donné la dépendance du processus de compilation à la machine compilant le code.
733733+Bien que toutes ces dépendances puissent être spécifiées avec des contraintes de version strictes @lockfiles pour éviter des changements imprévus de comportement du code venant des bibliothèques, beaucoup celles-ci ont besoin de compiler du code C++ _à l'installation_#footnote[Pour des raisons de performance @cpp-python, certaines bibliothèques implémentent leurs fonctions critiques en C++. C'est par exemple le cas de NumPy #refneeded]: fixer la version de la bibliothèque ne suffit pas donc à guarantir la reproductibilité de la compilation de l'arbre des dépendances.
+7-7
rapport/gz-unitree.typ
···715715})
716716717717718718-Ici également, `LowStateWriter` s'exécute _en parallèle_ du code de `::PreUpdate`: En effet, la création du `ChannelPublisher` démarre une boucle qui vient éxécuter `LowStateWriter` périodiquement, dans un autre _thread_: on a donc aucune garantie de synchronisation entre les deux.
718718+Ici également, `LowStateWriter` s'exécute _en parallèle_ du code de `::PreUpdate`: En effet, la création du `ChannelPublisher` démarre une boucle qui vient exécuter `LowStateWriter` périodiquement, dans un autre _thread_: on a donc aucune garantie de synchronisation entre les deux.
719719720720Ici, il y a en plus non pas deux, mais _cinq_ boucles indépendantes qui sont en jeux:
721721···866866867867== Amélioration des performances <perf>
868868869869-Les premiers essais affichent un facteur temps-réel#footnote[Appelé RTF @rtf (Real-Time Factor). Un RTF de 100% signifie que la simulation s'éxécute à vitesse réelle, un RTF inférieur à 1 signifie que la simulation est plus lente que la vitesse simulée] autour des 10 à 15%.
869869+Les premiers essais affichent un facteur temps-réel#footnote[Appelé RTF @rtf (Real-Time Factor). Un RTF de 100% signifie que la simulation s'exécute à vitesse réelle, un RTF inférieur à 1 signifie que la simulation est plus lente que la vitesse simulée] autour des 10 à 15%.
870870871871#grid(
872872 columns: 2,
···929929Ainsi que d'autres optimisations, qui ne sont pas en rapport avec cette phase d'un cycle:
930930931931/ Mise en cache de joints à l'initialisation du plugin: pour éviter de devoir appeler `model.JointByName` dans une _hot loop_#footnote[Boucle (`for` ou `while`) dont le corps est exécuté un très grand nombre de fois, et dont la rapidité est importante].
932932-/ Utilisation d'une implémentation de CRC32 plus rapide: tentative avec _CRC++_ @crcpp non achevée, à cause d'un _stack smashing_ pendant l'éxécution
932932+/ Utilisation d'une implémentation de CRC32 plus rapide: tentative avec _CRC++_ @crcpp non achevée, à cause d'un _stack smashing_ pendant l'exécution
933933934934935935Après optimisations, on arrive à atteindre un RTF aux alentours des 30%. Des recherches supplémentaires sont nécéssaires pour atteindre un RTF raisonnable.
···980980981981Une fois l'enregistrement vidéo rendu automatisable, si l'on veut mettre en place le lancement automatique à chaque commit du dépôt git de la politique (i.e. chaque changement de la politique), il faut crééer une description de _workflow_ (dans notre cas, un workflow _Github Actions_).
982982983983-Un workflow est un ensemble de commandes à exécuter dans un environnement virtualisé (qu'il s'agisse d'une machine virtuelle ou d'un simple container), ainsi que des évènements et conditions décrivant quand lancer l'éxécution (par exemple, "à chaque commit sur la branche `main`"). C'est un des outils permettant de mettre en place la CI/CD.
983983+Un workflow est un ensemble de commandes à exécuter dans un environnement virtualisé (qu'il s'agisse d'une machine virtuelle ou d'un simple container), ainsi que des évènements et conditions décrivant quand lancer l'exécution (par exemple, "à chaque commit sur la branche `main`"). C'est un des outils permettant de mettre en place la CI/CD.
984984985985=== Une image de base avec Docker
986986987987-L'environnement d'éxécution des workflows ne comporte pas d'installation de Gazebo. Étant donné le temps de compilation élevé, on peut "factoriser" cette étape dans une _image de base_, de laquelle on démarre pour chaque éxécution du workflow, dans laquelle tout les programmes nécéssaires sont déjà installés.
987987+L'environnement d'exécution des workflows ne comporte pas d'installation de Gazebo. Étant donné le temps de compilation élevé, on peut "factoriser" cette étape dans une _image de base_, de laquelle on démarre pour chaque exécution du workflow, dans laquelle tout les programmes nécéssaires sont déjà installés.
988988989989Pour cela, on part d'une image Ubuntu, dans lequelle on installe le nécéssaire: Just (pour lancer des commandes, un sorte de Makefile mais plus moderne @just), FFMpeg (pour l'encodage H.264 servant à la création du fichier vidéo), XVFB (pour émuler un serveur X, cf @simulate-x), Python (pour lancer la politique RL), et Gazebo.
990990···10541054 [
1055105510561056 ==== Un environnement de développement contraignant
10571057- Développer et débugger une définition de workflow peut s'avérer complexe et particulièrement chronophage: n'ayant pas d'accès interactif au serveur éxécutant celui-ci, il faut envoyer ses changements au dépôt git, attendre que le workflow s'éxécute entièrement, et regardé si quelque chose s'est mal passé.
10571057+ Développer et débugger une définition de workflow peut s'avérer complexe et particulièrement chronophage: n'ayant pas d'accès interactif au serveur exécutant celui-ci, il faut envoyer ses changements au dépôt git, attendre que le workflow s'exécute entièrement, et regardé si quelque chose s'est mal passé.
1058105810591059 Par exemple, si jamais des fichiers sont manquants, ou ne sont pas au chemin attendu, il faut modifier le workflow pour y rajouter des instruction listant le contenu d'un répertoire (en utilisant `ls` ou `tree`, par exemple), lancer le workflow à nouveau et regarder les logs.
1060106010611061- Ceci rend le développement assez fastidieux, surtout quand le workflow s'éxécute pendant des dizaines de minutes.
10611061+ Ceci rend le développement assez fastidieux, surtout quand le workflow s'exécute pendant des dizaines de minutes.
1062106210631063 ==== Émuler un serveur graphique <simulate-x>
10641064
+28-26
rapport/nix.typ
···4455=== État dans le domaine de la programmation
6677-La différence entre une fonction au sens mathématique et une fonction au sens programmatique consiste en le fait que, par des raisons de practicité, on permet aux `function`s des langages de programmation d'avoir des _effets de bords_. Ces effets affectent, modifient ou font dépendre la fonction d'un environnement global qui n'est pas explicitement déclaré comme une entrée (un argument) de la fonction en question @purefunctions.
77+La différence entre une fonction au sens mathématique et une fonction au sens programmatique consiste en le fait que, par des raisons de practicité, on permet aux `function`s des langages de programmation d'avoir des _effets de bords_. Ces effets affectent, modifient ou font dépendre la fonction d'un environnement global qui n'est pas explicitement déclaré comme une entrée (argument) de la fonction en question @purefunctions.
8899Cette liberté permet, par exemple, d'avoir accès à la date et à l'heure courante, interagir avec un système de fichier d'un ordinateur, générer une surface pseudo aléatoire par bruit de Perlin, etc.
1010···2323 return date.today().year + a
2424```
25252626-Selon l'année dans laquelle nous sommes, $mono(f)(0)$ n'a pas la même valeur.
2626+Selon l'année dans laquelle nous sommes, `f(0)` n'a pas la même valeur.
27272828-De manière donc très concrète, si cette fonction `f` fait partie du protocole expérimental d'une expérience, cette expérience n'est plus reproductible, et ses résultats sont donc potentiellement non vérifiables, si le papier est soumis le 15 décembre 2025 et la _peer review_ effectuée le 2 janvier 2026.
2828+De manière donc très concrète, si cette fonction `f` fait partie d'un protocole expérimental, l'expérience n'est plus reproductible, et ses résultats sont donc potentiellement non vérifiables, si le papier est soumis le 15 décembre 2025 et la _peer review_ effectuée le 2 janvier 2026.
29293030=== Contenir les effets de bords
31313232-En dehors du besoin de vérifiabilité du monde de la recherche, la reproductibilité est une qualité recherchée dans certains domaines de programmation @reproducibility
3232+En dehors du besoin de vérifiabilité du monde de la recherche, la reproductibilité est une qualité recherchée dans certains domaines de programmation @reproducibility #todo[Lesquels?].
33333434-Il existe donc depuis longtemps des langages de programmation dits _fonctionnels_, qui, de manière plus ou moins stricte, limite les effets de bords. Certains langages font également la distinction entre une fonction _pure_#footnote[sans effets de bord] et une fonction classique @fortran-pure. Certaines fonctions, plutôt appelées _procédures_, sont uniquement composées d'effet de bord puisqu'elle ne renvoie pas de valeur @ibm-function-procedure-routine
3434+Il existe donc depuis longtemps #todo[préciser + #refneeded] des langages de programmation dits _fonctionnels_, qui, de manière plus ou moins stricte, limitent les effets de bords. Certains langages font également la distinction entre une fonction _pure_ (sans effets de bord) et une fonction classique @fortran-pure. Certaines fonctions, plutôt appelées _procédures_, sont uniquement composées d'effet de bord et ne renvoie pas de valeur @ibm-function-procedure-routine.
353536363737=== État dans le domaine de la robotique
···4343L'idée de s'affranchir d'effets de bords pour rendre les programmes dans la recherche en robotique reproductibles est donc plus utopique que réaliste.
444445454646-=== Environnements de développement
4646+=== Reproductibilité de la compilation
47474848-Cependant, ce qui fait un programme n'est pas seulement son code: surtout dans des langages plus anciens sans gestion de dépendance intégrée au langage, les dépendances (bibliothèques) du programme, ainsi que l'environnement et les étapes de compilation de ce dernier, représentent également une partie considérable de la complexité du programme (par exemple, en C++, on utilise un outil générant des fichiers de configuration pour un autre outil qui à son tour configure le compilateur de C++ @cmake)
4848+Cependant, ce qui fait un programme n'est pas seulement son code: surtout dans des langages plus anciens sans gestion de dépendance intégrée au langage, les dépendances (bibliothèques) du programme, ainsi que l'environnement et les étapes de compilation de ce dernier, représentent également une partie considérable de la complexité du programme (par exemple, en C++, on utilise un outil générant des fichiers de configuration pour un autre outil qui à son tour configure le compilateur de C++#footnote[Il est ici question de CMake, qui génère des Makefile configurant GCC] @cmake)
49495050C'est cette partie que Nix, le gestionnaire de paquet, permet d'encapsuler et de rendre reproductible. Dans ce modèle, la compilation (et de manière plus générale la construction, ou _build_) du projet est la fonction que l'on veut rendre pure. L'entrée est le code source, et le résultat de la fonction est un binaire, qui ne doit dépendre que du code source.
5151···5353 forall "src", "bin", forall f in "bin"^"src", forall (P_1, P_2) in "src"^2, P_1 = P_2 => f(P_1) = f(P_2)
5454$
55555656-Ici, $P_1$ et $P_2$ sont deux itérations du code source (src) du programme. Si le code source est identique, les binaires résultants de la compilation ($f$) sont égaux, au sens de l'égalité bit à bit.
5656+Ici, $P_1$ et $P_2$ sont deux itérations du code source (éléments de src) du programme. Si le code source est identique, les binaires résultants de la compilation ($f$) sont égaux, au sens de l'égalité bit à bit.
57575858-On a la proposition (1), avec $E = "src"$, l'ensemble des code source possibles pour un langage, et $F= "bin"$, l'ensemble des binaires éxécutables
5858+On a la proposition (1), avec $E = "src"$, l'ensemble des code source possibles pour un langage, et $F= "bin"$, l'ensemble des binaires exécutables
59596060Nix ne peut pas garantir que le programme sera sans effets de bords au _runtime_, mais vise à le garantir au _build-time_.
6161···63636464=== Un _DSL_#footnote[Domain-Specific Language] fonctionnel
65656666-Une autre caractéristique que l'on trouve souvent dans la famille de langages fonctionnels est l'omniprésence des _expressions_: quasi toute les constructions syntaxiques forment des expressions valides, et peuvent donc servir de valeur
6666+Une autre caractéristique que l'on trouve souvent dans la famille de langages fonctionnels est l'omniprésence des _expressions_: la quasi-totalité des constructions syntaxiques forment des expressions valides, et peuvent donc servir de valeur
6767+6868+#todo[améliorer exemple, ya des ternaires dans tt les langages...]
67696870#table(
6971 columns: (50%, 50%),
···101103 ```,
102104)
103105104104-Voici un exemple de définition d'un programme, appelée _dérivation_ dans le jargon de Nix:
106106+Voici un exemple de définition d'un paquet Nix, appelée _dérivation_ dans le jargon du langage:
105107106108107109```nix
···146148}
147149```
148150149149-La dérivation ici prend en entrée le code source (`src-odri-masterboard-sdk`), ainsi que des dépendances, que ce soit des fonctions relatives à Nix même (comme `stdenv.mkDerivation`) pour simplifier la définition de dérivation, ou des dépendances au programmes, que ce soit pour sa compilation ou pour son exécution (dans ce dernier cas de figures, les dépendances sont inclues ou reliées au binaire final)
151151+La dérivation prend ici en entrée le code source (`src-odri-masterboard-sdk`), ainsi que des dépendances, que ce soit des fonctions relatives à Nix même (comme `stdenv.mkDerivation`) pour simplifier la définition de dérivation, ou des dépendances du programme, qu'elles servent à la compilation ou à son exécution (dans ce dernier cas de figure, les dépendances sont inclues ou dynamiquement liées dans le binaire final)
150152151153=== Un ecosystème de dépendances
152154153153-Afin de conserver la reproductibilité même lorsque l'on dépend de libraries tierces, ces dépendances doivent également avoir une compilation reproductible: on déclare donc des dépendances à des _packages_ Nix, disponibles sur _Nixpkgs_ @nixpkgs.
155155+Afin de conserver la reproductibilité même lorsque l'on dépend de libraries tierces, ces dépendances doivent également avoir une compilation reproductible: on déclare donc des dépendances à des paquets Nix, disponibles sur un registre centralisé, _Nixpkgs_ @nixpkgs.
154156155155-Parfois donc, écrire un paquet Nix pour son logiciel demande aussi d'écrire les paquets Nix pour les dépendances de notre projet, si celles-ci n'existent pas encore, et cela récursivement. On peut ensuite soumettre nos paquets afin que d'autres puissent en dépendre sans les réécrire, en contribuant à _Nixpkgs_ @nixpkgs-contributing
157157+Ainsi, écrire un paquet Nix pour son logiciel demande parfois d'écrire des paquets Nix pour les dépendances de notre projet, si celles-ci n'existent pas encore, et cela récursivement. On peut ensuite soumettre ces autres paquets à Nixpkgs @nixpkgs-contributing afin que d'autres puissent en dépendre sans les réécrire.
156158157157-Pour ne pas avoir à compiler toutes les dépendances soit-même quand on dépend de `.nix` de _nixpkgs_, il existe un serveur de cache, qui propose des binaires des dépendances, Cachix @cachix
159159+Pour ne pas avoir à compiler toutes les dépendances soi-même quand on dépend de paquets sur _Nixpkgs_, il existe un serveur de cache, qui propose des binaires des dépendances, Cachix @cachix
158160159161=== Une compilation dans un environnement fixé
160162161161-Certains aspects de l'environnement dans lequel l'on compile un programme peuvent faire varier le résultat final. Pour éviter cela, Nix limite au maximum les variations d'environnement. Par exemple, la date du système est fixée au 0 UNIX (1er janvier 1990): le programme compilé ne peut pas dépendre de la date à laquelle il a été compilé.
163163+Certains aspects de l'environnement dans lequel l'on compile un programme peuvent faire varier le résultat final. Pour éviter cela, Nix limite au maximum les variations d'environnement. Par exemple, la date du système est fixée au 0 UNIX (1er janvier 1990) pendant la compilation#footnote[La date système n'est pas modifiée par Nix, mais il expose une date zéro au processus compilant le logiciel]: le programme compilé ne peut pas dépendre de la date à laquelle il a été compilé.
162164163163-Quand le _sandboxing_ est activé, Nix isole également le code source de tout accès au réseau, aux autres fichiers du système (ainsi que d'autres mesures) pour améliorer la reproductibilité @nix-sandboxing
165165+Quand le _sandboxing_ est activé, Nix isole également le code source de tout accès au réseau, aux autres fichiers du système, ainsi que d'autres mesures, pour améliorer la reproductibilité @nix-sandboxing
164166165165-==== Un complément utile: compiler en CI
167167+==== Un complément utile: compiler en _CI_
166168167167-Pour aller plus loin, on peut lancer la compilation du paquet Nix en _CI_#footnote[Continuous Integration, lit. intégration continue], c'est-à-dire sur un serveur distant au lieu de sur sa propre machine. On s'assure donc que l'état de notre machine de développement personnelle n'influe pas sur la compilation, puisque chaque compilation est lancée dans une machine virtuelle vierge @github-runners.
169169+Pour aller plus loin, on peut lancer la compilation du paquet Nix en _CI_#footnote[Continuous Integration, lit. intégration continue], c'est-à-dire sur un serveur distant, au lieu de compiler sur sa propre machine. On s'assure donc que l'état de notre machine de développement personnelle n'influe pas sur la compilation, puisque chaque compilation est lancée dans une machine virtuelle vierge @github-runners.
168170169171== NixOS, un système d'exploitation à configuration déclarative
170172171171-Une fois le programme compilé avec ses dépendances, il est prêt à être transféré sur l'ordinateur ou la carte de contrôle embarquée au robot.
173173+Une fois le programme compilé avec ses dépendances, il est prêt à être transféré à l'ordinateur ou la carte de contrôle embarquée sur le robot.
172174173175Lorsqu'il y a un ordinateur embarqué, comme par exemple une Raspberry Pi @raspi, il faut choisir un OS sur lequel faire tourner le programme.
174176175175-Là encore, un OS s'accompagne d'un amas considérable de configuration des différentes parties du système: accès au réseau, drivers,…
177177+Là encore, un OS s'accompagne d'un amas considérable de configuration des différentes parties du système: accès au réseau, drivers, etc.
176178177177-Sur les OS Linux classiques tels que Ubuntu ou Debian, cette configuration est parfois stockée dans des fichiers, ou parfois retenue en mémoire, modifiée par l'éxécution de commandes.
179179+Sur les distributions Linux classiques tels que Ubuntu ou Debian, cette configuration est parfois stockée dans des fichiers, ou parfois retenue en mémoire, modifiée par l'exécution de commandes.
178180179179-C'est un problème assez récurrent dans Linux de manière générale: d'un coup, le son ne marche plus, on passe ½h sur un forum à copier-coller des commandes dans un terminal, et le problème est réglé… jusqu'à ce qu'il survienne à nouveau après un redémarrage ou une réinstallation.
181181+C'est un problème assez récurrent avec Linux de manière générale: d'un coup, le son ne marche plus, on passe ½h sur un forum à copier-coller des commandes dans un terminal, et le problème est réglé… jusqu'à ce qu'il survienne à nouveau après un redémarrage ou une réinstallation.
180182181181-Ici, NixOS assure que toute modification de la configuration d'un système est _déclarée_ (d'où l'adjectif "déclaratif") dans des fichiers de configurations, également écrits dans des fichiers `.nix` @nixos-impatient.
183183+Ici, NixOS assure que toute modification de l'état du système est _déclarée_ (d'où l'adjectif "déclaratif") dans des fichiers de configurations, également écrits dans des fichiers `.nix` @nixos-impatient.
182184183185Ici encore, cela apporte un gain en terme de reproductibilité: l'état de configuration de l'OS sur lequel est déployé le programme du robot est, lui aussi, rendu reproductible.
184186185187== Packaging Nix pour _gz-unitree_
186188187187-Le packaging pour Nix de gz-unitree lui-même n'est pas très complexe: il s'agit d'un projet C++ / CMake standard.
189189+Le packaging pour Nix de _gz-unitree_ lui-même n'est pas très complexe: il s'agit d'un projet C++ / CMake standard.
188190189189-Cependant, gz-unitree a deux principales dépendances
191191+Cependant, _gz-unitree_ a deux principales dépendances
190192191193- Gazebo lui-même, à travers `gz-sim`, `gz-sensors`, `gz-common`, `gz-plugin`, `gz-cmake`, etc.
192194- Le SDK2 d'Unitree
+10-1
rapport/sdk2-study.typ
···2233#show figure: set block(spacing: 3em)
4455-Unitree met à disposition du public un _SDK_#footnote[Kit de développement logiciel (Software Development Kit)] permettant de contrôler ses robots (dont le H1v2).
55+== Le robot _H1v2_ d'Unitree
66+77+Le _H1v2_ est un modèle de robot humanoïde créé par la société Unitree.
88+99+Il possède plus de 26 degrés de liberté, dont
1010+1111+- 6 dans chaque jambe (3 à la hanche, 2 au talon et un au genou),
1212+- 7 dans chaque bras (3 à l'épaule, 3 au poignet et un au coude) @h1v2
1313+1414+Unitree met à disposition du public un _SDK_#footnote[Kit de développement logiciel (Software Development Kit)] permettant de le contrôler.
615716== Canaux DDS
817