23/01/2012 RAPPORT DE PRT. MIQ 5 Le Roux Nicolas



Documents pareils
µrv : Realité Virtuelle

La visio-conférence holographique : Pourquoi? Comment?

I. Introduction aux fonctions : les fonctions standards

Sommaire. Leap motion Technologie Fonctionnement Langages utilisés Possibilités d utilisation... 4

ARDUINO DOSSIER RESSOURCE POUR LA CLASSE

SHERLOCK 7. Version du 01/09/09 JAVASCRIPT 1.5

Le langage C. Séance n 4

Cahier des charges. driver WIFI pour chipset Ralink RT2571W. sur hardware ARM7

TP n 2 Concepts de la programmation Objets Master 1 mention IL, semestre 2 Le type Abstrait Pile

Seance 2: En respectant la méthode de programmation par contrat, implémentez les autres fonctions de jeu.

Nb. De pages : 24 MANGO. Manuel d'utilisation. Version 1.2. décembre 2010

1 Gestionnaire de Données WORD A4 F - USB / / 6020 Alco-Connect

Plan du cours. Historique du langage Nouveautés de Java 7

Installation et prise en main

Sommaire. Bertrand PECUCHET

Rapport projet MMI. Luis Domingues, I3 Naomi Favre, I3 Tiago De Deus, I3. Luis Domingues, Tiago De Deus, Naomi Favre SP Interfaces Multimodales

Interface PC Vivago Ultra. Pro. Guide d'utilisation


HMI target Visu / PLC HMI. Pour réaliser une interface homme machine avec PLC control

Livre blanc Mesure des performances sous Windows Embedded Standard 7

DA MOTA Anthony - Comparaison de technologies : PhoneGap VS Cordova

TD/TP 1 Introduction au SDK d Android

Working with Kinect. Intelligence Ambiante. Tomás DÍAZ TRONCOSO Arturo GARCÍA TOVAR Daoud MAROUAN LMTIUI

INITIATION AU LANGAGE C SUR PIC DE MICROSHIP

A- Observez la vidéo A présentant le fonctionnement de deux objets techniques que nous

Qui ont toujours à mon côté pour me soutenir et me guider au long de ce projet.

Conservation des documents numériques

Programmation système I Les entrées/sorties

Le langage C++ est un langage de programmation puissant, polyvalent, on serait presque tenté de dire universel, massivement utilisé dans l'industrie

Logiciel EV3 LEGO MINDSTORMS Education

Travaux pratiques. Compression en codage de Huffman Organisation d un projet de programmation

MASTER 2 INFORMATIQUE - UNIVERSITE DE FRANCHE-COMTE. Projet Kinect. Détection de mouvements intempestifs dans un bloc opératoire

1. Structure d un programme C. 2. Commentaire: /*..texte */ On utilise aussi le commentaire du C++ qui est valable pour C: 3.

IN Cours 1. 1 Informatique, calculateurs. 2 Un premier programme en C

CARPE. Documentation Informatique S E T R A. Version Août CARPE (Documentation Informatique) 1

Annexe : La Programmation Informatique

Projet Robot Centaure

Utilisation du logiciel GALAAD

Traitement numérique de l'image. Raphaël Isdant

ACTIVITÉ DE PROGRAMMATION

Utilisation du visualiseur Avermedia

Utilisation de la Kinect

COMMUNICATION PC/MINITEL

Système de vidéoconférence avec périphériques

PRECAUTIONS DESCRIPTION DU PRODUIT

Algorithmique et Programmation, IMA

Introduction au langage C


GS301-A Notice d installation et d utilisation.

Introduction à MATLAB R

Ladibug TM 2.0 Logiciel de présentation visuel d'image Manuel de l utilisateur - Français

LES CARTES À POINTS : POUR UNE MEILLEURE PERCEPTION

Généralités sur le Langage Java et éléments syntaxiques.

Compression de Données - Algorithme de Huffman Document de Conception

LES TOUT PREMIERS PAS

I00 Éléments d architecture

Éléments d'architecture des ordinateurs

Bases de programmation. Cours 5. Structurer les données

"! "#$ $ $ ""! %#& """! '& ( ")! )*+

Documentation utilisateur, manuel utilisateur MagicSafe Linux. Vous pouvez télécharger la dernière version de ce document à l adresse suivante :


Sharpdesk V3.3. Guide d installation Push pour les administrateurs système Version

Chapitre 4 Pierre, papier, ciseaux

Notions fondamentales du langage C# Version 1.0

Télécom Nancy Année

1 INSTALLATION DU LOGICIEL CGVCAM Télécharger et installer le logiciel Démarrer le logiciel 5 2 PRESENTATION DU LOGICIEL CGVCAM 5

Documentation utilisateur. [EIP] TransLSF

MODE D EMPLOI LOGICIEL DE PILOTAGE CROIX SMART 5.0

VTigerCRM. CRM : Logiciel de gestion des activités commerciales d'une (petite) entreprise

1/24. I passer d un problème exprimé en français à la réalisation d un. I expressions arithmétiques. I structures de contrôle (tests, boucles)

Start me quick! Français

JUPITER /20/27/61m. Contact NF, 50mA à 24v max. avec R50 Ohms en série

PRODIGE V3. Manuel utilisateurs. Consultation des métadonnées

Compte-rendu de projet de Système de gestion de base de données

L'USB et Windows XP. Tout d'abord, il faut connaître un peu de vocabulaire pour s'y retrouver par la suite :

Matériel informatique (hardware)

HP Data Protector Express Software - Tutoriel 3. Réalisation de votre première sauvegarde et restauration de disque

Stockage du fichier dans une table mysql:

De l automatisme à la domotique...

