从“水缸加水”到“平衡车”:用STM32 CubeMX和HAL库,5步搞定你的第一个PID闭环控制项目
2026/4/20 12:43:20 网站建设 项目流程

从“水缸加水”到“平衡车”:用STM32 CubeMX和HAL库,5步搞定你的第一个PID闭环控制项目

平衡车、恒温杯垫、无人机悬停——这些看似复杂的控制系统,核心都离不开PID算法。许多初学者在啃完理论公式后,面对实际项目仍无从下手。本文将用STM32CubeMX和HAL库,带你在5个步骤内构建完整的PID闭环系统,避开那些教科书不会告诉你的实战陷阱。

1. 硬件准备与CubeMX基础配置

1.1 最小系统搭建

平衡车项目需要这些核心部件:

  • STM32F103C8T6最小系统板(蓝色药丸)
  • MPU6050六轴传感器(约8元/个)
  • TB6612电机驱动模块
  • 12V直流减速电机(带编码器更佳)
  • 18650电池组(两节串联)

注意:电机驱动模块的VM引脚必须接电池正极,VCC接5V逻辑电源,避免控制器供电不足导致的异常抖动。

1.2 CubeMX关键配置

在CubeMX中完成这些必要设置:

/* PWM生成配置 */ TIM1->CCR1 = 0; // 初始化占空比为0% HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); /* ADC采样配置 */ HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, 2); /* 串口调试输出 */ printf("PID Debug: Kp=%.2f, Output=%.2f\r\n", pid.Kp, output);

配置要点:

  1. 选择正确的时钟源(HSE 8MHz)
  2. 启用TIM1的PWM输出通道
  3. 配置ADC规则组为连续转换模式
  4. 开启DMA传输减轻CPU负担

2. PID算法移植与HAL库适配

2.1 从公式到代码

经典位置式PID的HAL库实现:

typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PID_Controller; float PID_Update(PID_Controller* pid, float setpoint, float measurement) { float error = setpoint - measurement; pid->integral += error * dt; float derivative = (error - pid->prev_error) / dt; pid->prev_error = error; return pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; }

2.2 三个易错点解决方案

  1. 积分饱和:限制integral累计范围
    if(pid->integral > 1000) pid->integral = 1000; else if(pid->integral < -1000) pid->integral = -1000;
  2. 微分冲击:对测量值进行低通滤波
    # Python模拟代码展示原理 filtered = 0.9 * filtered + 0.1 * new_value
  3. 采样时间抖动:使用硬件定时器触发
    HAL_TIM_Base_Start_IT(&htim2); // 定时器中断中调用PID计算

3. 参数调试实战技巧

3.1 从零开始的调参路线图

阶段目标操作预期现象
纯P控制建立基础响应Kp从0.1开始倍增出现小幅振荡
加入积分消除静差Ki=Kp/采样周期超调量增大
加入微分抑制振荡Kd=Kp*采样周期/8响应曲线平滑

3.2 串口可视化调试法

使用匿名四轴地面站观察实时曲线:

  1. 发送数据格式:
    printf("$%.2f,%.2f,%.2f#", setpoint, actual, output);
  2. 典型问题诊断:
    • 持续低频振荡:Kp过大,需降低20%
    • 静差无法消除:Ki过小,加倍尝试
    • 高频抖动:Kd过大,减半处理

4. 平衡车项目完整实现

4.1 姿态解算关键代码

MPU6050数据处理流程:

// 读取原始数据 HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, ACCEL_XOUT_H, 1, raw_data, 14, 100); // 互补滤波 angle = 0.98*(angle + gyro*dt) + 0.02*accel_angle;

4.2 电机控制策略

速度环+角度环双PID结构:

+-------+ 设定角度 ->| 角度环 |-> 目标速度 ->| 速度环 |-> PWM输出 +-------+ +-------+

实现代码框架:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim2) { // 10ms定时中断 float angle = Get_MPU6050_Angle(); float speed_target = PID_Angle_Update(angle); float speed_actual = Get_Encoder_Speed(); float pwm = PID_Speed_Update(speed_target, speed_actual); __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwm); } }

5. 进阶优化与故障排查

5.1 常见问题速查表

现象可能原因解决方案
电机剧烈抖动电源功率不足更换大电流电池
角度测量漂移传感器未校准执行零偏校准
响应延迟明显PID计算周期过长优化代码结构

5.2 性能提升技巧

  • 动态参数调整:根据倾斜角度自适应调整Kp
    pid.Kp = BASE_KP + fabs(angle) * ADAPTIVE_FACTOR;
  • 死区补偿:消除电机启动静摩擦
    if(fabs(output) < 0.1) output = 0.15 * (output>0?1:-1);
  • 软件限幅:保护电机驱动电路
    pwm = constrain(pwm, -900, 900); // 限制在±90%占空比

调试平衡车那周,实验室地板上全是车轮打滑的黑色痕迹。最惊喜的时刻是当Kd值调到0.8时,原本摇晃的车体突然像被无形的手扶稳——那一刻真正理解了微分项"预测未来"的魔力。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询