Guida o suggerimenti per la decodifica di un protocollo IR


10

Qualche tempo fa ho comprato un piccolo elicottero giocattolo a controllo IR semplice ed economico (uguale a questo - si chiama "Diamond Gyro" o "Diamond Force"). Per divertimento, ho cercato di controllarlo tramite un Arduino.

Aggiornamento: capito il protocollo; vedi risposta

Altri hanno già condiviso i loro risultati sulla pirateria informatica di un diverso elicottero giocattolo IR e sulla decodifica del suo protocollo IR. Davvero bello, ma sfortunatamente il mio elicottero usa un protocollo diverso. Uno che non riesco a capire. (Dovrei aggiungere che l'elettronica è solo un hobby a volte per me, quindi potrei aver trascurato qualcosa di ovvio).

Proprio come nel secondo collegamento sopra, ho smontato il controller, ho individuato il pin IC che controlla i LED (i segni dell'IC sono stati cancellati, tra l'altro) e ho collegato un analizzatore logico.

Ho molti dati validi, ma non riesco ancora a capire il protocollo. Questo sito è un'ottima risorsa, ma nessuno dei protocolli elencati sembra adattarsi. E nient'altro che ho trovato sembra corrispondere al segnale che ho catturato neanche. Devo immaginare, tuttavia, che si tratta di un protocollo semplice e standard, solo perché è un piccolo giocattolo economico.

Quindi apprezzerei tutte le idee che potresti avere. Forse sto solo guardando male.
(Ulteriori informazioni sotto l'immagine)

Campioni dal canale A

Caratteristiche del segnale / protocollo

L'ho catturato a 16MHz con il controller impostato sul canale A; dovrebbe essere preciso, in termini di tempismo. (Ci sono 3 canali IR tra cui scegliere, ma l'uso degli altri due canali non modifica le caratteristiche, solo parti del pacchetto stesso.) I tempi sono molto coerenti (+/- 10µs max). I pacchetti vengono ripetuti con intervalli variabili ma almeno sono distanti circa 100 ms.

Operatore: 38kHz al 50% di duty-cycle

Bassi:
- Corto: 285µs
- Lungo: 795µs

Alti:
- Corto: 275µs
- Lungo: 855µs

Sempre 17 massimi per pacchetto.

Controlli / ingressi

L'elicottero ha 3 controlli: "Acceleratore" (cioè velocità di sollevamento / rotore), inclinazione (avanti / indietro) e imbardata (rotazione attorno all'asse del rotore) tutti controllati con 2 levette. Hanno tutti una sorta di intervallo (non solo on / off) e, per quanto ne so, sono tutti trasmessi in un unico pacchetto. Gli ingressi sinistro / destro vengono inviati solo se viene inviato qualcos'altro, quindi ho applicato la massima accelerazione durante il campionamento. Input di acceleratore e pitch sui propri pacchetti trigger inviati, non appena si spingono le levette oltre una certa soglia / banda morta (nel grafico sotto l'etichetta "min" è per il primo pacchetto inviato quando si spinge lentamente un controllo oltre la sua banda morta).

Ha anche pulsanti per tagliare a sinistra ea destra, poiché l'eli non è uno strumento di precisione ( per niente ) e tende a girare lentamente altrimenti. Sfortunatamente i pulsanti di trim sinistro / destro non sembrano inviare un segnale che incrementa / decrementa qualcosa per ogni pressione (che sarebbe utile per capire il protocollo); sembra essere solo un comando, dicendo all'elicottero di tagliare a sinistra / a destra, e poi ne tiene traccia.


Perché non usare semplicemente le tracce del segnale che devi già scrivere i pacchetti grezzi?
Ignacio Vazquez-Abrams,

@ IgnacioVazquez-Abrams Intendi semplicemente riprodurre i segnali registrati sull'elicottero?
Flambino,

Sicuro. Non è come se l'elicottero fosse in grado di dire la differenza ...
Ignacio Vazquez-Abrams,

@ IgnacioVazquez-Abrams Vero, ma per quanto ne so, il pacchetto contiene tutti e 3 i controlli (acceleratore / intonazione / imbardata) e i controlli dell'elicottero, nessuno dei quali è solo acceso / spento. Per guidare la cosa riproducendo, dovrei catturare ogni singola configurazione ... Inoltre voglio capire il protocollo
Flambino,

