Utilizzando l’ethernet shield possiamo pilotare da remoto le uscite dell’Arduino
Continuiamo la serie di articolo per il controllo da remoto del nostro Arduino. Negli articoli precedenti abbiamo visto come sia semplice leggere lo stato dei pin digitali e come acquisire dei segnali con gli ingressi analogici della scheda.
Questo articolo vedrà di utilizzare il browser per inviare dei comandi alla board Arduino UNO, tramite protocollo http, per pilotare le uscite dei in digitali.
La prima operazione da decidere riguarda la scelta dei pin che intendiamo impiegare come uscite in questo esempio ho decido di configurare i pin2 e il pin3.
void setup() { //inizializza lo shield con il mac e l'ip Ethernet.begin(mac, ip); //inizializza l'oggetto server ArduinoServer.begin(); //definisco i pin6 e pin7 come ingressi pinMode(6, INPUT); pinMode(7, INPUT); //definisco i pin2 e pin3 come uscite pinMode(2, OUTPUT); pinMode(3, OUTPUT); }
Adesso dobbiamo capire come inviare via browser dei comandi all’Arduino. Questo è possibile utilizzando la barra degli indirizzi del browser, infatti inserendo del testo dopo l’indirizzo ip della board possiamo recuperarlo utilizzando la funzione read(). Per capire meglio, l’esempio seguente illustra le varie fasi:
inserisco, nel browser, l’indirizzo ip della board e del testo aggiuntivo:
http://10.192.1.251/testo_personalizzato
dopo aver premuto il tasto invio o il pulsante vai, il browser invierà alla board questa informazione:
GET /testo_personalizzato HTTP/1.0
I singoli byte letti dalla funzione read() vengono concatenati per ricostruire l’intera stringa http. Questo avviene creando un oggetto String e utilizzando l’istruzione di concatenamento +=
//Dichiaro un oggetto String String msg = ""; ... //leggo i byte disponibili //provenienti dal client Data_RX = pc_client.read(); //ricostruisco la stringa ricevuta concatenando i singoli byte msg += Data_RX; ...
Quando termino di leggere tutti i byte inviati dal browser, l’oggetto msg conterrà l’intero dato, così come inviato dal browser
GET /testo_personalizzato HTTP/1.0
utilizzando il metodo indexOf() dell’oggetto msg posso controllare se all’interno di questa stinga è presente un particolare teso, ad esempio per verificare la presente del testo HTTP dovrò scrivere
int occorrenza = msg.indexOf(“HTTP”);
il valore restituito rappresenta il numero di occorrenze trovate all’interno della stringa msg, in questo caso il testo HTTP è presente una sola volta quindi la variabile occorrenza conterrà il valore 1.
Di conseguenza per pilotare l’uscita pin2 al livello alto potremmo scrivere sulla barra dell’indirizzo del browser qualcosa del tipo
http://10.192.1.251/PIN2ON
in questo caso la stringa msg sarà uguale a
GET /PIN2ON HTTP/1.0
il metodo indexOf dovrà cercare la stringa PIN2ON e, in base al risultato, attivare o meno l’uscita dell’Arduino. Il codice seguente realizza quanto esposto
... //cerco all'interno della stringa il parametro che mi interessa cmd = msg.indexOf("LEDON"); if (cmd > 0) digitalWrite(2, HIGH); else digitalWrite(2, LOW); ...
Per chiarezza inserisco tutto il codice dello sketch :
/* Semplice Controllo remoto Settembre 2011 Marco Lai */ //Librerie impiegate per il progetto #include <SPI.h> #include <Ethernet.h> //Creao un array di byte per specificare il mac address byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //creo un array di byte per specificare l'indirizzo ip byte ip[] = {10, 192, 1, 251}; //modificate questo valore in base alla vostra rete char Data_RX; String msg = ""; int cmd = 0; //creao un oggetto server che rimane in ascolto sulla porta //specificata Server ArduinoServer(80); void setup() { //inizializza lo shield con il mac e l'ip Ethernet.begin(mac, ip); //inizializza l'oggetto server ArduinoServer.begin(); //definisco i pin2 e pin3 come uscite pinMode(2, OUTPUT); pinMode(3, OUTPUT); } void loop() { //IMPORTANTE pulisco la variabile msg msg = ""; Client pc_client = ArduinoServer.available(); //controllo se pc_client è true if (pc_client != false) { //controllo continuamente che il client sia connesso while (pc_client.connected()) { //Controllo se ci sono byte disponibili per la lettura if (pc_client.available()) { //leggo i byte disponibili //provenienti dal client Data_RX = pc_client.read(); //ricostruisco la stringa ricevuta concatenando i singoli byte msg += Data_RX; //Attendo che tutti i byte siano letti //quando Data_RX contiene il carattere //di nuova line capisco tutti i byte sono //stati letti if (Data_RX == '\n') { //cerco all'interno della stringa il parametro che mi interessa cmd = msg.indexOf("LEDON"); //Invio la risposta al client //invio lo status code pc_client.println("HTTP/1.1 200 OK"); //imposto il data type pc_client.println("Content-Type: text/html"); pc_client.println(); //invio codice html pc_client.print("<html><body>"); pc_client.print("<head>"); //questo codice html permette di eseguireil refresh automatico //della pagina html pc_client.print("<META HTTP-EQUIV='refresh' CONTENT='5; /'>"); pc_client.print("</head>"); //Piloto l'uscita e invio lo stato al browser if (cmd > 0) { digitalWrite(2, HIGH); pc_client.print("<p>PIN2 Attivo</p>"); } else { digitalWrite(2, LOW); pc_client.print("<p>PIN2 NON Attivo</p>"); } pc_client.print("</body></html>"); //aspetto 1 ms affinche la risposta giunga al browser del client delay(1); //esco dal ciclo while una volta completato l'invio della risposta break; } } } //chiudo la connessione pc_client.stop(); } }
Utilizzando questo metodo possiamo attivare le uscite dell’Arduino ma anche inviare altri comandi che ad esempio generano un segnale pwm piuttosto che inviare dati tramite la porta UART ad altri dispositivi; le possibilità sono tante e permettono un controllo remoto completo ed efficiente.
Related posts
24 Comments
Lascia un commento Annulla risposta
Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.
Articoli popolari
Sorry. No data so far.
.Net micro framework Arduino Arduino Webserver Domotica Flyport I2C IOT Netduino OpenPicus raspberry RTC Speed Test
Ciao Marco, per prima cosa volevo farti i complimenti perchè i tuoi post sono veramente utili e chiari. Leggendo questo utilissimo articolo mi è venuta voglia di metterlo in pratica ma ho riscontrato un problema che non riesco a risolvere: inviando la stringa http:/ ETHERNETSHIELD.I.P/LEDON dalla barra degli indirizzi del browser il led connesso al pin2 si accende ed immediatamente dopo si spegne. In un primo istante ho pensato al fatto che la pagina si aggiona automaticamente, ma il motivo non è questo perchè il led rimane acceso una frazione di secondo e il suo spegnimento non coincide con l’aggiornamento della pagina. Cosa ancora più strana è che la visualizzazione del testo “PIN2 Attivo” o “PIN2 NON Attivo” è corretta. Ecco, vorrei sapere se è già capitato a qualcuno e quale potrebbe essere la soluzione. Grazie
Ciao
Giuri
Ciao
è un comportamento alquanto strano :). Per risolvere il problema bisogna eseguire dei piccoli test per capire dov’è l’errore. Io procederei in questo modo
1- proverei a cambiare browser
2- aumenterei il refresh a 20 secondi o più
3- proverei a cambiare pin
4- utilizzerei serial.print per tracciare l’esecuzione del codice controllandolo con serial monitor
prova un po a fare questi passi e poi fammi sapere
grazie e a presto
Marco
Grazie per la risposta, ora il problema è stato risolto.
Ciao
Giuri
Figurati!
Ciao
Ciao,
trovo molto interessanti i tuoi articoli. Vorrei sapere come poter pilotare l’Arduino all’esterno della LAN, via internet. Puoi darmi qualche dritta?
Grazie,
Pasquale
Ciao Pasquale
Accedere da internet risulta abbastanza semplice, anche se i passi da eseguire sono diversi e potrebbero risultare difficoltosi, naturalmente spiegarlo in un commento risulta difficile, ma non ti preoccupare presto preparerò un articolo per trattare questo argomento.
In linea di principio bisogna rintracciare l’ip del tuo router, questo si fa con i servizi di dynamic dns (DDNS) come No-Ip o dyndns, una volta ottenuto un account ci sono due vie per leggere l’ip dinamico del tuo router, o tramite il router stesso che espone al suo interno di una sezione creata appositamente per lavorare con dyndns piuttosto che con np-ip, oppure tramite un applicazione client da installare su pc, in quest’ultimo caso per rintracciare l’ip il pc deve stare acceso.
Una volta capito come rintracciare l’ip devi collegare Arduino alla tua rete lan che funge ad esempio da webserver, ed in ultimo devi aprire la porta 80 per l’indirizzo ip dell’Arduino.
lo so scritto così è un po complicato, fammi sapere se ti serve altro
a presto
Marco
Ciao Marco,
ti scrivo ancora perchè spero con il tuo aiuto di realizzare un webserver con Arduino con le seguenti caratteristiche:
1. una o più pagine web memorizzate nella scheda microSD allocata nella Ethernet Shield, pagine semplici costruite con un editor esterno e non tramite l’inserimento del linguaggio html nello sketch di programmazione di Arduino, questo per rendere l’aspetto grafico un pò più articolato e carino/professionale,
2. per mezzo di queste pagine, possibilità di controllare/visualizzare stati di ingressi e uscite, valori analogici, comunicazioni seriali ecc… sempre mantenedo l’aspetto grafico di cui al punto 1.,
3. funzionalità di webserever, sempre disponibile su ip fisso in rete LAN locale e eventualmente in futuro accesso da remoto tramite internet come chiesto da Pasquale.
Scusami per la lunghezza del post, non so se sono stato chiaro e se tutto questo è fattibile, lo chiedo a te che sicuramente hai molta più esperienza di me…
Grazie
Giuri
Ciao Giuri
certamente, puoi realizzare tutto quello che hai scritto senza troppi problemi, devi solamente fare una buona progettazione e vedrai che non sarà difficile realizzare questo progetto.
Proverò a scrivere un articolo propedeutico per aiutarti in questo progetto
a presto
Marco
Ciao Marco,
non vedo l’ora di leggere il tuo articolo….
Ciao
Giuri
;)
Mi associo. Sto lavorando sul progetto TinyWebServer, ma avere un Tutorial in italiano porebbe essere risolutivo.
Per caricare dei files su Arduino (e/o sulla relativa SDCard) ho capito solo dopo un pò di rilettura delle istruzioni, che bisognava utilizzare un software nativo per linux (il programma Curl.exe) e attraverso un macchinosos sistema a riga di comando DOS-like, si può raggiungere il risultato di caricare i files.
In particolare vorrei utilizzare questo sistema (WebServer) per poter pilotare da remoto alcune apparecchiature che ho nella mia officina, e leggere alcuni ingressi analogici, come temperatura e presenza luce.
Ricapitolando: Web Server che attraverso una pagina HTML, e Web Browser, possa interagire con le operazioni di Arduino. La pagina dovrebbe risiedere su la SD per superare la limitazione della pochissima memoria dell’ATMega368.
E poi si può fare qualcosa in Java per ovviare alla pochezza dell’HTML, ed evitare l’uso di un bottone di tipo send per dover spedire le variazioni fatte sulla maschera?
Seguo con interesse lo sviluppo degli articoli dal primo della serie.
Grazie
Guido
Ok ok, mi state invogliando alla realizzazione di questo progetto… cercherò di trovare un po di tempo per pensare e realizzare qualcosina…
a presto
Marco
Sto provando a buttare una pagina di lieve complessità con la direttiva PROGMEM, ma ho difficoltà ad intercettare le azioni che metto in atto a pagina aperta.
Una pagina decentemente formattata dovrebbe risiedere su SD, ma ignoro come intercettare le azioni che eseguo sul Browser a pagina aperta.
L’ideale sarebbe intercettare due ingressi analogici (sensore temperatura e luce) ed intervenire sui valori ricevuti, più un paio di On/Off per pilotare luci e attuatori vari.
Se poi ci fosse un controllo PWM per triac da usare come dimmer per eventuale lampada alogena e/o creare scenari di luce, possiamo fare un Monumento a Marco! :D
Eventualmente il PWM l’ho già progettato: recupero i 100Hz dalla rete, li squadro e li infilo in un ingresso e poi attuo un ritardo su un breve impulso, rispetto al passaggio per lo zero, e questo impulsino a ritardo variabile (ritardato da un ingresso Analogico=potenziometro) e lo spedisco al gate del triac.
Ciao Marco, sono nuovo di questo mondo arduino :)
ho letto il tuo sketch sul controllo di arduino da browser,
non capisco una cosa.. (premessa non conosco nessun sistema di linguaggio)
ma come faccio ad inserire un secondo comando.. es.. led3 che possa accendere il led 3 ?
ciao grazie
ciao Marco…
nella pagina “chi sono” del tuo sito leggo che hai cominciato con visual Basic.
Ho un quesito da porti a riguardo.
Come faccio fare quello che descrivi in questo tutorial premendo un bottone programmato in visual Basic? Sono arrivato a scrivere questo codice ma il led non si accende,
Public Class Form1
Private Sub Button1_Click_1(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/PIN2ON”)
Sleep(1000)
End Sub
End Class
Dove ho sbagliato?
intanto ti ringrazio
…..Stefano
Ciao
prova a mettere il direttamente il controllo WebBrowser sul form e nel codice del Button inserisci semplicemente
wb.Navigate(“192.168.1.8/LEDON”);
ho provato con C# è funziona. Ora non ho installato VB e quindi non posso fare una prova specifica. Fai un test anche con un browser per vedere se non ci sono altri problemi o errori
Fammi sapere
a presto
Marco
ciao Marco.
Grazie al tuo aiuto ho risolto, ti riporto qui il codice:
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/PIN2ON”)
End Sub
End Class
Grazie mille!
Con questo inizio spero di riuscire a comandare un servomtore e un motore dc tramite un’ interfaccia fatta con visual basic
Ottimo
interfacciare l’hardware al pc on un software dedicato è una delle cose più interessanti che si possano fare con Arduino
Buon lavoro
Marco
ciao marco…
ho un problema che affligge…xd
ho modificato lo skatch qui presente per poter spegnere il led con il commando pin2off. Fin qui tutto ok con i sistemi operativi linux, mac e browser come safari chrome e firefox.
Il peblema sorge con windows xp e con tutti i browser che ti ho elencato. Il problema si presenta cosi:
accendo il led con il commando pin2on ma quando faccio per spegnerlo com il commando pin2off nn ne vuole sapere il led resta acceso, é come che si bloccasse sull prima istruzione.
Intanto ti ringrazio….ci sentiamo..
Ciao Stefano
dovresti postarmi il codice per capire dove sia il problema, ti consiglio di utilizzare la funzione Serial.print() da inserire in vari punti del codice per verificare dove sia il problema.
fammi sapere
Marco
Ciao Marco…
Ti dico già che ho eliminato la parte riguardante alla comunicazione dello stato al browser perchè per l’ uso che intendo fare non mi serve, in compenso ho aggiunto le librerie per i servomotore. Ho avuto modo di verificare se il problema che ti dicevo persisteva anche su un pc con installato windows 7 e in questo caso il problema non si presentava. Ho provveduto poi ha fare un programmino con visualbasic per il controllo remoto per vedere se tutto funzionava come vorrei e il risultato è stato ottimo. Controllo un motore dc e un servomotore senza problemi e il sistema risulta molto stabile. Ora ti posto qui il codice di Arduino:
/*
Semplice Controllo remoto
Settembre 2011
Marco Lai
*/
//Librerie impiegate per il progetto
#include
#include
#include
Servo myservo;
int pos = 90;
//Creao un array di byte per specificare il mac address
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//creo un array di byte per specificare l’indirizzo ip
byte ip[] = {192, 168, 1, 8}; //modificate questo valore in base alla vostra rete
char Data_RX;
String msg = “”;
int cmd = 0;
//creao un oggetto server che rimane in ascolto sulla porta
//specificata
EthernetServer ArduinoServer(80);
void setup()
{
//inizializza lo shield con il mac e l’ip
Ethernet.begin(mac, ip);
//inizializza l’oggetto server
ArduinoServer.begin();
//definisco i pin2 e pin3 come uscite
pinMode(2, OUTPUT);
myservo.attach (8);
}
void loop()
{
//IMPORTANTE pulisco la variabile msg
msg = “”;
EthernetClient pc_client = ArduinoServer.available();
//controllo se pc_client è true
if (pc_client != false)
{
//controllo continuamente che il client sia connesso
while (pc_client.connected())
{
//Controllo se ci sono byte disponibili per la lettura
if (pc_client.available())
{
//leggo i byte disponibili
//provenienti dal client
Data_RX = pc_client.read();
//ricostruisco la stringa ricevuta concatenando i singoli byte
msg += Data_RX;
//Attendo che tutti i byte siano letti
//quando Data_RX contiene il carattere
//di nuova line capisco tutti i byte sono
//stati letti
if (Data_RX == ‘\n’)
{
//cerco all’interno della stringa il parametro che mi interessa
cmd = msg.indexOf(“MOTOREON”);
if (cmd > 0)
{
digitalWrite(2, HIGH); }
cmd = msg.indexOf(“MOTOREOFF”);
if (cmd > 0)
{
digitalWrite(2, LOW); }
cmd = msg.indexOf(“SERVODX”);
if (cmd > 0)
{
pos= 180;}
cmd = msg.indexOf(“SERVOSX”);
if (cmd > 0)
{
pos= 0;}
cmd = msg.indexOf(“SERVOCX”);
if (cmd > 0)
{
pos= 90;}
myservo.write(pos);
delay (1);
//esco dal ciclo while una volta completato l’invio della risposta
}
}
}
}
}
Aggiungo che per correttezza, visto che mi hai aiutato, il codice che ho usato per visaulbasic. Dopo tante prove ho scoperto che il programma senza l’istruzione threading.thread.sleep non funziona. Ecco il codice:
Public Class Form1
Private Sub Button1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseDown
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/MOTOREON”)
Threading.Thread.Sleep(30)
wb.Stop()
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/SERVODX”)
Threading.Thread.Sleep(20)
wb.Stop()
End Sub
Private Sub Button1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Button1.MouseUp
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/MOTOREOFF”)
Threading.Thread.Sleep(20)
wb.Stop()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/SERVOSX”)
Threading.Thread.Sleep(20)
wb.Stop()
End Sub
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
Dim wb As New System.Windows.Forms.WebBrowser
wb.Navigate(“http://192.168.1.8/SERVOCX”)
Threading.Thread.Sleep(20)
wb.Stop()
End Sub
End Class
…..A PRESTO CI SENTIAMO
Ottimo lavoro!
ti ringrazio per il tuo contributo.
a presto
Marco
Non esistono altri modi per passare i dati?
Se voglio passare una stringa per esempio perchè devo visualizzare su un display una stringa come posso fare?
Grazie e complimenti!
Ciao
utilizzando la libreria standard puoi passare i parametri solo in questo modo. Potresti dare uno sguardo alle librerie di terze parti come Webduino (https://github.com/sirleech/Webduino) che implementa diversi metodi http come post e get.
grazie
Marco