树莓派使用PCA9685控制舵机

PAC9685是一款专门为LED背光调节而设计的控制芯片,为了提高性能,芯片专门针对红、绿、蓝、琥珀(RGBA)等颜色的混合进行优化,通过输出PWM脉冲信号来控制LED亮度。PAC9685能输出16路(16-channel)PWM信号,也可以用于控制舵机,只需要通过两个I2C接口。本文主要介绍使用树莓派通过PCA9685来控制舵机,实现摄像头的二自由度云台。

本文中涉及的树莓派是3B+,舵机是sg90,首先来一张PCA9685的外观图:

PCA9685芯片工作电压在2.3 - 5.5V,可以由树莓派的3V输出供电,舵机供电使用外部电源,如果使用树莓派的5V输出可能引起树莓派的不稳定。树莓派、PCA9685和舵机的接线图如下:

  • 树莓派3.3V输出连接PCA9685的VCC
  • 树莓派GND连接PCA9685的GND
  • 树莓派SCL连接PCA9685的SCL
  • 树莓派SDA连接PCA9685的SDA
  • 舵机的黄线连接channel 0的PWM
  • 舵机的红线连接channel 0的V+
  • 舵机的棕线连接channel 0的GND

由于PCA9685是通过I2C来控制的,在使用PCA9685之前首先要开启树莓派的I2C接口,输入如下命令:

1
sudo raspi-config

选择”5 Interfacing Options - P5 I2C”,启用后重启树莓派。

启用I2C之后,安装python库及i2c工具:

1
2
sudo apt-get install python-smbus
sudo apt-get install i2c-tools

i2c-tools是用来查找7-bit I2C地址:

1
sudo i2cdetect -y 1

以上命令会扫描/dev/i2c-1 port,会出来如下信息:

安装adafruit-pca9685:

1
sudo pip install adafruit-pca9685

下面是一个使用python来控制舵机的脚本,使用pca9685的channel 4 和 channel 5,通过方向键控制二自由度摄像头云台:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
from __future__ import division
import time
import Adafruit_PCA9685
import sys,tty,termios

class Servo(object):
def __init__(self):
self.pwm = Adafruit_PCA9685.PCA9685()
self.pwm.set_pwm_freq(50)

def set_angle(self, channel, angle):
# pulse_width=((angle*11)+500)/1000, 0.5ms - 2.5ms
# pulse/4096=pulse_width/20
pulse = int(4096*((angle*11)+500)/20000)
self.pwm.set_pwm(channel, 0, pulse)

class _Getch:
def __call__(self, n):
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(n)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch

if __name__ == "__main__":
pan = 90
tilt = 90
servo = Servo()
servo.set_angle(4, pan)
servo.set_angle(5, tilt)
inkey = _Getch()

print("enter ext for quit")
try:
while True:
k = inkey(3)
if k == '\x1b[A':
print("up")
tilt -= 1
servo.set_angle(5, tilt)

elif k == '\x1b[B':
print("down")
tilt += 1
servo.set_angle(5, tilt)

elif k == '\x1b[C':
print("right")
pan += 1
servo.set_angle(4, pan)

elif k == '\x1b[D':
print("left")
pan -= 1
servo.set_angle(4, pan)

elif k == 'ext':
print("exit")
servo.set_angle(4, 90)
servo.set_angle(5, 90)
break
else:
print("not an arrow key!")

except KeyboardInterrupt:
pass

PWM频率在设置为50Hz的情况下,输出角度angle为0 ~ 180°C,高电平占空时间pulse_width为0.5 ~ 2.5ms,其为线性关系,可得出方程:

1
pulse_width=1/90 * angle + 0.5

近似为:

1
pulse_width=(11*angle + 500)/1000

PCA9685的精度(分辨率)为4096(2^12),可得公式:

1
pulse/4096=pulse_width/20

最终得到角度(angle)转4096分辨率(2^12)数值公式为:

1
pulse=4096*((angle*11)+500)/20000

参考: