Projet IMA3 P5, 2016/2017, TD1 : Différence entre versions

De Wiki de Projets IMA
(Scéance supplémentaire 3: Montage de la harpe)
 
(61 révisions intermédiaires par 3 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
= Projet IMA3-SC 2016/2017 : Synt'Harpe (Sainte) Laser =
 
= Projet IMA3-SC 2016/2017 : Synt'Harpe (Sainte) Laser =
 +
 +
Lien vers le Git du projet: https://archives.plil.fr/mdelapor/SC_Harpe_Laser_IMA3/tree/master/projetSC
  
 
== Cahier des charges ==
 
== Cahier des charges ==
Ligne 42 : Ligne 44 :
 
Le principe de fonctionnement de la harpe est le suivant:
 
Le principe de fonctionnement de la harpe est le suivant:
 
Chaque capteur sera situé en face d'un laser. Les capteurs seront dans la partie haute de la harpe afin de limiter les interférences dues à d'autres sources lumineuses. Chaque laser pointera vers un capteur.  
 
Chaque capteur sera situé en face d'un laser. Les capteurs seront dans la partie haute de la harpe afin de limiter les interférences dues à d'autres sources lumineuses. Chaque laser pointera vers un capteur.  
 
* Ajout du dessin de la harpe *
 
  
 
Les capteurs enverront tous par défaut la même valeur au FPGA. Quand l'utilisateur passera sa main dans la harpe, un faisceau laser sera coupé. Le capteur n'enverra plus sa valeur seuil au FPGA, il aura donc changé d'état.
 
Les capteurs enverront tous par défaut la même valeur au FPGA. Quand l'utilisateur passera sa main dans la harpe, un faisceau laser sera coupé. Le capteur n'enverra plus sa valeur seuil au FPGA, il aura donc changé d'état.
 
Dès lors que le FPGA détectera un changement d'état, il enverra l'état dans lequel se trouvent les 8 capteurs au Raspberry.  
 
Dès lors que le FPGA détectera un changement d'état, il enverra l'état dans lequel se trouvent les 8 capteurs au Raspberry.  
 
 
  
 
Nous avons réalisé des tests sur les phototransistors et les lasers. Nous avons mis en parallèle un laser et deux capteurs, sans oublier leur résistance de 1.2k Ohms chacune.  
 
Nous avons réalisé des tests sur les phototransistors et les lasers. Nous avons mis en parallèle un laser et deux capteurs, sans oublier leur résistance de 1.2k Ohms chacune.  
  
 
Nous avons vu que à luminosité ambiante, quand le laser pointe sur le capteur, celui-ci envoie à l'Arduino une valeur de 950 environ. Ensuite, quand le faisceau laser est coupé, la valeur envoyée par le phototransistor monte à 1020.
 
Nous avons vu que à luminosité ambiante, quand le laser pointe sur le capteur, celui-ci envoie à l'Arduino une valeur de 950 environ. Ensuite, quand le faisceau laser est coupé, la valeur envoyée par le phototransistor monte à 1020.
Puis, nous avons réitéré l'expérience en mettant le système dans une boîte. (schrodinger #blague #amusement #drole #notreparagrapheaetesupprimeunefois). Cette fois, le valeur est passée de 840 quand le capteur est éclairé par le laser à 900 quand le faisceau est coupé.
+
Puis, nous avons réitéré l'expérience en mettant le système dans une boîte. Cette fois, le valeur est passée de 840 quand le capteur est éclairé par le laser à 900 quand le faisceau est coupé.
 
Nous en avons déduit que nous allons devoir refaire l'expérience une fois la harpe assemblée.
 
Nous en avons déduit que nous allons devoir refaire l'expérience une fois la harpe assemblée.
  
 
Les lasers étant très directionnels tout comme les phototransistors, nous n'aurons pas de soucis d'interférences. Un capteur détectera uniquement le laser situé directement en face de lui et non ceux de son voisinage.
 
Les lasers étant très directionnels tout comme les phototransistors, nous n'aurons pas de soucis d'interférences. Un capteur détectera uniquement le laser situé directement en face de lui et non ceux de son voisinage.
 +
 +
=== Partie boitier ===
 +
 +
Même si il peut paraitre futile d'insérer une partie boitier dans un projet centré sur l'informatique et l'électronique, il s'est avéré que le boitier de notre Harpe nécessitait une attention particulière.
 +
 +
La taille de la harpe à été un sujet de débat, et nous avons réalisé des tests afin de vérifier que des phototransistors trop proches les uns des autres n'allait pas compromettre le bon fonctionnement de la harpe dans son ensemble. En effet, si le phototransistor détectait un autre laser que celui vers lequel il pointe serait extrêmement problématique. Heureusement, il s'est avéré que les phototransistors sont très directionnels, au point que se pose désormais le problème inverse.
 +
 +
Nous allons devoir faire très attention au fait que les lasers soient bien fixés et pointent exactement vers les phototransistors, car dans le cas contraire, ceux-ci ne détectent absolument pas le laser, et tout le principe de fonctionnement s'effondre. La conception et l'assemblage de la boite devront donc être relativement précis, pour éviter ces problèmes.
 +
 +
Enfin, nous avons dès le départ décidé d'éviter l'utilisation de diodes infra-rouges, pour leur préférer les lasers. Tout d'abord, parce que les diodes ne sont en aucun cas assez puissantes pour être détectées par les phototransistors, ce qui une fois de plus rend notre harpe inutile. Ensuite, parce qu'il nous a semblé que réaliser une harpe 'laser' sans lasers était un concept déconcertant, et enlève beaucoup de l’intérêt de ce projet.
 +
 +
Un premier jet de design avait été réalisé avant cette séance, et au vu des données récoltées pendant celle-ci, nous l'avons modifié pour les prendre en compte, notamment la taille des lasers par rapport aux diodes, et la précision requise.
  
 
=== Partie informatique ===
 
=== Partie informatique ===
Ligne 68 : Ligne 78 :
  
 
Coté mise en place du serveur web, l'utilitaire de serveur web apache2 a été installé sans soucis, et les pages d'exemples web et javascript fonctionnent. En revanche, l'utilisation du code d'exemple sur les sockets n'est pas utilisable, le paquet proposé n’existe pas et le site du paquet de socket est mort.
 
Coté mise en place du serveur web, l'utilitaire de serveur web apache2 a été installé sans soucis, et les pages d'exemples web et javascript fonctionnent. En revanche, l'utilisation du code d'exemple sur les sockets n'est pas utilisable, le paquet proposé n’existe pas et le site du paquet de socket est mort.
Le reste de la séance a été consacré a des recherches sur les moyens de pouvoir streamer du son, recherches non concluantes. Aucune solution n'a été trouvé sans passé par un service internet hébergé par un tier.
+
Le reste de la séance a été consacré a des recherches sur les moyens de pouvoir streamer du son, recherches non concluantes. Aucune solution n'a été trouvé sans passer par un service internet hébergé par un tier.
 +
 
 +
 
 +
==== Partie lecture port série ====
 +
 
 +
Cette première séance fut consacrée à la sélection du langage de programmation et à sa prise en main. Il a été décidé d'utiliser Python pour écrire le programme récupérant et traitant les données récupérées à travers le port série. Python étant un langage fort usité, il possède une très large documentation. Ce fut donc facile de trouver la librairie permettant de lire les données envoyées par le port série.
 +
 
 +
Un doute subsiste encore sur le type de données envoyé par le port série. L'idéal serait de récupérer un tableau de 8 entiers de type binaire correspondant aux états des 8 ports liés aux "cordes" laser, pour pouvoir ensuite traiter ces données facilement.
 +
 
 
== Séance 2 ==
 
== Séance 2 ==
  
 
=== Partie électronique ===
 
=== Partie électronique ===
 +
Lors de cette séance, nous avons réalisé le premier circuit sur le FPGA.
 +
 +
Nous avons commencé par réaliser un circuit simple, qui envoie en permanence l'état des huit phototransistors au port série. Les phototransistors sont alors directement reliés à celui-ci. Nous avons pu tester le bon fonctionnement du système grâce aux diodes du FPGA. Nous avons branché en parallèle sur le circuit les huit diodes, afin de vérifier qu'un signal était bien envoyé en permanence, on a pu les voir s'éteindre lorsqu'on éclairait un laser.
 +
Ces diodes se sont avérées très utiles, car il n'est pas encore possible d'effectuer les tests sur le port série, car la partie informatique n'est pas encore opérationnelle, on ne peut donc pas lire directement sur le port série pour le moment.
 +
 +
 +
[[Fichier:Envoiconstant.JPG]]
 +
 +
 +
 +
Nous avons ensuite réalisé un montage permettant de faire l'envoi seulement sur changement d'état, comme prévu à la séance 1 Nous avons donc réalisé un système de bascules permettant de comparer l'état actuel de chaque diode avec son état précédent, puis de réaliser l'envoi seulement si une différence était observée. Comme précédemment, les diodes sont reliées directement au Port Série, mais cette fois-ci au lieu de brancher le Bit d'envoi du port Série sur un Vcc, soit un '1' logique, nous l'avons relié à la vérification de changement d'état, qui passe à '1' uniquement avec un changement d'état.
 +
 +
[[Fichier:Changementdetat.JPG]]
 +
 +
 +
Le problème qui s'est alors posé était de savoir si on envoyait le signal assez longtemps pour qu'il puisse être lu. En effet on envoie un signal seulement si il y a changement d'état, et cette vérification se fait à chaque incrément d'horloge. Hors, la différence sera donc observée sur un seul incrément d'horloge, par conséquent, on n'envoie de signal que pendant ce seul incrément. Pour l'instant, nous supposons que le port série est capable de stocker les données à envoyer en un seul incrément d'horloge.
 +
Cependant, si lors des tests, ça ne fonctionne pas, nous prévoyons d'utiliser un compteur pour pouvoir envoyer le signal plus longtemps au Bit d'envoi du port série, et ainsi laisser le temps au port série d'envoyer l'information.
 +
 +
=== Partie boitier ===
 +
 +
Pendant cette séance, nous nous sommes focalisés sur le FPGA, mais nous avons néanmoins terminé la conception du boitier de la harpe, sous la forme de trois 'boites' crénelées, que nous avons ensuite l'intention de découper au FabLab puis d'assembler.
 +
 +
 +
[[Fichier:Boites.jpg|400px]]
 +
 +
 +
Il s'est avéré que réaliser des boites crénelées rendrait tout le boitier beaucoup plus solide, et donc fiable.
  
 
=== Partie informatique ===
 
=== Partie informatique ===
 +
Le problème de l'impossibilité d'utiliser l'exemple sur les sockets a été résolu, grâce à l'intervention de M. Redon. Le problème était une différence de version de la distribution Linux entre le RPi utilisé et celle utilisé pour l'exemple. En effet, le RPi de travail est sur une distribution Wheezy, alors que la version la plus récente est la Jessie. Les chemins des dépots des sources de la librairie libwebsocket n’existant pas sur Wheezy, on ne pouvait installer la librairie directement en ligne de commande. M. Redon a ajouté le chemin de la librairie dans le gestionnaire de paquet du RPi et on a pu utiliser sans problèmes la librairie. De plus le site du paquet libwebsocket n'était inaccessible que temporairement.
 +
La séance a été consacré à comprendre le fonctionnement des sockets et comment l'exemple html interagissait avec.
 +
 +
La partie importante du code d'exemple est la suivante :
 +
 +
<pre>static int callback_my(
 +
  struct libwebsocket_context * this,
 +
  struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason,
 +
  void *user,void *in,size_t len)
 +
{
 +
static char *message=NULL;
 +
static int msize=0;
 +
switch(reason){
 +
  case LWS_CALLBACK_ESTABLISHED:
 +
    printf("connection established\n");
 +
    message=NULL;
 +
                // Declenchement d'un prochain envoi au navigateur
 +
    libwebsocket_callback_on_writable(this,wsi);
 +
    break;
 +
  case LWS_CALLBACK_RECEIVE:
 +
                // Ici sont traites les messages envoyes par le navigateur
 +
    printf("received data: %s\n",(char *)in);
 +
    message=malloc(len+LWS_SEND_BUFFER_PRE_PADDING+LWS_SEND_BUFFER_POST_PADDING);
 +
    if(message==NULL){ perror("callback_my.malloc"); exit(EXIT_FAILURE); }
 +
    memcpy(message+LWS_SEND_BUFFER_PRE_PADDING,in,len);
 +
                // Declenchement d'un prochain envoi au navigateur
 +
    msize=len;
 +
    libwebsocket_callback_on_writable(this,wsi);
 +
    break;
 +
  case LWS_CALLBACK_SERVER_WRITEABLE:
 +
                // Ici sont envoyes les messages au navigateur
 +
    if(message!=NULL){
 +
      char *out=message+LWS_SEND_BUFFER_PRE_PADDING;
 +
      libwebsocket_write(wsi,(unsigned char *)out,msize,LWS_WRITE_TEXT);
 +
      free(message);
 +
      message=NULL;
 +
      }
 +
    break;
 +
  default:
 +
    break;
 +
  }
 +
return 0;
 +
}
 +
</pre>
 +
Il s'agit d'une fonction de callback gérant à la fois la réception et la transmission. On peut remarquer 3 cas du switch : LWS_CALLBACK_ESTABLISHED correspondant à la création d'un lien entre la page web et le serveur websocket à la demande de la page web, LWS_CALLBACK_RECEIVE correspondant aux actions à entreprendre à la réception d'un message provenant du navigateur web, et LWS_CALLBACK_SERVER_WRITEABLE correspondant aux actions afin d'envoyer un message au navigateur.
 +
 +
Coté HTML, on utilise les sockets grâce à ce code suivant :
 +
 +
<pre>window.WebSocket=(window.WebSocket||window.MozWebSocket);
 +
var websocket=new WebSocket('ws://127.0.0.1:9000','myprotocol');
 +
websocket.onopen=function(){ $('h1').css('color','green'); };
 +
websocket.onerror=function(){ $('h1').css('color','red'); };
 +
websocket.onmessage=function(message){
 +
console.log(message.data);
 +
$('#messages').append($('<p>',{ text: message.data }));
 +
};
 +
function sendMessage(){
 +
websocket.send($('#message').val());
 +
$('#message').val('');
 +
}</pre>
 +
 +
 +
 +
La fonction websocket.onmessage gère le traitement à faire coté client quand le serveur envoie des informations, et la fonction sendMessage permet l'envoie d'information du client vers le serveur.
 +
 +
Pour notre projet, nous avons besoin principalement, dans un premier temps, d'envoyer des informations du serveur vers le client, nous nous sommes donc concentrer à comprendre et modifier les parties du code fourni suivantes : websocket.onmessage coté client et le "case LWS_CALLBACK_SERVER_WRITEABLE:" coté serveur.
 +
 +
Le but des tests était de réussir à faire jouer deux sons différents par le client, avec changement de son imposé par le serveur. HTML5 propose nativement de lire des sons à partir d'une source grâce à une balise audio :
 +
 +
<audio controls="controls" id="mySound">
 +
    </audio>
 +
 +
On récupère l'identifiant de cette balise avec
 +
 +
var test1 = document.getElementById("mySound");
 +
 +
afin de pouvoir l'utiliser de n'importe où dans le programme.
 +
On définit la source grâce à
 +
 +
test1.src="sound.mp3";
 +
 +
avec "sound.mp3" le chemin d'accès au fichier son par rapport à l'emplacement du fichier html sur le serveur. Ici, le fichier son sound.mp3 est dans le même dossier que la page index.html.
 +
Enfin, on peut lire le son avec
 +
 +
test1.play();
 +
 +
Le but du projet étant d'émettre en continue le son généré par la harpe, l'objectif ici est soit de générer un fichier de streaming que l'on lit en continue, soit de lire un fichier différent par son possible et on change la valeur de test1.src en fonction du son à lire, soit on lit toujours la même source, mais que l'on modifie à la volée en fonction du son voulu. La première option a été étudiée jusqu'en fin de séance.
 +
Nous n'avons pas réussi à comprendre comment générer un fichier de streaming audio simple, de plus toutes les documentations et exemples trouvés ne concernant qu'un streaming simultanée de son et de vidéo à partir d'une caméra et d'un micro, et nous n'avons pas compris comment adapter ces exemples.
  
 
== Séance 3 ==
 
== Séance 3 ==
  
 
=== Partie électronique ===
 
=== Partie électronique ===
 +
 +
Pendant cette séance, nous avons pu tester l'envoi sur changement d'état, toujours avec les diodes du FPGA.
 +
 +
Nous avons commencé par ajouter une horloge sur le détecteur de changement d'état, afin d'augmenter le nombre d'incréments d'horloge sur lequel il est à '1', et ce dans le but de rendre le clignotement d'un diode visible à l’œil nu.
 +
Ensuite, nous avons relié la sortie du détecteur de changement d'état et des phototransistors par un 'ET' logique, que nous avons ensuite relié aux diodes du FPGA.
 +
De cette façon, si l'on détecte un changement d'état sur un phototransistor, la nouvelle valeur est alors envoyée sur les diodes. Le système a fonctionné, nous disposons donc d'un système envoyant sur la liaison série 8 bits correspondant à l'état des 8 diodes, en utilisant le Fpga.
 +
 +
Nous avons ensuite passé le reste de la séance à mettre en commun notre partie avec la partie informatique, en essayant de leur permettre de lire sur le port série du FPGA. Les essais ont pour l'instant été infructueux, mais des progrès ont été faits.
 +
 +
L'objectif étant que le Raspberry Pi puisse lire les informations envoyées par le FPGA, pour ensuite les transmettre au site Web que nous allons réaliser par la suite.
  
 
=== Partie informatique ===
 
=== Partie informatique ===
 +
Au vu des difficultés rencontrées lors de la mise en place d'un véritable système de streaming, nous avons décider d'étudier les autres options possibles.
 +
Notre deuxième solution était de modifier la valeur de test1.src. Mais cela voulait dire effectuer beaucoup de traitement coté client, et si on décidait de rajouter beaucoup de son, ou de générer de nouveaux fichiers son, ce la demandait soit de modifier le HTML à chaque ajout de fonctionnalité, ou de créer une grande quantité de fichier son qui pollueraient le serveur. Nous avons donc décidé qu'il serait plus pratique de toujours écraser la source avec le nouveau son a lire, et de ne jamais changer la valeur de test1.src.
 +
 +
Afin d'effectuer des tests afin de voir si notre idée marchait bien, nous avons utiliser le code C très simple suivant :
 +
 +
  <pre>int cpt;
 +
  for (cpt = 0; cpt < 250000000; cpt++);
 +
 +
    boole = !boole;
 +
printf("changement: %d\n",boole);
 +
    if(boole)
 +
      system("sudo cp Level-complete-sound-effect.mp3 ./sound.mp3");
 +
    else
 +
      system("sudo cp Raindrops-noise.mp3 ./sound.mp3");
 +
  }</pre>
 +
 +
