this repo has no description
0
fork

Configure Feed

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

Continue rapport

+28 -30
+1 -1
rapport/conclusion.typ
··· 2 2 3 3 Bien que la reproductibilité de compilation ne soit pas encore atteinte, l'utilisation du gestionnaire de paquets Nix semble possible pour obtenir des garanties de reproductibilité. 4 4 5 - Les performances du _bridge_ SDK2 $arrows.lr$ Gazebo sont encore à améliorer, mais son utilisation est envisageable dans un context asynchrone, où le développement ne demande pas d'attendre les résultats de la simulation, via la pratique du CI/CD, par exemple. 5 + Les performances du _bridge_ SDK2 $arrows.lr$ Gazebo sont encore à améliorer, mais son utilisation est envisageable dans un contexte asynchrone, où le développement ne demande pas d'attendre les résultats de la simulation, via la pratique du CI/CD, par exemple.
+27 -29
rapport/gz-unitree.typ
··· 634 634 ` .ddq`, 635 635 $RR quad ("rad" dot "s"^(-2))$, 636 636 [Angle de rotation du moteur], 637 - empty, 637 + [#empty#footnote[Tant que nos politiques n'ont pas besoin de ces champs, le SDK semble fonctionner avec des valeurs vides] <empty-why>], 638 638 639 639 ` .tau_est`, 640 640 $RR quad ("N" dot "m")$, 641 641 [Estimation du couple exercé par le moteur], 642 - empty, 642 + [#empty@empty-why], 643 643 ) 644 644 645 645 ··· 647 647 648 648 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). Gazebo envoie également le nouveau tick de simulation (1C) et les valeurs du capteur IMU (1D) dans leurs topics respectifs. 649 649 650 - Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $Pi$ (4), qui (on le suppose) possède une subscription sur `rt/lowstate`. 650 + Le `LowStateWriter` vient lire le _State buffer_ (1B) pour publier l'état sur le canal DDS (2, 3) qui est ensuite lu par $Pi$ (4), qui possède une subscription sur `rt/lowstate`, via sa propre utilisation du SDK d'Unitree. 651 651 652 652 653 653 #let transparent = luma(0).opacify(0%) ··· 710 710 }) 711 711 712 712 713 - 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. 713 + Ici également, `LowStateWriter` s'exécute _parallèlement_ à `::PreUpdate`: En effet, on 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. 714 714 715 - Ici, il y a en plus non pas deux, mais _cinq_ boucles indépendantes qui sont en jeux: 715 + Ici, il y a en plus non pas deux, mais _cinq_ boucles indépendantes qui sont en jeu: 716 716 717 717 - La boucle de simulation de Gazebo (fréquence d'appel de `::PreUpdate`), 718 718 - La boucle du `ChannelPublisher` (fréquence d'appel de `::LowStateWriter`), et ··· 734 734 / Si la boucle IMU est plus fréquente: Certaines valeurs du capteur ne seront pas prises en compte par la politique 735 735 / Si la boucle IMU est moins fréquente: $Pi$ recevra plusieurs fois le même état, ce qui sera représentatif du fait que la simulation n'a pas encore avancé. 736 736 737 - Pour la boucle du tick, cela a peut d'importance. En effet, $Pi$ ne dépend probablement pas du tick de simulation, ou si il en dépend, ce serait de manièr peu précise (ce serait plutôt pour savoir "depuis quand est-ce qu'on a lancé la politique", ce qui ne demande pas une précision à la milliseconde) #refneeded. On met quand même à jour le tick pour que nos messages `rt/lowstate` synthétiques se rapprochent le plus possible des vrais messages tels qu'envoyés par le robot physique. 737 + Pour la boucle du tick, cela a peu d'importance. En effet, $Pi$ ne dépend probablement pas du tick de simulation, ou si elle en dépend, on suppose que c'est une dépendance à une valeur peu précise (ce serait plutôt pour savoir "depuis quand est-ce qu'on a lancé la politique", ce qui ne demande pas une précision à la milliseconde). On met quand même à jour le tick pour que nos messages `rt/lowstate` synthétiques se rapprochent le plus possible des vrais messages, tels qu'envoyés par le robot physique. 738 738 739 739 == Désynchronisations 740 740 ··· 861 861 862 862 == Amélioration des performances <perf> 863 863 864 - 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%. 864 + Les premiers essais affichent un facteur temps-réel#footnote[Appelé RTF (Real-Time Factor) @rtf. 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 ce qu'elle simule] autour des 10 à 15%. 865 865 866 866 #grid( 867 867 columns: 2, ··· 886 886 // ``` 887 887 888 888 #figure( 889 - caption: [Profiling d'une simulation avec _gz-unitree_], 889 + caption: [Profilage de _gz-unitree_ lors d'une simulation], 890 890 image("./profiler-many-ticks.png"), 891 891 ) 892 892 ··· 897 897 #let durations = (0.267, 0.051, 0.039, 0.142, 0.028) // total, state, tick+crc, pub state, cmd 898 898 #let dur = idx => [#durations.at(idx) ms] 899 899 #figure( 900 - caption: [Profiling d'un cycle de simulation], 900 + caption: [Profil d'un cycle de simulation], 901 901 table( 902 902 columns: durations.slice(1).map(x => x / durations.at(0) * 1fr), 903 903 table.cell([`::PreUpdate` #dur(0)], colspan: 4), ··· 909 909 ) 910 910 911 911 912 - Plus de la moitié du temps de calcul du plugin provient de l'envoi de l'état du robot sur le canal DDS `rt/lowstate`. 912 + Plus de la moitié du temps de calcul du plugin est dû à de l'envoi de l'état du robot sur le canal DDS `rt/lowstate`. 913 913 914 914 Notons également que, même si ce cyle-là a duré 0.267 ms, la durée d'un cycle est assez variable, certains atteignent 0.8 ms. 915 915 ··· 917 917 918 918 Quelques mesures ont été tentées pour réduire le temps nécéssaire à l'envoi d'un message DDS: 919 919 920 - / Restreindre DDS à `localhost`: Il est possible que DDS envoie les messages en mode "broadcast", c'est-à-dire à 920 + / Restreindre DDS à `localhost`: Il est possible que DDS envoie les messages en mode "broadcast", c'est-à-dire à tout addresse IP accessible dans un certain intervalle. En restreignant à `localhost`, on s'assure que le message n'a pas à être copié plusieurs fois. 921 921 / Déplacer dans un autre thread: C'est ce qui a motivé la désynchronisation du thread "LowStateWriter" (cf @send-lowstate) 922 922 / Ajuster la fréquence d'envoi: Une fois `LowStateWriter` déplacé dans un thread indépendant, on peut ajuster la fréquence d'envoi, le thread étant récurrant#footnote[Créé avec `CreateRecurrentThreadEx`] 923 923 ··· 933 933 934 934 Gazebo possède une fonctionnalité d'enregistrement vidéo, ce qui s'avère utile pour partager des résultats de simulation. 935 935 936 - Cependant, l'enregistrement vidéo n'est pas nativement contrôlable par du code. L'idée était en effet de faire automatiquement tourner une simulation à chaque changement de la politique RL, et d'obtenir la vidéo du résultat, pour en observer l'évolution. 936 + Cependant, l'enregistrement vidéo n'est pas nativement contrôlable programmatiquement. L'idée était en effet de faire automatiquement tourner une simulation à chaque changement de la politique RL, et d'obtenir la vidéo du résultat, pour en observer l'évolution. 937 937 938 - Il a donc fallu développer un autre plugin, héritant de `gz::gui::Plugin` cette fois-ci. Ce plugin écoute des messages sur des topics Gazebo, `/gui/record_video/...`, et permet de démarrer et arrêter l'enregistrement, tout en indiquant le chemin vers le fichier mp4 de sortie. 938 + Il a donc fallu développer un autre plugin, héritant de `gz::gui::Plugin` cette fois-ci. Ce plugin écoute des messages sur des topics Gazebo, `/gui/record_video/`${$`start`,`stop`$}$, et permet de démarrer et arrêter l'enregistrement, tout en indiquant le chemin vers le fichier MP4 de sortie. 939 939 940 940 Au final, un script complet permettant de démarrer une simulation et l'enregistrer en MP4 ressemble à ceci 941 941 942 942 ```bash 943 - # Envoyer un message Gazebo avec un argument de type String et une valeur de retour de type Booléen 943 + # Fonction pour envoyer un message Gazebo avec un argument de type String et une valeur de retour de type Booléen 944 944 send_to_gz() { 945 945 gz service -s $1 --reqtype gz.msgs.StringMsg --reptype gz.msgs.Boolean --req "data: \"$2\"" 946 946 } ··· 955 955 956 956 # Lancement de la politique RL 957 957 uv run policy.py & policy_pid=$! 958 - # On décide de la durée maximale de la vidéo (si la politique ne s'arrête pas d'elle même) 958 + # On décide de la durée maximale de la vidéo (si la politique ne l'arrête pas d'elle même) 959 959 sleep 120 960 960 kill $policy_pid 961 961 ··· 971 971 == Mise en CI/CD 972 972 973 973 974 - On appelle CI/CD (pour _Continuous Integration / Continuous Delivery_) la pratique consistant à intégrer fréquemment des petits changements à un dépôt de code source commun, en lançant des tests régulièrement (partie "CI") et éventuellement déployer la base de code fréquemment (partie "CD") @cicd. 974 + On appelle CI/CD (pour _Continuous Integration / Continuous Delivery_) la pratique consistant à intégrer fréquemment des petits changements à un dépôt de code source commun, en lançant des tests régulièrement (partie "CI") et éventuellement en déployant la base de code fréquemment (partie "CD") @cicd. 975 975 976 - Une 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_). 976 + Une fois l'enregistrement vidéo rendu automatisable, si l'on veut mettre en place l'enregistrement vidéo automatique à chaque changement de la politique, il faut crééer une description de _workflow_ (dans notre cas, un workflow _Github Actions_). 977 977 978 - 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. 978 + Un workflow est un ensemble de commandes à exécuter dans un environnement virtualisé#footnote[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. 979 979 980 980 === Une image de base avec Docker 981 981 982 982 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. 983 983 984 - Pour 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. 984 + Pour 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), Gazebo et gz-unitree. 985 985 986 986 ```dockerfile 987 987 FROM ubuntu:24.04 988 988 989 - RUN apt update 989 + RUN apt update 990 + # Just 990 991 RUN apt install -y curl just sudo 991 992 # Python (via le gestionnaire de versions et dépendances UV) 992 993 COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ ··· 1006 1007 RUN just install 1007 1008 ``` 1008 1009 1009 - Un autre workflow, celui-là vivant dans le dépôt de gz-unitree, crée une image Docker depuis ce Dockerfile, qui est ensuite utilisable via `ghcr.io/Gepetto/gz-unitree` @gzu-ghcr. 1010 + Un autre workflow, défini cette fois-ci dans le dépôt de gz-unitree et non celui de la politique RL, crée une image Docker depuis ce Dockerfile, qui est ensuite utilisable via `ghcr.io/Gepetto/gz-unitree` @gzu-ghcr. Les commandes installant Gazebo et les outils de compilation sont écrites dans le _Justfile_, que nous lançons ici avec `RUN just setup`. 1010 1011 1011 1012 === Une pipeline Github Actions 1012 1013 1013 - Une fois cette image disponible, on peut l'utiliser dans un workflow Github: 1014 + Une fois cette image disponible, on peut l'utiliser dans un workflow Github sur le dépôt Git de la politique RL: 1014 1015 1015 1016 #zebraw( 1016 1017 numbering: false, 1017 1018 highlight-lines: (6, 7), 1018 1019 ```yaml 1019 - ... 1020 - 1021 1020 jobs: 1022 1021 test: 1023 1022 runs-on: ubuntu-latest ··· 1026 1025 steps: 1027 1026 - name: Checkout repository 1028 1027 uses: actions/checkout@v5 1029 - - ... 1030 1028 ```, 1031 1029 ) 1032 1030 ··· 1042 1040 path: /tmp/result.mp4 1043 1041 ``` 1044 1042 1045 - #v(2em) 1043 + #v(0.5em) 1046 1044 #grid( 1047 1045 columns: (5fr, 3fr), 1048 1046 gutter: 2em, 1049 1047 [ 1050 1048 1051 1049 ==== Un environnement de développement contraignant 1052 - 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é. 1050 + 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 regarde si quelque chose s'est mal passé. 1053 1051 1054 1052 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. 1055 1053 ··· 1059 1057 1060 1058 Les environnements de CI/CD s'apparentent plus à des serveurs qu'à des ordinateurs complets: en particulier, il n'y a pas d'interface graphique et donc pas de serveur d'affichage (_display server_). 1061 1059 1062 - Mais Gazebo nécéssite un display server pour enregistrer une vidéo. 1060 + Mais Gazebo a besoin d'un display server pour enregistrer une vidéo. 1063 1061 1064 - Il convient donc de simuler un serveur d'affichage. Dans notre cas, l'environnement de CI/CD étant sous Linux, on simule un serveur X11 avec _XVFB_ @xvfb. 1062 + Il faut donc simuler un serveur d'affichage. Dans notre cas, l'environnement de CI/CD étant sous Linux, on simule un serveur X11 avec _XVFB_ @xvfb. 1065 1063 1066 1064 ], 1067 1065 figure(