@ IgnacioVazquez-Abrams Oops, in qualche modo ho confuso il mio ultimo commento. Volevo dire: "... il pacchetto contiene tutti e 3 i controlli (acceleratore / beccheggio / imbardata) e nessuno di essi è solo acceso / spento".
Flambino,

Risposte:


8

Mi sto prendendo la libertà di rispondere alla mia domanda, come ho capito la maggior parte e questo è un buon modo per condividere le mie scoperte. I miei ringraziamenti a Olin Lathrop per avermi dato un punto di partenza e alcune idee da provare, ma alla fine il protocollo si è rivelato molto diverso dall'ipotesi di Olin, quindi ho pubblicato questa risposta.


Aggiornamento: ho pubblicato una domanda di follow-up riguardante gli ultimi 8 bit, che non ho capito fino in fondo, e Dave Tweed l'ha capito . Includerò i dettagli qui, quindi questa risposta può funzionare come specifica del protocollo completo, ma vai a controllare la risposta di Dave.


Ho dovuto provare alcune cose diverse per capirlo, ma sono abbastanza fiducioso di averlo capito. Stranamente, non ho trovato nulla che assomigli a questo protocollo altrove, ma potrebbe benissimo essere un protocollo comune che non conosco.

Comunque, ecco cosa ho trovato:

Protocollo / encoding

Entrambi gli impulsi e gli spazi intermedi vengono utilizzati per codificare i dati. Un impulso / spazio lungo è uno binario (1) e un impulso / spazio breve è zero binario (0). Gli impulsi vengono inviati utilizzando la modulazione standard a 38 kHz a infrarossi di consumo al 50% di duty-cycle.

I tempi di impulso / spazio sono nella domanda originale, ma li ripeterò qui per completezza:

 Bit    Pulse     Space
-----+---------+---------
  0  |  275µs  |  285µs
  1  |  855µs  |  795µs

Tutti ± 10µs max., ± 5µs tip. Si basa su campioni acquisiti con un analizzatore logico a 16MHz; Non ho un oscilloscopio, quindi non conosco il profilo esatto (ovvero i tempi di salita / discesa).

I pacchetti vengono ripetuti fintanto che gli ingressi di controllo vengono applicati e sembrano essere distanziati di almeno 100 ms.

La trasmissione del pacchetto inizia con un preambolo "impulso 1", che è fisso e non parte dei dati. Lo spazio seguente codifica il primo bit di dati del pacchetto e l'ultimo impulso codifica l'ultimo bit.

Ogni pacchetto è lungo 32 bit e contiene tutti gli input che il telecomando può fornire. I valori vengono letti come little endian, ovvero prima MSB.

Struttura dati

Di seguito è riportata la struttura di base dei singoli pacchetti. Gli ultimi 8 bit mi hanno confuso, ma ora è stato capito (vedi sotto).

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
--+---------------------------+-----------+---+-------+-----------
 P|    Yaw    |   Throttle    |   Pitch   | T | Chan. |   Check

P: Preamble (always a pulse-1), T: Trim, Chan.: Channel

Bit    Length    Description (see note below)
-----------------------------------------------
0      1         Preamble. High 1
1-6    6         Yaw. Range 0-36 for left-right, 17 being neutral
7-14   8         Throttle. Range 0-134
15-20  6         Pitch. Range 0-38 for forward-back, 17 being neutral
21-22  2         Trim. Left = 1, right = 2, no trim = 0
23-26  4         Channel. A = 5, B = 2, C = 8
27-32  6         Check bits