Ce code nous permet de modifier assez fréquemment le fichier source. Les fichiers audio de tests ont été trouvé sur http://www.orangefreesounds.com/ et sont libre de droit.
 +
 +
Dans la page HTML de test nous utilisé les options de la balise source suivante :
 +
 +
test1.loop = true;
 +
 +
qui permet au son de se jouer en boucle.
 +
 +
Bien que les fichiers soit bien modifiés en local sur le serveur, toujours le même son est joué.
 +
 +
On a donc testé de recharger le son uniquement lorsque le son est modifié, avec un envoi de message du serveur par socket.
 +
Le serveur est conçu tel que suit :
 +
  <pre>while(1){
 +
  int cpt;
 +
  bool boole;
 +
  boole = 1;
 +
  for (cpt = 0; cpt < 50000; cpt++);
 +
 +
    boole = !boole;
 +
 +
    if(boole)
 +
      system("cp Level-complete-sound-effect.mp3 ./sound.mp3");
 +
    else
 +
      system("cp Raindrops-noise.mp3 ./sound.mp3");
 +
 +
      libwebsocket_write(test,(unsigned char *)out,1,LWS_WRITE_TEXT);
 +
 +
  }
 +
libwebsocket_context_destroy(context);
 +
return 0;
 +
}</pre>
 +
 +