Pour les futurs développeurs Sommaire

as Architecture des Systèmes d Information

But de cette présentation

Dossier projet isn 2015 par Victor Gregoire

Premiers pas avec NetSupport SCHOOL

Introduction à la programmation orientée objet, illustrée par le langage C++ Patrick Cégielski

Manuel d'utilisation de la maquette

DETERMINER LA LARGEUR DE PAGE D'UN SITE et LES RESOLUTIONS d'ecran

L'émulateur multi-système

1. Introduction Création d'une macro autonome Exécuter la macro pas à pas Modifier une macro... 5

Utilisation et création de la clé USB OSCAR

Tutorial Terminal Server sous

TRAAM STI Acquisition et exploitations pédagogiques des données sur un système pédagogique

Programmer en JAVA. par Tama

LOGICIEL KIPICAM : Manuel d installation et d utilisation

Cours Programmation Système

OPTENET DCAgent Manuel d'utilisateur

Dossier technique. Présentation du bus DMX et Utilisation des options EL13 / EL14 ERM AUTOMATISMES INDUSTRIELS 1 LE PROTOCOLE DMX 2

Retrouver de vieux programmes et jouer sur VirtualBox

Virtual PC Virtual PC 2007 Page I

Transcription:

23/01/2012 RAPPORT DE PRT MIQ 5 Le Roux Nicolas

Remerciement Je tiens avant tout à remercier Monsieur Kiefer, maitre de conférence à l'institut National des Sciences Appliquées de Strasbourg, pour avoir proposé un sujet de projet de recherche technologique aussi intéressant et enrichissant que la commande d'un drone par un module kinect ainsi que pour l'aide apportée durant le développement. Je remercie ensuite Monsieur Vedrines, responsable de la spécialité mécatronique, pour m'avoir laissé l'opportunité de travailler sur ce projet. Je remercie enfin mon camarade de génie électronique, Etienne Jaillot, pour avoir partagé mon travail sur le module kinect. Résumé Etudiant en 5 ème année dans la section mécatronique du département mécanique de l'institut National des Sciences Appliquées de Strasbourg, j'ai effectué mon projet de recherche technologique sur le module kinect. La kinect est un périphérique de control ne nécessitant pas de manette. Il utilise pour cela la détection du corps humain via des capteurs 3 dimensions afin de déterminer sa position dans l'espace à l'aide une vingtaine de points d'intérêts (mains, coudes, épaules, genoux,...). L'objectif principal du projet est de mettre en œuvre un programme permettant de contrôler un drone en utilisant la détection du mouvement des bras de l'utilisateur par le biais d'un module kinect. La commande du drone habituellement réalisée par une radiocommande se voit donc remplacée par la kinect. Figure 1 : La Kinect

Sommaire Remerciement... 2 Sommaire... 3 Table des illustrations... 4 I. Présentation du projet... 4 1. Les objectifs... 4 2. La kinect... 4 3. Avantages et inconvénients... 6 II. Cahier des charges... 6 III. La commande de haut niveau... 7 IV. Le code... 8 1. Recherche de l'existant... 8 2. Prémices... 8 3. Les linkers/includes... 9 4. Code pour la kinect... 10 5. Code pour détection des mouvements... 13 6. Code pour la communication RS232... 18 V. Mise en œuvre des tests... 22 VI. Conclusions... 22 VII. Bibliographie... 23 1. Fonctionnement de la Kinect... 23 2. Développement du code pour la Kinect... 23 3. Développement du code pour la communication RS232... 23 VIII. Annexes... 24 1. Les caractéristiques techniques... 24

Table des illustrations Figure 1 : La Kinect... 2 Figure 2 : Les capteurs de la kinect... 5 Figure 3 : Lumière infrarouge projeté par la kinect... 5 Figure 4 : GANT du PRT... 6 Figure 5 : Linkers & Includes... 9 Figure 6 : Additionnal Dependancies... 10 Figure 7 : Interface de programmation de la kinect (API)... 11 Figure 8 : Repère kinect... 14 Figure 9 : Repère associé au buste... 14 Figure 10 : Point d'intérêt pour le pilotage... 15 Figure 11 : Les caractéristiques techniques... 24 I. Présentation du projet 1. Les objectifs L'objectif du projet de recherche technologique sur la kinect est de développer un code d'interfaçage entre le module Kinect et la commande Xbee du drone de manière à pourvoir envoyer des ordres de pilotage de haut niveau par détection des mouvements des bras. Ce module kinect à donc pour visée de se substituer au pilotage standard par radiocommande. 2. La kinect La kinect, initialement connu sous le nom de code Project Natal est un périphérique destiné à la console de jeux vidéo Xbox 360 permettant de contrôler ces derniers sans utiliser de manette. Suite aux multiples hacks (et tentatives de hacks) de ce périphérique dans le but de le porter sur ordinateur, Microsoft a dévoilé le 17 Juin 2011 la sortie du kit de développement officiel (Microsoft kinect SDK). Avec la sortie du SDK aujourd hui, nous sommes impatients de voir une autre vague de créativité de la part des chercheurs universitaires, des développeurs et des passionnés, dans des domaines bien au-delà du jeu et du divertissement, alors que nous apportons interface utilisateur naturelle (NUI) de développement à tous. Microsoft Au niveau technologique, ce périphérique de Microsoft est constitué d'un ensemble de capteur (barre horizontale) connectée à une base via un moteur. L'ensemble peut donc effectuer des mouvements de haut en bas (27 ) afin d'adapter la perception de la caméra en fonction de la position des utilisateurs dans la pièce. La kinect se compose de plusieurs éléments permettant d'améliorer l'analyse des mouvements par rapport à de simple caméra (comme EyeToyde chez Sony): multi-microphones caméra RGB 3D depth sensor

