Archive for the ‘小制作’ Category

Arduino自带的Servo库小实验

之前有很多朋友问过我,为什么不用Arduino自带的Servo库来控制电机。我在动手做四轴之前,其实也大概看了下Servo库的说明,当时看到

servo.write(angle) 这个函数,其中angle(int)是角度,取值范围是0 到 180

我想当然的认为,这个servo库最多也就是180级的梯度来设置PWM,这样说来精度完全不够啊;另外也没有看到有地方能修改PWM频率。

总结了下我当时不用Servo库的原因:
1. 控制的级数太少,不够精确;
2. 不可修改PWM频率;
3. 需要使用特殊的几个脚;(不知道在什么地方看错了,留下的错误印象)

这几天obK仔给了很多建议,我也看了看源代码。现在看来,上面这几点都是我瞎操心了。

首先,0~180是servo库对应的从min到max的控制,对应于0.9ms到2.1ms的电调来说,angle参数加1对应的时间变化为:
(2.1-0.9)*1000/180 = 6.7微秒,已经是比较精确了。
即使这样如果还觉得不够精确,还可以使用servo.writeMicroseconds,这个函数可以直接用微秒作为参数。

其次,PWM频率是可以修改的,在Servo.h文件中,修改下面这行可以把PWM频率升到400Hz:
#define REFRESH_INTERVAL 2500
不过这只能在编译之前改,不能在程序运行的过程中动态修改。当然修改源代码也可以解决这个问题,把这个参数做成一个变量,用接口进行修改控制即可。

最后,Servo库可以绑定所有digitalWrite的脚,这一点来说,比原生的PWM还方便!

做了一个简单的小程序,测试Servo库同时控制4个电机的情况。实验结果看上去还不错,不过没有测试4个电机转速各不相同的情况。
代码果然看上去简洁多了:

Servo powerServo[4];
void setup()  
{
  motorPins[0] = 38;   //x1
  motorPins[1] = 43;   //x2
  motorPins[2] = 42;   //y1
  motorPins[3] = 39;   //y2
  for(int i = 0; i < 4; i++) powerServo[i].attach(motorPins[i]);
}
void loop()
{
  long t0 = micros(); //记录进入loop的时间
  while(Serial.available()) {
    // 这里是获取控制指令
    pushData(Serial.read());
  }
  double T = 2500; // 一个周期的微秒值
  double len = 900 + ctrlPower * 5;  //(0~200对应总周期0.9ms~1.9ms)
  for(int i = 0; i < 4; i++) powerServo[i].writeMicroseconds(len);

  int leftMs = (int) (t0 + T - micros());
  delayMicroseconds(leftMs);
}

电调的特性实验

最近收到了好多朋友的帮助,在此表示感谢。wnq同学送了很多好东西,并且帮我挑选了一款好用的航模专用遥控器,终于让我下定决定再重新做一个新的四轴。很多快递都还在路上,这几天继续研究老四轴的问题。

今天有位年仅14岁的年轻朋友ENIAC留了言:“对于我开始的商品电调,由于里面自带的 PID 控制器。严重影响了转速的快速反应。这就造成了对于四轴稳定性之一的“自动悬停”基本无法做到了。由于自动悬停的首要要求就是在四轴倾斜时能够在最短时间内自动回到水平位置, 这就要求马达转速在四轴有倾斜时需要加快,而到快回到平衡位置时需要降下来。商品电调里的 PID 恰好阻止了这个的发生。转速上去可以,想要马上降下来?没门!我试验的结果就是一旦转速上去了,想要降下来,等 0.2秒吧。即使这段时间里通知电调降低转速也没效果。带来的后果就是四轴一旦倾斜后就会不可控地晃来晃去,好像抬轿子。

这段文字是ENIAC在无线电上看到的,不得不佩服现在的孩子们,14岁已经开始看这种专业的书籍了。回想我这么大的时候,干的事情基本都是从楼上尿尿,往厕所里扔鞭炮之类的。闲话不多说,我在网上也很容易搜到了相关的讨论。刚看到它的时候,我确实是心头一惊,如果有0.2秒的下降延时,那么我的350Hz的采样,50Hz的控制全白瞎了。但是转念一想,不对啊,现在很多飞的很好(包括悬停动作)的飞控,配套的也是普通的电调啊。

再后来看到一名叫做gale的网友评论:“误区啊。。。 1500元以下的商品电调,根本没有PID。。。连P都没有,何谈ID? 我的经验是商品电调使用挺好的,PPM的信号控制速度也挺快的,目前最低档的KK飞控,也达到了300HZ的控制频率,其所谓的时延问题最主要还是在电机和桨的惯性上。I2C没有看出有明显的必要。” 原文看这里

从这篇讨论贴中的视频看,确实有人用KK飞控+普通电调实现了较为稳定的控制,这样说来我就放心点儿了。另外一个有用的信息是其中提到的300Hz的频率,前几天我刚做了一个实验(企图修改电调PWM频率的实验),当时的结论是电调的频率不可修改。今天突然意识到一个错误的理解:我假定电调是按高电平的占空比来控制电机的,事实上,电调也可能不看占空比,而是只计算高电平的脉宽来控制转速。