On modifie la source, et ensuite on envoi un message, dont le contenu n'est pas important, le message sert juste d'indication au client que la source a changé.
 +
 +
Le code coté client :
 +
 +
<pre>websocket.onmessage=function(message){
 +
test1.pause();
 +
test1.load();
 +
test1.play();
 +
};</pre>
 +
 +
A la réception d'un message, on pause le son avec test1.pause() puis on recharge le son afin d'aller chercher la valeur actuelle de la source, puis on relance le son avec test1.play().
 +
D'après la documentation technique de HTML5, la fonction load() est sensé recharger la source si elle a changé, mais le résultat de ce test n'est pas concluant : le client joue toujours le même son.
 +
Nous ne comprenons pas pourquoi.
 +
 +
== Séance supplémentaire 1 : Réalisation du site Web ==
 +
 +
Nous avons réalisé ce site web lors de notre temps libre afin de permettre la communication entre le Raspberry Pi et l'ordinateur. En effet, il était inclus dans notre projet de devoir réaliser une communication par internet. Ce site internet va donc remplir cette condition. Sur celui-ci, on pourra trouver une brève description de notre projet, un lien vers le wiki, une image exemple d'un harpe et les boutons Play et Pause qui permettent d'activer et de désactiver la harpe laser.
 +
==== Partie websocket et échange d'information ====
 +
Après de nombreux tests sur la communication entre le serveur et le client web et le problème de toujours lire le même son, même si la source a été modifié, il s'est avéré que le client lisait toujours le même son quoi qu'il arrive, même si le fichier cible n’existait plus sur le serveur. Comprendre pourquoi a nécessité quelque recherche et la source du problème était la suivante : les navigateurs utilisés, Mozilla Firefox et Google Chrome, mettaient en cache le fichier son à la première lecture, et ne vérifiait plus l'état du fichier sur le serveur, fichier qui donc pouvait être modifié sans que cela n'ai un impact sur le déroulement coté client. Il a fallut trouver un moyen de contourner le cache. N'ayant aucune connaissance sur le domaine, les recherches ont été infructueuses. Suite à une conversation avec M. Rudametkin, nous avons été orienté vers ce lien https://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url/1077051#1077051 qui nous a permit de résoudre le problème.
 +