Figure 2 : Les capteurs de la kinect La principale nouveauté de cette caméra est le capteur de profondeur (3D depth sensor). Basé sur la technologie caméra portée conçue par la société israélienne PrimeSense, la kinect utilise un projecteur de lumière structurée et un système de capteurs IR (infrarouge) largement répandu dans les procédés de fabrication industrielle. La détection de la lumière structurée se fait grâce à l angle spécifique qui existe entre l'émetteur et le capteur, la profondeur peut être récupérée par de la simple triangulation. Figure 3 : Lumière infrarouge projeté par la kinect La lumière structurée est composé de 9 blocs avec un modèle spécifique semi-aléatoire de points à l'intérieur. Cette structure se répète à travers les blocs, et cette tendance résulte d'une structure holographique du point lumineux dans le centre de chaque bloc. La structure a été conçue pour être sphérique (forme sinueuse sur les bordures). Cette grille de projection définit le champ de vision du capteur Kinect, à savoir 43 degré pour l axe verticale et 57 degré pour l axe horizontale le tout pour une portée du capteur de 1,2 mètre à 3,5 mètres.

La distance entre les points à l'intérieur de la grille détermine la résolution spatiale du capteur de profondeur (320 240 en couleur 16 bits à 30 image par seconde et de 640 480 en couleur 32 bits à 30 image/sec). 3. Avantages et inconvénients L'avantage d'utiliser un module kinect pour la commande du drone est, à priori, de rendre le produit plus attractif et ludique. En effet, le nombre important de d'élément de la radiocommande peut paraitre rébarbatif pour certains utilisateurs. Cependant, l'utilisation de ce type d'appareil impose de multiples contraintes : La nécessité de disposer d'une source d'alimentation secteur La présence d'un ordinateur afin de traiter l'ensemble de données La présence de soleil perturbant fortement les mesures du capteur de profondeur L'utilisation de cet appareil se limite donc à priori à des manipulations en intérieur dans une zone où le soleil ne perturbe pas les mesures effectuées par la kinect. II. Cahier des charges Le cahier des charges de ce PRT définit l'ensemble des éléments indispensables que doit contenir le projet. A savoir : Mettre en place des mouvements de commande intuitifs qui permettent de facilement contrôler le drone. Rester ciblé sur le pilote et ce même si un autre individu entre dans le champ visuel de la kinect Envoyer les données sous la forme d'une trame semblable à celle de la radiocommande Créer un mode de sécurité en cas de problème (disparition du pilote, mouvement aberrants ou non souhaité) Une fois le cahier des charges mise en place, il était nécessaire de définir un planning des tâches dans le but de surveiller l'avancement du projet. Figure 4 : GANT du PRT

Finalement, ce planning a été plutôt bien respecté dans l'ensemble. Les objectifs principaux du projet étant remplis dans les temps. Le seul bémol se situe au niveau de la préparation du drone puisque il aurait été souhaitable de réaliser une démonstration de vol stationnaire commandé via la kinect. Tâche qui nécessite obligatoirement un asservissement en altitude robuste sur le drone, ce qui n'est malheureusement pas encore le cas. III. La commande de haut niveau La recherche de commande de haut niveau intuitive permettant de rapidement prendre en main le pilotage est un point essentiel de ce PRT. Le but de la kinect est de faire disparaitre la nécessitée d'avoir une manette mais pas seulement physiquement, il faut donner à l'utilisateur l'impression qu'il agit directement avec son corps sur l'objet d'intérêt afin d'améliorer l'expérience de pilotage en rendant la commande plus intuitive. De plus, l'utilisateur n'ayant aucun objet en main, la probabilité de perdre conscience qu'il est en train de piloter, à cause de perturbation extérieur, est plus élevée qu'avec une radiocommande. Les mouvements autres que le pilotage (se gratter, fouiller ces poches,...) ne doivent surtout pas être interprétés comme des consignes émissent par l'utilisateur. Nonobstant le fait que les mouvements doivent être référencés par rapport à l'utilisateur et non pas par rapport à l'espace de travail afin que ce dernier soit libre de se déplacer sans que ces mouvements ne soient interprétés comme des consignes. Parmi les nombreux choix de commande existant, très peu parviennent à satisfaire l'ensemble des critères mentionnés plus haut. La commande finalement retenue revient à contrôler le drone comme si l'utilisateur le tenait entre ses mains. Si les mains du pilote sont à dans un certain intervalle de distance, l'utilisateur "tient" le drone et peut donc le déplacer (le piloter). Si ces mains sont trop éloignées, l'utilisateur ne "tient" pas le drone, les mouvements réalisés par ce dernier ne doivent pas être interprétés comme des consignes. Le problème posé par ce choix de commande est de savoir où se localise la zone de non déplacement et par rapport à quoi la référencer. Pour la référencer, c'est le buste qui a été choisi, en effet, il ne bouge pas (ou peu) durant le mouvement des bras. De plus, quand l'utilisateur se déplace dans l'espace de travail, il n'existe pas (ou presque pas) de mouvement entre les bras et le buste. Il reste maintenant le problème de la localisation (la position zéro). La solution la plus pratique est de laisser l'utilisateur la définir, ainsi, il doit positionner la position zéro au début du programme et peut ensuite, s'il le souhaite, la modifier en cours de fonctionnement. Le placement de cette référence s'effectue simplement en tapant dans les mains. L'avantage de pouvoir replacer la référence de la position zéro durant le pilotage est de diminuer le risque de problème tels que la perte de la référence du point de vue de l'utilisateur. En ce qui concerne le détaille de la mise en œuvre du code nécessaire à cette détection de mouvement, il sera détaillé dans la partie code du rapport.

