很久之前整过PWM舵机,刚好最近师弟需要,并且网上现有教程不是很完整,就整理一下。方便交流以及后面回顾。
首先要明确,在这个控制方式中需要用到哪些方面:
1、树莓派与PCA9685之间使用I2C通信
2、PCA9685通讯协议
3、FT2331M舵机性能参数
一、树莓派与PCA9685 I2C通信
接线
接线方式可如下图所示,参考树莓派4B使用PCA9685控制舵机:
其中VCC供电为6V.
开启I2C:
在终端执行:
sudo raspi-config
Interfacing Options-->I2C-->YES-->Finish
保险起见 重启树莓派 终端输入 :
sudo reboot
安装相关库文件:
sudo apt-get update
sudo apt-get install python-pip
sudo pip install RPi.GPIO
sudo apt-get install python-smbus
开启I2C并且完成树莓派与PCA9685接线之后,可以通过如下命令查看设备是否正常搭载:
ls /dev/*i2c*
查看I2C搭载设备地址:
pi@raspberrypi:~ $ sudo i2cdetect -y 1 # 默认为I2C1,如果是I2C0.则只需要将1-->0即可
关于I2C设备的操作,详细可看之前的文章关于树莓派4B两个I2C通道(I2C0、I2C1)的总结 。
二、PCA9685通讯协议
相关代码我放在文中,并且有具体注释。
from __future__ import division
import logging
import time
import math# Registers/etc:
PCA9685_ADDRESS = 0x40
MODE1 = 0x00
MODE2 = 0x01
SUBADR1 = 0x02
SUBADR2 = 0x03
SUBADR3 = 0x04
PRESCALE = 0xFE
LED0_ON_L = 0x06
LED0_ON_H = 0x07
LED0_OFF_L = 0x08
LED0_OFF_H = 0x09
ALL_LED_ON_L = 0xFA
ALL_LED_ON_H = 0xFB
ALL_LED_OFF_L = 0xFC
ALL_LED_OFF_H = 0xFD# Bits:
RESTART = 0x80
SLEEP = 0x10
ALLCALL = 0x01
INVRT = 0x10
OUTDRV = 0x04logger = logging.getLogger(__name__)def software_reset(i2c=None, **kwargs):"""Sends a software reset (SWRST) command to all servo drivers on the bus."""# Setup I2C interface for device 0x00 to talk to all of them.if i2c is None:import Adafruit_GPIO.I2C as I2Ci2c = I2Cself._device = i2c.get_i2c_device(0x00, **kwargs)self._device.writeRaw8(0x06) # SWRSTclass PCA9685(object):"""PCA9685 PWM LED/servo controller."""def __init__(self, address=PCA9685_ADDRESS, i2c=None, **kwargs):"""Initialize the PCA9685."""# Setup I2C interface for the device.if i2c is None:import Adafruit_GPIO.I2C as I2Ci2c = I2Cself._device = i2c.get_i2c_device(address, **kwargs)self.set_all_pwm(0, 0)self._device.write8(MODE2, OUTDRV)self._device.write8(MODE1, ALLCALL)time.sleep(0.005) # wait for oscillatormode1 = self._device.readU8(MODE1)mode1 = mode1 & ~SLEEP # wake up (reset sleep)self._device.write8(MODE1, mode1)time.sleep(0.005) # wait for oscillatordef set_pwm_freq(self, freq_hz):"""Set the PWM frequency to the provided value in hertz."""prescaleval = 25000000.0 # 25MHzprescaleval /= 4096.0 # 12-bitprescaleval /= float(freq_hz)prescaleval -= 1.0logger.debug('Setting PWM frequency to {0} Hz'.format(freq_hz))logger.debug('Estimated pre-scale: {0}'.format(prescaleval))prescale = int(math.floor(prescaleval + 0.5))logger.debug('Final pre-scale: {0}'.format(prescale))oldmode = self._device.readU8(MODE1);newmode = (oldmode & 0x7F) | 0x10 # sleepself._device.write8(MODE1, newmode) # go to sleepself._device.write8(PRESCALE, prescale)self._device.write8(MODE1, oldmode)time.sleep(0.005)self._device.write8(MODE1, oldmode | 0x80)def set_pwm(self, channel, on, off):"""Sets a single PWM channel."""self._device.write8(LED0_ON_L+4*channel, on & 0xFF)self._device.write8(LED0_ON_H+4*channel, on >> 8)self._device.write8(LED0_OFF_L+4*channel, off & 0xFF)self._device.write8(LED0_OFF_H+4*channel, off >> 8)def set_all_pwm(self, on, off):"""Sets all PWM channels."""self._device.write8(ALL_LED_ON_L, on & 0xFF)self._device.write8(ALL_LED_ON_H, on >> 8)self._device.write8(ALL_LED_OFF_L, off & 0xFF)self._device.write8(ALL_LED_OFF_H, off >> 8)def cmd(self, channel, Position):'''已经进行数据转换,position范围0-210度''''''PCA9685是一种PWM控制器,可以产生从0到4096之间的脉宽值,对应于PWM信号的高电平时间PWM频率被设置为60Hz,周期的时间为 1 / 60 秒,即约 16.67 毫秒(16666 微秒)servo_min = 150 # Min pulse length out of 4096servo_max = 600 # Max pulse length out of 4096servo_min 的实际脉宽时间为 (150 / 4096) * 16666 微秒 ≈ 610 微秒servo_max 的实际脉宽时间为 (600 / 4096) * 16666 微秒 ≈ 2440 微秒Ft2331舵机参数为0~240°对应500~2500us'''servo_min = int(500 * 60 / 1000000 * 4096) # Min pulse length out of 4096servo_max = int(2500 * 60 / 1000000 * 4096) # Max pulse length out of 4096Position = int(Position / (240 - 0) * (servo_max - servo_min) + servo_min) # 240这个数值需对每个舵机进行标定,有可能需要增大,有可能需要减小self.set_pwm(channel, 0, Position)pwm = PCA9685()
pwm.set_pwm_freq(60)
channel = 0while True:pwm.cmd(channel, 0)time.sleep(1)pwm.cmd(channel, 90)time.sleep(1)pwm.cmd(channel, 180)time.sleep(1)pwm.cmd(channel, 90)time.sleep(1)
三、FT233M1舵机参数
舵机控制参数如下所示:
从旋转角度那一栏可知,舵机由0-240°,对应周期时间为500-2500us。
所以在第二节中的协议中,控制函数cmd(self, channel, Position)中存在(同样和通信频率有关),如下代码:
'''PCA9685是一种PWM控制器,可以产生从0到4096之间的脉宽值,对应于PWM信号的高电平时间PWM频率被设置为60Hz,周期的时间为 1 / 60 秒,即约 16.67 毫秒(16666 微秒)servo_min = 150 # Min pulse length out of 4096servo_max = 600 # Max pulse length out of 4096servo_min 的实际脉宽时间为 (150 / 4096) * 16666 微秒 ≈ 610 微秒servo_max 的实际脉宽时间为 (600 / 4096) * 16666 微秒 ≈ 2440 微秒Ft2331舵机参数为0~240°对应500~2500us'''servo_min = int(500 * 60 / 1000000 * 4096) # Min pulse length out of 4096servo_max = int(2500 * 60 / 1000000 * 4096) # Max pulse length out of 4096Position = int(Position / (240 - 0) * (servo_max - servo_min) + servo_min) # 240这个数值需对每个舵机进行标定,有可能需要增大,有可能需要减小