世界最小的Arduino——ATTiny13上手全攻略2C舵机测试仪

本实验我们将教大家制作一款简单的舵机测试器
01_20150503_175851_meitu_1.jpg

01_servo6.jpg
如图是网上常见的一款舵机测试器。其主要功能是可以切换三种不同的工作模式,通过旋钮电位器调节舵机角度的手动模式,中位测试模式和像雨刷一样往返摆动的自动模式。整体硬件有1个电位器模拟量输入,1个模式切换按钮开关数字量输入,3个LED模式状态指示灯和1路PWM舵机控制脉冲输出(图中显示CH1到CH3实际是一路PWM输出)。而我们要做的是其中的自动模式,只要能测试舵机进行往复摆动即可。

03_Servo(FromWeb).png

(图片转自MAKE杂志19期中网友Tod E. Kurt的文章)
在正式开始之前,我们先简单的普及下舵机的基础知识。舵机的分类有两种,数字舵机和模拟舵机。数字舵机比模拟舵机多了个主控,所以响应速度等性能大幅提升,但价格也增加了,不过这种舵机不在我们这次实验的范围内。下面我们主要围绕可180°旋转的模拟舵机进行试验,从硬件接线上看,舵机一般都是由电源,接地和控制信号这三根线组成。常见的两种接线颜色定义如下图,市面上最常见的都是第二种棕红橙。
04_ServoPin.png
要想控制模拟舵机,就要明白其运行原理。舵机系统通过控制信号线接收来自单片机的可变宽度的脉冲信号来进行角度控制,但其频率是一定的,即调幅等频脉冲。一般来说,舵机的基准信号周期为20ms,不同的脉冲宽度决定了舵机的角度。脉冲宽度的范围从0.5ms到2.5ms对应的就是舵机0到180°。但这也不是绝对的,有的厂商采用1ms到2ms的脉冲范围。但绝大部分舵机的中点都是1.5ms,具体数据需要查阅舵机的产品手册或者进行角度测试。
05_ServoDegree.png

为了进一步的论证舵机控制原理,我们先下载Arduino软件的舵机样例File  Examples  Servo  Sweep到一个Arduino UNO中去,舵机实际的测试效果还不错。然后用Saleae Logic逻辑分析仪对其IO口的状态进行监控。由测量结果可知,舵机的运行周期和理论周期20ms一致。舵机在某一摆动时刻的脉冲宽度为1.4ms,应该是接近中点的位置。
06_SaleaeLogicServoUNOStd.png

因为目前没有支持ATTiny13的Arduino舵机库,所以我们可以根据以上的控制原理,自己写一个控制舵机的函数了。大体的控制思路就是将舵机的输入角度0到180°映射到0.5ms到2.5ms的高电平,然后再输出(20-高电平时长)毫秒的低电平,重复发送多次来实现调幅等频脉冲。
07_ServoSweepBadCode.png

写完之后我们先在Arduino UNO测试了一下,舵机的控制没有问题。从测量结果中可以看出周期比标准值多了1ms,但并没有影响舵机运动。
08_SaleaeLogicServoUNOUD.png

本想把在UNO测试过的代码直接下载到ATTiny13的控制器内,结果软件报警说程序太大,存储空间不足。总程序占用1046 Bytes,比系统空间1024 Bytes还多出好几十字节。
09_Tiny13_ServoUserDefineTooBig.png

无奈之下只好对程序进行删减。但删减后的程序功能比较弱,只能实现到达指定的舵机角度。舵机的角度需要手动修改变量然后重新下载程序后才会有效。程序下载成功后可以开始搭建硬件电路了。本实验整体接线比较简单,舵机的三根线分别接VCC,GND和ATTiny13的D4端口即可。
10_T0202_ServoSweep_bb.png

