STM32编码器模式与PID算法实现小车定点停靠

📅 2026/7/15 2:51:27
STM32编码器模式与PID算法实现小车定点停靠
1. STM32编码器模式基础与硬件连接要让小车实现精准停靠首先得知道它跑了多远。这就轮到编码器出场了——它就像是小车的里程表通过记录车轮转动的脉冲数来测量行驶距离。STM32的定时器自带编码器接口模式能自动处理正交编码器信号大大减轻CPU负担。我常用的配置方法是选择TIM2/TIM3/TIM4这类通用定时器将两个通道配置为编码器模式。以TIM3为例通常将通道1PA6接编码器A相通道2PA7接B相。硬件连接时要注意编码器电源最好与MCU共地信号线建议加10kΩ上拉电阻长距离传输时可考虑使用双绞线配置编码器模式的关键寄存器就三个TIM3-SMCR 0x0003; // 编码器模式3双通道计数 TIM3-CCMR1 0x0101; // 输入捕获模式 TIM3-CCER 0x0011; // 捕获使能极性不反转实际项目中遇到过信号抖动问题后来在代码里加了软件滤波// 简单的移动平均滤波 #define FILTER_LEN 5 uint16_t filter_buf[FILTER_LEN]; uint16_t encoder_filter(uint16_t new_val) { static uint8_t idx 0; filter_buf[idx % FILTER_LEN] new_val; uint32_t sum 0; for(uint8_t i0; iFILTER_LEN; i) sum filter_buf[i]; return sum / FILTER_LEN; }2. 脉冲到距离的精确换算拿到编码器脉冲数只是第一步关键是要转换成实际距离。这里有个换算公式距离 (脉冲数 / 每转脉冲数) × 车轮周长以我最近做的智能小车为例电机减速比30:1编码器分辨率13线转轴转一圈产生13个脉冲正交解码后每转脉冲数 13×4×30 1560车轮直径6.5cm周长π×6.5≈20.42cm单个脉冲对应距离 20.42/1560 ≈ 0.013cm在代码中我是这样实现的#define ENCODER_PPR 1560 // 每转脉冲数 #define WHEEL_DIAMETER 6.5 // 车轮直径(cm) float pulse_to_cm(int32_t pulses) { static const float pulse_per_cm (3.1416f * WHEEL_DIAMETER) / ENCODER_PPR; return pulses * pulse_per_cm; }实测发现两个常见问题轮胎打滑会导致测量误差电池电压变化影响电机转速解决方法是在小车底盘加装光电对管辅助校准同时采用电压补偿算法。3. 位置式PID算法的实现与调参PID控制就像是小车的智能刹车系统它通过不断调整电机功率来精确控制停车位置。位置式PID的特点是积分项会累积误差适合我们这种定点停靠场景。先看PID结构体定义typedef struct { float Kp, Ki, Kd; // PID系数 float integral; // 积分项 float last_error; // 上次误差 float limit; // 输出限幅 } PID_Controller;核心算法实现float PID_Compute(PID_Controller* pid, float target, float feedback) { float error target - feedback; // 比例项 float P_out pid-Kp * error; // 积分项带抗饱和 pid-integral error; if(pid-integral pid-limit) pid-integral pid-limit; else if(pid-integral -pid-limit) pid-integral -pid-limit; float I_out pid-Ki * pid-integral; // 微分项 float D_out pid-Kd * (error - pid-last_error); pid-last_error error; // 总和输出 float output P_out I_out D_out; if(output pid-limit) output pid-limit; else if(output -pid-limit) output -pid-limit; return output; }调参是个技术活我的经验是先调Kp让小车能快速接近目标位置但不过冲再调Kd抑制超调和振荡最后调Ki消除稳态误差实测发现对于1kg左右的小车以下参数效果不错PID_Controller pid { .Kp 15.0f, .Ki 0.5f, .Kd 2.0f, .limit 5000 // 对应PWM最大值 };4. 防过冲与精准停车的软件策略即使PID参数调好了小车还是会因为惯性冲过头。我总结了几种应对方案提前减速策略void brake_control(float target_cm) { float current_cm pulse_to_cm(encoder_read()); float remain target_cm - current_cm; if(remain 5.0f) { // 距离目标5cm时开始减速 float brake_ratio remain / 5.0f; // 线性减速系数 pwm_output * brake_ratio; } }惯性预测算法 记录最近几次的速度变化预测停车位置float predict_distance(int32_t current_pulse) { static int32_t last_pulse[3] {0}; static uint8_t idx 0; last_pulse[idx % 3] current_pulse; float speed (last_pulse[0] last_pulse[1] - 2*last_pulse[2]) / 3.0f; return pulse_to_cm(current_pulse) speed * 0.2f; // 0.2是经验系数 }最终微调阶段 当距离目标2cm以内时切换到低速模式if(fabs(remain_cm) 2.0f) { pwm_output pid_output * 0.3f; // 降为30%功率 if(fabs(remain_cm) 0.3f) { motor_stop(); // 完全停止 } }在最近的项目中结合这三种策略后小车能在120cm行程内实现±0.5cm的停靠精度完全满足工业应用要求。