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);
}


对 “Arduino自带的Servo库小实验” 的 15 条 评论

  1. obK仔 说:

    Yeah~~~沙发一下~~咔咔~~

    这两日加上PID的库再继续试飞一下..
    一齐努力吧动大哥:)

  2. js200300953 说:

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

    但应该会更加消耗CPU。
    因为“原生PWM”是硬件实现的,设置好参数后不需要CPU干预。
    而Servo库可以通过所有Digital Pin输出,应该是计时器+中断实现的,每个周期中断两次,如果频率高,会比较占CPU。

  3. seraph 说:

    关注中,努力呀,支持你。我最近也在研究这个,想要使用wifi方式,同时可以支持摄像头。

  4. crane 说:

    同研究者
    受益匪浅

  5. 清水 说:

    PWM的频率可调老大能不能改一下,我们这些小白对底层了解少啊

  6. blackblue 说:

    动力博主:

    请教一下,你如何控制这个四个马达的反转呢?直升机的特技飞行中有一种完全倒过来飞的状态,是通过变桨的螺距来实现的,但四轴上没有这类可变螺距结构,同样车模上面如果要后退怎么办,这种情况下,如果能让马达倒转都好,但这个SERVO库我想做不到了……

    • sunny 说:

      硬件结构根本不一样,四轴用的是类似半桥的驱动电路,前后的话得全桥

  7. GK 说:

    motorPins[0] = 38; //x1
    motorPins[1] = 43; //x2
    motorPins[2] = 42; //y1
    motorPins[3] = 39; //y2
    为什么后面的数字是那么大的?不应该是脚管的编号吗?

  8. rhastaz 说:

    我现在用的是Intel的Galileo板子,为什么我的Servo.h文件里面没有REFRESH_INTERVAL。我想把频率改成50hz。

发表评论

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