Autodiscovery degli slave modbus rtu

Avrei la necessità di implementare un meccanismo di "autodiscovery" per semplificarmi la vita: in una rete multipunto rs485 basata su modbus vorrei essere in grado di riconoscere, automaticamente, i device collegati (tramite pooling, quindi effettuo una ricerca ogni TOT di tempo)

Premesso che sto usando un clone del MAX485 e premesso che nella rete multipunto sono presenti ESCLUSIVAMENTE dispositivi miei e non di terze parti, pensavo di implementare un meccanismo per l'autoriconoscimento molto banale!
In pratica pensavo: se mando un pacchetto con slave id a zero, quindi un pacchetto di broadcast, con codice di funzione 17 (Report Slave ID), un semplice e banale controllo che verifichi se il pin TX è HIGH mi metterebbe al sicuro da eventuali sorprese?
Stavo pensado, eventualmente, non di rispondere subito ma di rispondere dopo un tempo casuale, il problema però è come calcolare il tempo casuale visto che l'unico elemento che potrei usare è millis ... solo che se si accendono tutti gli arduino insieme (a causa di uno sbalzo di tensione oppure viene tolta e riattivata la corrente) sarà in tutti più o meno uguale

Cosa mi consigliate?

Ciao,
Tempo fà anche io stavo affrontando un problema del genere, ma io avrei voluto anche fare l'assegnazione automatica degli id ai singoli slave :grin: (troppo ghiotto!)

L'unica soluzione che mi era venuta in mente era quella che il master invia sequenzialmente una richiesta di 'echo'(Report slave ID 0x11 del protocollo) specificando progressivamente tutti gli indirizzi da 1 a 247 [0 è broadcast e 248-255 sono riservati), ed in questa maniera si accorgerebbe dalle risposte quanti e quali slave sono collegati ed operativi.
Ovviamente non è il massimo dell'efficienza, ma non credo si riesca a fare diversamente.

Avevo pensato di adottare questa soluzione inizialmente, però il fatto è che voglio cambiare leggermente la logica degli ID per passare il dato dalla lunghezza di 1 byte alla lunghezza di 4 byte (lo so, 4 miliardi è una cifra che non raggiungerò mai) perché in questo modo non mi devo preoccupare di far permettere all'utente finale e/o all'installatore che imposta il sistema di impostare lo slave id (dovrei farlo fare tramite dei jumper o un dip switch altrimenti)

E quest'aspetto mi interessa molto più dell'autodiscovery motivo per il quale non posso ciclarmi 4 miliardi di possibili slave id, la ricerca impiegherebbe, attenendo anche solo 500ms a richiesta inviata, una cifra astronomica (68 anni per ricerca è eccessivo :D)

In realtà al massimo nella mia rete ci staranno 32 slave, non di più, però il problema di fondo rimane

L'idea di controllare il pin RX per verificare se ci sono ricezioni in corso e quindi posticipare l'invio è malvagia? Lo so che non sono operazioni atomiche e ci sono sempre dei tempi di latenza ma è l'unica cosa che mi viene in mente. Al massimo potrei prevedere una logica di ACK dove il primo comando successivo alla risposta deve essere un comando SPECIFICO per quello slave id (anche un echo, o in generale un comando diagnostico) perché se non lo ricevo entro 10 secondi allora significa che è andato perso e devo reinviare il pacchetto per l'autodiscovery.

O magari, visto che tanto controllo sia il DE sia l'RE dell'ic, potrei tenere il DE in HIGH e l'RE(negato) in low e controllare ogni singolo byte che scrivo ... questo insieme al check del pin RX dovrebbe darmi un certo livello di sicurezza, no?
Anche se a dire la verità poi il problema si sposta sul master che si ritrova un un buffer tutto scassato, ma li mi sa che l'unica cosa che mi conviene fare è modificare il protocollo modbus per prevedere una sequenza di apertura ed una sequenza di chiusura posta dopo il CRC così da scartare tutti quei byte che non sono preceduti da una sequenza di apertura.
Così, in questo modo, se ci fosse il buffer dei dati del master corrotto non risponderei nemmeno a quello che mi ha fatto la richiesta corretta, ma dopo i 10 secondi di timeout quest'ultima verrebbe rispedita risolvendo il problema.
E negli slave, appena becco la prima collisione, fermo l'invio e lo riprogrammo dopo 1 secondo

