Pepper 2019 – Localisation wifi par ESP8266

Il n’est pas possible d’utiliser les commandes systèmes de Pepper en programmation normale. En effet, les accès « sudo » sont verrouillés par le constructeur. Pour localiser le robot en fonction des signaux wifi, il faut donc y embarquer un matériel communicant supplémentaire, un peu comme un GPS dans une voiture.



Taille : 75mm x 35mm
Le principe retenu utilise une carte ESP8266 qui scanne le réseau wifi en permanence,
et publie le résultat sur une page HTML de son site internet local.

Le logiciel embarqué dans la carte ESP :

  1. s’initialise pour avoir une adresse IP fixe
  2. se connecte au Wifi local
  3. initialise un serveur web
  4. scanne en permanence le wifi local
  5. la page HTML d’accueil est recrée en fonction des résultats du scan, avec
    les 4 signaux les plus forts.



Page renvoyée par l’ESP

Initialisation de l’ESP


void setup() {
  Serial.begin(115200);
  // IP statique
  IPAddress ip(192, 168, 1, 222);
  IPAddress gateway(192, 168, 1, 254);
  IPAddress subnet(255, 255, 255, 0);
  IPAddress dns(192, 168, 1, 254);
  WiFi.config(ip, dns, gateway, subnet);
  WiFi.begin(ssid, password);
  Serial.println("");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.print("\nConnexion ");
  Serial.println(ssid);
  Serial.print("Addresse IP: ");
  Serial.println(WiFi.localIP());
  ...
}

Scan réseau

La fonction Wifi.scanNetworks() renvoie le nombre de wifi détectés. Les fonctions Wifi.SSID(i) et Wifi.RSSI(i) renvoient respectivement
le i-ème SSID détecté ainsi que la force du signal (le rssi)

void loop() {

    Serial.println("scan ...");
    // WiFi.scanNetworks renvoie le nombre de reseaux trouves
    int n = WiFi.scanNetworks();
    Serial.println("scan ok");
    if (n == 0)  Serial.println("Pas de reseau");
    else {
      Serial.print(n);
      Serial.println(" Wifi : ");
      SCAN=1;
      raz(); 
      for (int i = 0; i < n; ++i)  {
          ajoute((WiFi.SSID(i)).c_str(), WiFi.RSSI(i)); 
          Serial.print(i + 1);
          Serial.print(": ");
          Serial.print(WiFi.SSID(i));
          Serial.print(" (");
          Serial.print(WiFi.RSSI(i));
          Serial.println(")\n");
      }
      SCAN=0;
    }
   server.handleClient();
}

 

Stockage des n meilleurs résultats

Les wifi détectés sont stockés dans un tableau de structures.
Chaque structure contient un SSID et son RSSI. On ne conserve que les NWIFI les meilleurs

#define NWIFI 4

struct Swifi {
  char wf[128];
  int rssi;
} TW[NWIFI];


// RAZ du tableau des meilleurs wifi
void raz() {
  for (int i=0; i<NWIFI; i++) {
     TW[i].rssi=-1000;
     TW[i].wf[0] = 0;
  }
}

// Ajout d'un wifi dans la sélection.
// Seulement s'il fait partie des meilleurs ..
void ajoute(const char *ssid, int rssi){
   int r = 0;
   while (rr; i--) TW[i]=TW[i-1];
   TW[r].rssi = rssi;
   strcpy(TW[r].wf, ssid);
}

 

Fabrication de la page HTML

La page HTML est fabriquée à partir de la dernière mesure de wifi.
La fonction handleRoot() renvoie le message à chaque client web
qui a fait la requête http://192.168.1.222/

 


// page html
char html[128*NWIFI];

void handleRoot() {
  char b[128];
  html[0] = 0;
  while (SCAN==1) delay(10);
  for (int i=0; i<NWIFI; i++) {
     sprintf(b,"%s;%d\n", TW[i].wf, TW[i].rssi);
     strcat(html, b);
  }
  server.send(200, "text/plain", html);
}

 

Code complet

ScannerDoc.ino

Récupération des informations en python

Le programme python utilise le module requests. Le code est trivial :


La trace d’exécution est dans la partie droite

Firmware ESP8266-1 pour rObOtscratch II

Câblage

/**
 *  C.G. 2017 - Firmware ESP 8266-1 pour rObOscratch II
**/
 
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* ssid = "rObOtScratch";
const char* password = "56claude";

ESP8266WebServer server(80);


int bAV_D = 1; // variable d'état : moteur droite en avant (1) ou arrière (0)
int vAV_D = 0; // nb de ticks en position haute pour le hacheur
int vAV_Dold = 4; // pour reprendre à la meme vitesse apres un arret

int bAV_G = 1;
int vAV_G = 0;
int vAV_Gold = 4;

int h = 0;

void handleRoot() {
  server.send(200, "text/plain", "CG 2017 PETIT ROBOT avec ESP8266");
}

void handleAV() {
  bAV_D = 1;
  vAV_D = vAV_Dold;
  bAV_G = 1;
  vAV_G = vAV_Gold;
   
}

