Différences entre versions de « Projets:Bionic mouse »

De wikilab
Ligne 134 : Ligne 134 :
  
 
<pre>
 
<pre>
int V0 = 350; // (1)** Valeur max de sortie de l'EMG de la contraction de la partie haute de l'avant bras / Max output value from the EMG captor for the upper part of the forearm
+
int V0 = 350;           // (1)** Max output value from the EMG captor for the upper part of the forearm
int V1 = 350; // (2)** Idem mais pour la partie basse / Same but for the lower part of the forearm
+
int V1 = 350;           // (2)** Same but for the lower part of the forearm
int upDuration = 280;  // (3)** Durée d'une contraction "haute" moyenne de l'utilisateur    / Duration of an "up" contraction of the user
+
int upDuration = 280;  // (3)** Duration of an "up" contraction of the user
int downDuration = 200; // (4)** Idem mais pour la contraction "basse"                        / Same but for a "down" contraction  
+
int downDuration = 200; // (4)** Same but for a "down" contraction  
int timerUp = 0;   // Chronomètre pour la durée de la contraction haute / Timer for duration of the upper contraction
+
int timerUp = 0;       // Timer for duration of the upper contraction
int timerDown = 0; //
+
int timerDown = 0;    
  
 
void setup() {
 
void setup() {
 
   Serial.begin(9600);
 
   Serial.begin(9600);
   pinMode(A0, INPUT); // Entrée de l'EMG de la partie haute de l'avant bras / Input from the EMG captor for the upper part of the forearm
+
   pinMode(A0, INPUT);   // Input from the EMG captor for the upper part of the forearm
   pinMode(A1, INPUT); // Entrée de l'EMG de la partie basse de l'avant bras / Input from the EMG captor for the lower part of the forearm
+
   pinMode(A1, INPUT);   // Input from the EMG captor for the lower part of the forearm
   pinMode(2, OUTPUT); // Sortie sur le clic gauche / Output signal towards the left click
+
   pinMode(2, OUTPUT);   // Output signal towards the left click
   pinMode(3, OUTPUT); // Sortie sur le clic droit  / Output signal towards the right click
+
   pinMode(3, OUTPUT);   // Output signal towards the right click
 
    
 
    
 
}
 
}
  
 
void loop() {
 
void loop() {
   digitalWrite(2,LOW); // Initialisation des signaux de sortie à 0 pour ne pas avoir de clics rémanents entre deux boucles.
+
   digitalWrite(2,LOW); // Initialize the output signals to 0 to avoid persistent clicks between two loops.
  digitalWrite(3,LOW); // Initialize the output signals to 0 to avoid persistent clicks between two loops.
+
  digitalWrite(3,LOW);
 
   timerUp = 0;  
 
   timerUp = 0;  
 
   timerDown = 0;
 
   timerDown = 0;
   while(upIsHold() and timerUp<4*upDuration){ // (5)* Tant que la contraction haute est maintenu pendant au plus 4*upDuration, / As long as the high contraction is maintained for at most 4*upDuration,  
+
   while(upIsHold() and timerUp<4*upDuration){           // (5)* As long as the high contraction is maintained for at most 4*upDuration,  
     delay(10);                               //   on incrémente 10 ms au chronometre.                                      / the timer is incremented by 10 ms.
+
     delay(10);                                           //     the timer is incremented by 10 ms.
 
     timerUp += 10;
 
     timerUp += 10;
 
   }
 
   }
   while(downIsHold() and timerDown<3*downDuration){// (6)* Idem pour la contraction basse pendant au plus 3*upDuration / Same for the low contraction for a maximum of 3*upDuration
+
   while(downIsHold() and timerDown<3*downDuration){     // (6)* Same for the low contraction for a maximum of 3*upDuration
 
     delay(10);
 
     delay(10);
 
     timerDown += 10;
 
     timerDown += 10;
 
   }
 
   }
   if(timerUp>20 and timerUp<=upDuration){ // Clic gauche simple / Simple left click
+
   if(timerUp>20 and timerUp<=upDuration){               // Simple left click
 
     digitalWrite(2,HIGH);
 
     digitalWrite(2,HIGH);
 
     delay(50);
 
     delay(50);
Ligne 177 : Ligne 177 :
 
     digitalWrite(2,LOW);   
 
     digitalWrite(2,LOW);   
 
   }
 
   }
   else if(timerUp>2*upDuration){ // Triple clic.k
+
   else if(timerUp>2*upDuration){                         // Triple clic.k
 
     digitalWrite(2,HIGH);
 
     digitalWrite(2,HIGH);
 
     delay(50);
 
     delay(50);
Ligne 190 : Ligne 190 :
 
     digitalWrite(2,LOW);     
 
     digitalWrite(2,LOW);     
 
   }
 
   }
   if(timerDown>10 and timerDown<=downDuration){ // Clic droit / Right click
+
   if(timerDown>10 and timerDown<=downDuration){         // Right click
 
     digitalWrite(3,HIGH);
 
     digitalWrite(3,HIGH);
 
     delay(50);
 
     delay(50);
 
     digitalWrite(3,LOW);     
 
     digitalWrite(3,LOW);     
 
   }
 
   }
   else if(timerDown>downDuration){ // Clic maintenu / Hold click
+
   else if(timerDown>downDuration){                       // Hold click
 
     do{
 
     do{
 
       digitalWrite(2,HIGH);
 
       digitalWrite(2,HIGH);
Ligne 201 : Ligne 201 :
 
     digitalWrite(2, LOW);
 
     digitalWrite(2, LOW);
 
   }
 
   }
   // Serial.print(timerDown);  Commandes permettant d'afficher les différentes durées de contraction, afin d'adapter le code à chacun
+
   // Serial.print(timerDown);  Commands to display the different contraction times, in order to adapt the code to each individual
   // Serial.print("    ");    Commands to display the different contraction times, in order to adapt the code to each individual
+
   // Serial.print("    ");     
 
   // Serial.println(timerUp);
 
   // Serial.println(timerUp);
 
   // delay(80);
 
   // delay(80);
 
}
 
}
 
    
 
    
bool upIsHold(){ // Fonction permettant de determiner à l'instant de l'appel s'il y a contraction haute ou non / Function to determine at the moment of the call whether there is a high contraction or not  
+
bool upIsHold(){   // Function to determine at the moment of the call whether there is a high contraction or not  
 
   bool upIsHold = 0;
 
   bool upIsHold = 0;
   if((analogRead(A0)>0.6*V0)and(analogRead(A1)<0.6*V1)) upIsHold = 1; // (7)* Valeur seuil de détection de la contraction haute, / Threshold value for detecting high contraction,
+
   if((analogRead(A0)>0.6*V0)and(analogRead(A1)<0.6*V1)) upIsHold = 1;   // (7)* Threshold value for detecting high contraction,
   return upIsHold;                                                   //   ici fixée à 60% de la valeur de contraction max V0 / here set at 60% of the max contraction value V0
+
   return upIsHold;                                                     //     here set at 60% of the max contraction value V0
 
}
 
}
  
bool downIsHold(){ // Idem pour la contraction basse
+
bool downIsHold(){ // Same for the lower contraction
 
   bool downIsHold = 0;
 
   bool downIsHold = 0;
 
   if((analogRead(A1)>0.6*V1)and(analogRead(A0)<0.6*V0)) downIsHold = 1; // (8)*
 
   if((analogRead(A1)>0.6*V1)and(analogRead(A0)<0.6*V0)) downIsHold = 1; // (8)*
 
   return downIsHold
 
   return downIsHold
}
+
} </pre>
 
+
 
</pre>
 
 
'''(code bionic mouse v4)'''
 
'''(code bionic mouse v4)'''
 
    
 
    

Version du 19 juillet 2021 à 08:43

Description du projet

Le but de ce projet est de réaliser une prothèse permettant à des utilisateurs dépourvus d'une main valide de pouvoir se servir d’une souris d’ordinateur.

Cette solution s'adapte au poignet universel commercialisé par l’entreprise Orthopus, et utilise les contractions musculaires de l’avant-bras comme de signaux de commande des clics de la souris.

Cahier des charges

Objectif : Contrôler le déplacement du curseur et des clics droit et gauche d'une souris d'ordinateur en utilisant les contractions musculaires de l'avant-bras comme signaux de commandes.

Pour qui : Pour toutes personnes désirant utiliser une souris d'ordinateur comme outil au bout d'un poignet universel recevant les signaux de contractions musculaires de l'avant-bras.

Fonctions :

  • Déplacement du curseur sur l'écran
  • Clic gauche
  • Clic droit

Contraintes :

  • Réalisable dans un FabLab
  • La solution développée s’adapte sur le poignet universel
  • La solution n’est pas exclusive, elle doit pouvoir se répliquer sur un maximum de souris

Combien :

 : Au Humanlab, ou dans un Fablab proche de chez vous : Carte des Fablabs par Makery

Analyse de l'existant

Un projet similaire réalisé au Humanlab permet de contrôler un curseur d'ordinateur et de déclencher les clics de la souris à l'aide d'un joystick : le projet Dé'clic.

La différence est que le projet Dé'clic utilise un module HID (pour Human Interface Device) qui vient remplacer complètement la souris par le joystick alors que le projet Bionic Mouse transforme une souris classique d'ordinateur.

Equipe (Porteur de projet et contributeurs)

  • Porteur de projet : Nico
  • Contributeurs : Pierre M
  • Animateur (coordinateur du projet)
  • Fabmanager référent : Yo
  • Responsable de documentation : Pierre M

Matériel nécessaire

Outils nécessaires

  • Tournevis de précision
  • Fer à souder
  • Pompe à dessouder
  • Pince à dénuder
  • Ordinateur avec le logiciel Arduino
  • Carte Arduino Uno ou Nano
  • Cable USB A-Mini USB (Nano et Mini) et USB A-USB B (Uno)
  • Imprimante 3D
  • Clef allen

Coût

Délai estimé

Fichiers source

Étapes de fabrication pas à pas

Pour cet exemple, on utilise une souris filaire NGS disponible ici, mais ces bidouilles sont reproductibles sur la plupart des souris.

1 - Démontage de la souris

La première étape est de repérer sur votre souris où est la petite vis qui maintient la souris entière. Elle peut être directement visible, cachée sous une étiquette, ou sous le capot des piles pour une souris bluetooth.

Cependant, il arrive que des souris ne soient pas démontables via une vis, je vous conseille donc de changer de souris pour vous éviter de forcer l'ouverture de la souris et de risquer de la casser.

Souris non démontée.jpg

2 - Retrait du circuit imprimé

Une fois la souris ouverte, il vous faut retirer le circuit imprimé afin d'accéder aux soudures de celui ci.

Faites attention à ne pas endommager les clips d'attache du circuit imprimé, par la suite on remettra le circuit à sa place et il faudra qu'il tienne en place pour que le système optique de la souris continue de fonctionner correctement.

Faites également attention à ne pas perdre le prisme en plastique en dessous de la souris.

Circuit imprimé visible.jpg Circuit imprimé non déssoudé recto.jpg Circuit imprimé non déssoudé verso.jpg


Prisme à ne pas perdre!


3 - Dessoudage (ou dessoudure?) des boutons poussoirs des clics de la souris

Repérez les boutons poussoirs correspondants aux clics gauche et droit de la souris.

Circuit imprimé non déssoudé recto entouré.jpg Circuit imprimé non déssoudé verso entouré.jpg

A l'aide d'un fer à souder et d'une pompe à dessouder, retirez ces boutons poussoirs du circuit imprimé.

Repérez également quelles pattes du bouton poussoir étaient soudées au circuit imprimé. Ce sont à ces endroits que l'on soudera deux fils par clic plus tard.

Si jamais les trois pattes du boutons poussoirs étaient soudées, vérifiez où se fait la fermeture du bouton poussoir à l'aide d'un multimètre réglé sur la fonction "bipeur". Demandez de l'aide à un fabmanager si vous ne savez pas comment faire.

Circuit dessoudé.jpg Bouton poussoir entouré.jpg

4 - Choix et connexion de la carte Arduino

Vous pouvez choisir une carte Arduino Nano ou une Mini pro. La différence majeure est que la Mini n'a pas de connecteur USB pour téléverser le code, il faut donc utiliser un adaptateur (cf. Matériel nécessaire), souvent disponible dans les Fablabs. En revanche elle a l'avantage d'être plus petite et moins chère que la Nano. Le choix vous revient. Les soudures finales seront similaires.

Je recommande toutefois l'Arduino Nano car le code peut être amené à changer au cours de l'utilisation de la souris, notamment en ce qui concerne la vitesse de clic. Ainsi, avec une Nano, il est plus facile de modifier le code car il y a un connecteur USB alors que la manip sera plus difficile avec une Mini pro.

4.1 - Arduino Nano

La carte Arduino Nano se connecte à l'ordinateur via un câble USB-Mini USB.

Câble USB-mini USB Nano branchée.jpg

4.2 - Arduino Mini Pro

La carte Arduino Mini Pro se connecte à l'ordinateur via un adaptateur lui même relié à l'ordinateur par un câble USB-Mini USB.

Adaptateur Mini branchée.jpg

5 - Explication du code Arduino

Récupérez le code Arduino ci-dessous.

int V0 = 350;           // (1)** Max output value from the EMG captor for the upper part of the forearm
int V1 = 350;           // (2)** Same but for the lower part of the forearm
int upDuration = 280;   // (3)** Duration of an "up" contraction of the user
int downDuration = 200; // (4)** Same but for a "down" contraction 
int timerUp = 0;        // Timer for duration of the upper contraction
int timerDown = 0;      

void setup() {
  Serial.begin(9600);
  pinMode(A0, INPUT);   // Input from the EMG captor for the upper part of the forearm
  pinMode(A1, INPUT);   // Input from the EMG captor for the lower part of the forearm
  pinMode(2, OUTPUT);   // Output signal towards the left click
  pinMode(3, OUTPUT);   // Output signal towards the right click
  
}

void loop() {
  digitalWrite(2,LOW);  // Initialize the output signals to 0 to avoid persistent clicks between two loops.
  digitalWrite(3,LOW); 
  timerUp = 0; 
  timerDown = 0;
  while(upIsHold() and timerUp<4*upDuration){            // (5)* As long as the high contraction is maintained for at most 4*upDuration, 
    delay(10);                                           //      the timer is incremented by 10 ms.
    timerUp += 10;
  }
  while(downIsHold() and timerDown<3*downDuration){      // (6)* Same for the low contraction for a maximum of 3*upDuration
    delay(10);
    timerDown += 10;
  }
  if(timerUp>20 and timerUp<=upDuration){                // Simple left click
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);    
  }
  else if(timerUp>upDuration and timerUp<=2*upDuration){ // Double clic.k
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);
    delay(50);
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);   
  }
  else if(timerUp>2*upDuration){                         // Triple clic.k
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);
    delay(50);
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);
    delay(50);
    digitalWrite(2,HIGH);
    delay(50);
    digitalWrite(2,LOW);    
  }
  if(timerDown>10 and timerDown<=downDuration){          // Right click
    digitalWrite(3,HIGH);
    delay(50);
    digitalWrite(3,LOW);     
  }
  else if(timerDown>downDuration){                       // Hold click
    do{
      digitalWrite(2,HIGH);
    }while(not(upIsHold()));
    digitalWrite(2, LOW);
  }
  // Serial.print(timerDown);  Commands to display the different contraction times, in order to adapt the code to each individual
  // Serial.print("    ");     
  // Serial.println(timerUp);
  // delay(80);
}
  