En utilisant la commande :
 +
 +
test1.src="sound.mp3?"+ new Date().getTime();
 +
 +
nous trompons le cache en forçant la revérification de la source sur le serveur. Grâce a cette méthode nous avons enfin réussi à modifier le son joué par le client, et nous avons pu passer à la gestion de la communication série entre le RPi et le FPGA/Arduino.
 +
 +
Le code fonctionnel de la page web est le suivant :
 +
 +
<pre><!DOCTYPE html>
 +
<html>
 +
  <head>
 +
    <meta charset="utf-8">
 +
    <audio controls="controls" id="mySound">
 +
    </audio>
 +
    <script
 +
        src="jquery.js"></script>
 +
    <script type="text/javascript">
 +
window.WebSocket=(window.WebSocket||window.MozWebSocket);
 +
 +
var websocket=new WebSocket('ws://10.42.93:9000','myprotocol');
 +
var test1 = document.getElementById("mySound");
 +
test1.src="sound.mp3";
 +
test1.autoplay = true;
 +
websocket.onopen=function(){ $('h1').css('color','green'); };
 +
 +
websocket.onerror=function(){ $('h1').css('color','red'); };
 +
 +
websocket.onmessage=function(message){
 +
test1.pause();
 +
test1.src="sound.mp3?"+ new Date().getTime();
 +
test1.load();
 +
test1.play();
 +
};
 +
 +
function sendMessage(){
 +
websocket.send($('#message').val());
 +
$('#message').val('');
 +
}
 +
 +
var son = document.getELementById("sound");
 +
son.loop = true;
 +
 +
    </script>
 +
  </head>
 +
  <body>
 +
    <h1>WebSockets test</h1>
 +
    <input type="text" id="message"/>
 +
    <button onclick="sendMessage();">Send</button>
 +
    <div id="messages"></div>
 +
  </body>
 +
</html>
 +
</pre>
 +
 +
Ce code n'est pas la version final, juste l'ensemble des parties logiques et fonctionnelles de la page web.
 +
 +
== Séance supplémentaire 2 : Réalisation du programme secondaire sur Arduino 'en cas de problèmes' ==
 +
 +
Nous nous sommes réunis à plusieurs occasions en dehors des heures de projet afin d'avancer sur notre harpe. Nous avons donc décidé que nous devions réaliser un programme sur Arduino nous permettant de réaliser des tests de transmission par la liaison série sans avoir besoin du FPGA. Dans un premier temps, nous avons tenté d'utiliser le port USB comme liaison série. Cependant, il s'est avéré que le Raspberry pi ne pouvait pas lire son port USB, ce qui nous a donc forcé à utiliser les pins de communication série de l'Arduino.
 +
Nous sommes sur un Arduino Mega 2560, nous avons a notre disposition plusieurs pins de communication série différents. Ils seront utilisés uniquement en transmission. Pour communiquer, nous allons ensuite utiliser le pin Tx1. Nous aboutissons donc au programme suivant:
 +
 +
[[Fichier:Setup.PNG]]
 +
 +
 +
[[Fichier:Captprog.PNG]]
 +
 +
La communication série de ce programme nous a causé des problèmes, surtout du fait que l'ordinateur ne recevait pas les informations transmises par l'Arduino. Nous avons donc du effectuer de multiples tests afin de voir où se situait le problème. Nous avons pu déterminer que nous avions un problème au niveau de notre pont diviseur de tension entre l'alimentation de l’Arduino et celle du Raspberry Pi, nous avons alors changé les résistances.
 +
Nous avons également notamment modifié le programme afin de vérifier que l'information était bien transmise sur le Pin Série de l'Arduino, et que le problème ne venait donc pas de l'Arduino mais bien du Raspberry, dont le port série était mal configuré.
 +
 +
[[Fichier:Changement1.PNG]]
 +
 +
[[Fichier:Changement2.PNG]]
 +
 +
On n'a pas mit la Setup du programme, car c'est la même que pour le programme précedent.
 +
 +
==== Connexion série coté RPi ====
 +
Afin de lire sur la liaison séri du coté de RPi, nous avions écrit le code C suivant :
 +
<pre>#include <stdio.h>  /* Standard input/output definitions */
 +
#include <string.h>  /* String function definitions */
 +
#include <unistd.h>  /* UNIX standard function definitions */
 +
#include <fcntl.h>  /* File control definitions */
 +
#include <errno.h>  /* Error number definitions */
 +
#include <termios.h> /* POSIX terminal control definitions */
 +
 +
 +
// Lecture port série
 +
 +
typedef int serialPort;
 +
serialPort SerialLib_open(const char * portPath);
 +
 +
int main(int argc, char **argv) {
 +
  serialPort p = SerialLib_open("/dev/ttyAMA0");
 +
  char buffer[1];
 +
printf("ouverture reussi\n");
  
== Séance supplémentaire 1 ==
+
while(1){
  
=== Partie électronique ===
+
printf("lecture d'un caractere\n");
 +
  read(p, buffer ,1);
 +
 
 +
 
 +
  printf("Message recu: %s \n",buffer);
 +
}
 +
  return 0;
 +
}
 +
 
 +
/**
 +
* Ouverture du port
 +
*
 +
*
 +
*/
 +
serialPort SerialLib_open(const char * serialPortPath) {
 +
  int fd;
 +
 
 +
  fd = open(serialPortPath, O_RDWR | O_NOCTTY);
 +
  if (fd == -1) {
 +
     
 +
      printf("Could not open the serial port : %s - ", serialPortPath);
 +
  }else {
 +
      fcntl(fd, F_SETFL, 0);
 +
  }
 +
  return (serialPort)fd;
 +
}
 +
</pre>
 +
 
 +
Ce code, combiné avec le programme sur l'Arduino, était sensé permettre la réception d'un caractère sur le RPi et l'afficher sur la sortie standard sur RPi.
 +
Nous avons eu beaucoup de problème à recevoir notre message avec ce code : en effet, pour une raison qui nous reste inconnue, le programme permet la réception des caractères voulus, mais sur une courte période de temps, puis après cette période, aucun caractère n'est reçu, que l'on relance le serveur ou l'arduino.
 +
 
 +
Le code d'exemple fournit, en revanche, fonctionne très bien et si utilisé en parallèle avec notre programme, permet le fonctionnement notre programme sans problème. Nous avons donc décidé d'utiliser le code d'exemple comme base :
 +
<pre>
 +
/*
 +
* Test on serial device
 +
*/
 +
 
 +
////
 +
// Include files
 +
////
 +
#include <stdio.h>
 +
#include <stdlib.h>
 +
#include <unistd.h>
 +
#include <termios.h>
 +
 
 +
#include "serial.h"
 +
 
 +
////
 +
// Constants
 +
////
 +
#define        SERIAL_DEVICE          "/dev/ttyACM0"
 +
 
 +
////
 +
// Global variables
 +
////
 +
 
 +
////
 +
// Main function
 +
////
 +
 
 +
