PJON - Multi-master, multi-media network protocol stack

Ciao @Paolo, grazie per il tuo supporto!! Senti ma hai mai testato PJON?? Mi farebbe piacere sapere cosa ne pensi vedendolo funzionare!! In ogni caso, ho letto attentamente la tua risposta. Ho risposto su github alla tua ultima pull request, ma ti scrivo anche qui:

Cosa ne dici di includere in examples gli esempi per entrambe le versioni?
Tipo dir 0.x_blink_example con .pde e 1.x_blink_example con i .ino?

@simonenascivera ciao! Cosa intendi? La libreria si istanzia con il pin utilizzato per la comunicazione in entrambi i casi (ricevitore e trasmettitore). Ho provato soltanto in configurazione monodirezionale, e ho ottenuto range intorno ai 200 metri in environment cittadino (attraverso palazzi) con una quarter wavelength dipole antenna autocostruita da entrambi i lati.

Ecco una foto dell’impianto:

fa parte di una micro radiosonda meteorologica che sto costruendo:

(il grafico rappresenta l’esperimento con cui ho analizzato l’efficacia dell’isolamento termico della capsula, costruita in polistirolo e mylar militare)

In uno dei precedenti post che probabilmente ti è sfuggito, ti ho posto delle domande.

Te le riformulo:

  • al pacchetto di dati viene aggiunto un carattere di checksum?
  • è possibile trasmettere un messaggio a tutti i dispositivi della rete, senza doverlo ripetere per ciascun nodo?
  • come fai a garantire la ricezione di un dispositivo occupato?
  • come gestisci le collisioni in caso di multi master?

Ciao mi devi scusare, hai ragione, mi e’ sfuggita la tua risposta.

  1. Al pacchetto viene aggiunto il CRC, (1 byte xor based)

  2. Per trasmettere un messaggio a tutti i devices connessi puoi usare la costante BROADCAST al posto dell’id
    che vuoi contattare

  3. La ricezione non e’ garantita, cio’ che e’ garantito e’ che chi invia sia sicuro se o no il ricevente ha ricevuto correttamente grazie all’implementazione dell’ ACK o acknowledge e del CRC precedentemente descritto.

  4. Prima di trasmettere qualsiasi device ascolta il canale per un determinato periodo per capire se c’e’ una trasmissione in corso oppure il canale e’ occupato.

Ti consiglio di dare un occhio al readme della libreria che ho cercato di migliorare molto, e che e’ stato di certo molto migliorato da chi ha contribuito al repository :slight_smile:

Spero farai un test :slight_smile:

gbm: A questo punto porterei la tua versione a master con alcune modifiche che intatto ho fatto sulla attuale master, e creerei una branch dedicata alle versione 0.x e 1.x pre 1.5

cosi' da retrocompatibilizzare qualsiasi sketch che usi PJON

La 1.0.6 è deprecata ma ancora utilizzata, la 0.23 e precedenti sono semplicemente preistoriche. Io non perderei tempo con la retrocompatibilità per questa versione (0.23).

@PaoloP ok considero il tuo consiglio, probabilmente hai ragione!!

In una branch locale sto provando un nuovo approccio possibile al reaction manager e volevo chiedervi quale implementazione preferite:

Attualmente il sistema funziona cosi': l'utente puo' inviare un comando (prendo per esempio lo short_command che manda a un determinato device un paccketto composto dalla costante CMD che determina che sia un comando e di un singolo byte (il tutto controllato con CRC) e aspetta l'acknowledge del ricevitore)

network.send_short_command(44, 'B');

Cosi' sto inviando alla board con ID 44 il carattere B.

Dall'altra parte e' possibile configurare una reazione a un determinato comando:

network.insert_reaction('B', blink_function);

void blink_function() {
  // Cicla i dati ricevuti
  for(int i = 0; i < max_package_length; i++)
    Serial.print(network.data[i]);
  Serial.println();

  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
}

In questo modo e' possibile per esempio nel mio sistema di home automation, definire che T e' un simbolo che rappresenta la temperatura e che ogni board nelle varie stanze invia T, il proprio id seguito dalla temperatura cosi' che il master possa aggiungere i dati in un database tramite POST su un server web.

Il nuovo approccio a cui ho pensato:

Definisco un puntatore a una funzione che venga chiamata quando qualsiasi messaggio e' ricevuto correttamente:

typedef void (*receiver)(int length, char *payload);

