树莓派通过PCA9685控制FT2331M舵机(Python)

        很久之前整过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             = 0x04


logger = 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 I2C
        i2c = I2C
    self._device = i2c.get_i2c_device(0x00, **kwargs)
    self._device.writeRaw8(0x06)  # SWRST


class 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 I2C
            i2c = I2C
        self._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 oscillator
        mode1 = self._device.readU8(MODE1)
        mode1 = mode1 & ~SLEEP  # wake up (reset sleep)
        self._device.write8(MODE1, mode1)
        time.sleep(0.005)  # wait for oscillator

    def set_pwm_freq(self, freq_hz):
        """Set the PWM frequency to the provided value in hertz."""
        prescaleval = 25000000.0    # 25MHz
        prescaleval /= 4096.0       # 12-bit
        prescaleval /= float(freq_hz)
        prescaleval -= 1.0
        logger.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    # sleep
        self._device.write8(MODE1, newmode)  # go to sleep
        self._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 4096
        servo_max = 600  # Max pulse length out of 4096
        servo_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 4096
        servo_max = int(2500 * 60 / 1000000 * 4096)  # Max pulse length out of 4096
        
        Position = 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 = 0

while 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 4096
        servo_max = 600  # Max pulse length out of 4096
        servo_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 4096
        servo_max = int(2500 * 60 / 1000000 * 4096)  # Max pulse length out of 4096
        
        Position = int(Position / (240 - 0) * (servo_max - servo_min) + servo_min)  # 240这个数值需对每个舵机进行标定,有可能需要增大,有可能需要减小

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/671415.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

牛客网刷题 | BC113 数字三角形

目前主要分为三个专栏,后续还会添加: 专栏如下: C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读! 初来乍到,如有错误请指出,感谢! 描述 KiKi学习了循环&am…

【Text2SQL 论文】DBCopilot:将 NL 查询扩展到大规模数据库

论文:DBCopilot: Scaling Natural Language Querying to Massive Databases ⭐⭐⭐⭐ Code: DBCopilot | GitHub 一、论文速读 论文认为目前的 Text2SQL 研究大多只关注具有少量 table 的单个数据库上的查询,但在面对大规模数据库和数据仓库的查询时时却…

RHEL7.9修改分区

系统RHEL7.9 他因为安装软件,需要修改分区 进入超级用户root,输入lsblk 查看分区,可见465.8G系统盘sda下有三个物理卷,其中sda3下/home有410.6G,需要这部分拆分出200G软件和100G的数据库分区 备份/home 目录下文件 c…

自动化办公02 用openpyxl库操作excel.xlsx文件(新版本)

目录 一、文件读操作 二、文件写操作 三、修改单元格样式 openpyxl 是一个处理Excel表格的第三方库。openpyxl 库可以处理Excel2010以后的电子表格格式,包括:xlsx/xlsm/xltx/xltm。 openpyxl教程 一、文件读操作 工作簿(workbook): excel文件 工作表…

LNMP网站架构部署

目录 一、LNMP架构部署(源码编译安装) ①实验准备 ②安装nginx服务 ③安装mysql服务,配置文件 ④安装php服务,修改配置文件 ⑤验证 静态页面测试访问 动态页面测试访问 调用数据库测试 二、LNMP架构应用实例 1.论坛网站…

南京观海微电子---简单驱动电路设计用NMOS防反接,性价比比较高?

来看看NMOS的防反保护电路有什么不同? 简单的栅极驱动电路设计,我们会使用NMOS来作防反电路,原因是成本较低。 PMOS一般会放置在电路的高边,NMOS则是在低边放置。两者的功能类似。不过,NMOS的防反结构,它…

..\MYLIB\modbus.c(49): error: #84: invalid combination of type specifiers

在keil中添加相应的文件出现以下问题时 ..\MYLIB\modbus.c(49): error: #84: invalid combination of type specifiers 是由于:在定义的函数体的前面有一个变量类型

攻防世界---misc---心仪的公司

1、题目描述 2、下载附件是一个流量包 方法一: 1、用winhex分析,ctrlf搜索flag 2、尝试将搜索到的flag拿去提交,但是不对 3、担心flag不是长flag,做题多了你就会发现有些flag会是fl4g这种,为了可以稍微全面一点&…

