用一块Arduino输出多路PWM

【经wwwtiger同学提醒,关于Arduino原生PWM的频率,我之前的理解是错的,应该是490Hz左右,特此更正】

周末有朋友来家里玩,看到了放在角落里的那个大的四轴飞行器。拿下来看了看,发现上面已经落满了灰尘。应该有几个月没动了,当时写的攻略目录也好久没更新了。这段时间打算抽空陆陆续续把这个页面里的目录内容都补齐,免得成为烂尾工程。可惜实验还没有成功,所以不能算是经验,各位兄弟权当教训看吧 :)

四轴飞行器最终的控制手段,就是分别调节4个电机的转速。对于常见的无刷电机,一般通过高电平在0.9ms~2.1ms左右的PWM来控制转速。这就涉及到如何用arduino输出多路PWM的问题,在Arduino中,一般可以通过下面这些方式来输出PWM方波:

1. 用原生的PWM输出功能
把pinMode定义为输出,然后用analogWrite就可以输出PWM。以Arduino Mega 1280为例,它有14路PWM输出。analogWrite的参数范围是0~255,对应的是0~2ms的高电平。
一般情况下,原生的PWM频率固定为490Hz,通过一些参数的修改,可以提高PWM频率,但是参数范围只能是0~255。

int pin = 8; //0~13

void setup()
{
    pinMode(pin, OUTPUT);
}   

void loop()
{
    analogWrite(pin, 128);
    delay(500);
}

2. 通过普通的输出管脚手动控制PWM

PWM归根结底无非就是输出0,1序列的方波,所以我们还可以简单的通过digitalWrite和delay来生成PWM方波。
这种方式的特点是可以非常精确的控制高电平时间和PWM周期,缺点是CPU时间不好充分利用,多路时编程有点复杂。

void loop()
{
  long t0 = micros(); //记录进入loop的时间
  double T = 20000; //一个周期的微秒值
  double len = 900;  //高电平时间
  for(int i = 0; i < 4; i++) digitalWrite(pins[i], HIGH);
  delayMicroseconds(len);
  for(int i = 0; i < 4; i++) digitalWrite(pins[i], LOW);
  /*
   *在这里干别的事情
   */
  int leftMs = (int) (t0 + T - micros()); //剩余时间
  if(leftMs < 0 ) leftMs = 0; //万一超出周期,只能立刻中止
  delayMicroseconds(leftMs);
}

3. 用servo库
Servo库是Arduino用来控制伺服电机的,印象中是使用了内部中断来触发的,所以主程序只管干自己的事情,时间到了PWM就会自动触发。
它默认的频率是50Hz,但是可以在头文件中修改。文件位置是arduino-0023\libraries\Servo.h,修改下面这行可以把PWM频率升到400Hz:
#define REFRESH_INTERVAL 2500

具体的细节在之前的一篇小结里提到了:Arduino自带的Servo库小实验

先记录这些,希望在把全部的“教训”写完之前,能有空把四轴飞起来 :)



