制作简单的RC航空船

有时,在Internet上,我会遇到初学者提出的问题,他们想从头开始建造直升机并为其编写固件。我本人就是这样,为了练习创建RC模型,我决定从简单的事情开始。



他在最小的文章中详细介绍了船的算法,控制面板和组件的选择。

为什么要乘高空船?


  1. 简单
  2. 便宜
  3. ;
  4. , -.

飞行器很棒,但是很难。在空中,如果出现问题,您不能只关掉螺丝。是的,即使飞机,也需要非常好的推力,更不用说多直升机了。

这样的平台



此处有更详细的描述)。

在大多数情况下,它们只能沿着人造的光滑表面移动,并且它们的控制方式非常不同。

但是在水上我们可以在任何地方航行,这将来会给我们提供使用GPS进行自动驾驶的机会。带有螺旋桨的经典设计对我来说是很复杂的,因为从外壳上出来的轴出口单元-我无法想象如何密封它。

空气推进系统的更多优势:
  1. 它可以放在不同的平台上:船,雪橇,一块聚苯乙烯...
  2. 它不会卡在底部或藻类上。

设备必须旋转。有3个选项:
  1. 一圈螺丝+方向盘 ;
  2. 一螺丝+车削系统 ;
  3. 两个固定螺钉。改变他们的渴望是最简单的方法。他用了。


遥控功能


工作原理


1个操纵杆+多个开关。遥控器的任务是在操纵杆手柄的位置上发送数据并每秒切换几次。

怎么办


首先,您需要一个无线电发射器。最便宜的选择是NRF24L01 +,价格为$ 0.85

其次,您需要一个操纵杆。另外1美元

几个开关- $ 0.12

好吧,所有这些都以0.13美元的价格固定在一块PCB上

已经算了2.1美元,但仍然需要MK和食物。这里的一切还不是很清楚。

展望未来,我会说ATmega8或STM8S103F3P6足够了,但是由于我开始了这个项目很长时间,而且经验很少,所以我将它撞到了Arduino Pro Mini控制面板和Arduino Nano船上(到处都是ATmega32P)。

在远程仍然需要:
  1. 电源转换器0.9-5 V-> 5 V,可为Arduino供电,价格为0.35美元(USB连接器和一块电路板可以断开,以实现紧凑性);
  2. 用于给无线电模块供电的3.3V稳定器AMS1117-3.3,每单位成本为0.03美元
  3. 一根手指电池的电池盒价格为0.15美元 ;

总计加$ 0.53。除了控制器,一对电容器和电线外,控制台组件的成本为2.63美元。

RC模型填充


组成部分


一切都来自引擎。您购买的发动机,电子设备都必须安装有这种功率,并且需要底座(船,雪橇)来提供相应的承载能力。从意识形态上讲,仅需要以正确的速度旋转螺钉,就需要进行其他所有操作。

我在这里买与螺旋桨发动机


每双2.88 $

我把L293D当作电动机驱动器-另一个0.35美元
然后有一个问题
L293D . , .

食物。我们将需要多达三个电源电压:
  1. 除无线电模块外,所有电子设备的电压为5 V;
  2. 无线电模块为3.3 V;
  3. 用于尽可能多的电动机(最小4.2 V)。

1和2与控制面板中的相同,对于电机,我们将MT3608的价格$ 0.86

现在最有趣的部分是:陀螺仪。MPU-6050模块的价格为1.53美元希望也使用加速度计,以便当操纵杆移至侧面时,船舶就位。但是最后,他放弃了这个想法:略微的俯仰斜率,系统开始认为它正在向前或向后加速。事实证明,仅通过操纵杆补偿向前/向后运动,就可以更轻松地将船转到适当的位置。

再加上0.4美元即可获得2个AA电池的电池盒,并获得6.4美元的组件,无需控制器和电线。

程序


再说一遍,让我们从引擎出发。L293D驱动的两个引擎中的每个引擎可能会或可能不会挖
  1. 向前旋转;
  2. 回旋;
  3. 不要扭曲。

为了使代码更易于阅读,请编写
6功能
inline void motLeftStop(){
  PORTD &= ~(1 << MOT_LEFT_PLUS);
  PORTD &= ~(1 << MOT_LEFT_MINUS);
}