Tra l'altro ho il problema di non poter fare un test a pieno regime perché attualmente sono in fase di progettazione e per avere la certezza di questa situazione dovrei collegare almeno un 15/20 arduino nella rete multipunto

Ciao, comunque vada, visto il casino, sarà un successo!!

Quello che non capisco è il perchè portare l'id da 1 byte a 4(ricordati che devi comunque modificare il protocollo perchè di suo non è previsto!) visto che userai massimo 32 terminali.
Per il discorso dell'assegnazione automatica dell'id ti capisco, del resto ci ho provato anche io :grin: , non con tantissima energia però un paio di ragionamenti sopra li avevo fatti.
Non credo che riuscirai a risolvere il problema delle collisioni solo implementandoti qualche magheggio hardware verificando lo stato delle linee, delr esto come dici tu, esiste sempre la possibilità che due o più slave facciano sulla stessa linea la stessa operazione nello stesso identico istante ( o perlomeno in un intervallo tale il cui nessuno si accorge che un altro è in trasmissione).
Una soluzione interessante potrebbe essere quella di vedere se si riesce a portare la logica di funzionamento del protocollo one wire su linea 485.
Per quel protocollo è prevista una logica molto interessante per stabilire univocamente quale sia il primo slave che deve rispondere alla chiamata.
Non risolveresti in pieno il problema in quanto ti rimarrebbe il fatto che perlomeno all'avvio del singolo slave, esso si 'autonomini' con un certo id e sperare che nella rete non vi sia un altro 'autonominato' alla stessa maniera, ma con un codice a 11 byte è sicuramente mooooolto più difficile che con uno singolo!

niki77:
Ciao, comunque vada, visto il casino, sarà un successo!!

Quello che non capisco è il perchè portare l'id da 1 byte a 4(ricordati che devi comunque modificare il protocollo perchè di suo non è previsto!) visto che userai massimo 32 terminali.

Il sistema su cui sto lavorando dovrà essere, alla fine, prodotto in serie e quindi una delle cose per me necessarie è evitare questa seccatura all'installatore che, altrimenti, dovrà tenersi una mappa degli slave e dei loro ID per evitare accavallamenti

Per il discorso dell'assegnazione automatica dell'id ti capisco, del resto ci ho provato anche io :grin: , non con tantissima energia però un paio di ragionamenti sopra li avevo fatti.
Non credo che riuscirai a risolvere il problema delle collisioni solo implementandoti qualche magheggio hardware verificando lo stato delle linee, delr esto come dici tu, esiste sempre la possibilità che due o più slave facciano sulla stessa linea la stessa operazione nello stesso identico istante ( o perlomeno in un intervallo tale il cui nessuno si accorge che un altro è in trasmissione).

si, infatti è questa la mia preoccupazione :smiley:

Una soluzione interessante potrebbe essere quella di vedere se si riesce a portare la logica di funzionamento del protocollo one wire su linea 485.
Per quel protocollo è prevista una logica molto interessante per stabilire univocamente quale sia il primo slave che deve rispondere alla chiamata.
Non risolveresti in pieno il problema in quanto ti rimarrebbe il fatto che perlomeno all'avvio del singolo slave, esso si 'autonomini' con un certo id e sperare che nella rete non vi sia un altro 'autonominato' alla stessa maniera, ma con un codice a 11 byte è sicuramente mooooolto più difficile che con uno singolo!

non mi interessa fargli prendere l'id da solo, lo voglio assegnare io a priori (è proprio il motivo per cui voglio ingrandire la dimensione dello slave id passandolo a 4 byte, una volta che faccio la modifica trovo poco sensato portarlo a 3 byte)
Però mi pare di capire che la collisione sul bus nel protocollo 1-wire è gestita interamente a livello software (o almeno così dice wikipedia)