加大电调控制频率的方式

加大电调控制频率的方式

上面这幅图表示了从50Hz的控制变成100Hz控制的方式,其中中间那部分是我之前的错误理解,以为高电平的脉宽应该减半,事实上应该是下面那种方式。

为了验证这个想法,特地又做了一个小实验,代码如下:

void loop()
{
  long t0 = micros(); //记录进入loop的时间
  while(Serial.available()) {
    // 这里是获取控制指令
    pushData(Serial.read());
  }
  double frequency = P_Control * 1.5 + 50;  //(0~200对应50到350)
  double T = 1000000 / frequency; // 一个周期的微秒值
  double len = 900 + ctrlPower * 5;  //(0~200对应总周期0.9ms~1.9ms)
  for(int i = 0; i < 4; i++) digitalWrite(motorPins[i], HIGH);
  delayMicroseconds(len);
  for(int i = 0; i < 4; i++) digitalWrite(motorPins[i], LOW);
  int leftMs = (int) (t0 + T - micros());
  if(leftMs < 1 ) leftMs = 1;
  if(leftMs > 2000) {
    int ms = leftMs >> 10 - 1;
    delay(ms);
    delayMicroseconds(leftMs - ms<<10);
  } else {
    delayMicroseconds(leftMs);
  }

其中P_Control和ctrlPower是我从手机遥控器传入的参数,偷了个懒保留了P_Control的变量名,其实它在这里是用来调节PWM周期的。

手机端截图

手机端截图

其中ctrlPower就是图中那个油门值了。这个实验表明,普通商品电调的控制频率确实可以修改的!
我之前的控制频率是50Hz,确实有点少了,反应比较慢,如果推理正确的话,也许可以加到到300Hz左右。

今天有点生病了,做完这个实验,有点头痛欲裂的感觉。把接下来打算做的事情整理一下,然后去睡觉啦:
1. 修改电调的控制频率,看看是否能让飞行器更平稳
2. 四个电机轴都已经有点歪了,买了几个新电机,也买了几根新的电机轴,看看能不能自己修好
3. 给老四轴加上螺旋桨保护罩,前几天听说有人玩航模砸死了过路人,罪过啊,大家也一定要多加小心!
4. 用wnq朋友的飞控和机架组装一套新四轴,改为用遥控器控制
5. SSS_SXS朋友提到了Arduino自带的PID库,这个可以考虑替换掉自己的PID

带好盈程序的电子调速器控制

最近制作四轴飞行器陷入困境,用手抓住它左右摇晃,能够感受到螺旋桨明显的阻力。但是PID参数调节的结果,要么就是飞行器剧烈摇摆失控,要么就是起飞后向一侧斜飞,很难达到一个较为稳定的状态。

应朋友们的建议,先陆陆续续写一些攻略和步骤。一来可以相当于做好笔记,二来也可以请大家帮忙查找原因,出谋划策。

前面几篇提到了目前控制电机的一些问题,正好在这里介绍下我控制电机的方式。

电机

首先,航模的电机一般都是无刷电机,这种高速的无刷电机不像直流电机那样,接上一定电压就可以旋转,一般需要在多个电源线中输入周期性的交流电。例如我买的电机就是下面这样的:

无刷电机

无刷电机

它有三根输入电源线,如果用单片机直接输出交变的电信号给它,因为单片机输出功率太低,是转不动的。
如果把单片机的输出经过电流放大电路,例如L298N,事实上很多步进电机就是这样控制的。它的问题在于一个单片机只能控制几个电机,并且很难再做其他的计算了。

电调

由于上面的原因,我们必须采用专门控制电机转速的设备,就叫做电调(全称电子调速器,英文electronic speed controller ,简称ESC)。它的作用就是接受单片机的PWM指令,并且生成成无刷电机需要的高频交流电。

电调

电调

大家可以看到电调有很多线,其中两根粗线连接的是电源的正负极;三根输出线分别连电机的三根输入线(如果需要电机反转,任意对换两根接线即可);另外还有三根细线,分别是单片机接地,5V输出电源和PWM信号线。

 根据航模标准,PWM信号线的频率应该是50Hz,对应的每个周期总时长是20ms。经过我的实测,基本上超过55Hz以后就不转了。
在这个20ms的周期中,高电平的持续时间应该在0.92ms到2.120ms之间,分别对应电机的最低转速和最高转速。

我曾经在想为什么只给转速控制留了这么小的PWM范围?如果是按Arduino系统PWM输出的话,用0~255来输出20ms之间的PWM值,有效控制转速的值范围大约只有pwm=(20~40)之间。后来大概明白了,这是为了给单片机节约宝贵的CPU资源,这样才可以在剩余的18ms中处理其他事务。

好盈程序

看电调的说明书,它有很多功能。比如设置电池的特性,设置刹车特性,设置最大转速等等。这些功能都可以通过遥控器进行设置,其中大部分功能我们使用默认值就可以,只有初始化一项是必须做的。
具体的设置方法是,把油门推到最大(2.12ms),这时候电调就会滴滴几声提醒你进入设置模式,然后就可以把油门迅速拉到最低(0.92ms)保持一会儿之后,电调就可以初始化成功了。

新手可能会有和我一样的疑问:把油门推到最大的时候,会不会电机突然暴走起来?
所以这里需要强调的是,电调的使用一定要按照说明书操作。单片机通电的时候,需要立刻给电调输出最低油门的PWM值(0.92ms),经过我的实验,0.85或0.95也没有太大关系。再低的话就会滴滴滴的报警,告诉你没有初始化成功;再高的话(0.95到2.1之间)只会有一声警报,但是无法正常转动;再再高到最高油门值(2.12ms)的时候,就会提醒你进入设置模式。

这样做是安全的,如果你不慎把遥控器留到了高位,这时候给电机通电,不至于突然上升到非常高的转速。前几天我企图修改PWM的时候,发生了一次这样的失误,手机控制的参数一下子升到最大,螺旋桨的风力大到手几乎抓不住,真是吓的屁滚尿流……

初始化和调速

之前有提到过用电脑通过串口通信控制电机,这里也是类似,在PC上写一段小程序,可以输出0~200之间的一个整数到Arduino。
在Arduino上,分别把0对应到0.9ms的高电平;200对应到2.1ms的高电平。

void loop()
{
  long t0 = micros(); //记录进入loop的时间
  while(Serial.available()) {
    // 这里是获取控制指令
    pushData(Serial.read());
  }
  //ctrlPower从串口读取,0~200分别对应高电平脉宽0.9ms~2.1ms
  double len = 1000 * (0.9 + ctrlPower * (2.1 - 0.9) / 200.0));
  // 输出高电平
  for(int i = 0; i < 4; i++) digitalWrite(motorPins[i], HIGH);
  // 延时len毫秒
  delayMicroseconds(len);
  // 输出低电平
  for(int i = 0; i < 4; i++) digitalWrite(motorPins[i], LOW);
  // 等待一段时间,形成20ms的周期
  delayMicroseconds(t0 + 20000 - micros());
}