bool upIsHold(){   // Function to determine at the moment of the call whether there is a high contraction or not 
  bool upIsHold = 0;
  if((analogRead(A0)>0.6*V0)and(analogRead(A1)<0.6*V1)) upIsHold = 1;   // (7)* Threshold value for detecting high contraction,
  return upIsHold;                                                      //      here set at 60% of the max contraction value V0
}

bool downIsHold(){ // Same for the lower contraction
  bool downIsHold = 0;
  if((analogRead(A1)>0.6*V1)and(analogRead(A0)<0.6*V0)) downIsHold = 1; // (8)*
  return downIsHold
} 

(code bionic mouse v4)

Ouvrez le fichier sur le logiciel Arduino de l'ordinateur. Si le logiciel n'est pas installé sur votre ordinateur, vous pouvez le télécharger ici et l'installer. (Le logiciel est gratuit rassurez vous (; )

Lisez attentivement les commentaires du code et repérez les endroits où les valeurs devront changer, en particulier les valeurs de V0 et de V1.



6 - Détermination des valeurs V0 et V1

Les valeurs seuils peuvent changer d'un utilisateur à l'autre, il faut donc vérifier quelles valeurs sont transmises par vos capteurs EMG jusqu'au bout du poignet universel. Repérez ces 4 fils :

  • Vbatt (fil rouge souvent) : c'est la tension d'alimentation de la batterie de vos capteurs EMG
  • GND (pour Ground) (fil noir souvent) : c'est la masse de vos capteurs EMG
  • Signal EMG 1 : c'est le signal de votre premier capteur EMG
  • Signal EMG 2 : idem pour le deuxième capteur

