STM32自平衡小车

前言

平衡小车制作前前后后也半个多月了,在这段时间里真的很难熬,几经想要放弃,但是还好,最后完成了,演示视频链接,代码链接放在了文章最后,希望大家多多支持



一、踩坑之路

1.固件库转hal库的无从下手

刚接触hal库看似很简单,其实有很多问题,因为配置问题,我曾把stm32f103c8t6芯片给锁住了,还以为芯片坏了,最后找到一些博客文章才解决完

2.mpu6050

初次使用这个模块,很陌生,在网上找到了很多文章,才开始敲代码,起初mpu6050无法初始化,程序卡死,后来程序只可以在主循环使用,不可以使用INT引脚外部中断精准定时,至今没有解决,最后使用定时器就10ms精准定时

3.电机驱动选择

开始使用TB6612电机驱动,但是不知道电路的哪里问题,导致芯片烧毁,现在都已经产生阴影了,后又选择a4950,PCB板子也是根据这个设计,但是因为使用a4950模块每个轮子PWM死区都不一样,不易调PID,最后确定L298N为电机驱动模块

4.电源管理

设计PCB时使用的a4950考虑到5V输入,就适用了12-5v降压模块,后又考虑stm32供电为3.3v电压,无奈在PCB又加了一个5-3.3V降压模块

5.PCB设计

没有考虑到OLED的位置,a4950的引脚方向是相反方向,mpu6050的位置没有固定容易松动,影响角度,好的一点是,我把没有用到的引脚引了出来,给我后来改变方案带来了极大的便利。

二、模块选取

1.带编码器的减速电机及周边相关
2.主控芯片STMF103C8T6
3.IIC接口OLED
4.MPU6050–姿态传感器
5.HC05蓝牙模块
6.12转5V,5转3.3V降压模块
7.ADC电源模块
8.12V电源

三、各个调试部分的主要代码

1.MPU6050

初始化

  MX_GPIO_Init();
  MX_USART2_UART_Init();
  MX_TIM3_Init(); 
  printf("init=%d\r\n",mpu_dmp_init());
  while(mpu_dmp_init());		//dmp初始化
  printf("OK!\r\n");
  HAL_TIM_Base_Start_IT(&htim3);//每10ms触发一次中断

定时器中断测试

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM3)//进入中断
	{
		mpu_dmp_get_data(&OutMpu.pitch, &OutMpu.roll, &OutMpu.yaw);
		MPU_Get_Accelerometer(&OutMpu.aacx,&OutMpu.aacy, &OutMpu.aacz);		//加速度传感器数据
	    MPU_Get_Gyroscope(&OutMpu.gyrox, &OutMpu.gyroy, &OutMpu.gyroz);		//得到陀螺仪数据
		OutMpu.temp=MPU_Get_Temperature();						//得到温度信息
	}
}

2.编码器电机

初始化

void TIM_Init(void)
{
	//定时器1 PWW
	//2 编码器
	//3 中段
	//4 编码器B
	HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);//PWM 10kZ 7199
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);	
	
	HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_1);//编码器 
	HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_2);
	
	HAL_TIM_Base_Start_IT(&htim3);//每10ms触发一次中断  
	
	HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_1);
	HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_2);	
	
	
}//死区4230;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance ==TIM3)
	{
		Rcnt = Read_Speed(2);//右轮
		Lcnt = -Read_Speed(4);
		if(dir == 1)
		PWM++;
		else 
		PWM--;
		Set_Pwm(PWM,PWM);//zuo you
	}
}

3.蓝牙通信

中断接收

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance==USART2)
	{
		abc=HAL_UART_Receive_IT(&huart2,UART_Receive_buffer, 1);
		if(UART_Receive_buffer[0]=='A')
		{
		printf("\r\nYou send data : %d\n",UART_Receive_buffer[0]);
		}
		else 
		printf("\r\ntest");
		HAL_UART_Transmit(&huart2,UART_Receive_buffer,1,0xffff);
	}
}

