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

De Wiki de Projets IMA
(Prototype Arduino)
(Prototype Arduino)
Ligne 346 : Ligne 346 :
  
 
Après s'être assuré du bon fonctionnement de tous les capteurs, il ne nous restait plus qu'à assembler ces différents tests en un seul programme. Ce programme Arduino doit être capable de transmettre par l'intermédiaire de la liaison série les informations provenant des capteurs. De plus, il doit permettre d'allumer ou non la pompe selon la consigne d'humidité qu'il aura reçu par l'utilisateur depuis l'interface.
 
Après s'être assuré du bon fonctionnement de tous les capteurs, il ne nous restait plus qu'à assembler ces différents tests en un seul programme. Ce programme Arduino doit être capable de transmettre par l'intermédiaire de la liaison série les informations provenant des capteurs. De plus, il doit permettre d'allumer ou non la pompe selon la consigne d'humidité qu'il aura reçu par l'utilisateur depuis l'interface.
 +
 +
[[Fichier:PFC_cablage.jpg|250px|thumb|right|Montage du prototype]]
  
 
  int STBY = 2;
 
  int STBY = 2;

Version du 16 juin 2017 à 12:21


Projet IMA3-SC 2016/2017 : Pot de fleur connecté

Lien du projet GIT (vidéo comprise)

Cahier des charges

  • Mesure du taux d'humidité de la terre
  • Mesure de la température
  • Mesure de la luminosité
  • Affichage des données (humidité, température et lumière) sur une interface Web
  • Régulation automatique de l'arrosage lorsque l'humidité du sol est inférieure à la limite fixée par l'utilisateur
  • Affichage d'alertes lorsque les conditions de températures/luminosité ne correspondent plus à ce que l'utilisateur à fixé
  • Garder un historique horodaté des alertes et de l'arrosage
  • Avertir l'utilisateur lorsque le niveau d'eau est faible

Description du système

Le pot de fleur connecté est un système permettant de faciliter le soin d'une plante.
Il régule automatiquement l’arrosage afin de garder un taux d'humidité propice au développement de la plante et avertit l'utilisateur en cas de réserve d'eau insuffisante.
Il permet également de prévenir l'utilisateur lorsque les conditions de lumière/température ne correspondent plus à ce qu'il avait fixé sur l'interface web.

Le matériel

  • 1 hygromètre (certains incluent une sonde de température)
  • 1 photorésistance
  • 1 sonde de température
  • 1 capteur de niveau d'eau
  • 1 Rapsberry Pi
  • 1 Nanoboard

Séance 1

Partie électronique

FPGA

Nous avons consacré cette première séance à la découverte du FPGA.

AOP comparateur

N’en ayant encore jamais utilisé, nous avons commencé par réaliser le tutoriel proposé, celui-ci nous à permis de nous familiariser aussi bien avec la Nanoboard qu’avec la programmation graphique d’Altium qui est assez semblable à celle de logiciel libre Logisim.

Nous avons constaté qu’il est possible de d’utiliser des interfaces d’Entrée/Sortie afin d’interagir avec notre FPGA, mais aussi qu’il nous est possible d’avoir accès à des instruments virtuels directement sous Altium nous permettant de régler des Entrées/Sorties virtuelles ou encore d’adapter la fréquence de l’horloge du FPGA suivant nos besoins.

Pour notre projet nous disposons de 3 capteurs, humidité, température et niveau d’eau. Ces capteurs sont analogiques, il nous faut donc créer un ADC (Analog to Digital Converter ou Convertisseur Analogique Numérique).

Après discussion avec nos professeurs encadrant nous choisissons de nous orienter vers une conversion analogique numérique basée sur une PWM (Pulse Width Modulation ou Modulation des Largeurs d’ Impulsions). Cette technique permet de changer périodiquement le rapport cyclique d’un signal carré, nous avons utilisé un compteur sur 8bits pour réaliser cette fonction. Nous avons appris à utiliser l’analyseur logique afin de visualiser les signaux numériques.

Cette technique consiste à utiliser un Amplificateur OPérationnel (AOP) en mode comparateur afin de comparer la tension d’un signal en dents de scie avec la tension du capteur.

