Dossier sur la communication et l`interface de contrôle
Transcription
Dossier sur la communication et l`interface de contrôle
Projet Pluritechnique encadré : Quadricoptère - Partie communication - Achille DANTZ, En groupe avec DUSSOURD Nicolas et DIETRICH Lucas Lycée J.B. Schwilgué, Sélestat – Session 2014 Plan : 1) Introduction 2) Etude fonctionnelle 3) Le système et les solutions techniques a. Piloter le drone b. Récupérer les informations c. Visualiser les informations 4) Le fonctionnement de la communication a. Communication Utilisateur -> Drone b. Communication Drone -> Utilisateur 5) L’évolution du projet Introduction : Pour réaliser notre premier Quadricoptère, nous avions comme objectif de le réaliser à partir du matériel le plus basique, et non pas de solutions déjà existantes dans le commerce. C’est dans cette optique qu’a été réalisée la partie de la communication entre le drone et l’utilisateur. Cette partie, qui m’a été assignée, comprend plusieurs aspects, que nous allons explorer ici. Cette partie a été cruciale au projet, car en plus de permettre de piloter le drone, elle a aussi permis de visualiser les informations du drone, pour analyser et modifier son comportement en conséquence. Le travail dans cette partie comprend le choix et l’exploitation du contrôleur pour piloter le drone, l’envoi des commandes au drone, la réception des informations du drone et la visualisation de ces dernières. Etude fonctionnelle : I. Problématique Le Drone construit a pour but la prise de vue aérienne de photos ou de vidéos, par exemple pour l’examen en toute sécurité d’un ouvrage en hauteur. Pour réaliser une telle mission, le drone doit être capable d’être conforme pour une utilisation de type professionnel. Cela inclut, par exemple, une autonomie supérieure à 5 minutes, et une portée suffisante. Pour la partie communication, les points essentiels sont la sécurité, la portée et la fiabilité, tout en offrant une expérience de pilotage intuitive, le tout à un coût maitrisé. FAST (partie communication) : On voit ici l’ensemble des fonctions de la communication, ainsi que les solutions techniques adoptées (détaillés ci-après). Le système et les solutions technologiques I. Piloter le drone Le premier enjeu de la communication est bien évidemment de pouvoir piloter le drone. Pour ce faire, il a fallu faire le choix d’un contrôleur adéquat. La solution technique retenue a été un contrôleur de jeu, initialement destinée à être utilisé avec le système de jeu Playstation®3. Ce contrôleur est idéal car il inclut 2 gâchettes analogiques (utilisées pour augmenter/diminuer l’altitude du drone), 2 joysticks analogiques, mettant à disposition 4 axes, utilisés pour les mouvements de ROLL, PITCH, YAW*, ainsi que d’une multitude de boutons. (* : Tangage, roulis, lacet) Le contrôleur utilisé Crédit image : skatter.com Une fois le choix du contrôleur fait, il reste à pourvoir récupérer les commandes de l’utilisateur. La manette présentée agit comme un périphérique d’interface humaine (HID) standard. Pour pouvoir communiquer avec, il faut donc disposer d’un hôte USB. Cet hôte pourra communiquer avec la manette et ainsi récupérer les commandes utilisateurs. Le module ci-dessous fournit un hôte USB et est capable de communiquer avec les microcontrôleurs Arduino. Crédit image : circuitsathome.com Une fois ces informations extraites du contrôleur, il reste à les interpréter. Pour ce faire, nous avons recours à un microcontrôleur Arduino MEGA 2560, principalement pour la raison qu’il intègre 4 ports de communication série, dont un sera utilisé pour le drone et un pour l’interface graphique. Il offre également l’avantage d’être alimenté en USB sans problème de sous-intensité. Ce microcontrôleur permet de communiquer avec le module ci-dessus grâce au code disponible en annexe et à une librairie, modifiée spécifiquement pour le drone. Il est à noter que le projet utilise trois Arduino : deux sur le drone et un au sol. Le microcontrôleur utilisé Crédit image : australianrobotics.au Le microcontrôleur ici présenté est le « centre des opérations » de la communication. Il assure la communication entre le drone, l’utilisateur, et l’interface graphique. Pour transmettre les commandes au drone, plutôt que d’utiliser des modules radios dédiés au modélisme, et qui ne fonctionnent que dans un sens, nous avons optés pour des modules de télémétrie Xbee®, qui sont des Zigbee (manufacturés par Digi intl.) adaptés à l’Arduino. Ces modules émulent un port de communication série asynchrone entre les 2 points du réseau (les deux modules), et permet ainsi de profiter d’une communication à double sens. La communication entre les deux modules est basée sur une liaison radio utilisant le protocole Wi-Fi. Un ensemble au sol manette-Arduino-Xbee sera donc placé au sol et peut fonctionner de manière autonome (alimenté par batterie ou autre source électrique) ou bien de concert avec un ordinateur équipé de l’interface graphique spécialement créée pour. L’interface graphique est programmée en VB.net et permet de communiquer avec l’arduino par le biais d’un port série virtuel, puisque ce langage intègre une puissante librairie pour la communication série, ainsi que des contrôles permettant une visualisation agréable et rapide des informations. Partie 2 : le fonctionnement de la communication Les deux modules communiquant (un sur le drone, un au sol) seront considérés par les microcontrôleurs comme une liaison série asynchrone simple. La vitesse (baudrate) de cette liaison a été fixée à 9600 bits/seconde, ce qui signifie que le signal est capable de changer d’état 9600 fois par seconde. Si l’on augmente cette vitesse, on remarque, même à faible distance, la perte de paquets, ce qui peut s’avérer très problématique pour le pilotage d’un drone. Les commandes envoyées au drone se composent de deux parties : l’adresse et le paramètre. L’adresse est codée sur 6bits et le paramètre sur 8 bits (la table des commandes et des paramètres correspondants sont disponibles en annexe). Une commande envoyée vers le drone sera sous la forme : AAAABBAABBBBBB Où A est un bit d’adresse et B un bit de paramètre. Cet agencement non linéaire de la commande permet de détecter une commande incohérente, et de notifier l’Arduino au sol de l’erreur. Lors de l’appui d’une touche, ou de la modification d’un paramètre de la manette, on envoie une commande, à une fréquence maximale de 5Hz, ce qui correspond, en phase de pilotage normal, à un envoi maximal, toutes commandes comprises, de l’ordre de 15Hz (15 commandes par secondes). La réception sur le drone est réalisée par le Xbee placée sur le drone, qui peut Communiquer directement avec l’ArduIMU. Il a donc fallu, de concert avec Lucas DIETRICH, établir une table des commandes, disponibles en annexe, qui permet d’envoyer les bonnes commandes. Il est cependant à noter que la plupart des commandes sont utilisées pour le débogage du drone, et ne sera pas utile pour un utilisateur « standard ». Une fois ces commandes envoyées au drone, il réagit en conséquence, et pour visualiser ces réactions, et l’état général du drone, ce dernier est en mesure d’envoyer un rapport de statut comprenant plusieurs paramètres, comme les angles, l’altitude, les vitesses de rotation des moteurs etc… Pour un rapport de statut, 34 octets (checksum inclus) transitent depuis le drone vers le sol, à une fréquence (modifiable), actuellement de 2Hz, ce qui engendre un trafic de données à un débit de 78octets/seconde, sur un maximum de 9600/8 = 1200 octets/seconde. On a donc une marge de manœuvre confortable et on n’a pas à craindre une saturation de la mémoire tampon (buffer) de l’interface série. Ces données sont formatées pour pouvoir être analysées. Chaque donnée est codée sur 1 à 4 octets. Voici ces paramètres : Nom Angle Phi Angle Thêta Angle Psi Altitude Fréquence Usage processeur Commandes reçues Commandes envoyées Events Timers Overflows Niveau d’alerte général Mu (strictement debug) checksum Taille en octets 2 2 2 2 3 1 3 3 4 4 4 2 2 1 L’interprétation de ces informations n’est pas réalisée par l’Arduino, mais par l’interface graphique : Les données ne font que transiter par l’Arduino, même s’il est possible de les analyser, mais cela ne présente pas d’intérêt. Chaque nouvelle chaîne est séparée de la précédente par trois retours à la ligne (code ASCII 10). On évite ainsi la mauvaise détection de séparateurs (par exemple si l’on prend un seul retour à la ligne une donnée peut prendre 10 comme valeur, mais la probabilité que 3 octets valent 10 est négligeable). En connaissant la longueur du rapport (34 octets), on est en mesure de séparer les différents octets pour les interpréter. Le programme intégrant une interface graphique qui se charge de cela est codé en VB.NET, et utilise un port série de type RS232 virtuel pour communiquer avec l’Arduino terrestre. Ce programme est principalement destiné à afficher les données du rapport, mais on peut également envoyer rapidement des commandes au drone par cet intermédiaire. Des contrôles visuels ont été créés spécialement pour visualiser les informations du drone de manière adaptée, comme par exemple des jauges ou barres de progrès (code disponible en annexe), qui, en plus de contrôles existants ou modifiés (comme les contrôles « chart » qui sont à la base des graphiques visibles sur l’interface. Voici un diagramme résumant la structure de la communication : 6) L’évolution du projet I. Le cahier des charges Nom Portée Contrainte Portée minimale de 100m (illégal de piloter le drone à plus de 100m) Utilisation Etre facile d’utilisation et pilotable de façon sécurisée Conformité Etre conforme aux normes européennes et françaises sur la radiocommunication II. Validation La portée a été testée avec succès en terrain demi-dégagé à une distance d’environ 150m sans interruption de la communication. Pilotage par contrôleur de jeu : intuitive et facile. Logiciel portable et aisé à configurer Utilise les fréquences et protocoles 802.15.4 avec une puissance de 60mW : conforme à la législation. Egalement conforme RoHS Difficultés rencontrées et évolution du projet La partie de la communication du drone a connu beaucoup de changements. Plusieurs solutions techniques ont été envisagées et rejetées durant les phases de prototypage, comme par exemple l’utilisation d’une manette « faite maison », qui se serait certainement avérée de mauvaise qualité et peu pratique, alors que la solution retenue est versatile et complète. L’interface graphique, elle aussi, a d’abord été codée en python, qui se trouve être excellent pour la liaison série, mais très peu pratique quand il s’agit d’afficher plusieurs graphiques et autres contrôles. Globalement, le résultat de la communication d’avère être conforme à l’idée de départ : un pilotage avec une manette, une liaison à double sens et une interface graphique pratique pour visualiser l’état du drone. Cependant plusieurs difficultés ont fait surface : par exemple la noncompatibilité de la manette (résolue en modifiant la librairie) ou bien encore le comportement des Xbee, qui changeaient d’adresse à chaque mise sous tension, et qu’il a fallu « reflasher ». L’expérience de créer un produit en partant de composants ordinaires, sans avoir recours à des solutions technologiques courantes a été très enrichissant. Le travail de groupe, en particulier avec Lucas, a été primordial pour la réussite du projet, et bien que cela n’ait pas toujours été chose aisée, le résultat final est satisfaisant. Avec le groupe, nous envisageons, et dès cet été, de poursuivre ce projet, afin de l’améliorer et de le terminer. ANNEXE 1 : Extrait du tableau de commandes Adresse car 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 ! " # $ % & ' ( ) * param 000000 000001 000010 000011 000100 000101 000110 000111 001000 001001 001010 001011 001100 001101 001110 001111 010000 010001 010010 010011 010100 010101 010110 010111 011000 011001 011010 011011 011100 011101 011110 011111 100000 100001 100010 100011 100100 100101 100110 100111 101000 101001 101010 + , . / 0 101011 101100 101101 101110 101111 110000 - commande CMD_RESERVED_1 CMD_RESERVED_2 CMD_COM_OK CMD_COM_ERROR CMD_COM_BUSY CMD_COM_READY CMD_COM_INCREASE_FREQ CMD_PROC_EMERGENCY CMD_PROC_LANDING CMD_PROC_TAKEOF CMD_PROC_BATTERY CMD_MANUAL_LEFT CMD_MANUAL_RIGHT CMD_MANUAL_FORWARD CMD_MANUAL_BACKWARD CMD_MANUAL_UP CMD_MANUAL_DOWN CMD_MANUAL_TURN_LEFT CMD_MANUAL_TURN_RIGHT CMD_CFG_ABOUT_TURN CMD_STOP CMD_WARN_EMERGENCY CMD_CFG_AZIMUT CMD_CFG_ALTITUDE CMD_CFG_PITCH CMD_CFG_ROLL CMD_CHANGE_PR_KP CMD_CHANGE_PR_KI CMD_CHANGE_PR_KD CMD_CHANGE_AVG_THROTTLE CMD_CHANGE_STATUS CMD_PITCH_SETPOINT CMD_ROLL_SETPOINT CMD_YAW_SETPOINT CMD_ALTITUDE_SETPOINT CMD_PID_MODE MASK1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 MASK2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 description 0° nord 0 au sol 0 : -20 0 : -20 pitch roll pitch roll pitch roll on change avg undefined (0), config (1), on (2), pause (3), emergency (4) pitch setpoint roll setpoint yaw setpoint altitude setpoint start or stop 1 or 0 ANNEXE 2 : EXTRAIT PROCESSUS D’ENVOI SOL > DRONE et DRONE >SOL #include <PS3USB.h> # On importe la librairie PS3 modifiée #endif unsigned unsigned unsigned unsigned unsigned long long long long long lastcmd = 0; //Pour limiter la fréquence d’émission lastcomLHX = 0; lastcomLHY = 0; lastcomRHX = 0; lastcomRT =0; USB Usb; //On declare le “shield” hôte PS3USB PS3(&Usb); // On declare le contrôleur uint8_t state = 0; int inter = 50; // Délai mini. Entre deux émissions void send_IMU(byte cmd, byte param) // Cette fonction envoie les données formatées au port 1 (Drone) { // cmd < 64 - param < 255 byte serial_cmd = CMD_FIRST_BIT << 7 | cmd << 1 | MSB(param); byte serial_param = PARAM_FIRST_BIT << 7 | LSBS(param) << 0; Serial1.write(serial_cmd); Serial1.write(serial_param); Serial.println(String(cmd) + " " + String(param)); } void setup() { Serial.begin(115200); //Liaison à 115200bauds avec l’ordinateur (port 0) Serial1.begin(9600); // 9600bauds pour le drone (port 1) while (!Serial); // On vérifie que la liaison série est effectuée if (Usb.Init() == -1) { Serial.print(F("PAS DE LIAISON SERIE")); while (1); } Serial.print(F("INITIALISE")); //On peut commencer à communiquer } void loop() { Usb.Task(); if (PS3.PS3Connected) { […] if (getAnalogHat(L1) > 137 || getAnalogHat(L1) < 117) //valeur centrée : 127 { send_IMU(46, getAnalogHat(L1)) //YAW(46) = valeur joystick } […] // On vérifie si la mémoire contient un rapport if (Serial1.available() > 0) { if (Serial1.read() == 59) // 59 correspond à ';' (remplacé par 3 fois 10 (triple retour à la ligne)) { Serial1.readBytes(buffer, 34); //on enregistre 34 caractères dans le buffer (tampon) Serial.print('@');// séparateur de début de rapport for (int j = 0; j < 34; j++) { Serial.print(byte(buffer[j]), DEC); Serial.print("-"); } } ANNEXE 3 : Aperçu de l’interface graphique Contrôles « compteur » (voir ci-dessous) Contrôles « barres de progression » Espace « debug » Contrôles « Chart » ANNEXE 3.5 : Code du contrôle « compteur » (VB.NET) Public Function SetVal(ByVal cible As Panel, ByVal value As Integer) pan = cible.Width target = cible.CreateGraphics target.ResetTransform() target.Clear(Color.White) target.TranslateTransform(pan / 2, pan / 2) target.RotateTransform(50) target.RotateTransform(value) target.FillEllipse(Brushes.Black, New Rectangle(-pan / 2, -pan / 2, pan, pan)) target.FillEllipse(Brushes.White, New Rectangle(-pan / 2 + 2, -pan / 2 + 2, pan - 4, pan - 4)) target.FillEllipse(Brushes.SteelBlue, New Rectangle(-pan / 4, -pan / 4, pan / 2, pan / 2)) target.FillEllipse(Brushes.White, New Rectangle(-pan / 8, -pan / 8, pan / 4, pan / 4)) target.FillEllipse(Brushes.Navy, New Rectangle(-pan / 20, -pan / 20, pan / 10, pan / 10)) target.FillRectangle(Brushes.Navy, New Rectangle(-pan / 100, 0, pan / 50, pan / 3)) End Function ANNEXE 4 : Extraits du code d’acquisition (VB.net) a. Déclaration du port série Try s.Close() s.PortName = "com13" s.BaudRate = 115200 s.DataBits = 8 s.ReadTimeout = 1000 s.Parity = Parity.None s.StopBits = StopBits.One s.Handshake = Handshake.None s.Encoding = System.Text.Encoding.Default s.Open() s.RtsEnable = True Label1.Text = "Drone connecté" Label1.ForeColor = Color.Green ''Timer1.Start() Catch ex As Exception Label1.Text = "Erreur de com." Label1.ForeColor = Color.Red End Try For k As Integer = 1 To 20 Chart1.Series(0).Points.Add(Math.Sin(k)) Chart2.Series(0).Points.Add(Math.Sin(k)) Chart2.Series(1).Points.Add(Math.Sin(k + 4)) Next End Try b. Interprétation du rapport de statut 7) Dim Roll As Double '' Les 3 en degrés - 2 octets 8) Dim Pitch As Double 9) Dim Yaw As Double 10) 11) Dim Altitude As Integer '' En cm - 2o 12) Dim Frequence As Double '' 3o 13) Dim CPU_use As Integer '' 1o 14) Dim cmd_received As Integer '' 3o 15) Dim cmd_sent As Integer '' 3o 16) Dim eventscount As Integer ''4o 17) Dim timers As Integer ''4o 18) Dim events_overflow As Integer ''4o 19) Dim warning As Integer ''2o 20) Dim mu As Integer ''2o 21) 22) Dim motor1 As Integer 23) Dim motor2 As Integer 24) Dim motor3 As Integer 25) Dim motor4 As Integer Try Dim msg As String = s.ReadExisting If msg.Length > 0 Then TextBox1.Text = msg params = msg.Split("-") If params(0) = "@" And params(50) = "#" Then Pitch = CInt(params(1)) * 256 + CInt(params(2)) Roll = CInt(params(3)) * 256 + CInt(params(4)) Yaw = CInt(params(5)) * 256 + CInt(params(6)) Altitude = CInt(params(7)) * 256 + CInt(params(8)) motor1 motor2 motor3 motor4 = = = = CInt(params(9)) CInt(params(10)) CInt(params(11)) CInt(params(12)) Frequence = CInt(params(13)) * 65536 + CInt(params(14)) * 256 + CInt(params(15)) CPU_use = CInt(params(16)) cmd_received = CInt(params(18)) * 65536 + CInt(params(18)) * 256 + CInt(params(19)) cmd_sent = CInt(params(20)) * 65536 + CInt(params(21)) * 256 + CInt(params(22)) eventscount = CInt(params(23)) * 16777216 + CInt(params(24)) * 65536 + CInt(params(25)) * 256 + CInt(params(26)) timers = CInt(params(27)) * 16777216 + CInt(params(28)) * 65536 + CInt(params(29)) * 256 + CInt(params(30)) events_overflow = CInt(params(31)) * 16777216 + CInt(params(32)) * 65536 + CInt(params(33)) * 256 + CInt(params(34)) warning = CInt(params(35)) * 256 + CInt(params(36)) mu = CInt(params(37)) * 256 + CInt(params(38)) Label23.Text Label22.Text Label21.Text Label27.Text Label28.Text Label31.Text Label32.Text Label36.Text Label37.Text Label38.Text = = = = = = = = = = warning.ToString Frequence.ToString + "Hz" CPU_use.ToString cmd_received.ToString cmd_sent.ToString eventscount.ToString events_overflow (Roll / 65535.0 * 360).ToString (Pitch / 65535.0 * 360).ToString (Yaw / 65535.0 * 360).ToString ''Label49.Text = params(1) ''SI MOTOR ENABLED Label43.Text = motor1.ToString Label44.Text = motor2.ToString Label45.Text = motor3.ToString Label46.Text = motor4.ToString Panel15.Size Panel16.Size Panel17.Size Panel18.Size = = = = New New New New Point(motor1, Point(motor2, Point(motor3, Point(motor4, 20) 20) 20) 20) SetVal(Panel25, CPU_use, Brushes.LimeGreen) SetVal(Panel24, Frequence / 65793, Brushes.LimeGreen) SetVal(Panel1, SetVal(Panel4, SetVal(Panel5, SetVal(Panel6, motor1, motor2, motor3, motor4, Brushes.SteelBlue) Brushes.SteelBlue) Brushes.SteelBlue) Brushes.SteelBlue) Label49.Text = params(39).ToString ''39 Panel3.Width = params(46) Panel9.Width = params(47) Panel7.BackColor = Color.FromArgb(params(42) * 255, 0, 0) Panel11.BackColor = Color.FromArgb(params(43) * 255, 0, 0) Panel12.BackColor = Color.FromArgb(params(44) * 255, 0, 0) Panel13.BackColor = Color.FromArgb(params(45) * 255, 0, 0) Chart1.Series(0).Points.Add(params(48)) Chart2.Series(0).Points.Add(params(49)) If Chart1.Series(0).Points.Count > 100 Then Chart1.Series(0).Points.RemoveAt(0) Chart2.Series(0).Points.RemoveAt(0) End If End If End If Catch ex As TimeoutException Catch ex As Exception End Try ANNEXE 5: Drone complet