对 “用一块Arduino输出多路PWM” 的 35 条 评论

  1. 老薛 说:

    很有实用价值,多谢!

    不知动力哥是否把你的四轴给曾经做成过的人看过,让他们亲眼看一看说不定就能很快找出问题所在。北京藏龙卧虎,这样的人肯定有吧

    • 嗯,北京这里有好多朋友。比如wnq,不过约了两次都没见上面 :)
      我的调试环境太不理想,家里杂物太多,小朋友又到了到处乱翻的阶段,所以都装箱收起来了……

  2. 小浩 说:

    用一块Arduino输出多路PWM,这个题目跟文章内容好像不怎么搭边吧,还是说题目只是一个疑问?不知道能否实现。
    我的理解是,产生多路PWM,这多路PWM应该有一个比例关系的。如果产生没比例关系的多路PWM,可能比较难实现吧。
    这个问题也困扰我,如果老男孩解决了,麻烦共享一下你的方法啊。不吝赐教

    题外话:
    一方面DIY,一方面工作,一方面照顾小孩。还真不容易啊。佩服老男孩这样的人!

  3. darkorigin 说:

    最近工作忙了,来看的多,写的少了。嘿嘿
    加上昨天才从张家界回来。
    动力兄 不要放弃啊,继续做下去啊!有时候看你的博客就能激发斗志呢

    • sunny 说:

      小四轴难度低啊。。。。目测用薄的万能版都有戏。。。。现在已经画好电路了。。。。马上准备开始印板子。。。。你们有没有要的。。。邮费自理

      • 哈,厉害,你是打算连那些小芯片都自己焊吗?

        • sunny 说:

          936的烙铁换一个平头的刀然后再来一个热风枪就ok了。。。其实还可以用烤箱。。。新车间这边来了个人准备出烤箱套件。。。。

      • darkorigin 说:

        神马样的板子???需要焊哪些?空PCB?额~~这个 哎我焊接技术不行啊

        • sunny 说:

          不然飞不起来//焊接其实不难。。。。焊了300+ 0603led后表示基本掌握贴片焊 实际发现贴片速度要比直插快 接至于itg3205么。表示可以热风枪焊。。焊锡量相当关键。。//我现在打算把nrf24l01遥控改成红外的

          • 嘿嘿,我绝对贴片对我来说太困难了,不过我打算买一个新的电烙铁,原来那个太挫了,焊出来都是锡豆

    • 多谢鼓励:) 没放弃,呵呵。
      不过最近也是工作很忙,所以没啥动作

  4. Jeck164 说:

    一直关注和追随,坚持真是一件不容易的事,加油!

  5. 菜鸟来看看 说:

    固定翼飞机的升力中心与其重心不在一点,重心越低越稳定,四轴飞行器由于结构对称造成升力中心与其重心重合,不稳定,在静止状态下用一根针顶住飞行器中心看是否稳定与平衡,螺旋浆安装是否能朝外倾斜一点,用模糊控制可能会好一点。不过小弟都没试过没发言权(因为没m ),都只是些想象,不足为提。

    • 我也想过重心的问题,所以把电池装在下面,理论上重心是要低一点。
      事实上小四轴的平衡好像相对比较容易,我还没有把PID的算法加进去,只是简单的让四个轴功率加大,飞起来的时候摇摇晃晃却也不会像大四轴那样扣盘子

  6. 菜鸟来看看 说:

    如果重心不能调低,将螺旋浆朝内倾斜安装应能自动平衡,稳定度与倾斜角度有关,朝外倾斜的话会降低稳定度,我想应该如此,请高手指点。

    • 可能还是垂直向下比较好,主要是动力比较集中,向内倾斜也许可以增加稳定性,但是对称的两个电机,其实有一部分动力是互相抵消浪费了。
      对于寸土寸金的小四轴来说,浪费能源太可惜了,平衡应该由PID来做

    • darkorigin 说:

      内倾和外倾都会导致合力降低,不管是大四轴还是迷你四轴都会影响动力性能和能源利用率.

  7. 叁颠 说:

    前辈,最近我也和朋友一起在学着做四轴,因为说电调的控制还是用I2C总线来比较灵敏,但是要自己做电调的I2C接口,找了好久没有找到相关的资料。请问这个I2C接口应该怎么来做啊?小弟还是菜鸟,希望前辈能分享一下经验!

  8. buaa 说:

    北航校庆了

  9. SSS_SXS 说:

    兄弟,最近在忙什么呢?好久没看到更新了

  10. SSS_SXS 说:

    难怪了很久没有看到更新新作品了:)

  11. 筱梓 说:

    我是来继续跟踪学习小四轴的,最近工作太忙,哎…

  12. LOWLOW 说:

    請問一下我現在剛會控制電調!!

    我該怎麼寫PID使他飛起來?

  13. wwwtiger 说:

    原生的PWM频率不是50Hz吧,
    The frequency of the PWM signal is approximately 490 Hz.
    http://arduino.cc/en/Reference/AnalogWrite

    64分频,相位PWM
    16M/64/2/255 = 490 Hz

    • 啊,为什么我觉得自己穿越了,以前查资料的时候,好像到处看到的PWM周期都是20ms,现在看到都是2ms,真是糊涂了。
      从链接看,确实应该是490Hz,多谢纠正!

  14. allankliu 说:

    原来Arduino的PWM和Servo是这么个区别。

  15. 剑舞飞花 说:

    请问arduino输出pwm的最高频率是多少

发表评论

可以使用下列 XHTML 标签:<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>