目录
P.S.本次项目复刻 bilibili 会飞的鱿鱼03《草履虫都能学会的STM32平衡小车教程》,基础较为薄弱的同学可以同时参考视频步骤进行复刻。将此过程写入博客,其一是作一个完整的复盘总结,其二是记录自我思考的部分,其三分享的过程也是再学习的过程。千里之行始于足下,与诸位同学共勉之。
该项目的蓝牙控制转向部分仍有优化空间,每次需要手动复位stm32将被转向环影响过的PWM重置。学有余力的同学在现有基础上可以拓展更多的功能。
项目成品展示:
一、硬件层
1.原理图设计
MCU:STM32F103C8T6单片机
外设:MPU6050陀螺仪模块、MP1584EN降压模块(12V转5V)、TB6612驱动模块、JDY-31蓝牙模块、OLED显示模块、HC-SR04超声波模块、JGB37-520霍尔编码器电机
2.系统总体框图
3.PCB电路板设计
嘉立创eda源文件:
链接:https://pan.baidu.com/s/131FcrzkQumy9IszWKIDr6w?pwd=Nice
提取码:Nice
将源文件拿去嘉立创商城下单打印PCB板子,具体步骤可以在网上查到很多,这里就不列举了
4.物料准备
该表格购买链接是置顶视频b站up推荐,我在2024.2.27按清单采购过一批使用,使用过程没有发现太大问题,全套采购价大约在200左右区间。市场价格是浮动的,追求性价比的同学可以根据产品参数多方对比下各家不同店铺。
物料采购补充点:
1.TB6612 驱动模块 网上商城大多是红色款的,红色款钽电容接12V电压可能会过载爆炸,建议买白色兼容版或黑色原版
2.电机驱动 370/520编码电机 都可以,520转速高些价格也稍微贵些,在驱动代码和接线上略微不同,本次项目复刻使用的是520编码电机,如若使用370,可以借助项目源bilibili视频上的电机驱动模块及小车拼装部分进行补充学习
3.亚克力板定制(车体框架)
链接:https://pan.baidu.com/s/1lTdszEW4-E8I-NtPeib7iQ?pwd=Nice
提取码:Nice
网上找一家定制亚克力板店铺,将源文件发给商家即可
4.如果想跳过手动焊接流程,可以在嘉立创下SMT贴片订单,可以得到用机器将元器件焊接在PCB板子上的成品,价格会相对贵些。
如果想体验学习PCB焊接元器件过程,还需要再准备一个手工焊枪+焊锡,以及一个万用表测量PCB电路板通断(非必须只是尽量有,可检测硬件是否存在故障) 遇到不懂的不要怕,一个一个去学就好。
名称 | 描述 | 链接 | 分类 | 数量 | 单价 | 总价 |
---|---|---|---|---|---|---|
DC005 | 电源接口母座 | 【淘宝】https://m.tb.cn/h.5rorkrlIKbSglyF?tk=BFd1WRxZYpB CZ0001 「DC电源插头插座 002/005 3.5-1.1/1.35 5.5-2.1/2.5MM 直流耐高温」 | DC-005 5.5-2.1(耐不耐高温都可以、5.5-2.1和5.5-2.5可以通用) | 1 | 0.04 | 0.04 |
MP1584EN模块 | 降压模块,12V输入5V输出 | 【淘宝】https://m.tb.cn/h.5rcAP2YK2d0VDxL?tk=hz6SWRx1Yjt CZ0000 「3A可调降压模块DC-DC稳压电源 MP1584EN 超小体积 超LM2596」 | 固定输出5V | 1 | 4.29 | 4.29 |
开关 | 【淘宝】https://m.tb.cn/h.5JOt5xTSKSg7v3o?tk=TvPoWRxYogn CZ0001 「SS12D06 SS12D10 5MM柄高 2档3脚 大电流拨动开关 直/弯脚」 | 直脚 | 1 | 0.45 | 0.45 | |
STM32核心板 | STM32F103C8T6单片机 | 【淘宝】https://m.tb.cn/h.5IRPFZ2ruCeS1fW?tk=VWazWRxdX3M CZ0000 「原装正品ARM 核心板 STM32F103C8T6开发板 最小系统板 STM32」 | 1 | 10.7 | 10.7 | |
MPU6050模块 | 陀螺仪模块 | 【淘宝】https://m.tb.cn/h.5rXbXEPeNTCnAsP?tk=kLAzWRxdOGf CZ0001 「【优信电子】MPU-6050模块三轴加速度+三轴陀螺仪 6DOF模块GY-521」 | 1 | 7.7 | 7.7 | |
JDY-31 | 蓝牙模块 | 【淘宝】https://m.tb.cn/h.5rXYQIYcMU5t68I?tk=xmoHWRxdQBv CZ0000 「【优信电子】蓝牙3.0模块 SPP透传 兼容HC-05/06从机 JDY-31」 | 4针 | 1 | 7.8 | 7.8 |
OLED | 显示模块 | 【淘宝】https://m.tb.cn/h.5IRNUMsfpmb3fxY?tk=PjCWWRxWltV CZ0001 「0.91/0.96/1.3寸 OLED显示液晶屏模块 IIC/SPI液晶串口屏」 | 0.96寸白色OLED模块/4P | 1 | 11 | 11 |
HC-SR04 | 超声波模块 | 【淘宝】https://m.tb.cn/h.5rLfmMPOVrmPMs0?tk=Fc6NWRxlJdq CZ0001 「HC-SR04 新版 超声波测距模块 宽电压3-5.5V 工业级 传感器」 | 1 | 4.4 | 4.4 | |
TB6612模块 | 白色兼容版 | 【淘宝】https://m.tb.cn/h.5rLKuB9Dr3PVd1Q?tk=Bf5gWRxC2k0 CZ0001 「TB6612FNG 两路直流电机驱动板模块小体积 高性能超L298N」 | 1 | 5.8 | 5.8 | |
排针 | 【淘宝】https://m.tb.cn/h.5rXhxL65O4xaUzP?tk=vta4WRx96bc CZ0000 「单/双 排针 2.54MM 间距 1*40 2*40P 直针 弯针 贴片 长排针 特殊」 | 单排直针2.54铁 | 1 | 0.04 | 0.04 | |
排母 | 元件座 | 【淘宝】https://m.tb.cn/h.5IREYgy8eDtDNvH?tk=XLxNWRx9PM7 CZ0000 「2.54MM间距 排母 单排母 排针插座 1*2P3P4P5P6P7P8P10P12P--40P」 | 4P | 3 | 0.1 | 0.3 |
排母 | 同上 | 8P | 3 | 0.12 | 0.36 | |
排母 | 同上 | 20P | 2 | 0.2 | 0.4 | |
PH2.0插座 | 电机连接座 | 【淘宝】https://m.tb.cn/h.5Jmfbi7uII1J4JT?tk=vb9HWRxPC8a CZ0000 「PH2.0弯针插座 间距2.0MM 接插件2P/3/4/5/6/7/8/9--13P(10个)」 | 6P | 1 | 0.6 | 0.6 |
PH2.0连接线 | 【淘宝】https://m.tb.cn/h.5JmgsHkaOXn7NEg?tk=EvqCWRxnbXx CZ0000 「PH2.0mm 红白排线 端子线2/3/4/5/6/10-12P 单头/双头 电子连接线」 | 6P双头10cm | 1 | 3.6 | 3.6 | |
同上 | 6P双头20cm | 1 | 3.9 | 3.9 | ||
M3铜柱 | 电路板固定 | 【淘宝】https://m.tb.cn/h.5I8aB8ce8Syqbi5?tk=BbOcWRxMfCb CZ0000 「六角铜柱M3M4M5M6单头铜螺柱机箱主板螺丝柱铜柱隔离柱支柱M2M2.5」 | M3*25+6 | 1 | 1.4 | 1.4 |
M3螺母 | 【淘宝】https://m.tb.cn/h.5JmSZrQ7aPwjgLS?tk=TDWSWRxoKmG CZ0000 「304 316不锈钢六角螺母螺丝螺母螺帽螺丝帽大全M3M4M5M6M8M10M12」 | M3 304材质 | 1 | 1.77 | 1.77 | |
M3螺丝 | 电机架固定 | 【淘宝】https://m.tb.cn/h.5rLRcKIXdrS3aQF?tk=zDuEWRxKkV3 CZ0001 「304不锈钢圆头螺丝盘头十字螺钉圆头机牙螺栓小螺丝M2M3M4M5M6」 | M3*10 | 1 | 2.15 | 2.15 |
M3铜柱 | 亚克力顶板固定 | 【淘宝】https://m.tb.cn/h.5I81kiYm2wzzedQ?tk=beXmWRxqHL3 CZ0001 「六角铜柱M3M4M5M6单头铜螺柱机箱主板螺丝柱铜柱隔离柱支柱M2M2.5」 | M3*60+6 | 1 | 6.5 | 6.5 |
M2.5双通铜柱 | 陀螺仪固定 | 【淘宝】https://m.tb.cn/h.5rXoEpBL2dh9MlP?tk=j12sWRxIFHz CZ0001 「铜柱双通六角铜柱M2M3M4M5M6隔离柱螺母柱空心机箱主板电脑铜螺柱」 | M2.5*11 | 1 | 1.8 | 1.8 |
M2.5尼龙螺丝 | 【淘宝】https://m.tb.cn/h.5rXL714SduGuEhB?tk=EQhKWRxsbhP CZ0001 「M2M2.5M3M4M5塑料螺丝尼龙螺丝圆头十字塑胶螺丝盘头尼龙螺钉螺栓」 | M2.5*4 | 1 | 3.5 | 3.5 | |
电池及充电器 | 【淘宝】https://m.tb.cn/h.5rLMXburm5EVlFE?tk=bz25WRxEPUG CZ0000 「祺索12V锂电池组大容量18650智能小车音响户外电源LED灯充电电池」 | 12V一字形【1500mAh】配1A充电器 | 1 | 26.9 | 26.9 | |
电机 | 370编码电机 | 【淘宝】https://m.tb.cn/h.5I8WS1y0y8f6b4Z?tk=3JMoWRxs817 CZ0001 「25GA370直流减速电机带编码器测速码盘大功率大力矩平衡小车转用」 | 12V280转 | 2 | 25 | 50 |
520编码电机 | 【淘宝】https://m.tb.cn/h.5Jm9WiL0wjUa2bP?tk=gO0jWRxs3Qt CZ0001 「JGB37-520霍尔编码器直流减速电机 四驱平衡智能小车6V12V小马达」 | 12V333转 | 2 | 36.58 | 73.16 | |
扎带 | 固定电池 | 自选,长度20CM就可以,也可以用双面胶替代 | 0 | |||
STM32下载器 | 下载程序用 | 【淘宝】https://m.tb.cn/h.5rIvrpBBjPqmJBG?tk=CgVnW8lccc9 CZ0000 「ST-LINK V2 STM8/STM32仿真器编程器 stlink下载器线烧录器调试器」 | 推荐进口芯片版本 | 1 | 10 | 10 |
总计 | 155.4 |
二、软件层
项目复刻使用的环境是STM32CubeMX+Hal库,先将各模块功能完善,最后整合成项目。各模块驱动代码在此便不赘述了,大家可以针对性查漏补缺,网上现有很多完善的资料了。这里主要分析项目整合过程,理解项目运作的基本原理。以及主要逻辑控制代码展示及PID调参过程。
项目源码:
链接:链接:https://pan.baidu.com/s/1QL8OjVrXFQiRoU-ww8tk_A?pwd=Nice
提取码:Nice
平衡小车开发手册:
链接:https://pan.baidu.com/s/187n7TSUJqfOxWb5DarizDQ?pwd=Nice
提取码:Nice
1.原理概览
平衡车的模型大体是这样
平衡车倾斜时会有一个向前或向后的倾斜力
这时候把轮子向着倾斜的方向 加速度运行,如果加速度正好把倾斜的力抵消,就能达到平衡了
那么要如何控制轮子的速度呢?
通过改变电机的电压值便可以控制电机速度了,也就是输出不同的PWM脉冲波
那这个加速度值需要多少合适,而且不同的倾斜角度需要的加速度值也不同怎么办?
这时候就用到了PID算法,原理如下
速度环控制器(PI):将编码器反馈的真实速度和期望速度偏差 加上真实速度的积分,输出角度值。
直立环控制器(PD):将速度环输出的角度和MPU6050反馈的真实角度偏差 加上真实角度的微分也就是角速度,输出PWM给电机。
主控芯片持续读取数据传给对应控制器,形成闭环控制。
角度值和速度值是哪里得来的呢?
角度值从mpu6050模块来的,mpu6050内置加速度计和陀螺仪,可以获取到三轴的加速度和角速度,通过内部DMP进行姿态解算和原始数据互补融合后,便可以得出X、Y、Z三个方向的角度值,需要留意的是MPU6050测量的Z轴角度值,因为重力加速度固定是Z轴 ,所以只能通过角速度积分获取,这种方法时间一长会出现误差
速度值是从电机上的霍尔编码器来的,PWM也是作用于此控制电机的转速和方向
2.直立环PD控制器
//直立环PD控制器
//输入:期望角度、真实角度、角速度
int Vertical(float Med,float Angle,float gyro_Y)
{
int temp;
temp=Vertical_Kp*(Angle-Med)+Vertical_Kd*gyro_Y;// Kp*(真实速度-期望速度)+Kd*角速度(真实速度微分)
return temp;
}
3.速度环PI控制器
//速度环PI控制器
//输入:期望速度、左编码器、右编码器
int Velocity(int Target,int encoder_L,int encoder_R)
{
static int Err_LowOut_last,Encoder_S;
static float a=0.7; //低通滤波a值 取经验值
int Err,Err_LowOut,temp;
Velocity_Ki=Velocity_Kp/200; //ki取经验值 为 kp/200
//1、计算偏差值
Err=(encoder_L+encoder_R)-Target;
//2、低通滤波(去噪平滑) 公式
Err_LowOut=(1-a)*Err+a*Err_LowOut_last;
Err_LowOut_last=Err_LowOut;
//3、积分
Encoder_S+=Err_LowOut; //编码器积分值等于其自身累加
//4、积分限幅(-20000~20000)
Encoder_S=Encoder_S>20000?20000:(Encoder_S<(-20000)?(-20000):Encoder_S);
if(stop==1)Encoder_S=0,stop=0; //这里是为了配合蓝牙遥控刹车时,积分清零避免刹车仍滑行
//5、速度环计算
temp=Velocity_Kp*Err_LowOut+Velocity_Ki*Encoder_S;//Kp*速度偏差滤波值+Ki*真实速度积分
return temp;
}
4.转向环PD控制器
//转向环PD控制器 用于简单的差速转向原理 这个控制器不算严格意义上的PD控制
//mpu6050无法输出精准的z轴角度值 故用角速度作偏移约束
//输入:角速度、角度值
int Turn(float gyro_Z,int Target_turn)
{
int temp;
temp=Turn_Kp*Target_turn+Turn_Kd*gyro_Z;//Kp当作系数用于放大 Target_turn转向值,Kd*z轴角速度做一个转向约束
return temp;
}
5.PWM控制层
void Control(void) //将这段函数mpu6050通过自带的INT中断口 每隔10ms调用一次
{
int PWM_out;
//1、读取编码器和陀螺仪的数据
Encoder_Left=Read_Speed(&htim2);//从编码器读取左电机速度值
Encoder_Right=-Read_Speed(&htim4);//从编码器读取右电机速度值
mpu_dmp_get_data(&pitch,&roll,&yaw); //从mpu6050读取角度值
MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //从mpu6050读取角速度值
MPU_Get_Accelerometer(&aacx,&aacy,&aacz); //从mpu6050读取加速度值
//2、将数据传入PID控制器,计算输出结果,即左右电机转速值
Velocity_out=Velocity(Target_Speed,Encoder_Left,Encoder_Right);//PI速度环控制器输出角度值
Vertical_out=Vertical(Velocity_out+Med_Angle,roll,gyrox);//PD直立环输出PWM Med_Angle 即机械中值,因为平衡车不是对称的且安装不同会有差异,而且读取的角度值也存在一定偏差,加上平衡时角度偏移量用以修正
PWM_out=Vertical_out;
Turn_out=Turn(gyroz,Target_turn);//PD转向环输出PWM Target_turn可用于蓝牙遥控修改参数转向
MOTO1=PWM_out-Turn_out; //左右电机的PWM 一边减去一边加上 转向环输出的PWM 便形成了差速转向
MOTO2=PWM_out+Turn_out;
Limit(&MOTO1,&MOTO2); //给电机进行了一个限幅 避免过载
Load(MOTO1,MOTO2); //最终PWM驱动电机
}
6.蓝牙控制层
驱动层直接写在hal库的串口中断里面
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
// HAL_UART_Transmit(&huart3,rx_buf,1,1000);
// HAL_UART_Receive_IT(&huart3,rx_buf,1);
Bluetooth_data = rx_buf[0];
if(Bluetooth_data==0x05)front=0,back=0,left=0,right=0;//刹车
else if(Bluetooth_data==0x08)front=1,back=0,left=0,right=0;//前进
else if(Bluetooth_data==0x04)front=0,back=0,left=1,right=0;//左转
else if(Bluetooth_data==0x06)front=0,back=0,left=0,right=1;//右转
else if(Bluetooth_data==0x02)front=0,back=1,left=0,right=0;//后退
else front=0,back=0,left=1,right=0;
HAL_UART_Receive_IT(&huart3,rx_buf,1);
/* USER CODE END USART3_IRQn 1 */
}
在mpu6050中断控制层函数 void Control(void) 里 补充遥控操作代码即可
void Control(void) //将这段函数mpu6050通过自带的INT中断口 每隔10ms调用一次
{
//遥控
//前进后退
if((front==0)&&(back==0))Target_Speed=0;//未接受前进后退指令
if(front==1)
{
if(distance<20) //超声波模块检测前方距离小于20cm,车辆后退
Target_Speed--;
else
Target_Speed++;
}
if(back==1){Target_Speed--;}
Target_Speed=Target_Speed>SPEED_Pitching?SPEED_Pitching:(Target_Speed<(-SPEED_Pitching)?(-SPEED_Pitching):Target_Speed);//限制幅度
//左右转向
if((left==0)&&(right==0))Target_turn=0;
if(left==1)Target_turn+=30;
if(right==1)Target_turn-=30;
Target_turn=Target_turn>SPEED_Pitching?SPEED_Turn:(Target_turn<(-SPEED_Turn)?(-SPEED_Turn):Target_turn);//限制幅度
//转向约束
if((left==0)&&(right==0))Turn_Kd=0.6;//若无转向指令,开启转向偏移约束
else if((left==1)||(right==1))Turn_Kd=0;
}
7.程序框架图
三、平衡车PID调参
首先要了解pid的基本概念,读多几遍就都懂了:
P(比例)控制是:输出量的大小与输入误差信号的大小成比例关系的一种控制。(追求快速性)
I(积分)控制是:输出量的大小与输入误差信号的积分值成比例关系的一种控制,其主要作用是消除系统的误差。(追求准确性)
D(微分)控制是:输出量的大小与输入误差信号的微分值成比例关系的一种控制,其主要作用是:在系统平衡后,若存在干扰信号,D(微分)控制可以让系统在最短的时间内回复到原有的平衡状态(减少振荡)。(追求稳定性)
以该平衡车为例
1.机械中值调参
以本项目为例,先用OLED显示roll值(根据mpu6050安装方向而定来取对应角度值),将平衡车平稳放置,观察记录前倾将要倒地瞬间时roll的值,观察记录后倾将要倒地瞬间时roll的值,可以多试几次,找出相对准确的值。取前后倾roll值相加的平均值,即可作机械中值。
2.直立环Kp调参
参数范围:
该项目PWM占空比100%时电机转速为7200,假设我们希望平衡车在+-10%左右时达到满转状态,即kp取值720。
实际我们不需要这么高转速,也就是说可以在大约0~720之间取值测试。
确定极性:
将速度环和转向环的PID参数注释或置0,Kp取一个正值或负值测试,将平衡车抬起前倾的时候车轮向前极性就对了,反之就错了,这样便确定了正负极性。依次取值测试,建议开始不用那么保守可以从100开始或者直接对半取360,观察小车直到出现低频震荡能保持基本平衡即可。
3.直立环Kd调参
参数范围:
电机满转时为7200,OLED显示陀螺仪原始的角速度值,观察一下最大区间值,大概是在2~3000左右,也就是说可以在大约0~3之间取值测试,不用太精确,预估一个范围值进行测试看实际效果即可。
确定极性:
将速度环和转向环的PID参数注释或置0,Kd取一个正值或负值测试,拿起车子前后倾极性正确轮子会向倾斜同方向快速转一下。
根据参考范围依次取值测试,观察小车出现高频振荡时马上关闭电机,否则有烧坏的可能。
4.速度环Kp及Ki调参
参数范围:
OLED显示左右编码值,相加大概在70~90之间,假设倾斜0~60度时达到满转,60/90≈0.66,Kp估值0~1区间,Ki按经验值取Kp/200
确定极性:
将直立环和转向环的PID参数注释或置0,Kp和Ki同取一个正值或负值测试,向前或向后倾即加速度,极性对了会向同方向加速转一会,极性错了会转的很慢。
5.转向环Kp及Kd调参
参数范围:
这里转向环Kp只是作一个系数,大小决定了转向的快慢,灵活取值即可。Kd通过观察Z轴加速度区间在4位数,可取值0~2之间测试。
确定极性:
将直立环和速度环的PID参数注释或置0,Kp和Kd同取一个正值或负值测试,把车子摁地上旋转,极性正确则感觉有股力阻止旋转,极性错误旋转很顺利。