IV. Le code Après avoir définit de façon plus précise les mouvements de commande à détecter, cette seconde partie va s'orienter vers la réalisation du code permettant cette détection. Ainsi que sur le code nécessaire à l'émulation de la radiocommande. 1. Recherche de l'existant Avant tout, afin de ne pas perdre de temps dans la mise en œuvre du code spécifique à la commande du drone, une recherche de l'existant (code ou tutoriel) a été effectuée. Peu de codes existent sur internet pour la kinect (encore trop récente) et presque aucun ne remplissent toutes les conditions souhaitées (même langage, même compilateur, code suffisamment commenté,...). Finalement, c'est un tutoriel trouvé par Etienne Jaillot qui aura permit un gain de temps précieux. En ce qui concerne la communication RS232 avec les modules Xbees, un tutoriel de qualité détaillant point par point l'ensemble des lignes de code nécessaires a été trouvé facilement sur internet. Les explications détaillant le fonctionnement des codes kinect et communication RS232 sont tirées des tutoriels trouvés sur internet. La seul valeur ajoutée vient des éclaircissements sur les problèmes et points noirs rencontrés durant le développement du code. 2. Prémices Avant de pouvoir réellement commencer le code, il est nécessaire d'installer plusieurs programmes et de vérifier les compatibilités matériels. Au niveau hardware, il faut au minimum: Un processeur de 32 ou 64 bits Un processeur dual-core 2,66GHz Un bus USB2 dédier 2GB de RAM Au niveau software, il faut installer : Microsoft Visual studio 2010.NET Framework 4.0 Microsoft Kinect SDK En ce qui concerne le logiciel de développement, il est fortement conseillé d'utiliser Microsoft Visual studio 2010 et ce pour plusieurs raisons : La librairies Kinect SDK a été créée pour fonctionner avec ce logiciel de développement Les exemples de fonctionnement, les tutoriels et les aides en lignes sont presque toute faite pour ce logiciel de développement Les éclaircissements apportés par ce document sont en majorités fait sous Microsoft Visual studio 2010

3. Les linkers/includes La mise en place des linkers est un des points noirs du tutoriel et sans ces derniers, rien ne fonctionne. Un temps précieux a été perdu sur cette partie durant le développement du code et c'est pour cela qu'une partie entière leurs a été consacrée. Dans un premier temps, il faut indiquer les chemins des librairies statiques et dynamiques de la kinect. Include Directories : $(MSRKINECTSDK)\inc;$(IncludePath) Librairy Directories : $(MSRKINECTSDK)\lib;$(LibraryPath) Figure 5 : Linkers & Includes Puis, dans Additionnal Dependancies : MSRKinectNUI.lib

Figure 6 : Additionnal Dependancies Et enfin, pour terminer, il ne faut pas oublier d'inclure au début du programme : #inclure "windows.h" 4. Code pour la kinect La kinect est capable de traquer 20 points d'intérêts par corps. Pour pouvoir traquer ces points, il faut dans un premier temps préciser le drapeau NUI_INITIALIZE_FLAG_USES_SKELETON (utilisation du mode squelette de la kinect) lors de l initialisation du runtime (le temps durant lequel s'exécute le programme, ou fonctionnement normal) de la Kinect lors de l appel à la méthode NuiInitialize (méthode d'initialisation). Puis, il faut déclarer et créer un manual reset event, qui servira au runtime Kinect pour nous signaler la présence d une nouvelle trame que nous utiliserons par la suite en conjonction avec l API (l'interface de programmation). WaitForSingleObject HANDLE _skeleton; _skeleton = CreateEvent( NULL, TRUE, FALSE, NULL ); Ensuite nous démarrons la détection du Squelette avec l API NuiSkeletonTrackingEnable, en lui passant comme paramètre le HANDLE (pointeur d'objet utilisé dans plusieurs programme) de l évènement précédemment crée. hr = NuiSkeletonTrackingEnable( _skeleton, 0 );

Figure 7 : Interface de programmation de la kinect (API) Le second paramètre est ignoré dans la version actuelle du runtime. Pour désactiver la détection du squelette, il suffit d utiliser l API NuiSkeletonTrackingDisable. Pour capturer une trame du squelette, nous utiliserons l API NuiSkeletonGetNextFrame en mode polling (appel en boucle) dans une boucle de la manière suivante : NuiSkeletonGetNexFrame, prend un pointeur sur la structure NUI_SKELETON_FRAME, structure qui contiendra les données de la trame envoyée par Kinect. C est à partir de cette structure que nous allons pouvoir déterminer si un ou plusieurs squelettes ont été détectés comme nous le verrons par la suite. NUI_SKELETON_FRAME SkeletonFrame; hr = NuiSkeletonGetNextFrame( 0, &SkeletonFrame ); Le 1er paramètre est un délai d attente exprimé en milliseconde avant le retour sans trame de la fonction. Ce qui nous intéresse dans notre exemple avec la structure NUI_SKELETON_FRAME, c est qu elle contient un tableau de structures nommé SkeletonData de NUI_SKELETON_DATA réglé au nombre de NUI_SKELETON_COUNT (Constante définie à 6 squelettes). typedef struct _NUI_SKELETON_FRAME { LARGE_INTEGER litimestamp; DWORD dwframenumber; DWORD dwflags; Vector4 vfloorclipplane; Vector4 vnormaltogravity;

NUI_SKELETON_DATA SkeletonData[NUI_SKELETON_COUNT]; NUI_SKELETON_FRAME; C est ce tableau de structures que nous allons manipuler afin de retrouver l index ou les index des squelettes détectés par kinect. Pour ce faire, il suffit de boucler sur le nombre NUI_SKELETON_COUNT et tester si l état du squelette etrackingstate est détecté ou pas. for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ) { if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) { //code omis pour plus de clarté Une fois que le squelette est détecté, nous allons traquer, les 20 points ou jointures du squelette. La structure NUI_SKELETON_DATA contient elle-même un tableau SkeletonPositions de Vector4 de NUI_SKELETON_POSITION_COUNT (Constante définie sur 20). typedef struct _NUI_SKELETON_DATA { NUI_SKELETON_TRACKING_STATE etrackingstate; DWORD dwtrackingid; DWORD dwenrollmentindex; DWORD dwuserindex; Vector4 Position; Vector4 SkeletonPositions[NUI_SKELETON_POSITION_COUNT]; NUI_SKELETON_POSITION_TRACKING_STATE eskeletonpositiontrackingstate[nui_skeleton_position_count]; DWORD dwqualityflags; NUI_SKELETON_DATA; Par exemple si nous souhaitons traquer les mains il suffit d utiliser les index NUI_SKELETON_POSITION_HAND_RIGHT et NUI_SKELETON_POSITION_HAND_LEFT. for( int i = 0 ; i < NUI_SKELETON_COUNT ; i++ ) { if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) { Vector4 maindroite=skeletonframe.skeletondata[i].skeletonpositions [NUI_SKELETON_POSITION_HAND_RIGHT] Vector4 maingauche = SkeletonFrame.SkeletonData[i].SkeletonPositions [NUI_SKELETON_POSITION_HAND_LEFT]

Et ainsi de suite pour chacun des éléments du corps que l'on souhaite détecter. Pour résumer, le code minimum que doit contenir le programme est le suivant : //Variables de calcul float distancemain = 0; //Variable retournant infos fonctions HRESULT hr; Vector4 maindroite, maingauche, centrebuste, positionjoystick, positionjoystickoffset; //Initialisation des offsets positionjoystickoffset.x = 0; positionjoystickoffset.y = 0; positionjoystickoffset.z = 0; //Event afin de signaler la présence d'une nouvelle trame HANDLE _skeleton; _skeleton = CreateEvent( NULL, TRUE, FALSE, NULL ); //Structure contenant les données envoyé par la kinect NUI_SKELETON_FRAME SkeletonFrame; //Initialisation hr = NuiInitialize(NUI_INITIALIZE_FLAG_USES_SKELETON); hr = NuiSkeletonTrackingEnable( _skeleton, 0 ); //*** Boucle principale *** while(1){ hr = NuiSkeletonGetNextFrame( 0, &SkeletonFrame ); if( SkeletonFrame.SkeletonData[0].eTrackingState == NUI_SKELETON_TRACKED ) { //Récupération des coordonnées des points d'intérêts du pilote uniquement maindroite = SkeletonFrame.SkeletonData[0].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT]; maingauche = SkeletonFrame.SkeletonData[0].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT]; //Désactivation du tracking et fermeture NuiSkeletonTrackingDisable; NuiShutdown(); 5. Code pour détection des mouvements En ce qui concerne la détection des mouvements de l'utilisateur, on commence par récupérer la position des points d'intérêts de ce dernier, à savoir la main droite, la main gauche et le centre du buste. Ces données sont référencées par rapport au repère caméra dont l'origine est au centre de la focale.

Figure 8 : Repère kinect //Récupération des coordonnées des points d'intérêts maindroite = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT]; maingauche = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT]; centrebuste = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_CENTER]; On effectue ensuite un changement de repère afin de référencer les mains de l'utilisateur par rapport au centre de son buste. Figure 9 : Repère associé au buste //Changement de repère pour les coordonnées des mains (par rapport au centre du buste) maindroite.x = maindroite.x - centrebuste.x;

maindroite.y = maindroite.y - centrebuste.y; maindroite.z = maindroite.z - centrebuste.z; maingauche.x = maingauche.x - centrebuste.x; maingauche.y = maingauche.y - centrebuste.y; maingauche.z = maingauche.z - centrebuste.z; Ensuite, on calcule la distance euclidienne séparant les deux mains de l'utilisateur. //Calcul de la distance entre les mains (simple norme euclidienne) distancemain = fabs( sqrt( pow( maindroite.x - maingauche.x, 2) + pow( maindroite.y - maingauche.y, 2) + pow( maindroite.z - maingauche.z, 2) ) ); Puis, on calcul les coordonnées du point situé au milieu de la droite liant les deux mains. Figure 10 : Point d'intérêt pour le pilotage //Calcul des coordonnées du point entre les mains positionjoystick.x = maindroite.x - sqrt( pow( maindroite.x - maingauche.x, 2) ); positionjoystick.y = maindroite.y - sqrt( pow( maindroite.y - maingauche.y, 2) ); positionjoystick.z = maindroite.z - sqrt( pow( maindroite.z - maingauche.z, 2) ); Si la distance entre les deux mains est inférieur à une distance défini, on considère que l'utilisateur frappe dans ses mains souhaitant réaliser le réglage des offsets. La position courante au centre des mains est alors enregistrée comme position de référence. De plus, un booléen réglageoffset impose à l'utilisateur le réglage de l'offset avant la première utilisation. //Si la distance entre les mains est inférieur à 20cm, on fait les offsets if( distancemain <= 0.20 ){ cout << "Reglage des offsets" << endl;

positionjoystickoffset.x = positionjoystick.x; positionjoystickoffset.y = positionjoystick.y; positionjoystickoffset.z = positionjoystick.z; //Les offsets ont bien été effectués reglageoffset = TRUE; Sinon, l'utilisateur est dans la configuration de pilotage. Le programme calcul donc les données qu'il doit envoyer au drone en utilisant le tableau de caractère lpbuff qui correspond à la trame émulée de la radiocommande. Dans tout les autres cas, les mouvement de l'utilisateur ne sont pas pris en compte puisqu'il ne sont pas considérés comme des mouvements de pilotages. //Si la distance entre les mains est compris entre 30 et 5 cm, on envoie les commandes else if (distancemain <= 0.4 && reglageoffset){ //Données de la voix 0 (quadri: Tangage) (MicroD: NaN) lpbuff[2] = 1; //saturation_radiocommande( 100*(- positionjoystick.z + positionjoystickoffset.z), 0 ); //Données de la voix 1 (quadri: NaN) (MicroD: Gouverne Droite) lpbuff[3] = saturation_radiocommande( 100*(positionJoystick.y - positionjoystickoffset.y), 50 ); //Données de la voix 2 (quadri: mode manuel-100 / semi-auto-0) (MicroD: Moteur Droit) lpbuff[4] = 1; //Données de la voix 3 (quadri: Puissance) (MicroD: Moteur Gauche) lpbuff[5] = 1; //Données de la voix 4 (quadri: Roulis) (MicroD: Gouverne Gauche) lpbuff[6] = saturation_radiocommande( 100*(positionJoystick.x - positionjoystickoffset.x), 50 ); //Données de la voix 5 (quadri: Lacet) (MicroD: mode manuel-100 / semi-auto-0) lpbuff[7] = 100; //Données de la voix 6 (quadri: mode auto-100 / semi-auto-0) (MicroD: mode auto-100 / semi-auto-0) lpbuff[8] = 1; //Calcul du checksum lpbuff[9] = 0; for(i=0; i<9; i++){ lpbuff[9] += lpbuff[i]; Le code complet nécessaire à la détection des mouvements de pilotage de l'utilisateur se trouve ci-dessous. Ce dernier est un exemple utilisé uniquement dans le but de commander les gouvernes du drone orange. if( SkeletonFrame.SkeletonData[i].eTrackingState == NUI_SKELETON_TRACKED ) { //Récupération des coordonnées des points d'intérêts

maindroite = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_RIGHT]; maingauche = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_HAND_LEFT]; centrebuste = SkeletonFrame.SkeletonData[i].SkeletonPositions[NUI_SKELETON_POSITION_SHOULDER_CENTER] ; //Changement de repère pour les coordonnées des mains (par rapport au centre du //buste) maindroite.x = maindroite.x - centrebuste.x; maindroite.y = maindroite.y - centrebuste.y; maindroite.z = maindroite.z - centrebuste.z; maingauche.x = maingauche.x - centrebuste.x; maingauche.y = maingauche.y - centrebuste.y; maingauche.z = maingauche.z - centrebuste.z; //Calcul de la distance entre les mains (simple norme euclidienne) distancemain = fabs( sqrt( pow( maindroite.x - maingauche.x, 2) + pow( maindroite.y - maingauche.y, 2) + pow( maindroite.z - maingauche.z, 2) ) ); //Calcul des coordonnées du point entre les mains positionjoystick.x = maindroite.x - sqrt( pow( maindroite.x - maingauche.x, 2) ); positionjoystick.y = maindroite.y - sqrt( pow( maindroite.y - maingauche.y, 2) ); positionjoystick.z = maindroite.z - sqrt( pow( maindroite.z - maingauche.z, 2) ); //Si la distance entre les mains est inférieur à 5cm, on fait les offsets if( distancemain <= 0.20 ){ cout << "Reglage des offsets" << endl; positionjoystickoffset.x = positionjoystick.x; positionjoystickoffset.y = positionjoystick.y; positionjoystickoffset.z = positionjoystick.z; //Les offsets ont bien été effectués reglageoffset = TRUE; //Si la distance entre les mains est compris entre 30 et 5 cm, on envoie //les commandes else if (distancemain <= 0.4 && reglageoffset){ /*** Trame télécommande ***/ //! Octet de type d'une trame télécommande /*! Une telle trame est construite de la façon suivante : * <'@'> <'@'> <voie1:1> <voie2:1> <voie3:1> <voie4:1> <voie5:1> <voie6:1> * <voie7:1> <Checksum> * -> 10 octets * /!\ Ne pas mettre de 0 dans les trames car il est considéré comme un * octet de fin de trame (Non supprimable dans la réglage du port série * de l'ordi...) */ //Données de la voix 0 (quadri: Tangage) (MicroD: NaN) lpbuff[2] = 1; //Données de la voix 1 (quadri: NaN) (MicroD: Gouverne Droite) lpbuff[3] = saturation_radiocommande( 100*(positionJoystick.y -positionjoystickoffset.y), 50 ); //Données de la voix 2 (quadri: mode manuel-100 / semi-auto-0) (MicroD: //Moteur Droit) lpbuff[4] = 1; //Données de la voix 3 (quadri: Puissance) (MicroD: Moteur Gauche) lpbuff[5] = 1; //Données de la voix 4 (quadri: Roulis) (MicroD: Gouverne Gauche)