四、PID调参

1.直立环

比例系数KP的确定

  1. 使微分系数KD参数置零
  2. 随便选则一个数,判断电机旋转极性,确定小车向前倾,车轮向前转
  3. 计算电机PWM驱动死区,例如我的小车死区是4000,PWM最大值为7200,假设俯仰角为10度,则(7200-4000)/10=320,那么我的KP范围为0-320
  4. 取中间值KP,调整参数,直到小车可以平衡一段时间,此时Kp就确定了

微分系数KD的确定

  1. 同样的方法,使比例系数KP参数置零
  2. 判断极性
  3. 计算KD范围
  4. 调参,使小车可以平衡一段时间

最后KP,KD同时控制PWM,参数*0.6,就是最后的KP,KD

2.速度环

比例系数KP的确定

  1. 极性的确定,关闭直立环的影响,随意设定一个KP值,KI等于KP/200,转动一个轮子,另一个轮子 也向同一方向转动,极性正确
  2. 计算KP范围KP=(7200-4000)/(160*40%)=50,及KP范围(0-50)
  3. 取中间值,打开直立环的作用,根据小车状态改变参数

积分系数KI的确定

1.KI等于KP/200

3.转向环

比例系数KP的确定

1.根据死区计算的PWM上升空间最大值为3200,那么两个轮子及各为1600的转向PWM空间
2.根据目标角度,偏转角度,Turn=-Turn_TargetPID.Turn_KP-gyroPID.Turn_KD;即可算的范围

微分系数KD的确定

1.Kd = Kp/100;

五、引脚连接

1.初版PCB

电机驱动模块最终修改为了L298N。
在这里插入图片描述

在这里插入图片描述

总结