int main(void){
 +
int c=0;
 +
int sd=serialOpen(SERIAL_DEVICE,SERIAL_BOTH);
 +
serialConfig(sd,B9600);
 +
if(write(sd,&c,sizeof(char))!=1){ perror("main.write"); exit(-1); }
 +
int i;
 +
for(i=0;i<8;i++){
 +
  if(read(sd,&c,sizeof(char))!=1){ perror("main.read"); exit(-1); }
 +
  printf("%02x\n",c);
 +
  }
 +
serialClose(sd);
 +
exit(0);
 +
}
 +
</pre>
 +
 
 +
==Scéance supplémentaire 3: Montage de la harpe==
 +
 
 +
[[Fichier:Harpe2.jpg|400px]]
 +
 
 +
Harpe en cours de montage
 +
 
 +
[[Fichier:Harpe1.jpg|1000px]]
 +
 
 +
Harpe assemblée et branchée sur l'ordinateur.
 +
 
 +
 
 +
Comme on peut clairement le voir sur les images, nous ne disposons pas de suffisamment de laser pour faire les huit fils de la harpe, aussi avons remplacés ceux-ci par des câbles tendus, qu'on peux ensuite mettre en contact avec un câble branché sur une borne positive de l'Arduino qui vient du haut de la harpe, afin de simuler le fait qu'on coupe le faisceau d'un laser. Nous avons tout de même mit le seul laser à notre disposition, mais il s'est avéré qu'il est très compliqué de l'aligner avec la diode, qui est de plus très directionnelle. La harpe montée et branchée fonctionne donc comme si on avait coupé en permanence un des lasers.
 +
 
 +
Pour l'assemblage, nous avons d'abord tenté de coller les boites entre elles, mais il s'est avéré que ça ne fonctionnait pas, on a donc du les visser à la place.
 +
 
 +
Chaque boite est assemblée avec un côté pouvant se séparer afin de pouvoir accéder aux composants et câbles à l'intérieur. Pour la boite du bas, c'est la face inférieure, pour la boite du haut, c'est la face supérieure, pour la boite du milieu, c'est la face arrière.
  
=== Partie informatique ===
+
L'arduino et le raspberry sont à l'intérieur de la boite du bas, et on peut les relier à l'ordinateur et les alimenter grâce aux câbles ethernet, usb et d'alimentation qui passent par les trous prévus à cet effet.
  
== Conclusion ==
+
Le site Web qui permet de démarrer ou d'arrêter la Harpe peut être trouvé à l'adresse suivante: 169.254.120.42

Version actuelle datée du 22 juin 2017 à 19:39

Projet IMA3-SC 2016/2017 : Synt'Harpe (Sainte) Laser

Lien vers le Git du projet: https://archives.plil.fr/mdelapor/SC_Harpe_Laser_IMA3/tree/master/projetSC

Cahier des charges

Description du système

Pour le projet Système Communicant, nous allons réaliser une harpe laser. Notre but est de créer un instrument de musique similaire à une harpe, où les cordes sont remplacées par des capteurs infra-rouges.

Un son sera émis par l'ordinateur dès que le capteur IR captera une main et le joueur pourra avec son autre main moduler l'amplitude de la note.

Dans un premier temps, on travaillera sur une gamme de son sur 8 bits. Puis, nous implémenterons une banque de sons qui nous permettra de sélectionner l'instrument désiré, d'où l'appellation Synt'Harpe.

L'ordinateur décidera du fonctionnement ou non de la harpe. C'est aussi grâce à lui qu'on pourra choisir la banque de sons voulue.

Toutes les banques de sons seront enregistrées sur le Raspberry. Les LEDs signaleront l'emplacement des cordes.

Pour la partie optionnelle, on remplacera les LEDs par des lasers pour un effet visuel de qualité (plus poussé). La fumée permettra de voir les lasers.

Le matériel

  • Un raspberry pi
  • 8 phototransistors
  • 8 émetteurs lasers
  • Des résistances
  • Une structure
  • Carte d'acquisition de type Arduino au début puis FPGA
  • Un ordinateur
  • Une alimentation

Optionnel (visuel)

  • 8 émetteurs laser
  • Un générateur de fumée
  • Une caméra

Séance 1

Partie électronique

Le but de cette première séance était de se répartir les tâches, de tester le matériel mit à disposition et de découvrir le fonctionnement du FPGA.

Le principe de fonctionnement de la harpe est le suivant: Chaque capteur sera situé en face d'un laser. Les capteurs seront dans la partie haute de la harpe afin de limiter les interférences dues à d'autres sources lumineuses. Chaque laser pointera vers un capteur.

Les capteurs enverront tous par défaut la même valeur au FPGA. Quand l'utilisateur passera sa main dans la harpe, un faisceau laser sera coupé. Le capteur n'enverra plus sa valeur seuil au FPGA, il aura donc changé d'état. Dès lors que le FPGA détectera un changement d'état, il enverra l'état dans lequel se trouvent les 8 capteurs au Raspberry.

Nous avons réalisé des tests sur les phototransistors et les lasers. Nous avons mis en parallèle un laser et deux capteurs, sans oublier leur résistance de 1.2k Ohms chacune.

Nous avons vu que à luminosité ambiante, quand le laser pointe sur le capteur, celui-ci envoie à l'Arduino une valeur de 950 environ. Ensuite, quand le faisceau laser est coupé, la valeur envoyée par le phototransistor monte à 1020. Puis, nous avons réitéré l'expérience en mettant le système dans une boîte. Cette fois, le valeur est passée de 840 quand le capteur est éclairé par le laser à 900 quand le faisceau est coupé. Nous en avons déduit que nous allons devoir refaire l'expérience une fois la harpe assemblée.

Les lasers étant très directionnels tout comme les phototransistors, nous n'aurons pas de soucis d'interférences. Un capteur détectera uniquement le laser situé directement en face de lui et non ceux de son voisinage.

Partie boitier

Même si il peut paraitre futile d'insérer une partie boitier dans un projet centré sur l'informatique et l'électronique, il s'est avéré que le boitier de notre Harpe nécessitait une attention particulière.

La taille de la harpe à été un sujet de débat, et nous avons réalisé des tests afin de vérifier que des phototransistors trop proches les uns des autres n'allait pas compromettre le bon fonctionnement de la harpe dans son ensemble. En effet, si le phototransistor détectait un autre laser que celui vers lequel il pointe serait extrêmement problématique. Heureusement, il s'est avéré que les phototransistors sont très directionnels, au point que se pose désormais le problème inverse.

Nous allons devoir faire très attention au fait que les lasers soient bien fixés et pointent exactement vers les phototransistors, car dans le cas contraire, ceux-ci ne détectent absolument pas le laser, et tout le principe de fonctionnement s'effondre. La conception et l'assemblage de la boite devront donc être relativement précis, pour éviter ces problèmes.

Enfin, nous avons dès le départ décidé d'éviter l'utilisation de diodes infra-rouges, pour leur préférer les lasers. Tout d'abord, parce que les diodes ne sont en aucun cas assez puissantes pour être détectées par les phototransistors, ce qui une fois de plus rend notre harpe inutile. Ensuite, parce qu'il nous a semblé que réaliser une harpe 'laser' sans lasers était un concept déconcertant, et enlève beaucoup de l’intérêt de ce projet.

Un premier jet de design avait été réalisé avant cette séance, et au vu des données récoltées pendant celle-ci, nous l'avons modifié pour les prendre en compte, notamment la taille des lasers par rapport aux diodes, et la précision requise.

Partie informatique

Le travail a été séparé en 2 parties, une personne par partie : - une première partie sur le serveur même (page web, système de streaming de son depuis la page web) - une seconde partie sur la lecture du port série

