Collegare due o piu arduino in ethernet

Salve, sono nuovo nel forum, ho programmato PLC industriali per 40 anni e ora sono in pensione, da poco ho conosciuto Arduino e sto cercando di capirci qualcosa.
In pratica vorrei automatizzare la casa di modo che collegando piu arduino in rete locale e non in internet possa io comandare da PC il cancello, la pompa del pozzo, il livello cisterna per irrigazione ecc... a me interessa come accendere un led per ogni arduino da pulsante creato in visual studio da PC e ricevere da arduino un segnale su PC, sapere questo sara una base per costruire poi un programma piu complesso.
Allego una foto per dare una idea di quello che vorrei fare.
Grazie fin d'ora chi mi potra dare una mano.

Buongiorno,

prima di tutto ti segnalo che, nella sezione in lingua Inglese, si può scrivere SOLO in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato, dopo di che ...

... essendo il tuo primo post, nel rispetto del regolamento della sezione Italiana del forum (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti IN QUESTO THREAD (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con molta attenzione tutto il succitato REGOLAMENTO ... Grazie.

Guglielmo

P.S.: Ti ricordo che, purtroppo, fino a quando non sarà fatta la presentazione nell’apposito thread, nel rispetto del suddetto regolamento nessuno ti risponderà (eventuali risposte verrebbero cancellate), quindi ti consiglio di farla al più presto. :wink:

P.P.S.: ...e presta particolare attenzione al punto 15 del regolamento ed ai suoi sottopunti.

Con Ethernet non puoi fare una rete ad anello di questo tipo, a meno di non aggiungere uno switch per ogni punto (cosa che mi sembra da matti sinceramente).

Io valuterei anche altre soluzioni come ad esempio RS485/ModBus che poi non è cosi distante dai bus di campo che si usano comunemente con i PLC e quindi la tua esperienza pregressa viene tutta a tuo vantaggio.

...a quanto detto da cotestatnt aggiungo solo che, utilizzando una RS485, puoi usare, per il collegamento multipunto, l'ottima libreria PJON per la quale trovi supporto anche in area Megatopic.

Guglielmo

Grazie cotestatnt, si in effetti ad ogni nodo mettero uno switch, mi piace di piu ethernet perche ad ogni punto potro' collegarmi con il PC portatile e comunque mi sembra piu professionale.

... veramente a me sembra solo un impianto molto più complesso e costoso.

Impianti di quel genere si fanno tranquillamente con un doppino incrociato (se vai in half duplex) o con due doppini incrociati (se vuoi andare in full duplex) in RS485, molto meno problematica e più adatta a queste applicazioni ... poi fai come credi ... :roll_eyes:

Guglielmo

Grazie Guglielmo, ma lo standard RS485 non e' obsoleto? e comunque poi non posso collegarmi con il PC da qualunque posto mi trovi con il RS485. Io usavo questo sistema a lavoro 25 anni fa per collegare un PC a vari magazzini ruotanti da porta parallela se ben ricordo.

Assolutamente NO, ampiamente utilizzato in ambito industriale dove serve una certa immunità al rumore.

Mah ... veramente esistono adattatori RS485 per il collegamento al PC quindi ... non vedo il problema ... poi, come detto, vedi tu ... :roll_eyes:

Guglielmo

Per quanto riguarda l'affidabilita' onestamente non so, comunque io ho gia 4 arduino con altrettanti w5100 (mi ero portato avanti con il lavoro) e oramai vado avanti cosi, io ho gia fatto prove collegando arduino in USB e da un form in visual studio da pc ho acceso un led su arduino (un piccolo passo per l'uomo ma un grande balzo per l'umanita') ora quello che mi serve e' connettere il pc ad ognuno dei arduino e viceversa poi vedo di capirci qualcosa.....

Ho visto che hai esperienze con il mondo Siemens: tieni conto che il protocollo Profibus a livello elettrico è sostanzialmente RS485.

Si lo so, il profibus si usava credo fino alla serie 300 ma ora la serie 1500 Siemens usa esclusivamente ethernet per collegare tutte le periferiche sia bordo macchina che dentro il quadro generale, pulsantiere e pannelli operatori nelle varie postazioni, ecco perché pensavo che la rs485 era oramai superata.....errore mio!!

I W5100 hanno un piccolo "difetto", non mantengono una tabella di ARP interna per cui ad ogni connessione TCP inviano anche una richiesta ARP per risolvere l'associazione IP<->MAC del destinatario. Tutto bene (a parte un po' di traffico in più sulla rete) finché le unità chiamate sono online, un po' meno se sono offline: oltre a un piccolo flooding di richieste ARP, nel mittente il pacchetto in uscita si corrompe mescolandosi col successivo.

Personalmente nelle prove che ho fatto ho risolto usando esclusivamente pacchetti UDP broadcast, che vengono semplicemente spediti alla massima velocità, senza necessità di sapere esattamente chi ci sia in ascolto.

Ciao Claudio, quindi ritieni che la RS485 sia la via migliore??

Non credo sia una questione di migliore o peggiore, ma solo di maggior praticità ed economicità in funzione del risultato finale.

Sicuramente un'interfaccia ethernet è molto più "prestante" in termini di banda passante, espandibilità etc etc quindi se non ti "costa" più di tanto il dover usare uno switch per ogni punto rete (che immagino avrà bisogno anche della sua alimentazione, a meno di non usare device PoE), benvenga l'ethernet!

Ok grazie mille cotestatnt, quindi in definitiva per comunicare con i vari Arduino dal PC basta inviare i comandi a secondo degli IP, diversi da Arduino ad Arduino?
Puoi farmi un esempio di come accendere un led su Arduino da PC naturalmente in ethernet.....te ne sarò eternamente riconoscente e mi ricorderò di te nelle mie preghiere notturne!!!!!

Ti conviene lasciar perdere, non credo di essere ben voluto ai piani alti, sempre ammesso che siano abitati :wink:

Tenendo in considerazone anche quanto detto da @Claudio_FF , in realtà l'esempio da cui potresti partire è già incluso nell'IDE ed è UDPSendReceiveString.ino

Quello che manca è un protocollo di gestione dei comandi e questa esigenza potrebbe essere brillantemente risolta con l'approccio usato da @gpb01 nella sua libreria SerialCMD.

Ho provato ad usarla direttamente con lo stream UDP, ma purtroppo non funziona (o almeno non sono stato in grado io) e allora prendendo liberamente spunto ho fatto una classe che fa il parser più o meno con lo stesso principio ma con un buffer di char ovvero quello usato dall'esempio per i dati provenienti dal socket UDP.

Per provare rapiamente con un PC, ci sono molti Serial Terminal che consentono di inviare testo anche su socket UDP oppure TCP (io ad esempio uso sscom5, oppure Hercules Setup Utility

#include <Ethernet.h>
#include <EthernetUdp.h>

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;

// Definizione del tipo "funzione di callback"
typedef void(*function_cb)();

// Definizione struct per memorizzare stringa comando e relativa funzione di callback
struct CmdCallback_t  {
  function_cb fn;
  char* cmd;
  CmdCallback_t* next;    // Puntatore al nodo successivo della linked list
};

class CommandParser
{
  private:
    // "Linked list" di struct CmdCallback_t 
    // al posto dell'array "originario" per la lista dei comandi
    CmdCallback_t *head, *tail;

  public:
    // Costruttore della classe
    CommandParser(): head(nullptr), tail(nullptr) {}

    // Metodo per l'aggiunta di un comando al parser
    void AddCmd(const char* cmd, function_cb foo) {
      CmdCallback_t *node = new CmdCallback_t;
      node->cmd = cmd;
      node->fn = foo;
      node->next = nullptr;
      if (head == nullptr) {
        head = node;
        tail = node;
      }
      else  {
        tail->next = node;
        tail = tail->next;
      }
    }

    // Esecuzione del parsing di tutti i comandi memorizzati
    bool ParseBuffer (char* buffer) {
      for (CmdCallback_t *node = head; node != nullptr; node = node->next) {
        if (strstr(buffer, node->cmd) != NULL) {
          if (node->fn != nullptr)
            node->fn();
          return true;
        }
      }
    }
};

CommandParser myParser;

#define LED_ON    "LEDON"
#define LED_OFF   "LEDOFF"

// Sulla board UNO il led buil-in D13 è impegnato dal segnale SCK del bus SPI
#define LED_PIN   5   

// Questa funzione di callback sarà eseguita con il comando "LEDON"
void ledOn() {
  Serial.println("LED ON");
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write("LED is now ON\n");
  Udp.endPacket();

  digitalWrite(LED_PIN, HIGH);
}

// Questa funzione di callback sarà eseguita con il comando "LEDOFF"
void ledOff() {
  Serial.println("LED OFF");
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write("LED is now OFF\n");
  Udp.endPacket();
  digitalWrite(LED_PIN, LOW);
}

// 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, 2, 177);

unsigned int localPort = 8888;      // local port to listen on

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,
char ReplyBuffer[64];


void setup() {
  pinMode(LED_PIN, OUTPUT);

  myParser.AddCmd(LED_ON, ledOn);
  myParser.AddCmd(LED_OFF, ledOff);

  // You can use Ethernet.init(pin) to configure the CS pin
  Ethernet.init(10);  // Most Arduino shields

  // start the Ethernet
  Ethernet.begin(mac, ip);

  // Open serial communications and wait for port to open:
  Serial.begin(115200);

  // Check for Ethernet hardware present
  if (Ethernet.hardwareStatus() == EthernetNoHardware) {
    Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
    while (true) {
      delay(1); // do nothing, no point running without Ethernet hardware
    }
  }
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start UDP
  Udp.begin(localPort);
}

void loop() {

  // if there's data available, read a packet
  if (Udp.parsePacket()) {

    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    myParser.ParseBuffer(packetBuffer);

    // send a reply to the IP address and port that sent us the packet we received
    IPAddress remote = Udp.remoteIP();
    snprintf(ReplyBuffer, sizeof(ReplyBuffer), "Received command from %d.%d.%d.%d (%d): %s",
             remote[0], remote[1], remote[2], remote[3], Udp.remotePort(), packetBuffer);

    Serial.println(ReplyBuffer);
    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
    Udp.write(ReplyBuffer);
    Udp.endPacket();
  }

}

Riassumendo con le informazioni dei link:
https://www.arduino.cc/en/Reference/Ethernet
https://docs.arduino.cc/tutorials/ethernet-shield-rev2/UDPSendReceiveString
il minimo indispensabile per ricevere un pacchetto UDP è il seguente:

#include <Ethernet.h>
#include <EthernetUdp.h>

//====================================================================

byte         mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  // MAC modulo locale
IPAddress    ip(192, 168, 1, 177);                            // IP modulo locale
unsigned int LOCALPORT = 8888;                                // porta locale in ascolto
unsigned int MAXBUF = 64;                                     // lunghezza buffer ricezione
char         packetBuffer[MAXBUF];                            // buffer di ricezione
EthernetUDP  Udp;                                             // Oggetto Udp per ricevere e trasmettere

//====================================================================

void setup() 
{
    Ethernet.init(10);
    Ethernet.begin(mac, ip);
    Udp.begin(LOCALPORT);
}

//====================================================================

void loop() 
{
    int packetSize = Udp.parsePacket();
    if (packetSize > 0)                   // Se arrivato un pacchetto
    {
        Udp.read(packetBuffer, MAXBUF);
        ...qui si possono usare i byte ricevuti in packetBuffer...
    }
}

Lato PC si dovrà aprire un socket UDP su porta 8888 e inviare un pacchetto di byte all'IP 192.168.1.177

O in alternativa all'indirizzo 192.168.1.255 se si vuole trasmettere in broadcast a tutti i moduli.

Come fare in visual studio non ne ho idea.

... hai provato a guardare, nell'ultima versione, l'esempio fatto proprio per ESP32/8266 che fa da WebServer?

Guglielmo

Avevo per le mani solo un AVR e non ci ho guardato :smile:

Io però intendevo processare direttamente lo stream, in teoria dovrebbe essere possibile, no?

Un grazie di cuore a voi tutti, ora proverò a mettere in pratica i vostri consigli!!!!