Quand la tension du signal triangulaire est supérieure à la tension du capteur alors l’AOP envoie un signal.




Prototype Arduino

On a commencé par faire l'inventaire des différents capteurs et matériels présents dans notre boîte.

  • Une pompe accompagnée de son shield permettant le contrôle du moteur par PWM avec un Arduino
  • Un capteur d'humidité couplé avec un capteur de température
  • Une sonde "chirp" qui émet du son lorsque l'humidité du sol descend en dessous d'un relevé initial "dry point"
  • Un phototransistor qui réagit au changement d'intensité lumineuse
  • Un microcontrôleur Arduino et une breadboard

Sonde chirp

Cette sonde, bien que fonctionnelle, n'est pas réellement adaptée à notre projet. Il s'agit d'un produit fini et non réellement d'un simple capteur. Nous avons trouvé inutile de perdre du temps à modifier un produit existant sans avoir la certitude d'aboutir à des résultats probants.

Capteur d'humidité / température

Grâce aux librairies fournies par Adafruit, ce capteur est assez simple à prendre en main. Des fonctions comme readTemperature() ou readHumidity() permettent d'accéder à la valeur de ces grandeurs. Seulement, ce capteur est plutôt destiné à un fonctionnement à l'air libre. Or, il va nous falloir la température de l'air mais également l'humidité du sol. De plus, le protocole de communication utilisé (I2C) est bien plus complexe à comprendre qu'une liaison série.

Finalement, nous avons pris la décision de ne travailler qu'avec des capteurs analogiques. En effet, pour le prototype Arduino ce choix n'est pas impactant mais pour la partie FPGA ce choix est préférable. Nous avons demandé une sonde de température (LM35) et nous avons commandé un kit comprenant un détecteur de niveau d'eau ainsi qu'un détecteur d'humidité à planter (lien).

Partie informatique

La distribution d'eau est une fonction essentielle de notre projet. Tout naturellement, on s'est penché en priorité sur le fonctionnement de la pompe. Pour connecter notre pompe, nous nous sommes référé à un schéma du driver TB6612FNG.

Programme du contrôle des moteurs

int STBY = 2;
int PWMA = 6; 
int AIN1 = 4;
int AIN2 = 5;

On commence par définir le numéro des pins à utiliser en veillant à prendre un pin compatible PWM pour contrôler la vitesse du moteur

void setup(){

 pinMode(STBY, OUTPUT);
 pinMode(PWMA, OUTPUT);
 pinMode(AIN1, OUTPUT);
 pinMode(AIN2, OUTPUT);

}

On initialise les pin en mode sortie

void loop(){

 move(255);
 delay(5000);
 stop();
 delay(2000);

}

La fonction loop se répète à l'infini. Ici, elle a simplement pour but de faire aspirer la pompe au maximum pendant 5s puis de s’arrêter 2s. C'est durant ce test que nous avons constaté que les valeurs en dessous de 255 ne permettaient pas une vitesse suffisante pour aspirer de l'eau. On fonctionnera donc en tout ou rien.

void move(int speed){

 digitalWrite(STBY, HIGH);
 boolean inPin1 = LOW;
 boolean inPin2 = HIGH;

 digitalWrite(AIN1, inPin1);
 digitalWrite(AIN2, inPin2);
 analogWrite(PWMA, speed);

}

Cette fonction met en marche le moteur et lui applique la consigne de vitesse. Le pin PWN sortira alternativement du 0 et du 5V afin d'obtenir une valeur moyenne correspondant à la consigne émise.

void stop(){

 digitalWrite(STBY, LOW); 

}

Les premiers tests sur la pompe sont concluants. Toutefois, même à une vitesse maximale, le débit est assez faible (goutte à goutte).

En seconde partie de matinée, nous avons commencé à réfléchir à l'interface web et plus précisément à son apparence. Nous avons décidé d'inclure des barres de progression afin de rendre plus graphique l'affichage de la température et de l'humidité. Pour le niveau d'eau, un pictogramme est suffisant pour signaler un manque d'eau ou non dans le réservoir. De même, à coté de la barre figurera sans doute un pictogramme indiquant le respect ou non des conditions de température.

Séance 2

Partie électronique

FPGA

PWM et comparaison

Durant cette seconde séance nous avons, continué notre ADC basé sur une PWM. Nous avons généré un signal en dents de scie à partir du signal carré modulé.

Pour cela, nous avons ajouté un filtre passe bas afin de filtrer la composante alternative dans le but de garder uniquement la composante continue du signal.

PWM sous Altium





Nous avons choisi une résistance de x Ohm et un condensateur de x Farad (prochainement : dimensionnement des composants)

Nous avons ensuite utilisé l’analyseur en mode oscilloscope afin de visualiser à la fois notre signal en dents de scie et le signal du capteur.

On remarque que le dispositif fonctionne.




Prototype Arduino

En première partie de matinée, on a finalisé les essaies des capteurs, à savoir celui de température (LM35) et celui d'humidité (VMA303). Les deux capteurs étant analogique, il nous à fallu trouver une correspondance entre la valeur numérique (entre 0 et 1023) et la grandeur physique. On sait pour le LM35 que 10mV = 1°C et que 5V = 5000mv ≡ 1023, par conséquent on obtient :  temperature = val\_num\_mesuree * (5.0 / 1023.0 * 100.0) . Pour le VMA303, on souhaite un pourcentage d'humidité, on a donc la formule suivante :  humidite = (100 / 1023) * val\_num\_mesuree . On a ensuite écrit un programme Arduino permettant d'afficher ces deux grandeurs sur le moniteur série de l'IDE Arduino.

void setup() {
 Serial.begin(9600);
}

void loop() {
 
 int valeur_num_temp = analogRead(A0);
 int valeur_num_hum = analogRead(A1);
 
 float temperature = valeur_num_temp * (5.0 / 1023.0 * 100.0);
 int humidite = valeur_num_hum * (100 / 1023);
 
 Serial.print("Température : ");
 Serial.println(temperature);
 Serial.print("Humidité : ");
 Serial.println(humidite);
 delay(150);

}

Les résultats nous ont permis de vérifier la précision du LM35 (+/-0.5°C) et de déterminer un ordre de grandeur des valeurs du capteur d'humidité. Contrairement à notre premier capteur (numérique), celui-ci est prévu uniquement pour les sols (valeur de 0 à l'air).

En seconde partie de matinée, on a cherché des solutions techniques pour mesurer le niveau d'eau dans un réservoir. En premier lieu, on a pensé à un système composé d'un capteur ultrason. Il a l'avantage d'être simple à mettre en place et de retourner un niveau précis en théorie. La mesure est calculée par une fonction Arduino permettant de mesurer une largeur d'impulsion émise par le HC-SR04 qui est proportionnelle à la distance. Cependant, nous n'avons pas réussi à trouver le moyen électronique de reproduire ce procédé. C'est pourquoi après réflexion entre tous les membres du groupe, on a pris la décision de n'utiliser que des capteurs analogiques afin de ne pas complexifier davantage la partie FPGA. On s'est remis à la recherche de dispositifs et on s'est aperçu qu'ils ne permettaient que de détecter des paliers. On a donc opté pour trois niveaux de contrôle : niveau bas / moyen / haut. La plupart étaient basés sur le même procédé : du courant injecté dans l'eau avec des conducteurs disposés dans l'eau à chaque palier. Le faible courant qui passe permet de commander des transistors qui laisseront ou non passer un courant plus important qui représentera l'immersion ou non du câble dans l'eau.

Schéma du capteur de niveau

Test du capteur de température et d'humidité Réalisation d'un PCB qui nous permettra de détecter le niveau d'eau dans le réservoir Réflexion sur le design de la page web de supervision

Partie informatique

En dehors des séances, nous avons travaillé sur l'interface web du projet. A l'aide d'un logiciel de création graphique, nous avons imaginé l'apparence souhaitée pour la page. Les images n'ont pas été gardées mais celle-ci ressemblée fortement au "Croquis de l'interface web" vu plus haut. Suite à cela, nous avons débuté l'étape de l'intégration en HTML/CSS. Pour ce faire, nous avons choisi d'utiliser le Framework Bootstrap pour sa modularité d'affichage sur tous les supports. Pour le moment, tous les éléments visibles sont statiques, nous ajouterons par la suite un script JavaScript permettant de modifier les valeurs des barres de progression.

Interface web (v1)











Séance 3

Partie électronique

FPGA

Comparaison sous Altium


Nous avons maintenant besoins d’un système de comparaison qui comparera la valeur numérique du capteur avec celle de notre consigne (la pompe devra se déclencher lorsque le taux d’humidité est inférieur à la consigne).

Pour cela, nous avons réalisé ce programme sous Altium dans le but de mieux comprendre le fonctionnement du bloc « comparator » grâce à 2 entrés virtuelles simulant la valeur du capteur et la consigne.





Partie informatique

Nous avons consacré cette séance à la partie informatique du projet. Tout d'abord, nous avons finalisé l'interface web en incorporant quelques changements visuel. Ensuite, nous avons attaqué la partie la plus intéressante : la dynamisation. N'ayant pas encore la liaison série établie (avec le serveur WebSocket), nous avons écrit nos fonctions en y faisant abstraction. En parralèle, nous avions créé un autre fichier nous permettant de réaliser des tests et de s'affranchir avec la syntaxe du JavaScript. La première fonction que nous avons réalisé été celle de la réception d'un message par le serveur WebSocket. Pour ne pas surcharger de code le wiki, nous ne détaillerons que la sous-partie consacrée à la température.

Interface web (v2)
websocket.onmessage=function(message){
		
 console.log(message.data);

On affiche le contenu du message sur la console (pour le débogage)

 if((message.data)[0] == 'T')		
 {
  var value = (message.data).substring(1) * (5.0 / 1023.0 * 100.0);
  value = Math.round(value*100)/100;
  document.getElementById("temp").innerHTML = value;
  document.getElementById("temp_lvl").style.width = value +"%"; 

La condition if signifie que le message commence par un 'T'. Ensuite, grâce à la méthode substring, on va découper le message et ne garder que la partie qui contient le nombre auquel on appliquera une formule pour passer d'une valeur analogique entre 0 et 1023 à une température en degré celsius. La ligne suivante permet simplement d'arrondir le résultat. Finalement, on change la valeur inscrite dans la barre de progression et on modifie sa largeur.

  if(value < consigne_temp_inf || value > consigne_temp_sup)
  {
   document.getElementById("temp_ok").className = "glyphicon glyphicon-remove";
   document.getElementById("temp_lvl").style.backgroundColor = "#e74c3c"; 
  }

Cette nouvelle condition permet d'avertir l'utilisateur d'un défaut de température. Lorsque celle-ci n'est pas comprise dans l'intervalle fixé, la couleur de la barre passe au rouge et un logo en forme de croix apparaît.

  else
  {
   document.getElementById("temp_ok").className = "glyphicon glyphicon-ok";
   document.getElementById("temp_lvl").style.backgroundColor = "#2ecc71";
  }
 
}  

Dans le cas contraire, la barre passe au vert et un logo "Ok" fait son apparition.

A quelques détails près, ce morceau de fonction est bâti sur le même principe pour le taux d'humidité et le niveau d'eau. Pour le moment, les informations ne transitent que dans un sens, du serveur WebSocket au client. En dehors de cette séance, nous avons travaillé sur la transmission inverse, du client au serveur. Une seule information doit pouvoir être envoyée, il s'agit du taux d'humidité. En effet, la plage de température ne sert que d'indicateur mais ne joue aucun rôle sur le système contrairement à l'humidité qui peut activer la pompe. Deux fonctions ont été réalisées pour la gestion des consignes : sendTemp() et sendMoisture().

Commençons par regarder celle pour l'humidité.

function sendMoisture()
{

 var consigne = document.getElementById("consigne_moisture_change").value;

On commence par récupérer la valeur de l'input.

 if(consigne == ""){return;}

Si la valeur est nulle, on sort de la fonction.

 document.getElementById("consigne_moisture_change").value = ;

Sinon, on efface la valeur de l'input.

 if (parseInt(consigne) > 100)
 {
  consigne = "100";
 }
 websocket.send("M"+consigne);

} 

Si la consigne est supérieure à 100, on la fixe à 100 et dans tous les cas on envoie au serveur WebSocket la nouvelle valeur précédée d'un 'M'.

Pour s'assurer de la prise en compte du nouveau seuil, l'Arduino doit envoyer en retour "M[consigne]". Une condition de la fonction websocket.onmessage=function(message) permet de mettre à jour la variable de la consigne dans le script et de l'afficher.

La fonction consacrée à la température n'a besoin d'aucun envoie, il s'agit simplement d'un affichage.

function sendTemp()
{
 var consigne1 = document.getElementById("consigne1_temp_change").value;
 var consigne2 = document.getElementById("consigne2_temp_change").value;

On récupère les valeurs des deux inputs dans des variables temporaires.

 if(consigne1 == "" || consigne2 == ""){return;}

Si l'une des deux est nulle, on sort de la fonction.

 var temp_bornes = [parseInt(consigne1),parseInt(consigne2)];

On crée un tableau d'entier contenant les deux valeurs (permet de gérer plus facilement les cas où la première valeur est supérieur à la seconde).

 consigne_temp_inf = Math.min.apply(Math, temp_bornes);
 consigne_temp_sup = Math.max.apply(Math, temp_bornes);
 document.getElementById("consigne_temp").innerHTML = consigne_temp_inf+"-"+consigne_temp_sup+"°C";
}

On changes les variables globales de consigne de température puis on les affiche.

L'ensemble du fichier html sera disponible sur notre repository git en fin de projet.

Séance supplémentaire 1

Partie électronique

FPGA

Nous avons décidé de mettre en application notre programme de comparaison et nous nous sommes alors rendu compte qu’il nous manquait un élément indispensable à notre ADC : un compteur !

En effet, jusque là nous étions en mesure de comparer 2 signaux avec un AOP mais nous ne pouvions pas récupérer la valeur numérique.

Pour cela, nous avons ajouté un compteur 8bits comptant au même rythme que la PWM, de cette manière, quand l’AOP renverra un signal comme quoi la tension du capteur est supérieure à la tension du signal en dents de scie, nous récupérerons la valeur numérique du compteur sur 8bits.

Le test de notre ADC avec un capteur de luminosité s’est révélé être un succès ! Notre ADC est donc opérationnel, nous allons donc pouvoir nous concentrer sur la structure globale du FPGA

Prototype Arduino

Après s'être assuré du bon fonctionnement de tous les capteurs, il ne nous restait plus qu'à assembler ces différents tests en un seul programme. Ce programme Arduino doit être capable de transmettre par l'intermédiaire de la liaison série les informations provenant des capteurs. De plus, il doit permettre d'allumer ou non la pompe selon la consigne d'humidité qu'il aura reçu par l'utilisateur depuis l'interface.

Montage du prototype
int STBY = 2;
int PWMA = 6; 
int AIN1 = 3;
int AIN2 = 4;
int consigne = -1;
String received;

On commence par définir les variables du programme.

void setup() 
{
 pinMode(STBY, OUTPUT);
 pinMode(PWMA, OUTPUT);
 pinMode(AIN1, OUTPUT);
 pinMode(AIN2, OUTPUT);  
 Serial.begin(115200);
}

On initialise les pins en sortie et on active la liaison série avec un baud rate de 115200.

void loop() {

 int temp_analog = analogRead(A0);
 int water_lvl = analogRead(A1);
 int hum_purcent = analogRead(A2)/10.23;
 received = Serial.readString();

On récupère les valeurs analogiques des capteurs et on lit sur le port série une éventuelle consigne.

 if(received != "")
 {

  char c = received.charAt(0);

  if(c == 'M')
  {
   consigne = (received.substring(1)).toInt();
   Serial.print(received);
   delay(50);
  }

 }

Si le message n'est pas vide et qu'il commence par la lettre M alors on change la valeur de la consigne et on envoie le même message que celui reçu pour avertir de la bonne réception.

 if(hum_purcent < consigne && consigne != -1 )
 {
  move(255); 
 }
 else
 {
  stop();
 }

On active la pompe si le taux d'humidité est inférieure à celui demandé (et que la consigne est différente de -1, valeur initiale) sinon on l'éteint.

 String water = "N"+String(water_lvl,DEC);
 String temp = "T"+String(temp_analog,DEC);
 String hum = "H"+String(hum_purcent,DEC);

 Serial.print(water); 
 delay(300);
 Serial.print(hum);
 delay(300);
 Serial.print(temp);  
 delay(300);

}

Dans cette dernière partie, on envoie les données des capteurs en rajoutant une lettre pour les identifier correctement.

Partie informatique

Parallèlement à la partie Arduino, nous avons commencé le programme en C du serveur WebSocket et celui de la liaison série en se basant sur les exemples fournis. La première étape a été de comprendre le fonctionnement global du serveur et notamment la notion de callback. Pour nous initier, nous avons réalisé un premier programme permettant d'afficher sur la page web un caractère transmis depuis un programme Arduino. Une fois fonctionnel, nous avons expérimenté la transmission inverse. Ces deux petits programmes nous ont permis de combiner à la fois la lecture/écriture sur le port série et l'envoie/réception de données sur le serveur WebSocket. Prochaine étape, adapter l'ensemble à notre système.

Séance supplémentaire 2

Partie électronique

FPGA

Après avoir passé 4 séances sur l’ADC il nous fallait donc revenir au schéma global de notre FPGA.

Multiplexeur liaison série

Nous disposons de 3 capteurs analogique : Niveau d’eau et Température qui ne servent qu’a donner des informations à l’utilisateur (ie : n’agit sur aucun actionneur), et un capteur d’Humidité qui doit donner des informations à l’utilisateur mais aussi déclencher la pompe lorsque le taux d’humidité de la terre est trop faible.

Nous aurons donc besoin d’une liaison série. Nous utiliserons les blocs en .VHDL fournis.

Notre AOP dispose de 2 comparateurs, nous aurons donc besoin d’un AOP supplémentaire.


Nous récupérerons donc les valeurs numériques des 3 capteurs et nous allons devoir les envoyer en série.

Dans le but de réunir partie informatique et partie électronique, nous décidons d’établir un protocole de communication : les valeurs des capteurs seront précédées des lettre ‘H’, ‘T’ et ‘N’ en ASCII. De cette manière, lorsque la raspberry recevra un ‘H’ elle sait que l’octet suivant correspondra à la valeur de l’humidité, idem pour les autres capteurs.

Nous allons pour cela utiliser un multiplexeur auquel on connectera un compteur allant de 0 à 6 (voir schéma ci-contre) Le schéma de base du FPGA est donc terminé, il ne nous reste plus qu’a tester les capteurs afin de voir si la conversion s’effectue correctement.


Partie informatique

Séance supplémentaire 3

Partie électronique

FPGA

Problème de calibrage de la tension de référence

Malheureusement, la conversion analogique numérique ne se passe pas comme prévue pour le capteur de température. En effet, le capteur varie de 0V…1,5V -> 0°C…150°C soit 10mV par °C alors que la PWM varie de 0V à 3V.

On constate sur l’analyseur qu’a 24,8°C (température de la salle) le capteur renvoi 248mv, valeur bien trop petite comparé aux 3V du capteur et même si le convertisseur fonctionne, la précision est déplorable.(la conversion donne 25 à 24,8°C, à 100°C elle donnerait 85)

En lien avec notre cours sur l’ATMEGA nous nous sommes rappelé que son ADC requiert une « tension de référence ».

C’est également ici le cas et la tension de référence correspond à celle du signal en dents de scie.

En effet : ADC = (Vin * 256 (8 Bits))/Vref donc ADC = [0 ,128] nous perdons la moitié de notre précision.

Si on s’intéresse uniquement à des températures entre 0°C et 100°C alors on choisira un Vref de 1V.

En effet En effet : ADC = (Vin * 256 (8 Bits))/Vref donc ADC = [0 ,256] et à 24,8°C on aura 63 ce qui est bien plus intéressant compte tenu de notre application.

Nous avons donc besoin de réduire la tension du signal en dents de scie grâce à un pont diviseur.


Partie informatique

Conclusion