舵机的作用和特性
舵机的一个作用是用于充当机械手臂的关节或者机械爪的闭合,控制四驱车的转向等。上好旋臂后,它的活动示意图如下:
(网络图片,侵删!)。可以看到他有一些基本运动规则:
- 不同的舵机有不同的旋转角度范围,如0-180度或者0-360度。
- 在这个范围内的,旋转任意角度。
- 旋转速度快。大约0.15s左右旋转60度。不同的品牌速度不同。
运动的控制原理
我们主观感觉舵机基本没有延迟的执行我们的命令,但是其实并非如此。舵机会将时间分为一段段的,比如20ms,在这个时间内,用户发送一个指令他接受并执行。这是,使用细小的离散来对世界的连续性进行模拟。绝对的连续是做不到的。
在这个周期内,用户发送一份特定时长的脉冲,舵机根据脉冲的时长来旋转特定的位置。对于sg90舵机来说,脉冲为0.5ms, 旋转到0度位置,脉冲为1.5ms时旋转到90度位置,2.5ms时旋转到180度位置。如果想让舵机从0度位置依次转到,45度,90度,135, 180度,然后再依次转回来,发送0.5, 1.0, 1.5, 2.0, 2.5, 2.0, 1.5, 1.0, 0.5的脉冲即可,如上图所示。
不管当前,在旋臂在什么位置,想让舵机转到0度位置,只要输入0.5ms的脉冲即可,想要转到其他位置也是同样道理。
使用GPIO控制舵机
由于GPIO每个针脚限制3mA的电流,全部针脚电流和限制在100mA,所以,不要接大电流的舵机,否则会烧坏树梅派。树梅派3B+可以接sg90舵机。
另外,最好在关闭电源的情况下进行接线拔线,因为插拔瞬间有可能电流增大等情况,烧坏树莓派。
针脚配置
sg90电机是一个小电机,可以直接接在树莓派3B上。电机三个导线,橙色为信号线,也是我们需要变成控制的那根,红色正级黑色负极(红色正级,黑色负极,好像很多电器都是这样的,想想万用表,电压表、电流表都是如此)。电源使用树梅派的5V电源即可,树莓派的GND就是电源负极。橙色线接在任意编号的针脚上, 我这里使用的是BCM模式下的25号pin。下面上代码,具体的代码解释也在代码中:
# -*- coding:utf-8 -*-
# 这句是解决python2中,py文件中中文字符问题
from RPi import GPIO # 引入GPIO库
import time
# 先不要看这个函数,先看下边的程序
# 将角度位置转化为对应的pwm_value
def to_dutycycle(angle):
"""
这个函数为start()和ChangeDutyCycle()提供值,这两个函数的输入非常相似,值的范围都是0.--100.。
为了得到这个值,先求输入角度angle所对应的脉冲长度即,
length = angle * 1.0 / 180. * (2.5 - 0.5) + 0.5
然后,这个长度除以周期长度再乘100,即可获得dutycycle
dutycycle = lenght / 20. * 100.
"""
length = angle * 1.0 / 180. * (2.5 - 0.5) + 0.5
dutycycle = lenght / 20. * 100.
return dutycycle
try:
# 1. 树梅派3B 的针脚有两种编码方式,这里使用BCM,所以一定先制定编码方式
GPIO.setmode(GPIO.BCM)
# 2. 设置25号pin作为输出针脚,用于控制舵机
GPIO.setup(25, GPIO.OUT)
# 3. 进一步将25号pin设置为pwm模式输出,输出频率为50hz,所以第二个参数是hz
# 这时候,pwm的周期的时长是20ms了,即 1s / 50 = 20ms
pwm_sg90 = GPIO.pwm(25, 50)
# 4. 一开始,通过发送一个脉冲,通知舵机旋到对应的位置。参数dutycycle规定了脉冲的时常。(之所以叫dutycycle,是因为官方文档中,说这个参数叫做dutycycle)
# dutycycle 值范围为0.---100., 它表示脉冲长度与周期时长的百分比。即dutycycle=脉冲时长/周期时长 × 100.
# 此时要求旋到0度位置
pwm_sg90.start(to_dutycycle(angle=0))
# 5. 程序暂停1s,等待舵机将旋臂旋到0度位置。其实没必要等待1s,大概最多需要0.3ms。
time.sleep(1)
# 将
for angle in [0, 180, 0, 90, 0, 120, 90]:
dutycycle = to_dutycycle(angle)
pwm.ChangeDutyCycle(dutycycle)
time.sleep(1)
finally:
# 最后这一步很关键
# 意思是释放25号针脚的资源,使其他的程序可以使用这个针脚
# 另外不释放资源,还有一些安全隐患,所以一定要释放资源
# finally的作用是:当程序中途遇到错误的时候,不会立刻结束程序,而会向下执行,保证了cleanup一定会执行到。
GPIO.cleanup()