制作坊python教程--PCA9685PW驱动电机 专区

python教程--PCA9685PW驱动电机

binglingdang2019-01-22 1951人围观
简介PCA9685PW 是一款 I2C 总线 接口的 16 位 LED 控制器,每个 LED 都可以输出 12 位分辨率(4096 级)固定频率的独立 PWM 控制器,通过输出PWM驱动电机动作

    PCA9685PW 是一款 I2C 总线接口的 16 位 LED 控制器,每个 LED 都可以输出 12 位分辨率(4096

级)固定频率的独立 PWM 控制器,通过输出PWM驱动电机动作。

    PCA9685PW 连接 micro:bit 的 P19 和 P20 引脚进行I2C 通讯,建立通讯以后就可以控制16路引脚输出PWM了。

以集成了PCA9685PW 的microo:bit高级版扩展板为例,首先是原理图

image.png

image.png

    从原理图中得知使机器人前进只需要使得 LINA(12)输出高电平,LINB(13)输出低电平,RINA(14)输出高电平,RINB(15)输出低电平就可以了。

    接下来开始编程,可以选择在线版和离线版,我个人比较习惯使用离线版mu进行编程,注意!

    1.所有的英文与符号都应该在英文状态下输入,关键词如“,”与后面的内容之间需要有个空格,使用Tab键(制表键)进行缩进,最后一行以空白程序结尾。

    2.如下图所示,点击大拇指图标的Check(检查)键检查一下我们的代码是否有错误。如果某一行出现光标或下划线,表示某一行的程序出错,如果没有出现光标或下划线,则表示代码没有错误。

image.png

3.将micro USB数据线连接micro:bit与电脑,接着如下图所示点击Flash(刷入)按键下载程序至micro:bit

image.png

4. 下载成功后,可以观察到电机被驱动了,如视频所示。


程序源码:


from microbit import *

import ustruct

import math


# Registers/etc:

PCA9685_ADDRESS = 0x41

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 = 0x04

RESET = 0x00



class PCA9685():


    def __init__(self, address=PCA9685_ADDRESS):

        self.address = address

        i2c.write(self.address, bytearray([MODE1, RESET]))

        self.set_all_pwm(0, 0)

        i2c.write(self.address, bytearray([MODE2, OUTDRV]))

        i2c.write(self.address, bytearray([MODE1, ALLCALL]))

        sleep(5)  # wait for oscillator

        i2c.write(self.address, bytearray([MODE1]))

        mode1 = i2c.read(self.address, 1)

        mode1 = ustruct.unpack('

        mode1 = mode1 & ~SLEEP  # wake up (reset sleep)

        i2c.write(self.address, bytearray([MODE1, mode1]))

        sleep(5)  # wait for oscillator


    def set_pwm_freq(self, freq_hz):

        prescaleval = 25000000.0    # 25MHz

        prescaleval /= 4096.0       # 12-bit

        prescaleval /= float(freq_hz)

        prescaleval -= 1.0

        # print('Setting PWM frequency to {0} Hz'.format(freq_hz))

        # print('Estimated pre-scale: {0}'.format(prescaleval))

        prescale = int(math.floor(prescaleval + 0.5))

        # print('Final pre-scale: {0}'.format(prescale))

        i2c.write(self.address, bytearray([MODE1]))

        oldmode = i2c.read(self.address, 1)

        oldmode = ustruct.unpack('

        newmode = (oldmode & 0x7F) | 0x10    # sleep

        i2c.write(self.address, bytearray([MODE1, newmode]))  # go to sleep

        i2c.write(self.address, bytearray([PRESCALE, prescale]))

        i2c.write(self.address, bytearray([MODE1, oldmode]))

        sleep(5)

        i2c.write(self.address, bytearray([MODE1, oldmode | 0x80]))


    def set_pwm(self, channel, on, off):

        if on is None or off is None:

            i2c.write(self.address, bytearray([LED0_ON_L+4*channel]))

            data = i2c.read(self.address, 4)

            return ustruct.unpack('> 8]))

        i2c.write(self.address, bytearray([LED0_OFF_L+4*channel, off & 0xFF]))

        i2c.write(self.address, bytearray([LED0_OFF_H+4*channel, off >> 8]))


    def set_all_pwm(self, on, off):

        i2c.write(self.address, bytearray([ALL_LED_ON_L, on & 0xFF]))

        i2c.write(self.address, bytearray([ALL_LED_ON_H, on >> 8]))

        i2c.write(self.address, bytearray([ALL_LED_OFF_L, off & 0xFF]))

        i2c.write(self.address, bytearray([ALL_LED_OFF_H, off >> 8]))


    def duty(self, index, value=None, invert=False):

        if value is None:

            pwm = self.set_pwm(index)

            if pwm == (0, 4096):

                value = 0

            elif pwm == (4096, 0):

                value = 4095

            value = pwm[1]

            if invert:

                value = 4095 - value

            return value

        if not 0 <= value <= 4095:

            raise ValueError("Out of range")

        if invert:

            value = 4095 - value

        if value == 0:

            self.set_pwm(index, 0, 4096)

        elif value == 4095:

            self.set_pwm(index, 4096, 0)

        else:

            self.set_pwm(index, 0, value)



# Initialise the PCA9685 using the default address (0x41).

pwm = PCA9685()


# Configure min and max servo pulse lengths

servo_min = 150  # Min pulse length out of 4096  0?

servo_max = 600  # Max pulse length out of 4096: 180?



# Set frequency to 60hz, good for servos.

pwm.set_pwm_freq(60)



pwm.set_pwm(12, 0, 4095)

pwm.set_pwm(13, 0, 0)

pwm.set_pwm(15, 0, 4095)

pwm.set_pwm(14, 0, 0)


pwm.set_pwm(3, 0, servo_min)

sleep(1000)

pwm.set_pwm(3, 0, servo_max)

sleep(1000)


4 +1

评论