Drone et occulus rift : Différence entre versions

De Wiki de Projets IMA
(Système à cardan)
(Système à cardan)
Ligne 747 : Ligne 747 :
  
 
[[Fichier:Fonction 3d servo.jpg|vignette|upright=1.25|left]]
 
[[Fichier:Fonction 3d servo.jpg|vignette|upright=1.25|left]]
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
  
 
A partir de ce tableau, on a créé une fonction qui permet de placer nos servos. Voici son prototype :
 
A partir de ce tableau, on a créé une fonction qui permet de placer nos servos. Voici son prototype :

Version du 23 avril 2016 à 18:42

Cahier des charges

Présentation générale du projet

Contexte

Depuis quelques années seulement, les drones se sont popularisés dans le domaine de l'utilisation civile.

Équipés de caméras, ils peuvent être utilisés pour lutter contre l'insécurité, surveiller des manifestations ou pour savoir le nombre de personnes prises au piège d'un immeuble en flammes.

Ils peuvent être aussi utilisés pour la prise de vues aériennes.

Drone pour prise de vues aériennes
Drone civil OnyxStar Fox-C8 XT en vol

Description du projet

L'objectif de ce projet est de concevoir et implémenter, sur un drone de bonne manufacture, un système embarqué capable de diffuser un flux vidéo en 3D stéréoscopique sur un casque de réalité virtuelle.

De plus, nous avons eu deux idées pour la gestion du drone :

Schéma de la première idée
Schéma de la deuxième idée

La première idée est de contrôler le drone en position directement via les mouvements de la tête à l'aide du casque, et nous aurions simplement fixé une caméra sur le drone pour pouvoir nous repérer.

La deuxième idée, retenue après discussion avec notre encadrant M. Dequidt, est de contrôler le drone en position via une télécommande par exemple.

Nous aurions cependant une caméra fixée sur le drone capable de tourner suivant deux axes et contrôlée via les mouvements de la tête grâce au casque. Un ordinateur embarqué (type Raspberry) récupérera en liaison sans fil les informations (inclinaison par ex.) du casque pour agir sur les moteurs en plus d'envoyer le flux vidéo des caméras.

Contraintes

  • Notre système embarqué ne devra pas excéder le poids de charge du drone (1kg).
  • Il faudra pouvoir alimenter notre système soit via l'alimentation du drone, soit à l'aide d'une source d'énergie supplémentaire.
  • La communication entre le drone, la télécommande pour piloter le drone et l'oculus doit se faire depuis une distance raisonnable (au moins 20 mètres).