平衡小车的制作,前期是真的很难熬的,一旦你坚持完成了,你会发现原来好像也没什么,非常感谢CSDN开源博主的资源,实验室学长的支持,B站资源,代码整理后会开源放在这里,希望对大家有所帮助,也希望大家可以帮助更多的人。
百度网盘代码
链接:https://pan.baidu.com/s/11l6evi1tm7rRGBleDvpYqw
提取码:nwei
csdn资源内容和网盘一模一样的

  • 7
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
一、平衡小车原理: 自平衡小车是利用车模自身动力使小车保持相对的平衡,是一个动态平衡的过程。维持车模平衡的动力来自车轮的运动,由两个直流电机驱动。对车模的控制可以分解为三个控制任务: 1、控制小车平衡:通过控制小车车轮正反转使小车保持直立平衡。 2、控制小车速度:通过控制小车的倾角实现小车前后运动和速度的控制,其实最终的仍是通过控制电机的转速实现。 3、控制小车方向:通过控制小车两个电机之间的转速差来实现转向控制。 分解为三个控制任务显得相对简单一点,但是在最终的控制过程中都归结为对一个控制量的控制,这样三个任务之间就会存在耦合,会相互干扰。三个任务中控制平衡是关键,所以对小车的速度和方向控制应该尽量的平滑。 二、硬件方案设计 小车的硬件分为三个部分,分别是主控部分、小车姿态获取部分以及电机驱动部分。主控板采用目前常用的arduino UNO,同时也可以使用其他arduino通用控制板做主控。 小车姿态获取可以有很多方案,使用最多的就是通过加速度计和陀螺仪获取小车姿态。理论上只需要两轴加速度计(垂直方向Z轴和沿小车运动方向X轴)和一个单轴陀螺仪(沿小车车轮轴方向,获取绕小车轮轴的角速度)。陀螺仪通过角度积分可以获得小车角度,但是经过积分会产生累计误差,并且会越来越大,X轴与Z轴加速度计的值也可以算出小车的倾角,但是加速度计的瞬时误差较大,所以结合陀螺仪和加速度计两者获得的角度做数据融合可得真实角度。我们使用一个集成了三轴加速度计和三轴陀螺仪的集成芯片MPU6050,这样极大的简化了我们的传感器电路。 小车通过两个直流电机驱动车轮运动来获得动力,直流电机的驱动电路设计关系到整个系统的稳定性,因为电机反转时会产生反向电动势会干扰到电源系统内其他设备的运行。我们选用L298P做电机驱动器,它内部包含4通道逻辑驱动电路,可同时驱动两个直流电机,输出电流可达2.5A。 三、软件设计之小车姿态获取---卡尔曼滤波 在开始之前应该对MPU6050进行设置,主要设置角速度以及加速度的量程,加速度量程有±2g、±4g±8g与±16g,角速度量程分别为±250、±500、±1000与±2000°/sec (dps),可准确的追踪快速动作与慢速动作。在使用之前先设置好量程以便后面的换算。我们小车轮轴与传感器Y轴平行,即绕Y轴旋转则有: 那竖直方向弧度计算公式为: angle = atan2(x, z) //结果以弧度表示并介于 -pi 到 pi 之间(不包括 -pi) 如果要换算成具体角度: angle = atan2(x, z) *(180/3.14) 陀螺仪获取角速度积分得到角度公式为:anglen = anglen-1 + gyronn*dt ,式中anglen 为第N次采样的角度值,anglen-1 为第N-1次的角度值,gyronn为两次采样值之间的角速度值,dt为两次采样之间的时间。然后将换算后的两个角度数据进行卡尔曼滤波融合,可获得小车真实角度,也可以采用更简单的互补滤波算法。 注意加速度计所得角度与陀螺仪积分角度的方向。 四、软件设计之小车姿态调整---PID参数整定 小车的姿态获取最终结果是一个角度,就是小车偏离平衡位置的倾角。通过以小车的这个倾角为变量进行PID控制,输出用于控制车轮转速的PWM值,那么相当于小车只有一个角度反馈环路,虽然能使小车平衡,但是增加了控制难度,所以通常会使用带测速的电机,再加入一个小车速度反馈环路,这样使得小车更容易控制。关于PID的有下面一个简单易懂的描述: 假设我们想把一个小球稳定在一个光滑的坡顶,这显然是一个不平衡的系统,稍有扰动小球就会滚下来。假设恰好平衡的位置坐标是L,我们可以测量到小球的位置是x,那么怎么给小球施加f(x)的力反馈,让它能够平衡呢? 最直观的想法就是f(x) =Kp*(L-x),简单的说就是你在左边我就向右推,你在右边我就向左推,这就是比例因子P; 现在考虑两种情况,同样是在x位置,小球静止和小球具有速度V这两种情况。很明显,如果V>0,我们只需要施加更小的力,因为小球自身的惯性会让它运动向平衡位置。所以可以修正f(x) = Kp*(L-x) – Kd*V。因为速度一般不容易测量,我们常常用位置的变化Δx除以测量的时间差Δt来计算速度,所以这就是微分因子D; 情况继续发生变化,上面考虑的是斜坡静止的情况,如果这个变态的斜坡是移动的怎么办呢?(例如两轮平衡机器人实际上是可以运动的,对于静止的磁悬浮来说,不需要考虑这个参数)这时候我们需要不断的累加并平均x值,来计算平衡位置的L,这个就是积分因子I; 当PID用在我们自平衡小车中时,我们使用角度PD环与速度PI环进行控制。 pwm=angle*k1+angle_dot*k2+range*k3+wheel_speed*k4; PID参数整定步奏如下: 1、将k1,k2,k3,k4均设为0; 2、逐步增大k1,使得小车刚好能够来回摆动。 3、再逐步增大k2,使得小车相对平稳,太大会使小车发生抖动; 4、增大k3,使得小车能够来回走动(不是摆动也不是抖动); 5、增大k4,使得小车能稳定自平衡。 具体参数调整过程比较繁琐,需要自己体会每个参数的作用。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值