Il protocollo one wire, per quante se ne dicano in giro, secondo me è molto innovativo e funzionale.
Il SEARCH è fatto apposta per fare in modo che solo uno slave per volta completa la risposta verso il master rendendone univoca e unitaria l'identificazione per ogni chiamata.
Se poi intendi assegnare un ID ad ogni slave direttamete da codice (su eprom immagino) stai a cavallo, hai risolto tutti i problemi.
L'unico problema del protocollo one wire è che non è sicuramente affidabile come il 485.
La collisione in realtà nel protocollo one wire non esiste, in quanto una rete può contenere un solo master e ogni slave ha per forza un id univoco e trasmette solo su rischiesta.
Solo nella modalità SEARCH tutti gli slave trasmettono bit per bit le proprie informazioni simultaneamente, ma si autoescludono mano a mano che si completano i byte dell'id secondo un algoritmo del protocollo, e 'ALLA FINE NE RIMARRà SOLTANTO UNO!'(mai un affermazioni fu più azzeccata!!)

:smiley:

più o meno ho capito quello che intendi, ora approfondisco l'argomento

ma praticamente alla fine tra:

  • sequenza di inizio e fine
  • slave id ingrandito
  • necessariamente calcolo del CRC cambiato
  • meccanismo di rilevazione delle collisioni

la mia variante del modbus è diventata un nuovo protocollo :asd:

a questo punto mi cambio la parte che mi legge i registri per come mi serve e via, anzi faccio un meccanismo che mi permetta di richiamare delle generiche funzioni registrate alla libreria tramite una callback (il C dell'avr supporta i puntatori a funzione?)

comunque, ho appena avuto un imprevisto e mi sa che tutta l'idea che mi ero fatto l'ho appena "scaricata nel gabinetto" :asd:

mi sa che metterò dei ponticelli e farò un riduttore di tensione con delle resistenze per poi leggere il valore di ritorno da una porta dell'ADC così posso leggere le combinazioni delle resistenze

Azz peccato, poteva venir fuori qualcosa di molto interessante.
$)