其中ctrlPower就是从PC端读取的那个控制值。新电机和电调买回来,把4个装到一起,然后从这个程序统一进行初始化和控制转速。强烈建议第一次玩电机的朋友,先不要装上螺旋桨,应该等调试胸有成竹之后再安装。 :)

运动状态中的加速度传感器

之前对加速度传感器读数震荡早有耳闻,但是一直没有真正在电机启动状态下记录读数。今天春节的慵懒综合症差不多过去了,做了一个小实验,对加速度传感器做一个简单的评估。

实验条件是从上方吊起四轴飞行器,操作顺序为:
1. 接通电源,记录读数
2. 启动电机功率到40(80~100为起飞功率),飞行器无摆动
3. 停止电机
4. 启动电机功率到40,同时手动让飞行器做钟摆运动
5. 保持电机功率,用拉绳把飞行器倾斜30度左右

得到的记录数据如下:

传感器工作情况记录

传感器工作情况记录

图中的红色数据是加速度传感器计算出来的角度,黑色是平均滤波后的角度。横坐标是时间,50表示1秒。从图中得到以下结论:
1. 在电机未启动时,加速度传感器和陀螺仪传感器积分值较接近,数据抖动在1度到4度之间,因为是悬挂状态,所以可以认为数据是准确的;
2. 电机启动之后,在飞行器没有摆动的情况下,读数依然跳动的非常厉害(正负15度);
3. 在钟摆运动的情况下,由于数据抖动的原因,读数看上去和不动的时候居然没啥区别;
4. 在手动倾斜的情况下,可以看出传感器虽然读数跳动剧烈,但是总体趋势还是会偏移;

从钟摆运动的中段1500到2000之间取出数据放大,分别查看陀螺仪传感器读数和加速度传感器的读数:

钟摆运动下的陀螺仪传感器读数

钟摆运动下的陀螺仪传感器读数

钟摆运动下的加速度传感器读数

钟摆运动下的加速度传感器读数

果然如传闻所说,陀螺仪传感器还是比较给力的,至少数据图看上去还比较整齐;而加速度传感器基本处于暴走状态,必须要长时间的平均才能反映大致的倾角范围。

新来的朋友可能会有疑问,既然这样的话,为什么不直接抛弃加速度传感器,直接用陀螺仪来测量角度呢。其实主要原因在于陀螺仪测量角度是靠积分计算的,时间一长就会有误差的积累。最简单的验证就是把飞行器水平放到地上,你会发现积分出来的角度在几分钟之后非常缓慢的上升到几十度。所以需要在积分的过程中不断的掺入加速度传感器的读数,用来修正误差。

