Vol en intérieur avec ROS

Prérequis

Diapositives

Alternative text - include a link to the PDF!

Quelques alias

Les alias sont des racourcis qui nous permettent d’éxectuer des commandes recurentes plus rapidement.

alias sb="source ~/.bashrc"

Travaux pratiques

Vous devez utiliser la clef USB bootable fournit pour la formation.

A. Simulation

Pour mieux comprendre comment fonctionne l’assemblage ROS & drone, nous allons dans un premier temps essayer de faire voler un drone dans un environnement de simulation. Cet environnement de simulation permet de tester nos package ROS sans avoir de perte ou de casse de matériel. Une fois les essais concluants en simulation vous pourrez passer sur un drone bien réel. Dans un premier temps, il vous ai demandé de mettre en place l’environnement de simulation et de réussir à faire décoler le drone à environ 2m de hauteur et rester statique. Ensuite, nous ajouterons un package qui permet de simuler un système de MOtion CAPture (MOCAP). Une fois ce package ajouté, nous allons désactiver le GPS du drone et vérifier que ce dernier peut toujours décoller normalement. Enfin, nous ajouterons un package qui permet de faire de l’avoidance. Ce package se base sur l’ajout de différent capteurs sur le drone. La partie pratique de l’avoidance est donc en bonus.

1. Installer ROS

Avant de pouvoir commencer, nous devons mettre en place notre environnement de développement ROS. Nous allons donc installer ROS dans sa version noetic ainsi que Gazebo et Rviz. Gazebo est un logiciel de simulation d’environnement. C’est dans ce logiciel que nous pourrons voir notre drone évoluer lors des différentes simulations. Rviz est un logiciel d’analyse qui nous permet de debuguer notre système lors des simulations. Dans un premier temps, nous allons installer tous les paquets requis pour faire voler un drone en intérieur et le simuler. Pour ce faire, il vous faut ouvrir ce fichier et executer les commandes.

Une fois l’installation de ROS terminée, nous pouvons vérifier notre travail avec la commande suivante :

source /opt/ros/noetic/setup.bash

Afin de se faciliter le travail et d’avoir à taper cette commande tout le temps, nous pouvons l’ajouter à notre fichier ~/.bashrc :

echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc # $ sb

Vous pouvez remarquer que la commande ci-dessus est la même commande que nous vons configurée en alias précédemment. Un simple sb dans le terminal permet de remplacer la commande setup.bash.

Maintenant que nous avons installer le coeur de ROS, nous pouons installer ses dépendances. Ces dernières vont nous permettre de créer et gérer notre environnement de développement. Pour les installer, tapez la commande suivante.

sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential

Il est alors possible d’initialiser rosdep avec les commandes suivantes :

sudo rosdep init
rosdep update

Une fois ceci fait, nous allons installer les paquets qui permettent de créer la workspace :

sudo apt install ros-noetic-catkin python3-catkin-tools -y
sudo ln -s /usr/bin/python3 /usr/bin/python

Nous allons maintenant pouvoir installer un emulateur pour le controleur de vol du drone.

2. Installer PX4

Maintenant que nous avons un environnement ROS opérationnel, nous devons télécharger le firmware PX4 qui possède des outils permettant de simuler entièrement le controleur de vol (Pixhawk). Ainsi, nous pourrons avoir les mêmes interfaces de pilotage que dans la réalité. Dans un premier temps, nous devons récupérer le repertoire sur Github et ensuite nous devons le compiler :

cd ~

git clone https://github.com/PX4/PX4-Autopilot.git --recursive /home/$USER/PX4-Firmware/

echo 'source ~/PX4-Firmware/Tools/simulation/gazebo/setup_gazebo.bash ~/PX4-Firmware ~/PX4-Firmware/build/px4_sitl_default' >> /home/$USER/.bashrc
echo 'export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Firmware' >> /home/$USER/.bashrc
echo 'export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Firmware/Tools/simulation/gazebo/sitl_gazebo' >> /home/$USER/.bashrc
echo 'export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:/usr/lib/x86_64-linux-gnu/gazebo-9/plugins' >> /home/$USER/.bashrc

