Projet IMA3 P3, 2017/2018, TD1

De Wiki de Projets IMA

Projet IMA3-SC 2017-2018 : prototype de main artificielle

Description du projet

Cahier des charges

  • Reconnaissance d'un mouvement par la Rpi via l'accelerometre
  • Transmission du mouvement à l'arduino via bluetooth déclenchant le servomoteur
  • Visuel du mouvement sur serveur web
  • Bonus : Faire plusieurs doigts

Description du système

Des accelerometres sont fixés sur la main (le doigt d'abord) de l'utilisateur.
Detection d'un mouvement de doigt par les accelerometres.
Transmission du mouvement au servomoteur via l'arduino.
Transmission des informations a la Rpi pour la reproduction de mouvement sur serveur web.

Matériel nécessaire

*2 servomoteurs
*2 accelerometres
*1 Rasberry Pi 2
*1 Arduino Uno

Séance 1 : Début du projet

Durant cette première séance, nous avons constitué les groupes te définit un sujet.
Nous avons pris connaissance des contraintes imposés par le projet.
Chacun de nous a commencé a se familiariser avec les différentes composantes du projet.
Brandon -> Arduino
Flora -> Rasberry
Florent -> Impression du doigt et recherches

Séance 2

Le doigt étant imprimé, nous nous sommes attelés à la conception du programme permettant de faire fonctionner celui-ci. L'objectif était de faire en sorte que, lors de l'envoi d'une donnée précise du capteur à l'Arduino, les servomoteurs suivent le mouvement indiqué par l'utilisateur. Nous pouvons décomposer les mouvements du doigt comme ceci : (images)

Par soucis du matériel et n'étant pas encore sûrs du montage final, nous avons préféré réaliser nos test à l'aide de 1 breadboard sur laquelle nous avons réalisé toutes les connectiques nécessaires à la communication entre l'ADXL et l'Arduino.

A l'issue de la séance, nous avons réussi à simuler le mouvement complet d'un doigt à l'aide d'un capteur comme vous pouvez le voir dans la vidéo ci-dessous : (vidéo)

Cependant, pour pouvoir être en accord avec l'idée de mouvement pré-établi plus haut, il est nécessaire d'ajouter un 2e capteur ADXL au montage. Peut-on contrôler 2 ADXL séparément à l'aide d'une seule carte Arduino ?L'objectif de la séance suivante sera donc de trouver un moyen d'inclure et contrôler le 2e ADXL.

Séance 3

Le but de cette séance fut de pouvoir améliorer notre montage et notre programme en y ajoutant un deuxième capteur. La tâche était assez compliquée dans la mesure où nous devions pouvoir contrôler les 2 capteurs indépendamment. En suivant le même principe que le montage précédent, nous avons pu rajouter le 2e capteur et procéder à des test similaires à ceux réaliser sur le précédent montage. Cependant, le montage était réalisé de telle sorte que les 2 ADXL soient interconnectés. Ainsi, les données relevées par l'un était une copie conforme de celle relevées par l'autre. Cela ne correspondait pas à nos attentes. Nous avons donc tenté de modifier notre programme afin de remédier à cela mais le problème persistait. La seule option possible était de revoir le schéma de montage. N'ayant pas eu suffisamment de temps pour le faire, nous nous sommes accordés à revoir ce soucis hors-séance afin d'achever notre projet.

Bilan

Conception mécanique

Après avoir défini le sujet, nous avons réfléchi au support physique de ce dernier.
Modèle non satisfaisant

Nous nous sommes arrêtés sur une impression de doigt en 3D ainsi qu'une plaquette d'essai sur laquelle nous fixerons l'arduino et les servomoteurs.

Nous nous sommes très largement inspirés du projet InMoov dont le doigt est une copie. Cependant, nous avons du recréer la plaquette d'essai dans le but de fixer les deux petits servomoteurs fournis au lieu d'un seul dans le projet Inmoov.

Concernant le fonctionnement même du doigt, deux fils de nylon le parcourant de la pointe jusqu'à la base, l'un passant par la face interne et l'autre par la face externe, permettent la flexion et l'extension du doigt en tirant sur l'un ou l'autre des fils. Cette traction est exercée par les servomoteurs se situant à la base du doigt sur lesquelles nous fixons des roues munies d'un guide. Les roues tournent en même temps mais dans des sens opposés.

Roue avec tube

Après quelques erreurs de modélisation ne permettant pas de fixer correctement les moteurs, nous sommes arrivés à un modèle satisfaisant.


Suite à l'assemblage des différentes parties, nous nous sommes rendu compte qu'une des roues servant à entraîner un des fils de nylon, laissait sortir ce dernier du guide de la roue. C'est pourquoi nous avons du rajouter un tube autour de la roue pour que le fil ne s'échappe pas.

Partie électronique

Afin de réaliser notre projet tout en répondant notre cahier des charges, nous avons établit le montage suivant :
Montage un capteur

La masse (GND) du capteur doit être connectée à celle de l'Arduino. Les broches CS et 3.3V sont reliées à la pin 3.3V de l'Arduino, la broche CS étant étant reliée ainsi afin de faire comprendre à l'ADXL que nous l'utilisons en tant que I2C. Les broches SDA et SCL sont connectées aux pins analogiques A4 et A5 respectivement car la pin A4 de l'Arduino correspond au port série de données tandis que la pin A5 correspond au top d'horloge.

Nous nous sommes également procuré 2 LED et 2 servomoteurs pour servir de voyants repères et de simulation du mouvement respectivement.

(Vous pouvez également voir le rendu vidéo en regardant celle qui se trouve partie Séance 2)

Pour pouvoir contrôler le mouvement de la seconde partie du doigt, il a été nécessaire de rajouter un 2e capteur ADXL345 (de même type). Ainsi, le premier capteur gère le mouvement de la base du doigt, tandis que le 2e s'occupe de celui de la partie supérieure.
Schéma de câblage 2 ADXLs

Faisant suite aux problèmes signalés dans la partie Séance 3, nous avons revu le montage.

La pin SD0 de l'ADXL sert à la sélection de l'adresse de celui-ci. En effet, si on se réfère à la datasheet, l'ADXL dispose de 2 adresses internes qui sont sélectionnées selon l'état du pin SD0 : à l'état haut, c'est l'adresse 0x1D qui est sélectionnée; à l'état bas, c'est l'adresse 0x53 qui est sélectionnée.

Il suffit donc d'attribuer à chaque capteur l'une des 2 adresses. Pour ce faire, si on souhaite choisir l'adresse 0x1D de l'ADXL, il suffit de mettre la pin SD0 à l'état haut, soit le connecter au 3.3V de l'Arduino. À l'inverse, si on souhaite sélectionner l'adresse 0x53, on connecte le pin SD0 à la masse pour le mettre à l'état bas. Ce faisant, nous obtenons le montage ci-contre.
Montage 2 capteurs

Ainsi, nous pouvons contrôler séparément les 2 capteurs grâce au nouveau programme établit : (programme)

Penchons nous à présent sur les données émises par les capteurs. Commençons d'abord par une description générale de l'accéléromètre. Celui que nous utilisons est un ADXL345 dont les principales caractéristiques sont les suivantes :

  • Type de communication: I2C
  • Plage de mesure : ±2g - ±16g ("g" est une unité d'accélération traduisant l'accélération de la pesanteur sur Terre et correspond à 9.81 m.s-²)
  • Sortie numérique : I2C
  • Système de mesure 3 axes : ±2g/±4g/±8g/±16g
  • Tension de fonctionnement: 3V à 5V
  • Temperature de fonctionnement: -40° to 85°
  • Courant de fonctionnement: 30µA
    Axes de l'ADXL


L'ADXL345 transmet l'accélération sur chaque axe : il envoie une valeur entre 0 lorsqu'on est à l'horizontale et 280 à la verticale. Nous effectuons conversion dans le programme Arduino afin de récupérer l'angle d'inclinaison du capteur. Ce calcul varie en fonction de l'axe sur lequel on effectue la conversion : sur l'axe x, il faut calculer atan( x / (sqrt(square(y) + square(z)))); sur l'axe y il faut calculer atan( y / (sqrt(square(x) + square(z)))); sur l'axe z on calcule atan( sqrt(square(x) + square(y)) / z). Dans notre cas, nous récupérons l'angle sur l'axe x qui correspond à l'angle compris entre l'axe x et l'axe z.

Un soucis se pose, cependant, concernant les capteurs. En effet, les 2 capteurs fonctionnent correctement mais seul un des 2 capteurs semble influencer les servomoteurs. Ce problème reste encore irrésolu malgré les tests et les hypothèses émises.

Partie informatique

Ici nous présenterons la partie informatique, qui concerne notamment la communication entre l'Arduino et la Raspberry. Le projet initial visait à pouvoir contrôler une main via une application web ou des capteurs, mais aussi à recevoir les données desdits capteurs afin de présenter une modélisation virtuelle du système. Notre application web se présente donc en deux parties : celle gérant le mode application et celle gérant le mode capteurs. Pour cela, deux pages .html sont crées afin de naviguer entre les différentes fonctions : notre fichier index.php nous présente deux liens, afin de nous diriger vers le mode voulu : application ou capteurs. De plus, elle présente un bouton Arrêt afin d'éteindre la Raspberry et de pouvoir la débrancher simplement.

Page d'accueil


  • Partie application

Ici, le doigt est contrôlé via deux boutons, présents sur l'application, permettant d'ouvrir et de fermer le doigt. Pour cela, nous avons repris le code qui nous était fourni en exemple, que nous avons réadapté. Cette liaison série nous a présenté un premier problème : nous voulions pouvoir envoyer un caractère lors de l'appui sur un des deux boutons. Un 'f' déclencherait la partie du code sur l'Arduino correspondant pour "fermer" le doigt, de même avec un 'o' qui devait déclencher l'"ouverture" du doigt. Toutefois, nous nous sommes vite aperçu que l'envoi et le traitement de caractère était problématique. Nous avons donc vite décidé de simplement envoyer un entier : pour ouvrir le doigt, au lieu d'envoyer un 'o' (la 15e lettre de l'alphabet), nous enverrons un 15, et pour fermer nous enverrons un 6. Pour cela, nous passerons donc par la fonction sendMessage ()

function sendMessage(ordre){websocket.send(ordre);}

Ainsi, nous passons grâce aux websockets l'ordre voulu. Il peut ainsi être traité par l'Arduino. Dans le body de notre page html, nous plaçons donc les deux boutons ouverture et fermeture qui utilisent la fonction sendMessage() :

<button onclick="sendMessage(8);">Lancer la commande</button>
<button onclick="sendMessage(15);">Ouverture</button>
<button onclick="sendMessage(6);">Fermeture</button>


Il était initialement prévu de pouvoir naviguer directement d'un mode (appli/capteurs) à l'autre, cependant le code implanté sur l'Arduino impose d'envoyer une variable indiquant au système la fin d'un mode, nous imposant ainsi une nouvelle contrainte. En effet, on ne passe plus simplement d'une page à l'autre, mais lors de chaque appui sur un lien, cela interrompt le mode. Ainsi, nous avons ajouté des appels à la fonction sendMessage() dans toutes les balises <a> afin d'envoyer la valeur 9, permettant à l'Arduino de sortir du mode. Il suffit donc, une fois dans la page appli.html, de lancer la commande puis de choisir le bouton ouvrir ou fermer afin de commander le doigt !

AppliDoigt.JPG
Vidéo de mise en mouvement du doigt via l'application

Vous pouvez ici voir que ce ne sont pas les capteurs qui commandent le doigt : ils restent immobiles sur la table. Vous pouvez par contre distinguer le bruit de la souris, avant chaque mouvement du doigt : ce sont les boutons qui sont bien aux commandes.

  • Partie capteurs

Ici, nous utilisons la liaison série dans sa totalité : nous envoyons toujours une variable déclenchant le programme dans l'Arduino, mais nous recevons également des données de celui-ci. En effet, les capteurs n'envoient pas seulement les données vers le doigt pour le commander, afin que celui-ci suive les mouvements, mais ils envoient également ces mêmes données au serveur via le port série. Nous avons le choix : nous pouvons envoyer les positions suivant x ,y, z par exemple. Cependant, nous décidons de traiter ces données au préalable afin d'envoyer l'angle correspondant à la rotation du système. Ainsi, nous pouvons afficher cette valeur, mais surtout modéliser le doigt sur l'application. Le but actuellement est de représenter le doigt de manière simplifiée grâce à un rectangle : il a d'abord fallu réussir à comprendre comment insérer la figure sur l'écran, et comment le faire pivoter en fonction de la valeur reçue. Pour cela, nous utilisons un canvas, dans lequel nous plaçons un rectangle :
Capteurs.png
Ici, vous voyez que la valeur de l'angle envoyée sur le port série est de 13 degrés, et on observe bien que le rectangle a pivoté vers le haut. Pour cela, nous avons inséré dans le script le code suivant :