beh, guarda, sicuramente ci dovrò lavorare perché praticamente mi hanno commissionato anche la seconda versione, solo che mi serve il sistema funzionante (composto da 2 firmware differenti per arduino + un software in C# con mono for android per android, non mi piace java, e poi una controparte web fatta in php il tutto) per il 16 di questo mese :smiley:

però sicuramente è qualcosa su cui voglio lavorare perché l'idea mi piace parecchio!

Un po off topic , ma te lo devo dire, non mi piace molto mono in generale, figuriamoci per android.
Se posso una curiosità, perché non Java?

niki77:
Un po off topic , ma te lo devo dire, non mi piace molto mono in generale, figuriamoci per android.
Se posso una curiosità, perché non Java?

Trauma inter-lavorativo :smiley:

Detto questo, android, soprattutto nelle ultime incarnazioni, 4.0 a salire, è decisamente fatto di un'altra pasta. Inoltre io lavoro principalmente in C# ed ho MOLTO codice mio già scritto quindi per me poter sviluppare in C# è un grosso vantaggio.

Inizialmente, in realtà, avevo valutato di costruirmi un sistema da zero (crosstools-ng + buildroot) ma l'unica piattaforma interessante, che tra l'altro mi aveva anche fatto considerare l'ipotesi di bypassare in toto arduino per una parte del progetto, era l'i.MX233 (una board arm da 433mhz dal costo di 27€!) ma purtroppo non è supportata dalla serie 3 del kernel, neanche nella 3.7 RC2 che avevo letto esserlo invece, e quindi ho lasciato perdere pensado di tornare ad usare una ALIX (solitamente le uso per gli apparati di rete)
Ma usare android significa:

  • appoggiarsi ad un ecosistema già pronto
  • avere un ambiente grafico facilmente gestibile
  • avere le funzionalità di rete cablata, wireless e vpn già pronte
  • avere un server ssh con estrema semplicità
  • poter fare il debugging dell'applicativo direttamente da dentro il visual studio anche da remoto (adb su tcp/ip)

Ed insomma potrei continuare per un bel pezzo :slight_smile:

Beato te che puoi ancora scegliere!
Professionalmente anche io uso molto c# , o forse sarebbe meglio dire usavo, visto che nel corso degli anni ho dovuto spaziare talmente tanto che al momento scrivere in c# , c , c++, Java o che altra madonna sia è diventato indifferente.
Per fortuna di IDE ne riesco ad utilizzare 2 soli per tutto e ho fatto in modo di avere shortcuts e look&feel pressoché identiche,sennò c'e da diventare scemi!

niki77:
Beato te che puoi ancora scegliere!
Professionalmente anche io uso molto c# , o forse sarebbe meglio dire usavo, visto che nel corso degli anni ho dovuto spaziare talmente tanto che al momento scrivere in c# , c , c++, Java o che altra madonna sia è diventato indifferente.

beh, si, anch'io per lavoro spazio tra C#, C, PHP, Bash e proprio quando non se ne può fare assolutamente a meno anche Java, ma sinceramente se posso lo metto da parte :slight_smile:

La mia fortuna è che lavoro come libero professionista e quindi ho una certa libertà di azione :slight_smile:

Per fortuna di IDE ne riesco ad utilizzare 2 soli per tutto e ho fatto in modo di avere shortcuts e look&feel pressoché identiche,sennò c'e da diventare scemi!

io utilizzo 3 IDE: VS per il .NET/C#, Netbeans per C (la mia piattaforma principale, come puoi immaginare da solo, è Windows ma in C ci lavoro il 99.99% delle volte su linux/android quindi poter scrivere codice da me ma poter avviare/debuggare il codice remotamente sul mio server linux interno è magnifico!), programmer's notepad 2 per php e bash (disco montato via samba oppure winscp via sftp), midnight commander/gedit quando sono su linux per bash/c/php (ogni tanto capita di dover lavorare volante e quindi mi adatto)

Però, in generale, i miei due ide sono VS e PN2 perché in C lavoro poco e in generale mi faccio componenti di supporto, non applicativi interi

Inoltre Mono for Android si comporta veramente veramente veramente bene, per lo sviluppo oltre all'emulatore su x86 utilizzo dei tablet android cinesi (eken) con dentro un AllWinner Pro A10 da 1Ghz e va tutto una meraviglia!

mmm riprendendo un attimo la discussione, ma sempre a livello teorico, protocollo e correzioni degli errori a parte, ma non sarebbe, utile, secondo te eventualmente usare una linea aggiuntiva oltre a quelle A e B per gestire le scritture singole sulla rete RS485?

In questo modo si risolverebbe il problema alla base!

Il GROSSO svantaggio di questo sistema è che, ad esempio nel mio caso, non potrei usare direttamente un adattatore USB<->RS485 perché ovviamente non avrei come leggere la linea della "priorità".

In pratica si fa una linea, magari gestita tramite un transistor così da non uccidere arduino se la rete è di grosse dimensioni, e con una resistenza pull-down sui vari punti di collegamento, così da evitare attivazioni/disattivazioni per fluttazioni, e far si che nel momento in cui si avvia il firmware si attivi un interrupt su una porta di arduino per ricevere "in tempo reale" il segnale di linea occupata in modo da "posticipare"/"bloccare" le scritture (posticipare mettendo il tutto in buffer per poi scrivere appena la linea va low).
Chi scrive mette prima la linea in HIGH e poi fa l'operazione di scrittura (magari impostando una variabile su 1 così da ignorare il proprio interrupt legato alla linea)

Se ho capito bene, per fare questo, invece di "mangiarsi" uno degli interrupt esterni si può usare il "pin change" (ho capito cos'è ma non l'ho mai usato) su qualsiasi PIN.

Questo semplice giochino potrebbe risolvere alla base il problema.

Altrimenti, credo, si possa usare tramite il pin RE in modo tale che fin quando questo pin è high il sistema posticipi le scritture/oppure le blocchi. Questo dovrebbe ridurre considerevolmente eventuali accavallamenti e/o blocchi.

Secondo te è una cosa fattibile?

È fattibile ma non risolveresti sempre e comunque la possibilità di andare in collisione,ed oltretutto vai fuori dal protocollo, sia fisico sia applicativo.
In linea del tutto teorica potresti verificare se nel pin rx trovi lo stesso byte inviato al tx . Se il byte non corrisponde significa che c'e stata una collisione.
Ricordo anche che qualcuno ne parlava di questa cosa ed aveva sollevato anche buoni motivi per sostenere che potesse non funzionare, ma non ricordo ne dove e ne cosa...