Aide ou astuces pour décoder un protocole IR

10

Il y a quelque temps, j'ai acheté un petit hélicoptère jouet à commande infrarouge simple et bon marché (le même que celui-ci - il s'appelle "Diamond Gyro" ou "Diamond Force"). Pour le plaisir, j'ai cherché à le contrôler via un Arduino.

Mise à jour: Compris le protocole; voir la réponse

D'autres ont déjà partagé leurs résultats sur le piratage d'un autre hélicoptère jouet IR et le décodage de son protocole IR. Vraiment cool, mais malheureusement mon hélicoptère utilise un protocole différent. Un que je n'arrive pas à comprendre. (Je dois ajouter que l'électronique est purement un passe-temps pour moi, donc j'ai peut-être oublié quelque chose d'évident).

Tout comme dans le deuxième lien ci-dessus, j'ai démonté le contrôleur, localisé la broche IC contrôlant les LED (les marquages ​​de l'IC ont été effacés, soit dit en passant) et branché un analyseur logique.

J'ai beaucoup de bonnes données, mais je n'arrive toujours pas à comprendre le protocole. Ce site est une excellente ressource, mais aucun des protocoles répertoriés ne semble convenir. Et rien d'autre que j'ai trouvé ne semble correspondre au signal que j'ai capturé non plus. Je dois imaginer, cependant, que c'est un protocole simple et standard, uniquement parce que c'est un petit jouet bon marché.

J'apprécierais donc toutes vos idées. Peut-être que je le regarde mal.
(Plus d'informations sous l'image)

Échantillons du canal A

Caractéristiques du signal / protocole

J'ai capturé cela à 16 MHz avec le contrôleur réglé sur le canal A; doit être précis et chronologique. (Il y a 3 canaux IR parmi lesquels vous pouvez choisir, mais l'utilisation des deux autres canaux ne change pas les caractéristiques, seulement des parties du paquet lui-même.) Les synchronisations sont très cohérentes (+/- 10µs max). Les paquets sont répétés à des intervalles variables, mais au minimum, ils sont distants d'environ 100 ms.

Porteuse: 38 kHz à 50% de rapport cyclique

Bas:
- Court: 285µs
- Long: 795µs

Hauts:
- Court: 275µs
- Long: 855µs

Toujours 17 sommets par paquet.

Commandes / entrées

