Collegare due arduino in rete LAN

Ciao a tutti, possiedo due arduino mega 2560 e due ethernet shield w5100 e una board con 8 relè simile a questa:

Premetto che non sono un programmatore.

Questo quello che vorrei fare:

  • disporre all'interno dell'abitazione il primo arduino provvisto di shield w5100 e collegarci tre pulsanti (apertura cancello scorrevole, blocco cancello scorrevole, apertura elettroserratura cancelletto)

  • disporre all'esterno dell'abitazione il secondo arduino (munito anche lui di shield ethernet w5100), a questo collegherò la board con i relè che verranno a loro volta collegati con i relè propri del cancello e cancelletto.

-collegare i due arduino mediante rete LAN adibita esclusivamente all'uso di arduino tramite un router di riciclo.

In pratica vorrei che quando si premessero dei pulsanti dall'abitazione, l'arduino interno mandasse l'input all'arduino esterno e che quest'ultimo comandasse in uscita i relativi relè.

Ho visto che probabilmente ciò di cui avrei bisogno è del protocollo tcp/ip e quindi implementare una connessione client/server purtroppo però non riesco a venirne a capo, cioè non riesco a capire come passare gli input del primo arduino (client) al secondo (server).

Questo è un esempio del funzionamento su singolo arduino di quello che voglio fare:

int rele = 35;
int pulsante = 33;

void setup(){
 pinMode(rele,OUTPUT);
 pinMode(pulsante,INPUT);
 digitalWrite(pulsante,HIGH);
}
void loop() {
 int valor = digitalRead(pulsante);
 if (valor == LOW) {
 digitalWrite(rele, LOW);
 }
 else {
 digitalWrite(rele,HIGH);
 }
}

Qualcuno mi può spiegare esattamente come fare, ho visto che sul web è pieno di esempi ma non riesco ad interpretarli. L'unica cosa che sono riuscito a fare è mettere in comunicazione i due arduino facendogli prendere i relativi IP ma null'altro.

Vi ringrazio anticipatamente.

Mi dispiace di non starle spiegando esattamente cosa fare data l'ora, ma bisognerebbe eseguire un server sull'arduino all'esterno e un client sull'arduino all'interno che manda le richieste all'arduino all'esterno.
Se hai l'Arduino cookbook la ricetta che interessa a te per fare il server è esattamente la multipage webserver, cap 15 se non ricordo male.
Per il client(Arduino interno) basta aggiungere al codice sotto i digitalRead sui pin e la diversa bagina da richiedere in base al pulsante premuto.

/*
  Web client

 This sketch connects to a website (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 18 Dec 2009
 by David A. Mellis
 modified 9 Apr 2012
 by Tom Igoe, based on work by Adrian McEwen

 */

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

// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128);  // numeric IP for Google (no DNS)
char server[] = "www.google.com";    // name address for Google (using DNS)

// Set the static IP address to use if the DHCP fails to assign
IPAddress ip(192, 168, 0, 177);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // start the Ethernet connection:
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // try to congifure using IP address instead of DHCP:
    Ethernet.begin(mac, ip);
  }
  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 80)) {
    Serial.println("connected");
    // Make a HTTP request:
    client.println("GET /search?q=arduino HTTP/1.1");
    client.println("Host: www.google.com");
    client.println("Connection: close");
    client.println();
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}

Bisognerebbe che lei si spiegasse meglio su cosa non è riuscito a fare ( ha già provato con la configurazione a IP statico, non ha ancora fatto lo sketch Ethernet…)
Buona giornata,
Eugenio

eutampieri:
Bisognerebbe che lei si spiegasse meglio su cosa non è riuscito a fare ( ha già provato con la configurazione a IP statico, non ha ancora fatto lo sketch Ethernet…)
Buona giornata,
Eugenio

Grazie mille per il chiarimento. In effetti quello che ho visto sul web sono proprio esempi che si trovano sul book di arduino, solo un pò modificati.

Per quanto riguarda gli sketch della parte client e server glieli riporto qui sotto:

Sketch arduino server:

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

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEE };
 
EthernetServer ArduinoServer(4665); //creo un oggetto server con porta 4665 in ascolto

int rele1 = 35;
char Data_RX;

void setup()
{ 
  // Imposto una connessione seriale per verificare i dati
  Serial.begin(9600);

  pinMode(rele1,OUTPUT); //imposto il pin digitale del rele1 come OUTPUT
  // Connessione Ethernet usando MAC e DHCP (IP dinamico)
  Ethernet.begin(mac);
  
  ArduinoServer.begin();

  // Diamo alla Ethernet shield un secondo per inizializzarsi
  delay(1000); 
}