Partie serveur

La première séance a été consacré à deux grands axes : prendre la main à distance sur le raspberry pi et mettre en place le serveur web. Afin de pouvoir contrôler et travailler facilement sur le RPi, l'outil vncserver a été installé sur le raspberry, permettant de contrôler via un interface graphique le RPi depuis un ordinateur branché sur le même réseau. Cet utilitaire permettra a l'avenir de travailler directement sur le RPi sans devoir constamment uploader par ssh le travail effectué.

Coté mise en place du serveur web, l'utilitaire de serveur web apache2 a été installé sans soucis, et les pages d'exemples web et javascript fonctionnent. En revanche, l'utilisation du code d'exemple sur les sockets n'est pas utilisable, le paquet proposé n’existe pas et le site du paquet de socket est mort. Le reste de la séance a été consacré a des recherches sur les moyens de pouvoir streamer du son, recherches non concluantes. Aucune solution n'a été trouvé sans passer par un service internet hébergé par un tier.


Partie lecture port série

Cette première séance fut consacrée à la sélection du langage de programmation et à sa prise en main. Il a été décidé d'utiliser Python pour écrire le programme récupérant et traitant les données récupérées à travers le port série. Python étant un langage fort usité, il possède une très large documentation. Ce fut donc facile de trouver la librairie permettant de lire les données envoyées par le port série.

Un doute subsiste encore sur le type de données envoyé par le port série. L'idéal serait de récupérer un tableau de 8 entiers de type binaire correspondant aux états des 8 ports liés aux "cordes" laser, pour pouvoir ensuite traiter ces données facilement.

Séance 2

Partie électronique

Lors de cette séance, nous avons réalisé le premier circuit sur le FPGA.

Nous avons commencé par réaliser un circuit simple, qui envoie en permanence l'état des huit phototransistors au port série. Les phototransistors sont alors directement reliés à celui-ci. Nous avons pu tester le bon fonctionnement du système grâce aux diodes du FPGA. Nous avons branché en parallèle sur le circuit les huit diodes, afin de vérifier qu'un signal était bien envoyé en permanence, on a pu les voir s'éteindre lorsqu'on éclairait un laser. Ces diodes se sont avérées très utiles, car il n'est pas encore possible d'effectuer les tests sur le port série, car la partie informatique n'est pas encore opérationnelle, on ne peut donc pas lire directement sur le port série pour le moment.


Envoiconstant.JPG


Nous avons ensuite réalisé un montage permettant de faire l'envoi seulement sur changement d'état, comme prévu à la séance 1 Nous avons donc réalisé un système de bascules permettant de comparer l'état actuel de chaque diode avec son état précédent, puis de réaliser l'envoi seulement si une différence était observée. Comme précédemment, les diodes sont reliées directement au Port Série, mais cette fois-ci au lieu de brancher le Bit d'envoi du port Série sur un Vcc, soit un '1' logique, nous l'avons relié à la vérification de changement d'état, qui passe à '1' uniquement avec un changement d'état.

Changementdetat.JPG


Le problème qui s'est alors posé était de savoir si on envoyait le signal assez longtemps pour qu'il puisse être lu. En effet on envoie un signal seulement si il y a changement d'état, et cette vérification se fait à chaque incrément d'horloge. Hors, la différence sera donc observée sur un seul incrément d'horloge, par conséquent, on n'envoie de signal que pendant ce seul incrément. Pour l'instant, nous supposons que le port série est capable de stocker les données à envoyer en un seul incrément d'horloge. Cependant, si lors des tests, ça ne fonctionne pas, nous prévoyons d'utiliser un compteur pour pouvoir envoyer le signal plus longtemps au Bit d'envoi du port série, et ainsi laisser le temps au port série d'envoyer l'information.

Partie boitier

Pendant cette séance, nous nous sommes focalisés sur le FPGA, mais nous avons néanmoins terminé la conception du boitier de la harpe, sous la forme de trois 'boites' crénelées, que nous avons ensuite l'intention de découper au FabLab puis d'assembler.


Boites.jpg


Il s'est avéré que réaliser des boites crénelées rendrait tout le boitier beaucoup plus solide, et donc fiable.

Partie informatique

Le problème de l'impossibilité d'utiliser l'exemple sur les sockets a été résolu, grâce à l'intervention de M. Redon. Le problème était une différence de version de la distribution Linux entre le RPi utilisé et celle utilisé pour l'exemple. En effet, le RPi de travail est sur une distribution Wheezy, alors que la version la plus récente est la Jessie. Les chemins des dépots des sources de la librairie libwebsocket n’existant pas sur Wheezy, on ne pouvait installer la librairie directement en ligne de commande. M. Redon a ajouté le chemin de la librairie dans le gestionnaire de paquet du RPi et on a pu utiliser sans problèmes la librairie. De plus le site du paquet libwebsocket n'était inaccessible que temporairement. La séance a été consacré à comprendre le fonctionnement des sockets et comment l'exemple html interagissait avec.

La partie importante du code d'exemple est la suivante :

static int callback_my(
  struct libwebsocket_context * this,
  struct libwebsocket *wsi,enum libwebsocket_callback_reasons reason,
  void *user,void *in,size_t len)
 {
 static char *message=NULL;
 static int msize=0;
 switch(reason){
  case LWS_CALLBACK_ESTABLISHED:
    printf("connection established\n");
    message=NULL;
                // Declenchement d'un prochain envoi au navigateur
    libwebsocket_callback_on_writable(this,wsi);
    break;
  case LWS_CALLBACK_RECEIVE:
                // Ici sont traites les messages envoyes par le navigateur
    printf("received data: %s\n",(char *)in);
    message=malloc(len+LWS_SEND_BUFFER_PRE_PADDING+LWS_SEND_BUFFER_POST_PADDING);
    if(message==NULL){ perror("callback_my.malloc"); exit(EXIT_FAILURE); }
    memcpy(message+LWS_SEND_BUFFER_PRE_PADDING,in,len);
                // Declenchement d'un prochain envoi au navigateur
    msize=len;
    libwebsocket_callback_on_writable(this,wsi);
    break;
  case LWS_CALLBACK_SERVER_WRITEABLE:
                // Ici sont envoyes les messages au navigateur
    if(message!=NULL){
      char *out=message+LWS_SEND_BUFFER_PRE_PADDING;
      libwebsocket_write(wsi,(unsigned char *)out,msize,LWS_WRITE_TEXT);
      free(message);
      message=NULL;
      }
    break;
  default:
    break;
  }
 return 0;
 }
 

Il s'agit d'une fonction de callback gérant à la fois la réception et la transmission. On peut remarquer 3 cas du switch : LWS_CALLBACK_ESTABLISHED correspondant à la création d'un lien entre la page web et le serveur websocket à la demande de la page web, LWS_CALLBACK_RECEIVE correspondant aux actions à entreprendre à la réception d'un message provenant du navigateur web, et LWS_CALLBACK_SERVER_WRITEABLE correspondant aux actions afin d'envoyer un message au navigateur.

Coté HTML, on utilise les sockets grâce à ce code suivant :

window.WebSocket=(window.WebSocket||window.MozWebSocket);
 var websocket=new WebSocket('ws://127.0.0.1:9000','myprotocol');
 websocket.onopen=function(){ $('h1').css('color','green'); };
 websocket.onerror=function(){ $('h1').css('color','red'); };
 websocket.onmessage=function(message){
 console.log(message.data);
 $('#messages').append($('<p>',{ text: message.data }));
 };
 function sendMessage(){
 websocket.send($('#message').val());
 $('#message').val('');
 }


