ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32舵机控制实战:PWM时序、调试与电源设计

STM32舵机控制实战:PWM时序、调试与电源设计 简介基于STM32F103单片机的6自由度机械手舵机驱动源码包面向嵌入式初学者与机器人爱好者解决多路PWM舵机控制及串口联调问题。工程采用标准库与USMART调试组件含硬件初始化、舵机底层驱动及串口命令解析等模块便于通过串口逐路调试6路PWM输出可迁移至其他机械臂或云台项目。压缩包共86个文件其中38个头文件与36个C源文件构成完整工程代码另有启动汇编、Keil工程文件、hex固件与说明文档整体仅695KB结构紧凑。目前已有987人学习适合配合正点原子或野火开发板快速验证也可作为毕业设计或课程设计的参考蓝本。通过阅读源码可掌握STM32的RCC配置、PWM波生成、串口中断接收及舵机控制算法是一份轻量实用的入门素材。1. 从机械手项目理解STM32舵机控制的三个硬门槛接手过机械臂项目的人大概都有过这种体验6个舵机单独测试时动作干净利落一旦全部装到机械手上上电瞬间就像抽风一样乱抖甚至直接卡死。问题往往不在舵机本身而在PWM时序的初始化、调试手段的缺失以及电源系统的设计。这份基于STM32F103的6自由度机械手驱动程序之所以值得拆是因为它把三个最容易卡住新手的门槛都处理得比较完整一是通过硬件初始化阶段关全局中断来保证外设配置不被串口数据打断二是引入了USMART这种串口命令行调试组件让舵机角度和脉宽的在线调整脱离「每改一次参数就重新烧录一次」的低效循环三是6路PWM的定时器通道分配方式直接决定了后续扩展机械手控制算法时的资源边界。对于正在做舵机机械手、云台、仿生臂或者入门STM32运动控制的人这套代码里的工程组织方式和调试思路比单纯抄一遍PWM初始化更有参考价值。2. 工程框架与底层初始化时钟链路、USART1重定向与JTAG释放2.1 基于固件库的工程组织FWLib、SYSTEM、HARDWARE、APP分层拿到源码包后先看目录结构就能猜出这套工程沿用的是正点原子风格的固件库分层方式。FWLib目录下是标准的STM32F10x标准外设库配合STM32F10xR.LIB这个预编译库文件使用SYSTEM目录集中了delay、sys、usart、malloc、xprintf这些与具体业务无关的基础组件HARDWARE目录放的是bsp.c/h和steer.c/h前者负责板级初始化后者专门封装舵机控制USER目录则是main.c、启动文件startup_stm32f10x_hd.s和Keil工程文件。APP目录里的usmart组件独立于业务代码之外这种分层的直接好处是当你把这份驱动移植到自己的板子上时只需要改HARDWARE层SYSTEM层里的延时和串口函数基本可以原样复用。启动文件用的是startup_stm32f10x_hd.s对应大容量Flash的F103芯片。hd后缀说明这是512KB Flash或以上的型号如果你用的是STM32F103C8T6这种中容量芯片必须换成startup_stm32f10x_md.s否则中断向量表顺序对不上程序跑起来会出现莫名其妙的问题。系统中使用KeilDelAll.bat批处理来清理OBJ目录下的临时编译产物遇到编译报错找不到头文件或者链接时符号冲突先跑一遍这个脚本再做全量编译能排除掉大部分陈旧依赖导致的问题。2.2 关闭全局中断的初始化框架为什么外设初始化需要原子化项目里硬件初始化的主函数写得很有代表性原样摘录如下void hw_init(void) { __SETPRIMASK(); // 关闭全局中断, 防止初始化中途被串口/定时器打断 { RCC_Configuration(); // 配置系统时钟: 72MHz 主频 外设时钟门控 delay_init(72); // 传入 72, 让延时函数基于 72MHz 主频校准 uart_init(9600); // 初始化串口1, 波特率 9600, 作为 USMART 调试通道 jtag_set(JTAG_SWD_DISABLE); // 释放 PA15/PB3/PB4, 这三个引脚用于舵机 PWM usmart_dev.init(72); // USMART 组件初始化, 参数 72 用于内部延时换算 steer_init(); // 初始化 6 路舵机对应的定时器和 PWM 通道 } __RESETPRIMASK(); // 重新打开全局中断 }这段代码最值得琢磨的不是每一行调用了什么函数而是最外层那对__SETPRIMASK()和__RESETPRIMASK()。这两个操作分别对应Cortex-M3内核的PRIMASK寄存器置位和清零作用是屏蔽和恢复所有可屏蔽中断。在初始化阶段关闭全局中断是为了防止这样一种情况串口数据恰好在上电瞬间到达USART1的中断服务函数被触发而此刻定时器PWM通道还没来得及配置中断里如果对未初始化的外设寄存器做了读写轻则配置被覆盖重则直接进入HardFault。把整个初始化过程包成原子操作是一种在工业控制代码里非常常见的防御性写法尤其是在机械手这种上电瞬间就需要所有执行器处于已知状态的场景中。delay_init(72)和usmart_dev.init(72)这两个参数都是72这个值必须与RCC_Configuration()中配置的系统主频一致。如果外部晶振是8MHz通过PLL倍频到72MHz那么这里填72是正确的如果你的板子用的是25MHz晶振或者改成了48MHz主频这两个地方不改的话延时和USMART的定时逻辑会整体偏移最典型的症状就是舵机PWM频率正确但角度响应明显变慢。2.3 JTAG引脚释放与PA15、PB3、PB4复用代价在STM32F103上PA13、PA14、PA15、PB3、PB4默认被JTAG/SWD调试功能占用。F103的调试引脚默认模式是JTAG全功能加SWD这导致如果不做处理PA15、PB3、PB4这三个IO口根本无法作为普通GPIO输出PWM。机械手需要6路PWM引脚资源紧张所以代码里调用了jtag_set(JTAG_SWD_DISABLE)这个操作的含义是彻底关闭JTAG和SWD调试接口把PA15、PB3、PB4完全释放给普通外设使用。注意这里关的是JTAG_SWD_DISABLE不是JTAG_SET(SWD_ENABLE)意味着连SWD也一起关掉了。也就是说一旦运行了这行代码你就无法再通过ST-Link或者J-Link以SWD方式连接芯片进行在线调试。这在开发阶段的代价是很高的因为程序里如果出现运行期异常你没办法通过断点去查。这也是为什么这个工程里要引入USMART串口调试组件——调试通道从SWD切换到了串口所有运行期检查和参数修改都通过串口命令行来完成两者是配合使用的设计不是可选的加分项。如果你打算保留SWD调试能力继续开发可以把这行改成jtag_set(JTAG_SWD_ENABLE)代价是PA15、PB3、PB4这路PWM需要换到其他定时器通道上。2.4 RCC时钟配置与APB1定时器倍频规则RCC_Configuration()内部做的事情可以归纳为一张典型配置表配置项典型值作用HSE8MHz外部晶振系统时钟源PLL倍频9倍8MHz×972MHz系统主频AHB预分频1分频HCLK72MHzAPB1预分频2分频PCLK136MHz定时器时钟自动×2为72MHzAPB2预分频1分频PCLK272MHzUSART1、ADC、TIM1挂在此总线有一个非常容易踩的坑藏在表格第四行APB1预分频设置为2时挂载在APB1上的通用定时器TIM2、TIM3、TIM4的时钟并不是36MHz而是自动倍频到72MHz。这是STM32硬件的固定行为——当APB1分频系数不为1时定时器时钟倍频系数为2。所以舵机PWM的计数频率拿到的是72MHz而不是你以为的36MHz。很多人在计算PWM周期的时候少乘了这个2导致输出的PWM频率直接翻倍舵机发出尖锐的啸叫声。关于定时器PSC和ARR的具体计算公式在第四章里会结合六路舵机的脉宽参数一起展开。3. USMART串口调试组件把寄存器操作变成在线命令3.1 USMART的定位嵌入式环境下的极简命令行解释器在MCU开发场景中调试手段无非几种断点调试、printf打印、逻辑分析仪抓波形。但当你关闭了SWD接口之后前两者都变得不太方便——断点没法用printf基本靠串口。USMART组件解决的是更高一层的问题它让你不用改代码、不用重新编译烧录就能在运行状态下直接调用工程里的任意函数。说白了它不是打印调试信息的工具而是一个跑在MCU上的函数调用器类似Python的交互式控制台只不过函数列表是你事先注册进去的。// usmart_config.c 中的函数注册表 struct _m_usmart_nametab usmart_nametab[] { #if USMART_USE_WRFUNS 1 {steer_set_angle, (void(*)(void))steer_set_angle}, // 注册角度设置函数 {steer_set_pulse, (void(*)(void))steer_set_pulse}, // 注册脉宽设置函数 {read_steer_angle, (void(*)(void))read_steer_angle},// 注册角度读取函数 {hw_init, (void(*)(void))hw_init}, // 注册硬件重初始化 #endif };这段代码说明了一个关键机制USMART把C语言里的函数指针和字符串绑定在一起。steer_set_angle这个名字本身对MCU来说毫无意义但通过这张注册表字符串steer_set_angle就被映射到了对应的函数入口地址上。当你在串口调试助手里发送steer_set_angle 1 90时USMART的解析器会先按空格把字符串拆成三段第一段是函数名后两段是参数。函数名在这个链表里逐项匹配匹配成功后再按usmart_str.c里的解析规则把1和90这两个字符串转换成整型参数通过函数指针完成调用。这里的难点在于把字符串参数动态转换成不同类型的数据usmart_str.c内部维护了一套基于格式说明符的转换逻辑对标C标准库里的sscanf但做了裁剪以适配MCU的内存限制。3.2 串口接收与命令解析的配合流程USMART的串口数据接收并不依赖复杂的操作系统或DMA而是通过usart.c中的串口接收中断来完成的。常规接法是这样的串口收到一个字节就触发一次中断中断服务函数把字节缓冲到FIFO里USMART在main主循环中周期性检查这一批缓冲当收到回车符\r或换行符\n时认为一条命令输入完毕开始进入解析流程。// 串口中断服务函数中追加的 USMART 数据接收 void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) ! RESET) { uint8_t ch (uint8_t)USART_ReceiveData(USART1); usmart_dev.read(ch); // 把字节交给 USMART 缓冲 } }usmart_dev.read(ch)并不是直接把字节放进一个简单的数组它内部维护了接收计数器和换行判断逻辑。如果串口助手设置的发送格式是「发送新行」那么在命令末尾就会附带\n或\r\nUSMART检测到换行后就会触发一次命令执行。这里有一个很容易让新手困惑的细节如果串口助手没有勾选自动发送新行命令永远不会被执行因为USMART只会在收到换行符时才认为输入结束。正确操作是PC端串口调试助手发送命令时勾选「发送新行」选项这样代码逻辑才能与PC端配合顺畅。USMART连接PC上位机时usmart_str.c内部对命令的解析顺序是先检查命令名在注册表中是否存在如果不存在把整个字符串原样返回提示Invalid Command如果存在再解析参数的个数。参数个数的校验会对上usmart_config.c中注册表项的参数长度描述比如steer_set_angle注册时声明接收两个参数你只传一个或者传三个USMART会在串口里打出一条参数数量不匹配的错误信息而不会真正执行函数调用。这一点很重要因为C语言的函数指针类型已经被强制转换成void(*)(void)类型参数类型的安全保障只能靠解析器的校验逻辑来兜底。3.3 在线调参机械手角度标定的加速器如果你是在实验室调试六自由度机械手最常做的事情就是试角度让某一路舵机转到90度观察机械臂姿态觉得偏了就改成85度再观察。不用USMART的常规做法是修改代码里角度常量、重新编译、烧录、上电、观察一次调试循环维持在20秒左右。而通过USMART整个过程被压缩为在串口调试助手里输入一条命令的时间steer_set_angle 1 90 steer_set_angle 1 85 steer_set_angle 2 45 read_steer_angle 1第一行命令将1号舵机设置为90度。执行过程中steer_set_angle函数内部会把角度值换算为对应PWM通道的比较寄存器CCR值然后更新定时器。第二行命令将1号舵机角度改为85度你可以直接观察机械臂末端位置有没有到达预期。read_steer_angle 1则会把1号舵机当前记录的脉冲宽度回传到串口终端方便你反推当前实际角度。这种方式在处理机械手逆运动学参数标定时尤其高效逐关节微调的角度值可以直接记录下来作为运动学模型的补偿量。需要特别注意的是USMART调用函数的运行上下文与主程序完全相同。这意味着你在steer_set_angle里访问的全局变量就是主程序里那个全局变量USMART执行期间不会被高优先级中断抢占——除非对应中断的优先级本来就高于USMART执行位置。所以在机械手运行过程中如果主循环正在执行复杂的轨迹插值算法而此时你在串口里发了一条steer_set_angle命令USMART会插队执行这次角度修改可能造成机械臂动作的瞬间跳变。安全操作习惯是在机械手处于静止状态下调整参数运动过程中不要给USMART发命令。3.4 串口打印组件xprintf与重定向方向的选择工程里还有一个容易被忽略的组件xprintf.c。这是把printf系函数裁剪后用于嵌入式串口输出的轻量实现核心格式化输出函数是xprintf。它和标准库printf的最大区别是不依赖半主机模式点对点直接操作串口发送寄存器。如果你的工程里已经接了uart_init(9600)那么xprintf(Current Angle: %d\n, angle)就会直接把数据从USART1的TX引脚发出去。在这个项目中xprintf和USMART共用同一个串口外设但二者并不冲突因为USMART处理的是RX方向接收到的命令而xprintf只是TX方向发送数据。PC端的串口调试助手同时承担了命令输入和日志输出的功能这也是这种调试架构最省资源的地方——不需要额外占用一个串口做日志通道。4. 六自由度舵机控制的PWM设计与运动学边界4.1 舵机控制信号本质20ms周期和1ms~2ms脉宽窗口标准模拟舵机和数字舵机的控制信号本质上是同一类东西周期为20ms的PWM波高电平脉宽在0.5ms到2.5ms之间对应舵机输出轴从0度转到180度。这里最重要的一点是舵机不关心频率精度它只关心高电平持续的时间长度也就是脉宽。50Hz这个频率只是20ms周期的倒数只要脉宽保持准确即使PWM频率有微小漂移也不会对舵机角度产生影响。这个特性给了设计者一个宽松的空间不需要高精度的PWM时钟源普通定时器的PWM输出就能满足要求。具体的脉宽与角度对应关系如下表所示这是一份可以直接写入驱动代码的映射标准目标角度高电平脉宽典型应用场景0°0.5ms机械手关节回零位45°1.0ms小范围调整90°1.5ms舵机中位机械臂水平状态135°2.0ms大角度摆动180°2.5ms机械手极限姿态有相当一部分舵机支持的是0.5ms到2.5ms范围但市面上一些标称180度的舵机实际线性区只到1ms到2ms之间超过这个区间后脉宽和角度的线性关系变差关节角度超过这个范围时关联到的只是死区或者极限位置的机械限位。所以在代码里对角度做限幅处理之外最好还根据具体舵机型号微调脉冲上下限。这个参数的标定方式在第五章会有说明。4.2 定时器通道分配与捕获比较寄存器计算6路舵机意味着需要6路PWM输出。STM32F103的定时器资源中TIM1和TIM2各有一组PWM输出通道TIM3和TIM4同理每个定时器最多4路通道。这个工程的做法是基于资源利用率优先原则把6路PWM分配到两个定时器上常见做法有两种方案通道分配特点方案ATIM1_CH1~CH4 TIM2_CH1~CH2TIM1是高级定时器自带互补输出和刹车功能但CH1~CH4分布在不同IO引脚方案BTIM2_CH1~CH4 TIM3_CH1~CH2全部使用通用定时器逻辑简单适合均匀负载工程选用哪种方案取决于舵机控制板的接口定义。我在类似项目里更倾向于方案B因为通用定时器在PWM模式下的初始化和中断配置比高级定时器简单且不会引入TIM1的刹车信号误触风险。不管选哪种核心都是配置定时器的预分频系数PSC、自动重装载值ARR以及每个通道的比较值CCR。舵机控制要求PWM周期为20ms也就是50Hz。在APB1定时器时钟为72MHz的条件下周期计算公式为PWM频率 72MHz / ((PSC 1) * (ARR 1))假设取PSC71则计数频率为72MHz / 72 1MHz即每个计数单位1微秒。要让周期为20msARR 1 20000因为计数单位是微秒20000个单位就是20000微秒。此时PWM频率正好是1MHz / 20000 50Hz。这样设置的好处是CCR比较值的单位恰好是微秒舵机脉宽1.5ms就把CCR设为1500而脉宽0.5ms对应CCR500直观且不易出错。下面是完整的舵机PWM通道初始化代码思路void steer_pwm_init(TIM_TypeDef* TIMx, uint16_t channel) { TIM_TimeBaseInitTypeDef TIM_BaseInitStructure; TIM_OCInitTypeDef TIM_OCInitStructure; // 预分频 71, 定时器计数频率 72MHz / 72 1MHz (1us 一个计数单位) TIM_BaseInitStructure.TIM_Prescaler 71; // 重装载值 19999, 周期 20000us 20ms TIM_BaseInitStructure.TIM_Period 19999; TIM_BaseInitStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIMx, TIM_BaseInitStructure); // PWM 模式1, 计数值小于 CCR 时输出有效电平 TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 1500; // 默认 1.5ms, 舵机中位 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OCInit(TIMx, channel, TIM_OCInitStructure); }这段代码里的TIM_Prescaler 71和TIM_Period 19999必须配对出现不少人只改了PSC忘了改ARR结果PWM周期变成了10ms或者40ms舵机在20ms周期之外的脉宽下工作一段时间后就会发烫甚至烧毁。PWM模式1的含义是当定时器计数值小于CCR时输出引脚为有效电平这里配置为高电平计数值超过CCR后输出翻转为低电平。所以CCR直接决定了高电平持续长度也就是舵机脉宽。在后面的角度换算函数里我们要做的基本操作就是把角度映射到500到2500这个CCR区间上。4.3 多路PWM初始化时的相位对齐问题六路舵机同时工作时如果每路PWM的计数起点各不相同出现的现象是即使各路的脉宽都是1.5ms机械手上电瞬间也会发生短暂的抖动因为各路舵机的输出轴会先快速响应到各自脉宽对应的角度之后才进入稳定状态。解决这个问题的常见做法是在定时器初始化完毕、启动计数之前手动设置所有通道的CCR为同一个中间值比如全部设为1500对应1.5ms中位。然后一次性调用TIM_Cmd()启动定时器这样所有通道的高电平起点完全对齐上电瞬间6路舵机都会保持在中位机械手呈现一个姿态确定的静止状态然后你再去控制它逐关节运动。void steer_init(void) { uint8_t i; // 初始化所有通道 CCR 为中位值 for (i 0; i 6; i) { steer_ch[i].tim steer_ch[i].tim; // 每路指定对应 TIM 和通道 TIM_SetCompare(steer_ch[i].tim, steer_ch[i].channel, 1500); } // 所有定时器同时启动, 保证相位一致 TIM_Cmd(steer_ch[0].tim, ENABLE); TIM_Cmd(steer_ch[3].tim, ENABLE); }各通道独立更新CCR时如果不把定时器的预装载功能打开CCR的新值会在下一个计数周期立即生效这可能造成当前PWM周期内高电平宽度突然跳变。打开预装载后CCR的更新会等到当前计数周期结束即发生更新事件时才生效从而避免脉宽突变。在TIM_OCInitStructure中对应字段是TIM_OCPreload一般建议在所有舵机控制项目里开启。这一点在做平滑运动控制时尤为重要机械手轨迹插补要求每拍更新CCR如果预装载关闭脉宽突变积累下来会让关节产生肉眼可见的抖动。4.4 电源电流峰值与PWM故障保护的设计边界六自由度机械手在实际运行时舵机负载变化最大的时刻就是各关节同时从静止加速到目标速度的瞬间。普通9g舵机堵转电流在500mA左右而MG995这类大扭矩舵机堵转电流可以达到2A以上。6路舵机如果同时堵转瞬时总电流超过10A此时如果5V电源的峰值输出能力不够输出电压会瞬间跌落舵机控制芯片检测到欠压后可能进入复位或锁定保护状态表现就是机械手运行中断断续续抖动。这个工程源码包里没有包含供电方案设计但在实际搭建时我一般会采用舵机电源与单片机电源完全隔离的做法一路5V~6V大电流电源专门给舵机供电另一路经过稳压芯片单独供给STM32最小系统板两路电源只在GND处单点共地。这样既保证了舵机大电流不拉低MCU供电又让PWM信号有了共同的参考地平面。PWM故障保护也是这一节需要单独提的点。如果单片机因为程序跑飞或者其他原因停止输出PWM舵机引脚会处于恒高或恒低电平状态舵机随即失控。工程里没有专门实现看门狗与PWM联动但你在实际项目中应该考虑在main循环里喂IWDG独立看门狗同时把舵机使能引脚接在某个IO上一旦看门狗超时复位初始化代码把所有舵机通道CCR恢复为1500中位值保证机械手不会在失控状态下保持危险姿态。5. 串口烧写与联调验证从CH340驱动到多路舵机同步5.1 串口烧写失败时先查DTR/RTS自动复位电路与boot0因为工程初始化时已经关闭了SWD调试口所以烧录只能走串口ISP方式。大多数ST-Link或者USB转串口模块在ISP下载时依赖DTR和RTS信号控制复位引脚和BOOT0引脚如果连接失败最先检查的是这两个引脚的接线方向——CH340模块的DTR/RTS输出逻辑电平与STM32复位电路要求的触发电平方向相反是很常见的接错点。正常的ISP烧录序列是先让BOOT0拉高进入Bootloader模式然后复位芯片启动后等待接收串口写入的固件。烧写完成后手动把BOOT0拉回低电平再次复位进入用户程序。另外一个高频坑是串口驱动没装好。无论设备管理器里是否显示CH340或FTDI设备都建议去官网下载最新驱动重装一次因为系统自带的通用串口驱动在某些操作系统版本上波特率9600下的时序与STM32F103内置Bootloader的要求存在偏差表现为下载进度条停在0%。这里不需要改波特率STM32F103内置Bootloader固定支持9600、57600等多种波特率问题通常出现在USB转串口芯片的驱动时序上。建议直接用万用板飞线连接CH340的TXD、RXD、GND到STM32最小系统板的对应引脚交叉接线TXD接PA10(RX)RXD接PA9(TX)。5.2 用xprintf打点验证串口链路与PWM时序烧录成功后验证串口链路是否正常的最快方式是在程序开头调用一次xprintf输出一个固定字符串。由于波特率设置是9600PC端串口调试助手的波特率必须与此一致否则看到的就是乱码。如果PC端串口画面没有反应先确认PA9和PA10的复用功能是否开启——在RCC_Configuration里需要使能USART1时钟同时把PA9配置为复用推挽输出PA10配置为浮空输入。这两个引脚如果复用配置不对USMART和xprintf都没有用武之地。验证PWM波形时临时把某一路舵机脉宽设定到固定值比如steer_set_pulse 1 1500再用示波器或者逻辑分析仪去抓对应引脚的波形。如果你手头没有示波器一个土办法是把该路PWM输出直接接到一个LED串联电阻上LED亮度随脉宽变化而变亮或变暗。这一招在验证PWM频率是否正确时很有用——50Hz的PWM信号驱动LED会看到明显闪烁而如果周期错配到10ms闪烁感会减弱甚至消失这说明定时器时钟配错需要回到第四章的参数重新核对。5.3 舵机抖动排查波形、共地、干扰三件套六路舵机同步运行后如果出现抖动排查顺序应该固定为先看波形再看共地最后查串口干扰。波形检查用万用表无法判定脉宽所以至少在PA15、PB3、PB4这三路释放出来的IO上接一个逻辑分析仪确认输出脉宽是否与期望一致。共地问题最容易悄悄出现舵机电源和单片机电源如果不共地PWM信号的电平参考点与舵机控制板存在电压差舵机内部的光耦或者晶体管无法可靠识别高电平抖动几乎是必然的。而串口干扰是指调试用的USB转串口线在机械手电机动作时接收到脉冲噪声导致USMART误判命令——这种情况把USB转串口线换成带磁环的屏蔽线或者降低波特率到4800一般就能解决。最后还有一个实用小技巧在验证新舵机的脉冲上下限时不要直接发180度对应的2500us脉宽先用steer_set_pulse命令发500us舵机转到极限位置后手摸一下外壳温度如果发烫明显说明这个舵机的实际可用脉宽范围比标称窄需要把限幅上限收窄到2200us左右。这个操作通过USMART输入一条命令就能完成整个标定过程不超过两分钟。本文还有配套的精品资源点击获取
返回列表