lpbuff[6] = saturation_radiocommande( 100*(positionJoystick.x - positionjoystickoffset.x), 50 ); //Données de la voix 5 (quadri: Lacet) (MicroD: mode manuel-100 / semi- //auto-0) lpbuff[7] = 100; //Données de la voix 6 (quadri: mode auto-100 / semi-auto-0) (MicroD: //mode auto-100 / semi-auto-0) lpbuff[8] = 1; //Calcul du checksum lpbuff[9] = 0; for(i=0; i<9; i++){ lpbuff[9] += lpbuff[i]; 6. Code pour la communication RS232 Le code de la communication RS232 fait le liens entre la détection des mouvement effectués par la kinect et l'émission des trames vissant à émuler la radiocommande. Dans un premier temps, il faut créer un HANDLE que l'on initialisera en appelant un CreateFile. Le première argument est le nom du fichier que l'on souhaite ouvrir. Dans notre cas, il s'agit d'un port série, il faut donc indiquer : "COM1", "COM2",... Ensuite, le second argument définit si l'on souhaite lire ou écrire sur le fichier (GENERIC_READ, GENERIC_WRITE). Les arguments 2 et 3 doivent être placé à zéro. L'argument 4 indique que l'on souhaite ouvrir un fichier existant, en effet, le port série existe si un appareil y est connecté. L'avant dernière argument stipule que nous ne voulons pas de fichier spécifique. Puis, enfin le dernier qui doit être placé à zéro. hserial = CreateFile ( TEXT("COM5"), GENERIC_READ GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); On vérifie ensuite la validité du port de communication série sélectionné et informe l'utilisateur des problèmes rencontrés (s'il y en a). if(hserial==invalid_handle_value){ if( GetLastError()==ERROR_FILE_NOT_FOUND ){ //serial port does not exist. Inform user //some other error occurred. Inform user. Dans cette partie, on commence par créer une variable contenant les paramètres du port série dcbserialparams. Une fois la variable créée, on définit les paramètres de notre port série (baudrate, taille des octets, bits de stop,...). Puis, on termine cette partie en associant ces nouveaux paramètres au port série.