inline void motLeftForward(){    
  PORTD |= 1 << MOT_LEFT_PLUS;
  PORTD &= ~(1 << MOT_LEFT_MINUS);
}

inline void motLeftBackward(){
  PORTD &= ~(1 << MOT_LEFT_PLUS);
  PORTD |= 1 << MOT_LEFT_MINUS;
}

inline void motRightStop(){
  PORTD &= ~(1 << MOT_RIGHT_PLUS);
  PORTD &= ~(1 << MOT_RIGHT_MINUS);
}

inline void motRightForward(){
  PORTD |= 1 << MOT_RIGHT_PLUS;
  PORTD &= ~(1 << MOT_RIGHT_MINUS);
}

inline void motRightBackward(){
  PORTD &= ~(1 << MOT_RIGHT_PLUS);
  PORTD |= 1 << MOT_RIGHT_MINUS;
}


现在我们要控制螺钉的旋转速度。当然,我们将使用PWM进行此操作。我不知道这样的PWM是否可以在硬件中完成...我以编程方式中断了它。声明一对全局变量
int8_t motLeft = 0, motRight = 0; // -127..+127

让这些变量的值<0表示您需要向后旋转,值> 0-向前,如果它们为0,则不需要扭曲。
我们将编写计时器中断处理程序
ISR(TIMER2_OVF_vect)
{
  if(motLeft > 0)
    motLeftForward();
  else if(motLeft < 0)
    motLeftBackward();
  if(motRight > 0)
    motRightForward();
  else if(motRight < 0)
    motRightBackward();
}

ISR(TIMER2_COMPA_vect)
{
  motLeftStop();
}

ISR(TIMER2_COMPB_vect)
{
  motRightStop();
}


现在,要更改螺旋桨的旋转速度,我们需要执行2个操作:
  1. 在motLeft / motRight中写入正,负或零值(模块不重要);
  2. 在OCR2A / OCR2B中记录“转速”。

让我们为此编写更多的功能
void setMotLeft(int8_t v){ // -127..+127
  if(abs(v) < 5) v = 0;
  motLeft = v;  
  OCR2A = abs(v) * 2;
}

void setMotRight(int8_t v){ // -127..+127
  if(abs(v) < 5) v = 0;
  motRight = v;
  OCR2B = abs(v) * 2;
}


if(abs(v) < 5) v = 0;

OCR2x 5 ( ).

现在剩下的是配置MK引脚和计时器
void motInit(){
  DDRD |= (1 << MOT_LEFT_PLUS) | (1 << MOT_LEFT_MINUS) | (1 << MOT_RIGHT_PLUS) | (1 << MOT_RIGHT_MINUS);
  //TCCR2B |= (1 << CS22)|(1 << CS21)|(1 << CS20); // set up timer with prescaler = 1024.   16 
  //TCCR2B |= (1 << CS22)|(0 << CS21)|(0 << CS20); // set up timer with prescaler = 64.   1 
  TCCR2B |= (0 << CS22)|(1 << CS21)|(0 << CS20); // set up timer with prescaler = 8.  128 
  //TCCR2B |= (0 << CS22)|(0 << CS21)|(1 << CS20); // set up timer with prescaler = 1.  16 
  TIMSK2 |= (1 << TOIE2)|(1 << OCIE2A)|(1 << OCIE2B); // enable overflow interrupt
  TCCR2A &= ~(3); // set WGM20 = 0, WGM21 = 0
  TCCR2B &= ~(1 << 3); // set WGM22 = 0
  setMotLeft(0);
  setMotRight(0);
  sei();
}


您只需调用函数setMotLeft(int8_t v)和setMotRight(int8_t v),即可控制电动机。

但是我们要控制船不对!我们要发出“前进/后退”和“右/左”之类的命令!让她找出为此必须扭转的螺旋桨。此外,我希望船本身能够补偿风,洋流和弯曲螺旋桨的转向作用!

让我们从另一边开始。从遥控器。在最简单的情况下,其操作算法如下:
  1. 打开电源时,请记住操纵杆的初始位置。
  2. 在循环中,读取操纵杆的位置,从中减去零位置,然后将数据发送到船上。