La fonction websocket.onmessage gère le traitement à faire coté client quand le serveur envoie des informations, et la fonction sendMessage permet l'envoie d'information du client vers le serveur.

Pour notre projet, nous avons besoin principalement, dans un premier temps, d'envoyer des informations du serveur vers le client, nous nous sommes donc concentrer à comprendre et modifier les parties du code fourni suivantes : websocket.onmessage coté client et le "case LWS_CALLBACK_SERVER_WRITEABLE:" coté serveur.

Le but des tests était de réussir à faire jouer deux sons différents par le client, avec changement de son imposé par le serveur. HTML5 propose nativement de lire des sons à partir d'une source grâce à une balise audio :

<audio controls="controls" id="mySound">
   </audio>

On récupère l'identifiant de cette balise avec

var test1 = document.getElementById("mySound");

afin de pouvoir l'utiliser de n'importe où dans le programme. On définit la source grâce à

test1.src="sound.mp3";

avec "sound.mp3" le chemin d'accès au fichier son par rapport à l'emplacement du fichier html sur le serveur. Ici, le fichier son sound.mp3 est dans le même dossier que la page index.html. Enfin, on peut lire le son avec

test1.play();

Le but du projet étant d'émettre en continue le son généré par la harpe, l'objectif ici est soit de générer un fichier de streaming que l'on lit en continue, soit de lire un fichier différent par son possible et on change la valeur de test1.src en fonction du son à lire, soit on lit toujours la même source, mais que l'on modifie à la volée en fonction du son voulu. La première option a été étudiée jusqu'en fin de séance. Nous n'avons pas réussi à comprendre comment générer un fichier de streaming audio simple, de plus toutes les documentations et exemples trouvés ne concernant qu'un streaming simultanée de son et de vidéo à partir d'une caméra et d'un micro, et nous n'avons pas compris comment adapter ces exemples.

Séance 3

Partie électronique

Pendant cette séance, nous avons pu tester l'envoi sur changement d'état, toujours avec les diodes du FPGA.

Nous avons commencé par ajouter une horloge sur le détecteur de changement d'état, afin d'augmenter le nombre d'incréments d'horloge sur lequel il est à '1', et ce dans le but de rendre le clignotement d'un diode visible à l’œil nu. Ensuite, nous avons relié la sortie du détecteur de changement d'état et des phototransistors par un 'ET' logique, que nous avons ensuite relié aux diodes du FPGA. De cette façon, si l'on détecte un changement d'état sur un phototransistor, la nouvelle valeur est alors envoyée sur les diodes. Le système a fonctionné, nous disposons donc d'un système envoyant sur la liaison série 8 bits correspondant à l'état des 8 diodes, en utilisant le Fpga.

Nous avons ensuite passé le reste de la séance à mettre en commun notre partie avec la partie informatique, en essayant de leur permettre de lire sur le port série du FPGA. Les essais ont pour l'instant été infructueux, mais des progrès ont été faits.

L'objectif étant que le Raspberry Pi puisse lire les informations envoyées par le FPGA, pour ensuite les transmettre au site Web que nous allons réaliser par la suite.

Partie informatique

Au vu des difficultés rencontrées lors de la mise en place d'un véritable système de streaming, nous avons décider d'étudier les autres options possibles. Notre deuxième solution était de modifier la valeur de test1.src. Mais cela voulait dire effectuer beaucoup de traitement coté client, et si on décidait de rajouter beaucoup de son, ou de générer de nouveaux fichiers son, ce la demandait soit de modifier le HTML à chaque ajout de fonctionnalité, ou de créer une grande quantité de fichier son qui pollueraient le serveur. Nous avons donc décidé qu'il serait plus pratique de toujours écraser la source avec le nouveau son a lire, et de ne jamais changer la valeur de test1.src.

Afin d'effectuer des tests afin de voir si notre idée marchait bien, nous avons utiliser le code C très simple suivant :

int cpt;
  for (cpt = 0; cpt < 250000000; cpt++);

    boole = !boole;
	printf("changement: %d\n",boole);
    if(boole)
      system("sudo cp Level-complete-sound-effect.mp3 ./sound.mp3");
    else
      system("sudo cp Raindrops-noise.mp3 ./sound.mp3");
  }

Ce code nous permet de modifier assez fréquemment le fichier source. Les fichiers audio de tests ont été trouvé sur http://www.orangefreesounds.com/ et sont libre de droit.

Dans la page HTML de test nous utilisé les options de la balise source suivante :

test1.loop = true;

qui permet au son de se jouer en boucle.

Bien que les fichiers soit bien modifiés en local sur le serveur, toujours le même son est joué.

On a donc testé de recharger le son uniquement lorsque le son est modifié, avec un envoi de message du serveur par socket. Le serveur est conçu tel que suit :

while(1){
  int cpt;
  bool boole;
  boole = 1;
  for (cpt = 0; cpt < 50000; cpt++);

    boole = !boole;

    if(boole)
      system("cp Level-complete-sound-effect.mp3 ./sound.mp3");
    else
      system("cp Raindrops-noise.mp3 ./sound.mp3");

      libwebsocket_write(test,(unsigned char *)out,1,LWS_WRITE_TEXT);

  }
 libwebsocket_context_destroy(context);
 return 0;
 }

On modifie la source, et ensuite on envoi un message, dont le contenu n'est pas important, le message sert juste d'indication au client que la source a changé.

Le code coté client :

websocket.onmessage=function(message){
 test1.pause();
 test1.load();
 test1.play();
 };

A la réception d'un message, on pause le son avec test1.pause() puis on recharge le son afin d'aller chercher la valeur actuelle de la source, puis on relance le son avec test1.play(). D'après la documentation technique de HTML5, la fonction load() est sensé recharger la source si elle a changé, mais le résultat de ce test n'est pas concluant : le client joue toujours le même son. Nous ne comprenons pas pourquoi.

Séance supplémentaire 1 : Réalisation du site Web

Nous avons réalisé ce site web lors de notre temps libre afin de permettre la communication entre le Raspberry Pi et l'ordinateur. En effet, il était inclus dans notre projet de devoir réaliser une communication par internet. Ce site internet va donc remplir cette condition. Sur celui-ci, on pourra trouver une brève description de notre projet, un lien vers le wiki, une image exemple d'un harpe et les boutons Play et Pause qui permettent d'activer et de désactiver la harpe laser.

Partie websocket et échange d'information

Après de nombreux tests sur la communication entre le serveur et le client web et le problème de toujours lire le même son, même si la source a été modifié, il s'est avéré que le client lisait toujours le même son quoi qu'il arrive, même si le fichier cible n’existait plus sur le serveur. Comprendre pourquoi a nécessité quelque recherche et la source du problème était la suivante : les navigateurs utilisés, Mozilla Firefox et Google Chrome, mettaient en cache le fichier son à la première lecture, et ne vérifiait plus l'état du fichier sur le serveur, fichier qui donc pouvait être modifié sans que cela n'ai un impact sur le déroulement coté client. Il a fallut trouver un moyen de contourner le cache. N'ayant aucune connaissance sur le domaine, les recherches ont été infructueuses. Suite à une conversation avec M. Rudametkin, nous avons été orienté vers ce lien https://stackoverflow.com/questions/1077041/refresh-image-with-a-new-one-at-the-same-url/1077051#1077051 qui nous a permit de résoudre le problème. En utilisant la commande :

