Fattibilita': replicare con MCU atmel operazioni eseguite da PIC ?

Ok, come gia successo un po di volte, ho ripreso in mano il vecchio progetto di riconversione totale del ROV piu primitivo (va avanti un pezzo alla volta, quando ho un po di tempo libero, cioe' in pratica, tutti i 5 minuti al mese di tempo libero che mi avanzano :P) ... ora, l'hardware e' relativamente facile, ho gia pronte e completate in Eagle quasi tutte le schede da spedire al service, che sono tante ... solo nel ROV sono previste 10 (11 con le uscite opzionali) schede tonde da 120mm, piu quelle che andranno nella centralina di pilotaggio ... tutti schemi ristudiati e riprogettati da zero :stuck_out_tongue: (l'unica ancora incompleta e' quella dei tx video, perche' devo vedere se trovo una soluzione migliore dei canali TV in analogico, per cui di quella non ho ancora completato il routing)

Purtroppo, non essendo un programmatore, per me la parte software e' relativamente ostica (nel senso che mi fa venire voglia di tirare giu santi ogni volta che cerco di capirla :stuck_out_tongue: :D) ... il problema principale per me' e' il riuscire a capire se una cosa che l'originale faceva con dei PIC, si puo fare anche con delle MCU Atmel (perche' anche se il sistema attuale ha alcuni problemi, il principio di funzionamento mi sembra valido, quindi anche se ho riprogettato il circuito, vorrei mantenere lo stesso principio di funzionamento ... seconda legge dell'elettronica: se funziona, non ripararlo :P) ... dico problema, perche' i PIC originali sono ovviamente "bloccati", quindi non ho il software originale, e perche' le poche informazioni che sono riuscito ad ottenere, me le hanno mandate in Francese (e fra l'altro pure incomplete, perche' chi me le ha inviate in teoria non avrebbe neppure potuto dirmi quel poco, essendo l'originale un prodotto commerciale) ... e dato che il tutto avrebbe alla fine un costo non indifferente (e la mia stampante degli Euro e' rotta :P), vorrei prima di iniziare a mandare stampati ai service, fare un po di prove pratiche su breadboard riguardo a quello che mi sta causando piu problemi a capirlo, cioe' la parte di creazione e decodifica delle stringhe da inviare alla sezione di trasmissione ed annessa procedura per ricevere/decodificare dall'altra parte ...

Comunque, in pratica, si tratta del modo in cui la parte centralina e la parte ROV comunicano (o "dovrebbero" comunicare) ... la centralina legge una catena di LS165 (4, 5 oppure 6, per un totale di 32, 40 oppure 48 comandi possibili, anche se teoricamente di LS165 se ne potrebbero collegare fino ad 8, 16, oppure 32 ma con molto ritardo di risposta, ma a me non servono piu di 5, massimo 6, almeno per ora) tramite il PIC, che effettua alcune operazioni e pilota un chip modem FSK, il quale poi modula una portante che viene sovrapposta al resto dei segnali sul cavo coassiale ... dall'altro lato un'altro chip modem FSK decodifica il segnale e lo passa ad un secondo PIC che lo ritrasforma e lo usa per pilotarci una catena di UCN5841A (che non sono altro che degli shift con driver di potenza incorporati sulle uscite) ... ovviamente, non avendo ne il software del PIC che trasmette ne quello del PIC che riceve, mi devo basare solo sulla scarna descrizione del funzionamento che ho a disposizione ...

Segue sul post successivo (limite dei 9000 caratteri)

Questo e' il senso delle mail che ho riunito insieme e tradotto (spero correttamente, perche' il mio Francese e' peggio del mio Inglese :stuck_out_tongue: ... le parole "dubbie" le ho messe fra parentesi):