L'utente puo' gestire il routing e la reazione ai messaggi nel ricevitore in un unica funzione che riceve come parametri la lunghezza del paccketto e il contenuto, questi parametri verranno passati automaticamente dal sistema quando un messaggio verra' ricevuto, l'unica accortezza dell'utente e' quella di dover dichiarare la funzione come segue:

network.set_receiver(message_received);

receiver message_received(int length, char *payload) {
  // Ciclo i dati ricevuti
  for(int i = 0; i < lenght; i++)
    Serial.print(*payload[i]);

  Serial.println();

  if(payload[0] == 'B') {  // Stessa funzionalita' della reazione
    digitalwRITE(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
  }
    
}

Quale soluzione pensate sia piu' sensata? Quale pensate che sia piu' comoda e semplice nell'uso per un utente anche meno esperto?

Ciao, anche io alle prese con la domotica per casa mia, mentre stavo cercando informazioni sulle tecniche migliori per evitare le collisioni di pacchetti mi sono imbattuto in questa tua liberia.

Lato software ad una prima occhiata mi è sembrata fatta molto bene.

Personalmente ho preferito seguire la strada di implementare le funzioni aggiuntive (criptazione, controllo collisioni ecc) su protocolli noti, semplicemente per avere una egevole estendibilità della rete e avere almeno in parte la strada pronta per la coesistenza di oggetti di terze parti sullo stesso bus (conscio ovviamente che integrarli non sarà comunque una passeggiata).

Dal lato "Hardware" però ho serie perplessità. Mi pare di capire che in casa hai collegato direttamente gli Arduino, giusto? I microcontrollori si "parlano" passando in decine di metri di cavo e ti sei fidato solo delle protezioni onboard del microcontrollore?

E' questo che mi lascia molto perplesso. I miei prototipi hanno più componenti per la sezione di ingresso e filtraggio che in tutto il resto dalla board :)

Sarà anche che io ho a che fare con l'apertura della porta di casa e la gestione di antifurto e tapparelle, e sicuramente sarà che io non sono ottimista :) Ma arrivare a casa e non riuscire ad entrare perché il frigo si è attaccato nel momento sbagliato, o vedersi chiudere le tapparelle mentre si è sul balcone, mi spaventa non poco. Ho perso davvero molto più tempo a studiare i possibili malfunzionamenti e a prevenire danni che a studiare il caso d'uso in cui tutto funziona.

Non dico di optoisolare tutto quanto ma secondo me dovresti almeno passare ad una RS485 come livello fisico (su cui potrai tranquillamente mantenere il tuo protocollo logico) e proteggere la linea con dei TVS, altrimenti al primo fulmine potresti avere sgradevoli sorprese.

Hai fatto un gran lavoro, ti manca davvero poco a trasfomarlo in qualcosa che abbia sapore di professionale e affidabile ;)

Eh sei in una situazione non proprio tradizionale, per quello hai risultati così buoni.

Dalla tua parte hai la relativa lentezza della comunicazione e la banda (intesa come tempo nel quale il bus è in comunicazione rispetto a quanto è a riposo) bassa, cose che sicuramente giovano al riconoscere correttamente i livelli logici ed avere margini per una eventuale ritrasmissione del pacchetto senza sovrapporre i flussi dati.

Ma la cosa più importante è l'alimentazione che è veramente poco influenzata dalle spurie di rete. Non tutti possono contare su un sitema del genere. Magari hai pure la fortuna di non abitare a ridosso di industrie...

Il cavo di rete immagino sia STP (schermato) o comunque molto ben fatto perché sei in una situazione ancor più roesea di cosa potessi immaginare.

Il fatto che il cavo sia attorcigliato aiuta, ma l'effetto di protezione sarebbe decisamente migliore se al suo interno passasse una connessione bilanciata (come lo sono le connessioni Ethernet, RS485 ecc).

Visto come hai fatto la rete fisica, non avrai problemi a fare un upgrade ad un sistema bilanciato quando noterai errori di comunicazione.

Fossi in te metterei però almeno uno zener in ingresso di ciascun modulo per evitare che qualche spuria ti faccia fuori l'intera rete. Sono facilmente reperibili, costano pochissimo, e non fanno certo miracoli, ma un minimo di protezione la danno, per lo meno riesci a circoscrivere l'area danneggiata.