source ~/.bashrc

cd ~/PX4-Firmware
make px4_sitl_default gazebo_iris

Une fois la dernière commande lancée, la compilation du firmware va démarrer. Une fois cette dernière terminée, une simulation de décollage va commencer. Vous pouvez regarder le resultat de la simulation dans la fenêtre de Gazebo.

Vous pouvez alors télécharger et lancer QGroundControl qui est le logiciel qui permet de communiquer avec le drone :

sudo usermod -a -G dialout $USER
sudo apt-get remove modemmanager -y
sudo apt install gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-gl -y
sudo apt install libqt5gui5 -y
sudo apt install libfuse2 -y

wget https://d176tv9ibo4jno.cloudfront.net/latest/QGroundControl.AppImage
chmod +x ./QGroundControl.AppImage
./QGroundControl.AppImage

Une fois ce dernier lancé, il va automatiquement détecter le drone dans la simulation et se connecter.

Vous pouvez maintenant fermer la simulation en tapant Ctrl+C dans le terminal où vous avez lancé la simulation. Nous allons maintenant comment lier la simulation du firmware et ROS.

3. “Offboard Flight Mode”

Les choses sérieuses peuvent commencer … Notre environnement de développement est enfin opérationel. Nous allons maintenant créer une workspace qui va accueillir les différents packages ROS dont nous avons besoin et ceux que nous allons créer.

Pour créer la workspace, nous devons dabord créer un dossier et ensuite dire à ROS d’initialisé la workspace :

mkdir -p ~/mocapfly_ws/src
cd ~/mocapfly_ws
catkin init
wstool init src

Ensuite, on installe MAVLink. MAVLink est un paquet qui permet de communiquer entre le drone et le companion computer. Plus précisemment, il va permettre de décoder les messages envoyer par le drone et de coder les messages de ROS afin qu’ils soient compréhensible par le drone.

rosinstall_generator --rosdistro noetic mavlink | tee /tmp/mavros.rosinstall

Puis, MAVROS. Dans la continuité de MAVLink, MAVROS à la charge la connexion entre le drone et le companion computer.

rosinstall_generator --rosdistro noetic --upstream mavros | tee -a /tmp/mavros.rosinstall

On merge la WS puis on installe les packages :

wstool merge -t src /tmp/mavros.rosinstall
wstool update -t src -j4
rosdep update
rosdep install --from-paths src --ignore-src -y --rosdistro noetic

Nous pouvons maintenant build la WS avec catkin :

catkin build

Ensuite, on charge les outils de la WS :

source devel/setup.bash

Nous allons maintenant créer notre premier package qui permet de passer le FCU en mode OFFBOARD. Ceci, permettra à ROS de devenir le “pilote” du FCU. Nous pourrons donc créer des missions grâce à ROS.

Il est important de comprendre qu’ici ROS n’est pas le pilote du drone mais le donneur d’ordre sur la destination où aller. Pour vulgariser : Quand vous commandez un Uber c’est à vous de dire au chauffeur où vous souhaitez aller, et il se débrouille pour vous y emmener. Dans cet exemple, ROS c’est vous et le chauffeur Uber est le FCU.

On se rend dans la WS :

roscd  # Should cd into ~/mocapfly_ws/devel
cd .. 
cd src

On créé le nouveau package :

catkin_create_pkg offboard_py rospy

Ensuite, on rebuild la WS, on recharge les outils et nous pouvont commencer à coder :

cd .. # Assuming previous directory to be ~/mocapfly_ws/src
catkin build
source ../devel/setup.bash

On se rend dans le dossier du package et ensuite on créé un dossier pour stocker notre package :

roscd offboard_py
mkdir scripts
cd scripts

Dans un premier temps on créé le fichier du controller et on le rend executable :

touch offb_node.py
chmod +x offb_node.py

