Yùn Rover

Ciao a tutti!

Ho costruito un Rover che comando con Arduino via WiFi; vi spiego meglio il funzionamento in breve:

Il rover è dotato di 4 motorini elettrici con annessi motoriduttori; per controllarne velocità e direzione utilizzo un L298N (per chi non lo conoscesse, guardate pure qui). Inutile dire che ho dotato il Rover di sensori per praticamente qualsiasi cosa :grinning: Quanto al pilotaggio, ho optato per l'acquisto di un router di piccolissime dimensioni, il WR-703N di Tp-Link, del tutto simile al 702, eccolo qui. Perché il WR703, vi chiedete? Beh, perché con una leggera abilità in saldature è possibile dotarlo di antenna WiFi esterna, in modo che sia possibile avere una maggiore portata. Ho quindi connesso la ethernet shield del mio Arduino al router, tramite apposito cavo Lan e controllo il Rover con una semplicissima pagina web all'interno dello sketch con un pò di html e css, sfruttando dei pulsanti che ho disposto a mò di joystick (quindi avanti, indietro, destra, sinistra, luci, ecc...).

Ecco, dunque, il problema di questo ecosistema perfetto :P :

ogni volta che clicco su un pulsante per inviare al rover una direzione da seguire, ciò che succede è che viene inviata una stringa di questo tipo: 192.168.0.xxx/avanti che mi causa due grossi problemi, ovvero:

  • la pagina web viene inevitabilmente ricaricata (perdita inutile di tempo)
  • ricaricando la pagina web, ho dovuto per forza immettere all'interno dello sketch un controllo del movimento basato sul tempo. Mi spiego meglio: quando premo avanti il Rover va avanti per 5 secondi, schifezza assoluta. :'(

Ora, cari amici, vengo al punto: esiste un modo per evitare tutto sto casino, senza ricorrere ad un software o una app?

Vorrei cioè che una volta premuto il pulsante "avanti" dalla pagina web, Arduino ricevesse il comando senza la necessità di dover ricaricare l'intera pagina. Un ulteriore passo in avanti sarebbe compiuto se, mantenendo premuto il pulsante (non ho la più pallida idea di come farlo) il rover andasse avanti e, una volta rilasciato, si fermasse.

Grazie a tutti coloro che vorranno aiutarmi.

Buona Giornata!

P.S: se avete bisogno di sketch, foto, schemi elettrici o altro, non esitate a farmelo sapere ;)

Ciao, x evitare di ricaricare tutta la pagina ma solo una piccola parte devi usare ajax. http://www.w3schools.com/ajax/

e poi giocare con i "eventi" tipo onmousedown, onmouseover ecc... http://www.w3schools.com/jsref/dom_obj_event.asp

Ciao Andrea,

grazie per la risposta velocissima (scusami invece se rispondo solo ora…). Ho provato a fare come dici ma non riesco proprio a capire (non avendo mai avuto a che fare con ajax o comunque molto poco) come far ricevere ad arduino un comando, nel momento in cui premo e mantengo premuto un tasto della mia pagina web. Provo a caricare lo sketch e la pagina web per cercare di essere un attimino più specifico.

EDIT: vorrei provare a far funzionare questo sistema su Arduino Yùn, dato che ce l’ho e non ho ancora mai avuto occasione di poterlo utilizzare. Usando Yùn potrei avere dei vantaggi, in quanto:

  • E’ già dotato di modulo WiFi, quindi non servirebbe più il nano router che attualmente uso sul rover
  • Essendo dotato di porta ethernet, configurandolo come Master, cioè come Access Point, teoricamente dovrei essere in grado di attaccargli via cavo Ethernet una IpCam (tipo questa) e vederla sulla mia pagina web.

Ma devo gestire bene la memoria, onde evitare di saturarla (anche se sono ben lontano dal farlo con lo sketch attuale).

*** PAGINA WEB - generata dallo sketch presente sul microcontrollore ***