void loop() {
  
  EthernetClient client1 = ArduinoServer.available();
  if (client1 != false){
    while (client1.connected()) {
      Data_RX = client1.read();
      Serial.write(Data_RX);
      }
    }
  delay(10);
   
  }

Sketch arduino client:

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


byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte server[] = { 192,168,0,220 };
int wait = 1000;

EthernetClient client1; // Imposto Arduino1 come client

int pulsante1 = 33;

void setup()
{

  pinMode(pulsante1, INPUT);
  digitalWrite(pulsante1, HIGH);
  
  // Connessione Ethernet usando MAC e DHCP (IP dinamico)
  Ethernet.begin(mac);
  
  // Imposto una connessione seriale per verificare i dati
  Serial.begin(9600);

  // Diamo alla Ethernet shield un secondo per inizializzarsi
  delay(1000); 
  
 Serial.println("Connesso");

  
}

void loop() {
  if (client1.connect(server, 4665)){
    for(;;) {
      int valor1 = digitalRead(pulsante1);
      Serial.print("valore del sensore =");
      Serial.println(valor1);
      client1.println(valor1);
      delay(wait);
      }
    }
}

In sostanza volevo testare attraverso il monitor seriale del softare di arduino se funzionava l'input e l'output.
Le uniche cose che funzionano (ora ovviamente lo sketch risulta modificato nuovamente) sono la comunicazione tra client e server, il ping sui singoli indirizzi ip che anche se sono dinamici, sono impostati come reservation sul router. Sembra anche che l'input funzioni poichè facendo la prova del pulsante su monitor mi appare inizialmente uno stato 1 in loop e non appena premo il pulsante a monitor esce lo "0" ovviamente sempre in loop. Purtroppo non riesco a capire come passare questo parametro di input al server...ho provato e provato a fare diverse prove ma non ci riesco.

Via questo tono formale, questo è un forum, siamo tutti colleghi/amici.
Purtroppo non esistono scorciatoie, anche quando si parla di Arduino è necessario studiare.
In prima approssimazione l'Arduino relè dovra svolgere la funzione di server, e porsi in ascolto su un endpoint TCP (indirizzo ip e porta), l'atro Arduino quando dovrà in caso di verificarsi di un evento dovrà instaurare una connessione TCP verso quel endpoint e comunicare i comandi che il server deve eseguire.
Nell'IDE sono messi a disposizione gia delle classi pronte per questo lavoro.
La classe Server e la classe Client per le rispettive controparti.

P.S.
Un web server mi pare poco adatto per lo scopo.

RobertoBochet:
P.S.
Un web server mi pare poco adatto per lo scopo.

Hai ragione. Infatti mi è appena venuto in mente il telnetClient nell'IDE di arduino.
Occhio e croce questi due sono perfetti.
http://forum.arduino.cc/index.php?topic=8533.msg69271#msg69271

/*
  Telnet client

 This sketch connects to a a telnet server (http://www.google.com)
 using an Arduino Wiznet Ethernet shield.  You'll need a telnet server
 to test this with.
 Processing's ChatServer example (part of the network library) works well,
 running on port 10002. It can be found as part of the examples
 in the Processing application, available at
 http://processing.org/

 Circuit:
 * Ethernet shield attached to pins 10, 11, 12, 13

 created 14 Sep 2010
 modified 9 Apr 2012
 by Tom Igoe

 */

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

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177);

// Enter the IP address of the server you're connecting to:
IPAddress server(1, 1, 1, 1);

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 23 is default for telnet;
// if you're using Processing's ChatServer, use port 10002):
EthernetClient client;

void setup() {
  // start the Ethernet connection:
  Ethernet.begin(mac, ip);
  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }


  // give the Ethernet shield a second to initialize:
  delay(1000);
  Serial.println("connecting...");

  // if you get a connection, report back via serial:
  if (client.connect(server, 10002)) {
    Serial.println("connected");
  } else {
    // if you didn't get a connection to the server:
    Serial.println("connection failed");
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  if (client.available()) {
    char c = client.read();
    Serial.print(c);
  }

  // as long as there are bytes in the serial queue,
  // read them and send them out the socket if it's open:
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    if (client.connected()) {
      client.print(inChar);
    }
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting.");
    client.stop();
    // do nothing:
    while (true);
  }
}

E poi è importante che tu cambi i MAC address con quelli appiccicati dietro alla tua shield.
Buona giornata