今天的实验是室内试验,只敢把电机功率调到40,在真正飞行状态下,误差会更大。不过有了数据,心里大概能踏实点儿了。接下来就是考虑如何减少加速度传感器的震动误差,可以考虑从结构上物理减震和从算法上调整计算参数。希望接下来好运吧! :)

四轴飞行器第二次试飞小结

春节期间进行了第二次不拴绳的试飞。总体来说,革命尚未成功,同志仍需努力……

和第一次相比,主要做了以下变化:

1. 给油门控制添加了一点渐变处理,当不小心把油门推高或者降到0的时候,飞行器不会猛升猛降,油门会较为平稳的变化。
好的飞控不会有这个功能,因为控制比较平稳,尤其是玩暴力飞行的朋友,肯定不能有延时。这里主要是为了在调试阶段不要损伤器件。

2. 添加了超声波测距传感器,把离地距离限制在1.5米以内,超出这个高度后,油门就会适当下降,这个主要是为了避免飞出控制范围和直接坠落。

3. 把采样频率从原来的50Hz提高到了350Hz,本来想提高到400Hz,但是某些情况下单个周期里的运算时间会超过2.5ms一点儿,所以最后改为350Hz。

4. 增加了从上面拴绳和下面拴绳两种调试方法,主要是为了调试PID时使用。

这是加了超声波大眼睛的四轴飞行器:

四轴飞行器上的超声波测距传感器

四轴飞行器上的超声波测距传感器

飞行视频:

从飞行的状态看,超声波测距起了一定的作用,四轴没有像上次那样飞的太高和直线下降。但是起飞以后侧飞的非常严重,看上去像是在很大尺度上摆动。做一个小小的总结,下个阶段准备在以下几个方面进行改进:

1. 减少震动,把控制板用弹簧或者橡胶垫稍微做点隔离,减少电机震动对传感器的影响
2. 校准螺旋桨,刚刚知道我买的螺旋桨(5元一对)平衡性能不是很好,不校准的话震动很大。建议的校准可以用一根细的针穿过中心轴,看看不会向一侧偏。轻的一边用透明胶带绕几圈配重。但是不知道透明胶带会不会影响气动性能
3. 没有做误差标定,就是把四轴放在平地上,在启动电机前记录平地时的各种读数
4. 除了1和2中的物理减震外,还应该做软件减震,按老薛的建议,打算把平均滤波改为卡曼滤波
5. 挂绳的试飞和无绳的试飞并不完全相同,挂绳时有垂直或水平的作用力,会辅助四轴平衡。所以这个四轴在挂绳时有时表现的还凑合,一到实战就横着飞
6. 初期犯了个经验主义错误,我以为气压计只能测量较大尺度上的高度,毕竟上下几米气压几乎没有变化;另外也担心在快速上升下降的过程中,气压会受到风速的影响。但是通过网友们的实战看来,气压计的高度估计可以精确到0.25米左右,并且在高速飞行时的表现也还不错。真是小看了当前的电子设备,这个在下一步可以考虑加上。

另外还有一个小小的经验可以分享:刚开始挂绳时,发现挂绳也不安全。当四轴上升的时候,会把挂绳吸进螺旋桨,结果叮叮咣咣,你懂的……
后来找了一些叫做易拉宝的东西,本来是用来拴钥匙门卡的,自重小而且伸缩性挺好,绳子也挺结实。四轴上升下降的时候,绳子也跟着伸缩,这样就不怕螺旋桨卷绳子啦。

用可伸缩的挂绳来测试四轴

用可伸缩的挂绳来测试四轴

四轴飞行器攻略3:串口通信

虽然四轴飞行器还没有最后完工,但我觉得这不妨碍先发一部分攻略。作为一个新手,我在调试过程中遇到了很多问题,现在不记下来的话,等完工了很可能都忘了;另外,高手们也可以通过我的攻略,看看有没有什么错误,或者哪里可以优化;最主要的是,独乐乐不如众乐乐,分享是DIYer们的精神之一 :)

上次整理了四轴攻略的目录,今天正式把它放在导航栏成为一个新项目,目录的顺序是按照我制作的顺序来组织的。
比如刚买回来电机和电调,本来应该先做电机控制实验。但是看了说明书发现这种电机还需要初始化,而且初始化需要可调比例的PWM方波(具体的设置方法会在后续的电调部分介绍)。对于控制来说,调节方法至少有两种:一种用旋转电位器连接Arduino的模拟输入,另一种是用计算机或者手机通过串口控制调节。

因为电机的初始化只需要做一次,为了这个增加电位器好像没有必要;而串口通信则会贯通在整个控制和调试的过程中,所以我决定先从它开始实验。

串口通信其实之前已经做过很多小实验了,简单的一段演示代码如下:

Serial.begin(9600);  // 设置波特率
Serial.write(123);   // 向控制端写数据
while(Serial.available()) {
       // 如果有数据,则读取数据
       byte data = Serial.read();
}