<html>
 <head>
 <meta name="viewport" content="width=device-width">
 <style>
 table {
    border-collapse: collapse;
 }
 
 table, td {
    border: 1px solid black;
    text-align: center;
    vertical-align: center;
 }
 
 .butt {
   border: 1px outset black;
   background-color: lightGrey;
   height:50px;
   width:50px;
   cursor:pointer;
 }
 
 .butt:hover {
   background-color: blue;
   color:white;
 }
 
 body {
    background-color: #00979C;
 }
 
 </style>
 </head>

 <body style='margin: 0px; padding: 0px; height: 100%; width: 100%;'>
 <table width=100% height=100%>
 <tr>
 <td height=10% colspan=3>Online Rover Control System &copy</td>
 </tr>
 <tr>
        <td width=60%>CAM</td>
        <td width=40%>
 <input class=butt type=button name=su value=&#8593>


 <input class=butt type=button name=sx value=&#8592>&nbsp;&nbsp;&nbsp;
 <input class=butt type=button name=stop value=&#9679>&nbsp;&nbsp;&nbsp;
 <input class=butt type=button name=dx value=&#8594>


 <input class=butt type=button name=giu value=&#8595>
        </td>
    </tr>
 </table>
 </body> 
</html>

*** SKETCH DI CONTROLLO (solo motori, niente sensori, niente webpage, versione base) ***

#include <String.h>
#include <SPI.h>
#include <Ethernet.h>

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; 
byte ip[] = { 192,168,0,170}; 
byte gateway[] = { 192,168,0,1};
byte subnet[] = { 255, 255, 255, 0 };
EthernetServer server(80); 

String clientMsg ="";
int stato;

void setup(){
Ethernet.begin(mac, ip, gateway, subnet);
pinMode(42,OUTPUT); //MOTORE POST DESTRO AV
pinMode(43,OUTPUT); //MOTORE POST DESTRO IND
pinMode(44,OUTPUT); //MOTORE POST SINISTRO AV
pinMode(45,OUTPUT); //MOTORE POST SINISTRO IND
pinMode(46,OUTPUT);  //MOTORE ANT DESTRO AV
pinMode(47,OUTPUT);  //MOTORE ANT DESTRO IND
pinMode(48,OUTPUT);  //MOTORE ANT SIN AV
pinMode(49,OUTPUT); //MOTORE ANT SIN IND

pinMode(7,OUTPUT); // FARI

server.begin();
}
 
void loop(){
      
EthernetClient client = server.available();
if (client) {
  boolean currentLineIsBlank = true;
  while (client.connected()) {
    if (client.available()) {
      
      char stato = client.read();
 
        switch (stato){
          
        case '1':
        digitalWrite(42,200);
        digitalWrite(44,200);
        digitalWrite(47,200);
        digitalWrite(48,200);
        digitalWrite(43,LOW);
        digitalWrite(45,LOW);
        digitalWrite(46,LOW);
        digitalWrite(49,LOW);
        break;
        
        case '2':
        analogWrite(43,200);
        analogWrite(45,200);
        analogWrite(46,200);
        analogWrite(49,200);
        digitalWrite(42,LOW);
        digitalWrite(44,LOW);
        digitalWrite(47,LOW);
        digitalWrite(48,LOW);
        break;
        
        case '3':   
          //DESTRA
        analogWrite(43,150);
        analogWrite(44,150);
        analogWrite(46,150);
        analogWrite(48,150);
        digitalWrite(42,LOW);
        digitalWrite(45,LOW);
        digitalWrite(47,LOW);
        digitalWrite(49,LOW);
        break;
        
        
      
        case '4':   
       //SINISTRA   
        analogWrite(42,150);
        analogWrite(45,150);
        analogWrite(47,150);
        analogWrite(49,150);
        digitalWrite(43,LOW);
        digitalWrite(44,LOW);
        digitalWrite(46,LOW);
        digitalWrite(48,LOW);
        break;
        
        case '5': //LUCI ON             
        digitalWrite(7,HIGH);
        break;
        
        case '6':
           //STOP
        digitalWrite(42,LOW);
        digitalWrite(43,LOW);
        digitalWrite(44,LOW);
        digitalWrite(45,LOW);
        digitalWrite(46,LOW);
        digitalWrite(47,LOW);
        digitalWrite(48,LOW);
        digitalWrite(49,LOW);    
        break;
        
        case '7': //LUCI OFF  
        digitalWrite(7,LOW);        
        break;
        
        }

    }} 
  } 
}

