ESP8266 Web server con telemetria

Da raspibo.
Jump to navigation Jump to search
Web serv 01.png

ESP8266 Web server con telemetria
Interfaccia di comando WiFi

Introduzione

Il presente progetto è un'estensione di ESP8266 Web server touch e si prefigge di aggiungere al progetto citato la restituzione su Display touch di dati misurati da Arduino.

In questa estensione si mostra come si possano ottenere sul display touch di un cellulare o di un tablet valori 'inviati ad' e 'prelevati da' Arduino.

  • Nell'immagine si vede il riquadro centrale L=127 R=127 che mostra i valori pwm attuali 'inviati ad Arduino'.
  • Nell'immagine i due riquadri piccoli in alto V=4 e K=2 mostrano i dati telemetrici 'prelevati da Arduino'.
  • Il pulsante BLU circolare, inserito in alto, consente di inviare con un touch la richiesta di aggiornamento dei dati telemetrici.
  • NOTA: Per estensione si potrebbe usare, con modifiche 'leggere', questa applicazione in ambito domotico sia per visualizzare lo stato di sensori che per azionare switch o relays.

Il circuito usato per lo scambio dati

La figura mostra come sono stati connessi tra loro ESP8266 ed Arduino.

Oltre a questo sono mostrate le connessioni con il driver motori del Robottino che verrà usato e il collegamento dei sensori con Arduino.

NANO ESP8266.png

Il progetto illustrato qui è stato ricavato dal modello Ruschino, con piccole variazioni del SW e dell'HW nell'utilizzo del driver motori.

In particolare qui si fa uso del ponte H del driver per motori DC del tipo L298N interfacciato con integrato Inverter tipo 4069 che consente di utilizzare solo due segnali PWM per 'governare' i motori.

L298N.png

I valori PWM variano da 127 a 255 per il moto in avanti e da 127 a 0 per il moto all'indietro.

Le connessioni

  1. Sono visibili, in alto a sinistra, le TRE connessioni all'alimentazione: 7-12v per Arduino (verso pin VIN), Gnd e 3.3v per ESP8266. Il Diodo Schottky è stato inserito per impedire inversioni di alimentazione.
  2. Arduino Nano e scheda ESP8266 sono connessi serialmente sui pin 6,7 di Arduino facendo uso della libreria <SoftwareSerial.h>. In questo modo i collegamenti Rx e TX nativi di Arduino sono utilizzati per il caricamento e il debug dei programma con IDE. Si nota lo switch SW2 che ha il compito di isolare il collegamento seriale se si utilizza FTDI per aggiornare i file di ESP o per il caricamento del firmware NodeMCU.
  3. Il partitore in alto, 8.2k-4.7k è calcolato per ridurre la tensione massima di circa 14v ad un valore ADC minore di 5.0v. La connessione del partitore al pin A0 consente la misura della tensione della batteria di alimentazione. La connessione (di esempio) di un sensore di Temperatura NTC al pin A1. Le DUE misure sono inviate in telemetria al display touch.
  4. Connessione tra ESP e convertitore FTDI USB-Seriale. Da notare il partitore in basso 18k-12k che serve per ridurre il segnale seriale Tx di Arduino dai 5v ai 3.3 di Rx di ESP. Lo switch SW1 è indispensabile per portare a massa il pin di ESP quando si usa la connessione FTDI per caricare il firmware NodeMCU.
  5. E' mostrata a parte l'immagine di L298N con 4096 e le relative connessioni.

Modifiche al Software di ESP8266

i file del progetto Ruschino web_serv.lua, init_lua, e index.htm hanno mantenuto lo stesso nome e sono stati modificati come illustrato qui:

init.lua

tmr.alarm(0, 3000, 0, function() dofile('web_serv.lua') end );
print("");
uart.setup(0,57600,8,0,1,0);

Unica modifica la velocità di trasmissione dati da 115200 a 57600. Utilizzando la velocità più alta si riscontrava qualche errore di ricezione da parte di Arduino, non è escluso che si possa far funzionare anche a 115200 bisognerebbe fare altre prove.

web_serv.lua

Vengono mostrati i soli punti di modifica del file web_serv.lua

print("R=127&l=127&C=0");

la linea (14 in web_serv.lua originale) ha subito la seguente modifica: Si invia ad Arduino l'azzeramento iniziale delle velocità motori che ora hanno valore PWM=127.

Il parametro C=0 è stato utilizzato, per distinguere le varie opzioni touch, per il testing del JavaScript di index.htm e può essere eliminato.

Inserimento:

httpRequest["/info.txt"]="info.txt";

Alle linee 16-19 della versione originale è stata aggiunta la linea (20 in web_serv.lua) che dichiara i file disponibili sul server.

l'inserimento della linea di codice sottostante dopo la (26 in web_serv.lua originale) dichiara in una intestazione il mimetype da fornire ai browser dei client per gestire le richieste ad Arduino di inviare i dati telemetrici.