好不容易瘦身成功,没想到自从连上舵机以后,舵机大部分时间都在不停的抖动,主轴偶尔会动弹两下,而且全程伴随着各种噪音。
12_Tiny13_ServoUserDefine.png
(缩减功能后的代码是1014 Bytes)
关于舵机发出的声音,大家要仔细判断。一般有三种,主轴快速旋转时齿轮的声音是连续而且比较尖锐的;主轴在某个位置微调时齿轮的声音是断断续续的哒哒声;还有一种是超程时的声音,舵机本体会严重的抖动,而且齿轮有比较沉闷的呜呜声。其中前两种声音都是正常的,如果舵机质量较好且控制信号源的脉冲稳定的话,第二种声音则几乎听不到。而第三种声音是最伤舵机的,应该立即断开舵机与单片机的连接,然后修改程序,缩小行程范围(即提高脉冲高电平持续时间的最小值或最大值)以便解决问题。
11_SaleaeLogicServoTiny13UD.png

为了解决抖动和噪音的问题,我们用逻辑分析仪先看一下ATTiny13的输出波形,发现其输出的周期已经达到了26ms,远远超过标准的20ms周期。即使通过修改延时参数,也很难将其周期控制在20ms之内。大家还记得我们在上一篇教程中开篇提到的ATTiny13支持函数清单么?其中delayMicroseconds() 后面是有“*”号,官方说对这个函数的支持是有限的,也就是说延时会有误差。不过us级的MCU会有ms级的误差,倒是有些让人意外。于是笔者又单独用Arduino样例代码中的Blink在ATTiny13环境下测试了一下delay()函数。一个1s的延时,实际测量是1.3s也是有一定误差的。更悲剧的是这两种延时的误差都是非线性的,多次测量其稳定性也不太理想,我也是醉了。如此看来用延时函数制作简单的功能还可以,如果需要精确定时就不要考虑了。
13_ServoCode.png

(采用寄存器操作后的代码是644 Bytes)
这个舵机小实验就这样停滞了好几天,实在没辙了,只好尝试去从AVR单片机的底层寻找解决方案。最终我们通过采用定时器的寄存器操作不仅解决了舵机脉冲控制信号不准的问题,还仅用了644 Bytes就实现了之前预期的摆动功能。这和先前的写到溢出都实现不了摆动功能相比可以说是质的飞跃了。照目前的程序容量推测,即使实现那种舵机测试器的全部三个功能也应该不是问题。我们监控一下其波形,基本算是比较理想。舵机当前位置大概在170°左右。实际测试舵机的转动也是比较理想的,往返运动都比较顺畅。
14_ServoMon.png

我们在程序中首先定义了一些变量,其中有两个参数是需要大家根据自己舵机实际测试的效果进行微调的,“int pulseStartPoint = 7; ”和“int pulseEndPoint = 22;”该变量表示高电平脉冲的持续时间,最小值是5,最大值是25。如果大家在测试舵机时发现其明显抖动,正如前面所述的第三种声音时,应该将其值进行调整,避免损坏舵机。然后我们setup()中定义了输出和定时器,在loop()中通过对输出脉冲的占空比进行调节,实现了舵机往复摆动的运动。而在定时器中,我们使用了大量的寄存器操作,大体的意思就是让单片机的定时器可以在20ms内实现波形占空比的调整。
15_Timer.png
大家还记得在上一个实验的最后,我们提到的寄存器么?其实寄存器在Arduino的字典里是不存在的事物,就好像一堆奇怪的大写字符。笔者在玩Arduino的这几年里都不曾“遇见过”寄存器。但如果细心的读者翻开各种Arduino库的话,相信里面多少都能看到寄存器的影子,例如我们之前提到过的AnalogWrite()函数。寄存器虽然不是最方便的功能,但却是非常高效和节省空间的。当然,本教程的侧重点是实验过程,寄存器的详细功能不在我们讨论的范围内,感兴趣的小伙伴可以查阅ATMEL官方的ATTiny13的Datasheet手册。

样例代码
T0202_ServoSweep.7z (77.96 KB, 下载次数: 17)
T0202_ServoSweepBad.7z (398 Bytes, 下载次数: 13)
网盘下载http://pan.baidu.com/s/1dExdYV3

参考资料
果壳网DIYer修炼:舵机知识扫盲:http://www.guokr.com/article/5292/
极客工坊舵机详解:http://www.geek-workshop.com/thread-70-1-1.html
模型中国伺服马达原理与控制,模拟舵机与数字舵机的区别以及常见问题解决方法(资料):http://bbs.mx3g.com/thread-172006-1-1.html

标签: none