Les hélicoptères ont 3 commandes: "Throttle" (c'est-à-dire la vitesse de levage / rotor), le tangage (avant / arrière) et le lacet (rotation autour de l'axe du rotor) tous contrôlés avec 2 baguettes. Ils ont tous une sorte de plage (pas seulement marche / arrêt) et sont, pour autant que je sache, tous transmis en un seul paquet. Les entrées gauche / droite ne sont envoyées que si quelque chose d'autre est envoyé, j'ai donc appliqué l'accélération maximale lors de l'échantillonnage. L'entrée des gaz et de la hauteur sur ses propres paquets de déclenchement est envoyée, dès que vous poussez les manettes au-delà d'un certain seuil / bande morte (dans le graphique ci-dessous, l'étiquette "min" correspond au premier paquet envoyé lorsque vous poussez lentement un contrôle au-delà de sa bande morte).

Il a également des boutons pour couper à gauche et à droite, car l'hélicoptère n'est pas un instrument de précision ( du tout ) et a tendance à tourner lentement sinon. Les boutons de trim gauche / droite ne semblent malheureusement pas envoyer un signal qui incrémente / décrémente quelque chose à chaque pression (ce qui serait pratique pour comprendre le protocole); il semble que ce soit une commande unique, indiquant à l'hélicoptère de compenser gauche / droite, puis il en garde la trace.

Flambino
la source
Pourquoi ne pas simplement utiliser les traces de signal dont vous disposez déjà pour écrire les paquets bruts?
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams Vous voulez dire juste rejouer les signaux enregistrés à l'hélicoptère?
Flambino
Sûr. Ce n'est pas comme si l'hélicoptère allait faire la différence ...
Ignacio Vazquez-Abrams
@ IgnacioVazquez-Abrams Certes, mais pour autant que je sache , le paquet contient les 3 commandes (accélération / tangage / lacet) et les commandes de l'hélicoptère, aucune n'est juste activée / désactivée. Pour diriger la chose en rejouant, je devrais capturer chaque configuration ... En plus, je veux comprendre le protocole
Flambino
@ IgnacioVazquez-Abrams Oups, j'ai en quelque sorte déformé mon dernier commentaire. Signifie: "... le paquet contient les 3 commandes (accélérateur / tangage / lacet) et aucune d'entre elles n'est juste activée / désactivée".
Flambino

Réponses:

8

Je prends la liberté de répondre à ma propre question car j'ai compris l'essentiel et c'est un bon moyen de partager mes résultats. Mes remerciements à Olin Lathrop pour m'avoir donné un point de départ et quelques idées à essayer, mais en fin de compte, le protocole s'est avéré assez différent de la supposition d'Olin, donc j'ai posté cette réponse.


Mise à jour: J'ai posté une question de suivi concernant les 8 derniers bits, que je ne comprenais pas complètement, et Dave Tweed l'a compris . Je vais inclure les détails ici, donc cette réponse peut fonctionner comme une spécification de protocole complète, mais allez vérifier la réponse de Dave.


J'ai dû essayer différentes choses pour comprendre cela, mais je suis assez confiant de l'avoir compris. Curieusement, je n'ai rien trouvé de semblable à ce protocole ailleurs, mais il pourrait très bien s'agir d'un protocole commun que je ne connais tout simplement pas.

Quoi qu'il en soit, voici ce que j'ai trouvé:

Protocole / encodage

Les impulsions et les espaces intermédiaires sont utilisés pour coder les données. Une impulsion / espace long est un binaire (1), et une impulsion / espace court est un zéro binaire (0). Les impulsions sont envoyées en utilisant une modulation infrarouge standard grand public de 38 kHz à un rapport cyclique de 50%.

Les temps d'impulsion / espace sont dans la question d'origine, mais je vais les répéter ici pour être complet:

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

Tous ± 10µs max., ± 5µs typ. Ceci est basé sur des échantillons capturés avec un analyseur logique à 16 MHz; Je n'ai pas d'oscilloscope, donc je ne connais pas le profil exact (c'est-à-dire les temps de montée / descente).

Les paquets sont répétés tant que les entrées de contrôle sont appliquées et semblent espacées d'au moins 100 ms.

La transmission des paquets commence par un préambule "impulsion 1", qui est fixe et ne fait pas partie des données. L'espace suivant code le premier bit de données du paquet et la dernière impulsion code le dernier bit.

Chaque paquet a une longueur de 32 bits et contient toutes les entrées que la télécommande peut fournir. Les valeurs sont lues comme peu endiennes, c'est-à-dire MSB en premier.

Structure de données

Vous trouverez ci-dessous la structure de base des paquets individuels. Les 8 derniers bits m'ont confondu, mais cela a été compris maintenant (voir ci-dessous).

 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

Remarque: les plages sont basées sur les lectures les plus élevées que j'ai obtenues. Le protocole est capable de plus grandes gammes - jusqu'à 255 pour les gaz, 63 pour le tangage / lacet - mais plafonne à environ la moitié.
La valeur de hauteur semble avoir une zone morte de 14 à 21 (inclus); seules les valeurs supérieures ou inférieures font réellement réagir l'hélicoptère. Je ne sais pas si c'est la même chose pour le lacet (difficile à dire, car l'hélicoptère est instable de toute façon, et peut juste tourner légèrement tout seul).

Ici, c'est en termes graphiques (comparer avec le graphique de la question d'origine)

structure de paquets

Les 6 bits de contrôle sont calculés en XOR 'toutes les valeurs précédentes. Chaque valeur est traitée comme 6 bits. Cela signifie que les 2 MSB de la valeur de limitation à 8 bits sont simplement ignorés. C'est à dire

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

Notes pratiques

Les timings et la modulation du signal n'ont pas besoin d'être super précis. Même le timing pas du tout précis de mon Arduino fonctionne très bien malgré une modulation douteuse et un peu de coups et échecs sur les durées d'impulsion / espace par rapport à la vraie télécommande.

Je crois - mais je n'ai pas testé - que l'hélicoptère se verrouillera simplement sur le canal du premier signal qu'il trouvera. S'il est laissé sans signal trop longtemps (quelques secondes), il semble revenir à son mode "recherche", jusqu'à ce qu'il acquière à nouveau un signal.

L'hélicoptère ignorera les valeurs de tangage et de lacet si la manette des gaz est nulle.

Les commandes de trim ne sont envoyées qu'une seule fois par pression sur un bouton de la télécommande. On peut supposer que la valeur de trim augmente / diminue simplement une valeur dans le propre contrôleur de l'hélicoptère; ce n'est pas quelque chose que la télécommande garde en mémoire. Donc, toute implémentation de ceci devrait probablement s'en tenir à ce schéma, et envoyer uniquement la valeur de trim occasionnelle gauche / droite, mais sinon, la valeur par défaut est zéro dans les paquets.

Je recommande d'avoir un kill switch qui met simplement l'accélérateur à zéro. Cela entraînera la chute de l'hélicoptère du ciel, mais il subira moins de dommages lorsqu'il ne fait pas tourner ses moteurs. Donc, si vous êtes sur le point de vous écraser ou de heurter quelque chose, appuyez sur le bouton d'arrêt pour éviter de démonter les engrenages ou de casser les lames.

Les LED IR de la télécommande d'origine semblent avoir une longueur d'onde> 900 nm, mais je n'ai aucun problème à utiliser une LED ~ 850 nm.

Le récepteur IR de l'hélicoptère est correct, mais pas super sensible, donc plus votre source IR est lumineuse, mieux c'est. La télécommande utilise 3 LED en série, reposant sur le rail 9V au lieu du rail 5V utilisé par la logique. Je n'ai pas vérifié leur tirage actuel très précisément, mais je parierais que c'est 50mA.

Exemples de données

Voici un tas de paquets, pour toute personne intéressée (oui, j'ai écrit un décodeur; je n'ai pas décodé tout cela à la main). Les paquets du canal A proviennent des mêmes captures que les graphiques de la question d'origine.

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

Comme mentionné ci-dessus, les 8 derniers bits ont été compris, mais juste pour la postérité, voici mes pensées originales. N'hésitez pas à l'ignorer complètement, car j'avais à peu près tort dans mes suppositions.

Les 8 derniers bits

Les 8 derniers bits du paquet sont encore un peu mystérieux.

Les 4 bits du bit 23 à 26 semblent tous être entièrement déterminés par le réglage du canal de la télécommande. Changer le canal sur la télécommande ne modifie en rien le protocole ou la modulation; cela ne change que ces 4 bits.

Mais 4 bits est le double de ce qui est réellement nécessaire pour coder le paramètre de canal; il n'y a que trois canaux, donc 2 bits suffisent. Par conséquent, dans la description de la structure ci-dessus, je n'ai étiqueté que les 2 premiers bits comme "Canal", et laissé les deux autres étiquetés "X", mais c'est une supposition.

Vous trouverez ci-dessous un échantillon des bits pertinents pour chaque paramètre de canal.

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

Fondamentalement, il y a 2 bits de plus que nécessaire pour transmettre le paramètre de canal. Peut-être que le protocole a 4 bits mis de côté pour permettre plus de canaux plus tard, ou alors le protocole peut être utilisé dans des jouets entièrement différents, mais je ne sais tout simplement pas. Pour les valeurs plus grandes, le protocole utilise des bits supplémentaires qui pourraient être laissés de côté (lacet / accélération / tangage pourraient se débrouiller avec un peu moins chacun), mais pour le trim - qui a également 3 états - seuls 2 bits sont utilisés. Donc, on pourrait soupçonner que le canal n'est également que de 2 bits, mais cela laisse les 2 suivants disparus.

L'autre possibilité est que la somme de contrôle du paquet soit de 8 bits, en commençant par les "X bits", et - grâce à la magie de la somme de contrôle - ils se trouvent toujours refléter le réglage du canal. Mais encore une fois: je ne sais pas.

Et en parlant de: je n'ai aucune idée de la façon dont ces bits de contrôle sont formés. Je veux dire, ce sont des bits de contrôle, car ils ne correspondent à aucune entrée de commande unique, et l'hélicoptère ne semble pas répondre si je les tripote. Je suppose que c'est une sorte de CRC, mais je n'ai pas pu le comprendre. La vérification est longue de 6 à 8 bits, selon la façon dont vous interprétez les «X bits», il existe donc de nombreuses façons de les assembler.

Flambino
la source
6

Ça n'a pas l'air si mal. Remarquez tout d'abord que tous les messages contiennent exactement 17 impulsions. Cela nous donne immédiatement un indice fort que les espaces courts dans un message ne sont pas pertinents. Il semble que les données soient codées par des impulsions courtes ou longues, et qu'une certaine plage d'espacement entre ces impulsions est acceptable.

De toute évidence, chaque message commence par une longue impulsion comme bit de départ. Cela laisse 16 bits de données. Quelques-uns des premiers bits sont probablement un opcode, éventuellement de longueur variable. Si je faisais cela, quelques-uns des bits de fin seraient une somme de contrôle. Imaginez que les ingénieurs qui ont écrit le micrologiciel voulaient garder les choses simples pour eux-mêmes, vous pouvez donc commencer par supposer qu'il y a 8 bits de données quelque part. Maintenant, voyez si l'un des messages a du sens.

Appelons un long 1 et un court 0. Cela pourrait être l'inverse, mais nous devons commencer quelque part. Dépouillant le bit de départ laisse:

1010001101011010 accélération min.
1010011101011000 accélérateur max.
1010000001011111 min en avant
1010000000011110 max avant
1010000011011101 max retour
1010000100011010 min en arrière
0000010101011100 max gauche + max papillon
0100010101011110 max droite + max papillon
1010000101111111 garniture gauche
1010000101011011 garniture droite

Quelques choses ressortent tout de suite. De toute évidence, le bit 0 est un bit de parité. Sinon, il semble y avoir un champ de 3 bits <15:13>, une valeur de données de 8 bits <12: 5> et un autre champ de 4 bits <4: 1>.

Il semble que la valeur des données soit envoyée par ordre de bits faible à élevé, il est donc probablement plus logique d'interpréter les 16 bits entiers à partir de ce que je montre.

Je n'ai pas envie de passer plus de temps là-dessus, mais j'espère que cela vous a donné un bon départ. Je procéderais en réécrivant la liste ci-dessus avec le bit de parité retiré, le nombre entier retourné LSB en MSB, et chaque champ supposé montré séparément avec un espace entre lui et le champ contigu. Cela pourrait permettre à davantage de vous sortir. Gardez également à l'esprit que nous pouvons avoir le sens 1/0 de chaque bit en arrière. Peut-être écrivez le nouveau tableau dans chaque sens et voyez si quelque chose a plus de sens dans un sens.

Olin Lathrop
la source
Merci, c'est excellent! Je vais aller droit au but et voir ce que je trouve. Après avoir examiné d'autres protocoles, j'ai commencé à penser que les espaces n'étaient peut-être pas pertinents, mais comme ils avaient deux horaires très cohérents, je n'en étais pas si sûr. J'ai pensé qu'ils varieraient davantage s'ils n'étaient pas importants. Quoi qu'il en soit, je vais l'essayer. Merci encore
Flambino
Huh ... pour autant que je peux dire, les espaces font la matière. Je me suis concentré sur l'accélérateur et j'ai capturé quelques échantillons supplémentaires à 10 positions d'accélérateur différentes. L'exclusion d'espaces ne m'a donné aucun chiffre significatif quelle que soit la façon dont j'ai effectué les conversions. Mais les inclure comme long = 1, short = 0 donne une progression en douceur de la valeur de l'accélérateur de 1 à 134 (petit endian). Toujours en train de travailler sur les autres paramètres
Flambino
J'ai le protocole presque entièrement compris, mais il y a encore un peu de mystère. Ajout d'une tonne de trucs à ma question, si vous voulez faire un swing. Quoi qu'il en soit, merci pour votre aide jusqu'à présent! Me fait travailler dans la bonne direction.
Flambino
@Flambino: On dirait que vous êtes bien en avance sur ce que j'ai fait pour commencer, ce qui s'est avéré être la plupart du temps de mauvaises suppositions avec le recul. J'ai lu votre question mise à jour mais je ne comprends toujours pas exactement comment la longueur des espaces est utilisée. Était-ce juste une coïncidence que tous les modèles que vous avez montrés avaient exactement 17 impulsions et que le dernier est arrivé à indiquer la parité si seulement les impulsions sont prises pour être 0 ou 1?
Olin Lathrop
Honnêtement, c'était surtout des essais et des erreurs de ma part. Étant donné que les 2 timings utilisés pour les espaces sont tout aussi exacts que les timings d'impulsion, j'ai pensé qu'ils pourraient être significatifs. Et, lorsque l'ignorance des espaces n'a pas donné de données binaires utiles, j'ai simplement supposé une impulsion longue = 1 et un espace long = 1 (et un espace / impulsion court = 0), ce qui m'a immédiatement donné des données très utiles. Ainsi, le premier espace après l'impulsion de préambule est le premier bit (le graphique d'accélération max droite + max montre un "espace 1" comme premier bit) suivi de 16 impulsions, avec 15 espaces supplémentaires entre les deux; 32 bits.
Flambino