Se un domani dovessi decidere per aumentare la velocità del bus, con quella rete potresti trovarti errori dovuti alle riflessioni. In tal caso dovrai sperimentare inserendo dei terminatori (resistenze a massa) come si faceva sulle vecchie reti a stella con cavo coassiale.

Sarò ciecato, ma non ho visto cenni alla resistenza nel readme che c'è su GitHub, per quello ti dicevo di metterla.

Lo zener impedisce allla linea di andare oltre una certa tensione. Se hai un bus a 5V e metti uno zener di valore superiore, di norma non interviene mai. Ma se qualche condizione esterna porta ad avere più di 5 volt sulla connessione, lo zener trasforma in calore questa energia in eccesso. Ha solo il difetto di essere un po' lento e quindi si preferisce il TVS (comportamento simile ma più rapido). In sostanza lo scopo è di non far fuori la porta del micro a causa di extratensioni in arrivo dall'esterno. Il microcontrollore ha già di suo un po' di protezioni, ma sono per forza di cosa minime, quindi è meglio averne di esterne.

Se un fulmine colpisce in pieno l'impianto non c'è nulla da fare, quindi i fusibili da soli farebbero pocco. Hai fatto bene comunque a metterli perché è sempre meglio avere dei circuiti di sicurezza (es, proteggere da cortocircuiti accidentali) Quello da cui guardarti è il caso di un fulmine non troppo distante, in quel caso potresti avere picchi di tensione di qualche decina di volta per pochi millisecondi, sufficienti a distruggere le porte del micro (ma niente incendi o cose di questo genere), in quel caso un semplice TVS ti salva la porta del mocrocontrollore.

Hai ragione, la delucidazione riguardo le pull down c'e' solo nei commenti nel codice :) Grazie della segnalazione :)

Ciao a tutti, ciao Paolo! :slight_smile:
Come puoi vedere ho accettato la tua pull request e modificato estensivamente la libreria. Attualmente in master sono finalmente presenti le modifiche a cui stavo lavorando in locale da tempo. Finalmente esiste un readme decente e degli esempi funzionanti. Grazie per il tuo supporto.

Posso dire di essere vicino alla release della 1.0 :o :o

Cosa ne pensate???

Ho fatto la richiesta (spero non ti dispiaccia) per l'inserimento nel library manager. Però devi creare una release. --> https://github.com/blog/1547-release-your-software

Mi serve un po' di tempo per testarla e comunque ho un probabile progetto dove utilizzarla.

La libreria è stata aggiunta. --> https://github.com/arduino/Arduino/issues/3837#issuecomment-142242947

Come già detto manca la release. :)

Ciao Paolo, grazie del tuo supporto!! :) :) Sono stato molto preso dal lavoro e nel gestire tutte le richieste, commenti e proposte relative a PJON grazie a un post su hackernews rimasto in prima pagina per piu' di un giorno :) . Mi hanno chiesto molto insistentemente di documentare lo "Standard" PJON per permettere una facile implementazione o porting su altri dispositivi. Ci sono gia 3 issues per compatibilita' ARM, raspberry e attiny.

Qui trovate la wiki: https://github.com/gioblu/PJON/wiki

Cosa ne pensate?

Mi pare di capire che, per distinguere i singoli bit in arrivo, non usi il classico oversalpling (quello che si usa nella RS232 per intenderci) ma ti affidi "solo" a dei loop di attesa.

Dovresti provare a mettere nel bus una scheda con il clock volutamente un po' fuori tolleranza (a parte cambiare quarzo, ci in genere ci sono modi per variare il clock tramite i registri interni dei microcontrollori, credo che questo valga anche per Arduino) e vedere cosa capita.

Specie se intendi fare il porting (o approvare ufficialmente porting fatti da terzi) su altri microcontrollori, ti accorgerai che il clock nel mondo reale può avere forti tolleranze dovute a fattori su cui non puoi avere controllo. E' necessario che la libreria sappia deformare (entro certi limiti) ed in tempo reale i tempi di attesa per riconoscere gli "1" dagli "0".

Nel caso di errori dovresti implementare quello che per la RS232 è il frame synchronization.

Ti suggerirei (ma questo non è un bug ma una proposta per migliorare la libreria) di prevedere qualche forma di auto-indirizzamento. Almeno prevederla a livello di protocollo. Poi se e come usarla puoi farlo in un secondo tempo.