笔试训练2

牛客.单词搜索 刚开始我就想是搜索,但是不清楚bfs还是dfs更好,我尝试了bfs但是队列存东西,没有我想象的那么好写,所以我决定试试dfs import java.util.*;public class Solution {static int m 0;static int n 0;static int […

【AIGC】FaceChain:发挥生成式内容的无限可能性

基于图像生成的个性化肖像框架 摘要 FaceChaine提供了一系列的生成方案,通过少量的图像输入,就能生成逼真的个性化肖像。它是一个个性化肖像生成框架,包含丰富的人脸感知相关的模型,例如人脸检测,深度人脸向量提取&am…

【算法】合并两个有序链表(easy)——递归算法

题解:合并两个有序链表(easy)——递归求解 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接:LINK 2.题解 本题有两种解法, 一是用循环去处理 链接:【刷题记录】合并两个有序数组、移除元素二是用递归去处理 将在下面中说…

23、linux系统文件和日志分析

linux文件系统与日志分析 文件时存储在硬盘上的,硬盘上的最小存储单位是扇区,每个扇区大大小是512字节。 inode:元信息(文件的属性 权限,创建者,创建日期等) block:块&#xff0c…

Java 22的FFM API,比起Java 21的虚拟线程

哪个对Java未来的发展影响更大?两个 Java 版本中的重要特性:Java 21 的虚拟线程和 Java 22 的 FFM API。我这里有一套编程入门教程,不仅包含了详细的视频讲解,项目实战。如果你渴望学习编程,不妨点个关注,给…

fintuning chatglm3

chatglm3介绍 ChatGLM3-6B 是 ChatGLM 系列最新一代的开源模型,在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上,ChatGLM3-6B 引入了如下特性: 更强大的基础模型: ChatGLM3-6B 的基础模型 ChatGLM3-6B-Base 采用…

2、浮动的用法特点,解决父元素高度塌陷解决

一、浮动 用法:浮动就是使用float样式,使元素脱离文档流。属性值有三个:none默认left right 特点: 常用于文字环绕图片浮动的元素脱离文档流影响其他元素排列造成父元素高度塌陷 1、一旦元素设置了浮动,元素就会脱离…

【教程】20个高级 Python 函数,让你编程更高效

在Python的编程世界中,函数是我们编写代码的重要工具之一。除了常见的内置函数外,Python还提供了许多强大而有趣的高级函数,它们可以帮助我们简化代码、提升效率,甚至在某些情况下让编程变得更加有趣。让我们一起来探索这些高级函数的奇妙之处吧! 1.enumerate() – 枚举函…

VBA字典与数组第十五讲:多行多列数组与同列数单行数组间的运算规则

《VBA数组与字典方案》教程(10144533)是我推出的第三套教程,目前已经是第二版修订了。这套教程定位于中级,字典是VBA的精华,我要求学员必学。7.1.3.9教程和手册掌握后,可以解决大多数工作中遇到的实际问题。…

【Intro】Heterogeneous Graph Attention Network(HAN)

论文链接:https://arxiv.org/pdf/1903.07293 Abstract 异构性和丰富的语义信息给面向异构图的图形神经网络设计带来了巨大的挑战。 -> 一种基于分层注意的异构图神经网络,包括节点级注意和语义级注意。具体来说,节点级关注旨在学习节点…

Anolis OS 8.9安装Linux 服务器运维管理面板“1Panel”

一、简介 1.Linux 服务器运维管理面板“1Panel” 使用go语言编写 2.很多的项目的应用都是采用 docker 技术来实现,这让 Linux 服务器的运维管理更简单、更安全。 3.1Panel 采纳最新的前端技术,并通过精心设计的UX 交互,为用户提供更好的用户…

从0开始学统计-什么是回归?

1.什么是回归? 回归(Regression)是统计学中一种用于探索变量之间关系的分析方法。它主要用于预测一个或多个自变量(输入变量)与因变量(输出变量)之间的关系。在回归分析中,我们尝试根…