if (angle_old != angle){
  ctx.rotate(angle_old);
  angle= angle*Math.PI/180;
  ctx.rotate(-angle);
 }
 ctx.fillStyle = 'black';
 ctx.fillRect(0,0, 100, 50);

Ainsi, si la valeur de l'angle change entre deux acquisitions, on replace le rectangle à la place correspondante. Nous n'utilisions pas au départ de variable angle_old. Mais en faisant de telle façon, à chaque acquisition le rectangle tournait de la valeur angle, on voyait donc le rectangle tourner continuellement. Nous avons donc adapté le code afin de ne modifier la position que lorsque la valeur de l'angle change : dans ce cas, on replace le rectangle à sa place initiale puis on le place à sa nouvelle position.
De plus, vous pouvez voir un peu plus haut dans le code qu'on initialise le canvas à chaque appel de la fonction onmessage(). En effet, on appelle cette fonction en continu, si on ne passe pas par cette étape, tous les rectangles restent affichés. De cette façon, on ne garde que l'affichage d'un rectangle.


  • Paramétrage du traitement des données des ADXL345
    Fonction writeTO()
Conversion de donnée en angle
Concernant le traitement des données des accéléromètres, nous avons créé une fonction writeTo() et une fonction readFrom(). La fonction writeTo() prend en paramètres l'adresse du capteur, le registre du capteur sur lequel on souhaite écrire, la valeur de l'octet que l'on souhaite écrire dans le registre. Elle permet d'écrire une valeur sur un registre d'un des capteurs et permet ainsi d'activer le capteur ciblé. La fonction readFrom() prend en paramètres le capteur, l'adresse du registre de données de l'accéléromètre, le nombre d'octets qui vont être lus (6 à raison de 2 pour chaque axe), un buffer dans lequel seront stockées les données lues sur le capteur. Cette fonction sert à récupérer un flux de données transmis par le capteur.
Fonction readFrom()
Ce flux contient les valeurs des positions x, y et z qui seront séparées et stockées dans le buffer qui est un tableau de taille 6 (le nombre d'octet reçu).
Stockage des données
Nous créons 6 variables correspondant aux axes x, y et z (j, k, l respectivement pour le 2e capteur) dans lesquelles nous stockeront les données contenues dans le buffer. Etant stockées sur 2 octets, nous stockeront buffer[0] et buffer[1] dans les variables x (et j), buffer[2] et buffer[3] dans y (et k), buffer[4] et buffer[5] dans z (et l).

Comme dit précédemment, nous recevons des valeurs d'accélération en g comprise entre 0 et 280. Nous avons donc créé une variable de type double pour chaque axe et utilisons la fonction atan() nous permettant de convertir ces mesures en angle. On multiplie cette valeur par 180 ou 3.14 selon l'unité de l'angle voulue (degrés ou radians).

Documents utiles