用Arduino UNO R3和MPU6050搞定平衡小车:从硬件接线到PID参数调试全记录
从零打造Arduino平衡小车硬件搭建与PID调参实战指南1. 项目准备与硬件选型平衡小车作为入门机器人的经典项目融合了传感器技术、控制算法和机电一体化设计。在开始动手前我们需要准备以下核心组件核心硬件清单主控板Arduino UNO R3性价比高社区支持完善姿态传感器MPU6050集成三轴加速度计三轴陀螺仪电机驱动TB6612FNG支持双路PWM控制最大1.2A持续电流执行机构带编码器的直流减速电机建议减速比1:48以上电源系统18650锂电池两节串联配专用充电保护板注意选购MPU6050时建议选择带电平转换的模块版本避免5V/3.3V电平不匹配问题硬件连接示意图如下表所示模块Arduino引脚连接说明MPU6050 SDAA4I²C数据线MPU6050 SCLA5I²C时钟线TB6612 PWMAD9左电机PWM控制TB6612 AIN1D7左电机方向控制线1TB6612 AIN2D6左电机方向控制线2TB6612 PWMBD10右电机PWM控制TB6612 BIN1D13右电机方向控制线1TB6612 BIN2D12右电机方向控制线22. 传感器数据采集与处理2.1 MPU6050初始配置MPU6050需要正确初始化才能输出可靠的姿态数据。以下是关键配置步骤#include Wire.h const int MPU_ADDR 0x68; void setup() { Wire.begin(); Wire.beginTransmission(MPU_ADDR); Wire.write(0x6B); // PWR_MGMT_1寄存器 Wire.write(0); // 解除休眠状态 Wire.endTransmission(true); // 设置陀螺仪量程为±500°/s Wire.beginTransmission(MPU_ADDR); Wire.write(0x1B); // GYRO_CONFIG寄存器 Wire.write(0x08); Wire.endTransmission(true); // 设置加速度计量程为±4g Wire.beginTransmission(MPU_ADDR); Wire.write(0x1C); // ACCEL_CONFIG寄存器 Wire.write(0x08); Wire.endTransmission(true); }2.2 卡尔曼滤波实现原始传感器数据存在噪声需要通过滤波算法提高数据质量。以下是简化版的卡尔曼滤波实现class SimpleKalman { private: float Q_angle 0.001; float Q_bias 0.003; float R_measure 0.03; float angle 0; float bias 0; float P[2][2] {{0}}; public: float update(float newAngle, float newRate, float dt) { // 预测阶段 angle dt * (newRate - bias); P[0][0] dt * (dt*P[1][1] - P[0][1] - P[1][0] Q_angle); P[0][1] - dt * P[1][1]; P[1][0] - dt * P[1][1]; P[1][1] Q_bias * dt; // 更新阶段 float y newAngle - angle; float S P[0][0] R_measure; float K[2] {P[0][0]/S, P[1][0]/S}; angle K[0] * y; bias K[1] * y; P[0][0] - K[0] * P[0][0]; P[0][1] - K[0] * P[0][1]; P[1][0] - K[1] * P[0][0]; P[1][1] - K[1] * P[0][1]; return angle; } };3. 电机控制与编码器处理3.1 TB6612FNG驱动配置这款电机驱动芯片需要特别注意引脚逻辑组合控制模式AIN1AIN2PWM电机状态正转HIGHLOWPWM顺时针反转LOWHIGHPWM逆时针刹车HIGHHIGHHIGH快速停止停止LOWLOW-自由停止典型控制代码示例#define AIN1 7 #define AIN2 6 #define PWMA 9 void setMotor(int speed) { if(speed 0) { digitalWrite(AIN1, HIGH); digitalWrite(AIN2, LOW); } else { digitalWrite(AIN1, LOW); digitalWrite(AIN2, HIGH); } analogWrite(PWMA, abs(speed)); }3.2 编码器速度测量使用中断方式捕获编码器脉冲实现速度反馈volatile long encoderCount 0; void setup() { attachInterrupt(digitalPinToInterrupt(2), countEncoder, CHANGE); } void countEncoder() { if(digitalRead(2) digitalRead(3)) { encoderCount; } else { encoderCount--; } } float getSpeed(unsigned long interval) { static long lastCount 0; long currentCount encoderCount; float speed (currentCount - lastCount) * 60.0 / (20.0 * interval) * 1000; // RPM lastCount currentCount; return speed; }4. PID控制算法实现4.1 直立环控制直立环采用PD控制核心公式输出 Kp×角度偏差 Kd×角速度调试步骤先将Kd设为0逐步增大Kp直到小车出现小幅振荡保持Kp不变逐步增加Kd直到振荡消失典型参数范围Kp15-30Kd0.3-0.84.2 速度环控制速度环采用PI控制解决直立环的静态误差输出 Kp×速度偏差 Ki×速度偏差积分调试技巧先调Kp使小车能抵抗轻微推力再调Ki消除稳态误差典型参数比例Ki ≈ Kp/2004.3 转向环控制转向环通过陀螺仪Z轴数据实现差速控制float turnControl(float gyroZ) { static float integral 0; integral gyroZ * dt; return Kp_turn * gyroZ Ki_turn * integral; }5. 系统集成与调试技巧5.1 多任务时序安排使用定时中断确保控制周期稳定#include MsTimer2.h void controlLoop() { static unsigned long lastTime 0; float dt (millis() - lastTime) / 1000.0; lastTime millis(); // 传感器数据读取 // 控制算法计算 // 电机输出 } void setup() { MsTimer2::set(5, controlLoop); // 5ms控制周期 MsTimer2::start(); }5.2 常见问题排查问题1小车剧烈振荡检查Kp是否过大确认MPU6050安装牢固验证电机转向是否正确问题2向一侧倾斜校准机械中值角检查电池电量是否平衡调整重心位置问题3响应迟钝适当增大Kp检查控制周期是否过长确认电机扭矩足够6. 进阶优化方向参数自整定实现PID参数的自动调整void autoTune() { // 通过施加阶跃响应分析系统特性 // 根据响应曲线计算PID参数 }无线调试接口通过蓝牙传输实时数据void sendData() { Serial.print(Angle:); Serial.print(currentAngle); Serial.print(,Output:); Serial.println(motorOutput); }运动轨迹规划实现预设路径行驶# 上位机路径生成示例 import numpy as np t np.linspace(0, 10, 100) path np.sin(t) # 正弦路径在完成基础版本后可以尝试添加超声波避障、手机蓝牙遥控或Wi-Fi视频传输等功能扩展。实际调试中发现电机齿轮间隙对控制效果影响显著建议使用金属齿轮电机并定期润滑维护。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2460073.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!