void handleAR() {
  bAV_D = 0;
  vAV_D = vAV_Dold;
  bAV_G = 0;
  vAV_G = vAV_Gold;
}

void handleDR() {
  bAV_D = 1;
  vAV_D = vAV_Dold;
  bAV_G = 0;
  vAV_G = vAV_Gold;  
}

void handleGA() {
   bAV_D = 0;
   vAV_D = vAV_Dold;
   bAV_G = 1;
   vAV_G = vAV_Gold;
}

void handlePlus() {
    vAV_D++; if (vAV_D>10) vAV_D=10;
    vAV_G++; if (vAV_G>10) vAV_G=10;
    vAV_Dold = vAV_D;
    vAV_Gold = vAV_G;
}

void handleMoins() {
    vAV_D--; if (vAV_D<0) vAV_D=0;
    vAV_G--; if (vAV_G<0) vAV_G=0;
    vAV_Dold = vAV_D;
    vAV_Gold = vAV_G;
}

void handleStop() {
  vAV_Dold = vAV_D;
  vAV_D = 0;
  vAV_Gold = vAV_G;
  vAV_G = 0; 
}

void handleNotFound(){
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET)?"GET":"POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i=0; i<server.args(); i++){ 
     message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; 
  } 
  server.send(404, "text/plain", message); 
} 


// HACHEUR 
volatile int toggle; 
void inline hacheur (void){ 
        h++; if (h>10) h=0;
	if (bAV_D == 1) { // moteur droite en avant
		if (h < vAV_D) { digitalWrite(0, 1);  digitalWrite(2, 0); } 
                else { digitalWrite(0, 0); digitalWrite(2, 0);}
	} else {
		if (h < vAV_D) { digitalWrite(0, 0); digitalWrite(2, 1);} 
                else { digitalWrite(0, 0); digitalWrite(2, 0);}
	}
	
	if (bAV_G == 1) { // moteur gauche en avant
		if (h < vAV_G) { digitalWrite(1, 1);  digitalWrite(3, 0);} 
                else { digitalWrite(1, 0); digitalWrite(3, 0);}
	} else {
		if (h < vAV_G) { digitalWrite(1, 0); digitalWrite(3, 1); } 
                else { digitalWrite(1, 0); digitalWrite(3, 0); } } 

       timer0_write(ESP.getCycleCount() + 80000); 
       // 80Mhz -> 80*10^6 = 1 seconde
       //          80*10^3 = 1 ms    
}

void setup(void){
   int i = 0;
   
   pinMode(0, OUTPUT);
   pinMode(1, OUTPUT);
   pinMode(2, OUTPUT);
   pinMode(3, OUTPUT);

   WiFi.begin(ssid, password);
   delay(500);
   // Attente de connexion
   while (WiFi.status() != WL_CONNECTED) delay(500);

   server.on("/", handleRoot);
   server.on("/av",[](){handleAV(); server.send(200, "text/plain", "AV");});
   server.on("/1", [](){server.send(200, "text/plain", "1");});
   server.on("/0", [](){server.send(200, "text/plain", "0");});
   server.on("/ar",[](){handleAR(); server.send(200, "text/plain", "AR");});
   server.on("/dr",[](){handleDR(); server.send(200, "text/plain", "DR");});
   server.on("/ga",[](){handleGA(); server.send(200, "text/plain", "GA");});
   server.on("/+", [](){handlePlus(); server.send(200, "text/plain", "+");});
   server.on("/-", [](){handleMoins(); server.send(200, "text/plain", "-");});
   server.on("/st",[](){handleStop(); server.send(200, "text/plain", "STOP");});
   server.onNotFound(handleNotFound);
   server.begin();  
   
   noInterrupts();
   timer0_isr_init();
   timer0_attachInterrupt(hacheur);
   timer0_write(ESP.getCycleCount() + 80000000);
   interrupts();
 
}

void loop(void){
  server.handleClient();
}

ESP8266: installations

ESP 8266

Installation des logiciels pour la programmation avec LUA

Il faut installer dans la carte ESP un firmware qui permet de recevoir et
d’exécuter les scripts écrits en langage LUA.
Page de référence: https://github.com/nodemcu/nodemcu-firmware

Dans un terminal:

  1. mkdir ESP8266
  2. cd ESP8266
  3. git clone https://github.com/nodemcu/nodemcu-firmware.git
  4. git clone https://github.com/espressif/esptool.git

Si la commande git n’est pas trouvée:
sudo apt install git

Après ces installations, vous disposez dans le dossier nodemcu-firmware du code source pour compiler un firmware pour la carte ESP8266; et dans le dossier esptool d’un outil pour flasher la carte ESP8266.

Compilation du firmware

L’espace de stockage est réduit dans l’ESP8266: il convient de compiler un firmware ne
contenant strictement que les modules qui seront véritablement utilisés par
l’application.

Choix des modules

Il suffit de commenter ou dé-commenter des lignes dans le fichier

nodemcu-firmware/app/include/user_modules.h
Exemple: user_modules.h