我们的无线电模块最多支持32个字节的数据包。为了不记住位移,我们将使用记录
struct ControlStatus{
  int16_t x,y;
}  controlStatus;

如下
    uint8_t packet[MAX_BUFF]; 
    memset(packet, 0, MAX_BUFF);    
    controlStatus.x = (int16_t)analogRead(1) - x0;
    controlStatus.y = (int16_t)analogRead(0) - y0;
    memcpy(packet, &controlStatus, sizeof(controlStatus));
    Mirf.send(packet);
    while(Mirf.isSending()){;};


在接收方,我们将声明完全相同的记录,
我们将填充它
  while (Mirf.dataReady()) { 
    uint8_t data[MAX_BUFF];
    Mirf.getData(data);
    memcpy(&controlStatus, data, sizeof(controlStatus));
    setMotRot(-controlStatus.x);
    setMotForward(controlStatus.y); 
  }


在函数setMotRot和setMotForward中
将值写入全局变量motRot和motForward
void setMotRot(int16_t v){
  if(abs(v)<10) v = 0;
  motRot = (int32_t)v;
}
void setMotForward(int16_t v){
  if(abs(v)<10) v = 0;
  motForward = (int32_t)v;
}


让我们继续进行最有趣的事情。关于如何转换“以每秒5度的速度向左转并向前移动一点!” 改为“左引擎后退10%,右引擎前20%!”。

关于什么是PID控制器,已经很多著作。我只使用了两个旋转组件:
  1. 比例
  2. 积分。

对于来回移动,监管机构没有使用它。

让我们举个例子:
int32_t iDeltaRot = 0;
void motTick(){
  int32_t rot = getRotAvg(); //     
  int32_t deltaRot = rot - motRot * rotMaxSpeed / 512;
  iDeltaRot += deltaRot;
  int32_t motRight = (int32_t)motForward * forwardMult - deltaRot * rotMult - iDeltaRot * iDeltaRotMult, 
          motLeft  = (int32_t)motForward * forwardMult + deltaRot * rotMult + iDeltaRot * iDeltaRotMult;  

  int32_t motMax = max(abs(motRight), abs(motLeft));
  if(motMax > 127){
    motRight = (int32_t)motRight * 127 / motMax;
    motLeft  = (int32_t)motLeft  * 127 / motMax;
  }
  
  setMotRight(motRight);
  setMotLeft(motLeft);
}

简化了代码,以专注于重要部分;存档将具有完整版本。

我们在这里做什么?
  1. 我们计算船的实际旋转速度(rot)与所需的实际旋转速度(motRot * rotMaxSpeed)之间的差;
  2. 我们计算出motRight和motLeft螺钉的期望转速;
  3. 如果所需的旋转速度超过最大可能的速度,则在保持两者之间的比率的同时降低它们。
  4. 我们称我们已经熟悉的setMotRight / setMotLeft。

仅此而已!

这就是整个船的控制算法!

有困难吗?我认为不是。但是,尽管如此,在测试和调整过程中出现了很多问题,如果是飞机,则会导致大量坠机。

所描述的函数中有4个系数:
  1. forwardMult-对操纵杆前进/后退运动的敏感性;
  2. rotMaxSpeed-完全向右/向左倾斜操纵杆时所需的旋转速度;
  3. rotMult-比例分量的系数(当前转速与所需转速之间的偏差会影响旋转多少);
  4. iDeltaRotMult-积分分量的系数(当前转角与所需转角的偏差在多大程度上影响旋转)。

这些系数是通过实验调整的,船对操纵杆的反应和外部展开的影响将取决于它们。

状态指示


在调试/调试时,“为什么船对操纵杆的反应不是我想要的那样?”系列中会有一些困惑。可以通过在PC上显示调试信息来调试某些点,但是,更方便地了解当场发生的事情。首先,我考虑了2种选择:
  1. 笔记本电脑;
  2. LCD诺基亚5110


两者的缺点都是可以理解的:笔记本电脑很大且不便于携带,诺基亚5110显示屏不允许您同时显示大量的船况参数。