E se un giorno volesse inserire un secondo dispositivo pilota? Arduino non è decisamente il dispositivo per eccellenza in caso di multiple connessioni, poi non so quanto sia semplice creare un server multi client per una persona relativamente nuova del campo.
In più una connessione aperta in accensione non garantisce che al momento dell'invio del comando questa sia disponibile. Il server nel frattempo potrebbe essere andato in crash o riavviato. Una connessione re instaurata ad ogni comando non è uno spreco di risorse cosi marcato.

E questo?

Un cavo di rete che arriva al cancello ha 7 conduttori disponibili per inviare comandi e ricevere segnali NC/NA

Comunque se proprio lo vuoi fare .... farei server e client quello interno e solo server quello esterno, abolire qualsiasi comunicazione seriale, la ethernet è già una "seriale" che usa un altro protocollo ma è pur sempre seriale.

perchè questa configurazione?
vado a spiegare il mio punto di vista ..... Partendo dal concetto elementare

Server: apparato silenzioso che non parla mai se non interrogato diciamo che non può prendere iniziative in quanto server
Client : apparato curioso e ignorante che fa solo domande nessuno può interrogarlo non risponderà mai, prende solo risposte belle o brutte che siano.

quindi:
client chiede a >>>> server >>>> server risponde >>> client riceve risposta >>>> ed è soddisfatto.

Ora avendo 2 server è possibile passare ordini al primo o al secondo indifferentemente raggiungendolo col suo IP .... ma supponiamo che tutto deve passare dal primo server (quello dentro) ... però per fare domande abbiamo bisogno di un client ... quindi server1 riceve la domanda che la passa a client1 e la spedisce a server2 ... il server2 risponde e il client1 prende la risposta
Facile no? :slight_smile: :slight_smile:

Il tutto sarà di una lentezza mostruosa e molto costosa, bella a vedersi perchè ci sono tatte lucine che lampeggiano, ma altamente inutile e poco performante.

eutampieri:
E questo?
Utilizzare la comunicazione UDP con Arduino

UDP non è la scelta migliore per un server comandi. Nell'UDP non vi è verifica della ricezione di pacchetti, UDP va bene per gli stream, video o audio, non per istruzioni ben precise.
Pablos ho difficoltà a seguire alcuni tuoi discorsi in questi ultimi giorni :smiling_imp:

Espresso in modo molto elementare è quello che hai scritto qui

In prima approssimazione l'Arduino relè dovra svolgere la funzione di server, e porsi in ascolto su un endpoint TCP (indirizzo ip e porta), l'atro Arduino quando dovrà in caso di verificarsi di un evento dovrà instaurare una connessione TCP verso quel endpoint e comunicare i comandi che il server deve eseguire.

  • la scheda esterna solo server che pilota i relay
  • quella interna che deve instaurare un dialogo con quella esterna client,
  • ma la stessa (interna) anche server se vuole essere raggiunta da una rete locale

altrimenti NODE TCP/IP socket che ho iniziato ottimizzato, ma non terminato del tutto
http://forum.arduino.cc/index.php?topic=173783.0;nowap

eutampieri:
....
E poi è importante che tu cambi i MAC address con quelli appiccicati dietro alla tua shield.
Buona giornata