test1.src="sound.mp3?"+ new Date().getTime();

nous trompons le cache en forçant la revérification de la source sur le serveur. Grâce a cette méthode nous avons enfin réussi à modifier le son joué par le client, et nous avons pu passer à la gestion de la communication série entre le RPi et le FPGA/Arduino.

Le code fonctionnel de la page web est le suivant :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <audio controls="controls" id="mySound">
    </audio>
    <script
        src="jquery.js"></script>
    <script type="text/javascript">
window.WebSocket=(window.WebSocket||window.MozWebSocket);

var websocket=new WebSocket('ws://10.42.93:9000','myprotocol');
var test1 = document.getElementById("mySound");
test1.src="sound.mp3";
test1.autoplay = true;
websocket.onopen=function(){ $('h1').css('color','green'); };

websocket.onerror=function(){ $('h1').css('color','red'); };

websocket.onmessage=function(message){
test1.pause();
test1.src="sound.mp3?"+ new Date().getTime();
test1.load();
test1.play();
};

function sendMessage(){
websocket.send($('#message').val());
$('#message').val('');
}

var son = document.getELementById("sound");
son.loop = true;

    </script>
  </head>
  <body>
    <h1>WebSockets test</h1>
    <input type="text" id="message"/>
    <button onclick="sendMessage();">Send</button>
    <div id="messages"></div>
  </body>
</html>
 

Ce code n'est pas la version final, juste l'ensemble des parties logiques et fonctionnelles de la page web.

Séance supplémentaire 2 : Réalisation du programme secondaire sur Arduino 'en cas de problèmes'

Nous nous sommes réunis à plusieurs occasions en dehors des heures de projet afin d'avancer sur notre harpe. Nous avons donc décidé que nous devions réaliser un programme sur Arduino nous permettant de réaliser des tests de transmission par la liaison série sans avoir besoin du FPGA. Dans un premier temps, nous avons tenté d'utiliser le port USB comme liaison série. Cependant, il s'est avéré que le Raspberry pi ne pouvait pas lire son port USB, ce qui nous a donc forcé à utiliser les pins de communication série de l'Arduino. Nous sommes sur un Arduino Mega 2560, nous avons a notre disposition plusieurs pins de communication série différents. Ils seront utilisés uniquement en transmission. Pour communiquer, nous allons ensuite utiliser le pin Tx1. Nous aboutissons donc au programme suivant:

Setup.PNG


Captprog.PNG

La communication série de ce programme nous a causé des problèmes, surtout du fait que l'ordinateur ne recevait pas les informations transmises par l'Arduino. Nous avons donc du effectuer de multiples tests afin de voir où se situait le problème. Nous avons pu déterminer que nous avions un problème au niveau de notre pont diviseur de tension entre l'alimentation de l’Arduino et celle du Raspberry Pi, nous avons alors changé les résistances. Nous avons également notamment modifié le programme afin de vérifier que l'information était bien transmise sur le Pin Série de l'Arduino, et que le problème ne venait donc pas de l'Arduino mais bien du Raspberry, dont le port série était mal configuré.

Changement1.PNG

Changement2.PNG

On n'a pas mit la Setup du programme, car c'est la même que pour le programme précedent.

Connexion série coté RPi

Afin de lire sur la liaison séri du coté de RPi, nous avions écrit le code C suivant :

#include <stdio.h>   /* Standard input/output definitions */
#include <string.h>  /* String function definitions */
#include <unistd.h>  /* UNIX standard function definitions */
#include <fcntl.h>   /* File control definitions */
#include <errno.h>   /* Error number definitions */
#include <termios.h> /* POSIX terminal control definitions */


// Lecture port série

typedef int serialPort;
serialPort SerialLib_open(const char * portPath);

int main(int argc, char **argv) {
   serialPort p = SerialLib_open("/dev/ttyAMA0"); 
   char buffer[1];
	printf("ouverture reussi\n");

while(1){

printf("lecture d'un caractere\n");
   read(p, buffer ,1);
   

   printf("Message recu: %s \n",buffer);
}
   return 0;
}

/**
 * Ouverture du port 
 * 
 *
 */
serialPort SerialLib_open(const char * serialPortPath) {
   int fd; 

   fd = open(serialPortPath, O_RDWR | O_NOCTTY);
   if (fd == -1) {
      
      printf("Could not open the serial port : %s - ", serialPortPath);
   }else {
      fcntl(fd, F_SETFL, 0);
   }
   return (serialPort)fd;
} 
 

Ce code, combiné avec le programme sur l'Arduino, était sensé permettre la réception d'un caractère sur le RPi et l'afficher sur la sortie standard sur RPi. Nous avons eu beaucoup de problème à recevoir notre message avec ce code : en effet, pour une raison qui nous reste inconnue, le programme permet la réception des caractères voulus, mais sur une courte période de temps, puis après cette période, aucun caractère n'est reçu, que l'on relance le serveur ou l'arduino.

Le code d'exemple fournit, en revanche, fonctionne très bien et si utilisé en parallèle avec notre programme, permet le fonctionnement notre programme sans problème. Nous avons donc décidé d'utiliser le code d'exemple comme base :

/*
 * Test on serial device
 */

////
// Include files
////
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <termios.h>

#include "serial.h"

////
// Constants
////
#define         SERIAL_DEVICE           "/dev/ttyACM0"

////
// Global variables
////

////
// Main function
////

int main(void){
int c=0;
int sd=serialOpen(SERIAL_DEVICE,SERIAL_BOTH);
serialConfig(sd,B9600);
if(write(sd,&c,sizeof(char))!=1){ perror("main.write"); exit(-1); }
int i;
for(i=0;i<8;i++){
  if(read(sd,&c,sizeof(char))!=1){ perror("main.read"); exit(-1); }
  printf("%02x\n",c);
  }
serialClose(sd);
exit(0);
}
 

Scéance supplémentaire 3: Montage de la harpe

Harpe2.jpg

Harpe en cours de montage

Harpe1.jpg

Harpe assemblée et branchée sur l'ordinateur.


Comme on peut clairement le voir sur les images, nous ne disposons pas de suffisamment de laser pour faire les huit fils de la harpe, aussi avons remplacés ceux-ci par des câbles tendus, qu'on peux ensuite mettre en contact avec un câble branché sur une borne positive de l'Arduino qui vient du haut de la harpe, afin de simuler le fait qu'on coupe le faisceau d'un laser. Nous avons tout de même mit le seul laser à notre disposition, mais il s'est avéré qu'il est très compliqué de l'aligner avec la diode, qui est de plus très directionnelle. La harpe montée et branchée fonctionne donc comme si on avait coupé en permanence un des lasers.

Pour l'assemblage, nous avons d'abord tenté de coller les boites entre elles, mais il s'est avéré que ça ne fonctionnait pas, on a donc du les visser à la place.

Chaque boite est assemblée avec un côté pouvant se séparer afin de pouvoir accéder aux composants et câbles à l'intérieur. Pour la boite du bas, c'est la face inférieure, pour la boite du haut, c'est la face supérieure, pour la boite du milieu, c'est la face arrière.

L'arduino et le raspberry sont à l'intérieur de la boite du bas, et on peut les relier à l'ordinateur et les alimenter grâce aux câbles ethernet, usb et d'alimentation qui passent par les trous prévus à cet effet.

Le site Web qui permet de démarrer ou d'arrêter la Harpe peut être trouvé à l'adresse suivante: 169.254.120.42