Riepilogo brevemente il risultato che vorrei ottenere:

Collegandomi all’ip di Arduino via pc mi viene mostrata la pagina web, cliccando e tenendo premuto (ad es.) il pulsante avanti vorrei che il rover continuasse ad andare avanti finché non rilascio il tasto del mouse e, di conseguenza, il pulsante della pagina web stessa; a quel punto la pagina invia al rover il comando di stop e quindi lui si ferma. Ma non riesco ad ottenere questo risultato, pur avendo provato più e più volte con js e ajax non capisco come far arrivare i vari comandi ad Arduino, evitando di ricaricare la pagina ogni volta.

Mi bastano anche solo due righe di codice d’esempio di come deve essere configurato il pulsante sulla pagina web e come deve essere impostato lo sketch per ricevere la stringa annessa al pulsante.

Ringrazio ancora una volta coloro che vorranno aiutarmi :slight_smile:

Mancano gli script js ... la pagina web è molto più complessa di quella che hai fatto e occupa molta ram inoltre vanno richiamate le librerie js dal sito jquery.com, per ultimo un compressore html

Che modello di arduino hai?

su una UNO non riuscirai a farlo con 32k di ram

Pardon… ho caricato la versione errata :sweat_smile:

Eccola qua:

<html>
	<head>
		<meta name="viewport" content="width=device-width">
		<style>
			table {
			    border-collapse: collapse;
			}
			
			table, td {
			    border: 1px solid black;
			    text-align: center;
			    vertical-align: center;
			}
			
			.butt {
			   border: 1px outset black;
			   background-color: lightGrey;
			   height:50px;
			   width:50px;
			   cursor:pointer;
			}
			
			body {
			    background-color: #00979C;
			}
			
		</style>
		
		<script>
			function down(obj) {
			    obj.style.backgroundColor = "#1ec5e5";
			}
			
			function up(obj) {
			    obj.style.backgroundColor="#D94A38";
			}
			</script>
		
	</head>

	<body style='margin: 0px; padding: 0px; height: 100%; width: 100%;'>
		<table width=100% height=100%>
			<tr>
				<td height=10% colspan=3>Online Rover Control System &copy</td>
			</tr>
			<tr>
		        <td width=60%>CAM</td>
		        <td width=40%>
					<input onmousedown="down(this)" onmouseup="up(this)" class=butt type=button name=su value=&#8593>


					<input onmousedown="down(this)" onmouseup="up(this)" class=butt type=button name=sx value=&#8592>&nbsp;&nbsp;&nbsp;
					<input onmousedown="down(this)" onmouseup="up(this)" class=butt type=button name=stop value=&#9679>&nbsp;&nbsp;&nbsp;
					<input onmousedown="down(this)" onmouseup="up(this)" class=butt type=button name=dx value=&#8594>


					<input onmousedown="down(this)" onmouseup="up(this)" class=butt type=button name=giu value=&#8595>
		        </td>
		    </tr>
		</table>
	</body>	
</html>

Ma il punto è che:

  • non riesco a capire come fargli aprire in background una pagina tipo: www.miosito.it/avanti per inviargli la stringa via HTTP GET
  • non riesco a capire -eventualmente- quali istruzioni devo inserire sullo sketch per fargliela ricevere

