尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

树莓派4B+PCA9685舵机控制全攻略:从PWM抖动根源到平稳驱动

发布时间:2026/9/28 1:52:44

资讯中心
01
ARTICLE

树莓派4B+PCA9685舵机控制全攻略:从PWM抖动根源到平稳驱动

树莓派4B+PCA9685舵机控制全攻略:从PWM抖动根源到平稳驱动
舵机一上电就左右抖、走不到位、转起来像抽风——这在树莓派上玩舵机的人基本都遇到过。我最早用树莓派4B的GPIO口直接输出PWM来控制SG90时就被这个问题折磨过两个晚上代码看着没问题频率也算对了可舵机就是又颤又飘时不时还发出高频滋滋声。后来把控制链路改成树莓派4B PCA9685方案由PCA9685这块16通道的硬件PWM驱动板来专职生成脉冲问题才算真正解决。这篇东西就是我完整复盘下来的记录为什么要这么改、硬件怎么接、代码怎么写、参数怎么算、抖动怎么排查全部给你捋顺。不管你是刚入手树莓派准备做机械臂还是机器人小车还是被PWM抖动搞到头大的老玩家按这套流程走都可以少踩一半的坑。1. 为什么树莓派直接输出PWM会抖先搞清楚问题根源1.1 树莓派原生PWM的硬伤树莓派4B的实际硬件PWM通道非常有限正常情况下能用的就那么两路分别对应GPIO12、GPIO13再加上它的互补输出一共也就四个引脚。硬件PWM够用吗做一个两轴云台勉强够想控制四足机器人、六足机器人那种八个甚至十几个舵机的项目直接麻爪。于是很多教程会让你用软件PWM也就是通过GPIO库在Python里不断翻转电平来模拟出波形。问题是树莓派跑的是Linux它不是实时系统Python解释器执行一条指令的时机本来就受操作系统调度影响再加上time.sleep()的最小精度往往只有几毫秒GPIO翻转的时间点就会随机漂移。舵机需要的是什么一个周期稳定在20毫秒左右的方波脉冲宽度精确到几十微秒而且每一帧的周期要均匀。软件PWM恰恰做不到这一点今天你的树莓派后台多跑一个进程明天WiFi信号不好触发网卡重传PWM波形就会毛刺不断。表现出来就是舵机乱抖、发热、走到目标角度后还来回挣扎。1.2 PCA9685到底解决了什么PCA9685是NXP出品的一块16路PWM控制器走I2C总线输出12位分辨率0到4095的脉冲。它和树莓派的关系很简单树莓派只负责把“频率”和“每个通道的占空比”这两个参数写进去之后PCA9685内部用独立时钟自己生成PWM波形跟树莓派CPU的调度完全解耦。这一下就把问题解决了一大半。就算树莓派后台在编译程序、下载固件、跑神经网络推理PCA9685这边的波形依然纹丝不动。而且它是16通道的一路I2C总线最多能挂多块PCA9685通过修改板上的地址跳线最多可以扩展出上千路PWM通道应付机器人、机械臂、云台的舵机阵列绰绰有余。还有一个细节很多人忽略PCA9685的每个通道都有独立的ON和OFF时间寄存器意味着你可以让通道之间错开相位启动。这一点在做多关节动作时特别有用能显著减小电源的瞬间冲击。1.3 什么场景该用、什么场景别用PCA9685不是万能药。如果只是控制一两个舵机我建议直接用树莓派的硬件PWM引脚加pigpio库接线更少延迟更低没必要折腾一块外设板。如果控制的是需要几十kHz频率的电机调速PCA9685最高PWM频率大概在1.5kHz左右远远不够得换专用的电机驱动方案。PCA9685的最佳场景很明确舵机数量多、动作要求平滑、需要长期稳定运行的机器人项目。我现在的机械臂项目就是树莓派4B 三块PCA9685分别管理六个关节舵机和两个云台舵机实测下来无论是脉冲稳定性还是多路扩展性都让人放心。2. 硬件清单、接线与供电方案2.1 器件清单和选购避坑标准配置如下树莓派4B主板任意内存版本都可以PCA9685模块一块舵机多可以买多块舵机若干我用的是SG90、MG996R混合搭配5V外置电源注意电流余量母对母杜邦线若干1000µF以上电解电容一个可选示波器I2C延长线买PCA9685模块时最大的坑是晶振问题。看板子上有没有安装一个25MHz的石英晶振。有晶振的版本PWM时钟由外部晶振锁定非常稳定没有晶振的版本用的是PCA9685芯片内部振荡器出厂精度一般还容易受温度影响表现出来就是微小漂移和周期抖动。做高精度舵机控制尽量买带晶振的板子价格也就多几块钱省一堆麻烦。舵机选择也要看你的应用。SG90是9克小舵机扭矩小、电流小适合做云台和人形机器人的小关节。MG996R是金属齿轮大扭矩舵机峰值电流能到2A以上做机械臂的主关节更合适。买舵机时看清楚是标准舵机还是360度连续旋转改版连续旋转舵机的PWM映射和标准舵机完全不同本文讲的是标准舵机。2.2 接线步骤和共地原则接线看起来简单但很多人第一步就接错了。树莓派4B的I2C接口在GPIO2SDA和GPIO3SCL物理引脚分别是3号和5号引脚。对照表如下功能PCA9685引脚树莓派4B引脚I2C数据SDAGPIO2物理引脚3I2C时钟SCLGPIO3物理引脚5逻辑电源VCC3.3V物理引脚1逻辑地GNDGND物理引脚6舵机电源正极V外置5V正极舵机电源负极GND外置5V负极这里最关键的一条原则是“共地”。如果你用外置电源给舵机供电外置电源的GND必须和树莓派的GND连在一起。道理很简单I2C的信号是相对的电压差如果两边的地电位不一致树莓派发出的0和1在PCA9685看起来就会飘忽不定轻则通信出错重则烧芯片。舵机信号线接到PCA9685的对应通道输出口注意三个引脚的方向。标准舵机接口是三根线棕线或黑线是GND红线是VCC即正极橙线或黄线是信号线。接舵机时先确认舵机端的线序尤其便宜舵机的线序偶尔会不按套路来接反之前最好用万用表测一下。2.3 供电设计的计算思路供电是整个系统能不能稳定的核心。很多抖动问题根本不是PWM质量问题纯粹是电源被拉垮了。先算电流。一只SG90静止状态下大约是几十毫安转动时200毫安左右堵转时可能飙到500到700毫安。MG996R静止电流低但带载转动轻松上1A堵转瞬间冲到2A以上都不奇怪。如果系统里有6只MG996R同时启动瞬时电流需求可能达到10A以上。供电电流估算经验公式总电流 舵机数量 × 单舵机峰值电流 × 同时系数。同时系数一般取0.5到0.8因为不是所有舵机会在同一瞬间满负载转动但做机械臂时如果你故意让所有关节同时大力抓取就得按最大系数算。给6只MG996R供电我实际用了12V转5V的降压模块峰值能输出12A。没外置电源只用树莓派USB-C口供电的话一个MG996R的启动电流就能把树莓派电压拉低轻则舵机抽搐重则树莓派直接重启。电源线也要讲究。同样5V电源如果导线太细走线过长负载一上来线路压降就足以让舵机电压跌破4.5V。舵机电压不足的典型表现是无负载时正常一加载就抖或者力不从心。电源线尽量粗、短可以用AWG18以上的硅胶线。另外在PCA9685的V和GND之间并一颗1000µF以上电解电容能显著吸收瞬时电流尖峰这是花几毛钱解决大问题的好习惯。3. 环境准备启用I2C并验证设备3.1 开启树莓派I2C接口树莓派官方系统的I2C接口默认是关闭的需要手动打开。在终端运行sudo raspi-config进入“Interface Options”选择“I2C”回车选择“Yes”系统会提示I2C内核模块已启用。重启后生效或者命令行加载模块sudo modprobe i2c_dev重启完成之后先确认I2C设备节点存在ls /dev/i2c*正常会输出/dev/i2c-1。树莓派4B的I2C控制器默认挂在1号总线上。然后安装必要工具sudo apt update sudo apt install -y python3-pip python3-smbus i2c-tools注意如果你用的是Raspberry Pi OS Bookworm版本直接用pip3安装Python包时可能会遇到“externally managed environment”的提示。这种情况可以用虚拟环境或者加--break-system-packages参数强制安装测试用怎么方便怎么来。3.2 安装依赖与验证设备地址验证PCA9685是否被系统识别运行i2cdetect -y 1如果接线正确会在地址0x40处看到一个编号。PCA9685的默认I2C地址就是0x40这是由板上A0到A5地址引脚默认全部接低电平决定的。如果你插了多块PCA9685需要给每块板设置不同地址。方法是把板上的A0、A1等引脚焊接到VCC或GND来改变地址值A0接到VCC地址变成0x41再把A1也接上地址变成0x42以此类推。这个操作要在断电状态下进行焊完之后再上电测试。地址验证很重要我见过不少“舵机怎么没反应”的求助最后发现是i2cdetect根本没扫到设备原因是SDA和SCL接反了或者忘了共地。先用i2cdetect扫地址再跑控制代码能省去一大半无谓的排查时间。Python控制还需要安装Adafruit的ServoKit库pip3 install adafruit-circuitpython-servokit这个库封装了PCA9685寄存器的底层操作并提供Servo类把“角度转脉冲宽度”的换算也一并解决了非常适合快速上手。4. 软件实现从PWM频率到舵机角度4.1 PCA9685的PWM频率与预设分频计算PCA9685内部时钟基准是25MHz输出是12位分辨率也就是每个周期分成4096个时间片。芯片通过一个8位的预设分频寄存器PRE_SCALE来调整最终PWM频率计算公式是prescale round(25000000 / (4096 × 频率)) - 1标准舵机需要50Hz的PWM频率代入计算prescale round(25000000 / (4096 × 50)) - 1 round(122.07) - 1 122 - 1 121也就是把PRE_SCALE寄存器设为121时实际PWM频率为实际频率 25000000 / (4096 × (121 1)) ≈ 50.03Hz周期约为19.99毫秒误差不到千分之一完全可以接受。这个计算过程建议自己算一遍别看库函数一行代码就跳过了。因为实操中如果换了一个不是25MHz晶振的板子或者想调成60Hz、100Hz的非标准频率只有懂得原理才能自己改参数不至于全靠试。4.2 舵机角度与脉冲宽度的换算舵机的转角控制规则是周期固定为20毫秒脉冲宽度决定角度。标准舵机以SG90为例0°对应0.5毫秒脉宽180°对应2.5毫秒脉宽中间基本呈线性关系。在PCA9685的4096个时间片里每个时间片对应的时间是多少呢20毫秒 / 4096 ≈ 4.88微秒所以脉宽换算成tick数的公式是tick数 脉宽(微秒) × 4096 / 20000几个关键点可以直接查表舵机角度脉宽tick数0°0.5ms10245°1.0ms20590°1.5ms307135°2.0ms410180°2.5ms512注意不同舵机的脉宽范围会有差异比如MG996R大多能到0.5到2.5毫秒而有些舵机只能到0.7到2.3毫秒强行驱动到极限位置会咔咔响久而久之齿轮就崩了。所以写代码时最好把每个舵机的可工作范围都测出来单独设置。4.3 基于Adafruit ServoKit的完整控制代码如果你是第一次跑通整条链路直接用ServoKit是最省事的from adafruit_servokit import ServoKit import time kit ServoKit(channels16) # 设置通道0的脉宽范围单位是微秒 kit.servo[0].set_pulse_width_range(500, 2500) # 转到90度 kit.servo[0].angle 90 time.sleep(1) # 转到30度 kit.servo[0].angle 30 time.sleep(1) # 释放舵机取消信号 kit.servo[0].angle None这里angle会帮我们自动完成角度到tick数的换算内部走的就是4.2节的公式。运行这段代码前先用i2cdetect确认设备在0x40否则ServoKit会报错找不到设备。ServoKit有个细节每次设置angle它内部会立即把脉宽写入PCA9685寄存器PWM随之变化所以不需要额外调用刷新函数。实测纯Python环境下从调用angle到波形更新延迟通常小于几毫秒很多项目完全够用。4.4 手动写寄存器想彻底搞懂底层就这么来ServoKit帮我们封得太高级很多读者其实更想知道底层到底干了什么。下面给一套不依赖任何库的手写寄存器方案用smbus2直接操作I2C。import smbus2 import time bus smbus2.SMBus(1) PCA9685_ADDR 0x40 MODE1 0x00 PRESCALE 0xFE CHANNEL0_ON_L 0x06 def setup_pca9685(freq50): osc_clock 25_000_000 prescale int(round(osc_clock / (4096 * freq))) - 1 # 读取当前MODE1 oldmode bus.read_byte_data(PCA9685_ADDR, MODE1) # 进入SLEEP模式才能修改PRE_SCALE bus.write_byte_data(PCA9685_ADDR, MODE1, (oldmode 0x7F) | 0x10) # 写入分频值 bus.write_byte_data(PCA9685_ADDR, PRESCALE, prescale) # 恢复原模式并从sleep唤醒 bus.write_byte_data(PCA9685_ADDR, MODE1, oldmode) time.sleep(0.005) # 设置RESTART让PWM重新输出 bus.write_byte_data(PCA9685_ADDR, MODE1, oldmode | 0x80) def set_channel_pwm(channel, off_ticks): # 每通道4个寄存器ON_L, ON_H, OFF_L, OFF_H reg CHANNEL0_ON_L channel * 4 # ON设为0表示每个周期从第0个tick开始输出高电平 bus.write_byte_data(PCA9685_ADDR, reg, 0x00) bus.write_byte_data(PCA9685_ADDR, reg 1, 0x00) # OFF写入目标tick数12位值拆成低8位和高4位 bus.write_byte_data(PCA9685_ADDR, reg 2, off_ticks 0xFF) bus.write_byte_data(PCA9685_ADDR, reg 3, (off_ticks 8) 0x0F) def set_servo_angle(channel, angle, us_min500, us_max2500): # 角度转脉宽再转tick数 us us_min (angle / 180.0) * (us_max - us_min) off_ticks int(us * 4096 / 20000) set_channel_pwm(channel, off_ticks) setup_pca9685(50) set_servo_angle(0, 90) set_servo_angle(1, 45)这里有几个细节要解释。第一为什么改PRE_SCALE前必须进SLEEP模式因为PCA9685要求分频寄存器只能在睡眠状态下修改否则芯片运行状态不可预料。第二为什么ON要写0我们希望每个周期从0开始就输出高电平然后到OFF的tick数时拉低这样才产生一个从周期起点开始的脉冲。第三OFF寄存器高4位掩码用0x0F因为12位数据的高4位只占用一个字节的低4位剩下的高位必须留0。这份代码跑出来的效果和ServoKit一模一样但你每一步都在做底层操作以后遇到奇葩问题也更容易定位。4.5 告别抖动的进阶操作平滑渐变很多舵机抖动的根源不是PWM精度而是你的程序让舵机“瞬移”。比如从0度直接跳到180度舵机为了在最短时间内到达目标会以最大速度猛冲产生的机械冲击和电流尖峰都会让系统一震后续控制也会变形。我习惯在代码里加平滑渐变让舵机按一定步长逐步逼近目标角度def smooth_move(kit, channel, target, step2, delay0.02): current kit.servo[channel].angle if current is None: current target if target current: value current while value target: value min(value step, target) kit.servo[channel].angle value time.sleep(delay) elif target current: value current while value target: value max(value - step, target) kit.servo[channel].angle value time.sleep(delay)step代表每帧变化的角度delay代表帧间隔。step2、delay0.02秒意味着舵机每秒大致走100度这个速度对做机械臂抓取比较平滑。你可以根据项目需要调节这两个参数想快就加大step想柔和就减小step、加大delay。这里背后有两个关键点。第一步进式的角度更新把一次大电流冲击拆成了若干小电流冲击电源负担小得多。第二每帧之间留了20毫秒以上的间隔给舵机完整执行动作和稳定下来的时间避免连续指令互相冲突。如果你在做需不停切换角度的动作序列还能用预计算脉宽表。把整个动作的每个角度提前映射成tick数存到数组里运行时直接查表写寄存器比每次做浮点运算快也能减少计算抖动。5. 常见问题排查与经验心得5.1 抖动问题定位与解决抖动分几种解决思路完全不同。第一类是持续性的高频抖动。舵机静止在某个角度时还嗡嗡响、左右小幅摆动。先在电源上下手用万用表量一下PCA9685的V和GND之间的电压看是不是在4.8V以上。如果电压稳定那就是PWM脉冲本身的问题换一块带外部晶振的PCA9685再试。第二类是动作过程中的卡顿或抽搐。这通常是平滑控制没做或者程序里执行了太多高负载任务导致I2C写入不及时。先检查你同时开了多少线程和后台任务再按4.5节的方式加入渐变逻辑。第三类是偶发性的随机抖动。这种可能就是共地不良、接线松动、或者I2C数据线太长受干扰。把I2C线缩短到20厘米以内适当降低I2C波特率或者在树莓派配置里加一行dtparami2c_arm_baudrate100000让通信更稳定。有示波器的话可以直接量PCA9685输出的PWM引脚看波形。正常波形应该是矩形波跳变沿干净、周期均匀。如果频率漂移明显芯片时钟有问题如果波形毛刺多供电或接地有问题。示波器的波形图比肉眼判断靠谱得多。5.2 常见故障速查表现象可能原因排查方法舵机完全不转PCA9685没供电或I2C接线错误i2cdetect确认设备地址测V电压只有部分通道有输出舵机信号线插错通道对照通道编号检查接线舵机一直往一个方向转输入了超出范围的脉宽检查角度映射公式和脉宽范围静止时高频抖动供电不稳或无晶振板子频率漂移测电压换带晶振的板子加滤波电容动作时卡顿抽搐缺少平滑过渡或程序负载过高加渐变逻辑减少后台任务多个舵机同时动作时掉电电源电流余量不足重新按峰值电流总和选用电源i2cdetect扫不到设备SDA/SCL接反或忘了共地重新查接线确保共地这张表我建议收藏起来每次排障直接从现象到根因不用每次重新人肉排查一遍。5.3 我踩过的几个坑和最终建议第一个坑是刚开始图便宜买了没有晶振的PCA9685结果舵机静止时总是轻微颤抖用示波器测了PWM频率发现中心频率在49.7Hz到50.3Hz之间来回飘。后来换了带25MHz晶振的板子波形立刻稳了。所以我现在给所有朋友的建议都是高精度舵机控制PCA9685要选带晶振版本。第二个坑是电源。一开始我用一个5V 2A的手机充电器给4只SG90供电以为够用结果舵机一转电压就跌到4.2V不仅舵机抖树莓派的声音也开始怪叫。后来换成专门的大电流5V电源问题立刻消失。千万别拿“额定5V 2A”的电源去带多个力矩舵机要用就按峰值电流对总需求做足余量。第三个坑是贪快直接让舵机从0度瞬移到180度。第一版机械臂调试时每次快速摆动都导致电源电压被瞬间拉低其他舵机跟着抖动。加上平滑渐变之后整个机械臂的动作才稳定下来。这事告诉我舵机控制不光是发出正确的PWM波形还要考虑机械系统的负载和电源的物理承受能力。最后再分享一个小技巧。如果你想把舵机初始化得更有仪式感可以开机后先让所有通道输出一个安全的中间角度比如90度停半秒再执行真正的动作序列。这样做可以避免上电瞬间舵机突然冲到一个极端位置既保护舵机齿轮也让机械结构更安全。特别是在多关节机械臂上这个习惯能少扭断好几个塑料齿轮。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。