···11+#import "@preview/arkheion:0.1.0": arkheion, arkheion-appendices
22+33+#let citneeded = super([[réf. nécéssaire]])
44+55+#show: arkheion.with(
66+ title: "Étude bibliographique I",
77+ authors: (
88+ (name: "Gwenn Le Bihan", email: "gwenn.lebihan@etu.inp-n7.fr", affiliation: "ENSEEIHT"),
99+ ),
1010+ date: "2 Septembre 2025",
1111+ abstract: [Ce stage porte sur l'intégration de Nix et NixOS dans les processus de développement et de déploiement logiciel dans le domaine robotique au sein du LAAS. Nix, le _package manager_, et NixOS, l'OS, sont des technologies permettant une reproductibilité, une qualité importante dans le monde de la recherche]
1212+)
1313+1414+#outline(
1515+ title: [Table des matières]
1616+)
1717+1818+= Reproductibilité
1919+2020+== État dans le domaine de la programmation
2121+2222+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.
2323+2424+Cette 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.
2525+2626+Mais, en contrepartie, on perd une équation qui est fondamentale en mathématiques:
2727+2828+$
2929+forall E, F, forall f: E->F, forall (e_1, e_2) in E^2, e_1 = e_2 => f(e_1) = f(e_2)
3030+$
3131+3232+En programmation, on peut très facilement construire un $f$ qui ne vérifie pas ceci:
3333+3434+```python
3535+from datetime import date
3636+3737+def f(a):
3838+ return date.today().year + a
3939+```
4040+4141+Selon l'année dans laquelle nous sommes, $mono(f)(0)$ n'a pas la même valeur.
4242+4343+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.
4444+4545+== Contenir les effets de bords
4646+4747+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
4848+4949+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
5050+5151+5252+== État dans le domaine de la robotique
5353+5454+En robotique, pour donner des ordres au matériel, on intéragit beaucoup avec le monde extérieur (ordres et lecture d'état de servo-moteurs, flux vidéo d'une caméra, etc), souvent dans un langage plutôt bas-niveau, pour des questions de performance et de proximité abstractionnelle au matériel
5555+5656+De fait, les langages employés sont communément C, C++ ou Python#footnote[Il arrive assez communément d'utiliser Python, un langage haut-niveau, mais c'est dans ce cas à but de prototypage, et le code contrôlant les moteurs est écrit dans un langage bas niveau plus appelé par Python par FFI] @programming-languages-robotics, des langages bien plus impératifs que fonctionnels @imperative-languages.
5757+5858+L'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.
5959+6060+6161+== Environnements de développement
6262+6363+Cependant, ce qui fait un programme n'est pas seulement son code: surtout dans des langages plus anciens sans gestion de dépendance simple, 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.
6464+6565+C'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.
6666+6767+$
6868+ 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)
6969+$
7070+7171+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.
7272+7373+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
7474+7575+Nix ne peut pas garantir que le programme sera sans effets de bords au _runtime_, mais vise à le garantir au _build-time_.
7676+7777+= Nix, le gestionnaire de paquets pur
7878+7979+== Un _DSL_#footnote[Domain-Specific Language] fonctionnel
8080+8181+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
8282+8383+#table(
8484+ columns: (50%, 50%),
8585+ ```python
8686+ def g(x, y):
8787+ if y == 5:
8888+ x = 6
8989+ else:
9090+ x = 8
9191+ return f(x)
9292+ ```,
9393+ ```ocaml
9494+ let g x y = f (
9595+ if y = 5 then
9696+ 6
9797+ else
9898+ 8
9999+ )
100100+ ```,
101101+ [ *Python* (`if` et `else` sont des instructions) ], [ *OCaml* (`if` et `else` forment une expression) ]
102102+)
103103+104104+Afin de décrire les dépendances d'un programme, l'environnement de compilation, et les étapes pour le compiler (en somme, afin de définir le $f in "bin"^"src"$), Nix comprend un langage d'expressions @nix-language. Un fichier `.nix` définit une fonction, que Nix sait exécuter pour compiler le code source.
105105+106106+#table(
107107+ columns: (50%, 50%),
108108+ table.header([Expression d'une fonction en Python], [En Nix]),
109109+ ```python
110110+ lambda f(a): a + 3
111111+ ```,
112112+ ```nix
113113+ { a }: a + 3
114114+ ```
115115+)
116116+117117+Voici un exemple de définition d'un programme, appelée _dérivation_ dans le jargon de Nix:
118118+119119+120120+```nix
121121+{
122122+ src-odri-masterboard-sdk,
123123+124124+ lib,
125125+ stdenv,
126126+ jrl-cmakemodules,
127127+ cmake,
128128+ python3Packages,
129129+ catch2_3,
130130+}:
131131+132132+stdenv.mkDerivation {
133133+ pname = "odri_master_board_sdk";
134134+ version = "1.0.7";
135135+136136+ src = src-odri-masterboard-sdk;
137137+138138+ preConfigure = ''
139139+ cd sdk/master_board_sdk
140140+ '';
141141+142142+ doCheck = true;
143143+144144+ cmakeFlags = [
145145+ (lib.cmakeBool "BUILD_PYTHON_INTERFACE" stdenv.hostPlatform.isLinux)
146146+ ];
147147+148148+ nativeBuildInputs = [
149149+ jrl-cmakemodules
150150+ python3Packages.python
151151+ cmake
152152+ ];
153153+154154+ buildInputs = with python3Packages; [ numpy ];
155155+156156+ nativeCheckInputs = [ catch2_3 ];
157157+158158+ propagatedBuildInputs = with python3Packages; [ boost ];
159159+}
160160+```
161161+162162+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)
163163+164164+== Un ecosystème de dépendances
165165+166166+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.
167167+168168+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
169169+170170+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
171171+172172+== Une compilation dans un environnement fixé
173173+174174+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é.
175175+176176+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
177177+178178+=== Un complément utile: compiler en CI
179179+180180+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.
181181+182182+= NixOS, un système d'exploitation à configuration déclarative
183183+184184+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.
185185+186186+Lorsqu'il y a un ordinateur embarqué, comme par exemple une Raspberry Pi @raspi, il faut choisir un OS sur lequel faire tourner le programme.
187187+188188+La 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,…
189189+190190+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'execution de commandes.
191191+192192+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.
193193+194194+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 écrit dans des fichiers `.nix`.
195195+196196+Ici 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.
197197+198198+199199+200200+201201+#bibliography("bib.yaml")
-11
biblio.typst
···11-= E'tude bibliographique
22-33-== Introduction
44-55-Mon stage porte sur l'intégration de Nix @nix et NixOS @nixos dans le processus du développement et déploiement des politiques de contrôle de robots du laboratoire du LAAS-CNRS, au sein de l'équipe Gepetto.
66-77-J'ai assez vite été chargée d'une autre mission s'incluant dans l'amélioration du processus de développement, qui consiste en la création d'un plugin Gazebo @gazebo. Ce plugin permet au SDK de Unitree @unitree_sdk2, le SDK des robots de la companie, d'envoyer des ordres à Gazebo, un logiciel de simulation.
88-99-Le but est d'en suite faire tourner de tests en simulateur
1010-1111-#bibliography("bib.yaml")
-27
july.typst
···11-=== 30 Juin - 4 Juillet
22-33-- Continuation du travail: essais pour rajouter un capteur IMU sur le robot, essais pour faire fonctionner l'auto-collision
44-55-=== 7-11 Juillet
66-77-- Capteur IMU rajouté
88-- Ajout du tick (temps) de simulation
99-- Essais d'utilisation de gz-unitree avec les politiques RL#footnote[Reinforcement Learning] de Gepetto
1010-1111-=== 14-18 Juillet
1212-1313-- Tentatives d'amélioration des performances pour améliorer le RTF: passage de 10% à 15%
1414- - Parallélisation de l'envoi des messages des DDS dans un thread différent du principal
1515- - Optimisations classiques
1616-1717-- Ecriture d'une recette _Just_ @justfile pour configurer l'environnement de développement, sur Arch Linux ou Ubuntu
1818-- Reproduction des résultats sur un OS et une machine différente
1919-2020-=== 21-25 Juillet
2121-2222-- Évaluation de `gazebo-sim-overlay` @gazebo-sim-overlay comme solution pour un packaging Nix
2323-- Recherche sur un mode headless de gazebo suite à des erreurs de QT sous devshell Nix
2424-2525-=== 28 Juillet - 1 août
2626-2727-- Recherche autour de l'utilisation de Gazebo dans des environnements CI/CD @msr2022-cps, en particulier pour capturer une simulation en vidéo
-24
june.typst
···11-=== 2-6 Juin
22-33-- Début de recherches sur l'installation de NixOS sur Raspberry Pi @raspi 400 et 5
44-- Flash du firmware master-board sur un testbench
55-- Test du packaging de odri_control_interface @odri-controls avec les scripts de démos à l'aide d'un testbench
66-- Début de recherches sur la création d'un plugin Gazebo @gazebo communiquant avec la couche bas niveau du SDK2 @unitree_sdk2 d'Unitree afin de simuler du code pour le robot H1 @h1 dans Gazebo
77-88-=== 9-13 Juin
99-1010-- Progrès sur l'accès à la couche bas niveau du SDK2 @unitree_sdk2
1111- - Analyse via Wireshark des paquets
1212- - Analyse du code source du plugin Mujoco @mujoco fourni par Unitree
1313-1414-=== 16-20 Juin
1515-1616-- Réussite de l'accès à la couche bas niveau du SDK2 via les définitions IDL @omgidl fournies par Unitree
1717-- Documentation sur le système de plugins de Gazebo @gazebo
1818-- Début de travail sur le bridge Gazebo/unitree: `gz-unitree`
1919- - Implémentation de la communication DDS @dds entre un binaire d'exemple d'utilisation du SDK2 et le plugin Gazebo
2020-2121-=== 23-27 Juin
2222-2323-- Construction du _lowstate_ à envoyer au SDK2 depuis _gz-unitree_:
2424-- Utilisation du modèle SDF @sdf du robot H1-2 @h1v2 au lieu de H1 @h1, ajout d'un sol au monde du SDF
+9
log.typ
···11+= Stage au LAAS
22+33+== Journal de bord
44+55+#for month in ("may", "june", "july", "august", "september", "november") {
66+ include("log/" + month + ".typ")
77+}
88+99+#bibliography("bib.yaml")
+27
log/july.typ
···11+=== 30 Juin - 4 Juillet
22+33+- Continuation du travail: essais pour rajouter un capteur IMU sur le robot, essais pour faire fonctionner l'auto-collision
44+55+=== 7-11 Juillet
66+77+- Capteur IMU rajouté
88+- Ajout du tick (temps) de simulation
99+- Essais d'utilisation de gz-unitree avec les politiques RL#footnote[Reinforcement Learning] de Gepetto
1010+1111+=== 14-18 Juillet
1212+1313+- Tentatives d'amélioration des performances pour améliorer le RTF: passage de 10% à 15%
1414+ - Parallélisation de l'envoi des messages des DDS dans un thread différent du principal
1515+ - Optimisations classiques
1616+1717+- Ecriture d'une recette _Just_ @justfile pour configurer l'environnement de développement, sur Arch Linux ou Ubuntu
1818+- Reproduction des résultats sur un OS et une machine différente
1919+2020+=== 21-25 Juillet
2121+2222+- Évaluation de `gazebo-sim-overlay` @gazebo-sim-overlay comme solution pour un packaging Nix
2323+- Recherche sur un mode headless de gazebo suite à des erreurs de QT sous devshell Nix
2424+2525+=== 28 Juillet - 1 août
2626+2727+- Recherche autour de l'utilisation de Gazebo dans des environnements CI/CD @msr2022-cps, en particulier pour capturer une simulation en vidéo
+24
log/june.typ
···11+=== 2-6 Juin
22+33+- Début de recherches sur l'installation de NixOS sur Raspberry Pi @raspi 400 et 5
44+- Flash du firmware master-board sur un testbench
55+- Test du packaging de odri_control_interface @odri-controls avec les scripts de démos à l'aide d'un testbench
66+- Début de recherches sur la création d'un plugin Gazebo @gazebo communiquant avec la couche bas niveau du SDK2 @unitree_sdk2 d'Unitree afin de simuler du code pour le robot H1 @h1 dans Gazebo
77+88+=== 9-13 Juin
99+1010+- Progrès sur l'accès à la couche bas niveau du SDK2 @unitree_sdk2
1111+ - Analyse via Wireshark des paquets
1212+ - Analyse du code source du plugin Mujoco @mujoco fourni par Unitree
1313+1414+=== 16-20 Juin
1515+1616+- Réussite de l'accès à la couche bas niveau du SDK2 via les définitions IDL @omgidl fournies par Unitree
1717+- Documentation sur le système de plugins de Gazebo @gazebo
1818+- Début de travail sur le bridge Gazebo/unitree: `gz-unitree`
1919+ - Implémentation de la communication DDS @dds entre un binaire d'exemple d'utilisation du SDK2 et le plugin Gazebo
2020+2121+=== 23-27 Juin
2222+2323+- Construction du _lowstate_ à envoyer au SDK2 depuis _gz-unitree_:
2424+- Utilisation du modèle SDF @sdf du robot H1-2 @h1v2 au lieu de H1 @h1, ajout d'un sol au monde du SDF
+20
log/may.typ
···11+=== 19-23 Mai
22+33+- Mise en place de l'environnement de développement
44+- Documentation sur Nix le langage @nix-language
55+- Découverte de la description d'une dérivation @nix-derivation et d'un flake
66+- Découverte de l'infrastructure autour de nixpkgs (github, la CI, Hydra @hydra...)
77+- Packaging en flake et CI basique (`nix build`) de `open-dynamic-robot-initiative/{interface_controls,master-board}` @odri-controls, @odri-masterboard
88+- Début du travail de packaging de `open-dynamic-robot-initiative/robot_properties_solo`
99+- Migration de `robot_properties_solo` vers uv @uv
1010+- Début du packaging de `xacro` sur NixOS/nixpkgs @nixpkgs-xacro
1111+- Création d'un JSON Schema @json-schema pour des fichiers de configuration de `robot_properties_solo` et mise en place d'une CI pour les valider @odri-properties-solo
1212+- Recherche autour d'une potentielle validation au runtime en C++ des fichiers de config par le JSON Schema
1313+- Découverte des overlays Nix
1414+1515+=== 26-28 Mai
1616+1717+- Continuation du travail précédent
1818+1919+2020+
main.pdf
This is a binary file and will not be displayed.
-9
main.typst
···11-= Stage au LAAS
22-33-== Journal de bord
44-55-#for month in ("may", "june", "july", "august", "september", "november") {
66- include(month + ".typst")
77-}
88-99-#bibliography("bib.yaml")
-20
may.typst
···11-=== 19-23 Mai
22-33-- Mise en place de l'environnement de développement
44-- Documentation sur Nix le langage @nix-language
55-- Découverte de la description d'une dérivation @nix-derivation et d'un flake
66-- Découverte de l'infrastructure autour de nixpkgs (github, la CI, Hydra @hydra...)
77-- Packaging en flake et CI basique (`nix build`) de `open-dynamic-robot-initiative/{interface_controls,master-board}` @odri-controls, @odri-masterboard
88-- Début du travail de packaging de `open-dynamic-robot-initiative/robot_properties_solo`
99-- Migration de `robot_properties_solo` vers uv @uv
1010-- Début du packaging de `xacro` sur NixOS/nixpkgs @nixpkgs-xacro
1111-- Création d'un JSON Schema @json-schema pour des fichiers de configuration de `robot_properties_solo` et mise en place d'une CI pour les valider @odri-properties-solo
1212-- Recherche autour d'une potentielle validation au runtime en C++ des fichiers de config par le JSON Schema
1313-- Découverte des overlays Nix
1414-1515-=== 26-28 Mai
1616-1717-- Continuation du travail précédent
1818-1919-2020-