我冒昧地回答我自己的问题,因为我已经弄清楚了大部分问题,这是分享我的发现的好方法。感谢 Olin Lathrop 给了我一个开始的地方和一些尝试的想法,但最终,该协议与 Olin 的猜测完全不同,因此我发布了这个答案。
更新:我发布了一个关于最后 8 位的后续问题,我并不完全理解,Dave Tweed 弄明白了。我将在此处包含详细信息,因此此答案可以作为完整的协议规范使用,但请务必查看 Dave 的答案。
我不得不尝试一些不同的事情来解决这个问题,但我很有信心我明白了。奇怪的是,我在其他地方没有发现任何类似这个协议的东西,但它很可能是一个我不知道的通用协议。
无论如何,这就是我发现的:
协议/编码
脉冲和其间的空间都用于对数据进行编码。长脉冲/间隔是二进制一 (1),短脉冲/间隔是二进制零 (0)。脉冲使用标准消费红外 38kHz 调制 @ 50% 占空比发送。
脉冲/空间时序在原始问题中,但为了完整起见,我将在这里重复它们:
Bit Pulse Space
-----+---------+---------
0 | 275µs | 285µs
1 | 855µs | 795µs
所有 ±10µs 最大值,±5µs 典型值。这是基于用逻辑分析仪在 16MHz 捕获的样本;我没有示波器,所以我不知道确切的配置文件(即上升/下降时间)。
只要应用了控制输入,数据包就会重复,并且看起来至少相隔 100 毫秒。
数据包传输以“脉冲 1”前导码开始,它是固定的,不是数据的一部分。下面的空间编码数据包的第一个数据位,最后一个脉冲编码最后一个位。
每个数据包长 32 位,包含遥控器可以提供的每个输入。值以小端方式读取,即 MSB 在前。
数据结构
下面是各个数据包的基本结构。最后 8 位让我感到困惑,但现在已经弄清楚了(见下文)。
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
注意:范围是基于我得到的最高读数。该协议能够实现更大的范围——油门最高 255,俯仰/偏航 63——但上限约为一半。
音高值似乎有一个从 14 到 21(含)的死区;只有高于或低于的值才会真正使直升机做出反应。我不知道偏航是否相同(很难说,因为直升机无论如何都不稳定,并且可能会自行轻微旋转)。
这是图形术语(与原始问题中的图形比较)
6 个校验位是通过对所有前面的值进行异或来计算的。每个值被视为 6 位。这意味着 8 位限制值的 2 个 MSB 被简单地忽略。IE
check = yaw ^ (throttle & 0x3F) ^ pitch ^ trim ^ channel
实用笔记
信号时序和调制不需要非常精确。与真正的遥控器相比,即使是我的 Arduino 的完全不准确的计时也能正常工作,尽管调制很狡猾,脉冲/空间持续时间有一点点命中和失误。
我相信 - 但尚未测试 - 直升机将简单地锁定它发现的第一个信号的通道。如果它长时间没有信号(几秒钟),它似乎会回到它的“搜索”模式,直到它再次获得信号。
如果油门为零,直升机将忽略俯仰和偏航值。
每次按下遥控器上的按钮,修剪命令仅发送一次。据推测,微调值只是增加/减少直升机自身控制器中的值;这不是遥控器跟踪的东西。因此,任何对此的实现都应该遵循该方案,并且只发送偶尔的修剪左/右值,否则默认为数据包中的零修剪值。
我建议有一个简单地将油门设置为零的终止开关。这将导致直升机从天上掉下来,但当它不旋转电机时,它受到的伤害会更小。因此,如果您即将坠毁或撞到什么东西,请按下终止开关以避免剥落齿轮或折断刀片。
原始遥控器的 IR LED 的波长似乎 >900nm,但我使用 ~850nm LED 没有问题。
直升机的红外接收器还可以,但不是超级敏感,所以你的红外源越亮越好。遥控器使用 3 个串联的 LED,位于 9V 导轨上,而不是逻辑使用的 5V 导轨上。还没有非常精确地检查他们的电流消耗,但我敢打赌它是 50mA。
样本数据
这是一堆数据包,供任何感兴趣的人使用(是的,我编写了一个解码器;我没有手动解码所有这些)。通道 A 数据包来自与原始问题中的图表相同的捕获。
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
如上所述,最后8位已经弄清楚了,但只是为了后人,这里是我的原始想法。随意完全忽略它,因为我的猜测非常错误。
最后 8 位
数据包的最后 8 位仍然有点神秘。
第 23 位到第 26 位这 4 位似乎完全由遥控器的频道设置决定。更改遥控器上的频道不会以任何方式改变协议或调制;它只会改变那 4 位。
但是 4 位是编码通道设置实际需要的两倍;只有三个通道,所以 2 位就足够了。因此,在上面的结构描述中,我只将前 2 位标记为“通道”,而将其他两个标记为“X”,但这是一个猜测。
下面是每个通道设置的相关位示例。
Chan. Bits 23-26
-----+-------------
A | 0 1 0 1
B | 0 0 1 0
C | 1 0 0 0
基本上,传输通道设置需要多出 2 位。也许该协议预留了 4 位以便稍后允许更多通道,或者该协议可以用于完全不同的玩具,但我根本不知道。对于较大的值,该协议确实使用了可以省略的额外位(偏航/油门/俯仰每个都可以少一点),但是对于修剪 - 它也有 3 个状态 - 只使用了 2 个位。因此,人们可能会怀疑该通道也只有 2 位,但这使得接下来的 2 位下落不明。
另一种可能性是数据包的校验和是 8 位长,从“X 位”开始,并且 - 通过校验和魔法 - 它们恰好以某种方式总是反映通道设置。但再说一遍:我不知道。
说到:我不知道这些校验位是如何形成的。我的意思是,它们是校验位,因为它们不对应于任何单个控制输入,而且如果我摆弄它们,直升机似乎没有响应。我猜这是某种CRC,但我无法弄清楚。检查的长度为 6-8 位,具体取决于您如何解释“X 位”,因此有很多方法可以放在一起。