Grazie degli utili consigli ed e' un piacere vedere che tu ti sei interessato e abbia letto lo standard e la documentazione. Allora, quello di cui sono abbastanza convinto e' che per esempio, la raspberry avra' una "percezione del tempo" diversa da un arduino e quelli che sono 10 microsecondi per arduino potrebbero essere 8 o 12 per la rasp (dico numeri a caso). Per ovviare al problema il primo approccio a cui ho pensato e' variare la definizione della durata di un bit nella raspberry fino ad ottenere una durata identica a quella generata dall'arduino. A quel punto nel porting avrai una definizione di lunghezza del bit diversa da quella presente nell implementazione dell arduino che pero' avra' effettivamente la stessa durata. Un'altra soluzione e' di certo quella proposta da te. Cosa ne pensi?

In teoria non fa una piega, in pratica però c'è da testare un po' di cose.

Raspberry non è un microcontrollore semplice ma ha un layer software molto complesso (ci gira linux, non quattro routine C in croce come siamo abituati con i micro a 8 bit...) Ne consegue che una implementazione software delle temporizzazioni potrebbe essere o estremamente precisa (ci sono risorse in abbondanza per gestirla) o estremamente scostante (perché qui hai un vero multitasking e quindi le temporizzazioni seguono concetti base molto differenti), dipende da come è scritta la routine di delay e da come la distribuzione linux gestisce il multitasking.

Hai buone probabilità che la tua soluzione funzioni, ma non potrei scommetterci su. Devi provare.

Tutte le problematiche in relazione al time-shift vengono risolte con un hardware appropriato che con contatori multipli al data-rate compensano differenze dovuti a quarzi da 50-200ppm e impedenze di linea dati, quì invece siamo di fronte a un protocollo totalmente software basato su un hardware standard minimale, per tenere leggero il carico software del protocollo una certa rigidezza sul timing penso sia più che tollerabile

Mah, l'versapling sulla rs232 veniva fatto via software sugli ST6 a 8 bit... non è niente di complicato. Si legge lo stato di una porta più volte al secondo di quanto servirebbe in teoria, e poi si conta se il passaggio da zero a uno e viceversa è capitato prima o dopo una certa soglia. Alla fine è una manciata di righe di codice. Certo bisogna vedere se davvero serva o no (per questo chiedevo un test esasperando un po' l'errore del quarzo), ma quanto a "carico software" si tratta di un impatto minimo.

Ciao! Sto ragionando a una nuova parte di questo standard che permetta la creazione di un unica grandissima rete, fatta di n bus con max 255 nodi, tutti connessi assieme tramite routers (un po' come internet).

Per supportare la possibilita' di comunicare da qualsiasi nodo di un bus a un altro nodo di un altro bus e' necessario:

-sapere identificativo univoco bus (BID) -sapere identificativo univoco pacchetto (PID) -sapere identificativo univoco device destinatario (DID) -Il router deve conoscere gli identificativi dei bus ai quali e' connesso

quindi un pacchetto potrebbe essere fatto cosi:

simbolo pacchetto outbound (non per un device all'interno del bus locale) 1 byte BID (4 byte) DID (1 byte) PID (2 byte) contenuto CRC

Il pacchetto verra' inviato al router presente nel bus del device trasmittente. Questo lo inviera' ai router presenti nei bus ai quali e' connesso e cosi' via, finche' uno dei router che ricevera' il messaggio all'interno della rete avra' nella lista degli identificativi bus conosciuti quello richiesto. A questo punto dovra' solo inviare un pacchetto locale (quello con cui ora funziona PJON) e comunicare all'identificativo del device all'interno del bus. Un pacchetto ACK partira' dal destinatario verso il mittente, e fara' la strada inversa all'interno della rete contenendo ACK e l'id del pacchetto cosi' da permettere il mittente di avere la sicurezza di aver ricevuto il messaggio.

Cosa ne pensate?? Offrendo una struttura del genere se un sacco di gente lo usasse, sarebbe possibile creare un sistema come APRS per comunicare pacchetti dovunque sia presente la rete.

Ohhh finalmente adesso PJON ha un porting stabile funzionante anche con i moduli radio ASK 433Mhz!! https://github.com/gioblu/PJON_ASK

Fatemi sapere cosa ne pensate!! Con queste due librerie e' possibile realizzare un router che puo' spostare pacchetti in arrivo da radio a filo o ancora peggio su internet (includendo una libreria per ethernet shield), un po' come funziona APRS!

Pero' devo decidere come definire i pacchetti outbound come dicevo nella risposta precedente per poter definire questa parte.