news 2026/6/13 7:05:04

用STM32和TB6612搞定智能小车:从编码器读取到串级PID调参全流程(附避坑经验)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用STM32和TB6612搞定智能小车:从编码器读取到串级PID调参全流程(附避坑经验)

STM32与TB6612智能小车开发实战:从编码器数据采集到串级PID调参完整指南

1. 项目概述与硬件选型

智能小车作为嵌入式学习和机器人开发的经典项目,涉及电机控制、传感器数据处理和自动控制算法等多个技术领域。本项目基于STM32微控制器和TB6612电机驱动模块,实现带编码器反馈的直流电机精准控制。

核心硬件组件

  • 主控芯片:STM32F103C8T6(72MHz主频,足够处理双电机PID运算)
  • 驱动模块:TB6612FNG(相比L298N具有更低发热量和更高效率)
  • 电机类型:6V直流减速电机(减速比1:48,自带AB相编码器)
  • 编码器分辨率:11线/转(通过4倍频后为44脉冲/转)

实测数据:电机空载转速约160RPM,带载后降至120RPM左右,编码器总分辨率=44×48=2112脉冲/转

2. 编码器数据采集与速度计算

2.1 编码器接口配置

使用STM32的定时器编码器模式,可自动识别转向并计数:

// TIM1配置为编码器接口模式(电机1) TIM_Encoder_InitTypeDef encoder_config = { .EncoderMode = TIM_ENCODERMODE_TI12, .IC1Polarity = TIM_ICPOLARITY_RISING, .IC1Selection = TIM_ICSELECTION_DIRECTTI, .IC1Prescaler = TIM_ICPSC_DIV1, .IC1Filter = 6, .IC2Polarity = TIM_ICPOLARITY_RISING, .IC2Selection = TIM_ICSELECTION_DIRECTTI, .IC2Prescaler = TIM_ICPSC_DIV1, .IC2Filter = 6 }; HAL_TIM_Encoder_Init(&htim1, &encoder_config); HAL_TIM_Encoder_Start(&htim1, TIM_CHANNEL_ALL);

2.2 速度测量实现

采用定时中断法测量转速,在20ms定时中断中读取脉冲差值:

// 在定时器中断回调函数中 int16_t pulse_diff = __HAL_TIM_GET_COUNTER(&htim1); __HAL_TIM_SET_COUNTER(&htim1, 0); float rpm = (pulse_diff * 60.0f) / (2112 * 0.02); // 转换为RPM

常见问题排查

  1. 脉冲计数异常:检查编码器接线,确保A/B相没有接反
  2. 速度波动大:适当增加滤波器参数(ICxFilter)
  3. 方向判断错误:交换A/B相接线测试

3. 电机驱动与PWM控制

3.1 TB6612驱动配置

控制信号IN1IN2PWM电机状态
正转10PWM正向旋转
反转01PWM反向旋转
刹车110快速停止
待机00X高阻状态

PWM配置建议

  • 频率:10-20kHz(超出人耳范围减少噪音)
  • 分辨率:16位定时器可获得更平滑控制
// 电机控制函数示例 void Motor_SetSpeed(int motor, float speed) { uint16_t pwm = fabs(speed) * PWM_MAX; if(speed > 0) { HAL_GPIO_WritePin(IN1_GPIO, IN1_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(IN2_GPIO, IN2_PIN, GPIO_PIN_RESET); } else { HAL_GPIO_WritePin(IN1_GPIO, IN1_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(IN2_GPIO, IN2_PIN, GPIO_PIN_SET); } __HAL_TIM_SET_COMPARE(&htim3, motor==MOTOR_LEFT?TIM_CHANNEL_1:TIM_CHANNEL_2, pwm); }

4. 串级PID控制实现

4.1 控制架构设计

位置环(外环) ↓ 速度环(内环) ↓ PWM输出

4.2 PID算法实现