很快你会发现这段简单的小代码有一些问题。

1. 传输速度:
代码中的9600是波特率,也就是数据通信的速度,它是目前比较流行的传输速率。以这个速度通信的话,每发送一个字节(Byte)到控制端需要的时间大概是1毫秒。需要注意的是,为了精确控制四轴的平衡,我们需要尽量在短时间内多读取各种传感器的值。以目前的350Hz的采样率来说,每2.85毫秒就需要读取一次陀螺仪和重力感应器。这种情况下,1Byte/ms的传输速度显然是不能容忍的。解决的办法就是修改波特率,Arduino支持的波特率包括:300, 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 和 115200。如果修改的话,相应的控制端也需要修改成一样的。
大家可能会说,为什么不全都用高速的呢?实际上能使用多少的波特率,跟处理器的主频有关;而且主频最好是波特率的整数倍,否则的话可能会增加错误率。对于我这个四轴来说,如果用USB和电脑通信,可以达到最高的115200;如果用蓝牙和手机通信,只能达到9600的波特率(因为蓝牙模块修改波特率还需要额外购买一个控制板)
很让人高兴的一点是,Arduino支持在运行过程中动态修改波特率。所以可以首先使用9600连接,当发现连接对象是电脑时,调整为115200:

    if(controlType == 100 && !connectToPc) {
      Serial.end();
      connectToPc = true;
      Serial.begin(115200);
    }

需要说明的是,只有发送数据才有这个问题,对于单向接收数据基本是没有关系的。因为Arduino接收的数据会放在缓冲区里,在读取的时候数据已经下载完毕,主程序不需要等待接收。

2. 关于通信协议
对于一个新手来说,协议可能是个特别吓人的词汇,感觉是权威机构才能制定的东西。事实上,在单片机领域经常需要自己定义协议。下面我们看看到底是怎么回事。
前面的代码中演示了如何接收一个字节的数据,问题是:如果需要接受多个控制数据,读取程序怎么知道哪个字节是控制那个参数呢?
我用了一个非常简单的协议,每组数据6个字节,其中第一个字节是FF,其他字节都小于255。这样一来,我们在读取数据时,如果看到FF就知道它是数组的第一个元素了。
当然我这里是一个简单的协议,对于复杂的系统,数据中很可能也带有FF数据,这种情况该怎么办呢?其实也很简单,就像高等语言中的转义功能。如果数据中有FF,那么我们把它改成FE01。等等,如果数据中原来就有FE01怎么办?我们可以把所有的FE改成FE02。这样就完成了转义。学过HTML语言的同学,可以用&转义符做参考进行理解。

3. 校验位
接下来是另外一个问题。单片机通信并不像我曾经想象的那样稳定和精确,它其实是有可能丢数据的。例如串口数据到达的时候,Arduino的中断正好被触发,这时候数据就丢了。
丢一个数据可能会带来非常严重的后果,例如我的控制参数,第一个是油门,第二个是PID的积分参数,第三个是PID的微分参数。如果第二个数据丢了,我就会认为第三个是积分参数,这两个参数如果相差较大的话,也许四轴就坠毁了……
所以在协议里,还需要确认一下收到的数据是否完整和正确,这里就需要用到校验位。一个常用的简单的方法是,把一组数据依次进行异或操作,把结果作为最后一个字节的数据一起发出去。接收端收到数据后,也相应的做一次异或操作,看看两个值是否相等。从数学上看,也可以把接收数据全部异或起来,如果等于0就对了。(这种异或校验法不能完全保证正确性,有一定的概率会误判,但是大多数情况够用了)
如果校验错误的话,我们宁可把这一组数据丢掉,也不能使用错误的参数。

void loop()
{
    while(Serial.available()) {
        pushData(Serial.read());
    }
}
int bufferIndex = 0;
void pushData(byte data)
{
  //验证是否数据的开始
  if (bufferIndex < 1 && data != (byte)0xFF) {
    bufferIndex = 0;
  } else {
    buffer[bufferIndex] = data;
    if (bufferIndex == 5) {
      setParams();
    }
    bufferIndex = (bufferIndex + 1) % 6;
  }
}
void setParams()
{
  // 因为超声波中断可能导致数据丢失,所以需要额外的一个字节用于校验
  if(buffer[1] ^ buffer[2] ^ buffer[3] ^ buffer[4] == buffer[5]) {
    ctrlPower = buffer[1];
    reportType = buffer[2];
    P_Control = buffer[3] / 200.0;
    I_Control = buffer[4] / 200.0;
    // 其他处理
  }
}

总结,其实所谓的“协议”,就是在数据通信时商量好的“规则”,按照这个规则,我们才能保证接收到正确的数据。

四轴飞行器首次试飞小结

今天的天气非常好,蓝天白云,风平浪静,阳光明媚,万物复苏,狗熊撒欢……想一想四轴飞行器已经在阳台上挂着试飞过若干次了,今天终于要摆脱枷锁,真正试飞一次。

