简介:本资源是一套面向高校嵌入式系统课程设计与期末大作业的完整实践项目,专为WHEELTEC B570平衡小车平台开发,适用于嵌入式初学者及课程实践者,解决从原理理解、代码调试到功能验证的一站式学习需求。压缩包共315个文件,涵盖44个C源文件(含HAL库驱动与MPU6050姿态解算核心逻辑)、71个头文件(定义传感器接口、PID参数与控制结构体)、44个编译中间文件及多个Makefile、.ioc工程配置与hex/elf可执行镜像,整体仅1.13MB,轻量易部署。已有266人下载学习,项目经实际课程验证获满分评价,配套文档详述硬件连接、DMP姿态融合原理、串口调试方法及PID调参步骤,代码全程中文注释,关键模块如inv_mpu_dmp_motion_driver.c、stm32f1xx_hal_adc.c等均深度适配B570平台,开箱即用,无需额外环境配置。
1. 项目概述:从零到一,打造一台能“站”起来的智能小车
如果你是一名电子信息、自动化或计算机相关专业的学生,或者是对嵌入式系统感兴趣的爱好者,那么“平衡小车”这个项目对你来说,绝对是一个里程碑式的挑战。它不像点亮一个LED灯那么简单,也不像驱动一个电机那样单向,它要求你的作品能够像人类一样,对抗重力,自主地保持直立平衡。我当年第一次看到实验室的学长让一台小车稳稳立在原地时,那种震撼感至今记忆犹新。今天,我们就以WHEELTEC的B570平衡小车套件为蓝本,深度拆解这个“满分项目”背后的技术逻辑、实现细节以及那些文档里不会写的“踩坑”实录。
WHEELTEC B570是一款非常经典的平衡小车教学与开发平台,它集成了STM32微控制器、MPU6050姿态传感器、直流减速电机与编码器、TB6612电机驱动等核心模块。所谓“平衡小车”,其核心目标就是通过程序(即“源码”)控制两个轮子,实时调整转速和方向,来补偿车体的倾斜,从而实现动态平衡。这个过程涉及嵌入式C语言编程、传感器数据采集与滤波、PID控制算法、电机驱动与PWM调制等多个关键技术的融合。完成这个项目,意味着你不仅理解了这些技术的理论,更具备了将它们整合到一个实时控制系统中的工程能力。接下来,我将带你超越简单的代码搬运,深入每个环节的“为什么”和“怎么做”,分享如何从一堆散件开始,最终得到一个运行稳定、响应灵敏的平衡小车。
2. 核心硬件平台与传感器选型解析
2.1 WHEELTEC B570核心板与主控芯片深度剖析
B570的核心大脑通常是一块基于ARM Cortex-M内核的STM32系列微控制器,常见的是STM32F103C8T6或STM32F407。选择这类MCU而非简单的51单片机,背后有深刻的工程考量。平衡控制是一个典型的实时控制系统,对处理器的运算速度、中断响应能力和外设丰富度有极高要求。
以STM32F103为例,它的主频可达72MHz,拥有丰富的定时器(用于产生精准的PWM波驱动电机)、ADC(用于读取电池电压等模拟量)、以及多个通信接口(如I2C用于读取MPU6050,USART用于调试输出)。更重要的是,它支持硬件中断嵌套,这对于平衡小车至关重要。姿态传感器MPU6050的数据需要以固定的频率(例如500Hz)被读取和处理,这个读取过程必须通过定时器触发的中断来保证其周期性,任何延迟都可能导致控制失调,小车倾倒。如果使用查询方式,主循环中的其他任务(如蓝牙通信、状态显示)很容易干扰采样时序。因此,STM32的中断系统和DMA(直接存储器访问)功能,是实现高实时性控制的基础硬件保障。
在硬件连接上,需要特别注意电源部分的设计。电机在启动和急停时会产生巨大的反向电动势,对数字电路的电源造成干扰。B570的PCB设计通常会将电机驱动部分(大电流)与核心控制部分(小电流)进行电源隔离或使用磁珠、大电容进行滤波。我们在自己焊接或检查电路时,如果发现单片机偶尔复位或传感器数据异常跳动,第一个要怀疑的就是电源质量。一个实用的技巧是,用示波器探头测量单片机VCC引脚在电机动作时的波形,如果看到明显的毛刺或电压跌落,就需要加强电源滤波。
2.2 姿态感知核心:MPU6050传感器的工作原理与数据融合
MPU6050是这个项目的“前庭器官”,它集成了三轴陀螺仪和三轴加速度计。但获取原始的传感器数据只是第一步,如何从中得到准确、稳定的车身倾斜角,才是真正的挑战。
陀螺仪测量的是角速度,通过对角速度积分可以得到角度变化。但陀螺仪存在零漂(即使静止不动,输出也不为零),积分误差会随着时间累积,导致角度估计越来越偏离真实值。加速度计测量的是包括重力加速度在内的三轴加速度。当小车基本处于静止或匀速运动状态时,通过计算加速度矢量和重力方向的夹角,可以解算出一个“绝对”的俯仰角和横滚角。但加速度计对震动极其敏感,电机转动、车轮过坎带来的高频振动会严重污染加速度数据。
因此,单一传感器不可靠,必须进行“数据融合”。最经典且高效的方法就是互补滤波。其核心思想非常直观:利用加速度计数据的长期稳定性(低频特性好)来校正陀螺仪积分产生的累积误差;利用陀螺仪数据的短期精确性和抗动性(高频特性好)来弥补加速度计受震动影响的缺陷。在代码中,这通常体现为一个简单的公式:角度 = 0.98 * (上一角度 + 陀螺仪角速度 * dt) + 0.02 * 加速度计角度。其中0.98和0.02是权重系数,dt是采样周期。这个比例系数需要根据实际调试确定,原则是让融合后的角度既响应迅速,又不会因为车身震动而疯狂抖动。
注意:MPU6050上电后需要一小段时间稳定,且其内部有可配置的数字低通滤波器。务必在初始化时根据你的控制频率(如500Hz)配置合适的滤波器带宽。带宽过低会引入延迟,影响控制实时性;带宽过高则无法滤除噪声。通常设置为采样频率的1/4到1/2是比较合理的起点。
2.3 执行机构:直流电机、编码器与驱动电路协同
小车的“双腿”由两个带减速箱的直流电机构成,每个电机都配有一个正交编码器。编码器是闭环控制的“眼睛”,它反馈的是电机的实际转速(通过测量一定时间内的脉冲数)。驱动芯片常用TB6612或DRV8833,它们相比传统的L298N效率更高、发热更小。
这里的关键是电机驱动、PWM和编码器读取三者的配合。STM32的定时器功能在这里大放异彩。我们通常使用一个高级定时器(如TIM1)产生两路带死区互补的PWM波,分别控制一个电机的正反转和速度。死区时间是必须设置的,目的是防止驱动桥上下两个MOS管同时导通造成短路。同时,我们会用另外两个通用定时器(如TIM2, TIM3)的编码器接口模式,直接读取电机编码器的A、B相脉冲。定时器硬件会自动根据A、B相的相位关系判断正反转并计数,大大减轻了CPU负担。
电机的机械特性也对控制有影响。减速箱虽然增大了扭矩,但也引入了回差和摩擦。你会发现,给电机一个很小的PWM占空比,它可能根本不转(死区),直到占空比超过某个阈值才开始转动。这个非线性环节需要在速度环PID控制中加以考虑,有时会加入一个“静态补偿”值,或者使用带死区补偿的PID算法。
3. 控制系统架构与核心算法实现
3.1 平衡小车控制模型与直立环设计
平衡小车的控制模型可以抽象为一个倒立摆。控制目标是通过调整车轮的加速度(即给车轮施加的力),来抵消车身的倾斜。经过线性化处理后,可以得到一个相对简单的控制律:车轮加速度与车身倾斜角成正比。在数字控制器中,我们最终输出的是电机的PWM值,它对应电机的扭矩,进而产生加速度。
因此,最核心的“直立环”就是一个角度PD控制器。输入是期望角度(通常为0度,即直立)与MPU6050融合后的当前角度之差(误差e),输出是一个用于控制电机的基础PWM值。公式为:PWM_直立 = Kp * e + Kd * (e - last_e) / dt。其中,Kp是比例系数,它决定了小车“多么努力地想回到竖直位置”,Kp太小小车无力回正,Kp太大小车会剧烈振荡。Kd是微分系数,它感知角度变化的趋势(角速度),起到阻尼作用,防止小车回过劲而朝另一边倒下去。微分项的引入至关重要,它是抑制振荡的关键。
调试直立环时,一个非常有效的方法是“手持测试”。用手握住小车,让它稍微倾斜,感受电机输出的力度。你应该能感觉到,倾斜角度越大,电机抵抗的力越大(P项作用);当你快速倾斜小车时,电机会有一个更猛的“顿挫感”(D项作用)。通过反复调整Kp和Kd,直到小车在手中能给你一种“柔顺而坚定”的抵抗感,就成功了一半。
3.2 速度环与转向环:实现定速与转向功能
仅有直立环,小车只能像一个不倒翁一样站在原地。如果想让它前进、后退或者转向,就需要引入额外的控制环。
速度环:它的目标是让小车在保持直立的同时,将速度维持在一个设定值(通常为0,即静止)。速度环的输入是期望速度(常为0)与编码器测得的速度平均值之差,输出是一个叠加在直立环输出上的PWM修正量。速度环通常是一个PI控制器。I(积分)项的引入是为了消除静差。例如,当小车受到一个持续的外力(如地面轻微倾斜)时,纯比例控制可能会让小车以一个恒定的速度缓慢移动来维持平衡,而积分项可以累积这个速度误差,最终产生一个额外的力来完全抵消这个外力,使小车真正静止。调试速度环时,积分系数Ki要非常小心,太大容易引起系统超调和不稳定。
转向环:控制小车左转或右转。输入是期望转向速度(来自遥控器或自动循迹算法)与左右轮速度差之差,输出是左右电机PWM的差动值。转向环一般也是一个P或者PD控制器。它独立于直立环和速度环,直接修改左右轮的最终输出,实现差速转向。
这三个环的输出最终在代码中汇总:左轮PWM = 直立环输出 + 速度环输出 - 转向环输出;右轮PWM = 直立环输出 + 速度环输出 + 转向环输出。这里的加减号取决于你的电机接线方向定义。
3.3 PID控制器参数整定实战经验
PID调参是平衡小车项目的“玄学”部分,但有其内在逻辑。我的经验是严格遵守“先内环后外环,先比例后微分再积分”的顺序。
单独调试直立环(PD):将速度环和转向环的输出置零。从小参数开始(Kp=10, Kd=0.1),逐步增大Kp直到小车能站住但开始高频振荡。然后逐步增大Kd,振荡会减弱并变得缓慢。继续微调Kp和Kd,目标是让小车在受到轻微扰动后,能在1-2个摆动周期内稳定下来,且无明显超调。此时,可以尝试松手让它自己站立。
加入速度环(PI):在直立环稳定的基础上,加入速度环。先将Ki设为0,调速度环的Kp。给小车一个轻微的推力,观察它的反应。理想情况是,它移动一小段距离后,会缓慢回到原点。如果推走后加速跑开,说明速度环Kp为正反馈了(符号错了)。如果推走后很快回来但引起直立振荡,说明速度环Kp太强,需要减小。调好Kp后,再引入一个很小的Ki,用于消除静差。Ki的调试要非常缓慢,每次增加0.1的量级,观察效果。
最后调试转向环:转向环相对独立,主要保证转向响应平滑,不引起车身剧烈晃动即可。
一个至关重要的调试工具是串口绘图。将关键变量(如角度、角速度、速度、PWM输出)通过串口发送到电脑,使用SerialPlot、VOFA+等工具实时绘制曲线。通过曲线,你可以清晰地看到超调、振荡、静差,这是比单纯观察小车行为高效得多的调试方法。
4. 软件架构设计与关键代码模块精讲
4.1 基于定时器中断的实时任务调度
一个健壮的平衡小车软件架构必须是基于时间触发的。绝对要避免在main函数的while(1)循环里进行延时或顺序执行关键任务。标准的做法是利用一个基本定时器(如SysTick或TIM4)产生固定周期(如2ms)的中断,在这个中断服务函数中,以严格的顺序执行所有实时性要求高的任务。
// 定时器中断服务函数示例 (2ms周期) void TIM4_IRQHandler(void) { if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update); // 1. 读取传感器数据 (MPU6050 via I2C/DMP) Get_MPU6050_Data(&pitch, &gyro_y); // 2. 互补滤波计算融合角度 Angle_Calculate(pitch, gyro_y); // 3. 读取编码器值,计算速度 Get_Motor_Speed(&speed_left, &speed_right); // 4. 执行直立PD控制 PWM_vertical = Vertical_PD_Control(angle_set, angle_real, gyro_y); // 5. 执行速度PI控制 PWM_speed = Speed_PI_Control(speed_set, (speed_left+speed_right)/2); // 6. 执行转向控制 PWM_turn = Turn_Control(turn_set, speed_left, speed_right); // 7. 综合计算最终PWM并输出 Motor_Set_Pwm(PWM_vertical + PWM_speed - PWM_turn, PWM_vertical + PWM_speed + PWM_turn); } }这种架构保证了控制周期恒定,无论主循环中在处理蓝牙数据还是刷新OLED显示,都不会影响最核心的控制律计算。主循环只负责非实时任务,如接收遥控指令、更新状态显示、参数调试等。
4.2 传感器数据读取与滤波算法实现
MPU6050的读取有两种常见方式:一是直接读取原始寄存器的陀螺仪和加速度计数据,自己在MCU端进行融合计算;二是使用MPU6050自带的DMP(数字运动处理器)库。DMP是InvenSense公司内置在芯片中的固件,它直接输出解算好的四元数,可以大大减轻MCU负担并提高精度。对于STM32F103这类资源相对紧张的单片机,使用DMP是更优选择,但需要移植官方提供的inv_mpu.c和inv_mpu_dmp_motion_driver.c等库文件,并正确配置I2C接口。
如果自己实现融合,除了前述的互补滤波,卡尔曼滤波是更优但更复杂的方案。它通过状态空间模型,对系统的“状态”(如角度、角速度)进行最优估计。对于平衡小车,一个一维的卡尔曼滤波器(仅估计俯仰角)就能取得比互补滤波更好的效果,尤其是在存在持续加速度(如小车匀加速运动)时。网上有大量开源的一维卡尔曼滤波代码,核心是五个公式:状态预测、协方差预测、卡尔曼增益计算、状态更新、协方差更新。将其封装成一个函数,在每次获取传感器数据后调用即可。
编码器速度计算需要注意防溢出和滤波。定时器的编码器模式是16位计数器,高速正反转时会溢出。需要在中断中检查计数器的溢出标志并进行累计。计算速度时,是读取固定时间间隔dt内的脉冲数delta_cnt。速度 =(delta_cnt / 编码器线数 / 减速比) * (2 * PI * 轮半径) / dt。得到的原始速度值噪声很大,通常需要进行低通滤波:speed_filtered = 0.9 * speed_filtered + 0.1 * speed_raw。
4.3 电机控制与PWM输出模块
电机控制函数的核心是限幅和保护。计算出的PWM值在赋值给定时器比较寄存器前,必须进行限幅,确保其在有效范围内(如-999到999)。同时,需要根据电机驱动芯片的逻辑,将正负的PWM值转换为具体的控制引脚电平。例如,对于TB6612,一种常见的控制方式是:
- PWM > 0:AIN1=1, AIN2=0, PWM值直接输出。
- PWM < 0:AIN1=0, AIN2=1, PWM值取绝对值输出。
- PWM = 0:刹车或滑行(根据AIN1和AIN2都设为0或1决定)。
此外,必须加入“软件死区”。虽然硬件驱动有死区,但在控制逻辑上,当PWM绝对值小于某个阈值(如20)时,直接将其设为0。这是因为电机存在静摩擦,过小的PWM不足以驱动电机,只会让它发热并引入非线性干扰。
5. 项目调试、问题排查与性能优化实录
5.1 上电调试流程与常见故障现象
一套规范的调试流程能极大节省时间。我的习惯是:
- 硬件静态检查:万用表检查所有电源对地是否短路,核心电压(3.3V, 5V)是否正常。确保所有插接件牢固。
- 基础外设测试:编写最简单的程序,测试LED闪烁、串口打印“Hello World”。确保最小系统正常。
- 传感器单独测试:编写MPU6050测试程序,通过串口打印原始加速度计和陀螺仪数据。静止时,加速度计Z轴应约为重力加速度,陀螺仪各轴输出应在零点附近小幅波动。晃动传感器,观察数据变化是否灵敏、符合预期。
- 电机与编码器单独测试:编写程序,让电机以一个固定的低速正反转,同时打印编码器计数。观察电机转向是否正确,编码器计数是否随转向增减。
- 闭环控制调试:按照第3.3节的顺序,逐步调试PID参数。
常见故障与排查:
- 现象:小车一上电就向一边猛冲倒地。
- 排查:首先检查MPU6050安装方向与代码中的坐标系定义是否一致。常见错误是传感器前后或左右装反了。其次,检查直立环PD控制器的输出符号。角度误差为正时,电机应该产生一个纠正的加速度,这个加速度的方向需要根据你的机械结构和电机接线来确定,可以通过“手持测试”验证。
- 现象:小车能站住,但身体高频颤抖。
- 排查:直立环微分项D系数不足,无法提供足够的阻尼。尝试增大Kd。也可能是传感器数据噪声太大,检查MPU6050的滤波参数设置,或为融合后的角度增加一个低通滤波。
- 现象:小车站住后,会缓慢地向一个方向移动。
- 排查:这是速度环未起作用或参数不合适的典型表现。检查速度环是否已启用,速度环的反馈量(编码器速度)符号是否正确。如果启用了速度环,尝试适当增大速度环的积分系数Ki。
- 现象:通过蓝牙发送指令,小车无反应。
- 排查:检查串口中断优先级是否低于控制定时器中断。如果控制中断优先级最高,且执行时间过长,可能会阻塞蓝牙串口中断,导致数据丢失。确保控制中断执行路径尽可能短,非关键计算可移到主循环。
5.2 抗干扰与稳定性提升技巧
- 电源去耦:在每个芯片的电源引脚附近,紧贴芯片放置一个0.1uF的陶瓷电容,用于滤除高频噪声。电机驱动电源入口处,并联一个大容量(如470uF)的电解电容,用于缓冲大电流冲击。
- 传感器隔离:MPU6050尽量通过排线或软连接与主控板连接,避免电机振动直接传递到传感器。可以在传感器和车架之间垫一层海绵或硅胶减震。
- 软件滤波:除了传感器融合算法,对关键的反馈量如编码器速度,进行滑动平均滤波或一阶低通滤波。
- 看门狗:开启STM32的独立看门狗(IWDG),在
while(1)主循环中定期喂狗。一旦程序跑飞,系统会自动复位,避免小车失控造成危险。 - 参数存储:调试好的PID参数可以存储在STM32的内部Flash或外置EEPROM中,避免每次上电都需要重新调整。
5.3 功能扩展与进阶优化思路
当基础平衡和速度控制稳定后,这个平台可以扩展出许多有趣的功能:
- 无线遥控:通过蓝牙(如HC-05/06)或2.4G(如NRF24L01)模块接收手机APP或遥控器的指令,实现前进、后退、转向。
- 姿态导航:利用MPU6050的陀螺仪进行航向角积分,实现粗略的原地转向角度控制(注意陀螺仪Z轴漂移需要补偿)。
- 循迹与避障:增加红外对管或灰度传感器实现循迹,增加超声波或TOF传感器实现避障。这时需要设计更上层的决策逻辑,例如状态机。
- 上位机监控:利用串口将小车内部的关键数据(角度、速度、PWM、PID参数)实时发送到电脑上位机(如VOFA+、匿名科创地面站),实现可视化调试和参数在线调整,这是专业调试的利器。
- 模型与仿真:对于学有余力的同学,可以在MATLAB/Simulink中建立小车的动力学模型,进行PID参数仿真整定,再将参数应用到实物上,理论与实践结合。
完成一个平衡小车项目,收获的远不止一份代码和一份报告。你经历的是一个完整的嵌入式产品开发流程:硬件选型、电路理解、传感器驱动、算法实现、调试排错、性能优化。这个过程里对实时性、稳定性、抗干扰的深刻体会,是任何书本都难以完全传授的。当你最终看到自己亲手打造的小车稳稳立住,并听从你的指令灵活运动时,那种成就感就是对所有努力最好的回报。最后分享一个小心得:调试时,不妨给小车系上一根“安全带”(比如在顶部系一根绳子吊起来,或者放在两块软海绵中间),这样可以在它失控时提供保护,避免硬件损坏,让你能更放心地进行参数调试。
本文还有配套的精品资源,点击获取