Utilizzerei Arduino Yùn, sembra esserci ancora più del 50% di memoria libera con questo sketch, dovrei farcela :slight_smile:

Grazie!

Ciao Gabry,

nelle due funzioni up e down devi usare l'oggetto XMLHTTPRequest per inviare la segnalazione dell'evento ad arduino. Anche se si chiama XML.... non sei obbligato a fare richieste xml, puoi mandare praticamente ogni cosa. Qui trovi un tutorial su come usarlo http://www.w3schools.com/xml/xml_http.asp

Bye, Ste

Ciao Ste!

Grazie per la risposta. Ho provato come dici tu e, a primo impatto, visualizzando la console di JS mi sembra stia funzionando. Posto il codice della pagina per permettere a te e agli altri di analizzare eventuali problemi:

<html>
	<head>
		<meta name="viewport" content="width=device-width">
		<style>
			table {
			    border-collapse: collapse;
			}
			
			table, td {
			    border: 1px solid black;
			    text-align: center;
			    vertical-align: center;
			}
			
			.butt {
			   border: 1px outset black;
			   background-color: lightGrey;
			   height:50px;
			   width:50px;
			   cursor:pointer;
			}
			
			body {
			    background-color: #00979C;
			}
			
		</style>
		
		<script>
			function down(obj) {
			    obj.style.backgroundColor = "#1ec5e5";
			}
			
			function up(obj) {
			    obj.style.backgroundColor="#D94A38";
			}
			
			var myRequest = null;

			function CreateXmlHttpReq(handler) {
			  var xmlhttp = null;
			  xmlhttp = new XMLHttpRequest();
			  xmlhttp.onreadystatechange = handler;
			  return xmlhttp;
			}
			
			function myHandler() {
			    if (myRequest.readyState == 4 && myRequest.status == 200) {
			        alert(myRequest.responseText);
			    }
			}
			
			function su() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","avanti");
			    myRequest.send(null);
			}
			
			function giu() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","indietro");
			    myRequest.send(null);
			}
			
			function dx() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","destra");
			    myRequest.send(null);
			}
			
			function sx() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","sinistra");
			    myRequest.send(null);
			}
			
			function stop() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","stop");
			    myRequest.send(null);
			}
			</script>
		
	</head>

	<body style='margin: 0px; padding: 0px; height: 100%; width: 100%;'>
		<table width=100% height=100%>
			<tr>
				<td height=10% colspan=3>Online Rover Control System &copy</td>
			</tr>
			<tr>
		        <td width=60%>CAM</td>
		        <td width=40%>
					<input onmousedown="down(this);su();" onmouseup="up(this);stop();" class=butt type=button name=su value=&#8593>


					<input onmousedown="down(this);sx();" onmouseup="up(this);stop();" class=butt type=button name=sx value=&#8592>&nbsp;&nbsp;&nbsp;
					<input onmousedown="down(this);stop();" onmouseup="up(this)" class=butt type=button name=stop value=&#9679>&nbsp;&nbsp;&nbsp;
					<input onmousedown="down(this);dx();" onmouseup="up(this);stop();" class=butt type=button name=dx value=&#8594>


					<input onmousedown="down(this);giu();" onmouseup="up(this);stop();" class=butt type=button name=giu value=&#8595>
		        </td>
		    </tr>
		</table>
	</body>	
</html>

Di seguito, invece, lo screen della console errori di JavaScript (che diamine sono tutte quelle scritte rosso inferno??? :fearful: )

Mi sembra che gli URL comunque li apra… Ma c’è possibilità di attivare i tasti “virtuali” con i tasti reali della tastiera?

Grazie

Utilizzerei Arduino Yùn, sembra esserci ancora più del 50% di memoria libera con questo sketch, dovrei farcela

bene hai una yun, disponi di un processore a 400Mhz RAM 64 MB DDR2 Flash Memory 16 MB

