Projet IMA3 P4, 2016/2017, TD1
Sommaire
Projet IMA3-SC 2016/2017 : Caméra connectée
Tous les fichier-sources utilisés pour ce projet sont disponible sur le dépôt git suivant le lien : Sources du projet SC
Un fichier README explique comment faire fonctionner la caméra lors du premier usage : README
Ici, vous trouverez le wiki de notre projet, qui détaille les étapes de la conception de ce projet.
Cahier des charges
Description du système
Le système envisagé est une caméra de bureau connectée. Cette caméra aura deux modes de fonctionnement :
- actif : le flux vidéo est transmis en direct sur l'application web. Un pilotage de la caméra est envisagé, deux servomoteurs permettraient d'orienter la caméra selon deux axes depuis l'application web.
- passif/sécurité : le flux vidéo n'est plus transmis, mais une fonction de détection de mouvement est activée qui permet le retour au mode actif en notifiant la détection sur l'application web.
Le matériel
Une caméra (voir si des pilotes sont nécessaires)
Deux servomoteurs
Un raspberry
Un arduino
Un support reliant les moteurs à la caméra
Séance 1
Partie électronique
La première étape dans la réalisation de notre projet fut le contrôle des servomoteurs. Pour cela, nous avons commencé par analyser le signal type envoyé aux servomoteurs afin de pouvoir reproduire celui-ci à partir d'un FPGA.
Afin de capter ce signal, nous avons commandé le servomoteur à l'aide d'une Arduino. Puis nous avons relié le pin de sortie de l'Arduino à un oscilloscope (voir photo montage).
On remarque que la période ne change pas (20ms), cependant, l'intervalle de temps ΔT durant lequel le signal reste à l'état haut (5V) change par rapport à la commande d'angle du moteur.
ΔT =
- 0.6ms pour 0°
- 1.5ms pour 90°
On a ensuite cherché à recréer ce signal avec la NanoBoard, grâce à Altium. Afin de créer un rapport cyclique dans le signal de commande du moteur, nous avons décidé d'utiliser le principe de la MLI intersective (PWM en anglais).
La MLI consiste à restreindre la durée ΔT via la comparaison entre un mot de 8 bits (donné par l'utilisateur), et un autre mot de 8 bits, sortant d'un compteur relié à une horloge interne de la NanoBoard.
On utilise pour cela le composant PWM de la bibliothèque 'FPGA Configurable':
- CLK_BRD : fréquence de la Nanoboard
- CLKGEN : générateur de fréquence
- DIGITAL_IO : entré numérique. Permet la sélection du mot de bits servant à la comparaison d'un mot de 8 bits.
- HA5 : sortie du FPGA (pin5).
Ce montage nous a permis de faire varier le rapport cyclique en sortie de la PWM, et donc, de faire tourner notre servomoteur.
On finit par relever les valeurs suivantes:
Pour 100kHz:
- -45° = 1100 0110
- 0° = 1011 0011
- 45° = 1001 1110
Pour 200kHz:
- -45° = 1001 0011
- 0° = 0101 1111
- 45° = 0011 1000
N.B. : nous avons convenu que l'on allait se limiter à un angle compris entre -45° et 45°.
Finalement, en incrémentant la valeur en entrée de notre PWM grâce au composant 'DIGITAL_IO', nous avons été capable de faire tourner le servomoteur dans un sens et dans l'autre.
La prochaine séance consistera à créer un circuit permettant le comptage et le décomptage du mot de 8bits en entré de notre PWM.
Partie informatique
La partie informatique se découpe grossièrement en deux parties :
- Une partie réseau et développement web
- Une partie acquisition et analyse d'image et communication Raspberry/Arduino
Réseau et développement web
L'objectif de cette première séance était de rechercher les fonctions HTML, qui nous permettrait d'afficher en streaming les images de notre caméra, mais aussi de contrôler la direction de celle ci. Il sera également donné à l'utilisateur la possibilité de mettre en pause la vidéo, sans pour autant interrompre le flux de données.
Pour l'instant il n'est pas encore possible d'afficher en streaming notre vidéo. HTML offre un large choix de méthodes permettant d'afficher du contenu vidéo, celles ci dépendant de la source mais aussi du type d'action souhaité. Notre affichage devra donc être adapté au format envoyé par la caméra.
Nos boutons ne sont pas encore reliés aux moteurs contrôlant la caméra, mais une future implantation de cette fonctionnalité est prévue.
Voici un aperçu de ce à quoi pourrait ressembler notre interface :
Acquisition et communication
Lors de cette séance, le gros du travail effectué a été réalisé sur Raspberry.
Il a d'abord fallu réinstaller raspibian, puisque la version installée de base sur la carte était assez modifiée par rapport à l'originale. (Programmes et bibliothèques nombreuses à manquer).
Grâce à l'utilitaire NOOB pré-installé sur la carte cela a été facilement réalisé.
Ensuite, il a fallu rechercher un programme ou une bibliothèque permettant l'acquisition des images.
Notre caméra étant une PiCaméra, il a d'abord semblé logique de choisir la bibliothèque PiCamera, que nous aurions pu utiliser en Python.
Mais après des recherches plus approfondies, le choix de Motion s'est imposé, puisque ses nombreuses fonctionnalités correspondent à nos attentes. (stream et détection de mouvement par cadran)
Cependant il s'est avéré que la dernière version de Motion ne permet pas d'utiliser la PiCamera, qui n'est pas recconue comme /dev/video0. Il a donc fallu rechercher une solution pour contourner le problème.
L'utilitaire motion-mmal permet d'utiliser motion avec la PiCamera, il a donc été installé sur le Raspberry.
Ensuite il a fallu modifier le fichier de configuration de motion-mmal pour l'adapter à nos besoins. (/etc/motion.conf pour motion-mmal et non /etc/motion/motion.conf pour la version d'origine de motion)
Nous avons pu obtenir en fin de séance un stream accessible sur le réseau local à l'addresse locale du raspberry, sur le port 8081.
L'objectif pour la séance prochaine sera de faire communiquer l'arduino et le raspberry Pi.
Séance 2
Partie électronique
Cette séance à été principalement dédié à la réalisation des circuits pour la mise en place des fonctionnalités prévues, a savoir:
- déplacer la caméra grâce à deux servomoteurs, par l'intermédiaire d'un site internet.
- donner un position précise à la caméra, afin de pouvoir éventuellement gérer (si le temps le permet) le suivi d'un objet ou d'une personne.
- CLK_BRD : fréquence de la Nanoboard
- CLKGEN : générateur de fréquences
- COUNTER : compteur/décompteur configurable 8 bits, avec initialisation possible des donnée (L = 1).
- DIGITAL_IO : entré numérique. Permet la sélection du mot de bits servant à la comparaison d'un mot de 8 bits.
- HA5 : sortie du FPGA (pin5).
Comme on l'a vu précédemment, il est possible, via la transmission d'une info en 8 bits, de faire bouger la caméra (chaque mot de 8bits correspondant à une durée d’impulsion donc à un un angle précis).
Afin de faire tourner la caméra, nous avons décidé d'incrémenter le mot de 8 en question autour de celui correspondant à l'angle 0°.
On fixe le générateur de fréquences à 100kHz:
- 45° = 1100 0110
- 0° = 1011 0011
- -45° = 1001 1110
Pour cela, nous avons utilisé un compteur afin d'incrémenter le mot de 8 bits qui sera comparé avec celui issue du générateur de fréquence.
la commande du compteur se fait via l'entrée CE(Clock Enable), lors ce que CE est à 1, le compteur incrémente sa valeur à chaque signal d'horloge. Une fois mis à 0, ce dernier garde en mémoire la valeur du dernier mot compté.
A l'issue de la séance, nous n'avons pas été capable de faire fonctionner le circuit correctement. La rotation est en effet trop saccadé.
La prochaine séance sera dédié à la finalisation de notre circuit et à la correction des problèmes rencontrés.
Partie informatique
Réseau et développement web
Durant cette séance notre interface web a été réorganisée afin d'optimiser le contrôle de la caméra. En effet dans notre version précédente les boutons étaient placés autour de la vidéo, ce qui ne permettait pas de cliquer de l'un à l'autre très rapidement. Ils ont donc été rassemblés sur la droite de l'écran, afin de répondre à ce soucis de dynamisme.
Acquisition et communication
L'objectif au niveau de l'acquisition de l'image et du contrôle des servos a été de mettre au point un système de suivi de mouvement. Nous avons donc cherché à exploiter l'outil Motion, qui propose une fonctionnalité de tracking. Nous avons donc commencé par configurer Motion, pour activer le tracking, et adapter les options pour qu'elles correspondent à nous servos. Une fois cela fait, il a fallu récupérer l'information sur le mouvement à effectuer, fournie par Motion via la liaison série du raspberry Pi. Mais nous nous sommes heurtés à plusieurs difficultés:
- D'une part, il a été difficile de déchiffrer les données fournies par Motion via la liaison série, de part le peu de documentation à ce sujet
- D'autre part, il a fallu faire un choix entre le contrôle des servos via l'interface web, ou de manière autonome, puisque deux programmes différents ne peuvent utiliser une même liaison série. Nous avons choisi de nous consacrer exclusivement au contrôle via l'interface web.
L'objectif de la prochaine séance sera de contrôler les servos via la liaison série.
Séance 3
Partie électronique
Cette séance à été consacré à la finalisation du montage nous permettant de faire de tourner les servomoteurs dans un sens et dans l'autre.
Dans un premier temps, nous avons cherché à résoudre les problèmes rencontré durant la séance précédente. Ces derniers étant dû à un mauvais réglage de la fréquence. Afin de rendre la rotation moins saccadé, nous avons baissé la fréquence issue du générateur de fréquence à 12,8kHz, pour avoir une période en sortie de 50Hz (2^8 * 50 = 12600). Ce changement nous à permis à notre servomoteur d'avoir une rotation plus lisse.
Nous avons aussi opéré quelques modifications au niveau du compteur. Ce dernier à été modifié de tel manière à arrêter de compter une fois atteint les mots de 8bits correspondant aux angles de -45° et 45°. Dans ces cas là, le circuit fait en sorte de mettre à 0 la commande CE. Enfin, nous avons aussi prévu initialisation du compteur à une valeur bien précise, laquelle correspond à l'angle 0° (0001 0011).
- CLK_BRD : fréquence de la Nanoboard
- CLKGEN : générateur de fréquences
- COUNTER : compteur/décompteur configurable 8 bits, avec initialisation possible des donnée (L = 1).
- DIGITAL_IO : entré numérique. Permet la sélection du mot de bits servant à la comparaison d'un mot de 8 bits.
- HA5 : sortie du FPGA (pin5).
Les tests effectué à partir de ce circuit sont assez peu concluants. La rotation semble fonctionnelle que dans un sens. En revanche, le servomoteur arrête de tourner une fois les angles -45° et 45° atteins. L'initialisation à l'angle 0° fonctionne aussi. Malgré les améliorations apportés au circuit, les problèmes persistent. A l'issue de la séance, aucune solution n'a été trouvée.
Partie informatique
Réseau et développement web
Cette dernière séance a été principalement consacré à la programmation des boutons. Lorsque l'utilisateur clique sur l'un d'eux, un caractère est envoyé au raspberry.
Chaque bouton est associé à un caractère : h pour le haut, g pour gauche, d pour droite et b pour bas. Ainsi en cliquant sur un bouton l'utilisateur déplace la caméra dans la direction associée.
Pour arrêter les déplacement lors du relâchement de la souris, il envoie un caractère, 'u', au serveur websocket quand il détecte que la souris est relachée. ce qui devra stopper les servos.
Ces différentes applications ont été réalisé à l'aide de javascript
Acquisition et communication
Lors de cette dernière séance, nous avons abandonné l'idée de commander les servos de manière automatique. En effet, deux problèmes se posent:
- D'une part, parce que nous n'avons pas réussi lors de la séance précédente à lire les données de la liaison série données par motion, nous préférons consacrer notre temps à faire un projet plus simple mais fonctionnel
- D'autre part, pour que le système puisse être commandé de manière manuelle, nous avons besoin que le websocket accède à la liaison série, et ce en même temps que motion. Ce qui est impossible sans modifier puis recompiler Motion, ce que nous avons préféré ne pas faire dans un but évident de gain de temps.
Pour la suite de notre projet, nous poserons la priorité à la commande manuelle. Dans ce but, cette séance devra nous permettre de commander notre arduino depuis une page web proposée par le Raspberry Pi. Pour cela, notre page web devra envoyer des caractères ascii au serveur websocket, un caractère correspondant à une commande donnée à l'arduino. Une fois la page web modifiée de la manière vue précédemment, il nous reste deux étapes.
- La modification du code source du serveur Websocket, pour qu'il utilise la liaison série et lui communique tous les caractères ascii qu'il reçoit
- La création d'un programme arduino lui faisant interpréter les caractères reçus
Programme du websocket
Les sources ce programme peuvent êtres retrouvées ici : Sources du websocket
Brièvement, il a fallut ajouter au programme websocket la bibliothèque permettant de prendre en compte la liaison série. Ensuite, il s'agira d'ouvrir cette liaison série dans la fonction main. Enfin, pour qu'à chaque caractère reçu, le programme websocket appelle la fonction "callback_my" avec la raison LWS_CALLBACK_RECIEVE, il suffit alors de rajouter la ligne :
write(sd,in,sizeof(char));
Ainsi, tous les caractères reçus sont directement envoyés à la liaison série.
Programme arduino
Les sources de notre programme arduino sont disponibles ici : Programme arduino
Lors de cette séance, pour tester que la liaison série fonctionne réellement, nous avons réalisé un montage simple sur notre arduino. Nous lui avons connecté deux servos, le but sera de les commander via la liaison série. Nous alonns donc créer un programme arduino qui fonctionne de la manière suivante.
- Si un caractère est disponible sur la liaison série, alors on le lit.
- Si le caractère reçu correspond à une demande de déplacement pour l'un des servos, on va alors incrémenter ou décrémenter en boucle la valeur de l'angle correspondant, jusqu'à ce qu'un autre caractère soit reçu. Et on actualisera en boucl ela position des deux servos pendant le déplacement.
- Si le caractère reçu correspond à une demande d'arrêt de déplacement, alors on arrête de changer la valeur de l'angle à modifier. On attends alors l'ordre suivant.
A la fin de cette séance, le programme arduino est fonctionnel, bien qu'il semble que l'un des deux servos réponde de manière aléatoire par moment. Il faudra vérifier si le problème est matériel ou logiciel. Notre projet est presque terminé, puisque le projet fonctionne quasiment. Mais il reste des améliorations à ajouter.
- Notre .html et toutes ses ressources doivent être hébergées sur la machine du client pour accéder à la caméra IP. Il faut donc installer un serveur web sur le raspberry qui hébergerait cette page.
- Il faut lancer manuellement motion et le serveur websocket. Le mieux serait qu'on n'aie pas besoin de le faire, que tout se lance automatiquement dès qu'on alimente le raspberry.
- Il reste la partie matérielle à faire
Séance supplémentaire 1
Partie informatique
Nous avons commencé par résoudre le problème de l'hébergement web. Pour ce faire, nous avons utilisé apache. Quand on installe apache sur une machine, ce programme lance au démarrage de la machine un site web hébergé à l'adresse ip de la machine sur son port 8029. Nous avons remplacé la page web index.html, proposée par défaut et stockée dans /var/www, par notre page et ses ressources. Nous redémarrons le server avec la commande appache2ctl restart, on lance motion et le serveur websocket, et les servos peuvent être commandés depuis la page web.
Ensuite, nous voulons automatiser le lancement de motion et du serveur websocket. Pour ce faire, nous créons un fichier script, projetsc.sh, qui comprendra les lignes :
sudo motion &
sudo /home/pi/projetSC/SerialWebsocket/websocket &
On n'a pas besoin de lancer apache lors du boot, par défaut cela se fait automatiquement. On ajoute ce script au dossier /etc/init.d, et on change les droits du .sh pour qu'il puisse être executé. Si on redémmarre le raspberry, on peut alors se connecter sur l'adresse ip-du-raspberry:8029, et on accède au site permettant de contrôler les deux servomoteurs.
Partie matérielle
Il ne reste donc plus qu'à construire la partie matérielle. Pour ce faire, nous avons choisi d'utiliser des mécanos plutôt que l'imprimante 3D et la découpeuse laser pour les raisons suivantes :
- On avait des mécanos sous la main, ce qui permet de travailler tant qu'on veut à la maison
- Les mécanos sont plus modulable que ce qui est fait avec l'imprimante 3D : si on veut améliorer la structure, il faut juste démonter/remonter des pièces, et non démonter, réimprimer/redécouper, remonter les pièces. et par la suite, ça a grandement facilité la tâche, puisque la structure a bien évolué au cours du temps.
- la création de pièches personnalisées demande dans notre cas des
Mais par rapport à des pièces faites sur-mesure, nous avons les défauts suivants :
- Il a fallu pas mal d'imagination pour adapter les servos et le raspberry aux mécanos, car les mécanos ont des espaces biens définis entre deux vis, qui ne tombent pas pile sur les dimensions des servos/du raspberry.
- Il faut de temps en temps resserer les boulons car avec les vibrations générées par les servos, ils ont tendance à bouger.
Ces caractéristiques font de la maquette plus un prototype qu'une version commerciale, mais ça correspond bien à notre projet.
Conclusion
Pour conclure, ce projet nous a donné un premier aperçu de ce que peuvent être des projets plus conséquents. En effet, grâce au coté hétérogène des technologies que requièrent les systèmes communiquants, nous avons pu toucher à de nombreux domaine.En particulier, ce projet a permis de développer des compétences plus techniques que ce soit en électronique, en programmation embarquée ou non, en réseau, en développement web, ou même en mécanique, et nous a permis de développer nos connaissances dans ces domaines, voire d'en découvrir de nouveaux.
Mais ce projet nous a également permis de nous améliorer en terme de gestion de projet. Car réaliser notre caméra IP a nécessité d'abord un découpage efficace des tâches à réaliser, une bonne communication et une bonne cohésion du groupe.