树莓派使用GpioZero控制舵机

  • 内容
  • 评论
  • 相关

舵机是用通过齿轮来产生旋转运动的电动机。无线电控制的小车和其他的机器人项目经常会使用它来产生运动。舵机的大小和产生的力量各不相同,小型舵机很便宜,关于树莓派控制舵机的文章已经有很多了。诸如:树莓派PWM控制舵机的两种方式树莓派3 B+Servoblaster 舵机控制等等。今天我们在研究一下树莓派使用GpioZero来控制舵机。

舵机的接口定义

舵机通常有三根线。两根用于电源,一根是信号线。这些线的颜色因制造产商的不同也会存在一些差异,但通常都会采用以下几种方案之一:

舵机电缆颜色方案

舵机与PWM

舵机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的范围,就可以使舵机根据传感器或操作杆来运动了。