恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

STM32精确控制小车行驶距离:编码器与PID闭环实现指南

  • 首页
  • 资讯中心
  • /
  • STM32精确控制小车行驶距离:编码器与PID闭环实现指南

相关资讯

M4C-Hat NPU扩展板实战:Pulsar2工具链与边缘推理性能测试 2026/10/14 1:02:41
Quartz 定时任务到点不执行?misfire 策略与并发锁复盘 2026/10/14 0:57:41
uni-app 地图找岗:定位权限、map 组件与半径搜索,从授权到出结果 5 个坑 2026/10/14 0:57:41

最新资讯

一张思维导图打通《精通以太坊》密钥、钱包与交易核心链路
源师兄「重力文字」项目实战:利用加速度计让屏幕文字随倾斜方向滑动
Vue05-数据绑定
嵌入式自学习模式超时退出机制与串口联动设计
千金感真的太绝了!这4套小香风四视图一套比一套耐看
Potrace图片矢量化全攻略:从扫描件到可缩放SVG路径

今日推荐

IBM Verify Identity Access 修复 22 个漏洞:两个 9.8 严重 RCE 无需认证
小区物业管理系统
小型超市仓库管理系统

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

STM32精确控制小车行驶距离:编码器与PID闭环实现指南

发布时间:2026/10/14 1:02:41
STM32精确控制小车行驶距离:编码器与PID闭环实现指南 简介该压缩包提供了一套基于STM32与编码器的电机定距行驶完整工程面向学习PID闭环控制或做移动平台精确位移的嵌入式开发者。资源以Keil工程形式呈现共236个文件包含121个H头文件、107个C源文件、3个文本说明以及uvprojx工程文件等核心代码涵盖PID参数配置、编码器脉冲捕获、PWM输出及主控逻辑可帮助快速移植到同类电机驱动项目。压缩包整体约1.65MB轻量易部署。项目重点演示了比例、积分、微分三项在速度位置调节中的配合方式并给出STM32与编码器A/B相接口的中断处理思路便于理解从脉冲计数到目标距离匹配的完整信号链。目前已有1022人学习适合具备一定C语言和STM32基础、希望深入掌握精确运动控制的开发者下载参考。通过阅读源码可梳理系统初始化、PID运算周期和驱动输出之间的时序关系并据此调整Kp、Ki、Kd实现不同负载下的稳定控制。1. 用STM32控住车轮为什么「行驶指定距离」比「走直线」更考功夫很多刚接触嵌入式的开发者做小车第一反应是让轮子转起来就完事了真到了「走2.35米精确停下」这种需求才发现问题不在电机而在「你怎么知道轮子走了多远」。用定时器PWM控制转速只能算开环负载、电量、路面摩擦一变同样的占空比实际走的距离能差出两成。要解决「指定距离」必须引入闭环起码要满足位置可控、速度可测、停止无超调三个条件。这个资源围绕STM32F1系MCU展开用增量式光电编码器做测速反馈用PID控制PWM输出完成里程闭环整条链路从编码器脉冲计数到停机刹车逻辑都覆盖了适合做过基础PWM调速、现在想上闭环控制的开发者。限制距离控制的车速一般不超过0.6m/s一但超过这个值单纯的PID位置环会出现明显的停车过冲这是我在调试中反复踩到的一个数后面有专门一节说这事。2. 停车精度从哪来编码器测距与断电报数机制2.1 为什么选增量式编码器而不是霍尔或者GPS指定距离的控制本质是测距与纠偏所以测距的物理层必须自洽。常见的三种测距方案GPS精度在米级室内根本没用IMU惯性导航积分漂移严重两米内的距离误差随时间是二次方增长的霍尔传感器只能测转速对轮子打滑没有感知。增量式编码器直接装在电机减速箱输出轴或车轮轴上发出的脉冲数正比于转过的角度低速下精度能到毫米级所以这个项目选用带AB双相输出的编码器电机标准分辨率常见在11线或13线某些模块输出是每圈13个脉冲加上减速比1:30之后车轮每转一圈能产生的脉冲数编码器线数×减速比我们后面所有距离换算都基于这个固定系数。编码器的核心数据是「每圈脉冲数」这组参数将决定距离换算系数// 编码器参数与车轮距离换算定义 #define ENCODER_LINES 13 // 编码器码盘物理线数 #define GEAR_RATIO 30 // 减速箱减速比 #define WHEEL_DIAMETER_MM 65 // 车轮直径单位mm #define PULSE_PER_REV (ENCODER_LINES * GEAR_RATIO) // 390 float getDistanceMM(int32_t pulseCount) { float circumference WHEEL_DIAMETER_MM * 3.14159f; // 单圈周长 return (float)pulseCount * circumference / PULSE_PER_REV; }这里最容易搞混的是PULSE_PER_REV到底该不该乘以4如果只用TIM的CH1做单边沿计数一圈就是390个脉冲如果开启编码器接口模式的AB相双边沿计数一圈会变成780或1560。必须和测距代码里的系数保持一致否则里程会以整数倍漂移。我在第一次验证时用AB相4倍频数据除以390结果显示距离比实际远了一倍调了半小时才意识到计数器倍频已经把脉冲放大了。2.2 断电报数用小风扇的续航焦虑换来的一组可靠静态数据整车断电时MCU的RAM会全部清空编码器脉冲计数值在重新上电后无法恢复所以「走了多远」这个数据必须有一个非易失的落点。常见做法是在定时器中断里积攒脉冲再由主循环把累计脉冲数写入内部Flash或外部EEPROM。这个项目默认用STM32片内Flash的最后一个扇区做存储写入时机按距离阈值触发比如每经过5cm落一次数避免高频Flash擦写把寿命耗尽STM32F1系列Flash擦写寿命标称一万次按5cm间距算整车全寿命擦写约数万次其实有点吃紧所以我更建议只在断电前把计数值刷入Flash这个叫「掉电保存」需一个几十毫秒的掉电监测窗口。掉电保存必须用外部中断或低功耗定时器监测Vbat电压代码结构大概是这样的// 掉电检测中断服务函数 - 保存当前里程脉冲计数 void EXTI15_10_IRQHandler(void) { if(EXTI_GetITStatus(EXTI_Line14) ! RESET) { // 电池电压检测脚 // 禁用全局中断保证写入过程不被干扰 __disable_irq(); // 把脉冲计数写入Flash保留扇区(地址0x0800F800) uint32_t addr 0x0800F800; FLASH_Unlock(); FLASH_ErasePage(addr); FLASH_ProgramWord(addr, (uint32_t)encoderPulseCount); FLASH_Lock(); // 数据落地后进入深度停机 __enable_irq(); PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); // 系统掉电后由硬件断电如果电压还在则软件复位退出STOP NVIC_SystemReset(); } }若使用HAL库FLASH_ProgramWord在F1系列一次只能写半字16位写32位数据要分两次调用很多人在这里翻了车——裸机标准库版本能一次写完32位换了HAL库就必须拆开否则程序死在写Flash的断言里。另一点值得注意掉电检测的中断脚必须用带EXTI功能的引脚不能随便接一个普通输入口靠轮询测电压否则电压跌落到无法维持Flash写入时MCU还在执行别的事此时保存十有八九写进去的是坏数据。2.3 拨码开关设定目标距离与参数标定为了跑不同距离不用反复烧录程序这个资源在硬件层面预留了一个4位拨码开关代表二进制0-15。代码里把拨码值映射成目标距离映射表可按实际需求改常见设计是1代表0.3米2代表0.5米3代表1米4代表2米直到15代表10米。拨码开关接在STM32的PB0-PB3内部上拉输入读按键时需要考虑抖动拨码开关存在的抖动虽然比机械按键小很多但仍需要一次滤波// 拨码开关读取 - 带消抖滤波 uint8_t readDistanceDial(void) { uint8_t value 0; for (int i 0; i 4; i) { // 三读两同取一致值消除拨码抖动 uint8_t bit 0; for (int j 0; j 3; j) { if (GPIO_ReadInputDataBit(GPIOB, (uint16_t)(GPIO_Pin_0 i))) bit; } if (bit 2) value | (0x01 i); // 两次以上为高才判定为1 } return value; }拨码变化后的目标距离在运行中不建议实时更新因为斜坡规划器的目标值跳变会引起PID输出突变。我一般是在系统启动时读取一次运行中锁存到静态变量里除非你人为按下复位键否则不允许运行中修改目标距离。3. 控制策略选择梯形速度规划与增量式PID的位置闭环架构3.1 为什么开环时间基准不行从斜坡发生器说起直接给PWM一个固定占空比小车起步瞬间电流大、转速上升慢到了目标附近再停PWM小车因为惯性还会滑行一段这误差不是毫秒级的而是几十毫秒内滑动5-15厘米对两米以上的目标距离来说相对误差能到10%。梯形速度规划的核心思想是把速度曲线分成三段匀加速段、匀速段、匀减速段。速度从0线性升到目标巡航速度在距离目标还剩S_stop时开始线性降到0停车瞬间速度为零滑行距离最短。梯形规划器的每个阶段都需要一个独立的距离判断条件代码实现如下// 梯形速度规划 - 根据剩余距离计算目标速度 float trapezoidProfile(float remainingDist, float maxSpeed, float accel) { // 减速距离 v^2 / (2 * accel) float decelDist (maxSpeed * maxSpeed) / (2.0f * accel); if (remainingDist 0.001f) { return 0.0f; // 到位停止 } else if (remainingDist decelDist) { // 减速段目标速度 sqrt(2 * accel * remainingDist) return sqrtf(2.0f * accel * remainingDist); } else { return maxSpeed; // 中间段匀速巡航 } }加速段没单独写是因为它由「当前速度小于目标速度」自然形成只要PID输出能跟得上目标速度的变化实际速度会沿着斜坡爬升控制频率高一点就近似线性。3.2 增量式PID防止积分饱和的代码陷阱位置式PID直接把误差累加到积分项每次输出都是全量计算一旦执行机构饱和积分项持续累积直到系统超调这在电机调速里非常致命。增量式PID只计算本次输出与上次输出的差值累加发生在执行器的积分作用里天然不容易饱和。公式是ΔU Kp·(E_k - E_k-1) Ki·E_k Kd·(E_k - 2E_k-1 E_k-2)。实际输出U_k U_k-1 ΔU。这种结构天然不需要积分限幅吗并不是。增量式在持续大误差下U_k本身会不断增加直到PWM满占空比所以脉宽输出端仍需要一个限幅值。控制循环的频率我建议放在100Hz左右也就是10ms周期再高意义不大还占CPU。代码如下// 增量式PID - 10ms周期位置环 float pidUpdate(float target, float current, float dt) { static float prevError 0.0f; static float prevPrevError 0.0f; static float lastOutput 0.0f; float error target - current; // 增量式PID核心公式 float deltaOut KP * (error - prevError) KI * error KD * (error - 2.0f * prevError prevPrevError); // 更新误差历史 prevPrevError prevError; prevError error; // 输出限幅到电机驱动PWM范围这里是-1000到1000对应方向与占空比 float output lastOutput deltaOut; if (output 1000.0f) output 1000.0f; if (output -1000.0f) output -1000.0f; lastOutput output; return output; }从控制理论的角度说位置环的目标量是距离反馈量是编码器累计脉冲换算出的当前距离。输出量不是直接给电机转速值而是给一个「等效速度命令」这个速度命令再喂给内环的电机速度环就能构成串级PID。资源里的默认实现用单环若你要上串级只需把本函数的输出当作速度环的目标速度环的输出才给PWM。3.3 两轮差速模型下的行驶距离计算取左轮还是右轮双轮差速驱动的小车在走直线时左右轮转速不完全一致。如果只用左轮编码器计算距离右轮打滑或阻力大时距离读数失真只取右轮也一样。工程常用做法是取左右轮脉冲数的平均值作为里程依据这样可以抵消一部分差速转向带来的误差。这个前提是小车走的是直线路径或半径很大的弧线如果走原地旋转线性距离计算不适用。// 左右轮平均脉冲转距离 - 差速驱动适用 float getAverageDistanceMM(void) { // 取左右轮脉冲的平均作为里程依据减少单轮打滑干扰 int32_t avgPulse (leftEncoderPulse rightEncoderPulse) / 2; return (float)avgPulse * 65.0f * 3.14159f / 390.0f; }轮胎充气程度、地面材质都会有系统性的误差比如同样390个脉冲在木地板上和地毯上实际走出的距离不一样。这时候就靠一个线性修正系数校准即实际测量距离/理论计算距离。把校准系数乘到getAverageDistanceMM的返回值上实测误差能压到1%以内。校准系数通常保存在Flash里避免丢失。4. 100Hz控制循环的搭建定时器中断、滤波与状态机切换4.1 用定时器中断实现精确的时间基准控制系统的节拍必须准不能依赖主循环里whiledelay的软延时软延时受分支预测和中断响应影响会有毫秒级抖动时间基准抖动直接导致PID的I项不稳定。推荐用TIM6或TIM7基本定时器STM32F1系列有TIM6和TIM7两个基本定时器挂在APB1上配置为10ms中断一次。这段配置可以用STM32CubeMX生成也可以手写标准库版本核心参数是预分频和自动重载// TIM6定时器配置 - 10ms周期中断 void TIM6_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); TIM_TimeBaseStructure.TIM_Period 999; // 自动重载值 TIM_TimeBaseStructure.TIM_Prescaler 7199; // 预分频值72MHz/720010kHz // 72MHz / (71991) / (9991) 100Hz TIM_TimeBaseInit(TIM6, TIM_TimeBaseStructure); TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE); // 使能更新中断 TIM_Cmd(TIM6, ENABLE); NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel TIM6_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority 1; NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); }预分频和自动重载的搭配需要根据实际系统时钟调整我见过有人拿48MHz的芯片直接套用72MHz的配置中断频率变成约66Hz控制周期抖动直接让停车位置误差从1厘米变大到5厘米。如果用的是HAL库HAL_TIM_PeriodElapsedCallback里面做标志位置位、主循环消费不建议直接在中断函数里做全部PID运算F1主频72MHz10ms足够跑完一次PID但如果在中断里同时干「读编码器、做PID、刷新PWM」三件事中断耗时往往接近1ms也不算太差更怕的是有人在中断里放LCD刷新和浮点printf那CPU基本就没什么富余了。所以建议中断里只做事件标记主循环处理。4.2 编码器脉冲滤波与M法测速的取舍编码器信号在电机启停瞬间会出现振铃STM32的定时器编码器模式自带滤波输入滤波参数但有时滤波太强会把真实脉冲也滤掉。在标准库中用TIM_ICInitStructure.TIM_ICFilter设定滤波长度以fDTS为参考设定值从0x0到0xF每档代表不同采样窗口。我的经验值是用0x0A能滤掉大部分机械抖动而不牺牲真实脉冲。如果发现电机启动后脉冲数明显偏少先怀疑滤波设太强。M法测速是测量固定时间窗口内的脉冲数适合高速场景在低速下脉冲间隔长一个窗口可能只有几个脉冲速度分辨率很差。但本项目控制的是行驶距离而不是实时转速精度编码器累加本身不受低速影响所以我们只需要关注总的脉冲计数准不准不需要刻意做T法测速。编码器接口模式初始化的一个细节必须在GPIO配置为复用推挽之后立即配置定时器编码器模式否则计数方向寄存器未知。// 定时器编码器接口模式配置 - 双通道双边沿 TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising); TIM_SetCounter(TIM4, 0); // 清零计数器TIM_EncoderMode_TI12模式下TI1和TI2双边沿都计数四倍频。单边沿计数用TIM_EncoderMode_TI1即可。倍频系数在计算距离时要用对。4.3 运行状态机空闲、启动、巡航、减速、停止整个行驶过程需要一个状态机串联否则代码里到处都是if判断状态一多必然乱。状态机以目标距离的完成度为迁移条件// 行驶状态机 - 根据剩余距离切换状态 typedef enum { IDLE, START_ACCEL, CRUISE, DECEL, STOP } DriveState; DriveState state IDLE; float remainingDist targetDist - currentDist; switch (state) { case IDLE: if (startCmd) { state START_ACCEL; } break; case START_ACCEL: targetSpeed maxSpeed; // 让PID自然加速 if (currentDist targetDist * 0.2f) state CRUISE; break; case CRUISE: targetSpeed maxSpeed; if (remainingDist decelDist) state DECEL; break; case DECEL: targetSpeed trapezoidProfile(remainingDist, maxSpeed, ACCEL); if (remainingDist 0.0f) { state STOP; stopMotor(); } break; case STOP: break; }状态切换必须带滞回区间比如CRUISE切换到DECEL的条件是remainingDist decelDist切过去之后不能因为速度降低、剩余距离变大又切回CRUISE。否则系统会在阈值附近震荡停车点前后甩动。5. 光耦隔离与功率驱动为什么PWM直接焊上电机会烧GPIO5.1 共地问题的本质与光耦选型STM32的GPIO输出能力大约±25mA直接驱动电机驱动芯片的逻辑输入没问题但当电机是大功率空心杯电机或带电磁刹车时电机启停瞬间的母线电压跌落会在驱动板上产生地弹控制板和驱动板共地时地线上的噪声会直接窜进MCU的ADC和复位电路。所以这个资源在控制板和驱动板之间设计了光耦隔离。PC817的电流传输比CTR范围是50%-600%设计时要按最小CTR算保证GPIO高电平时光耦输出端能充分导通。上拉电阻取4.7k到10k过小会加大LED电流过大则输出波形沿变缓PWM频率超过10kHz时波形变形严重。本项目PWM频率默认设在10kHz左右所以光耦的开关延迟PC817典型上升时间约18us还没成为瓶颈若你想把PWM升到20kHz以上建议换高速光耦比如6N137。5.2 使能脚与方向脚的刹车时序电机驱动器无论是TB6612还是L298N都有IN1、IN2两个方向输入以及STBY或EN使能脚。刹车逻辑不能简单把PWM输出设为0因为电机电感续流会让电机继续滑行。主动刹车是把两个方向输入端同时拉高或拉低让电机两端短路产生能耗制动。顺序上要先把PWM降到0再切换方向脚防止桥臂直通。// 主动刹车 - 两输入同电平使电机短路制动 void motorBrake(void) { // 先禁止PWM输出 TIM_Cmd(TIM3, DISABLE); // 再让IN1和IN2同为高形成能耗制动 GPIO_SetBits(GPIOA, GPIO_Pin_8); GPIO_SetBits(GPIOA, GPIO_Pin_11); // 另一路输入也拉高 }这条刹车逻辑在PID到达目标后立即执行比单纯PWM0的滑行停车距离缩短一半以上。5.3 PWM频率与死区时间的匹配电机驱动芯片的输入PWM频率需要和芯片的死区时间匹配。TB6612的PWM频率范围大概在1kHz-100kHzL298N则建议1kHz-40kHz。频率太低电机电流纹波大、发热明显频率太高驱动芯片开关损耗上升光耦延迟会导致占空比失真。10kHz是多数小车的甜点频率。死区时间不足会导致上下桥臂直通轻则发热重则烧驱动芯片所以选型时不能只盯着PWM频率驱动芯片的dead time参数要能覆盖你PWM波形的上升沿一般在500ns以上就足够。6. 避坑指南与常见排查路径里程漂移、启动反转、停车过冲6.1 编码器脉冲数正常但距离严重偏短轮胎有效直径陷阱现象编码器脉冲数算出的理论距离是2米用卷尺量实际只走了1.6米。原因出厂标称车轮直径是胎冠外径但车轮受压后轮胎会压扁有效滚动半径小于物理半径充气轮胎尤其明显。代码里WHEEL_DIAMETER_MM直接用了65mm实际有效直径可能只有52mm。解决让车在平滑地面上跑20圈量实际距离反推有效直径实测周长除以20再除以π。然后把WHEEL_DIAMETER_MM改成反推出的值。标称直径是65MM但我手上这个轮子实际算出来的有效直径只有58.2mm差了10%以上这正是量产车轮出厂公差带来的误差。6.2 启动瞬间倒溜、方向抖动增量式PID的D项在作怪现象起步时电机明显反转一下然后才正转前进或启动过程中车身左右抖。原因起步瞬间编码器还没转出脉冲此时目标距离与当前距离的误差很大PID的微分项D对误差变化率敏感误差瞬间从0跳到很大D项输出一个反向脉冲抑制这个跳变在物理上就表现为电机瞬时反转。微分项系数KD如果设得过高任何对误差的阶跃响应都会先反向再正向车身就像点头。解决目标速度不能直接是最大速度阶跃要经过斜坡发生器让目标值以一个限定的斜率爬升KD初始值设为零先把P和I调稳再一点点加D项观察响应。另外一个技巧是启动时先让目标距离加上一个很小的正偏移再开始PID人为抹平相位。6.3 停车位置每次都差2-3cm且方向一致控制频率与反应延迟现象每次都冲过目标点约2厘米位置重复性很好但就是多一段固定距离。原因这是典型的系统延时型误差。100Hz控制频率下每个周期10ms而PID输出到电机响应还有机械惯性相当于系统有个固定的滞后时间Δt≈40ms速度0.5m/s时就对应2cm的过冲。这不是PID调参能完全消除的。解决把目标距离减掉一个「经验补偿距离」再进斜坡规划器补偿值由实测得到比如目标2米时实际停在2.02米那就把目标设成1.98米。另一个根治方案是提高控制频率到200Hz并把减速段的减速度调大让车在更短距离内完成减速但注意减速段太短会让停车动态显得「急刹车」机械冲击变大联轴器和螺丝容易松。6.4 掉电保存后重新上电距离跳变Flash写入未完成就断电现象每次断电再开机里程脉冲数要么变成0要么变成一个异常大数。原因在电压跌落过程中尝试写Flash但Flash写操作要求电源电压在正常工作范围电压低于阈值时写入内容无法保证。GPIO检测电压本身有ADC采样时间从检测到确实触发了掉电中断到写Flash完成需要大约几十毫秒如果电池电压跌得太快这段窗口期不够用。解决电源输入端加大容量电解电容至少1000uF给掉电保存提供能量缓冲另外把掉电检测阈值设在3.0V而不是2.7V留出更多时间余量。如果你用的是锂电池加稳压芯片在稳压后的3.3V侧加检测是错的必须检测电池端原始电压因为稳压芯片输出端掉电前一直保持3.3V检测不到外部断电。6.5 同一个PID参数在两台车上一台稳一台震荡电机一致性现象同一组Kp、Ki、Kd在A号车上运行平稳换到B号车上就开始周期性摆动。原因两个电机的减速箱摩擦转矩不同相同PWM下实际转速不同位置环增益在不同摩擦特性下稳定裕度不同。B车从静止到运动的静摩擦更大PID需要更高的输出才能起步一旦起步又容易过冲形成低速震荡。解决把速度环的积分系数降低同时增加PID输出的死区比如输出绝对值小于20时强制输出0避免小幅度抖动。若还有偏差就给每台车单独标定一组PID参数把参数表存在Flash里启动时根据车号读不同的参数组。7. 验证方法与实践技巧能跑直线不代表能精确停车验证一套距离控制是否合格不能只看代码、更不要靠信任。标准验证方法是贴着轮子侧向放一把卷尺让车跑完整个距离记录编码器给出的里程数和卷尺实测的距离偏差超过±2厘米就要查原因。执行三次取平均值如果三次偏差方向一致优先调补偿距离如果三次偏差方向随机说明存在机械打滑或编码器安装松动先拧紧码盘螺丝再谈调参。进阶调试技巧是把实时数据通过串口打印出来常用的调试命令组合是这样的以20Hz频率输出目标距离、当前距离、目标速度、当前速度、PID输出五个变量。观察曲线如果目标距离和当前距离曲线在减速段出现交叉但未停止说明减速段起点太晚如果当前距离在停止后还有缓慢增长说明电机还在爬行刹车时序太晚。// 串口调试输出 - 观察PID曲线特征 printf(dist:%.1f %.1f speed:%.1f %.1f out:%.1f\r\n, targetDist, currentDist, targetSpeed, currentSpeed, pidOut);串口波特率建议115200每20ms一轮输出5个浮点数约50字节在这个波特率下占用串口时间约4.3ms不能放在10ms控制中断里放在主循环即可。如果要看高速数据变化可以只输出整型误差值把串口负担降到1ms以内。还有一个容易忽略的验证点是压过障碍物或地毯时的距离表现PID只靠编码器反馈轮子悬空空转时脉冲依然在累积实际车没动里程却涨了。对于室内平地场景这不是问题但如果地面有缝隙或减速带缩短加减速段的加速度减少车轮打滑是更有效的处理路径。我曾经把一辆样车的加速度从1.0m/s²调到1.2m/s²同一段距离测试中打滑里程占比从3%掉到0.8%效果立竿见影。从那以后我每做一个距离控制相关的项目都会先花10分钟测车胎的实际有效直径再花10分钟把编码器倍频和距离系数的换算写在一张纸条上贴到机箱盖上防止过两天自己都忘。真的这两个参数任何一个错了后面调PID再好也白搭。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号