"E' stato usato un modem in (fonia ?) di tipo FX614, che viene fatto lavorare a 1200 baud, unito ad un PIC16F84A a 10MHz per interfacciarlo ai comandi - il PIC invia un segnale ad LD (load dei registri) caricando i dati degli ingressi nei registri interni, poi si legge la (catena ?) degli shift con 64/128/256 impulsi di clock (nota personale: si riferisce alla possibilita' di avere fino ad 8/16/32 shift in cascata, e va impostata in fase di programmazione del PIC, anche se sono meno di 8/16/32 si mandano sempre 64/128/256 impulsi secondo il caso scelto) - i dati sono memorizzati (provvisoriamente ?) nel PIC e spediti poi al modem dietro richiesta dello stesso, che provvede a convertirli in un segnale FSK ed inviarlo alla sezione trasmittente, che puo usare a scelta una portante fra 400KHz e 2MHz, quella che disturba meno gli altri segnali - le (sequenze ?) ricevute all'altro capo sono decodificate da un secondo FX614, che le invia ad un secondo PIC programmato per decodificare i segnali e pilotare una (catena ?) di UCN5814A configurata allo stesso modo di quella degli ingressi, in modo che ad ogni pin di ingresso degli LS corrisponde un pin di uscita degli UCN - il sistema non prevede alcun tipo di (handshake ?) in quanto uno dei due modem e' sempre in trasmissione e l'altro e' sempre in ricezione, quindi e' stata usata una correzione degli errori e sincronizzazione fatta in questo modo: il trasmettitore inizia sempre ogni sequenza di segnali con gli stessi 3 bytes di controllo, FF, FE, FD, poi trasmette i bytes relativi agli ingressi, incluso per ogni byte il bit di parita', ed alla fine due bytes che sono il checksum di tutti i bytes trasmessi, sommati in binario ed (invertiti ? ... negati forse), per evitare di avere uno zero se nessun ingresso e' attivo, ma invece un 255 (nota personale: sono un po perplesso qui ... serve ? ... se fosse zero che problemi potrebbe creare ? ) - il PIC ricevitore per ogni sequenza completa memorizza la sequenza, controlla i primi 3 bytes se sono corretti, controlla il bit di parita' di tutti i bytes dati, fa la somma (complessiva ?) dei comandi e la controlla con gli ultimi due bytes di checksum, e se tutto e' corretto manda i dati agli shift UCN ed invia poi il segnale per il latch alla (catena ?) per trasferirli alle uscite (nota personale: immagino quindi che i PIC trasmettano sempre gruppi di 64 o 128 o 256 bit, anche se gli ingressi sono di meno e gli shift inutilizzati non sono presenti sul circuito, altrimenti non mi immagino come potrebbero distinguere i bytes dei dati dagli ultimi due di checksum ... intendo dire, dopo i primi 3 e prima dei 2 di checksum, sempre o 8, o 16, o 32 bytes, secondo come sono stati programmati in fase di scrittura ... non lo dice, ma suppongo sia il sistema piu logico, o almeno a me non ne vengono in mente altri), se invece c'e' qualche errore lo segnala con il led rosso, non manda nulla agli UCN ed acquisisce la sequenza successiva - il resto e' solo hardware" (nota personale: analizzando lo stampato ed il funzionamento ho notato che nel ricevitore e' connesso anche il pin DETECT del modem al PIC, quindi pare, anche se non lo dice, che viene controllata anche la presenza della portante in se ... in effetti, se si interrompe, tutte le uscite vengono disabilitate fino al ripristino ed alla ricezione del successivo pacchetto di dati valido)

Questa e' tutta la descrizione che ho, peraltro ricavata da diverse email, un pezzo alla volta, ed in alcuni casi immaginata dal resto del discorso (mi sa che facevano meno fatica quelli dell'inquisizione a strappare le confessioni agli eretici con le tenaglie roventi, di quella che ho fatto io per ottenere queste poche informazioni, accidenti :P)

Ora supponendo che io abbia tradotto in modo corretto, mi piacerebbe riuscire a replicare il tutto usando due MCU Atmel, in modo da poter avere anche il codice in caso di necessita', o se dovessi farci delle modifiche, senza dipendere da una ditta a centinaia di chilometri in un'altro Paese, che la meta' delle volte non capisce quello che gli chiedi e l'altra meta' ti chiede somme enormi per modifiche da poco o parti di ricambio, ti fa aspettare mesi, ed a volte non ti risponde neppure (senza contare la soddisfazione di riuscirci, ma questo e' solo vanita' personale :stuck_out_tongue: :D)

Mi chiedo quindi: una serie di operazioni come queste descritte, e' fattibile con un, diciamo, 328P o simile ? ... posso usarlo per generare tutte le sequenze con cui pilotarci il modem in TX (le sequenze dovrebbe mandarle "a richiesta" del modem, dato che se funziona in quel modo, la velocita' di trasmissione e' per forza governata dal modem che viaggia a 1200baud, quindi sara' lui a dover "chiedere" alla MCU ogni volta la sequenza), e lato RX per ricevere le sequenze dal modem, eseguire tutti quei controlli, e pilotarci i driver ? (non userei gli UCN, sono un po un casino da trovare ormai, ma normali shift seguiti da ULN dove necessario o dalle logiche di pilotaggio negli altri casi) ? ... e soprattutto, se si, quale puo essere il sistema piu semplice ed allo stesso tempo piu "sicuro" (cioe' meno suscettibile di causare errori) per riuscirci ?

Non pretendo lo sketch scritto e funzionante (sarebbe bello, ma come dice sempre Guglielmo, "purtroppo qui non funziona cosi" ;)) ... ma un po di aiuto sarebbe gradito ... per ora, comunque, quello che mi interessa di piu sapere e' se una cosa simile e' replicabile con MCU Atmel, oppure se i PIC magari li hanno usati all'origine perche' altre MCU non sono adatte ... e magari una mano a capire il senso di quella parte della somma invertita di checksum ... poi vedremo il resto, ma da qualche parte, devo pure iniziare, se voglio tentare di capirci qualcosa ...

E, per favore, ricordatevi che io NON sono un programmatore ... se mi scrivete in linguaggio macchina, vi rispondo in Enochiano Antico (:P)

Il 16F84A è un modello vecchio di PIC, 15 anni fa ne vendevano a palate perché usati sulle schede per vedere la tv sat "gratis", ora è considerato obsoleto e non consigliato per nuovi progetti anche se il componente è ancora in produzione.
Un Atmega 328 è di gran lunga superiore ad un 16F84, quindi non ci sono problemi per la sostituzione, anche il software non mi sembra complicato da realizzare.
Ma i modem sono quelli che erano montati sul rover oppure possiamo usare qualcosa di meglio, sopratutto più veloce visto che 1200 bps è roba da preistoria. :slight_smile:

