树莓派使用GpioZero控制舵机
舵机是用通过齿轮来产生旋转运动的电动机。无线电控制的小车和其他的机器人项目经常会使用它来产生运动。舵机的大小和产生的力量各不相同,小型舵机很便宜,关于树莓派控制舵机的文章已经有很多了。诸如:树莓派PWM控制舵机的两种方式、树莓派3 B+Servoblaster 舵机控制等等。今天我们在研究一下树莓派使用GpioZero来控制舵机。
舵机的接口定义
舵机通常有三根线。两根用于电源,一根是信号线。这些线的颜色因制造产商的不同也会存在一些差异,但通常都会采用以下几种方案之一:
舵机与PWM
要解释伺服系统是如何工作的,重要的一点是PWM(脉冲宽度调制)信号。PWM是一个高低脉冲序列,其中每个脉冲之间的时间决定了舵机旋转位置。详情可查阅:秒懂舵机角度控制原理。
在本文中我们将使用软件来产生PWM信号。软件PWM并不像硬件生成的PWM信号那样准确,但对于基础运用来说已经足够了。
硬件配置
最小实验系统的配置是将舵机直接连接到树莓派。这仅适用于不需要执行大电流任务的小型舵机系统。舵机电源直接通过树莓派的5V引脚提供,要注意这样的话,如果舵机电流过大,将会影响USB设备或树莓派本身的正常运行。
舵机线 | 颜色 | 树莓派 GPIO | 备注 |
---|---|---|---|
电源 (+) | 红 | Pin 2 (5V) | |
信号/数据 | 白/黄/橙/蓝 | Pin 11 (GPIO17) | |
地 | 黑/棕 | Pin 9 | 只要是GND都可使用 |
上表中的GPIO是可以修改的,请参考 树莓派3 超声波测距代码 中的引脚定义来定位额外的引脚。
在本文中,使用了Pin 9(黑色线)作为舵机地线,舵机电源线(红色)连接到树莓派引脚2,舵机信号线(橙色)可以连接到任何的GPIO引脚,本文使用了引脚11 (GPIO17),因为它靠近引脚9,连接更容易。如果使用不同的GPIO,请确保使用正确的引脚号更新示例代码。
示例代码
Python Servo示例脚本#1
硬件连接完成后,让舵机运动起来最简单方法是在Python脚本中使用Gpiozero库,它默认已安装在最新的Raspbian映像中。
from gpiozero import Servo from time import sleep myGPIO=17 servo = Servo(myGPIO) while True: servo.mid() print("mid") sleep(0.5) servo.min() print("min") sleep(1) servo.mid() print("mid") sleep(0.5) servo.max() print("max") sleep(1)
将代码复制存储到名为“servo1.py”的文件中。使用以下命令运行脚本:
python servo1.py
运行后,一切正常的话,舵机应该在0度、90度和180度之间运动,每次运动中间会有一个小小的时间延迟。
Python Servo示例脚本#2 -校准范围
第一个脚本使用Gpiozero缺省值。它假设舵机使用的信号帧宽度为20ms。最小和最大旋转的脉冲宽度分别为1ms和2ms。我发现在默认设置下,我的舵机只移动到+45/-45度。我改变了脉冲宽度参数,以便在两个方向上都能旋转90度。脚本如下:
from gpiozero import Servo from time import sleep myGPIO=17 myCorrection=0.45 maxPW=(2.0+myCorrection)/1000 minPW=(1.0-myCorrection)/1000 servo = Servo(myGPIO,min_pulse_width=minPW,max_pulse_width=maxPW) while True: servo.mid() print("mid") sleep(0.5) servo.min() print("min") sleep(1) servo.mid() print("mid") sleep(0.5) servo.max() print("max") sleep(1)
将代码复制存储到名为“servo2.py”的文件中。使用以下命令运行脚本:
python servo2.py
在本例中,最小脉冲宽度从默认的1 ms减少了0.45 ms到0.55 ms,最大脉冲宽度从默认的2 ms增加0.45 ms到2.45ms。这样舵机在两个方向上都能完整运动到90度。“0.55”和“2.45”除以1000,是将它们转换为毫秒。“0.45”只是本例中经验证后,舵机最有效的修正值,可以根据实际调整,代码中通过以下公式找到最合适的修正值:
myCorrection=0 maxPW=(2.0+myCorrection)/1000 minPW=(1.0-myCorrection)/1000
修正量以每0.05增加/减少。“myCorrection”必须是一个介于0和1之间的数字,但不可能是1 !
Python Servo示例脚本#3 -精准定位
一旦我们确定了舵机的最小和最大脉冲宽度值,就可以使用这些“值”将舵机定位在其极限范围内的任何位置。将“value”参数设置为介于-1和+1之间的数字,就可以使舵机臂在其最小和最大位置之间移动。代码如下:
# Minimum position servo.value=-1 # Mid-point servo.value=0 # Maximum position servo.value=1 # Position between mid-point and maximum servo.value=0.5
下面的脚本生成了一系列的“值”来扫描舵机是否在其最大和最小位置范围内:
from gpiozero import Servo from time import sleep myGPIO=17 myCorrection=0 maxPW=(2.0+myCorrection)/1000 minPW=(1.0-myCorrection)/1000 servo = Servo(myGPIO,min_pulse_width=minPW,max_pulse_width=maxPW) while True: print("Set value range -1.0 to +1.0") for value in range(0,21): value2=(float(value)-10)/10 servo.value=value2 print(value2) sleep(0.5) print("Set value range +1.0 to -1.0") for value in range(20,-1,-1): value2=(float(value)-10)/10 servo.value=value2 print(value2) sleep(0.5)
第一个For循环生成一组介于0和20之间的整数。这个值减去10得到-10到10的范围。最后除以10得到-1到+1的范围。原始的值集包含20个整数,序列中还有20个步数。要将步数增加到40,需要将20替换为40,并减去20而不是10。第二个For循环做同样的事情,但是生成一个从+1返回-1的序列。
将代码复制存储到名为“servo3.py”的文件中。使用以下命令运行脚本:
python servo3.py
最后,你也可以根据需要修改到吗,让舵机按你的意图进行移动。例如,你可以随机生成一个介于-1和+1之间的数字,将舵机定位在其最大和最小移动范围内,或者根据传感器或操纵杆的输入值来移动舵机,重点是能将传感器的输入值转换为-1到+1的范围,就可以使舵机根据传感器或操作杆来运动了。