我在他们之间进行了交叉:Nextion增强型NX4827K043-通用4.3英寸HMI触摸显示器借助触摸屏,您可以在旅途中快速方便地调整船只参数。这是一种计算机,包括:
  1. 单片机GD32F103R8T6;
  2. SDRAM华邦W9864G6KH-6(8 MB);
  3. 华邦W25Q256FVFG闪存(32 MB,100,000个重写周期,非常好);
  4. FPGA Altera MAX II EPM570T144C5N。

组装中的所有内容都看起来像这样(可单击): 此计算机/显示器是一个黑匣子,旨在与人互动。甚至现有的GPIO也经过了改进,可以连接按钮和指示器。他们的扩展委员会对此进行了确认。因此,将内置控制器用作船的遥控器(读取操纵杆,与无线电模块NRF24L01 +交换数据)将失败。要与微控制器进行交互,需要使用UART,仅此而已。 关于如何使用此显示器可以完成什么工作,Youtube上写了很多+视频。你看,例如,在这里它是





-一切都清楚地显示在那里。但是由于此显示器比船上所有其他组件和控制台的总和还贵,因此我将更详细地描述使用它的印象。也许这将有助于某人了解此选项是否适合他,或者更适合使用诺基亚5110笔记本电脑/显示器。Nextion增强型NX4827K043的优点:
  1. 很好用。在YouTube上有简单的文档,示例,视频,...在几个小时内,您可以从头开始解决。您几乎需要了解有关他的所有内容都在两页上:Wiki页指令集
  2. 发展很快。像Visual Studio这样的可视编辑器(只会更简单)。我扔了组件,一切正常。
  3. 高品质的组件。相同的闪存可进行100k重写周期。
  4. 调试器,可以使用PC模拟显示并通过COM端口与MK通信。仅在一切正常后,您才能充分开发设备,调试并购买显示器。
    虽然他有问题
    . . , , .
  5. 电阻式传感器 您可以创建相当小的控件,并用指甲或任何手写笔戳一下它们。

缺点:
  1. 价钱 对于4.3英寸的显示屏,50美元仍然很多。
  2. 现有组件很少,组件设置很少,如何创建自己的组件还不清楚。绘制图元(线,矩形,圆等)的功能部分抵消了此功能。
  3. 升级后,标准量规组件会闪烁。
  4. 没有(至少我没有找到)透明度。
  5. 电源要求:4.75-7 V,平均电流250 mA。电压下降时,显示屏开始闪烁。
  6. 仅UART。可以在SPI和I²C上与他进行通信。
  7. GPIO输出仅用于电缆(无梳状2.54 mm),无ADC。


通常,显示器给人的印象是非常高质量的产品,使用起来既轻松又愉快。

显示器可以一次执行两项任务:
  1. 状态指示。我主要感兴趣:
    • 螺钉的“转速”;
    • iDeltaRot变量的值是所需的转弯角与所需的转角相差多少;
    • 船转速
    • 船的旋转角度;
    • 从遥控器接收数据包的频率;
    • motTick函数的调用频率。

  2. 设置参数,即上述的forwardMult,rotMaxSpeed,rotMult,iDeltaRotMult。


制作2页(可点击进行质量评估):
  1. 适应症:


  2. 参数设置: 从左到右的前4列:forwardMult,rotMult,iDeltaRotMult,rotMaxSpeed。






地板上的视频测试船:



船在各种iDeltaRotMult(积分系数)下对外部展开效果的反应:



演示参数对水的影响:



无法在露天拍摄视频。您可以相信他的处理方式很好,并且最大速度不是很高。

特点


  • 杆9克;
  • 重115克,其中电池重52克;
  • 最大加速度为0.77 m / s ^ 2。以人类5 km / h的速度,如果没有防水性,船将在1.8 s内加速;
  • 如果您在遥控器和船上使用Arduino Nano(不带显示器和电池),则组件的成本约为15美元。


结论


对于那些希望收集无线电控制的东西的人,我建议从带有两个固定螺旋桨的船只开始。我认为,这是该领域中最简单的事情。

项目存档

最后,为了有所作为,下面是一个很棒的设备的视频:

Source: https://habr.com/ru/post/zh-CN390429/


All Articles