Ensuite, on utilise le code suivant pour permettre le passage en mode OFFBOARD :

vim offb_node.py # you may use $ code . 

Le code :

#! /usr/bin/env python3

import rospy
from geometry_msgs.msg import PoseStamped
from mavros_msgs.msg import State
from mavros_msgs.srv import CommandBool, CommandBoolRequest, SetMode, SetModeRequest

current_state = State()

def state_cb(msg):
    global current_state
    current_state = msg


if __name__ == "__main__":
    rospy.init_node("offb_node_py")

    state_sub = rospy.Subscriber("mavros/state", State, callback = state_cb)

    local_pos_pub = rospy.Publisher("mavros/setpoint_position/local", PoseStamped, queue_size=10)
    
    rospy.wait_for_service("/mavros/cmd/arming")
    arming_client = rospy.ServiceProxy("mavros/cmd/arming", CommandBool)    

    rospy.wait_for_service("/mavros/set_mode")
    set_mode_client = rospy.ServiceProxy("mavros/set_mode", SetMode)
    

    # Setpoint publishing MUST be faster than 2Hz
    rate = rospy.Rate(20)

    # Wait for Flight Controller connection
    while(not rospy.is_shutdown() and not current_state.connected):
        rate.sleep()

    pose = PoseStamped()

    pose.pose.position.x = 0
    pose.pose.position.y = 0
    pose.pose.position.z = 2

    # Send a few setpoints before starting
    for i in range(100):   
        if(rospy.is_shutdown()):
            break

        local_pos_pub.publish(pose)
        rate.sleep()

    offb_set_mode = SetModeRequest()
    offb_set_mode.custom_mode = 'OFFBOARD'

    arm_cmd = CommandBoolRequest()
    arm_cmd.value = True

    last_req = rospy.Time.now()

    while(not rospy.is_shutdown()):
        if(current_state.mode != "OFFBOARD" and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
            if(set_mode_client.call(offb_set_mode).mode_sent == True):
                rospy.loginfo("OFFBOARD enabled")
            
            last_req = rospy.Time.now()
        else:
            if(not current_state.armed and (rospy.Time.now() - last_req) > rospy.Duration(5.0)):
                if(arming_client.call(arm_cmd).success == True):
                    rospy.loginfo("Vehicle armed")
            
                last_req = rospy.Time.now()

        local_pos_pub.publish(pose)

        rate.sleep()

Maintenant que nous avons créé le package nous devons créer un launch file :

roscd offboard_py
mkdir launch
cd launch 
touch start_offb.launch
chmod +x start_offb.launch

Pour le fichier start_offb.launch mettre le code suivant : Attention, gcs_bridge doit être configuré en fonction de vos paramètres réseaux.

<?xml version="1.0"?>
<launch>
	<!-- Bridge to get QGroundControl UDP link *to configure* -->
	<node pkg="mavros" type="gcs_bridge" name="qgroundcontrol" output="screen" args="_gcs_url:='udp://@127.0.0.1'"/>
	<!-- Include the MAVROS node with SITL and Gazebo -->
	<include file="$(find px4)/launch/mavros_posix_sitl.launch">
	</include>

	<!-- Our node to control the drone -->
	<node pkg="offboard_py" type="offb_node.py" name="offb_node_py" required="true" output="screen" />
</launch>

Nous devons maintenant exporter quelques variables d’environnement afin de pouvoir démarrer la simulation correctement. Pour exporter ces variables nous allons éditer le fichier ~./.bashrc et ajouter les lignes suivantes à la fin du fichier :

Note : Si vous l’avez déjà fait à l’étape précédente, contentez-vous de source le fichier .bashrc

source ~/PX4-Firmware/Tools/simulation/gazebo/setup_gazebo.bash ~/PX4-Firmware ~/PX4-Firmware/build/px4_sitl_default
source /opt/ros/noetic/setup.bash
source ~/mocapfly_ws/devel/setup.bash
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Firmware
export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:~/PX4-Firmware/Tools/simulation/gazebo/sitl_gazebo
export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:/usr/lib/x86_64-linux-gnu/gazebo-9/plugins
export GAZEBO_PLUGIN_PATH=$GAZEBO_PLUGIN_PATH:/usr/local/lib/gazebo

Attention à bien faire un coup de source du fichier .bashrc :

sb

Nous pouvons ensuite lancer la simulation et vérifier le comportement du drone :

roslaunch offboard_py start_offb.launch

Si jammais vous obtenez une erreur, essayez de source l’installation de ROS, puis devel/setup.bash et ensuite ~/.bashrc.

La simulation doit se lancer et vous devriez voir le drone décoller puis rester statique à une altitude de deux mètres. Vous pouvez vérifier l’état du drone en relançant QGroundControl.

Maintenant que nous avons vu comment donner le controle du drone à ROS, modifiez le package Offboard pour que le drone décolle et fasse la trajectoire de votre choix avant d’attérir.

4. MOCAP & UAV

ROS est maintenant en mesure de pouvoir communiquer avec le drone et de pouvoir le piloter. Cependant, pour le moment il utilise un “faux” GPS qui permet de positionner le drone correctement et de le déplacer. Dans un environnement clos, il n’est pas possible pour le drone de recevoir les données GPS qui permettent au drone de ce déplacer. Dans ce cas, nous pouvons utiliser un système de motion capture qui va traquer un tag disposé sur le drone. Le système de MOCAP nous donne alors la position du drone dans l’espace. Nous devons fournir cette position au drone pour qu’il puisse utiliser ces données à la place du GPS, et ainsi pouvoir voler.

Dans un premier temps, il faut installer ce package. Pour ce faire, placer vous dans le dossier src de votre workspace et taper les commandes suivantes :

cd ~/mocapfly_ws/src
git clone https://github.com/aiRCS-Lab/mocap_simulator.git

Une fois le paquet installer, il est nécessaire de modifier notre launch file afin de lancer le node mocap_simulator lors du démarrage de la simulation. Pour ce faire, il faut retourner dans le package offboard_py et éditer le fichier start_offb.launch.

Il faut y rajouter les lignes suivantes qui permettent de lancer le node MOCAP et de publier les positions du drone :

<node pkg="mocap_simulator"
	type="mocap_simulator_node.py"
	name="vrpn_client_node"
	output="screen">
	<param name="frame_rate" value="100"/>
	<param name="publish_tf" value="true"/>
	<param name="fixed_frame_id" value="local_origin"/>
	<rosparam param="model_list">[]</rosparam>
</node>

Enfin, nous allons rajouter une ligne qui permet de relayer les informations du système de MOCAP sur le bon topic, celui écouté par le drone :

<node pkg="topic_tools" type="relay" name="mocap_relay_mavros" output="screen" args="/vrpn_client_node/iris/pose /mavros/vision_pose/pose"/>

Vous pouvez maintenant source tous les fichiers :

source /opt/ros/noetic/setup.bash
source ~/mocapfly_ws/devel/setup.bash
source ~/.bashrc

Nous pouvons maintenant relancer la simulation et aller sur QGroundControl pour désactiver le GPS du drone et dire à ce dernier d’utiliser les données du système MOCAP. Pour désactiver le GPS, il faut aller dans “Vehicle Setup” puis dans “Parameters” et chercher has_gps est passer ce paramètre à disable.

disable gps

Vous devez maintenant restart complètement la simulation pour que le nouveau paramètre soit appliqué.

Note : Lors de la partie pratique vous n’aurez pas ce paramètre. En effet, il faudrat activer l’ekf2 et lui dire d’utiliser les données de positions d’Optitrack.

B. Pratique

Attention : Il est strictement INTERDIT de mettre les hélices sur le drone tant que vous êtes hors de la cage spécialement prévue pour faire voler les drones. Votre encadrant seul vous donnera les hélices au moment ou vous en aurez besoin.

1. Le materiel & assemblage

Afin de pouvoir faire voler un drone, il nous faut un drone … Pour ce faire, des drones pré-assemblés sont mis à votre disposition sans hélices (il faudrat venir les demander à votre encadrant de TP lors des tests en cage). Il suffit de flasher la carte SD du companion computer et de l’insérer dans ce dernier.

Pour ce faire il vous est demandé de télécharger l’image du companion computer disponible ici. Une fois le téléchargement terminé, utilisez Balena Etcher pour écrire l’image sur la carte SD.

L’image ci-dessous montre comment le companion computer est assemblé sur le drone : odroid on drone

La carte SD doit être insérée entre le connecteur d’alimentation et le potr HDMI (à droite sur la photo ci-dessus). Une fois la carte insérée, il est nécessaire de vérifier que l’intérupteur (en haut à droite sur la photo) est bien positionné sur µSD. Si ce n’est pas le cas le companion computer ne démarrera pas. Vérifiez la présence d’une clef WiFi sinon vous ne pourrez pas vous y connecter en SSH.

Si vous ne trouvrez pas l’adresse IP de votre Companion Computer ne pas hésiter à venir me demander.

Enfin, il faut vérifier que le PixHawk est bien relié depuis le port TELEM 2 au port USB du companion computer. Ce cable est en réalité un convertisseur UART vers USB. Il permet la communication entre le firmware du controleur de vol (Pixhawk) et ROS (companion computer). On peut en voir le connecteur USB sur la photo ci-dessus, et on peut voir le connecteur coté pixhawk sur la photo ci-dessous. connexion telem 2 pixhawk

2. Installation de ROS sur le companion computer embarqué

Une fois le drone mis sous tension, le companion computer devrait démarrer après quelques minutes. Le companion computer permet de faire tourner ROS sur le drone directement. C’est ce dernier qui va permettre de communiquer avec le serveur MOCAP et, pour ceux qui vont plus loin, de gérer les caméras et autres capteurs qui permettent de faire de l’avoidance. Enfin, il permet aussi de calculer les trajectoires en fonction des différents obstacles détectés par le drone.

On utilise un companion computer car les taches de calculs de trajectoire, de détection des obstacles, ou encore simplement d’une liaison WiFi ne sont pas supportées nativement par le controleur de vol. De plus, le fait de séparer les différents organes de pilotage permet de garder une certaine tolérance à la faute. Par exemple, dans notre exemple, si le drone perd son companion computer, le FCU est capable de prendre le relais le temps de faire attérir le drone en sécurité.

Vous pouvez vous y connecter directement via SSH :

ssh dev@odroid.local # ou l'adresse IP que vous avez récupérée
# password : dev_ros

Maintenant que nous sommes connectés au drone, nous pouvons installer les packages nécessaires pour faire fonctionner correctement le drone.

La suite de cette section contient les étapes nécessaires pour la création d’un environnement d’exécution de ROS coté robot. Cet environnement est mis en place sur un Odroid XU4 équipé d’un Ubuntu 20.04 LTS. Dans un premier temps, nous allons installer ROS sur le SBC avant de voir comment créer notre première workspace qui permettra à terme de piloter le drone.

Configure swap

Nous devons dans un premier temps augmenter la taille du fichier de SWAP. Ceci permet d’éviter qu’Ubuntu essaye d’arreter le compilateur CPP par manque de ressources. L’augmentation de la taille du fichier SWAP se fait à l’aide des commandes suivantes :

sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
sudo swapon --show
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab # Adding swap at boot

Une fois le fichier SWAP suffisament grand pour compiler ROS, nous pouvons ajouter les sources qui nous permettent d’installer ROS. Il vous faudra exectuer la commande suivante :

sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

Une fois les sources ajoutées, il vous faut récupérer les clefs qui permettent d’utiliser ces sources. Cette opération se fait avec la commande suivante.

sudo apt install curl # if you haven't already installed curl
curl -s https://raw.githubusercontent.com/ros/rosdistro/master/ros.asc | sudo apt-key add -

Une fois cette étape terminée, nous pouvons rafraichir les sources disponibles et enfin installer ROS sur notre drone.

sudo apt update

Sur le drone, nous allons uniquement installer ROS-Core. En effet, nous n’avons plus besoin de l’environnement de simulation.

sudo apt install ros-noetic-ros-base

Une fois que ROS est installé, nous pouvons charger sa configuration.

source /opt/ros/noetic/setup.bash

Pour plus de facilité, vous pouvez ajouter la commande précédante au fichier ~/.bashrc et aussi créer un alias.

echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

Comme nous l’avons fait à l’étape précédente, nous allons installer toutes les dépendances qui permettent de compiler et executer les paquets que nous allons créer / utiliser.

sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
sudo apt install python3-rosdep
sudo rosdep init
rosdep update
sudo apt install ros-noetic-catkin python3-catkin-tools -y
sudo ln -s /usr/bin/python3 /usr/bin/python
wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh 
sudo bash ./install_geographiclib_datasets.sh

Maintenant que ROS est correctement installer sur notre drone, vous devez recréer la workspace à l’aide des commandes que nous avons vues précedemment. Nous allons réutiliser le paquet offboard_py et modifier son launch file afin de pouvoir lancer ROS avec le FCU et non en simulation. Vous pouvez utiliser la commande scp pour transférer des dossiers et fichiers d’un PC à un autre.

Il est important de remarquer que le paquet mocap_simulator doit être remplacer par le paquet qui permet de se connecter au serveur MOCAP.

Le paquet qui permet de se connecter au serveur MOCAP est le suivant :

sudo apt-get install ros-noetic-vrpn-client-ros -y

Une fois le paquet installé, nous pouvons ouvrir un nouveau terminal et lancer la commande suivante qui va permttre de connecter ROS au serveur MOCAP et ainsi de pouvoir relayer les données de ce dernier sur les topics MAVROS. Ainsi, notre drone pourra utiliser les données de position Optitracks pour voler.

roslaunch vrpn_client_ros sample.launch server:=<mocap machine ip>

Nous pouvons maintenant rediriger le topics vrpn sur le topic mavros qui est utilisé par le drone :

rosrun topic_tools relay /vrpn_client_node/<rigid_body_name>/pose /mavros/vision_pose/pose

Une fois ceci réalisé, nous pouvons configurer le FCU pour qu’il prenne en compte les données de vision envoyées par le système de MOCAP. Nous devons alors utilisé QGroundControl (installé sur votre machine) pour se connecter au FCU et modifier les paramètres qui suivent :

Pour plus dinformations sur le fonctionnement de l’algorithme : EKF2 tuning guide

Les paramètres suivants doivent être appliqués pour que les informations de position externes soient utilisées avec EKF2 (QGroundControl > Vehicle Setup > Parameters > EKF2)

Parameter Setting for External Position Estimation
EKF2_AID_MASK Set vision position fusion, vision velocity fusion, vision yaw fusion and external vision rotation accoring to your desired fusion model.
EKF2_HGT_MODE Set to Vision to use the vision a primary source for altitude estimation.
EKF2_EV_DELAY Set to the difference between the timestamp of the measurement and the “actual” capture time. For more information see below.
EKF2_EV_POS_X, EKF2_EV_POS_Y, EKF2_EV_POS_Z Set the position of the vision sensor (or MoCap markers) with respect to the robot’s body frame.

Tip Reboot the flight controller in order for parameter changes to take effect.

Vous pouvez ensuite venir essayer votre drone dans la cage pour vérifier que ce dernier vol correctement avec le système de positionnement type MOCAP.

C. Pour aller plus loin !

Si vous avez réussi à faire voler votre drone correctement dans la cage avec le système de positionnement MOCAP, alors vous pouvez essayer d’intégrer le Package ROS : PX4-Avoidance. Ajoutez-le d’abord dans votre drone sur le simulateur et si vous arrivez à le faire fonctionner correctement en simulation vous pourrez essayer de voler dans la cage avec des obstacles.

Bon courage !