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

Per la velocità non so che dirti. Riguardo lo spazio è possibile che la nuova toolchain Atmel integrata nelle ultime versioni dell'IDE sia meno esosa di risorse.

posso fare una domanda? sarei interessato nell'applicazione di questa libreria a network però di arduino collegati tramite bluetooth secondo voi è adattabile?

Ho adattato il layer fisico di PJON per funzionare con le coppie di rx e tx 433 mhz da 3 dollari e ho ottenuto 200 metri di range in ambiente cittadino (tra i palazzi). Quindi credo che si possa fare ma non conosco il mondo del bluetooth per darti una risposta affidabile, qui trovi il link della libreria con layer fisico radio: https://github.com/gioblu/ASK_Slang

Fammi sapere come va!

Grazie Paolo per la pull request, l'ho accettata e ora ci lavoro un po' grazie ancora

Ho scambiato qualche battuta con Christian Maglie. Ho capito che sbagliavo a voler inserire la libreria nella sotto cartella SRC. Quella serve solo se si vuole creare una libreria esclusivamente per la nuova versione. Da 1.5.x in poi. Se si vuole una libreria retrocompatibile, basta aggiungere semplicemente il file library.properties per il Library Manager e mettere gli esempi come file .ino. Con la retrocompatibilità si perde la compilazione ricorsiva delle sottocartelle. Inoltre devo ancora controllare la funzione della sottocartella UTILITY al posto della tua "include". Non è necessario neanche il file .json che serve solo per i pacchetti del core.

Ho fatto una PR con le estensioni degli esempi aggiornate.

Ho fatto una prova e compila sia sulla 1.0.6 che sulla 1.6.5.

@gbm per interfacciarlo con il modulino hai dato come pin di trasmissione tx?

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?