于是携带专用摄影师圈圈妈,来到了附近的小绿园。因为最近剃了光头,所以脑袋还是挡一下吧,以免吓到小盆友和花花草草:

四轴飞行器首次试飞

四轴飞行器首次试飞

现在还没有加上超声波测距传感器,不能测量离地高度。因为觉得可以控制电机转速,所以觉得没有它也问题不大。

不过从试飞看来,没有这个测距传感器还是很不方便的,主要有以下几个原因:
1. 有效量程较小,我设置的量程是0~200,对应电机的最小和最大转速;但是转速到60的时候才刚刚离地,到80就已经接近失控;
2. 手机控制过于灵敏,手指头稍微动一下,十几二十就出去了;
3. 控制距离比较短,只能支持10多米,总担心飞出控制范围;

下面的视频是第一次正式离地,总的来说,离地还算平稳。第一次没敢使劲飞,一起来我就向下调油门。结果有点心急了,搞得像坠毁似的。
从离地表现看来,陀螺仪和重力传感器应该是工作正常,姿态平衡算法也还勉强凑合。Ar.Drone使用的是ARM芯片,读数采样率可以达到500Hz,而我这个Arduino目前只优化到350Hz,第一次试飞能直上直下还算满意了。

随后又试了几次类似的低飞操作,终于决定卯足劲飞高点。于是把油门推到80,结果瞬间就蹿到了十米高左右。
要知道这家伙如果超出蓝牙控制范围,就会保持这个速度乱飞,谁知道会发生什么事情呢?
那边还有几个打太极拳的老头老太太,再过去是一群小P孩,数千转的螺旋桨跟飞刀也差不多了……
太恐怖了,所以马上遥控降落,结果再次操作过快。这次从高空重重摔在地上,好不容易焊好的那块扩展板被震松了,所有的电机全部罢工。
第一次试飞只能到此结束啦。

这是由美女摄影师拍摄的坠落现场:

阶段总结:
1. 量程控制应该改进成非线性的,0~60可以缩短一点,60~90可以拉长一点(对应手机上的控制距离)。这样遥控的时候,在有效量程内就不会手忙脚乱的,一哆嗦就上天或者坠落。
2. 是时候加上超声波测距了,目前陀螺仪和加速度计都工作正常。如果能够测量离地高度,就可以比较平稳的悬浮。
3. 四个腿应该捆上点泡沫缓冲,不然高处坠落的时候,非常容易损坏零部件。
4. 蓝牙的遥控距离确实有点短了,一不留神就飞出10米远。接下来可以考虑wifi控制,或者捆一个手机上去,用另一个手机控制。
5. 添加意外处理,万一真的失去控制,应该平稳降低电机转速下降,否则的话一定会有安全隐患。

欢迎各路英雄提出宝贵意见 :)

关于四轴飞行器

今天看到SSS_SXS同学的提醒,发现已经有一个多月没更新了。这段时间乱七八糟的事情挺多,期间还开小差又玩了一阵子陀螺,总之进展不多。

目前的状况是:传感器可以正确读数,电机驱动和手机蓝牙控制也已经完成,最复杂的姿态平衡控制正在调试中。虽然还没有完成,现有的东西也可以大概总结一下攻略,这里先列出目录,以后慢慢补充内容。

快过年啦,祝大家新年快乐,万事如意,多拿红包!

基于Arduino的四轴飞行器制作攻略

  • 四轴飞行器教程1:器件介绍(上)
  • 四轴飞行器教程2:器件介绍(下)
  • Arduino串口通信
  • 用一块Arduino输出多路PWM
  • 带好盈程序的电子调速器控制
  • I2C总线和SPI总线
  • 三轴陀螺仪的调试
  • 三轴加速度感应器的调试
  • 三轴电子指南针的调试
  • 蓝牙接收板的使用
  • Android手机开发环境设置
  • Android手机的蓝牙通信
  • 自制Arduino扩展板
  • Arduino中的指令时间
  • 卡尔曼滤波和平衡滤波
  • 空间坐标系变换及调试
  • PID平衡算法
  • 在电脑上记录log并调试
  • 超声波测距传感器的使用

四轴飞行器攻略2:器件介绍(下)

首先说下现在的进度:目前已经测试了用Arduino读取陀螺仪传感器,加速度传感器,电子罗盘的读数;并且可以用Android手机通过蓝牙向Arduino发送指令;焊了一个小小的扩展板,并完成了初步的组装。接下来的主要工作是传感器读数的分析和姿态平衡算法的研究。发个近照:

组装完毕,等待编写程序的四轴飞行器

组装完毕,等待编写程序的四轴飞行器

圈妈学过一点心理学,忧心忡忡的对我说“据说提前说出目标的事情就不容易成功”,所以她不建议我还没做好就发攻略。但是攻略这种东西,想写的时候没写下来,过几天就忘了。我只好用男生追mm的例子做了解释:闷骚型的男生如果被人知道了暗恋对象,有的人变得更紧张,见到mm就躲;有的人则是硬着头皮展开攻势,最终满载而归。所以公布目标没啥问题,关键是看你把它当成动力还是压力。