Choix techniques : Matériel et Logiciel

  • Matériel
    • x1 ou x2 Caméras (résolution 800x600 minimum) pour récupérer des images depuis le drone, la vision 3D sera soit faite grâce à deux caméras, soit grâce à une caméra suivi d'un traitement d'image plus poussé.
    • x1 Raspberry Pi 2 pour le traitement d'image lié aux caméras, l’émission et réception du flux vidéo et le contrôle de la ou les caméras à distance. [Fournie 27/01/2015]
    • x1 Dongle Wifi (compatible Raspberry Pi 2, Wi-Pi par exemple) pour la communication sans fil entre l'utilisateur du drone et la structure montée sur le drone.[Fourni 27/01/2015]
    • x1 Drone de bonne manufacture (déjà commandé par l'école)
    • x1 Oculus Rift (déjà commandé par l'école)
    • x1 Servomoteurs pour faire pivoter selon 2 axes la structure où seront fixés les caméras (360°).[1 fourni 27/01/2015]
    • X1 Micro Servomoteur pour piloter "" (180°) Acheté par les élèves
    • X1 breadboard
    • X10 fils mâle/mâle
  • Logiciel
    • Solidworks ou un autre logiciel de modélisation 3D pour concevoir les différents supports de la structure.
    • Tout logiciel de traitement de texte pour la programmation (certainement C)
  • Autres
    • Utilisation de l'imprimante 3D du FabLab pour concevoir les différents supports de la structure.

Calendrier prévisionnel

Avancement du Projet

Semaine 1 (25 janv - 30 janv)

  • Rassemblement du matériel disponible à l'école (manque Oculus et Drone)
  • Recherche sur internet pour une batterie, deux caméras

Semaine 2 (1 fev - 6 fev)

  • Documentation sur la Raspberry (configuration des GPIO)
  • Installation et configuration de la Raspberry (connexion automatique sur réseau local)
  • Installation des bibliothèques pour la commande des servomoteurs via Raspberry
  • Premiers essais de commande des servos : problème au niveau des librairies
  • Premières idées sur la structure du support caméra pour 3D Stéréoscopique

Semaine 3 (8 fev - 13 fev)

  • Résolution (partielle) du problème de librairie pour contrôler les servomoteurs (toutes les fonctions non disponibles)
  • Précision angulaire d'environ 10° avec la fonction de contrôle utilisée (insuffisant) cf. Spécification de WiringPi et branchement
  • Début de conception de support pour fixer la Raspberry et la batterie externe sur le drone
  • Réception du drone

Semaine 4 (22 fev - 27 fev)

  • Résolution complète du problème de librairie pour contrôler les servomoteurs
    • Nouvelle fonction de la librairie utilisée pour le contrôle des servomoteurs
    • Précision angulaire d'environ 0,1° avec la nouvelle fonction de contrôle utilisée mais sur une plage de 120° au lieu de 180° //screens videos inc.
  • Essais et recherches pour contrôler les servomoteurs précisément et sur une plage plus grande
  • Problème de Wifi qui se déconnecte tout seul
    • On essayera de transformer la Raspberry en Hotspot pour voir si c'est mieux
    • Sinon on utilisera une borne wifi (solution mieux adaptée dans ce cas)
  • Discussion avec notre tuteur (M. Dequidt)
    • Mise au point sur l'avancement du projet
    • Une salle va nous être prêtée pour effectuer les tests au moment venu (plafond de 6m pour le drone)
    • L'Oculus, prêté par un laboratoire ne va pas tardé à arrivé
    • Notre tuteur se propose de passer quelques heures avec nous pour travailler sur la manière de récupérer les valeurs de l'accéléromètre de l'Oculus

Semaine 5 (29 fev - 5 mars)

  • Installation et paramétrage de la Raspberry en tant que point d'accès wifi
    • Point d'accès wifi sur la Raspberry impossible à faire fonctionner (problème au niveau du DHCP...)
    • On verra plus tard pour le wifi, à ce qu'il parait le réseau de l'école "fonctionne très bien" du coup on pourrait travailler dessus
  • OpenCV
    • Documentation
    • Compilation et test de fonctionnement sur une machine indépendante
  • Diverses méthodes étudiées vis à vis des flux vidéo des deux caméras
    • Motion, OpenCV, (et d'autres à ajouter car j'ai plus les noms) //screens videos inc.
    • Streaming sur une page internet ?
  • On reste pour l'instant sur le fait d'être précis mais limité de 120 degrés en angle pour la commande des servomoteurs

Semaine 6 (7 mars - 12 mars)

  • Travail sur l'Oculus DK2 dans les locaux de l'IRCICA avec notre tuteur (M. Dequidt)
    • Recherche sur le SDK pour comprendre le fonctionnement "logiciel" de l'Oculus
    • Code minimaliste et fonctionnel (testé sur OSX) récupérant les valeurs de l'orientation de l'Oculus
  • OpenCV est un peu trop lourd pour la Raspberry et peut être inadéquate pour l'utilisation qu'on souhaite en faire
  • Nouveaux objectifs
    • On va essayer d'ouvrir deux flux vidéos en même temps sur Raspberry
    • Tester la compilation du code minimaliste sur Windows et Linux
    • Tester le code avec un Oculus DK1 pour juger de la compatibilité du code
    • Trouver un moyen pour diffuser les valeurs sur le réseau (certainement de la même manière qu'en Tutorat S&R)

Semaine 7 (14 mars - 19 mars)

Semaine 8 (21 mars - 26 mars)

  • Finalisation de la conception du support pour fixer la Raspberry et la batterie externe sur le drone
  • Code minimaliste
    • La compilation du code minimaliste fonctionne sur Linux après plusieurs installations de bibliothèques, il faudra tester avec un Oculus
    • Par contre avec Visual Studio 2012 sur Windows c'est trop compliqué et rien fonctionne

Semaine 9 (28 mars - 2 avril)

  • Support terminé et imprimé [Lien partie Support à mettre]
    • Support assez fragile du fait que certaines parties sont petites (2mm d'épaisseur)
    • La batterie, la Raspberry et le premier servomoteur logent parfaitement, l'ensemble est plutôt léger, résultat conforme à nos attentes
  • Montage sur le drone
    • Impossibilité de démonter la caméra et son support présents de base [Lien partie explication à mettre]
    • Il faut repenser entièrement le support car la fixation ne se fait plus au milieu du drone au niveau des pieds...
  • Nouvelles idées support
    • Pour équilibrer les charges, un coté support avec la Raspberry, un autre avec la batterie
    • Entre les deux, notre support de caméra
    • En gros, moins équilibré, un peu plus lourd...

Semaine 10 (18 avril - 23 avril)

  • Développement support caméra (et non support Raspberry/Batterie)
    • Bricolage / Utilisation de l’imprimante laser
    • Premier prototype bricolé assez sympa mais trop fragile (épaisseur du bois très faible)
    • Deuxième prototype plus petit mais plus résistant, plans pour le refaire et l'améliorer sur SolidWorks

Test effectués

Gestion des caméras

Dans un premier temps, nous avons du réfléchir comment récupérer deux flux de caméras branchées en USB sur notre Raspberry Pi 2. Nous étions parti sur la bibliothèque d'Intel OpenCv, mais étant gourmande et assez difficile d'utilisation, et beaucoup trop puissante pour ce que l'on veut faire, on s'est dirigé vers une autre solution. Pour cela, on utilisera motion.

Installation de motion

sudo apt-get update 
sudo apt-get updrade 
sudo apt-get install motion
sudo apt-get install apache2 

On utilisera apache2 pour diffuser notre flux vidéo, depuis notre navigateur web, en local.

Configuration de motion

Tout d'abord, nous allons configurer motion à partir de deux fichiers :

nano /etc/motion/motion.conf

Et nous allons chercher les lignes suivantes et changer quelques paramètres :

deamon on (au lieu de off)
width 320
height 240
framerate 90

Dans le champ Live Webcam serveur

webcam_maxrate 24
webcam_localhost off
#rajoutez les lignes suivantes en dessous de la ligne précédente
thread /home/pi/webcam/cam1.conf
thread /home/pi/webcam/cam2.conf

Nous avons rajouter deux thread pour donner la configuration des deux caméras. Pour cela :

cd /home/pi
mkdir webcam
cd webcam
nano cam1.conf

On peut vérifier la présence des caméras avec la commande :

 ls /dev/vid*
/dev/video0  /dev/video1

Puis mettre la configuration suivante et faire de même pour la cam2.conf :

videodevice /dev/video0
webcam_port 8081

On a donc la cam1 qui est lu sur le port 8081 et la cam2 sur le port 8082.

Si on veut lancer le flux au démarrage de la Rasperry Pi :

nano /etc/default/motion
start_motion_daemon=yes

Lire le flux vidéo sur le navigateur web

On a installer apache2 précédemment, nous allons créer une page web minimal permettant d'afficher en même temps nos deux flux vidéo. Pour cela :

nano /var/www/webcam.html

Puis on récupère le flux via ce code minimaliste :

<html>
<head>
<title>Raspberry Pi Webcams</title>
<head>
<body>
<h1>Raspberry pi Webcaméras</h1>
<a href="http://raspberrypi:8081/">
<img src="http://raspberrypi:8081/" alt="Camera1"></a> 
<a href="http://raspberrypi:8082/">
<img src="http://raspberrypi:8082/" alt="Camera2"></a> 
</body>
</html>

Pour démarrer et arrêter le service (attention à bien être en root §sudo bash)

service motion start
service motion stop

Pour visualiser les flux de notre page web sur notre navigateur :

http://raspberrypi/webacam.html

On peut mettre l'adresse de la Rpi à la place de "raspberrypi" via :

ifconfig

Ainsi, on obtient bien la diffusion de nos deux streams de caméra en USB à partir d'une raspberry pi 2 :

Rpi cam.jpg

Une vidéo du branchement des différents éléments:

Média:Video branchement.mp4

Une vidéo qui montre le flux en directe :

Média:Test-cam-final.mp4

Récupérer le flux des caméra en C

//

Gestion des GPIO pour contrôle de servo-moteur

Dans les rubriques suivantes, on a décidé pour l'instant d'utiliser les bibliothèques de WiringPi <SoftServo.h> et <SoftPwm.h>.

installation de WiringPi

Tout d'abord, on a besoin d'installer git pour récupérer WiringPi :

apt-get install git-core

Pour obtenir WiringPi via Git :

git clone git://git.drogon.net/wiringPi

Au premier clone, lors de l'installation :

cd wiringPi
git pull origin

Puis, pour construire avec le script fourni :

cd wiringPi
./build

Spécifications de WiringPi et branchement

la documentation de wiringPi disponible en :

   -En français[1]
   -En anglais[2]

Pour vérifier que le programme est bien installé :

gpio -v

Pour lire les entrées et les sorties sur les gpio de la Pi :

gpio readall

On obtient ainsi le résultat suivant dans un terminal :


Terminal-gpio.png


et on branche comme spécifié ci-dessus le servo moteur qui a besoin d'une alimentation en +5V 0V. Puis on récupère le signal sur le gpio n°1 en pin n° 12 :


branchement du servo moteur 180°















Test avec <sofPwm.h>

Servo 180°

Ici on va utiliser la librairie de wiringPi <softPwm.h>, les spécifications de la librairie sont disponibles à cette adresse[3].

Voici un code sommaire permettant de contrôler un servomoteur sur sa plage d'action en position (ici 0 à 180 degrés). La Pwm envoyée au servomoteur détermine la position qu'il doit atteindre :

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <softPwm.h>

#define PIN_0 1

int main(int argc, char *argv[]){
        int pos =0;
        char reponse = ' ';
        if(wiringPiSetup() == -1){
                printf("Bug\n");
                exit(1);
        }//si l'initialisation de wiringPi échoue, on arrête le programme

        pinMode(PIN_0,OUTPUT); //dédfinition de la gpio 1 comme sortie
        digitalWrite(PIN_0,LOW);//son etat initial est à létat bas
        softPwmCreate(PIN_0,0,500);//creation de la pwm

        do{

                printf("Position à 0°:\n");
                softPwmWrite(PIN_0,25);
                delay(2000);
                printf("Position à 90° :\n");
                softPwmWrite(PIN_0,16);
                delay(2000);
                printf("Position à 180° : \n");
                softPwmWrite(PIN_0,8);
                delay(2000); //les positions sont arbitraires pour ma maquette sinon elle sera liée dans le futur aux accelero de l'oculus
                do{
                        printf("Voulez-vous continuer (0/N)\n");
                        scanf("%c",&reponse);
                }while(reponse != 'O' && reponse !='N');
        }while(reponse == 'O');

        printf("Au revoir\n");
        return 0;
}

Pour compiler le programme, on utilise la ligne ci-dessous :

gcc -o servo servo.c -lwiringPi

Et voici une vidéo illustrant le code ci-dessus :

Média:test-servo.mp4

Servo 360°

De même, on va asservir ici un servomoteur 360°. Le code reste similaire. On ne contrôle plus en position mais la Pwm appliquée détermine le sens/vitesse de rotation :

#include <wiringPi.h>
#include <stdio.h>
#include <stdlib.h>
#include <softPwm.h>

#define PIN_1 0

int main(int argc, char *argv[]){
        int pos =0;
        char reponse = ' ';
        if(wiringPiSetup() == -1){
                printf("Bug\n");
                exit(1);
        }//si l'initialisation de wiringPi échoue, on arrête le programme

        pinMode(PIN_1,OUTPUT); //dédfinition de la gpio 1 comme sortie
        digitalWrite(PIN_1,LOW);//son etat initial est à létat bas
        softPwmCreate(PIN_1,0,500);//creation de la pwm

        do{

                printf("Sens anti-horaire:\n");
                softPwmWrite(PIN_10,9);
                delay(2000);
                printf("Arrêt du servo :\n");
                softPwmWrite(PIN_1,15);
                delay(2000);
                printf("Sens horaire : \n");
                softPwmWrite(PIN_1,18);
                delay(2000); 
                softPwmWrite(PIN_1,15);//arret du servo apres test
                do{
                        printf("Voulez-vous continuer (0/N)\n");
                        scanf("%c",&reponse);
                }while(reponse != 'O' && reponse !='N');
        }while(reponse == 'O');

        printf("Au revoir\n");
        return 0;
}

On compile comme vu précédemment et voici une vidéo montrant le servomoteur en action :

Média:servo-360.mp4

Servomoteur 180° ou 360°?

Pour notre projet, on voudrait piloter un ensemble de caméras via des servomoteurs, il nous reste à choisir comment! Ici, on a utilisé la librairie <softPwm.h> de wiringPi. Le soucis c'est que le servomoteur 180° semble avoir des problèmes de stabilité. On a fait un autre test avec une autre librairie de wiringPi qui n'était pas compilée lors de son installation. On a eu de meilleurs résultats en terme de précisions pour le 180°, malheureusement il semblerait que cette librairie trouble le fonctionnement de la Raspberry Pi.

Sinon, comme pour le précédent test, voici une vidéo comparative des deux servos :

Média:test-2-servos.mp4

Test avec <softServo.h>

Servo-moteur 180°

//

Servo-moteur 360°

//

Contrôler les GPIO directement en C

On a utilisé WiringPi qui est une bibliothèque qui a gentiment été réalisée par un particulier mais ne correspond que à moitié à nos attentes. Pour cela, on va directement utilisé les bibliothèques du processeur de la raspberry Pi 2: la Bcm2835.

Installation de la bibliothèque

Liens de la documentation complète de la librairie : [4]

Pour commencer, choisir le dossier d'installation de la bibliothèque :

 cd /home/pi/ 
 wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.XX.tar.gz 

Puis pour dé-zippé le fichier téléchargé :

tar zxvf bcm2835-1.XX.tar.gz 

On va maintenant construire l'archive :

cd bcm2835.XX
./configure
make 
sudo make check
sudo make install

La librairie est maintenant prête à être utilisée. Attention à ne pas oublier :

#include <bcm2835.h> 

Pour compiler un .c :

gcc -o fichier fichier.c -lbcm2835

ou en utilisant un makefile:

all: output_file_name

output_file_name: main.o
	gcc main.o -lbcm2835 -o output_file_name

main.o: main.c
	gcc -c main.c

clean:
	rm -rf *o output_file_name 

Note: la librairie bcm2835 est issue de la première version de la raspberry pi et de son processeur associé. Aujourd'hui la rpi 2 fonctionne sous un bcm2836 et même problème pour la rpi 3. La solution est que la librairie est constamment mise à jour. Les changements majeurs se situent au niveau de l’appellation des broches.

Test avec une diode

Pour tester la librairie, on va compiler un programme pour faire clignoter une diode :

#include <bcm2835.h>

// Blinks on RPi Plug P1 pin 11 (which is GPIO 0 pin 17)
#define PIN 17 
int main(int argc, char **argv)
{
    // If you call this, it will not actually access the GPIO
    // Use for testing
//    bcm2835_set_debug(1);

    if (!bcm2835_init())
        return 1;

    // Set the pin to be an output
    bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);

    // Blink
    while (1)
    {
        // Turn it on
        bcm2835_gpio_write(PIN, HIGH);
        
        // wait a bit
        bcm2835_delay(500);
        
        // turn it off
        bcm2835_gpio_write(PIN, LOW);
        
        // wait a bit
        bcm2835_delay(500);
    }
    bcm2835_close();
    return 0;
} 

Vidéo (à venir)

Récupération des valeurs des accéléromètres de l'Oculus Rift

Pour essayer de comprendre comment le sdk des Oculus rift fonctionne, on va utiliser une série d'exemples créés et expliqués par Jherico sur son gitHub [5].Il montre comment utiliser et programmer les différents composants des Oculus Rift. Pour la suite, on a besoin d'installer cmake pour construire le projet [6].

On récupère ensuite le projet (sur notre pc) contenant les différents exemples :

git clone https://github.com/OculusRiftInAction/OculusRiftInAction.git --recursive

puis après la fin du téléchargement, pour compiler les différents projets,

cd OculusRiftInAction
mkdir build
cd build
cmake ..

On peut aussi générer au besoin un Makefile :

cmake .. -G "Unix Makefiles"

Ou ce que l'on souhaite (selon l'Os, l'IDE...) en regardant :

cmake -h

On lance un programme au hasard pour vérifier son bon fonctionnement :

./examples/cpp/./Example_2_2_Tracker.cpp

Cette exemple n'est pas tout à fait choisit au hasard, puisqu'il récupère les valeurs des accéléromètres dans le terminal :

(en construction)

Design de la nacelle

Au début du projet, nous avions commencé à réaliser une première structure, basé sur le support de la caméra du drone :

Base drone.jpg















Cette structure avait pour avantage de se situer sous le drone, embarquant tout l'électronique et le système de caméra. Son principal avantage était de centrer la masse pour garantir une bonne stabilité du drone en vol. Nous avions imprimé un premier prototype de cette nacelle :

Struct1.jpg









Struct2.jpg











Mais malheureusement, la modification de conception de la nacelle originelle du drone, en retirant deux vis, s'avère impossible. Pour cela, nous avons donc repensé la structure en optant pour deux supports: un pour la batterie, un pour la raspberry Pi, et un système attaché devant le drone pour le contrôle des caméras dans l'espace. Un premier croquis peut nous donné une idée du travail final à réaliser :

Croquis drone.jpg















Système à cardan

Pour pouvoir déplacer les caméra dans un plan se situant devant le drône, on a du imaginer une structure pouvant déplacer les deux caméras à différentes positions. On a réaliser une première version :

Support v1 cam.jpg










Puis une seconde (la première était beaucoup trop fragile) :

Support v2 cam.jpg










On réalise un rapide test pour montrer le fonctionnement de la structure :

Il a fallut ensuite, à partir de nos connaissances sur les servomoteurs, réaliser un "plan" des différentes positions que nous voulons atteindre. En effet, on a recensé 13 positions par servomoteur, ce qui nous donne un total de 168 couples disponible :

Fonction 3d servo.jpg















A partir de ce tableau, on a créé une fonction qui permet de placer nos servos. Voici son prototype :

 void pos_servo(int tableau1[], int tableau2[2], nombre) 

Elle demande deux tableaux qui sont les coordonnées des positions disponibles de nos servomoteurs (x,y,nombre) dans leur plage de fonctionnement. Puis elle demande un nombre qui correspond aux valeurs des différents couples de positions disponibles dans une demi-sphere se situant devant le drone.

Pour tester ces positions, on génère un nombre aléatoire que l'on rentre dans notre fonction pour vérifier son bon fonctionnement :

#include <time.h>
int rand_a_b(int a, int b){ //genère un nb aleatoire entre a inclue et b exclu
    return rand()%(b-a) +a;
}

Il reste ensuite à réaliser une fonction qui traitera les valeurs des accéléromètres de l'oculus rift et les transformera en position pour notre fonction.

Support batterie

//

Support Raspberry

//

Vu de l'ensemble

//