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接口,输入如下命令:
选择”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地址:
以上命令会扫描/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
|
参考: