vendredi 25 décembre 2015

ESP8266 Wifi ultrasonic distance logger

Envoi par wifi d'une mesure de distance à l'aide d'un capteur à ultrasons

J'ai besoin de mesurer la distance face à un obstacle qui peut survenir de manière aléatoire et de pouvoir disposer de cette mesure à distance.

L'idée est de faire aussi simple que possible et aussi d'apprendre à utiliser les composants à disposition.
Pour ce faire, il vous faut :


Pourquoi ces choix ?
Tout d'abord le coût, on ne peut pas faire plus bas, vraiment. Ensuite, ils ont été largement utilisés par les internautes, donc on en parle partout sur les forums et sites web, des exemples de programmation.
On apprend en s'amusant.

On apprend à programmer un Arduino, à connecter des liaisons séries, des commandes AT (commandes texte universelles pour dialoguer avec les modems, les périphériques séries), à envoyer des informations sur le Web par un petit dispositif électronique ! Internet des Objets, Internet of Things, IoT.

Il existe des sites web qui acceptent des requêtes de ce genres et vous permettent de stocker vos données, de vous les afficher et de les partager avec des proches ou en mode public. Regardez thingspeak.com

Tout d'abord il faut câbler l'Arduino nano V3 au module ultrason HC-SR04,.

J'ai choisi de souder directement ses 2 pins trig (demande logique d'envoi du signal us) et echo (signal logique indiquant qu'il a reçu l'écho us) sur les pins d'E/S 11 et 12

int trig = 11; 
int echo = 12; 
pinMode(trig, OUTPUT); 
digitalWrite(trig, LOW);
digitalWrite(trig, LOW);

Il faut connecter les 2 autres pins au +5V (attention le nano fonctionne sous 3.3V mais il a du 5V qui vient du connecteur USB) et à la masse (GND).

Pleins de tutoriaux expliquent le fonctionnement du capteur à ultrasons HC-SR04 :
http://tutorial.cytron.com.my/2012/10/11/testing-ultrasonic-ranging-module-sn-hc-sr04/
http://www.instructables.com/id/Easy-ultrasonic-4-pin-sensor-monitoring-hc-sr04/
http://www.instructables.com/id/Simple-Arduino-and-HC-SR04-Example/?ALLSTEPS
mais le plus simple, et c'est là d'ailleurs d'où j'ai pris les lignes du programme, est le site :
https://itechnofrance.wordpress.com/2013/03/12/utilisation-du-module-ultrason-hc-sr04-avec-larduino/


L'utilisation se fait dans la boucle qui s'exécute tout le temps, on mettra un délais d'une seconde ou plus entre deux lectures successives :
  digitalWrite(trig, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trig, LOW); 
  lecture_echo = pulseIn(echo, HIGH); 
  cm = lecture_echo / 58; 
  Serial.print("Distance (cm) : "); 
  Serial.println(cm); 

Ce qui correspond bien au schéma de la trame d'envoi et de réception :


Ensuite, on s'intéresse à la partie transmission de données à distance, via internet et donc le module Wifi ESP8266.

Il existe plusieurs modèles (cette page est très documentée), j'ai pris le plus répondu le ESP8266-01. Certains modules le -07 par exemple, ont en plus un connecteur SMA pour connecter une antenne extérieure afin d'augmenter la portée du wifi.
Le site de référence est : http://www.esp8266.com/

Plusieurs sites et tutoriaux existent aussi, je vous recommande
http://www.instructables.com/id/ESP8266-Wifi-Temperature-Logger/?ALLSTEPS
http://zeflo.com/2014/esp8266-weather-display/
et
http://www.les-electroniciens.com/videos/arduino-ep16-installation-du-module-wifi-esp8266
d'où j'ai puisé le code puis adapté.
La différence par rapport à mon application est que je veux utiliser le module comme client et non pas serveur. Je ne cherche pas à ce que des clients (Web browsers) se connectent sur mon ESP8266. Je veux juste que l'ESP8266 puisse se connecter à mon routeur Wifi puis envoyer des requêtes http et recevoir des informations (enfin pour l'instant je veux juste envoyer).

Tout d'abord, la présentation de ce module magique.
Il est le moins cher sur le marché (1 à 3€) !
Le plus simple car il embarque la pile TCP/IP (routines...) dans son firmware et y a pas à la programmer sur le micro-contrôleur qui le gère (Arduino) contrairement  à d'autre modules wifi qui se pilotent pas une pile TCP/IP logicielle à inclure dans votre programme de uC, je citerai l'exemple du Microchip MRF24WB0MA et qui coûte 25 €.

Il faut brancher l'ESP8266 sur le port série de l'Arduino. Pas le port logiciel standard (9600 bds) qui nous sert pour le débogage via le FTDI et donc le port USB, mais il faut le brancher sur un port série supplémentaire qui va fonctionner à 115200 bds, la valeur par défaut du ESP8266.

Y aussi ceux qui ont voulu reprogrammer le firmware du module
http://www.xess.com/blog/esp8266-reflash/
http://hackaday.com/2015/03/18/how-to-directly-program-an-inexpensive-esp8266-wifi-module/

mais il vaut mieux laisser ça quand vous serez plus familier avec ce module

Regardons le pinout (brochage)
ESP8266 pinout

Le connecteur ne peut pas aller sur une plaque d'essai (M-board) de connexion mais on peut y souder des fils ou les wrapper.
Il faut connecter, en mode normal, le CH-PD à VCC à 3.3V (il n'accepte pas le 5V) ce qui convient bien à l'Arduino nano V3.
Connecter la masse à celle de l'Arduino et le TXD et RXD à des pins d'E/S que l'on raccordera, en croisant (RX avec TX et TX avec RX), au module UART de l'Arduino.

CH_PD (power down) permet de couper le module si elle passe à l'état bas.

Pour vous montrer les connections, un outil simple et gratuit est Fritzing. Il permet de dessiner les connexions entre les différents éléments et on trouve pratiquement tous les composants électroniques courants.
Voici donc le schéma de connexion :



Du point de vue programme la configuration de la liaison série se fait par :

SoftwareSerial ESP8266(9, 8); // 8 sur RX du ESP8266 9 sur TX du ESP8266

dans la routine Setup il faudra configurer le port série à 115200 bds puis appeler l'initialisation du module

ESP8266.begin(115200);
initESP8266();

Cette routine doit configurer le Wifi de manière à ce que le module se connecte à votre routeur.
Le module peut aussi être point d'accès ou serveur.
On envoie d'abord la commande de Reset
AT+RST

Qui le remet par défaut. Notons qu'il enregistre dans sa mémoire les connexions précédentes et la config d'avant.On choisit ensuite le mode client (1) par opposition au mode serveur (3)
AT+CWMODE=1
Puis le SSID et le PW du wifi de votre routeur (entre guillemets).
"AT+CWJAP=\""+ WifiSSID + "\",\"" + WifiPW +"\""

On peut lire après la connxion l'adresse IP attribuée par le routeur au module ESP8266 à l'aide de la commande
AT+CIFSR

Ensuite, il faut lui dire de n'accepter qu'une seule connexion
AT+CIPMUX=0

J'ai galéré sur cette instruction car avant j'étais en CIPMUX=1 et je n'arrivais pas à faire des requêtes TCP...

Les commandes AT sont résumées sur


ou sur ESP8266_WiFi_Module_Quick_Start_Guide_v_1.0.4.pdf


Une fois que le module est connecté au routeur et qu'une IP lui est attribuée (on se sert du moniteur de de liaison série FTDI pour voir ça), on peut alors à chaque lecture de distance, se connecter à un site web et envoyer la requête :
http://api.thingspeak.com/update?key=VOTRECLEF&field1=31

Cela se fait d'abord par une connexion au site web à l'aide de la commande
AT+CIPSTART
où l'IP ou le site web est donné
#define IP "thingspeak.com" // thingspeak.com

puis, une fois connecté, d'envoyer la commande
AT+CIPSEND
en faisant un GET avec la commande update propre au site web thingspeak
String GET = "GET /update?key=VOTRECLEF&field1=";




On peut lire les réponses, les analyser pour vérifier s'il y a une erreur ou non.
Il faut faire attention car le site peut être "busy" si vous le sollicitez trop fréquemment.
Si vous disposez de votre propre site web et d'une base de données MySQL, cela peut être tout aussi intéressant.
Cependant, le site thingspeak offre des affichages graphiques, des cadrants, le partage en mode public, privé, la possibilité d'enregistrer plusieurs champs dans le même canal (requête).
Voici un exemple d'affichage :


En parlant d'autonomie, on peut alimenter directement tout le montage à travers le mini USB de l'Arduino nano avec un chargeur de téléphone portable classique. L'utilisation de piles ne sera pas viable car le système est relativement gourmand en énergie. Il faut aussi faire attention au pic de consommation de l'ESP8266 par rapport à ce que peut fournir le régulateur de tension 3.3V de l'Arduino nano.

Voici le proto, auquel j'ai rajouté un speaker de téléphone portable pour créer des alertes sonores.




Pour finir, voici le programme complet.
Il faut remplacer les Votre... par les mots de passe et codes qui vous sont propres.

// capteur Ultrason HC-SR04 + ESP8266 + thingspeak

#include 
<Arduino.h> #include <SoftwareSerial.h> SoftwareSerial ESP8266(9, 8); // 8 sur RX du ESP8266 9 sur TX du ESP8266 String WifiSSID = "VotreSSID"; String WifiPW = "VotrePW"; #define IP "thingspeak.com" // thingspeak.com String GET = "GET /update?key=VOTRECLEF&field1=";
// définition des broches utilisées 
int trig = 11; 
int echo = 12; 
long lecture_echo; 
long cm;

void setup() 
{ 
  pinMode(trig, OUTPUT); 
  digitalWrite(trig, LOW); 
  pinMode(echo, INPUT); 
  Serial.begin(9600); 
  ESP8266.begin(115200);
  initESP8266();
}

void loop() 
{ 
  digitalWrite(trig, HIGH); 
  delayMicroseconds(10); 
  digitalWrite(trig, LOW); 
  lecture_echo = pulseIn(echo, HIGH); 
  cm = lecture_echo / 58; 
  Serial.print("Distance (cm) : "); 
  Serial.println(cm); 
  
  delay(5000); 
  updateDistance(String (cm, DEC));

  while(ESP8266.available())
    {    
    Serial.println(ESP8266.readString());
    }   
}

//---------------------------------------------------------------
//                Fonction qui initialise l'ESP8266             */
void initESP8266()
{  
  Serial.println("---------------------------------");  
  Serial.println("--  DEBUT DE L'INITIALISATION  --");
  envoieAuESP8266("AT+RST");
  recoitDuESP8266(2000);
  Serial.println("---------");
  /*envoieAuESP8266("AT+GMR");
  recoitDuESP8266(2000);
  Serial.println("---------");*/
  //envoieAuESP8266("AT+CWMODE=3");  // Serveur
  envoieAuESP8266("AT+CWMODE=1");  // Client
  recoitDuESP8266(5000);
  Serial.println("---------------------------------");  
  envoieAuESP8266("AT+CWJAP=\""+ WifiSSID + "\",\"" + WifiPW +"\"");
  recoitDuESP8266(10000);
  Serial.println("---------------------------------");  
  envoieAuESP8266("AT+CIFSR");
  recoitDuESP8266(1000);
  Serial.println("---------------------------------");  
  //envoieAuESP8266("AT+CIPMUX=1");  // ne marche pas en client 
  envoieAuESP8266("AT+CIPMUX=0");   
  recoitDuESP8266(1000);
  Serial.println("---------------------------------");  
  //envoieAuESP8266("AT+CIPSERVER=1,80");
  //recoitDuESP8266(1000);
  
  Serial.println("---------------------------------");  
  Serial.println("--  FIN DE L'INITIALISATION  --");
  Serial.println("---------------------------------");  
  Serial.println("");  
}

//---------------------------------------------------------------
//        Fonction qui envoie une commande à l'ESP8266 
void envoieAuESP8266(String commande)
{  
  ESP8266.println(commande);
}
//---------------------------------------------------------------
// Fonction qui lit et affiche les messages envoyés par l'ESP8266
void recoitDuESP8266(const int timeout)
{
  String reponse = "";
  long int time = millis();
  while( (time+timeout) > millis())
  {
    while(ESP8266.available())
    {
      char c = ESP8266.read();
      reponse+=c;
    }
  }
  Serial.print(reponse);   
}

//---------------------------------------------------------------
// Fonction qui envoie la nouvelle distance à thingspeak.com/channels/LEVOTRE/
void updateDistance(String distance)
{
  String cmd = "AT+CIPSTART=\"TCP\",\"";
  cmd += IP;
  cmd += "\",80";
  ESP8266.println(cmd);
  recoitDuESP8266(1000);
  delay(2000);
  if(ESP8266.find("Error")){
    Serial.print("erreur connection thingspeak");   
    return;
  }
  cmd = GET;
  cmd += distance;
  cmd += "\r\n";
  ESP8266.print("AT+CIPSEND=");
  
  ESP8266.println(cmd.length());
  if(ESP8266.find(">")){
    ESP8266.print(cmd);
  }else{
    ESP8266.println("AT+CIPCLOSE");
  }
}