Come realizzare un controllo remoto con Arduino basato su http
Il mondo è sempre più connesso, non solo le persone sono presenti su internet ma anche gli oggetti, tramite semplici circuiti, possono collegarsi alla rete, condividendo dati ed interagendo con l’ambiente, acquisendo grandezze fisiche (tramite sensori) o pilotando carichi utilizzando degli attuatori.
Controllare da remoto uno di questi dispositivi è una operazione affascinante sia per l’utilità di questa tecnica sia, perché no, far stupire i nostri amici accendendo una luce di casa tramite web!
Per chi è alle prime esperienze con Arduino, potrebbe pensare che la realizzazione di questo circuito possa essere complicato e costoso.
Fortunatamente il materiale necessario si riduce a una board Arduino UNO e all’Ethernet shield, più qualche componente esterno.
In questo articolo preferisco fare un piccolo accenno nel descrivere il funzionamento del sistema all’interno della rete lan.
Per il controllo remoto, bisogna eseguire alcune configurazioni aggiuntive che vedremmo successivamente.
Lo schema illustra il funzionamento del progetto:
I pc della rete e l’Arduino UNO (con ethernet shield) sono collegati tra loro tramite uno switch.
Il pc eseguirà, usando un browser, delle richieste http, per recuperare, ad esempio, il valore di una tensione applicata su un pin analogico, oppure accendere o spegnere un led, applicato su un pin digitale in uscita.
Colleghiamo la shield ethernet al nostro Arduino UNO, inseriamo un cavo lan dritto, (che dal connettore rg45 dello shield si collega ad una porta qualsiasi dello switch), inseriamo il cavo USB (che dall’Arduino UNO si collega alla porta del pc) e diamo alimentazione a tutto il sistema.
Apriamo l’IDE di Arduino e scriviamo questo codice:
//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}; //creo una variabile char per memorizzare i byte letti dal client char Data_RX; //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(); } void loop() { //fai qualcosa! delay(10); }
I commenti nel codice spiegano a grandi linee il funzionamento dello stesso. Dopo aver inserito le due librerie che permettono di interfacciarsi all’ethernet shield, definiamo due array di byte, uno che contiene l’indirizzo fisico della scheda di rete (MAC address) e l’altro che contiene l’indirizzo ip.
Successivamente ho creato un oggetto Server che permette di rimanere in ascolto sulla porta specificata, in questo caso la porta 80, proprio quella utilizzata dal protocollo http.
La variabile Data_RX verrà impiegata successivamente per memorizzare i byte provenienti dal client.
Dentro il blocco setup() ci sono due importanti funzioni, la prima (Ethernet.begin(mac, ip);) serve per inizializzare il chip WIZnet con l’indirizzo mac e l’indirizzo IP, la seconda (ArduinoServer.begin();) avvia il server e lo mette in ascolto sulla porta 80 per le avvenutali richieste dei client.
Nel blocco loop() ho inserito un ritardo di 10ms, per il momento non eseguiamo altro.
Questo codice è utile per verificare, tramite un semplice ping, se l’ethernet shield è correttamente configurata e se risponde alle interrogazioni dei client.
Apriamo una finestra dei prompt dei comandi (Start->Esegui->cmd.exe)
Digitiamo il comando ping seguito dall’indirizzo ip che abbiamo specificato nel codice dello skecth, nel mio caso:
ping 10.192.1.251
se i collegamenti sono corretti, e il codice viene caricato senza intoppi, otterremo la risposta della scheda come illustrato di seguito:
Questo semplice test ci permette di escludere problemi di alimentazione della board o errori doviti al cavo di collegamento.
Informazioni base su come configurare l’indirizzo ip
Certamente tutti voi sapete come configurare un indirizzo ip nella rete, ma penso sia necessario, per chi è alle prime armi, scrivere una piccola nota.
L’indirizzo ip identifica univocamente un dispositivo nella rete, probabilmente se utilizzate un router, questo assegnerà in modo automatico un indirizzo ad ogni dispositivo collegato (DHCP).
Per eseguire questi esperimenti dobbiamo disattivare il DHCP (sebbene sia possibile sfruttare questa funzione con Arduino ritengo, per semplicità, di non impiegarla) ed assegnare un indirizzo ip statico univoco ad ogni dispositivo della vostra rete.
Per fare ciò dovete andare nelle impostazioni del router e disattivare DHCP, poi per ogni pc della vostra rete, assegnate un indirizzo ip utilizzando le impostazioni della connessione di rete, tramite il pannello di controllo. Potete seguire questo link che mostra un video su come eseguire questa operazione
http://www.webip.info/cambiare_ip_windows_xp.php
Questo tutorial, invece, è per chi possiede Windows 7
Come Impostare un Indirizzo IP Statico su Windows
Ad esempio potremmo impostare il nostro pc con l’indirizzo 192.168.1.10 e la nostra Ethernet Shield con indirizzo 192.168.1.20
Come rispondere ai client
Una volta definiti gli indirizzi ip dei dispositivi della rete, possiamo iniziare a scrivere il codice che effettivamente risponde alle richieste dei client.
All’interno del blocco loop() bisogna creare un oggetto dalla classe Client, necessario ad ascoltare (listening) le richieste dei client.
L’idea di base è che il server aspetta la connessione di un client, controlla se ci sono dati da leggere e di conseguenza crea un oggetto Client.
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield Client pc_client = ArduinoServer.available();
La funzione ArduinoServer.available() non è bloccante quindi viene eseguita ciclicamente all’interno del blocco loop(), di conseguenza il valore restituito dalla funzione in mancanza di una richiesta client è false.
E’ necessario quindi controllare se l’oggetto pc_client istanziato sia diverso da false prima di poter instaurare la connessione.
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield Client pc_client = ArduinoServer.available(); //controllo se pc_client è true if (pc_client != false) { //se pc_client è true continuo ad utilizzarlo... }
All’interno del blocco if utilizzo un ciclo while per eseguire il codice necessario a scambiare dati tra client e server fintanto che la connessione con il client è attiva
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield Client pc_client = ArduinoServer.available(); //controllo se pc_client è diverso da false if (pc_client != false) { //controllo se il client è connesso while (pc_client.connected()) { //eseguo questo codice fintanto che il client è connesso... } }
Riassumendo, quando la connessione è stabilita, Arduino esegue il codice all’interno del blocco while, questa è la parte più interessante perchè possiamo leggere e scrivere dati attraverso il protocollo di comunicazione http.
Continuiamo controllando se effettivamente ci sono byte da leggere impiegando la funzione read() dell’oggetto pc_client:
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield 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(); } } }
Ora eseguiamo un semplice test per verificare che il codice sin qui scritto funzioni.
Per avere un riscontro utilizziamo la classe Serial per inviare informazioni di debug tramite Serial Monitor. Inizializziamo, tramite Serial.Begin(9600), la porta seriale nel blocco setup().
Adesso posso controllare il contenuto della variabile Data_RX inviandoli al Serial Monitor.
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield 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(); //invio i dati letti al Serial Monitor Serial.write(Data_RX); } } }
Apriamo Serial Monitor con il relativo pulsante
Avviamo il nostro browser preferito, su un pc nella rete dove è collegato l’Arduino con Ethernet shield, e nella barra degli indirizzi digitiamo l’ip assegnato via codice all’ethernet shield.
Il browser eseguirà una richiesta GET che sarà elaborata dall’Arduino e visualizzata sul serial monitor.
Ecco il risultato:
Anche in questo caso questo semplice test ci da la conferma che il codice appena scritto funziona egregiamente.
Continuiamo ad aggiungere il codice di risposta che l’Arduino invierà al browser che ha effettuato la richiesta GET
//Ascolto le richieste dei client controllo se ci sono dati da leggere //e creo un oggetto relativo a client che sta interrogando l'Ethernet shield Client pc_client = ArduinoServer.available(); //controllo se pc_client è true if (pc_client) { //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(); //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') { //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><h1>"); pc_client.print("Hello world Arduino Web Server</h1></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(); }
Verifico il valore di ogni byte letto, tramite l’istruzione if, fino a quando non ricevo un carattere di nuova linea \n (ox0A in esadecimale). Quando si verifica questa condizione la richiesta del client è stata letta completamente e quindi possiamo iniziare ad inviare la nostra risposta tramite la funzione println() dell’oggetto pc_client.
La prima stringa da inviare riguarda lo status code del protocollo http, composta dalla versione del protocollo http(HTTP/1.1) e dal codice 200 OK che specifica al client la corretta elaborazione dei dati.
La seconda stringa specifica il tipo di dati (http Content types) che stiamo inviando al client con il protocollo http.
Queste due stringhe costituiscono l’header della risposta http.
A questo punto inviamo la stringa con il codice html che compone la pagina che verrà inviata al browser sul client. Terminata anche questa operazione non ci resta che uscire dal blocco while con l’istruzione break, e terminare la chiusura della connessione con la funzione stop() per predisporci ad elaborare ulteriori richieste.
Nel prossimo articolo vedremmo come sfruttare gli ingressi analogici per acquisire dei segnali e i pin digitali per attivare dei led.
Related posts
23 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…bel sito qui ho trovato maggiori informazioni in italiano confronto ad altri siti.
Ho provato a seguire il tutorial qui proposto ma nn mi funziona. Tra pc e router uso una connessione con protocollo Wi-Fi, magari il problema e proprio quello e prima di comprare un altro cavo vorrei avere un tuo parere. Se dovesse essere cosi come si fa a collegare l’arduino con una connessione WI-FI? Intanto ti ringrazio…
Ciao Stefano,
mi fa piacere che il sito sia utile. Per prima cosa dovresti verificare che gli indirizzi ip dell’arduino siano compatibili con la tua rete. Hai provato a fare il ping per verificare se l’Arduino risponde? In una finestra del prompt dei comandi digita ipconfig e verifica il tuo indirizzo ip rispetto a quello settato sull’Arduino.
Prova e fammi sapere
a presto
Marco
Era proprio un problema di compatibilità di indirizzo ip con la mia rete. Quando ho letto, subito non sapevo cos’era poi santo google mi ha aiutato e il problema l’ho risolto, per cui anche oggi ho imparato una cosa nuova. Grazie mille Marco!!
Ottimo lavoro!
grazie a te della visita
a presto
Marco
Ciao Marco.
ho appena cominciato a praticare Arduino e quindi faccio errori ovunque sia possibile farli :-))))
ho acquistato un Arduino UNO R3 + ETH shield R3…..ho collegato il tutto e adesso sono pronto a sperimentare.Partendo da questo articolo ho copiato la prima parte di codice giusto per fare i ping sull’Arduino……peccato ke, copiando e incollando sul “programmatore” arduino 1.0 e avviando la verifica,mi da un sacco di errori …….che sono i seguenti:
Prova:14: error: no matching function for call to ‘Server::Server(int)’
As of Arduino 1.0, the Server class in the Ethernet library has been renamed to EthernetServer.
C:\Users\Alessandro\arduino-1.0\hardware\arduino\cores\arduino/Server.h:4: note: candidates are: Server::Server()
C:\Users\Alessandro\arduino-1.0\hardware\arduino\cores\arduino/Server.h:4: note: Server::Server(const Server&)
Prova:14: error: cannot declare variable ‘ArduinoServer’ to be of abstract type ‘Server’
C:\Users\Alessandro\arduino-1.0\hardware\arduino\cores\arduino/Server.h:4: note: because the following virtual functions are pure within ‘Server’:
C:\Users\Alessandro\arduino-1.0\hardware\arduino\cores\arduino/Print.h:48: note: virtual size_t Print::write(uint8_t)
C:\Users\Alessandro\arduino-1.0\hardware\arduino\cores\arduino/Server.h:6: note: virtual void Server::begin()
puoi aiutarmi?
PS: a tuo rischio e pericolo se mi aiuti, perkè se poi funziona ti tempesterò di domande in futuro ;-)))))))))))) GRAZIE!
Ciao Alessandro
quando ho scritto questo articolo, la versione dell’ide era la 0022. Successivamente è stata rilasciata la versione 1.0 che ha introdotto diverse novità ed aggiornamenti. Il codice che hai caricato non funziona semplicemente perchè alcune classi sono state rinominate, quindi in questo caso devi sostituire la classe Server in EthernetServer:
//creao un oggetto server che rimane in ascolto sulla porta
//specificata
Server ArduinoServer(80);
diventa:
//creao un oggetto server che rimane in ascolto sulla porta
//specificata
EthernetServer ArduinoServer(80);
Prova e fammi sapere
a presto
Marco
Grazie Marco,adesso funziona :-))) (se avessi studiato di più il C++ ci sarei arrivato).
appena posso attacco il tutto ad un router e provo ad accendere il famoso LED!!!!
adesso mi occuperò dell’elettronica che mi servirà per comandare i vari carichi connessi alle uscite di Arduino (Prese, luci, etc..)
PS:il mio progetto è quello di comandare in remoto più cose possibili.
a presto Marco, Buonagiornata!!!!! ;-)
Ottimo! Buon divertimento
Marco
ah,dimenticavo!
utilizzo Win 7 64-bit oppure in alternativa posso utilizzare ubuntu 32-bit tramite VirtualBox
Farti i complimenti è riduttivo.
Sei gandioso, l’accuratezza nella descrizione dei passaggi è impeccabile.
Non vedo l’ora che mi arrivi l’ethernet shield per giocarci su.
Complimenti ancora
Troppo buono!
cerco sempre di scrivere i tutorial come se fosse la prima volta che uso Arduino in modo da permettere, a chi è alle prime esperienze, di riuscire a realizzare il proprio progetto senza incorrere in errori che demotivano il proseguimento nello studio e nell’uso di Arduino o Netduino.
Grazie ancora della visita e del commento.
a presto
Marco Lai
ciao Marco,
ecco arrivata la mia Ehternet Shield,
Ecco realizzato un bell’apriporta remoto da web.
Grazie
Danilo
Sono soddisfazioni!
buon divertimento…
Marco
Ciao Marco,possiedo arduino uno con la ethernet shield,collegata a 5 relay con stadio pilota,riesco ad accendere e spegnere le luci tramite wifi con il mio telefono con android,ora mi piacerebbe usarlo anche in remoto.Ho visto l’altro tutorial,ma non riesco ad aggiungere gli altri relay al codice,ovvero aggiungere i pin 5,6,7,8,9 che sono gia’ collegati all’impianto elettrico…
Grazie ancora per i tuoi tutorial,ti seguo con piacere,Michele
Ciao Michele
scusami ma non ho capito perchè non riesci aggiungere gli altri pin, magari scivimi via mail con un po di codice cosi posso provare a darti una mano
ciao a presto
Marco
Ciao a tutti, allora espongo a brei linee cio’ che ho realizzato;
Tramite aurduino uno ethernet sto pilotando diversi relè tramite programma scritto in c#, postero’ il codice per tutti non preocupatevi :-) riesco benissimo a gestire tutto ora arriva il bello vorrei collegare agli ingressi analogici una sonda di temperatura e magari anche una di umidità mi chiedevo e cercavo di realizzare il codice in c# gestibile attaverso la rete lan per la lettura di questi e visualizzarli in una textBox, ho provato ma non riesco, in rete non si trovano aiuti validi per risolvere il problema. Riesco a leggere se il valore dell’ingresso è alto o basso ma non riesco a visualizzare la stringa per esempio temperatura xx. Marco potrei inviarti il codice in c# e il codice arduino per poter eseguire delle prove o magari condividere con tutti questo tutorial???? ti ho inviato tutto tramite email… grazie in anticipo.
E’ possibile utilizzare l’UDP per ricevere l’IP da un sever?
Ciao, stò facendo le prime prove con Arduino con scheda ethernet,ho provato un semplice programma per mandare un tweet a twitter, compilo il programma e tutto ok, ma quando lo mando in esecuzione mi dà questo errore: ardude:stk500_getsync():not in synk reso 0x00 il codice è il seguente:
#if defined(ARDUINO) && ARDUINO > 18
#include
#endif
#include
#include
byte mac[] = {indirizzo mac};
Twitter twitter(“token “);
char msg[] = “Hello, World! I’m Arduino!”;
void setup()
{
delay(1000);
Ethernet.begin(mac);
Serial.begin(9600);
Serial.println(“connecting …”);
if (twitter.post(msg)) {
int status = twitter.wait();
if (status == 200) {
Serial.println(“OK.”);
} else {
Serial.print(“failed : code “);
Serial.println(status);
}
} else {
Serial.println(“connection failed.”);
}
}
void loop()
{
}
prova a caricare lo sketch blink e dimmi se ottieni lo stesso errore, Nel codice che hai scritto inserisci nel blocco loop una istruzione di ritardo delay(10);
Ciao Marco, sto realizzando un progetto con arduino ed ethernet shield. Ho collegato un sensore di temperatura ed un sensore di luce, ho creato tramite la mia etharnet shield una piccola pagine web dove pubblico i valori dei sensori, vorrei cheal superamento di una certa temperatura l’arduino mi invii una mail di notifica. Ho trovato del del codice per inviare la mail gironzolando su google , ma no riesco ad integrarlo nel mio progetto. Cosa mi sapresti dire in merito? Grazie!! Grande lavoro continua così!!
ciao
la soluzione più veloce sarebbe quella di spedire i dati ad un servizio web che possa inviarti una mail, oppure potresti interagire con Pachube per memorizzare costantemente i valori letti da arduino. Potresti anche valutare l’uso di Twitter, esiste una libreria molto semplice che potresti usare
Grazie della visita
Marco
Ciao Marco, è da poco che ho scoperto Arduino ed il tuo sito mi sta aiutando moltissimo.
Sto seguendo questo tutorial e spero di fare cosa gradita e utile incollando il codice corretto dove ho dovuto cambiare alcune stringhe per adattarle alle nuove librerie.
/*
Semplice Controllo remoto
Agosto 2011
Marco Lai
*/
//Librerie impiegate per il progetto
#include
#include
//Creao un array di byte per specificare il mac address
byte mac[] = { 0x60, 0xb2, 0xcA, 0x2D, 0x72, 0x95 };
//creo un array di byte per specificare l’indirizzo ip
byte ip[] = {193, 168, 1, 00};
char Data_RX;
//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();
Serial.begin(9600);
}
void loop()
{
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();
//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’)
{
//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(“Hello world Arduino Web Server”);
//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();
}
}
ora il codice viene compilato correttamente ho dovuto cambiare
EthernetServer ArduinoServer(80);
come da te suggerito poco sopra e
EthernetClient pc_client = ArduinoServer.available();
però ho sempre un problema, arduino risponde alla chiamata e mi stampa hello world ma sul monito seriale
non vedo alcuna risposta, il baud è giusto e la com è quella con cui programmo l’arduino….. intanto proseguo
Ciao
grazie delle modifiche! Sul serial monitor non vedi nulla perchè dovresti utilizzare il commando Serial.print per spedire i dati tramite la porta seriale
a presto
Marco