Eutampieri ti ringrazio, oggi pomeriggio o questa sera provo di effettuare delle prove, unica cosa non ho capito bene i due esempi (il link a questa pagina Re: Telnet Server for Arduino with Ethernet Server - #2 by system - Exhibition - Arduino Forum ) e cioè se fa riferimento al server o al client (mi verrebbe da dire server perchè è scritto nei commenti iniziali però bo, non saprei), mentre l'esempio di codice che mi hai riportato nel post se non vado errato è proprio di un client però a sto punto non riesco a capire il client dove va a prendere il valore dell'input, nel codice non vedo riferimenti all'input.

Grazie mille dell'aiuto.

RobertoBochet:
E se un giorno volesse inserire un secondo dispositivo pilota? Arduino non è decisamente il dispositivo per eccellenza in caso di multiple connessioni, poi non so quanto sia semplice creare un server multi client per una persona relativamente nuova del campo.
In più una connessione aperta in accensione non garantisce che al momento dell'invio del comando questa sia disponibile. Il server nel frattempo potrebbe essere andato in crash o riavviato. Una connessione re instaurata ad ogni comando non è uno spreco di risorse cosi marcato.

Ciao Roberto e grazie mille anche te dell'aiuto.

Aspita quello che stai dicendo non è molto rassicurante per me, cioè la parte in cui il server potrebbe essere in ascolto etc. (non lo avevo calcolato)

La questione è questa: in pratica i cavi elettrici che vanno dai pulsanti esistenti in casa ai relè del cancello sono marci e essendo a bassa tensione non arriva più tensione. Purtroppo togliere i vecchi cavi e aggiungerne di nuovi è un lavorone così mi son detto che con due arduino e una LAN avrei potuto risolvere, questo perchè c'è già un cavo di rete che arriva al cancello. Eventualmente si potrebbe sfruttare la connessione fra i due arduino con il cavo LAN (considera un 60-70 di distanza tra i due arduino) ma senza il protocollo ethernet e o diverso dal tcp/ip ?

hunte88:
(considera un 60-70 di distanza tra i due arduino)

Carote?

Teoricamente si puo fare tutto, la strada del Ethernet ha senso se si ha bisogno di qualcosa che si interfacci con protocollo IP, se hai solo due dispositivi in comunicazione diretta e sei sicuro che la rete non si amplierà usa il classico doppino differenziale.

Ciao scusami intendevo metri. Il cavo di rete tra i due arduino è di 60-70 metri.

Diciamo che in realtà avevo pensato di ampliare il numero di funzioni anche all'arduino server e cioè collegarci un campanello a pulsante e al client la "sirena" del campanello, questo perché anche i fili del campanello sono marci. L'alternativa per il campanello sarebbe quella di usare un campanello IP collegato ad un telefono voip....

Potresti spiegarmi il discorso doppino differenziale ? Serve sempre lo shield Ethernet ?

hunte88:
Ciao scusami intendevo metri. Il cavo di rete tra i due arduino è di 60-70 metri.

Proprio dietro l'angolo :slight_smile:
Con un solo doppino differenziale non so se arrivi a quelle distanza, aspettiamo che qualcuno piu acculturato di me risponda proponendo una connessione seriale alternativa.

scusate se mi intrometto.... ma utilizzare UDP? io l'ho fatto per comandare l'apertura di un cancello attraverso un ponte radio.
In pratica ho un arduino con un rele (che chiamerò da adesso in poi arducancello) collegato in rete e posizionato al cancello che deve essere aperto, un secondo arduino (che chiamerò da adesso in poi arduvilla), posizionato a 800 mt di distanza riceve un input da un pulsante a muro e che chiede l'apertura del cancello, arduvilla riceve il comando e, tramite UDP, invia ad arducancello il carattere "A".
Arducancello legge "A" e attiva il rele che apre il cancello.
Se non è chiaro allego gli sketches.
Questi arduino (che in realtà sono 3 - arducancello - arduvilla - arducantina) sono in attività da circa 3 anni.

killrob:
scusate se mi intrometto.... ma utilizzare UDP?

Per il semplice fatto che non è giustificato l'uso di UDP!
UDP si usa quando bisogna inviare un grande quantitativo di dati in modo rapido senza controllo di trasmissione, non mi sembra il caso di un comando di apertura, mi sbaglio? UDP è giustificato negli stream dati, stream video, per citarne un programma Skype usa prevalentemente UDP, se si perdono dei pacchetti non succede nulla, al massimo perderai un fotogramma, figuriamoci se te ne accorgi :stuck_out_tongue:
Per lo scambio di comandi si usa TCP, il risparmio dato da UDP non giustifica il suo impiego.

Prima di sviluppare un applicazione è importante conoscere le funzionalità delle componenti che si vorrebbe adoperare.

UDP può essere usato anche per la sua semplicità di gestione. Non c'è connessione, non ci sono socket bidirezionali, non c'è uno stream continuo che arriva a pezzi di dimensione pseudocasuale, ma solo singoli messaggi completi. È vero che possono non arrivare (ma su una LAN casalinga figuriamoci), ma se premo il pulsante e il cancello non si apre, posso sempre premerlo una seconda volta, pazienza.

Io appoggio la scelta di UDP, almeno in prima approssimazione. Quando la logica poi è completa, a complicare le cose si fa sempre in tempo ;).

Potrei darti ragione se dovessi scrivere da 0 il protocollo TCP, ma visto che il W5100 fa tutto il lavoro sporco non si può dire che TCP sia difficile da gestire.

@Roberto io non metto in dubbio la tua preparazione e la tua conoscienza in fatto di arduino e protocolli di rete, ma, come ha detto anche Sukko, io premo un pulsante nel muro ed arduino spedisce "A" all'altro arduino, se non viene ricevuto io premo di nuovo il pulsante nel muro. Siccome non devo controllare al bit quello che spedisco e ricevo, sinceramente non mi interessa proprio usare tcp. Ognuno fa come gli pare e per favore interventi un po' meno "cattivi", sopratutto con qualcuno che esordisce con "... scusate...", ma se vuoi litigare io sono sempre a disposizione.