Nota: gli intervalli si basano sulle letture più alte ottenute. Il protocollo è in grado di eseguire intervalli più ampi, fino a 255 per l'acceleratore, 63 per il passo / imbardata, ma ne riduce la metà.
Il valore del pitch sembra avere una banda morta da 14-21 (incluso); solo i valori sopra o sotto fanno effettivamente reagire l'elicottero. Non so se sia lo stesso per l'imbardata (difficile da dire, dato che l'elicottero è instabile e può girare leggermente da solo).

Eccolo in termini grafici (confronta con il grafico nella domanda originale)

struttura del pacchetto

I 6 bit di controllo vengono calcolati XOR'ing tutti i valori precedenti. Ogni valore viene trattato come 6 bit. Ciò significa che i 2 MSB del valore dell'acceleratore a 8 bit vengono semplicemente ignorati. ie

check = yaw ^ (throttle & 0x3F) ^ pitch ^ trim ^ channel

Note pratiche

I tempi e la modulazione del segnale non devono essere super precisi. Perfino il tempismo per nulla accurato del mio Arduino funziona bene nonostante la modulazione malvagia e un po 'di hit and miss sulle durate di impulso / spazio rispetto al vero telecomando.

Credo - ma non ho testato - che l'elicottero si aggancerà semplicemente al canale del primo segnale che trova. Se viene lasciato senza un segnale per troppo tempo (un paio di secondi), sembra tornare alla sua modalità "ricerca", fino a quando non acquisisce nuovamente un segnale.

L'elicottero ignorerà i valori di beccheggio e imbardata se l'acceleratore è zero.

I comandi di taglio vengono inviati una sola volta per ogni pressione del pulsante sul telecomando. Presumibilmente il valore di trim semplicemente aumenta / diminuisce un valore nel controller dell'elicottero stesso; non è qualcosa di cui il telecomando tiene traccia. Pertanto, qualsiasi implementazione di questo dovrebbe probabilmente attenersi a quello schema e inviare solo il valore trim sinistro / destro dell'assetto occasionale, ma per impostazione predefinita un valore di assetto zero nei pacchetti.

Consiglio di avere un kill switch che semplicemente imposta l'acceleratore a zero. Ciò farà cadere l'elicottero dal cielo, ma subirà meno danni quando non gira i suoi motori. Quindi, se stai per schiantarti o colpire qualcosa, premi l'interruttore kill per evitare di spellare gli ingranaggi o rompere le lame.

I LED IR del telecomando originale sembrano avere una lunghezza d'onda> 900nm, ma non ho problemi ad usare un LED ~ 850nm.

Il ricevitore IR dell'elicottero è ok, ma non super sensibile, quindi più luminosa è la tua sorgente IR, meglio è. Il telecomando utilizza 3 LED in serie, posizionati sulla guida da 9 V anziché sulla guida da 5 V utilizzata dalla logica. Non ho verificato il loro attuale assorbimento in modo molto preciso, ma scommetterei che è 50mA.

Dati di esempio

Qui ci sono un sacco di pacchetti, per chiunque sia interessato (sì, ho scritto un decoder; non ho decodificato manualmente tutto questo). I pacchetti del canale A provengono dalle stesse acquisizioni dei grafici nella domanda originale.

Channel A                                                       
Yaw     Throttle  Pitch   Tr  Chan  Check     Description
-----------------------------------------------------------
000100  10000100  000000  00  0101  000101    Left Mid + Throttle
000000  10000110  010001  00  0101  010010    Left Max + Throttle 
100001  10000110  000000  00  0101  100010    Right Mid + Throttle 
100100  10000100  010001  00  0101  110100    Right Max + Throttle
010001  00000000  001011  00  0101  011111    Forward Min 
010001  00000000  000000  00  0101  010100    Forward Max 
010001  00000000  011000  00  0101  001100    Back Min 
010001  00000000  100101  00  0101  110001    Back Max
010001  00000000  010001  01  0101  010101    Left Trim 
010001  00000000  010001  10  0101  100101    Right Trim 
010001  00000011  010001  00  0101  000110    Throttle 01 (min)
010001  00010110  010001  00  0101  010011    Throttle 02
010001  00011111  010001  00  0101  011010    Throttle 03
010001  00101111  010001  00  0101  101010    Throttle 04
010001  00111110  010001  00  0101  111011    Throttle 05
010001  01010101  010001  00  0101  010000    Throttle 06
010001  01011111  010001  00  0101  011010    Throttle 07
010001  01101100  010001  00  0101  101001    Throttle 08
010001  01111010  010001  00  0101  111111    Throttle 09
010001  10000101  010001  00  0101  000000    Throttle 10 (max)

Channel B
Yaw     Throttle  Pitch   Tr  Chan  Check     Description
-----------------------------------------------------------
000000  10000110  010001  00  0010  010101    Left Max + Throttle 
100100  10000110  010001  00  0010  110001    Right Max + Throttle 
010001  00000000  001001  00  0010  011010    Forward Min 
010001  00000000  000000  00  0010  010011    Forward Max 
010001  00000000  010111  00  0010  000100    Back Min 
010001  00000000  100110  00  0010  110101    Back Max
010001  00000000  010001  01  0010  010010    Left Trim 
010001  00000000  010001  10  0010  100010    Right Trim 
010001  00000001  010001  00  0010  000011    Throttle Min 
010001  00110100  010001  00  0010  110110    Throttle Mid 
010001  01100111  010001  00  0010  100101    Throttle High 
010001  10001111  010001  00  0010  001101    Throttle Max 

Channel C
Yaw     Throttle  Pitch   Tr  Chan  Check     Description
-----------------------------------------------------------
000000  10000101  010001  00  1000  011100    Left Max + Throttle 
100100  10000101  010001  00  1000  111000    Right Max + Throttle 
010001  00000000  001010  00  1000  010011    Forward Min 
010001  00000000  000000  00  1000  011001    Forward Max 
010001  00000000  010111  00  1000  001110    Back Min 
010001  00000000  100110  00  1000  111111    Back Max
010001  00000000  010001  01  1000  011000    Left Trim 
010001  00000000  010001  10  1000  101000    Right Trim 
010001  00000001  010001  00  1000  001001    Throttle Min 
010001  00110100  010001  00  1000  111100    Throttle Mid 
010001  01100110  010001  00  1000  101110    Throttle High 
010001  10000101  010001  00  1000  001101    Throttle Max

Come accennato in precedenza, gli ultimi 8 bit sono stati individuati, ma solo per i posteri, ecco i miei pensieri originali. Sentiti libero di ignorarlo completamente, dato che mi ero praticamente sbagliato nelle mie ipotesi.

Gli ultimi 8 bit

Gli ultimi 8 bit del pacchetto sono ancora un po 'misteriosi.

I 4 bit dal bit 23 al 26 sembrano essere interamente determinati dall'impostazione del canale del telecomando. La modifica del canale sul telecomando non altera in alcun modo il protocollo o la modulazione; cambia solo quei 4 bit.

Ma 4 bit è il doppio di ciò che è effettivamente necessario per codificare l'impostazione del canale; ci sono solo tre canali, quindi 2 bit sono molti. Quindi, nella descrizione della struttura sopra, ho etichettato solo i primi 2 bit come "Canale", e ho lasciato gli altri due etichettati come "X", ma questa è una supposizione.

Di seguito è riportato un esempio dei bit pertinenti per ciascuna impostazione del canale.

Chan.   Bits 23-26
-----+-------------
  A  |  0  1  0  1
  B  |  0  0  1  0
  C  |  1  0  0  0

Fondamentalmente, ci sono 2 bit in più di quelli necessari per trasmettere l'impostazione del canale. Forse il protocollo ha 4 bit messi da parte per consentire più canali in seguito, o così il protocollo può essere utilizzato in giocattoli completamente diversi, ma semplicemente non lo so. Per i valori più grandi, il protocollo utilizza bit extra che potrebbero essere esclusi (yaw / throttle / pitch potrebbero cavarsela con un po 'meno ciascuno), ma per il trim - che ha anche 3 stati - vengono usati solo 2 bit. Quindi si potrebbe sospettare che anche il canale abbia solo 2 bit, ma ciò non tiene conto dei successivi 2.

