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)
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.