typedef struct { float Kp, Ki, Kd; float target, actual; float err, last_err; float integral, integral_limit; } PID_TypeDef; float PID_Calculate(PID_TypeDef *pid, float actual) { pid->err = pid->target - actual; // 抗积分饱和 if(fabs(pid->err) > 10) pid->integral = 0; else { pid->integral += pid->err; pid->integral = constrain(pid->integral, -pid->integral_limit, pid->integral_limit); } float output = pid->Kp * pid->err + pid->Ki * pid->integral + pid->Kd * (pid->err - pid->last_err); pid->last_err = pid->err; return constrain(output, -OUTPUT_MAX, OUTPUT_MAX); }

4.3 参数整定步骤

  1. 先调速度环

    • 设Kp=0.5,Ki=0,Kd=0
    • 逐步增加Kp直到出现轻微振荡
    • 加入Ki消除静差(从Kp/10开始)
    • 最后加入Kd抑制超调
  2. 再调位置环

    • 采用更小的比例系数(约为速度环的1/5)
    • 通常不需要积分项

典型参数范围

  • 速度环:Kp=0.8-1.5, Ki=0.5-1.0, Kd=0.05-0.2
  • 位置环:Kp=0.2-0.5, Kd=0.5-1.0

5. 上位机调试与性能优化

5.1 匿名助手配置

通过串口发送数据到上位机:

// 发送实际速度和目标速度到上位机 void SendToAssistant(float target, float actual) { uint8_t buf[8]; memcpy(buf, &target, 4); memcpy(buf+4, &actual, 4); HAL_UART_Transmit(&huart1, buf, 8, 100); }

调试技巧

  1. 先测试阶跃响应(突然改变目标值)
  2. 观察上升时间、超调量和稳定时间
  3. 调整参数使响应曲线达到临界阻尼状态

5.2 常见问题解决方案

问题1:电机启动抖动

  • 原因:PID输出突变
  • 解决:增加启动斜坡
// 渐进式设定目标值 void SetTargetGradually(float *target, float new_target, float step) { if(fabs(*target - new_target) > step) { *target += (*target < new_target) ? step : -step; } }

问题2:直线行驶偏移

  • 原因:两轮机械差异
  • 解决:加入差速补偿
// 根据偏移量动态调整两轮速度 float left_speed = base_speed + offset_compensation; float right_speed = base_speed - offset_compensation;

问题3:转向不精确

  • 原因:惯性导致过冲
  • 解决:加入转向减速区
if(fabs(target_angle - current_angle) < 10) { // 进入减速区 speed = BASE_SPEED * (fabs(target_angle - current_angle)/10); }

6. 进阶优化方向

  1. 自适应PID:根据误差大小动态调整参数
  2. 运动规划:S曲线速度规划减少机械冲击
  3. 参数自整定:Ziegler-Nichols法等自动整定方法
  4. 卡尔曼滤波:对编码器数据进行滤波处理

实测性能指标:

  • 直线行驶误差:<±2cm/米
  • 转向精度:±3度
  • 速度控制精度:±5RPM

项目完整代码已托管至GitHub(示例链接),包含:

  • 完整的Keil工程文件
  • 上位机通信协议
  • 参数调试工具
  • 3D打印小车结构设计图
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/13 7:02:50

别再只会录宏了!WPS JS宏实战:用filter和箭头函数5分钟搞定数据清洗

别再只会录宏了&#xff01;WPS JS宏实战&#xff1a;用filter和箭头函数5分钟搞定数据清洗当你面对一份杂乱无章的销售数据表&#xff0c;是否还在手动筛选、复制粘贴&#xff1f;传统录制宏虽然简单&#xff0c;但面对复杂的数据清洗需求往往力不从心。本文将带你突破录制宏的…

作者头像 李华
网站建设 2026/6/13 7:02:42

Android代码编辑终极指南:如何用Acode打造移动开发神器

Android代码编辑终极指南&#xff1a;如何用Acode打造移动开发神器 【免费下载链接】Acode Acode - powerful text/code editor for android 项目地址: https://gitcode.com/gh_mirrors/ac/Acode 在移动设备上进行代码编辑一直是个挑战&#xff0c;直到你发现了Acode——…

作者头像 李华
网站建设 2026/6/13 7:02:24

计算机毕业设计之六盘水红色革命平台设计与实现

随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&#xf…

作者头像 李华