L'altra possibilità è che il checksum del pacchetto sia lungo 8 bit, iniziando con i "bit X", e - attraverso la magia del checksum - semplicemente riflettono sempre in qualche modo l'impostazione del canale. Ma ancora: non lo so.

E a proposito di: non ho idea di come si formino quei bit di controllo. Voglio dire, sono bit di controllo, poiché non corrispondono a nessun singolo input di controllo e l'elicottero non sembra rispondere se giocherò con loro. Immagino che sia un CRC di qualche tipo, ma non sono stato in grado di capirlo. Il controllo è lungo 6-8 bit, a seconda di come interpretate i "bit X", quindi ci sono molti modi per metterli insieme.


6

Questo non sembra così male. Si noti innanzitutto che tutti i messaggi contengono esattamente 17 impulsi. Questo ci dà immediatamente un indizio forte che spazi brevi all'interno di un messaggio sono irrilevanti. Sembra che i dati siano codificati da impulsi brevi o lunghi e che una certa distanza tra questi impulsi sia accettabile.

Ovviamente, ogni messaggio inizia con un impulso lungo come bit di inizio. Ciò lascia 16 bit di dati. Probabilmente alcuni dei primi bit sono un codice operativo, possibilmente di lunghezza variabile. Se lo facessi, alcuni dei bit finali sarebbero un checksum. Immagina che gli ingegneri che hanno scritto il firmware volessero mantenere le cose semplici per se stessi, quindi puoi iniziare assumendo che da qualche parte ci siano 8 bit di dati. Ora vedi se qualcuno dei messaggi ha un senso.

