基于STM32F103C8的两轮平衡车工程,应用了卡尔曼滤波和PID算法,很有参考价值
基于STM32F103C8的两轮平衡车工程,应用了卡尔曼滤波和PID算法,很有参考价值!
蹲在实验室角落的平衡车突然立起来的时候,我手里的烙铁差点掉地上——这玩意儿真能站住了!基于STM32F103C8的平衡车项目折腾了两个月,核心就靠卡尔曼滤波和PID这对黄金搭档。今天咱们不整虚的,直接扒代码看门道。
先聊聊传感器这货
MPU6050传回来的数据就跟喝醉似的,原始数据里的噪声能把陀螺仪和加速度计数据带偏到姥姥家。这时候卡尔曼滤波就像个靠谱的管家,把杂乱信息收拾得服服帖帖。上硬菜:
typedef struct {
float Q_angle; // 过程噪声协方差
float Q_bias; // 陀螺仪偏置噪声
float R_measure;// 测量噪声协方差
float angle; // 最优估计角度
float bias; // 陀螺仪偏置
float P[2][2]; // 误差协方差矩阵
} KalmanFilter;
这个结构体藏着卡尔曼滤波的魂。重点在P矩阵的更新策略,它决定了滤波器的收敛速度。实际调试时发现,把Qangle设为0.001、Rmeasure设为0.03时,能在响应速度和稳定性之间找到最佳平衡点。
预测函数里藏着玄机
void kalmanPredict(KalmanFilter* kf, float dotAngle, float dt) {
kf->angle += (dotAngle - kf->bias) * dt;
kf->P[0][0] += dt * (dt*kf->P[1][1] - kf->P[0][1] - kf->P[1][0] + kf->Q_angle);
kf->P[0][1] -= dt * kf->P[1][1];
kf->P[1][0] -= dt * kf->P[1][1];
kf->P[1][1] += kf->Q_bias * dt;
}
这坨代码实现了状态预测的核心逻辑。dt参数必须精确到毫秒级,用STM32的TIM3定时器捕获时间戳,实测误差控制在±0.5ms以内才不会翻车。
PID才是平衡车的灵魂
当滤波后的角度数据送到PID控制器时,真正的魔法开始了。别被教科书忽悠,实际工程中微分项得加低通滤波:
typedef struct {
float Kp, Ki, Kd;
float target;
float integral;
float lastError;
float derivative;
} PIDController;
float pidUpdate(PIDController* pid, float input) {
float error = pid->target - input;
pid->integral += error * dt;
// 微分项过滤(关键!)
pid->derivative = (error - pid->lastError) / dt;
pid->derivative = 0.6 * pid->derivative + 0.4 * pid->lastDerivative;
pid->lastError = error;
return pid->Kp*error + pid->Ki*pid->integral + pid->Kd*pid->derivative;
}
这个微分项的滑动平均滤波操作,能有效抑制电机的高频抖动。调试时发现,把0.6和0.4的系数对调会导致系统震荡,玄学程度堪比老中医把脉。
电机驱动得玩点骚操作
普通PWM控制不够劲,得上双极性驱动:
void setMotorPWM(int motor, float pwm) {
if(pwm >=0){
TIM_SetComparex(motor==LEFT ? TIM1 : TIM2, pwm);
GPIO_WriteBit(MOTOR_PORT, motor==LEFT ? IN1_PIN : IN3_PIN, 0);
} else {
TIM_SetComparex(motor==LEFT ? TIM1 : TIM2, -pwm);
GPIO_WriteBit(MOTOR_PORT, motor==LEFT ? IN1_PIN : IN3_PIN, 1);
}
}
这种正反转控制策略让电机的刹车响应速度提升约30%,实测从静止到直立稳定只需0.8秒。注意死区时间配置,否则MOS管分分钟放烟花。
调参时发现个邪门现象:当Kp值超过12时,平衡车会突然鬼畜般疯狂抖动,然后表演原地后空翻——别问我是怎么知道的。最终稳定参数是Kp=8.5, Ki=0.02, Kd=45,这组参数能让小车在5度倾斜内快速回正。
最坑爹的是供电问题。某次测试时锂电池电压降到7.4V以下,PID输出开始抽风,后来在代码里加了电压补偿才解决:
float voltageCompensation = (currentVoltage > 7.4f) ? 1.0f : (currentVoltage / 7.4f);
output *= voltageCompensation;
这种非线性补偿比单纯的电压检测靠谱得多,实测在6.8V时仍能保持平衡,虽然这时候的电机声听着像得了哮喘。
折腾完这破项目最大的感悟是:理论公式和实际代码之间隔着一整个银河系。那些论文里的完美曲线,都是debug时摔了八百次车才调出来的。现在这辆平衡车能驮着两瓶矿泉水满实验室跑,算是没白掉那些头发。

更多推荐
所有评论(0)