Ciao a tutti ragazzi.
Ieri sera mi sono messo a giocare con i LED e con il nuovo metodo che ho iniziato ad utilizzare, cioè percepire la tensione prodotta da un LED tramite una porta analogica (che dipende dalla luce che lo colpisce). Qui link: Gioblu.com is for sale | HugeDomains
Partendo da cio' ho provato a generare un'onda quadra 1 secondo HIGH e 1 secondo LOW con un Arduino e un LED ir (utilizzato come un normale emettitore), con un secondo Arduino e un LED ir identico al primo, connesso con + analog0 e - GND ricevo l'emissione del primo modulo.
Rendendo grafico l'input del ricevitore con Grapher è stato subito amore . Mi sono detto che quelle potevano essere informazioni in binario senza nessun problema. Il secondo passo è stato testare il range. Con normale illuminazione casalinga (2 faretti a incandescenza + 2 neon) è possibile notare l'onda quadra con una distanza tra tx e rx di anche 5 metri se ben orientate. Bellissimo!!
(un byte, esattamente una Z spedita a ripetizione )
Ho iniziato a scrivere un protocollino veloce a 8bit, suddividendo in 3 parti diverse la comunicazione di ogni singolo byte (a cui ci sarà da aggiungere il controllo di cosa è arrivato al mittente ) la Prima è un label di inizio messaggio dal periodo di 2bit, la seconda è il byte (suddiviso chiaramente in 8bit) e la terza è di fine comunicazione composta da 2bit.
int BITwidth = 10; //bit width in millis
float BITstart = 0; //time of start BIT communication
int BITValue = 0; // BIT value (0 or 1)
void setup() {
pinMode(12, OUTPUT); //PIN a cui è connesso il + del LED
Serial.begin(9600);
}
void startCOM() { //ipotesi del label inizio comunicazione
BITstart = millis();
while((millis() - BITstart) < (BITwidth * 2)) { digitalWrite(12, HIGH); }
}
void endCOM() { //ipotesi label fine comunicazione
BITstart = millis();
while((millis() - BITstart) < (BITwidth * 2)) { digitalWrite(12, LOW); }
}
void BIT(int b) { //funzione che genera valore BIT
if(b == 1) {
BITstart = millis();
while((millis() - BITstart) < BITwidth) {
digitalWrite(12, HIGH);
}
}
if(b == 0) {
BITstart = millis();
while((millis() - BITstart) < BITwidth) {
digitalWrite(12, LOW);
}
}
}
void printBYTE(char b) { //funzione che printa un BYTE
int BITcount = 0;
startCOM();
while(BITcount < 8) {
int value = bitRead(b, BITcount);
BIT(value);
BITcount++;
Serial.print(value);
}
endCOM();
Serial.println();
}
void loop() {
printBYTE('Z');
}
Ad ora il codice è in grado di spedire correttamente 1 byte con la funzione printBYTE() e io posso piacevolmente gustare la Z sotto forma di onda quadra sfrecciare in Grapher sul secondo Arduino.
Vi chiedo supporto / consigli per i seguenti dilemmi:
Ora che ho preparato la funzione printBYTE devo scrivere la funzione LEDprint() al cui interno inserire la variabile numerica o testuale da comunicare. Dopo di cio' questa deve essere suddivisa in n bytes da inviare ordinatamente uno dietro l'altro. Come faccio a suddividere per esempio int 255 in 2 , 5 e 5?
label inizio e fine comunicazione - Cosa ci mettereste per fare in modo che sia abbastanza sicuro??
Ricezione - Essendo un input analogico devo decidere che valore ha HIGH e che valore ha LOW. Voi come fareste?
Riuscendo a risolvere questi problemi, connettendo una digitale e una analogica al positivo del LED otterremo un sistema di comunicazione bidirezionale che puo' ascoltare e ricevere con solo un LED. Chiaramente non è la velocità il merito di questo progetto ma l'estrema semplicità dell' hardware e l'intuitività del codice (lo sto scrivendo a prova di niubbo).
Per scomporre un numero, puoi usare sprintf per scomporre il numero in un array di char, così che poi puoi spedire i caratteri uno alla volta.
Come protocollo, usa un qualsiasi valore seguito dal numero dei caratteri da spedire seguito dai dati, seguito dalla fine delle trasmissioni. Eventualmente aggiungi un byte di checksum subito dopo.
bella idea, supporto l'idea di flameman, crei un pacchetto con IP destinatario, IP mittente, numero di pacchetto, CRC e dati. Si complica la situazione ma puoi richiedere la ritrasmissione di pacchetti mai arrivati o il cui CRC non corrisponde, e (very very pro) addirittura far rimbalazare il pacchetto tra più arduini fino a raggiungere la destinazione.
Oppure puoi prendere spunto dal sistema usato dai moduli RX/TX a basso costo, che però non so quale sia, ma ha il vantaggio di comunicare col modulo esattamente come se fosse una seriale
Ciao raga, ho visto che vi interessa .
Quindi direi che point to point è la soluzione migliore. Questo implica l'inserimento del destinatario del messaggio se non sbaglio.
Vorrei creare un CRC veramente basico, che sia facilmente leggibile da tutti, mi avete postato ottime idee ma faccio fatica a leggerle io... figurati chi ha appena iniziato e vuole far comunicare 2 Arduino con 2 LED. Quello che vorrei fare è una cosa semplice semplice, facile da leggere e abbastanza affidabile, di certo non veloce .
Per Leo, cosa intendi per risoluzione??
La cosa piu' complicata è decidere, essendo un impulso analogico, far scegliere all'algoritmo qual'è il valore che determina HIGH e quale LOW.
Usare una media dei valori di luce ambientale come LOW, e una media dei massimi valori ottenuti (con la larghezza di un bit) come HIGH?
Non mi veniva facilissimo scrivere il codice e la media mi sembrava veramente pedestre... se avete idee
lesto:
bella idea, supporto l'idea di flameman, crei un pacchetto con IP destinatario, IP mittente, numero di pacchetto, CRC e dati. Si complica la situazione ma puoi richiedere la ritrasmissione di pacchetti mai arrivati o il cui CRC non corrisponde, e (very very pro) addirittura far rimbalazare il pacchetto tra più arduini fino a raggiungere la destinazione.
Oppure puoi prendere spunto dal sistema usato dai moduli RX/TX a basso costo, che però non so quale sia, ma ha il vantaggio di comunicare col modulo esattamente come se fosse una seriale
Coi LED a infrarosso é un po piú difficile perché I led a differenza delle antenne in radiofrequenza é difficile farli emanare luci sui 360 Gradi nello spazio. Per questo I LED devono essere sempre piú o meno allineati tra trasmettitore ericevitore. Se si vuole usare lo stesso LED IR anche per la ricezione le cose si complicano perché hanno meno rendimento in ricezione rispetto a un Fototransistore.
gbm:
La cosa piu' complicata è decidere, essendo un impulso analogico, far scegliere all'algoritmo qual'è il valore che determina HIGH e quale LOW.
Usare una media dei valori di luce ambientale come LOW, e una media dei massimi valori ottenuti (con la larghezza di un bit) come HIGH?
Non mi veniva facilissimo scrivere il codice e la media mi sembrava veramente pedestre... se avete idee
Non so se fare una modulazione a 38kHz come sui telecomandi é sensato per questa applicazione; diminurebbe di molto l'influenza della luce statica tipo sole o dei 100Hz dei tubi flurescenti.
Ciao Uwe
Intendevo la velocità massima di trasmissione. Cioè... qual'è la durata minima di un impulso affinché possa essere rilevato dal sensore sopra alla radiazione IR ambientale. Per capire quanti baud raggiunge questo sistema.
Raga devo correre al lavoro ho buttato giu in 5 min questo riassunto dove potete trovare i miei progressi.
Parliamone , nel pomeriggio lo sistemo, cmq funziona è anche abbastanza affidabile la state vedendo senza CRC nel video
Questo software che a breve trasformero' in una libreria Arduino e Pico85 compatible permette di comunicare un pacchetto composto da 10 bits, 1 largo alto iniziale (che è l'init), 8 bit che compongono il byte vero e proprio e l'ultimo bit basso. Il primo e l'ultimo hanno un periodo di 3.5 volte maggiore dei bit standard. Questo aiuta l'arduino che riceve l'informazione a inquadrare il pacchetto e riceverlo. I due bit divisori uno alto iniziale e uno basso finale sono studiati per permettere di stimare la distanza e il possibile valore dell'input all'inizio e basso alla fine per poter avere un valore puro di sola luce ambientale da poter percepire e salvare. Allo stesso modo la parte finale potrà essere utilizzata per avvisare il mittente di una non corretta ricezione.
Il sistema è pensato per essere scalabile tramite la variabile BITwidth e lo studio dei middlePoints, grazie a cio' è possibile variare la durata di ogni bit da 10000 microsecondi per bit (1 secondo cioè 1bit al secondo) a 500 microsecondi per bit (0.0005 secondi cioè 133bytes al secondo) avendo una connessione ancora funzionante e piuttosto pulita senza crc.
Questo software non è finito, manca tutta la parte del CRC e una buona revisione dei tempi di attuazione del codice e magari l'uso degli interrupt. Sarei felice di ricevere consigli e o critiche.
scusami ma qualcosa non va con i tempi.
1secondo = 1.000 millisecondi = 1.000.000 micosecondi
quindi se un bit dura 10.000 microsecondi, ovvero 10 millisecondi, hai un bitRate di 100bit/s
se il bit dura 500microsecondi, ovvero 0,5 millisecondi, hai 2000b/s
Ciao Lesto. Grazie della risposta. Questo è il calcolo della durata di ogni byte:
byte = 1000 / (( (3.5 * 500 ) + (8 * 500) + (3.5 * 500) ) / 1000) = 133bytes/s
3.5 * 500 micros x il bit iniziale 1, 8 * 500 microsecondi per gli 8 bit e altri 3.5 * 500 microsecondi per il bit 0 finale.
A questo devi aggiungere il tempo di esecuzione di analogRead() (100 micros che come vedi nel codice è tenuto in considerazione) e micros() svariate volte nel codice, infatti andando sotto i 500 micros (intervallo in cui è possibile fare solo 5 rilevazioni) è difficile che sia affidabile.
Come vedi nel codice sto utilizzando una semplice soglia (anche piuttosto alta, luce ambientale è 20 / 30, soglia a 150 per BIT1). Guardando il grafico con Grapher posso stimare un paio di metri di range per la comunicazione, questo sarà possibile solo lavorando su un algoritmo che sistemi la soglia in rapporto alla luce ambientale e all'ultimo bit 1 corretto e accertato.
Cosa vorrei aggiungere:
Gestione interrupt (avreste qualche consiglio?)
Indirizzo x destinatario comunicazione
CRC
Ottimizzazione delle routines e del codice per ottenere velocità maggiori.
Per creare qualcosa di adattivo dovresti leggere anche la luminosità ambientale e sottrarla alla lettura in ricezione.
Se ti salvi i valori letti da analogread puoi usare min() e max() per leggere il range e settare in automatico a 1/3 la soglia.
solo un'idea...
Ciao a tutti ragazzi.
Sono bloccato al CRC, è abbastanza complesso scrivere in C il calcolo polinomiale e lo shif dei bit.
Qualcuno di voi saprebbe darmi una mano??
Altra problematica, non è precissimo l'algoritmo, cioè piu allontano (oltre i 40 / 50cm) rx o tx piu i bit sballano.
Questo forse perchè uso micros() e non degli interrupt. Voi cosa ne dite potrebbe essere quello il problema?
Altro quesito. Mi conviene usare un CRC? Essendo una comunicazione gia di per se non velocissima, a questo punto non conviene dare conferma di avvenuta ricezione ad ogni byte? Esempio, mando un indirizzo, un byte, ricevo un indirizzo n e un byte, se il byte è lo stesso allora l'altro modulo con indirizzo n ha ricevuto il messaggio.
Ecco il codice ridotto all'osso e semplificato:
///LED COM
///BIDIRECTIONAL LED COMMUNICATION
///INVENTED BY GIOVANNI BLU MITOLO 2011
// W W W . G I O B L U . C O M
////Bidirectional ANALOG LED communication by Giovanni Blu Mitolo is licensed
////under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
//Based on a work at www.gioblu.com.
//int inputPIN = 12; // + LED in analog 0 - GND LED in GND Arduino
int inputPIN = A0; // + LED in analog 0 - GND LED in GND Arduino
int ENDstringValue = 41; //Decimal value of the carachter received that means END of stream / package ( in this case " ) " )
int BYTEvalue = 0;
int BITwidth = 2500; //bit width in micros (max tested 500) now 2500 60cm good
// 1000millis / (( (1.5bit * 2500microseconds ) + (8bit * 2500microseconds) + (1.5bit * 2500microseconds) ) / 1000conversion to millis) = 36bytes/s
int analogReadTime = 100; //acquistion time of analogRead function (from arduino website, not sure)
float time = 0;
int BITValue = 0;
int BITsReceived[8];
int ambient = 0;
int ambientIndex = 0;
int possibleInput = 138;
int input = 0;
int BITspacerWidth = 2.5; //1.5
int BITspacer = BITwidth * BITspacerWidth;
int BITspacerMiddlePoint = (BITspacer / 2) - (analogReadTime / 2);
int BITmiddlePoint = (BITwidth / 2) - (analogReadTime / 2);
int presumption = 150;
void setup() {
pinMode(inputPIN, INPUT);
for(int i = 0; i < 10; i++) { ambient = analogRead(0) + ambient; }
Serial.begin(115200);
}
// ACTIVE MODE///////////////////////////////////////////////////////////////
void startCOM() { time = micros(); while((micros() - time) < BITspacer) { pinMode(inputPIN, OUTPUT); digitalWrite(inputPIN, HIGH); } }
void endCOM() { time = micros(); while((micros() - time) < BITspacer) { pinMode(inputPIN, OUTPUT); digitalWrite(inputPIN, LOW); } }
void BIT(int b) {
if(b == 1) { time = micros(); while((micros() - time) < BITwidth) { pinMode(inputPIN, OUTPUT); digitalWrite(inputPIN, HIGH); } }
if(b == 0) { time = micros(); while((micros() - time) < BITwidth) { pinMode(inputPIN, OUTPUT); digitalWrite(inputPIN, LOW); } }
}
void printByte(char b) {
int BITcount = 8;
startCOM();
while(BITcount >= 0) { int value = bitRead(b, BITcount); if(value <= 1) {BIT(value); BITcount--;} }
endCOM();
}
// PASSIVE MODE//////////////////////////////////////////////////////////////
void getBYTE() {
time = micros();
pinMode(inputPIN, INPUT);
while(analogRead(inputPIN) > 150) { }
if((micros() - time) >= BITspacer) {
if( analogRead(inputPIN) <= 150) {
getBIT();
while((micros() - time) < BITspacer) { }
}
}
}
void getBIT() {
int BITcount = 8;
while(BITcount >= 0) {
time = micros();
while((micros() - time) <= BITmiddlePoint) {}
input = analogRead(inputPIN);
while((micros() - time) <= BITwidth) {}
if(input > 150) { BITsReceived[BITcount] = 1; }
if(input <= 150) { BITsReceived[BITcount] = 0; }
BITcount--;
}
BYTEvalue = ((BITsReceived[7] * pow(2 , 7)) + (BITsReceived[6] * pow(2 , 6)) + (BITsReceived[5] * pow(2 , 5)) +
(BITsReceived[4] * pow(2 , 4)) + (BITsReceived[3] * pow(2 , 3)) + (BITsReceived[2] * pow(2 , 2)) +
(BITsReceived[1] * pow(2 , 1)) + (BITsReceived[0] * pow(2 , 0)));
if(BYTEvalue == ENDstringValue) { Serial.println(); }
Serial.print(BYTEvalue, BYTE);
Serial.print(" ");
}
//////////////////////////////////////////////////////////////////////////////
void loop() {
getBYTE();
//printByte('B');
//printByte('2');
//printByte('1');
//printByte(')');
}
secondo me si dieprde troppo la luce. Magari prova a mettere un fibra ottica tra i 2 led, tanto il principio di funzionamento è lo stesso, però la fibra al contrario dell'aria trasporta meglio la luce.
Il CRC però è diverso: non serve per sapere se un byte è arrivato ma se è arrivato giusto. Con il tuo sistema, il dispositivo da pilotare trasmettere indietro SEMPRE ciò che riceve, appesantendo il protocollo.
In pratica vorresti fare:
A->B
A spedisce un indirizzo (1 byte)
B riceve l'indirizzo e preleva il dato dall'indirizzo
B spedisce 2 byte: l'indirizzo ed il dato
A controlla se l'indirizzo ricevuto indietro è uguale a quello che aveva spedito lui
Però così non sai se il "dato" è giusto, tu controlli solo l'indirizzo, che è l'unico dato in comune e quindi controllabile con certezza. Ma il dato? Solo B sa se quel dato è giusto. Dovresti allora fare in modo che A rispedisca indietro il dato per permettere a B di verificare che sia stato ricevuto correttamente. E se B lo riceve diverso, lo rispedisce. Però a questo punto il dato potrebbe essere diverso sia dal valore originale spedito da B sia dal valore ricevuto da A la prima volta. A si potrebbe fidare che il dato è giusto solo perché lo vede diverso dal precedente valore? Assolutamente no! Ecco che entri in un circolo vizioso.
Le somme di controllo servono a questo. Un buon sistema sarebbe già un piccolo byte di controllo. Fai una somma di tutti i byte spediti conservando il risultato in una variabile di tipo byte. Non avrai una grande precisione ma avresti già qualcosa in mano.
Esermpio:
indirizzo: 156
dato: 200
CRC=156+200=356=(356-256)=100
Il tuo CRC è 100. Se A riceve indietro 201-100, quando andrà a calcolare il CRC sul valore ricevuto, troverà:
156(l'indirizzo iniziale)+201(dato ricevuto)=357=(357-256)=101
101 != 100
quindi qualcosa è andato storto
Ciao Leo, ciao Lesto. Grazie dei consigli.
Stavo pensando di suddividere il messaggio in pacchetti contenenti: indirizzo mittente (1byte), soggetto / argomento (1byte), messaggio (4 byte), e CRC (1 byte).
In modo tale da ottenere un messaggio del tipo: AB1263CRC cioè
Da modulo A - argomento B (che puo' significare Batteria per esempio) - 1263 esempio 12.63v - CRC
Il tutto girerebbe intorno ai 36bytes x secondo
Stavo ragionando come "salvare" in una variabile la posizione di tutti gli 1 e tutti gli 0. Sto valutando una cosa tipo:
Somma 1 se c'è un 1, e somma il valore corrispondente alla posizione di ogni 0 se c'è uno 0, in questo caso:
10101101 Sarebbe
Primo conteggio: 1 + 0 + 1+ 0 + 1 + 1 + 0 + 1 = 5
Secondo conteggio: 0 + 2 + 0 + 4 + 0 + 0 + 7 + 0 = 13
Totale : 18
Il valore massimo ottenibile è
0 + ( 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 ) * 6bytes = 216
Spedendo un CHAR shiftato di +127 (visto che i valori dei char vanno da -128 a + 127), dovrebbe funzionare e dovremmo starci, potrei spedire il risultato sotto forma di valore decimale del byte e poi decodificarlo dalla parte che riceve.
Come calcolo quante possibilità di falso positivo ci sono?
Non son pratico di statistica quindi non so dirti le probabilità. Però se devi addentrarti nella costruzione di un checksum tuo, allora implementa il CRC8 e buonanotte
CRC(x) = x8 + x2 + x + 1
gbm:
Ciao Leo, ciao Lesto. Grazie dei consigli.
Stavo pensando di suddividere il messaggio in pacchetti contenenti: indirizzo mittente (1byte), soggetto / argomento (1byte), messaggio (4 byte), e CRC (1 byte).
In modo tale da ottenere un messaggio del tipo: AB1263CRC cioè
Da modulo A - argomento B (che puo' significare Batteria per esempio) - 1263 esempio 12.63v - CRC
Il tutto girerebbe intorno ai 36bytes x secondo
Stavo ragionando come "salvare" in una variabile la posizione di tutti gli 1 e tutti gli 0. Sto valutando una cosa tipo:
Somma 1 se c'è un 1, e somma il valore corrispondente alla posizione di ogni 0 se c'è uno 0, in questo caso:
10101101 Sarebbe
Primo conteggio: 1 + 0 + 1+ 0 + 1 + 1 + 0 + 1 = 5
Secondo conteggio: 0 + 2 + 0 + 4 + 0 + 0 + 7 + 0 = 13
Totale : 18
Il valore massimo ottenibile è
0 + ( 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 ) * 6bytes = 216
Spedendo un CHAR shiftato di +127 (visto che i valori dei char vanno da -128 a + 127), dovrebbe funzionare e dovremmo starci, potrei spedire il risultato sotto forma di valore decimale del byte e poi decodificarlo dalla parte che riceve.
Come calcolo quante possibilità di falso positivo ci sono?
non so quanti falsi positivi puoi avere, credo il calcolo sia ben complicato.
però secondo me il "soggetto" non deve far parte del sistama di invio, ma fa parte del "messaggio", in questo modo è molto più portabile in altri progetti, che magari richiedono argometi multipli o non hanno argomenti, oppure in cui il messaggio occupa più pacchetti e così via.
leo72:
Non son pratico di statistica quindi non so dirti le probabilità. Però se devi addentrarti nella costruzione di un checksum tuo, allora implementa il CRC8 e buonanotte
CRC(x) = x8 + x2 + x + 1
che cos'è X? se è il numero equivalente a trasformare tutto il messaggio considerandolo un numero intero (ma non a 2 byte, ha tanti byte quanti il messaggio), vedo molto dura crearsi la matematica da soli, e sarebbe particolarmente lenta, sopratutto x^8