Una coppia di FX614 ce l'ho, li tenevo di scorta, ma se c'e' qualcosa di meglio posso riprogettare sia schema che stampato senza problemi ... vorrei pero', se fosse possibile, mantenere lo stesso principio di funzionamento, in modo da poter inviare anche gruppi simultanei di comandi contemporaneamente ... ed anche perche' delle schede che ricevono i comandi dalla superfice, ognuna ha il proprio shift a bordo (in questo modo ogni gruppo di 8 ingressi nella centralina in superfice corrisponde ad una specifica scheda nel ROV), e sono tutte interconnesse da un flat a 16 EDIT: 20 o 24 (il 16 era il primo progetto, quello vecchio che poi ho ridisegnato) fili "a catena", che gli porta sia i comandi dalla MCU decoder agli shift (un paio di jumper selezionano se la scheda e' "pari" o "dispari" per la linea seriale dei dati) che l'alimentazione della parte logica (ho previsto un regolatore da 5V a bordo di ogni scheda, mentre quelle che richiedono i 12V di potenza hanno connettori appositi che arrivano da una scheda di distribuzione su cui ho messo le protezioni che scollegano il tutto in caso di corto circuito o sovratensione)

Poi serve considerare se le maggiori velocita' di comunicazione sono compatibili con la portante di trasmissione ... al momento usa 442KHz, per evitare di generare armoniche che interferiscano con i due canali video ... ma se si risolve il problema dei canali video in digitale e gli si assegna altre frequenze, nulla vieta di alzarla se necessario ... ora come ora (in teoria e se tutto dovesse funzionare) il ritardo dovrebbe essere di circa 300mS, fra trasmissione del comando e ricezione dello stesso (sull'originale era di circa 500mS o poco piu, nella pratica, ma ho notato che loro trasmettevano 16 bytes di dati ogni volta, anche se la macchina aveva solo 32 ingressi disponibili, mentre io nel mio progetto ho limitato il tutto ad 8 bytes, perche' gia 5 o 6 shift sarebbero piu che sufficenti, il che (sempre in teoria) avrebbe dovuto ridurre il ritardo ... o pensi che sia ancora troppo ? ... in fondo e' un veicolo subacqueo, non un'auto da corsa ...

Il problema in sè non è complesso, si tratta di trasmettere 8 byte da un punto all'altro. I livelli 1 e 2 sono già presenti e funzionanti: cavo/frequenze/modulazione/demodulazione e protocollo seriale asincrono start/stop.

Quindi, dato per scontato che trasmettere un byte da un capo all'altro è già risolto, quello che resta da fare sono due cose:

  • la sincronizzazione
  • il rilevamento degli errori

La sincronizzazione serve per agganciare il ricevitore al punto giusto dello stream dati, in modo che non parta a leggerlo dal centro ecc.

Ci sono vari modi, il più semplice è una pausa tra un pacchetto dati e l'altro, che naturalmente aumenta i tempi di trasmissione.

Se non si vogliono inserire lunghe pause, bisogna includere la sincronizzazione nei dati trasmessi. Se parlassimo di X25 allora si userebbe un byte univoco per indicare l'inizio del messaggio, aggiungendo opportuni bit (stuffing) ai restanti byte per far si che non si crei mai la stessa combinazione di bit dell'inizio messaggio.

Questo processo si potrebbe semplificare manipolando i dati in modo da far si che solo il primo byte abbia il bit più significativo alto, e tutti gli altri lo abbiano a zero.

Per evitare di modificare tutti i dati in trasmissione e rimodificarli in ricezione si possono usare uno o più byte iniziali fissi da riconoscere come start del pacchetto (come nel caso descritto), ma l'inconveniente è che anche i dati veri e propri potrebbero assumere la stessa configurazione di bit ed essere erroneamente scambiati per start.

Una soluzione comune a questo caso consiste nella tecnica delle parole di allineamento con toggle bit, cioè uno o più byte che invece di essere fissi hanno alcuni bit che vengono invertiti ad ogni nuova trasmissione.

Il software in ricezione deve stare in "ricerca" di una qualsiasi parola di allineamento, e verificare che dopo N byte (avendo un formato fisso è semplice) compaia la corrispondente parola con gli opportuni bit invertiti. Se questo non avviene si rimette in ricerca, se invece avviene si considera sincronizzato e inizia a leggere i dati.

A questo punto entra in gioco la seconda fase, il rilevamento degli errori.

Parità e checksum sono il sistema più semplice (le combinazioni errate non riconosciute sono tantissime), puntando all' affidabilità sarebbe decisamente consigliato il CRC16. Nota che non esiste un solo modo per calcolare il CRC ma diversi, con o senza inversione finale del risultato, con o senza XOR finale, con o senza un valore iniziale di partenza, con diversi polinomi, con diverso ordine di ingresso dei bit, ma in questo caso uno vale l'altro, sicuramente molto ma molto meglio di qualsiasi parità, checksum, o XOR a 8 bit.

