用CH32V103和逐飞库,手把手教你调出能完美循迹停车的智能车PID(附完整代码)

张开发
2026/4/17 23:23:30 15 分钟阅读

分享文章

用CH32V103和逐飞库,手把手教你调出能完美循迹停车的智能车PID(附完整代码)
从零构建智能车PID控制系统CH32V103与逐飞库实战指南1. 项目概述与核心原理在嵌入式系统开发领域智能车控制系统一直是检验开发者综合能力的绝佳项目。不同于简单的代码编写一个稳定可靠的智能车系统需要硬件选型、信号处理、控制算法和调试技巧的完美配合。本文将基于RISC-V架构的CH32V103微控制器和逐飞开源库带你完整实现一套具备循迹与精准停车功能的智能车系统。PID控制算法作为工业控制领域的经典方法其核心思想是通过比例P、积分I、微分D三个环节的线性组合来修正系统偏差。在智能车应用中我们通常采用简化版的PD控制省略积分项这是因为比例项快速响应当前偏差如车体偏离赛道中心微分项预测偏差变化趋势如车体正在加速偏离省略积分项避免赛道间断标记导致的误差累积电感传感器阵列通过电磁感应原理检测预埋的金属赛道其输出电压随距离变化。我们采用差比和算法处理原始数据差比和值 (右电感值 - 左电感值) / (右电感值 左电感值)这种归一化处理有效消除了环境干扰和器件差异的影响输出范围在[-1,1]之间0表示车体居中。2. 硬件系统搭建2.1 关键组件选型组件类别推荐型号功能说明主控芯片CH32V103R8T6RISC-V内核性价比高电机驱动TB6612FNG双路H桥支持PWM调速舵机SG90转向控制180度范围电感传感器LDC1314非接触式电磁检测干簧管MKA-12102磁感应停车开关电源管理LM2596模块提供稳定5V/3.3V输出2.2 电路连接要点电感布局建议采用三电感布局左、中、右间距15-20mm电机驱动PWM频率建议8-10kHz注意加入续流二极管保护MOSFET干簧管安装距地面5-8mm高度配合钕磁铁使用磁场强度约100mT提示初次搭建时务必先单独测试每个模块功能再逐步集成。常见问题包括电源干扰、接地不良和信号线过长导致的噪声。3. 软件开发环境配置3.1 工具链安装使用MounRiver Studio作为开发环境需按顺序安装RISC-V GCC工具链版本8.2.0以上OpenOCD调试工具CH32V系列支持包逐飞库最新版本# 示例逐飞库关键目录结构 ├── Drivers │ ├── CH32V10x_标准外设库 │ └── 逐飞扩展库 ├── Project │ └── Template # 工程模板 └── User ├── headfile.h # 主头文件 └── main.c # 入口文件3.2 关键驱动初始化在board_init()函数中需要完成以下配置// ADC初始化电感输入 adc_init(ADC_IN6_A6); // 左电感 adc_init(ADC_IN8_B0); // 右电感 // PWM初始化电机舵机 timer_pwm_init(PWM4_CH3_B8, 10000, 0); // 电机A timer_pwm_init(PWM4_CH2_B7, 10000, 0); // 电机B timer_pwm_init(PWM3_CH1_C6, 50, 740); // 舵机(50Hz)4. PID控制算法实现4.1 差比和信号处理原始电感值需经过滤波和归一化float get_normalized_value() { float left_sum 0, right_sum 0; for(int i0; i10; i) { left_sum adc_convert(ADC_IN6_A6, ADC_12BIT); right_sum adc_convert(ADC_IN8_B0, ADC_12BIT); systick_delay_ms(1); } float left_avg left_sum/10; float right_avg right_sum/10; return (right_avg - left_avg) / (right_avg left_avg 0.001f); // 避免除零 }4.2 PD控制器实现核心算法仅需几行代码但参数调校是关键// 全局变量 float kp 1.2f; // 比例系数 float kd 0.02f; // 微分系数 float last_error 0; void control_loop() { float current_error get_normalized_value(); float derivative current_error - last_error; float output kp * current_error kd * derivative; // 舵机限幅防止机械损伤 output fmaxf(fminf(output, 50.0f), -50.0f); set_servo_angle(output); last_error current_error; }4.3 参数调试技巧采用二分法逐步逼近最优参数先调P参数从较小值开始如0.5观察车体是否能够响应赛道偏移出现振荡时取当前值的50%再调D参数从P值的1/10开始主要抑制过冲和振荡过大值会导致响应迟钝典型参数范围参考赛道类型Kp范围Kd范围说明直道0.8-1.20.01-0.03小偏差微调急弯1.5-2.50.03-0.08需要快速响应S弯1.0-1.50.05-0.1抑制振荡是关键5. 精准停车实现方案5.1 干簧管信号处理// 硬件去抖动处理 uint8_t check_reed_switch() { static uint8_t count 0; if(gpio_get(D2) 0) { if(count 3) return 1; } else { count 0; } return 0; }5.2 停车状态机实现平滑停车的三个步骤预减速阶段检测到第一个磁铁信号时降低PWM占空比制动阶段检测到第二个信号时电机短时反转锁定阶段关闭所有电机输出enum {RUNNING, BRAKING, STOPPED} state RUNNING; uint8_t magnet_count 0; void parking_handler() { switch(state) { case RUNNING: if(check_reed_switch()) { magnet_count; if(magnet_count 2) { set_motor_reverse(30); // 30%功率反转 state BRAKING; } else { set_motor_speed(50); // 降速到50% } } break; case BRAKING: if(brake_timer 100) { // 制动100ms set_motor_speed(0); state STOPPED; } break; case STOPPED: // 保持停止状态 break; } }6. 实战调试技巧6.1 电感数据可视化通过LCD实时显示关键参数void display_debug_info() { lcd_showstr(0, 0, L:); lcd_showint16(20, 0, adc_left); lcd_showstr(0, 1, R:); lcd_showint16(20, 1, adc_right); lcd_showstr(0, 2, Err:); lcd_showfloat(40, 2, current_error, 2); lcd_showstr(0, 3, Out:); lcd_showfloat(40, 3, servo_output, 2); }6.2 常见问题排查电感值波动大检查电源滤波电容建议增加100μF电解0.1μF陶瓷缩短传感器引线长度软件端增加移动平均滤波舵机响应迟缓确认PWM频率是否为50Hz检查机械结构是否过紧适当增加PD参数停车位置不准调整干簧管安装高度优化制动阶段的持续时间考虑加入距离传感器辅助7. 系统优化方向7.1 速度闭环控制在基础PD控制上增加电机转速反馈// 编码器测速实现 uint32_t get_motor_speed() { static uint32_t last_count 0; uint32_t current encoder_get_count(); uint32_t speed (current - last_count) / SAMPLE_TIME; last_count current; return speed; }7.2 动态参数调整根据赛道特征自动切换PID参数void adaptive_control() { float error_change fabsf(current_error - last_error); if(error_change 0.3f) { // 急弯 kp 2.0f; kd 0.05f; } else { // 直道 kp 1.0f; kd 0.02f; } }7.3 赛道记忆功能通过记录历史误差实现预测控制#define HISTORY_SIZE 5 float error_history[HISTORY_SIZE]; void update_history() { for(int iHISTORY_SIZE-1; i0; i--) { error_history[i] error_history[i-1]; } error_history[0] current_error; }

更多文章