FPV飞行员有时间在赛车和持续故障中休息一下,拿起烙铁,并为他的爱好制作一些有用的东西,这是北纬的冬季。由于外面很冷,我们将在模拟器上训练飞行员技能。为此,您需要通过特殊适配器将无线电设备连接至计算机,该适配器将遥控器上的PPM信号转换为计算机可以理解的USB操纵杆信号。当然,这种适配器并不罕见,在中国商店中只花一分钱。但是,订单的交付需要等待很长时间,它是否可以按我们预期的那样工作?例如,我有一个:由于某些我尚未理解的原因,他断然拒绝在FPV Freerider模拟器中进行适当的校准,尽管它在Phoenix RC和Aerofly RC 7中表现出色。有免费的演示模式。解决-我们自己制造适配器!一点设备:
大多数或多或少严重的RC设备都有一个连接器,可在其中以PPM(脉冲位置调制)格式输出控制信号。PPM信号是一系列短脉冲,它们之间的间隔决定了无线电设备每个信道的控制值。PPM的精髓完美地传达了图像:要对PPM进行解码,您需要准确测量连续脉冲之间的时间间隔(在哪个边沿之间:前边还是后边无关紧要,因为脉冲本身的持续时间总是相同的)。实现方式:
从AlexeyStn的一篇文章中 汲取灵感,该文章关于基于STM32F3Discovery创建PPM到USB适配器,但是只有具有USB硬件支持的Arduino Pro Micro(Leonardo),让我们开始一条简单的适配器路径。您可以在github上找到一些类似的项目,有些甚至在控制器中甚至不需要硬件USB。但是,大多数文件都需要认真完成以使某些文件正常工作。合适的项目是rc-leonardo-joy,它在填入草图后几乎立即开始工作,但立即显示出一些缺陷:所有操纵杆读数都不十分稳定-控制面板中的光标标记始终在设定点附近摆动。我不能说这严重影响了模拟器的操作,但是我们想训练优质的设备!好了,我们进入代码,看到:PPM脉冲宽度的计算是通过处理外部中断并测量对micros()函数的调用之间的间隔来完成的:void rxInt(void) {
uint16_t now,diff;
static uint16_t last = 0;
static uint8_t chan = 0;
now = micros();
sei();
diff = now - last;
last = now;
if(diff>3000) chan = 0;
else {
if(900<diff && diff<2200 && chan<RC_CHANS ) {
rcValue[chan] = adjust(diff,chan);
}
chan++;
}
}
在Arduino文档中
阅读有关micros()函数的信息:返回自Arduino开发板开始运行当前程序以来的微秒数。大约70分钟后,该数字将溢出(返回零)。在16 MHz的Arduino板上(例如Duemilanove和Nano),此函数的分辨率为4微秒(即返回的值始终是4的倍数)。在8 MHz的Arduino板上(例如LilyPad),此功能的分辨率为8微秒。
也就是说,该函数不仅不是特别精确,并且始终返回4 s的倍数的值,而且在70分钟后也会溢出,从而为我们提供了所测量间隔的某种弯曲值。不好 最好使用计时器及其中断来捕获外部信号。我们进一步观察:操纵杆位置上的大多数数据被人为限制为一个字节(0-255):
byte stickValue(int rcVal) {
return map( constrain(rcVal - 1000, 0, 1000), 0, 1000, 0, 255);
}
嗯,我想更精确一些。但是为此,您将不得不重写HID描述符并更正所有相关的数据类型。快说不做!我们分叉存储库,重写代码以使用计时器来计数PPM间隔:void initTimer(void) {
TCCR1A = 0;
TCCR1B = (0<<ICNC1) | (1<<ICES1) | (1<<CS11);
TCCR1C = 0;
TIFR1 = (1<<ICF1);
TIMSK1 = (1<<ICIE1);
}
...
ISR(TIMER1_CAPT_vect) {
union twoBytes {
uint16_t word;
uint8_t byte[2];
} timeValue;
uint16_t now, diff;
static uint16_t last = 0;
static uint8_t chan = 0;
timeValue.byte[0] = ICR1L;
timeValue.byte[1] = ICR1H;
now = timeValue.word;
diff = now - last;
last = now;
if(diff > (NEWFRAME_PULSE_WIDTH * TIMER_COUNT_DIVIDER)) {
chan = 0;
}
else {
if(diff > (MIN_PULSE_WIDTH * TIMER_COUNT_DIVIDER - THRESHOLD)
&& diff < (MAX_PULSE_WIDTH * TIMER_COUNT_DIVIDER + THRESHOLD)
&& chan < RC_CHANNELS_COUNT)
{
rcValue[chan] = adjust(diff, chan);
}
chan++;
}
}
在HID描述符中将摇杆偏差间隔增加到0-1000:
0x05, 0x01,
0x09, 0x04,
0xa1, 0x01,
0x85, JOYSTICK_REPORT_ID,
...
0xA1, 0x00,
0x09, 0x30,
0x09, 0x31,
0x09, 0x33,
0x09, 0x34,
0x15, 0x00,
0x26, 0xE8, 0x03,
0x75, 0x10,
0x95, 0x04,
0x81, 0x02,
0xc0,
0xc0
在此过程中,无论发送杆偏差值的位置如何,都将uint8_t更改为uint16_t。我们删除了多余的代码,添加了一打#define,我们得到了一个很好的草图,经过了改进,可以用作PPM-USB适配器。结果在github中可用:github.com/voroshkov/Leonardo-USB-RC-Adapter草图设置:
如果您有其他硬件,则删除futaba的定义很有意义:#define FUTABA
如果您的设备产生其他计时,并在必要时调整参数中的微秒值:#define STICK_HALFWAY 500
#define STICK_CENTER 1500
#define THRESHOLD 100
编译:
要编译和上传草图,需要在备份后替换Arduino环境本身中的USB库。为此,请沿着以下路径进入Arduino的肠道... \ Arduino \ hardware \ arduino \ cores \ arduino \,备份usbapi.h和hid.cpp,然后用存储库中ArduinoLibs文件夹中的相同文件覆盖它们。接下来,打开草图,连接Arduino Leonardo并填充它。连接方式:
一切都很丑陋:一方面,我们插入USB,另一方面,我们将两条线(在数字引脚4和地面上)焊接在一起,并将其分别粘贴到变送器的PPM和地面上。原来是这样的:在Windows 7中,该设备被识别为名称为Arduino Leonardo的复合材料(键盘,鼠标,操纵杆)。特别值得一提的是设备中的连接器。在某个地方是普通音频插孔,在某个地方(例如在我的Futaba 7C中)比较棘手:对于组装各种“公”连接器,我长期以来一直成功使用热胶。为此,我们将纸或聚乙烯放在“母亲”上,用针刺穿该基材,使它们粘到另一侧的连接器中,然后逐渐在针之间倒入胶水,同时用湿手指使它成形。当然,电线需要预先焊接,以免在焊接时熔化固化的粘合剂。结果并不总是美观,但非常实用:(这里,在连接器中,明确定位需要4个引脚,只有两个工作人员。)就是这样。我们下载模拟器,连接设备并训练飞行员技能,同时在黑暗的冬天晚上在壁炉前喝热茶。聚苯乙烯
如果没有Arduino Leonardo,但STM32F103C8T6上有这样的最低开发板怎么办?
不用担心,一路走来。对于您以及我自己的开发,我移植了已经提到的 Alexey Stankevich 项目。可以在此处找到要上传到该控制器的源代码和已编译的二进制文件:github.com/voroshkov/STM32-RC-USB-Adapter。我将在评论中愉快地回答所有问题。祝您飞行愉快!