puoi caricare un webserver php direttamente sul processore Atheros AR9331 con le specifiche sopradescritte o magari non ho capito io cosa stai facendo ..... per un attimo mi era parso che il serverino lo stessi creando dentro allo sketch come sugli avr 328 o 2560 :)

Ciao Gabry,

non c'è lo screenshot ma a naso dovrebbero essere errori http (404) sulle chiamate ajax.

Bye, Ste

Ilste:
Ciao Gabry,

non c’è lo screenshot ma a naso dovrebbero essere errori http (404) sulle chiamate ajax.

Bye, Ste

Ciao Ilste, hai ragione, nessun errore, semplici alert relativi a errori http sulle chiamate Ajax, grazie!

Sto cercando di far funzionare lo sketch di controllo (quello postato all’inizio del topic) su Arduino Yùn ma niente da fare. Qualche buon’anima potrebbe spiegarmi in che modo va modificato per poter essere adattato al funzionamento su Yùn? Mi basta anche solo un pezzettino di codice che lo predisponga alla ricezione di stringhe a fine url, tipo: http://iparduino/avanti e capisca che quando gli arriva il comando avanti (dalla mia pagina web che si trova sulla sd) va eseguito tutto ciò che si trova all’interno del rispettivo case nello sketch (e quindi tutte le digitalWrite che azionano i motori)

Vi ringrazio in anticipo per l’aiuto.

Posto la nuova pagina web (aggiornata con controllo js sui tasti freccia della tastiera + adattamento automatico con viewport in portrait e landscape):

<!-- WIFI ROVER Control WebPage by Gabriele Piccione -->

<html>
	<head>
		<meta name="viewport" content="width=device-width">
		<style>
			
			table, td {
			    border: 1px solid black;
			    border-collapse: collapse;
			    text-align: center;
			}
			
			.butt {
			   border: 1px outset black;
			   background-color: lightGrey;
			   height:50px;
			   width:50px;
			}
			
			body {
			    background-color: #FFFFF;
			}
			
		</style>
		
		<script>
			
			var fired = false;
			
			document.onkeydown = function(e){
				if(!fired){
					fired=true;
				    e = e || window.event;
				    var key = e.which || e.keyCode;
				    if(key===37){
				        sx();
				    }
				    if(key===38){
				        su();
				    }
				    if(key===39){
				        dx();
				    }
				    if(key===40){
				        giu();
					}
				}
			}
			
			document.onkeyup = function(e){
				fired = false;
			    e = e || window.event;
			    var key = e.which || e.keyCode;
			    if(key===37){
			        stop();
			    }
			    if(key===38){
			        stop();
			    }
			    if(key===39){
			        stop();
			    }
			    if(key===40){
			        stop();
			    }
			}
			
			var myRequest = null;

			function CreateXmlHttpReq(handler) {
			  var xmlhttp = null;
			  xmlhttp = new XMLHttpRequest();
			  xmlhttp.onreadystatechange = handler;
			  return xmlhttp;
			}
			
			function myHandler() {
			    if (myRequest.readyState == 4 && myRequest.status == 200) {
			        alert(myRequest.responseText);
			    }
			}
			
			function su() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","avanti");
			    myRequest.send(null);
			}
			
			function giu() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","indietro");
			    myRequest.send(null);
			}
			
			function dx() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","destra");
			    myRequest.send(null);
			}
			
			function sx() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","sinistra");
			    myRequest.send(null);
			}
			
			function stop() {
			    myRequest = CreateXmlHttpReq(myHandler);
			    myRequest.open("GET","stop");
			    myRequest.send(null);
			}
			</script>
		
	</head>

	<body style='margin: 0px; padding: 0px; height: 100%; width: 100%;'>
		<table width=100% height=100%>
			<tr>
				<td bgcolor=#00979C height=10% colspan=2 valign="middle"><img src='http://forum.arduino.cc/Themes/default/images/logo_w_100.png' width=58 height=40></td>
			</tr>
			<tr>
		        <td height=60%>CAM</td>
		    </tr>
		    <tr>
		        <td height=30%>
					<input onmousedown="su();" onmouseup="stop();" class=butt type=button name=su value=&#8593>


					<input onmousedown="sx();" onmouseup="stop();" class=butt type=button name=sx value=&#8592>&nbsp;&nbsp;&nbsp;
					<input onmousedown="giu();" onmouseup="stop();" class=butt type=button name=giu value=&#8595>&nbsp;&nbsp;&nbsp;
					<input onmousedown="dx();" onmouseup="stop();" class=butt type=button name=dx value=&#8594>


		        </td>
		    </tr>
		</table>
	</body>	