Munissez vous d'une carte Arduino Uno ou Nano (il faut qu'elle puisse se connecter directement à l'ordinateur) et faites les branchements ci-dessous avec le poignet. A noter que pour ce circuit on ne se servira pas du fil Vbatt du poignet.

Lecture EMG Uno.jpg Lecture EMG Nano.jpg

Branchez la carte Arduino à l'ordinateur puis recopiez le code ci-dessous dans le logiciel Arduino. Vérifiez bien qu'il n'y a pas d'erreur dans le code en cliquant sur l'icône en haut à gauche.

 void setup() {
   pinMode(A0, INPUT); // Entrée du capteur de la contraction haute / High contraction sensor input
   pinMode(A1, INPUT); // Entrée du capteur de la contraction basse / Low contraction sensor input
   Serial.begin(9600);
 }
 void loop() {
   Serial.print(analogRead(A0));   // Colonne de gauche / Left column
   Serial.print("     ");
   Serial.println(analogRead(A1)); // Colonne de droite / Right column
   delay(200);
 }

Icone de vérification, raccourci clavier : Ctrl + R Icone de téléversement, Ctrl + U

S'il n'y a pas d'erreur, allez dans Outils>Type de carte, et vérifiez que le type correspond bien à la carte branchée. Sélectionnez aussi le port de votre ordinateur correspondant et finalement, téléverser le code.