言归正传,下面继续介绍四轴飞行器的器件们。

陀螺仪传感器
陀螺仪传感器又称角速度传感器,它的作用是测量物体运动的角速度(废话啊)。从测量维度分,陀螺仪传感器有单轴的,双轴的和三轴的;以传输方式分,又有数字型的和模拟型的。
对于四轴飞行器,最好使用三轴传感器。因为水平方向上就已经需要测量x,y两个维度的角速度,z轴方向上的自转如果有电子指南针的话,倒是也可以省略。所以很流行的另一种方案是用两个垂直安装的单轴传感器(ENC-03MB 村田角速度传感器),价格会便宜好多。
至于数字型的还是模拟型的,初学者开始会觉得模拟型的好用,它会引出3条线,分别输出0~5V之间的电压,表示xyz三轴的加速度值。
看上去似乎相当简单,用analogRead一下就好了。
从我的实践经验看来,它的问题在于线太多!陀螺仪需要3根线,加速度又3根线,指南针再3根线….随着器件的增加,Arduino的模拟输入口完全不够用。
而数字型则简单了很多,以I2C总线为例,数据通信只需要2根线,而且很多个设备(最多支持256个设备)都是公用这两条线。反正看你愿意花力气在焊板子上还是写代码上了。对于我这样的IT民工来说,显然觉得敲代码比焊板子舒服很多,所以我最终选择的是L3G4200D三轴数字式陀螺仪传感器。

加速度传感器
加速度传感器又称重力感应器,它可以感知物体受到的重力。例如水平静止放置的重力感应器,xy方向上重力加速度都是0,z轴方向上的读数则是9.8;而倾斜放置的传感器,在xy分量上就可以读出所受的重力。和陀螺仪相比,加速度传感器测量的是绝对的“倾角”,而陀螺仪测量的是“倾角的变化速度”。
这些传感器的最终目标,就是让四轴飞行器保持平稳。有人可能觉得用重力感应器就足够了,因为它可以测量绝对角度。但是请注意的是,这个倾角必须是在物体静止或者匀速的情况下测量的,飞行器在运动过程中是测不准的。就好比闭眼蹦极的人,在失重的时候是不知道上下左右的。所以一般需要两个传感器配合,一个用来测变化量,一个用来修正误差。
加速度传感器同样分为数字型的和模拟型的,我看上的是ADXL345数字型三轴加速度传感器。

电子指南针
电子指南针也叫电子罗盘,也有人叫磁通传感器。它的原理跟指南针类似,通过测量某个截面内的磁通量大小来判断方向。它也可以是三轴的,其中垂直于南北极磁力线的那个截面会有最大的读数。这个指南针不是四轴飞行器必须的,因为平稳飞行靠前面两个传感器就够了。
但是试想一下这样的情况,我们遥控一个直升机的时候,可以看到机头的朝向,所以我们可以让他“前进/后退/左移/右移”。
而四轴飞行器是对称的,当你发出“前进”指令的时候,它并不知道你期望的是哪个方向的“前进”。
网上一种流行的方案是,给四轴飞行器的某条腿涂上鲜艳的颜色,作为“机头”,前进后退的参照系都是以它为准。但是这样就需要对遥控者有一定要求,需要能够迅速分辨方向。
我加上这个电子指南针,是希望它能和手机遥控器上的指南针对应起来,永远以遥控者的面向方向作为“前方”。当然这样会给算法带来更多的工作量,大家祝我好运吧 :)
我最终选择的芯片是HMC5883L三轴数字型电子指南针

其他还有一些零七八碎的东西,包括:
超声波测距传感器,用来测量离地高度;
蓝牙适配器,用来和手机通信;
洞洞板,用来组合这些传感器;
各种插针、排母、导线、开关;
机架,这个也可以自己做,现成的比较好看;

最后是某些网友非常关心的价格问题,下面的价格表仅供参考,最终还是请大家自己擦亮眼睛,货比三家。
必须提到的是一个小插曲,很多芯片的价格分为散件价格和模块价格。例如L3G4200D芯片,单买芯片据说30元就可以搞定;如果买现成的小电路板+所有电容电阻等配件,那么需要70元左右;如果这些小配件都帮你焊好的成品,大概需要160元左右。
看到这些价格之后,勤劳勇敢的圈妈大骂奸商,说要帮我焊上,省下这100块钱!结果散件回来以后我们都傻眼了,这是一种叫LGA的封装方式,花椒一样大的小芯片,肚子下面有十几根脚。而且这些脚是在芯片肚子下面,不是伸出来的!

新手焊不了的小芯片

新手焊不了的小芯片

圈妈硬着头皮焊了几下,发现基本所有的脚都连在一起了,最后弄掉了焊盘,彻底报废。所以建议新手们,如果没有专业焊接工具的话,就不要尝试省这100块钱了。