Inserimento:

getContentType["/info.txt"]="text";

Infine sono state inserite:

dopo la linea 56 del di web_serv.lua originale

 [conn:on("sent",function(conn)]

Le seguenti linee:

conn:on("sent",function(conn)
-- Inserimento
_,_,nome,ext=string.find(requestFile, "(%w+).(%w+)"); 		
if ext=="txt" and nome=="info" then 
	conn:send("{\"V\": \""..uno_var.."\",");
	conn:send("\"K\": \""..due_var.."\"}");
else

la richiesta in Java script viene 'filtrata' e vengono inviate le due variabili popolate da arduino attraverso un comando impartito sulla connessione seriale, con identificatore V e K al client e mostrate su touch. Le due istruzioni numerate 5 e 6 sopra restituiscono al codice javascript la stringa in formato Json "{V:xxx,K:yyy}" che le seguenti istruzioni di index.htm mostrano sul display

  63	var A=JSON.parse(xhttp.responseText);
  64	document.getElementById("mis_uno").innerHTML = "V="+A.V;
  65	document.getElementById("mis_due").innerHTML = "K="+A.K;

Su Arduino l'istruzione per il popolamento delle variabili viene lanciato all'interno delle due funzioni Mis_1() e Mis_2()

 sprintf(_buffer1,  "uno_var=%s", S); 
 mySerial.println(_buffer1);
 sprintf(_buffer2,  "due_var=%s", S); 
 mySerial.println(_buffer2);

Le variazioni devono essere lette in parallelo con il codice JavaScript che le invoca e con il codice di Arduino che risponde alle richieste.

index.htm

In questo file le modifiche a quello originale sono più consistenti rispetto agli altri file web_ser.lua e int.lua. Chi è interessato al dettaglio può scaricarli e confrontarli.

In questa sede si dà per acquisita la parte relativa al codice html nella quale si sono inserite nuove linee con lo scopo di mostrare i campi e i pulsanti non presenti nell'originale.

Per illustrare le modifiche ad index.htm ci riferiremo alla sola parte in JavaScript che 'aziona' la telemetria.

// =========== Gestione Eventi Touch ======================
addEventListener('touchstart', function(e) {
	e.preventDefault();
	var touch = e.touches[0];
	var xhttp = new XMLHttpRequest();
	var posX = touch.pageX;
	var posY = touch.pageY-50;
	var url="";
	/* ===================================================
	 * Se premi il pulsante circolare Blue in alto
	 * Motori Fermi e Richiede, Riceve e Mostra misure telemetriche
	 * ====================================================*/
	if(	e.touches.length == 1 && posX > 110 && posX < 190 
		&& posY > 10 && posY < 100) {
		HL=200;HR=200;MR=127;ML=127;C=11;//C=11 Mostra

		// Invoca i parametri telemetrici da Arduino e li mostra
		url="info.txt?V=uno_var&K=due_var";
		loadDoc_UNO(url);

		// ==== Re-invia  i parametri ML=MR=127 azzerati ad Arduino 
		url="data.json?R="+MR+"&l="+ML+"&C="+C;
		loadDoc_ZERO(url);
		disegna(HL,HR);	
		mostra_speed(ML,MR);
	}

Le linee nuove inserite (in particolare dalla 13 alla 26) servono per gestire le richieste telemetriche. la condizione if si riferisce all'avvenuta pressione del Pulsante circolare BLU sul display:

 la riga 15 azzera le variabili per riposizionare TUTTO nella condizione iniziale.
 la riga 18 compone l'url che eseguirà la richiesta al Server di inviare i dati telemetrici.
 la riga 19 invoca la funzione loadDoc_UNO(url) che richiede/riceve i dati telemetrici 
 e li mostra sul display.
 le righe 22 .. 25 ripristinano le variabili motore, le inviano ad Arduino attraverso il Server 
 con la funzione loadDoc_ZERO(url), riposizionano le 'maniglie motori' e le mostrano.

le 4 funzioni invocate alle righe 19, 23, 24, 25 dovrebbero essere comprensibili ad una semplice lettura del codice JavaScript e per non 'tediare' non sono riportate qui nel loro dettaglio. Rispetto al JavaScript originale sono state modificate e adattate a queste funzioni anche altre parti del codice.

Il nuovo codice di Arduino

Anche questo codice (per ora si chiama RUSC_006) ha subito 'robuste' manipolazioni per adattarlo al circuito realizzato. In particolare è stato scomposto in diversi 'blocchi di funzioni'. Il main loop() seguente:

#define bat A0  // ADC Batteria
#define pot A1  // ADC Trimmer

int Sx=127;// Velocita' motori 127->V=0 255->V=Max 0->V=-Max 
int Dx=127;
int C=0;// Utile solo per i TEST

// variabili utili per manipolare i comandi
int command_name; 
int posi;

// La seriale aggiuntiva di comunicazione con ESP
// permette di usare Serial per i TEST
#include <SoftwareSerial.h>
SoftwareSerial mySerial(6, 7);     // RX, TX di Arduino

#define INPUT_SIZE 35            // Dim. buffer per invio e ricezione comandi
char input[INPUT_SIZE];          // Array di manipolazione delle stringhe seriali 
String inputString = "";         // Stringa che memorizza il comando inviato
boolean stringComplete = false;  // var logica di completamento Stringa

void setup() {
  Serial.begin(9600); 
  mySerial.begin(57600); 
  inputString.reserve(INPUT_SIZE);
  Serial.println("Start");
}
unsigned long time1,time2;

/* =======================
 * Tempo totale del ciclo di riconoscimento di una stringa 
 * di comando tipo 'move delle maniglie del display' 600us senza stampe.
 * Tempo totale di riconoscimento di comando tipo 'get' 
 * sulla telemetria impiega oltre 1 secondo
 *=======================*/
void loop() {
   if (mySerial.available()>0){ stacca();
   //  Serial.print("letta:");Serial.println(inputString);
   }
   /* ============================
    * Se il comando inviato inizia con R
    * lo legge e trascodifica le due Velocità
    * inviate dal server 
    ***********************************
    * Se il comando inizia con V si tratta
    * di una richiesta di misure  V=c1 e  K=c2
    *=========================*/
   if (stringComplete) {
     if(inputString[0]=='R')scan_get();
     if(inputString[0]=='V')scan_put();

     /* ==== qui sono disponibili i valori pwm per i motori====*/
     //Serial.print("Pwm_Sx:");Serial.print(Sx);
     //Serial.print(" Pwm_Dx:");Serial.println(Dx);
     inputString = "";
     stringComplete = false;
   }
}

Il codice del loop() dovrebbe essere sufficientemente commentato per una prima comprensione. In particolare si invoca, alla linea 37, la funzione stacca(), che realizza la funzione Serial.readBytes() di Arduino che legge tutta la stringa del comando ricevuto. Tale funzione è non presente nella libreria <SoftSerial.h>.

il main loop(), alle linee 49 e 50, invoca le funzioni sca_get() e scan_put() contenute nel blocco SCAN (qui non mostrato). Queste due funzioni si occupano rispettivamente, la prima, di analizzare e ricevere dal Server i valori PWM da inviare al driver motori; la seconda di analizzare e restituire le misure telemetriche invocando le funzioni Mis_1() e Mis_2() contenute nel blocco MISURE.

Di seguito il codice di stacca():

/*===================
 * acquisisce la stringa dalla seriale byte per byte
 *===================*/
void stacca() {
  while (mySerial.available()) {
    char inChar = (char)mySerial.read();
    if (inChar != '\n' && inChar != '\r')
    inputString += inChar;
    if (inChar =='\n') {
      stringComplete = true;
    } 
  }
}


Del blocco MISURE si mostrano solo la funzioni Mis_1() e Volt() che si ripetono in modo simile in Mis_2() e Kappa() che potrete analizzare nel codice completo:

void Mis_1(){
  /* =============================================
   * in c1 devi inserire la lettura, in questo caso
   * misura la tensione Batteria.
   * ===========================================*/
  float c1 =Volt();
  char _buffer1[INPUT_SIZE];
  char S[6];
  // trasformo prima in stringa
  dtostrf(c1, 5, 2, S);
  // poi invio su seriale
  sprintf(_buffer1,  "uno_var=%s", S); 
  mySerial.println(_buffer1);
  delay(500);
}


float Volt(){
   /* rapporto del partitore: Tensione massima misurabile 13.7Volt 
    * che corrisponde a (5Volt o 1023 digit) ai capi della resistenza da 4.7k */
   float R=13.70/1023.0;
   return (float)analogRead(bat)*R;
}

Il codice di Mis_1() fa uso di una stringa e un buffer e due trasformazioni dtostrf() ed sprintf(). La prima trasforma un numero decimale in una stringa la seconda compone il Buffer per la spedizione seriale. Forse si può rendere più efficiente ma sprintf() da sola funziona con interi ma non con float non ne conosco la ragione.

Volt() è una semplice lettura ADC dal partitore che ho costruito che dovrebbe fa corrispondere 13.7volt di input a 1023 ADC (5v sul partitore da 4.7k).

Conclusioni

TEL 02.png

ESP8266 Web server con telemetria
Interfaccia WiFi Finale

Come nella prima versione Ruschino WIFI, dopo il caricamento del Software e l'accensione, l'utilizzo è estremamente semplice: Si apre lo Smartphone o il Tablet scrivendo nel Browser l'indirizzo del Server di ESP8266 -> 192.168.4.1.


Dal display touch si possono modificare (ma anche leggere) le velocità del 'robottino' o le due variabili telemetriche gestite.


I valori visualizzati nell'immagine a fianco mostrano la tensione della batteria LiIon (due pacchi) e il valore di K attuale.