Ouvrez le moniteur série dans Outils>Moniteur Série (raccourci clavier Ctrl + Shift + M).

Si tout s'est bien passé, vous devriez voir défiler deux colonnes de valeurs : ce sont les valeurs des capteurs EMG transmises en direct par le poignet jusqu'à la carte Arduino. L'idée est de contracter la partie haute ou basse de l'avant-bras et de repérer les changements de valeurs.

Au repos, les valeurs affichées varient peu et tournent normalement autour de 0.

Maintenant, si vous simulez une levée de la main et contractez la partie haute de l'avant-bras (entrée A0), les valeurs affichées doivent augmenter pour la colonne de gauche, jusqu'à une valeur max V0. Pour être sûr de bien déterminer V0, faites plusieurs mesures en reproduisant ce mouvement de levée de la main, et faites une moyenne des différents maximums. Ainsi, vous avez déterminé la valeur V0! Notez cette valeur, on en aura besoin plus tard.

Attention : Il est important de bien différencier les câbles des contractions haute et basse. Si ce sont bien les valeurs de la colonne de gauche qui varient pour une contraction de la partie haute de l'avant-bras, alors les branchements sont corrects et vous pouvez noter quel fil correspond à quelle contraction. Si en revanche ce sont les valeurs de la colonne de droite qui augmentent lors de la contraction de la partie haute de l'avant-bras, c'est tout simplement qu'il faut inverser les câbles d'entrées de l'Arduino : le câble branché en A0 doit en fait être branché sur A1, et inversement. Une fois le changement fait, notez que le fil branché en A0 correspond à la contraction haute.

De la même manière, déterminez la valeur V1 avec cette fois une contraction de la partie basse de l'avant-bras.

7 - Modification du code Arduino de l'étape 5

De retour sur ce code, vous pouvez désormais remplacez les constantes V0 et V1 par les valeurs déterminées à l'étape 6.


Une fois toutes les modifications faites, vérifiez encore une fois qu'il n'y a pas d'erreur dans le code et finalement téléversez le sur votre carte Arduino Nano ou Mini.

8 - Alimentation de la carte Arduino

Durée de fabrication du prototype final