价格表(仅供参考!)
格氏11.1V2200mA25C锂电   128
B6充电器     160
郎宇A2212电机   62×4
天行者20A电调  48×4
四轴机架     88
三轴陀螺仪模块L3G4200D       160
三轴加速度ADXL345模块     50
三轴磁阻HMC5883L模块      70
蓝牙模块JY-MCU          40
超声波测距            16

四轴飞行器攻略1:器件介绍(上)

每次想做东西的时候,都会经历一个疯狂采购的过程,虽然不一定花很多钱,但是一定是零七八碎的一大箱子。以前圈圈妈很爱逛街,而我每次逛街就像参加一次马拉松似的。现在终于能理解这种购物的乐趣了,唯一的区别是兴趣方向不同。

正如开始计划的,我正在用蚂蚁搬家的方式做这个四轴飞行器,进展比较慢。目前正在做一些实验,电机和陀螺仪的控制和读数已经调试成功。思路和方案也慢慢的成型了,下面介绍一下制作所需的各种材料和器件,供大家参考:

一、电源
所谓“兵马未动,粮草先行”。四轴飞行器想上天,好电池是必须配备的。怎么才能算是一块好电池?除了长相英俊潇洒之外,还得有“吃的多,跑得快,力气大”等优良品质。这里推荐的是格氏11.1V/ 2200mAh/ 25C的锂电池。
选用锂电池的好处是单位重量的电容量大,所以电池比较轻巧,电量比较充足。锂电池的标准电压都是3.7V左右,所以套装的锂电池基本都是3.7的倍数,这个11.1V就是由三块锂电串联而成。2200mAh这个参数大家比较熟悉了,充电的电池一般都有这个参数。它表示电池的电容量,在2.2A的电流下,可以工作1小时。
25C对于初次接触航模的人来说可能有点陌生,某些色狼若有所思但是可能觉得数字不太对 :) 其实这里的xxC表示充放电的速率,可以在1/xx小时内把电用完。也就是说,25C的电池可以在60/25=2.4分钟把电放完。某些同学可能会提问:“这样说来,C值越大的电池用的越快,应该是越不好吧?”为了避免这些同学暴露智商,这里集中提示一下。航模一般都需要比较大的瞬间功率,所以需要很大的电流。一般的电池在这么大的电流条件下早就过热烧掉了,所以必须用C值较大的电池,可以认为C值越大的电池越好。

四轴飞行器专用锂电池

四轴飞行器专用锂电池

另外需要注意的是,好马配好鞍。好电池最好还是给它配一个好一点的充电器,例如B6充电器。其实充电器我也不太懂,但是作为北航的老校友,看到B6立刻冒出了巨大的轰炸机形象,于是果断买下。试用了一下,果然还不错,可以充放各种规格的电池,还可以设置充电速度,并且可以查看三组电池中任一组的状态。有负载均衡的充电器,可以保证电池组的每个电池基本都处于相同的状态。

专用充电器

专用充电器

二、电机和电调
曾经有人问能不能用玩具小车里拆出来的小电机来做四轴飞行器,其实飞行器对电机的要求是非常高的,不仅要转速快,还需要能够精确控制。对于四轴飞行器,推荐新西达或者郎宇的电机。以郎宇A2212为例,它分为KV980和KV1400两种。KV参数的含义是:电压每升高1V,电机转速的增加量。需要注意的是,并不是KV值越高就越好的,因为电机的最大转速是有限的,KV值越大,对控制的精度要求越高。
电机的最大转速我没有查到,有知道的朋友麻烦吱一声。

四轴飞行器专用电机

四轴飞行器专用电机

这几款电机都是使用的三相交流电,所以别指望直接接上电就可以转,我们还需要一种叫电调的东西。电调全称叫“电子调速器”。它的接线很多:两根输入电源线,和电池连接;三根输出电源线,和电机连接;三根控制线,和单片机连接。
其中三根控制线,一根是地线(地线是各种器件的潜规则,都会有),一根是引出的5V(这是个贴心的设计,单片机可以从这里取电,不用再考虑电池的问题),最后一根是控制线,接收PWM信号。关于PWM的介绍,可以看这里这里这里
电调有个重要的参数是最大电流,事实上我们通过简单的程序和电流放大器,也可以做出一个简易的电调。这里推荐使用20A以上的电调,最好是40A的。
购买电调的时候,还会经常看到一个词叫“好盈程序”。一些好点的电调都会带这个容易被念成“好淫”的程序。它不仅可以控制电机的转速,还可以进行更复杂的设置,例如:最大和最小转速,是否支持刹车,过热保护等等。
电调的三根输出电流线和电机的三根线可以随意接,如果发现电机转向不对,随便挑两根反接即可 :)

电子调速器

电子调速器

本来打算一篇介绍完所有器件的,结果罗里巴嗦写了一大堆,需要休息一下,然后继续实验我的电子指南针和重力感应器,改日再继续发攻略。