首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >遥控直升飞机协议解码+原理解读

遥控直升飞机协议解码+原理解读

作者头像
云深无际
发布2021-11-19 12:58:15
发布2021-11-19 12:58:15
1.3K0
举报
文章被收录于专栏:云深之无迹云深之无迹

童年特别想要的小飞机,现在5块一个。。。,找了个朋友,整了一包回来了。想要的也可以私信我,拼着买,才便宜!

买了好多。。。

捡了垃圾我必然是想搞逆向的,不然能干嘛。。。

先说原理,在说协议~

我查原理一般是用谷歌学术查

很好用

还能导出文件做一些后处理

代码语言:javascript
复制
https://patents.google.com/

这个原理上面比较复杂,我只讲一点,等我有时间我再编辑一篇好文,现在就是简单的写写。

桨距和桨叶角

桨距指的是直升机的旋翼或固定翼的螺旋桨旋转一周360度,向上或向前行走的距离(理论上的)。就好比一个螺丝钉,拧一圈后,能够拧入的长度。桨距越大前进的距离就越大,反之越小!桨叶角也叫攻角,是指桨叶角指桨叶与垂直于主轴平面的夹角。可以直接测量。

换算公式为: 桨距=2πRtan(桨叶角),其中R为所计算位置与主轴的距离。

对于绝大多数的模型直升机,为了满足特技飞行的需要使用的旋翼常常是不等距旋翼,旋翼的外侧桨距大,内侧桨距小。对于这一类模型直升机,常常不使用桨距这一概念,取而代之的是桨叶角这一概念,桨叶角指旋翼与垂直于主轴平面的夹角。在不等距旋翼中,各处的桨叶角是相等的。

对于如图所示的简易直升机,使用的是等距旋翼,这种旋翼各处桨距相等,但是内侧桨叶角大,外侧桨叶角小。这种旋翼升力大,效率高,但是无法实现特技飞行。

这满满的廉价感。。。

这个东西叫:倾斜盘(也叫十字盘)以及各种连杆和跷跷板结构。

这种三通的直升飞机用的是双浆反向旋转设计的,上下浆反向旋转,如果扭力刚好相同者三通飞机左右转向靠的就是这原理。一般起飞时是刚好平衡的,三通的遥控器上会有微调。

直升飞机向前飞的原因是主螺旋翼和副螺旋翼不平行,副螺旋翼前倾,导致它旋转的时候会向后施加一个力道,这个力使得飞机向前飞。

贝尔-希拉操纵方式

找到两个玩具的专利,下面展示一下:

就是加了个大圈

尾翼双螺旋桨(这是一个玩具的专利)

关于这个控制协议,我找了一下,这个价位的东西应该是用的红外线控制的。然后协议也比较明了了。

16M的速度就可以把所有的信息保存下来。

代码语言:javascript
复制
https://qastack.cn/electronics/94343/help-with-or-hints-for-decoding-an-ir-protocol

拆机

它这里是把这个发射的电路怼示波器口子上面了

波形是使用油门和方向控制杆设置的组合记录的(点击放大)。为了获得这些波形,将示波器设置为深存储器模式,并对每次运行的结果进行调整,以便对齐命令的开头。请注意,X 轴不代表时间,它仅代表我的示波器屏幕截图中的像素数。

从上面的波形捕获可以看出,每个信号由 34 个脉冲组成。由于数字系统的信息以字节表示,因此可以合理地假设脉冲形成一个 4 字节的信号,其中额外的两个脉冲作为首部。基于此假设,第一个高-低-高转换标志‍着命令的开始。在这里,我将其称为头。由于脉冲宽度相同(头部除外),因此通过低电平的持续时间区分 1 和 0。下图显示了信号的时序:

‍‍‍‍‍‍‍‍

38Khz的载波模式:

代码语言:javascript
复制
命令持续时间:180 毫秒
标头高持续时间:2.04 毫秒
标题低持续时间:2 us
脉冲宽度:380us 
0 的低持续时间:220 us
1 的低持续时间:600 us

57Khz的载波模式:

代码语言:javascript
复制
命令持续时间:160 毫秒
1 的低持续时间:660 us
代码语言:javascript
复制
No. Throttle  Direction                  Binary                              Dec(Hex)
00    ~0%      Middle       00111100 00111111 10001011 00110100    60(3C)  63(3F)  139(8B) 52(34)
01   ~25%      Middle       00111100 00111111 10100111 00110100    60(3C)  63(3F)  167(A7) 52(34)
02   ~50%      Middle       00111100 00111111 11001000 00110100    60(3C)  63(3F)  200(C8) 52(34)
03   ~75%      Middle       00111100 00111111 11100110 00110100    60(3C)  63(3F)  230(E6) 52(34)
04   100%      Middle       00111100 00111111 11111101 00110100    60(3C)  63(3F)  253(FD) 52(34)
05   100%      Left         01101010 00111111 11111101 00110100    106(6A) 63(3F)  253(FD) 52(34)
06   100%      Right        00001000 00111111 11111101 00110100    8(8)    63(3F)  253(FD) 52(34)
07   100%      Forward      01000000 00000001 11111101 00110100    64(40)  1(1)    253(FD) 52(34)
08   100%      Backward     00111100 01111110 11111111 00110100    60(3C)  126(7E) 255(FF) 52(34)
09    ~0%      Left         01101010 00111111 10001101 00110100    106(6A) 63(3F)  141(8D) 52(34)
10    ~0%      Right        00001000 00111111 10001101 00110100    8(8)    63(3F)  141(8D) 52(34)
11    ~0%      Forward      01000000 00000001 10001101 00110100    64(40)  1(1)    141(8D) 52(34)
12    ~0%      Backward     00111100 01111101 10010001 00110100    60(3C)  125(7D) 145(91) 52(34)