Chiamiamo un long a 1 e un short a 0. Potrebbe essere il contrario, ma dobbiamo iniziare da qualche parte. L'eliminazione del bit di partenza lascia:

Acceleratore min 1010001101011010
Acceleratore massimo 1010011101011000
1010000001011111 min in avanti
1010000000011110 max avanti
1010000011011101 max indietro
1010000100011010 min indietro
0000010101011100 max. Sinistra + acceleratore max
0100010101011110 massimo a destra + acceleratore massimo
1010000101111111 tagliare a sinistra
1010000101011011 tagliare a destra

Alcune cose spuntano subito. Ovviamente il bit 0 è un bit di parità. Altrimenti sembra esserci un campo a 3 bit <15:13>, un valore di dati a 8 bit <12: 5> e un altro campo a 4 bit <4: 1>.

Sembra che il valore dei dati venga inviato in ordine di bit da basso a alto, quindi probabilmente ha più senso interpretare tutti i 16 bit capovolti da quello che mostro.

Non mi va di dedicare più tempo a questo, ma spero che questo ti abbia dato un inizio. Procederei riscrivendo l'elenco sopra con il bit di parità rimosso, l'intero numero ha convertito LSB in MSB e ogni campo assunto è mostrato separatamente con uno spazio tra esso e il campo accanto. Ciò potrebbe consentire ad altri di emergere. Inoltre, tieni presente che potremmo avere il senso 1/0 di ogni bit all'indietro. Magari scrivi la nuova tabella in ogni modo e vedi se qualcosa ha più senso in un modo.


Grazie, questo è eccellente! Ci penserò subito e vedrò cosa trovo. Dopo aver esaminato altri protocolli, ho iniziato a pensare che forse gli spazi fossero irrilevanti, ma poiché avevano due tempi molto coerenti, non ne ero così sicuro. Ho pensato che avrebbero variato di più se non fossero importanti. Comunque, lo proverò. Grazie ancora
Flambino il

Eh ... per quanto posso dire, gli spazi fanno materia. Mi sono concentrato sull'acceleratore e ho raccolto altri campioni in 10 diverse posizioni dell'acceleratore. Escludere gli spazi non mi ha dato numeri significativi indipendentemente da come ho fatto le conversioni. Ma includendoli come long = 1, short = 0 produce una progressione regolare del valore dell'acceleratore da 1 a 134 (little endian). Ancora lavorando sugli altri parametri
Flambino,

Ho quasi completamente capito il protocollo, ma c'è ancora un po 'di mistero. Ho aggiunto un sacco di cose alla mia domanda, se vuoi fare un salto. Ad ogni modo, grazie per l'aiuto finora! Mi ha fatto lavorare nella giusta direzione.
Flambino,

@Flambino: Sembra che tu sia molto più avanti di quello che ho fatto per iniziare, che si è rivelato essere per lo più ipotesi sbagliate con il senno di poi. Ho letto la tua domanda aggiornata ma ancora non capisco come viene utilizzata esattamente la lunghezza degli spazi. Era solo una coincidenza che tutti gli schemi mostrati avessero esattamente 17 impulsi e che l'ultimo accadesse per indicare la parità se solo gli impulsi fossero considerati 0 o 1?
Olin Lathrop il

Onestamente, è stato principalmente tentativi ed errori da parte mia. Dato che i 2 tempi utilizzati per gli spazi sono esatti quanto i tempi degli impulsi, ho pensato che potrebbero essere significativi. E, quando ignorare gli spazi non ha prodotto utili dati binari, ho semplicemente assunto un impulso lungo = 1 e uno spazio lungo = 1 (e uno spazio / impulso = 0), che mi ha dato immediatamente dati molto utili. Quindi il primo spazio dopo l'impulso del preambolo è il primo bit (il grafico massimo destro + massimo dell'acceleratore mostra uno "spazio 1" come primo bit) seguito da 16 impulsi, con altri 15 spazi in mezzo; 32 bit.
Flambino,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.