C'est dans cette parti que ce situe un autre des points noir de la communication série. En effet, il est nécessaire de mettre en place un octet d'arrêt, dans notre cas l'octet choisi est l'octet 0. Quand cette octet apparait sur la trames, il stop l'émission de la dite trame, impliquant une coupure en plein milieu de celle-ci. Il existe certainement un mode permettant de ne pas avoir de bit de stop que je ne suis malheureusement pas parvenu à trouver. DCB dcbserialparams = {0; dcbserial.dcblength=sizeof(dcbserialparams); if (!GetCommState(hSerial, &dcbserialparams)) { //error getting state dcbserialparams.baudrate=cbr_19200; dcbserialparams.bytesize=8; dcbserialparams.stopbits=onestopbit; dcbserialparams.parity=noparity; if(!setcommstate(hserial, &dcbserialparams)){ //error setting serial port state De la même manière, on associe au port série des timeouts entre les intervalles de lecture/écriture afin que l'ordinateur n'attende pas éternellement la réception. COMMTIMEOUTS timeouts={0; timeouts.readintervaltimeout=50; timeouts.readtotaltimeoutconstant=50; timeouts.readtotaltimeoutmultiplier=10; timeouts.writetotaltimeoutconstant=50; timeouts.writetotaltimeoutmultiplier=10; if(!setcommtimeouts(hserial, &timeouts)){ //error occureed. Inform user Finalement, on déclare une chaine de caractère que l'on peut lire ou écrire à notre guise (Pour l'écriture il suffit simplement de remplacer!readfile par!writefile. Cette chaine est envoyée une seul fois et il est donc nécessaire de la placer dans une boucle qui l'enverra à une fréquence régulière. char szbuff[n + 1] = {0; DWORD dwbytesread = 0; if(!readfile(hserial, szbuff, n, &dwbytesread, NULL)){ //error occurred. Report to user. Pour résumer, le code global de la communication RS232 dans le but d'émuler la radiocommande se trouve ci-dessous. Un timeout supplémentaire a été ajouté afin de permettre l'envoie des données à une fréquence spécifiée dans le programme.

//Envoi des données toutes les 50 ms (600 ms pour le timeout com carte mère); #define TIMEOUT_COMMUNICATION 50 int _tmain(int argc, _TCHAR* argv[]) { HANDLE hserial; //Variables définissant les timeouts clock_t timeout_com; char i; char szbuff[10 + 1]= {0; char lpbuff[10 + 1] = {0; DWORD dwbytesread = 0; DWORD dwbyteswrite = 0; //Initialisation de l'envoi de donnée timeout_com = clock(); //Emulation de la trame télécommande lpbuff[0] = '@'; lpbuff[1] = '@'; lpbuff[2] = 1; lpbuff[3] = 2; lpbuff[4] = 3; lpbuff[5] = 4; lpbuff[6] = 5; lpbuff[7] = 110; lpbuff[8] = 7; //Calcul du cheksum lpbuff[9] = 0; for(i=0; i<9; i++){ lpbuff[9] += lpbuff[i]; //Initialisation du port série hserial = CreateFile (TEXT("COM5"), //Choix du port GENERIC_READ GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(hserial==invalid_handle_value){ if(getlasterror()==error_file_not_found){ //serial port does not exist. Inform user. cout << "Pas de port com" << endl; //some other error occurred. Inform user. cout << "Erreur" << endl; //Déclaration de la structures des paramètres de réglage du port série DCB dcbserialparams = {0; //Déclaration de la taille, une étrangeté de windows dcbserialparams.dcblength=sizeof(dcbserialparams); //On associe le port série (hserial) avec notre structure de paramètres de //réglage (dcbserialparams) if (!GetCommState(hSerial, &dcbserialparams)) { //error getting state

//Réglage des paramètres du port série dcbserialparams.baudrate=cbr_115200; dcbserialparams.bytesize=8; dcbserialparams.stopbits=onestopbit; dcbserialparams.parity=noparity; //On applique ensuite ces paramètres au port série if(!setcommstate(hserial, &dcbserialparams)){ //error setting serial port state /* Afin de ne pas bloquer le programme sur une attente de réception, * on demande au programme de ne pas attendre les données. Pour ce faire, * on utilise la structure : COMMTIMEOUTS */ COMMTIMEOUTS timeouts={0; // Le temps (en ms) entre 2 caractère avant l'arret de la réception timeouts.readintervaltimeout=maxdword; // Le temps (en ms) avant de relancer la réception timeouts.readtotaltimeoutconstant=50; // Le temps d'attente avant de retourner les informations lu timeouts.readtotaltimeoutmultiplier=10; // Le temps (en ms) avant de relancer l'écriture timeouts.writetotaltimeoutconstant=0; // Le temps d'attente avant d'écrire les informations timeouts.writetotaltimeoutmultiplier=0; //On associe le port série (hserial) avec notre structure de réception des //données (timeouts) if(!setcommtimeouts(hserial, &timeouts)){ //error occureed. Inform user //Lecture du port série en boucle while(1){ /*** Trame télécommande ***/ //! Octet de type d'une trame télécommande /*! Une telle trame est construite de la façon suivante : * <'@'> <'@'> <voie1:1> <voie2:1> <voie3:1> <voie4:1> <voie5:1> <voie6:1> * <voie7:1> <Checksum> * -> 10 octets */ if( (clock() - timeout_com) > TIMEOUT_COMMUNICATION ) //Affichage temps entre envoi cout << "Emission (dt= " << clock() - timeout_com << ")" << endl; if(!writefile(hserial, lpbuff, 10, &dwbyteswrite, NULL)){ cout << "error" << endl; //MAJ du temps de dernier envoi timeout_com = clock(); /* Fermeture du port série afin qu'il soit réutilisable sans que * l'utilisateur ne soit dans l'obligation de redémarrer son ordinateur */ CloseHandle(hSerial); return 0;

V. Mise en œuvre des tests Les tests mise en œuvre ont été réalisés sur le drone orange. Dans un premier temps, seul les gouvernes ont été commandée afin de tester la faisabilité. Puis, les moteurs une fois le code suffisamment robuste pour le permettre. Il est a noter que la courbe d'évolution de la consigne est pour le moment linéaire, avec une pente qui peut être programmée. Cette pente doit être soigneusement définit afin de ne pas envoyer de trop brusque variation de consigne (Risque de perte des moteurs). Un des inconvénients de la version actuelle du code est qu'il ne dispose d'aucun moyen de réglage des trimes associées à chacune des voies. L'influence du soleil sur les mesures a été mis en évidence par un test par beau temps, lumière du soleil étant faible dans la salle drone. Les données sont fortement perturbées et le programme a beaucoup de difficulté a reconstruire les positions exactes des différentes articulations de l'utilisateur. VI. Conclusions Le développement du code, sujet de ce projet de recherche technologique, fut très enrichissant. Exposant une problématique intéressant, qui était de rendre le pilotage du drone ludique. La kinect développé par Microsoft est un capteur 3D très performant par rapport au prix de vente de ce dernier. De plus, la librairie officiel est très simple et bien détaillé, il est donc très facile de réaliser des application utilisant la kinect. Pour aller plus loin dans la commande de drone par kinect, il serait intéressant de mettre en place une réel interface graphique permettant la visualisation des consignes émissent de façon plus ludique. Actuellement, seul la console est utilisée. De plus, la réception des données pourraient passer par le même programme afin de renvoyer des informations à l'utilisateur.

VII. Bibliographie 1. Fonctionnement de la Kinect Kinect capteur 3D, Cs-Engineering.Over-Blog.Com, Novembre 2010 http://cs-engineering.over-blog.com/article-kinect-capteur-3d-61729010.html Kinect, Wikipédia http://fr.wikipedia.org/wiki/kinect 2. Développement du code pour la Kinect Comment dévelloper avec le Kinect SDK en C++ Part I, Devosaure, Juillet 2011 http://blogs.msdn.com/b/devosaure/archive/2011/07/11/comment-d-233-velopper-avec-le-sdkkinect-en-c-part-i.aspx Comment dévelloper avec le Kinect SDK en C++ Part II, Devosaure, Juillet 2011 http://blogs.msdn.com/b/devosaure/archive/2011/07/11/comment-d-233-velopper-avec-le-sdkkinect-en-c-part-ii.aspx Comment dévelloper avec le Kinect SDK en C++ Part III, Devosaure, Juillet 2011 http://blogs.msdn.com/b/devosaure/archive/2011/07/12/comment-d-233-velopper-avec-le-sdkkinect-en-c-part-iii.aspx 3. Développement du code pour la communication RS232 Windows serial port programming, Robertson Bayer, March 2008 www.robbayer.com/files/serial-win.pdf

VIII. Annexes 1. Les caractéristiques techniques Capteur : Lentilles détectant la couleur et la profondeur Micro à reconnaissance vocale Capteur motorisé pour suivre les déplacements Champ de vision : Champ de vision horizontal : 57 degrés Champ de vision vertical : 43 degrés Marge de déplacement du capteur : ± 27 degrés Portée du capteur : 1.2m 3.5m Flux de données : 320 240 en couleur 16 bits à 30 images/sec 640 480 en couleur 32 bits à 30 images/sec Audio 16 bits à 16 khz Système de reconnaissance physique : Jusqu à 6 personnes et 2 joueurs actifs 20 articulations par squelette Application des mouvements des joueurs sur leurs avatars Xbox Live Audio : Chat vocal Xbox Live et chat vocal dans les jeux (nécessite un compte Xbox Live Gold) Suppression de l écho Reconnaissance vocale multilingue (pour les français attendre la MàJ du printemps 2011) Figure 11 : Les caractéristiques techniques