解码表在此

Timer1 来生成 180 毫秒的命令重复间隔。Timer2 用于生成 38kHz 50% 占空比 PWM 载波信号。通过使用delayMicroseconds在所需持续时间内打开和关闭 38kHz 信号来生成0和1。

三个电位器分别用于控制转子速度(油门)、向前/向后运动和向左/向右旋转。由于校准可以提前完成,这里选择在代码中硬编码校准值以简化控制。当然,可以为此使用第四个电位计,就地调节。

简单的连线

正常控制

代码语言:javascript
复制
#include <TimerOne.h>

//comment this out to see the demodulated waveform
//it is useful for debugging purpose.
#define MODULATED 1

const int IR_PIN = 3;
const unsigned long DURATION = 180000l;
const int HEADER_DURATION = 2000;
const int HIGH_DURATION = 380;
const int ZERO_LOW_DURATION = 220;
const int ONE_LOW_DURATION = 600;
const byte ROTATION_STATIONARY = 60;
const byte CAL_BYTE = 52;

int Throttle, LeftRight, FwdBack;

void sendHeader()
{
#ifndef MODULATED
    digitalWrite(IR_PIN, HIGH);
#else
    TCCR2A |= _BV(COM2B1);
#endif

    delayMicroseconds(HEADER_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, LOW);
#else
    TCCR2A &= ~_BV(COM2B1);
#endif

    delayMicroseconds(HEADER_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, HIGH);
#else
    TCCR2A |= _BV(COM2B1);
#endif

    delayMicroseconds(HIGH_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, LOW);
#else
    TCCR2A &= ~_BV(COM2B1);
#endif
}

void sendZero()
{
    delayMicroseconds(ZERO_LOW_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, HIGH);
#else
    TCCR2A |= _BV(COM2B1);
#endif

    delayMicroseconds(HIGH_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, LOW);
#else
    TCCR2A &= ~_BV(COM2B1);
#endif
}

void sendOne()
{
    delayMicroseconds(ONE_LOW_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, HIGH);
#else
    TCCR2A |= _BV(COM2B1);
#endif

    delayMicroseconds(HIGH_DURATION);

#ifndef MODULATED
    digitalWrite(IR_PIN, LOW);
#else
    TCCR2A &= ~_BV(COM2B1);
#endif
}

void sendCommand(int throttle, int leftRight, int forwardBackward)
{
    byte b;

    sendHeader();

    for (int i = 7; i >= 0; i--)
    {
        b = ((ROTATION_STATIONARY + leftRight) & (1 << i)) >> i;
        if (b > 0)
            sendOne();
        else
            sendZero();
    }

    for (int i = 7; i >= 0; i--)
    {
        b = ((63 + forwardBackward) & (1 << i)) >> i;
        if (b > 0)
            sendOne();
        else
            sendZero();
    }

    for (int i = 7; i >= 0; i--)
    {
        b = (throttle & (1 << i)) >> i;
        if (b > 0)
            sendOne();
        else
            sendZero();
    }

    for (int i = 7; i >= 0; i--)
    {
        b = (CAL_BYTE & (1 << i)) >> i;
        if (b > 0)
            sendOne();
        else
            sendZero();
    }
}

void setup()
{
    pinMode(IR_PIN, OUTPUT);
    digitalWrite(IR_PIN, LOW);

    //setup interrupt interval: 180ms
    Timer1.initialize(DURATION);
    Timer1.attachInterrupt(timerISR);

    //setup PWM: f=38Khz PWM=0.5
    byte v = 8000 / 38;
    TCCR2A = _BV(WGM20);
    TCCR2B = _BV(WGM22) | _BV(CS20);
    OCR2A = v;
    OCR2B = v / 2;
}

void loop()
{
}

void timerISR()
{
    //read control values from potentiometers
    Throttle = analogRead(0);
    LeftRight = analogRead(1);
    FwdBack = analogRead(2);

    Throttle = Throttle / 4;        //convert to 0 to 255
    LeftRight = LeftRight / 8 - 64; //convert to -64 to 63
    FwdBack = FwdBack / 4 - 128;    //convert to -128 to 127

    sendCommand(Throttle, LeftRight, FwdBack);
}

宏变量和函数

一些固定参数

配置

关于直升飞机的原理我也参考了一些论文和专利

代码语言:javascript
复制
http://www.kerrywong.com/2012/08/27/reverse-engineering-the-syma-s107g-ir-protocol/
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-11-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 云深之无迹 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档