Un crc16 può essere questo (nell'esempio si suppone di calcolare il crc per i tre byte dati 12, 130,82):

uint16_t crc;
//-----------------------------------------------------------------------------
void crcCalc(byte n){
    for(byte h=8; h; h--){
        if (crc & 0x8000)  crc = ((crc << 1) | (n >> 7)) ^ 0x1021;
        else               crc =  (crc << 1) | (n >> 7);
        n <<= 1;
    }
}
//-----------------------------------------------------------------------------
void setup(){
    Serial.begin(9600);
}
//-----------------------------------------------------------------------------
void loop(){
    // calcola crc
    crc = 0;
    crcCalc(12);
    crcCalc(130);
    crcCalc(82);
    crcCalc(0);         // due byte zero finali obbligatori
    crcCalc(0);
    Serial.println(crc, HEX);

    byte crcRXh = crc >> 8;
    byte crcRXl = crc & 0xFF;

    // verifica crc
    crc = 0;
    crcCalc(12);
    crcCalc(130);
    crcCalc(82);
    crcCalc(crcRXh);    // crc ricevuto al posto degli zeri finali
    crcCalc(crcRXl);
    Serial.println(crc, HEX);  // se risultato zero crc ok

    delay(2000);
}

...ma Arduino c'entra? :smiley: Ah, Il "subbaquo" lo voglio vedere! ;D

Il problema puo non essere complesso, per un programmatore (cosa che io non sono :P), ma io devo anche litigare con il resto del sistema ... principalmente con il fatto che sul cavo coassiale ci viaggiano anche l'alimentazione principale in AC e due canali TV (attualmente in analogico) che portano su il segnale di due telecamere (di piu in realta', ma solo due alla volta, almeno per ora) ... senza contare il fatto che, se possibile, vorrei riuscire a sovrapporci in qualche modo anche una linea RS485 bidirezionale half-duplex (un doppino, in pratica) ... il sistema attualmente gia funziona (ok, funzionicchia), ma e' molto soggetto a problemi ... prima di tutto la distorsione dei segnali video, ma anche parecchie "disconnessioni" volanti dei comandi (nel senso che, anche senza toccare nulla, a volte la portante sparisce e riappare in modo random, di solito per periodi di mezzo secondo o un secondo, ma mai in modo regolare o ripetitivo)