</html>

Trovate, invece, lo sketch a inizio topic.

Ciao ragazzi,

ho provato a scrivere il codice che mi servirebbe per far funzionare il sistema di cui ho parlato ampiamente :smiley: sopra, lo posto di seguito, nella speranza che qualcuno mi sappia dire cosa sbaglio:

#include <Bridge.h>
#include <YunServer.h>
#include <YunClient.h>

// L298N Pin ad Arduino
// motori lato dx
int enA = 5;
int in1 = 6;
int in2 = 7;

// motori lato sx
int enB = 10;
int in3 = 12;
int in4 = 11;

// Listen on default port 5555, the webserver on the Yun
// will forward there all the HTTP requests for us.
YunServer server;

void setup() {
  
  // set all the motor control pins to outputs
  pinMode(enA, OUTPUT);
  pinMode(enB, OUTPUT);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  
  Serial.begin(9600);

  // Bridge startup
  pinMode(13,OUTPUT);
  Bridge.begin();

  // Listen for incoming connection only from localhost
  // (no one from the external network could connect)
  server.listenOnLocalhost();
  server.begin();
}

void avanti()
{
  digitalWrite(in1, HIGH);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, HIGH);
  digitalWrite(in4, LOW);
  analogWrite(enA, 150);
  analogWrite(enB, 150); 
}

void indietro()
{
  digitalWrite(in1, LOW);
  digitalWrite(in2, HIGH);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, HIGH);
  analogWrite(enA, 150);
  analogWrite(enB, 150);
}

void destra()
{
  digitalWrite(in1, HIGH);
  digitalWrite(in2, HIGH);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  analogWrite(enA, 150);
  analogWrite(enB, 150);
}

void sinistra()
{
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, HIGH);
  digitalWrite(in4, HIGH);
  analogWrite(enA, 150);
  analogWrite(enB, 150);
}

void fermo()
{
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);  
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  //luci posizione effetto frenata
  analogWrite(9,100);
  delay(1000);
  analogWrite(9,255);  
}

void loop() {
  // Get clients coming from server
  YunClient client = server.accept();

  // There is a new client?
  if (client) {

    String command = client.readStringUntil('/');

      int stato = client.parseInt();

      switch(stato){       
        case 'avanti': avanti(); break;
        case 'indietro': indietro(); break;
        case 'destra': destra(); break;
        case 'sinistra': sinistra(); break;
        case 'stop': fermo(); break;
        case 'lucion': digitalWrite(8,HIGH); break;
        case 'lucioff': digitalWrite(8,LOW); break;
        default: fermo(); 
      }

    // Close connection and free resources.
    client.stop();
  }

  delay(50); // Poll every 50ms
}

N.B: mi da errore sulla linea 108 e 109, cioè nei case ‘destra’ e ‘sinistra’. Ho notato che sembra essere colpa della parte finale uguale delle due parole. Come posso fixare? :cold_sweat:

rover_fin.ino:109:9: error: duplicate case value
rover_fin.ino:108:9: error: previously used here

Come faccio a farlo funzionare per il mio rover?

Grazie ancora! :wink:

Non riesco proprio a pilotare il rover con Yùn, qualcuno può aiutarmi? :'(

Grazie