一、项目整体介绍
双轮自平衡小车本质上是一个倒立摆系统:
车身就像一根竖着的棍子,两侧的轮子不断调节转速,让车身维持在“快要倒、但没倒”的状态。
一个典型的 STM32 平衡小车系统通常包含:
-
主控 MCU:STM32F103C8T6 / STM32F103RCT6 等
-
姿态传感器:MPU6050(陀螺仪 + 加速度计)或其他 IMU
-
驱动模块:L298N、TB6612 或带编码器的直流电机驱动板
-
电机与编码器:12V/6V 直流减速电机 + 光电/霍尔编码器
-
电源模块:锂电池 + 升降压模块 + 5V/3.3V 稳压
-
通信与调试:蓝牙串口 / 无线串口 / 上位机(串口助手、MATLAB、QT 等)
-
显示与按键(可选):OLED/LCD,参数显示与调参
二 、平衡小车的控制原理
平衡小车常用的几个关键物理量:
-
角度 Angle(θ):相对于竖直方向的偏移角度,0° 为完全直立
-
角速度 Gyro(ω):车身倾斜变化的速度
-
车速 Speed(v):两个轮子的平均转速
-
位移 Position(s):小车前后移动的距离
对应的控制目标:
-
保持直立:θ 尽量接近 0°
-
速度控制:让期望速度 v_target 与实际速度 v 接近
-
位置控制(可选):让车回到某个目标位置
因此,常见的控制结构是三环控制:
三、硬件系统设计
3.1 姿态传感器:MPU6050
MPU6050 内部集成:
-
三轴陀螺仪(Gyro):角速度
-
三轴加速度计(Accel):加速度(静止时可估算重力方向 → 倾角)
接线常见方式:
-
MPU6050 → STM32:I2C 通信(SCL/SDA)
-
电源:3.3V(注意供电电压与 IO 电平)
3.2 电机与驱动
-
两个直流减速电机(带编码器)安装在小车两侧;
-
通过 L298N/TB6612 等驱动芯片接到 STM32 的 PWM / GPIO 引脚;
-
编码器接到 STM32 的外部中断 / 正交编码接口(TIMx_CH1/2)用于测速和记步。
注意事项:
-
电机电源与单片机电源注意分开供电或加足够滤波,避免干扰;
-
驱动芯片的电流、功率要匹配电机参数;
-
启停电流比较大,注意电池放电能力。
3.3 电源管理
-
常见方案:12V锂电池 + 升降压模块;
-
输出 12V(电机)、5V、3.3V(单片机与传感器);
-
要有电压检测功能(ADC 采样),方便实现欠压保护与电量显示。
四、姿态解算(角度计算)
MPU6050 提供:
-
陀螺仪:角速度(积分后得到角度,但会漂移)
-
加速度计:可算出倾角(但对震动和加减速非常敏感)
常用方法:互补滤波
核心思想:
-
低频成分信任加速度计(抗漂移)
-
高频成分信任陀螺仪(抗噪声)
一个简单的互补滤波公式:
float angle;
float K = 0.98f; // 互补滤波系数,一般 0.95~0.99
void Update_Angle(float gyro, float accel_angle, float dt)
{
float gyro_angle = angle + gyro * dt; // 陀螺仪积分角度
angle = K * gyro_angle + (1 - K) * accel_angle;
}
实际实现时的关键点:
-
陀螺仪和加速度计在上电后需要零偏校准;
-
采样周期
dt要尽量稳定(用定时器中断); -
互补滤波系数
K的选择会影响响应速度与稳定性,可以先 0.98 起步再微调。
如果想要更好的效果,可以使用卡尔曼滤波或开源的姿态解算库(如 Mahony/Madgwick),但对于简单的平衡小车,互补滤波已经够用。
五、PID 控制策略
5.1 常见三环结构
-
角度环(平衡环)PID
-
输入:目标角度 θ_target(一般设为 0)与当前角度 θ 的误差
-
输出:期望速度 v_expect(或者直接输出 PWM 分量)
-
-
速度环 PID
-
输入:目标速度 v_target 与实际速度 v 的误差
-
输出:对目标角度或角度环的偏置量(如让小车略微前倾以加速)
-
-
位置环 PID(可选)
-
输入:目标位置与当前位移差
-
输出:作为速度环的目标速度 v_target
-
在初学阶段,建议先实现:
-
只做角度环:先让车能在原地站住;
-
然后增加速度环:实现前进/后退 + 静止保持;
-
最后再考虑位置环与转向控制。
typedef struct
{
float Kp;
float Ki;
float Kd;
float integral;
float last_error;
} PID_t;
PID_t angle_pid = { .Kp = 50.0f, .Ki = 0.0f, .Kd = 1.0f, .integral = 0, .last_error = 0 };
float PID_Calc(PID_t *pid, float target, float measure)
{
float error = target - measure;
pid->integral += error;
float derivative = error - pid->last_error;
pid->last_error = error;
float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative;
return output;
}
六、调试与 PID 参数整定经验
6.1 调试顺序建议
-
先调角度解算
-
把小车放在桌面上,读取角度值;
-
手工轻轻前后倾斜,看看角度变化是否线性、方向是否正确;
-
静止时角度是否基本稳定(抖动范围小于 ±1° 为佳)。
-
-
再调电机驱动
-
单独写一个测试程序:给定 PWM 值,让左右轮正转/反转;
-
检查轮子转向是否符合预期,是否有一边明顯比另一边快;
-
确保编码器计数正常。
-
-
只开角度环
-
速度环、位置环全部关闭;
-
仅用角度 PID 输出电机 PWM;
-
小车会在原地“抖着站立”,此时重点调 Kp、Kd;
-
Ki 一开始可以设为 0,避免积分导致发散。
-
-
加入速度环
-
让车可缓慢前进后退,并在停止命令时能大致停住;
-
速度环的输出不要太大,否则会干扰角度环。
-
4081





