1. 项目概述:当ESP32遇上平衡控制
去年夏天我在工作室捣鼓废旧电机时,突然萌生了个想法:能不能用ESP32做个能塞进口袋的平衡车?经过三个月的迭代,这个巴掌大的miniBot已经能稳定地在桌面上自主平衡了。相比市面上的平衡车方案,这个项目的特别之处在于:
- 采用ESP32作为主控,兼具WiFi/蓝牙无线控制功能
- 整体尺寸控制在8×8cm以内
- 使用MPU6050实现低成本姿态检测
- 完整的PID调参方案开源
这个指南将完整呈现从零件选型到算法调参的全过程,特别适合想入门嵌入式控制和物联网开发的创客。所有代码和3D打印文件已托管在GitHub,文末会提供获取方式。
2. 硬件架构设计解析
2.1 核心部件选型对比
在迷你平衡车的硬件设计中,每个元件的尺寸和性能都需要精确平衡。这是我的选型对照表:
| 部件 | 候选方案 | 最终选择 | 选择理由 |
|---|---|---|---|
| 主控 | ESP32/STM32/Arduino | ESP32-WROOM-32 | 双核240MHz+无线功能 |
| 电机 | N20/TT/直流减速 | N20减速电机(1:50) | 体积小(Φ10mm)+足够扭矩 |
| 姿态传感器 | MPU6050/MPU9250/BMI160 | MPU6050 | 成本<20元且DMP支持 |
| 电池 | 18650/锂聚合物 | 602025锂电(800mAh) | 厚度仅6mm |
实测发现:电机转速不宜超过200RPM,否则PID响应会跟不上。建议选择带编码器的N20电机方便后期扩展速度环控制。
2.2 关键电路设计要点
电源管理是迷你平衡车的痛点,我的解决方案是:
- 采用TPS63020升降压芯片,实现2.5-5V稳定输出
- 电机驱动使用TB6612替代L298N,发热量降低70%
- 为MPU6050单独设计LC滤波电路,噪声降低到0.01Vpp
特别注意:ESP32的ADC引脚必须远离电机驱动线路,我在PCB布局时特意将两者分置板卡两侧,并铺铜隔离。
3. 软件控制逻辑实现
3.1 姿态解算方案对比
测试了三种常见的姿态获取方式:
cpp复制// 方案1:直接读取原始数据(不推荐)
float accelY = mpu.getAccelY();
// 方案2:使用DMP库输出四元数(推荐)
Quaternion q = mpu.dmpGetQuaternion();
// 方案3:Mahony滤波(需额外计算)
MahonyAHRSupdate(gx, gy, gz, ax, ay, az);
实测数据更新率对比:
- 原始数据:1.2ms/次
- DMP输出:2.8ms/次
- Mahony滤波:5.6ms/次
最终选择DMP方案,因其在精度和实时性间取得了最佳平衡。
3.2 PID控制核心代码
这是经过30多次调参验证的稳定版本:
cpp复制void balanceTask(void *pvParameters) {
while(1) {
float angle = getFilteredAngle(); // 获取当前倾角
float gyro = getGyroY(); // 获取角速度
// 位置式PID计算
err = targetAngle - angle;
integral += err * dt;
derivative = (err - lastErr) / dt;
output = Kp*err + Ki*integral + Kd*derivative + Kg*gyro;
setMotorSpeed(output);
lastErr = err;
vTaskDelay(5 / portTICK_PERIOD_MS);
}
}
关键参数经验值:
- Kp(比例):12-15
- Ki(积分):0.2-0.5
- Kd(微分):0.8-1.2
- Kg(陀螺仪补偿):0.05
4. 结构设计与装配技巧
4.1 3D打印参数优化
使用PETG材料打印时,这些参数组合效果最佳:
- 层高:0.16mm
- 壁厚:1.2mm
- 填充率:25%(蜂窝结构)
- 打印速度:40mm/s
特别提醒:电机支架需要添加0.3mm的装配余量,否则高温环境下可能卡死。我在第四版设计中加入了散热槽,电机温度下降了18℃。
4.2 装配顺序图解
正确的装配流程应该是:
- 先固定主板和电池仓
- 安装电机并测试转向
- 连接轮毂(使用乐高轮胎需加3D打印转接件)
- 最后装配外壳上盖
常见错误:若先装外壳再焊线,90%的概率会因操作空间不足导致虚焊。
5. 无线控制功能扩展
5.1 BLE遥控器实现
通过BLE实现手机控制的关键代码:
cpp复制class MyServerCallbacks: public BLEServerCallbacks {
void onWrite(BLECharacteristic *pChar) {
std::string value = pChar->getValue();
if(value == "F") motorForward();
else if(value == "B") motorBackward();
}
};
void setupBLE() {
BLEDevice::init("miniBot");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// ... 更多服务配置
}
5.2 OTA升级配置
在platformio.ini中添加这些配置实现无线升级:
ini复制[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
upload_protocol = espota
upload_port = miniBot.local
使用时只需执行 pio run -t upload 就能自动发现设备并上传固件。
6. 调试与问题排查实录
6.1 典型故障现象分析
这些是我踩过的坑及解决方案:
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| 启动后剧烈抖动 | PID参数过冲 | 先调Kp至刚好能立住 |
| 往单侧持续加速 | 电机极性接反 | 交换A/B相线序 |
| 运行几分钟后失控 | 电源电压跌落 | 增加1000μF电容缓冲 |
| 蓝牙连接频繁断开 | WiFi共存干扰 | 修改BLE间隔为20ms |
6.2 校准工具开发
自制了串口调试工具,关键功能包括:
- 实时绘制角度波形图
- PID参数滑动调节
- 电机PWM占空比测试
使用Python实现的核心代码片段:
python复制import serial
ser = serial.Serial('COM3', 115200)
while True:
data = ser.readline().decode().strip()
angle, output = map(float, data.split(','))
plt.plot(angle, 'r-', output, 'b--')
plt.pause(0.01)
7. 项目优化与进阶方向
当前版本的待改进点:
- 续航时间仅45分钟 → 可换用更高能量密度电池
- 无避障功能 → 加装VL53L0X激光测距
- 运动轨迹单一 → 开发手机APP路径规划
有个有趣的发现:通过修改PID目标值为动态正弦波,可以让小车实现自主摇摆舞蹈。代码实现如下:
cpp复制void danceMode() {
targetAngle = 10 * sin(millis()/500.0);
// 配合灯光效果更佳
neopixel.setColor(0,255*abs(sin(millis()/200.0)),0);
}
所有工程文件已开源在GitHub(搜索miniBot-ESP32),包括:
- 完整Arduino工程
- 3D打印STL文件
- 电路原理图
- 手机APP源码
最后分享一个调参心得:当小车出现高频振荡时,不要急着调小Kp,先检查结构刚性——有次发现是螺丝没拧紧导致共振,浪费了我两天时间。