Per cui vorrei cercare di tenere tutto il protocollo, se cosi possiamo chiamarlo, il piu semplice possibile ... non solo per me (che se e' semplice magari riesco pure a capirlo :stuck_out_tongue: :D), ma anche perche', in teoria, meno cose fa, e meno cose possono andare storte (si spera)

Per il problema delle possibili collisioni fra bytes di start e bytes di dati, avevo anche pensato di rinunciare ad uno degli 8 ingressi di ogni banco in modo da limitare le possibili combinazioni ... ad esempio, se usassi 6 shift con 7 ingressi l'uno, eliminando il bit piu significativo, avrei comunque a disposizione 42 comandi (che sarebbero anche troppi, al momento sono a 22 segnali, prevedendo tutto quello che mi e' venuto in mente fin'ora, per cui gia solo 4 shift, 28 segnali, almeno in teoria potrebbero coprirmi tutti gli attuali comandi ed avanzarne di scorta), ed i bit di dati non potrebbero mai superare il valore 127, quindi qualsiasi valore superiore a 127 potrebbe essere usato come bytes di sincronizzazione senza mai generare collisioni, ed allo stesso tempo "dire" alla MCU, se ricevuti in una posizione "dati", che c'e' qualcosa che non va ...

Allo stesso tempo, oltre al bit di parita' (supponiamo per ora di limitarci a 4 o 5 shift) se li sommassi insieme (semplice somma di bytes) e li spedissi alla fine degli 8 bytes di dati come coppia di bytes di checksum, non servirebbero anche come ulteriore controllo ?

Certo, dovrei rifare un po di schemi e di routing ... ma quello per me sarebbe il problema minore, rispetto al cercare di "inventarmi" qualche soluzione software ... e se fosse possibile preferirei non usare roba copiata da internet magari gia pronta ma che non capisco come funziona ...

EDIT: arduino c'entra, anche se in modo marginale ... perche' per ora usero' arduino per fare i test, poi quando (SE, incrociando tutte e 24 le dita :P) riusciro' a far funzionare tutto quanto, usero' degli standalone realizzati su misura ...

Allora, ho rivisto un po schemi e comandi tenendo presente quello che Claudio_F ha detto sulle collisioni, che a livello teorico potrebbero anche verificarsi, anche se in pratica no ... ma voglio comunque evitare qualsiasi rischio ... quindi diciamo che, riprogettando il tutto ed usando 7 ingressi per shift, i comandi previsti attualmente (che sostituirebbero poi quelli dell'elettronica vecchia) finirebbero per essere cosi divisi, sulle schede:

motori orizzontali: avanti - indietro - destra - sinistra - velocita' 1 - velocita' 2 (6 comandi, ne avanza uno di scorta, che posso portare fuori con un rele reed, per avere un contatto indipendente)

motori verticali: su - giu - velocita' 1 - velocita' 2 (4 comandi, ne avanzano 3 di scorta, che porto fuori con altri 3 rele)

luci ed aux: luce 1 - luce 2 - luce retro - luce opzionale - apri pinza - chiudi pinza - rele' 5A opzionale (7 comandi)

switch camere ed aux: cicla primo banco - cicla secondo banco - piu 5 reed per i vari rec/stop eccetera (7 comandi)

scheda opzionale - previsti 7 rele' con contatto scambio da 5A, per qualsiasi possibile futura espansione

E siamo a 5 shift in cascata (che gia ne basterebbero 4, a questo punto, ma e' sempre meglio prevedere la possibilita' di espandere il tutto senza doverlo ricostruire da zero) ... inclusa la scheda opzionale, che se ne sta li a fare nulla in attesa che al proprietario del ROV venga qualcuna delle sue strane idee di aggiungerci questo e quello, come ad esempio telecamera brandeggiabile, tagliasagole, alabarda spaziale, ecc :stuck_out_tongue: ... volendo esagerare, si puo arrivare a prevedere 6 shift e due diverse schede opzionali, spazio nel cilindro permettendo ...

Per cui, diciamo ad esempio che gia con 5 shift da 7 ingressi l'uno si coprono praticamente tutte le necessita', e ne avanza pure di scorta ... a questo punto io farei davvero cosi, cioe' limito i bytes di dati a 7 ingressi l'uno (da 0 a 127), ed uso FF, FE, FD, o qualsiasi altro valore che non possa essere confuso ne con i dati ne con i checksum come sequenza di bytes di start e sincronizzazione ... ora mettiamo l'esempio peggiore, che non potra' comunque mai verificarsi, cioe' avere tutti e 5 i bytes a 127 (non si potra' mai verificare, primo perche' uno non ha 35 dita da usare :P, e secondo perche' il ROV non potra' mai andare contemporaneamente su, giu, a destra, a sinistra, in alto ed in basso, e cosi via ... ma per ipotesi diciamo di si ... la sequenza sarebbe quindi FF, FE, FD (caratteri di start), 7F, 7F, 7F, 7F, 7F, 00, 00, 00 (i 5 bytes dei comandi piu 3 bytes "vuoti" per completare la sequenza di 8 bytes), 02, 7b (la somma dei bytes dei comandi, in questo esempio 127*5 = 635, rappresentato con 2 bytes in sequenza) ... una sequenza del genere, almeno in teoria, non dovrebbe mai poter generare una collisione fra indici di start e dati, perche' i bytes iniziali sarebbero sempre piu alti dei bytes di dati e sempre gli stessi 3 in sequenza, per cui non potrebbero essere neppure confusi con i due bytes finali di checksum, anche se uno di loro dovesse avere lo stesso valore di uno di quelli di start ... lo stesso se le schede, e quindi i bytes dati, fossero 6 ...

Secondo voi e' corretto come ragionamento, a livello teorico ?

Più tardi mi leggo tutto con attenzione e ti faccio sapere qualcosa.

Grazie ... fai pure con comodo, come ho detto, il progetto e' a luuunga scadenza ...

Etemenanki:
Secondo voi e' corretto come ragionamento, a livello teorico ?

A livello teorico non fa una piega, il problema è che un canale trasmissivo non è "teorico", e se è molto rumoroso si può formare qualsiasi configurazione in qualsiasi punto, tale da trarre in inganno sia il meccanismo di allineamento che quello di rilevazione degli errori.

Naturalmente più bit ridondanti si aggiungono, più si restringe il filtro sugli errori non riconsciuti, ma di nuovo aumentano i tempi di trasmissione.

Se a te va bene sacrificare un bit per byte trasmesso, allora la sincronizzazione può benissimo basarsi solo sul primo bit: il byte che avrà l'MSB alto sarà sempre il primo (in caso di errore in cui venga alterato il primo bit di un byte intermedio ci pensa l'error detect o l'arrivo del vero primo byte, in sostanza ad ogni byte ricevuto con l'MSB alto basta riportare all'inizio il puntatore del buffer di ricezione, e quando ne sono arrivati altri 7 con MSB basso fare il controllo errori).

Bisogna però fare in modo che anche i byte del checksum abbiano l' MSB a zero. Siccome con 6 byte dati il checksum andrebbe da zero a 127*6 = 762 (0x02FA), basta spostare un bit in trasmissione e rimetterlo a posto in ricezione.

Supponiamo che il checksum sia contenuto in una variabile uint16_t di nome chk, possiamo ottenere i due byte alto / basso chkh e chkl con MSB basso in questo modo:

byte chkl = chk & 0x7F;
byte chkh = chk >> 7;

In ricezione operazione inversa:

uint16_t chk = (chkh << 7) | chkl;

Per 42 comandi avremmo così un totale di 8 byte trasmessi, compresi sync e chk, aggiornati 15 volte al secondo.

La fragilità del checksum rimane però la proprietà commutativa dell'addizione, uno stesso bit invertito in due byte differenti genera la stessa somma. La parità invece riconosce l'alterazione di un numero dispari di bit, per cui l'inversione contemporanea di 2, 4, 6, 8 bit all'interno del byte non viene rilevata.

Il crc invece, essendo in pratica il resto della divisione tra il numero binario formato da tutti i byte dati e un valore fisso, è capace di rilevare una quantità maggiore di combinazioni errate (tutte è comunque impossibile)... c'è da dire che volendo mantenere il sistema di sync basato sull'MSB, e 8 byte trasmessi in totale, dovremmo calcolare un esotico CRC14... che però usando dati a 7 bit è piuttosto immediato:

uint16_t crc;
//-----------------------------------------------------------------------------
void crcCalc(byte n){
    n <<= 1;  // scarta MSB
    for(byte h=7; h; h--){
        crc = (crc << 1) | (n >> 7);
        if (crc & 0x4000) crc ^= 0x5021;
        n <<= 1;
    }
}
//-----------------------------------------------------------------------------
void setup(){
    Serial.begin(9600);
}
//-----------------------------------------------------------------------------
void loop(){
    // calcola crc
    crc = 0;
    crcCalc(102);   // Dati 0..127
    crcCalc(127);
    crcCalc(82);
    crcCalc(0);     // due byte zero finali obbligatori
    crcCalc(0);
    Serial.println(crc, HEX);

    // trasforma crc 14 bit in due byte crch crcl con MSB zero
    byte crcl = crc & 0x7F;
    byte crch = crc >> 7;

    // verifica crc
    crc = 0;
    crcCalc(102);
    crcCalc(127);
    crcCalc(82);
    crcCalc(crch);    // crc ricevuto al posto degli zeri finali
    crcCalc(crcl);
    Serial.println(crc, HEX);

    delay(2000);
}

Di questa rilevazione errori, anche senza parità sui singoli byte, mi fiderei molto ma molto di più.

Tu probabilmente parli di trasmissione dati "pura", ma tieni presente che stiamo parlando di un ROV ... cioe' di un veicolo subacqueo a comando remoto, ad assetto neutro ma con una massa inerziale di circa 60 chili (di piu con la pinza installata), dove gia di suo mezzo secondo di latenza fra comando ed inizio del movimento e' un tempo irrisorio, perche' di solito e' piu alta la semplice inerzia ...

Qui quello che mi serve di piu, e' che se un comando non e' considerato corretto, non venga eseguito, cioe' il corrispondente rele' o segnale non si attivi (per evitare ad esempio di far partire un motore quando non deve o magari qualcuno ha le mani vicino alle eliche) ... figurati che, se come dice Astro, si potesse realizzare qualcosa piu veloce di 1200bps, avevo persino considerato la possibilita' di inserire un'ulteriore sicura (sempre che non incasini tutto) facendo in modo che un'uscita venga attivata solo se almeno due cicli consecutivi sono uguali (cioe', ad esempio, attivo il motore solo se per almeno due cicli consecutivi il corrispondente bit e' ad 1) ... se fosse molto piu veloce, persino 3 cicli consecutivi ... voglio rifarlo, e' vero, ma voglio anche renderlo il piu sicuro possibile, e se possibile piu di come e' ora ... adesso, ad esempio, anche se succede molto raramente (fin'ora l'ho visto solo 2 volte sulle luci, in molte decine di ore), e' possibile che in modo casuale uno dei rele' scatti per un'attimo anche se non pilotato ... credo possa essere dovuto ad errori non individuabili, e vorrei evitarlo del tutto aggiungendo il controllo dei due o tre cicli consecutivi, ma lo potrei fare solo con un sistema piu veloce di quello originale ...

C'e' anche un'altra considerazione, da tenere presente, ed e' la tipologia di utilizzo del mezzo in se ...

Parliamo di un'oggetto che sara' probabilmente (anzi, in pratica, sicuramente) esposto a sollecitazioni meccaniche, urti, maltrattamenti, possibili incidenti (ad esempio, qualche anno fa il vecchio ROV era rimasto impigliato a delle cime a 236 metri di profondita', ed e' rimasto giu quasi 6 settimane, prima che fosse possibile recuperarlo con un'altro ROV fatto arrivare apposta), infiltrazioni di umidita' o rischio di allagamento, e tutta una serie di possibili guasti che bisogna per forza cercare di prevedere in anticipo, per cui serve costruirlo non solo robusto, ma anche facilmente riparabile sul campo (esempio, si brucia un componente, se sei fuori al largo con un'equipaggio di gente e magari un gommone di supporto con altre persone, che fai, gli dici "aspettatemi qui un paio d'ore che rientro in laboratorio per ripararlo" ? ... non si puo, o mandi all'aria tutto, oppure devi poterlo aprire sul posto e riparare semplicemente togliendo una scheda e rimpiazzandola al volo ... e dato che in genere chi dovrebbe ripararlo non ne capisce un tubo, devo progettarlo non solo "foolproof", ma anche "blind proof", cioe' riparabile pure da un'orbo :stuck_out_tongue: :D), per non parlare delle riparazioni in sede che devono essere il piu facili possibile (mica si puo buttare una scheda solo perche' usa uno stramaledetto chip SMD microminiatura senza pin che non puoi sostituire con un saldatore, per cui componenti piu robusti e facili da saldare e dissaldare possibile), da cui la progettazione cercando di usare il piu possibile componenti standard e facili da sostituire ... pero' la componentistica piu nuova tende tutta all'SMD "estremo", per cui tocca trovare un compromesso decente ...

Astro: indicativamente tu a che velocita' pensavi ? ... chip tipo ad esempio CMX469A a 4800bps, o altro ancora ? (escludendo a priori quelli impossibili da dissaldare con un saldatore e dell'aria calda, per i motivi esposti piu sopra)

Etemenanki:
aggiungendo il controllo dei due o tre cicli consecutivi, ma lo potrei fare solo con un sistema piu veloce di quello originale ...

I 15 aggiornamenti al secondo di cui parlavo erano già riferiti alla velocità di 1200 bps del modem presente (8 byte * 10 bit / 1200), se ci si accontenta di 35 comandi si può salire a 17 aggiornamenti al secondo. Quanto è lungo il cavo?

Per quanto riguarda la sicurezza, è un caso simile all'innesco razzi per aeromodellismo che ho costruito per un elimodello che doveva volare ad una manifestazione. La prima condizione era segnale in ricezione presente e senza microinterruzioni (in caso di un solo impulso mancante dalla ricevente blocco fino a N ricezioni ok). La seconda condizione era segnale entro i limiti previsti (strategia come sopra), la terza era livello di attivazione stabile per almeno N cicli (idem).

Qui secondo me abbiamo la stessa catena AND: portante presente/assente, dati ricevuti ok/ko, singolo comando stabile per N cicli.

Nel caso del razzo la priorità era bloccare tutto. Nel caso del ROV questa priorità potrebbe riguardare solo le parti potenzialmente pericolose (eliche ecc), mentre per luci o altro non ha importanza.

Un altro aspetto, ma questo riguarda un livello diverso del programma, è interbloccare attivazioni contemporanee di cose mutuamente esclusive.

Claudio_F:
... Quanto è lungo il cavo?

Quello attuale circa 300 metri ... c'era anche un 450 metri, ma vecchio, usurato internamente (i fili della calza erano parzialmente interrotti in modo casuale lungo piu di meta' della lunghezza, capita con questi cavi dopo diversi anni di utilizzo e sforzo), per cui al momento e' stato scartato ... ma se e quando capitera' l'occasione, vorrebbero riprendere un 450 metri o fare una prolunga al 300 ... quello che sara' piu economico, perche' e' una ONLUS, non una ditta commerciale ...

... interbloccare attivazioni contemporanee di cose mutuamente esclusive.

Al momento le uniche cose mutualmente esclusive sono le direzioni (avanti-indietro-destra-sinistra e su-giu), che sono escluse dai joystick di comando (con le crociere di blocco meccanico, per cui una sola posizione consentita per ogni joystick), e da due piccoli PIC ad 8 pin senza alcuna sigla sulle schede dei motori, che fanno i ritardi in caso di inversione di marcia

Spiegazione: l'inversione avviene rovesciando lo statore rispetto alle spazzole tramite un rele' invertitore, mentre la marcia e' data da un'altro rele' on-off ... i due PIC ad 8 pin ricevono entrambi due segnali, o avanti o indietro (la combinazione e' fatta sul trasmettitore con una matrice di diodi che manda per ogni posizione del joystick i due segnali opportuni), quindi, se stai andando avanti (rele' on-off acceso ed invertitore spento) ed inverti di colpo il comando con il joystick, per evitare di bruciare tutto il pic spegne il rele' on-off, aspetta 250ms, accende in rele invertitore, aspetta altri 250mS, riaccende il rele' on-off ... se ti limiti a spegnere e riaccendere senza invertire il senso di rotazione, invece, agisce solo sul rele on-off senza ritardo, mantenendo l'invertitore nell'ultima posizione in cui era per minimizzare i ritardi (cioe', supponi di essere in retro, spegni il motore, il pic spegne solo il rele' on-off, se riparti in retro lo riaccende subito, se riparti in avanti spegne l'invertitore, aspetta 250mS e accende l'on-off) ... dovro' in qualche modo replicare anche questi ritardi, ma pensavo di farlo con una sola MCU che leggesse il comando ed azionasse i rele' nella giusta sequenza, alla fine, ma la cosa principale per ora e' la comunicazione, perche' se non riesco a fare quella, tutto il resto non serve a nulla ...

Etemenanki:
la cosa principale per ora e' la comunicazione, perche' se non riesco a fare quella, tutto il resto non serve a nulla ...

Volendo, per fare quanto detto finora, cioè 6 byte dati (42 comandi), solo primo byte con MSB a 1 per il sync, e due byte crc14 finali (sempre con MSB a 0), è sufficiente:

byte     txbuf[6];  // buffer byte da trasmettere
uint16_t crc;
//-----------------------------------------------------------------------------
void crc14(byte n){
   n <<= 1;  // scarta MSB
   for(byte h=7; h; h--){
       crc = (crc << 1) | (n >> 7);
       if (crc & 0x4000) crc ^= 0x5021;
       n <<= 1;
   }
}
//-----------------------------------------------------------------------------
void trasmetti() {
    crc = 0;
    for (byte i=0; i<6; i++) {
        crc14(txbuf[i]);
        if (i) Serial.write(txbuf[i] & 0x7F);  // altri byte MSB 0
        else   Serial.write(txbuf[i] | 0x80);  // primo byte MSB 1
    }
    crc14(0);
    crc14(0);
    Serial.write((byte)(crc >> 7));
    Serial.write((byte)(crc & 0x7F));
}

E per la ricezione una funzione da chiamare ad ogni lettura della seriale:

bool     sync = false;  //  stato aggancio al primo byte
byte     rxbufi;        //  indice buffer ricezione
byte     rxbuf[8];      //  buffer byte ricevuti compresi crch crcl
uint16_t crc;
//-----------------------------------------------------------------------------
void crc14(byte n){
    n <<= 1;  // scarta MSB
    for(byte h=7; h; h--){
        crc = (crc << 1) | (n >> 7);
        if (crc & 0x4000) crc ^= 0x5021;
        n <<= 1;
    }
}
//-----------------------------------------------------------------------------
void ricevi(byte n) {
    if (sync) {
            if (n & 0x80) {
                rxbufi = 0;
                rxbuf[0] = n;
                crc = 0;
                crc14(n);
                return;    
            }
            rxbuf[++rxbufi] = n;
            crc14(n);
            if (rxbufi == 7) {
                if (crc) elaboraKO(); else elaboraOK();  // se crc==0 OK
                sync = false;
            }
            return;
    }

    if (n & 0x80) {
        rxbufi = 0;
        rxbuf[0] = n;
        crc = 0;
        crc14(n);
        sync = true;
    }
}

Testato con trasmissione serrata di dati casuali (tranne un bit pilotato in modo specifico), con Arduino come ricevitore e un programma Python su PC come trasmettitore, funziona bene.

Ma non si può trasmettere su fibra ottica ?

ExperimentUno:
Ma non si può trasmettere su fibra ottica ?

Eh, magari ... il cavo ombelicale (o "umbilicale" come scrivono alcuni :P) per i ROV e' un cavo ad assetto neutro con calza di kevlar interna per il rinforzo meccanico e rivestimento esterno particolare ... anche stando sull'economico andante e trovandolo non troppo usato, per 450 metri vogliono sui 2000 Euro (parecchio di piu se e' nuovo) gia per quello con l'RG58 dopato e basta ... se poi chiedi dei multiwire o peggio dei cavi che incorporano fibra otica, ci devi aggiungere almeno uno zero in fondo (ed ancora non basta) ... e qui parliamo di una ONLUS di volontari, non di una compagnia commerciale che ci guadagna ... i pochi lavori che fanno saltuariamente per una ditta in genere non coprono neppure le spese vive e dei materiali ... il resto e' ricerca pura, o assistenza ai volontari/crocerossa per la ricerca di qualche sub "disperso" sul fondo, e per quelli non prendono nulla ...

No, tocca fare tutto sul coassiale gia intasato di segnali ...

Se non hai ingressi digitali da leggere dal ROV ma solo uscite puoi sicuramente usare il DMX a velocità ridotta , invece dei 250KHZ che magari non arrivano a 500metri , va molto meno, invece del driver 485 che necessita di 2 fili bilanciati (se non sono disponibili) cerca un chip modem POWER OVER COAX un pò più veloce dei 1200baud.

Con il DMX puoi usare piu di 500 canali a 8 bit = 4000 bit che a 250KHz si aggiornano a 50Hz, nel DMX puoi limitare il numero di canali inviati che per avere 128 bit sono 16 canali , così il DMX potrebbe essere ridotto di 32X, da 250.000 a 7812.5Hz per mantenere l'aggiornamento a 50Hz

Con arduino ci sono già dei esempi software di Riceventi DMX mentre per la trasmittente un pò meno. Questa del DMX è un'idea molto simile a quella che hai già fatto e che comunque a questo punto dei tuoi lavori proseguirai , magari se non eri al livello attuale dei lavori potevi anche prenderla in considerazione(il DMX)

Ah , un'altra cosa, il vantaggio del DMX è anche che usando un microcontrollore come ricevente si accorge facilmente che lo streming può mancare o essere danneggiato, in tal caso può autonomamente 'pensare' di fare qualcosa in emergenza, una procedura di recovery, apertura pinze, scanciamenti, disincastramenti etc..

Interessante discussione. :slight_smile:

icio:
...usare il DMX a velocità ridotta...

Il fatto e' che tutta quella roba non mi serve ... io devo riuscire a mantenere il tutto il piu semplice possibile ...

Come modem piu veloce dei 1200 ci sarebbe ad esempio il CMX469A, che puo andare anche a 2400 e 4800 ... pero' non lo conosco e non so esattamente come lavora, sarebbe da provare ... (per quanto, se come dice Claudio a 1200 dovesse avere 15 aggiornamenti al secondo, o anche la meta', gia andrebbe bene quella velocita' ... i ROV sono lenti per natura ... ;))

Poi si, il flusso dati dei comandi va solo dalla centralina al ROV, quindi un lato sempre TX e l'altro sempre RX ...

La RS485 e' un "di piu", per riuscire a mandare in superfice il sonar, che comunica solo in RS485 half-duplex ... per ora e' portato su da un doppino extra avvolto intorno all'ombelicale, ma ti lascio immaginare i problemi, quindi riuscire ad aggiungerlo in qualche modo al resto dei segnali sarebbe il massimo (avevo persino pensato di riciclare un powerline ethernet, ma non so se il protocollo RS485 half-duplex potrebbe venire gestito dal chip dei powerline), pero' come ho detto, e' optional, si vedra' piu avanti, se sara' possibile farlo ...