stm32两轮平衡小车项目详解

摘要
这个项目是在20年11月初开始的,当时的我很迷茫,本应该去实习的我在线上培训,觉得无聊,便有了自己一人做项目的想法。也没想到这个项目做了将近整整一个月,才差不多做了出来。也是准备做两个项目的,这是第一个而已。

项目所需物料清单
主控板用到了c8t6、小车底盘(这个硬件是这项目于最贵的物料了),可以用大鱼电子、或者平衡小车之家的。由于经费的原因,我买了两个带电机的车轮、加上了亚克力板,勉强搭成了小车底盘。我的电机用的是JGA25-370电机。电机线正负是表示动力线1、2。电机线接反可以实现车轮反转的效果。为了布线方便,我用到了面包板。由于对焊接并不是很熟练,没用到洞洞板,这算是这个项目不大光彩的地方。用到的模块有mpu6050、oled(四针)、稳压模块(12V转5V)、JGA25-370电机、电机驱动模块(tb6612fng)、12v锂电池,目前想到的就这些模块。

项目过程中遇到的问题

这个项目历时一个月,过程的艰辛可想而知,也是本人太菜的原因,基础也很差。当时遇到的第一个问题就是稳压模块不知道怎么用,由于没有加上稳压模块,导致电机不转,这个问题困扰了很久,也问了很多人,最终知道了稳压模块是来将12v的电压降为5v的电压来给单片机供电的,虽然没用稳压模块,电机驱动模块并没有烧坏。用了稳压模块,由于不会焊接,就用了面包板代替了洞洞板。这让我也了解了面板板的强大之处。对于我这个小白来说。焊接的技术太差了,会焊接的同学可以忽略,本人计算机专业的,对电烙铁、焊锡并不是很了解。在校也没进实验室。电子、通信、自动化的同学应该带焊接并不陌生的。第一个问题花了很长一段时间的。
由于用到了洞洞板,接线就方便了许多。接着遇到的问题就是PID调节了。这个PID是真的难调。我们知道,虽说平衡小车是三闭环控制系统。但是仅仅直立环也是可以平衡的,只是不够精确罢了。直立环加速度环是完全可以平衡的,可以不用转向环的。

机械中值的确定
每个物体都有属于自己的机械中值,机械中值是调节PID的第一步,要想小车平衡性能非常好,首先必须得调节机械中值。之前也有人说过,要想小车能平衡,首先要让小车有一个短暂的平衡,不能一落地小车就倒。接着我们来谈谈如何来确定小车的机械中值。将小车的mpu6050测试代码烧录到主控,将小车放置地上顺时针转动,直至倒下,记下小车的角度。接着将小车逆时针转动,直至倒下,记下小车的角度。将两次角度的值相加,除以2,此时这个值就是小车的机械中值。确定好机械中值,就可以来调节速度环、直立环了。

PD(直立环)调节
我目前做的平衡小车v1.0版本,功能还有PID调节并不是很完善,目前小车只用到了直立环,根据我的调节,光直立环是可以平衡的。在调节直立环的时候,速度环PI中的kp、ki是必须置零的。首先判断直立环kp的极性,令kp=+1,kd=0;烧录程序,若小车向前倾,车轮向前加速,则说明极性正确,反之,则说明极性错误,令kp=-1。若小车两轮转动方向不一致,则说明硬件电机正负极接反了,需对调一下。kp极性判断完毕,接下来调节Kp的大小,令kd=0,不断增加kp,直至小车出现高频幅度震荡,调节kp不断消除震荡,持续增加,直至小车出现高频震荡,此时直立环调节完毕,由于kp、kd系数取的都是最大值,需要将系数乘以0.6,则是最平稳的。这是PD(直立环)调节。

PI(速度环)调节
在调节速度环PI的过程中,直立环的kp、kd是不需要置零的,首先也是判断极性,令kp=+1,烧录代码,用手向前转动一侧车轮,若两侧车轮同时向前加速,则kp极性正确,反之,则极性不正确,kp=-1。若kp极性判断正确,则可以通过调节Kp、Ki来让小车达到平衡。

程序讲解
mpu6050模块只用了五个引脚,分别是VCC、GND、SCL、SDA、INT,用到了IIC,引脚INT有相应的电平输出,依次可以触发外部中断作为控制周期,周期性反馈数据,保持mpu6050 数据的实时性。

/**************************************************************************
函数功能:外部中断初始化
入口参数:无
返回  值:无 
作    用:是用来配置MPU6050引脚INT的,每当MPU6050有数据输出时,引脚INT有相应的电平输出。
					依次来触发外部中断作为控制周期。保持MPU6050数据的实时性。
**************************************************************************/
void MPU6050_EXTI_Init(void)
{  
		GPIO_InitTypeDef GPIO_InitStructure;
		EXTI_InitTypeDef EXTI_InitStructure;
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	            //端口配置
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;         //上拉输入
		GPIO_Init(GPIOB, &GPIO_InitStructure);					      //根据设定参数初始化GPIOB 
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource5);
  	EXTI_InitStructure.EXTI_Line=EXTI_Line5;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 	//根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器
}

编码器通过定时器输入捕获脉冲数,来测速的。定时器中断和外部中断一直不是很理解,今天经过别人指导,豁然开朗。定时器中断是通过定时器的重转载值,分频系数以及计数模式等设置,然后定义它的中断触发方式而产生的中断,一般溢出中断比较多。编码器encode采用的就是定时器中断。外部中断则是通过定义管脚的电平状态,通过外部的电平来触发它产生的中断。mpu6050 INT引脚触发就是外部中断。

**************************************************************************
函数功能:单位时间读取编码器计数
入口参数:定时器
返回  值:速度值
**************************************************************************/
int Read_Encoder(u8 TIMX)
{
    int Encoder_TIM;    
   switch(TIMX)
	 {
	   case 2:  Encoder_TIM= (short)TIM2 -> CNT;  TIM2 -> CNT=0;break;
		 case 3:  Encoder_TIM= (short)TIM3 -> CNT;  TIM3 -> CNT=0;break;	
		 case 4:  Encoder_TIM= (short)TIM4 -> CNT;  TIM4 -> CNT=0;break;	
		 default: Encoder_TIM=0;
	 }
		return Encoder_TIM;
}

控制代码如下:直立环PD控制、速度环PI控制

KP、KD、KP、KI系数、机械中值

int Balance_Pwm,Velocity_Pwm,Turn_Pwm;

float Mechanical_angle=0; // 无超声波、电池平躺着的小车机械中值

float balance_UP_KP=1000; 	 // 小车直立环KP(第一次kp调1000 、参数乘以0.6       1000    //600
float balance_UP_KD=-1.2;              //-1.2                                    -1.2                          //-1.08
float velocity_KP=0;      // 1.0
float velocity_KI=0;    //0.005

PD控制


/**************************************************************************
函数功能:直立PD控制
入口参数:角度、机械平衡角度(机械中值)、角速度
返回  值:直立控制PWM
**************************************************************************/
int balance_UP(float Angle,float Mechanical_balance,float Gyro)
{  
   float Bias;
	 int balance;
	 Bias=Angle-Mechanical_balance;    							 //===求出平衡的角度中值和机械相关
	 balance=balance_UP_KP*Bias+balance_UP_KD*Gyro;  //===计算平衡控制的电机PWM  PD控制   kp是P系数 kd是D系数 
	 return balance;
}

附平衡小车图、资料及代码:

链接:https://pan.baidu.com/s/1VlaNkVwey1i6BrMO0dQ-tw
提取码:s7k1

本人qq:1050497845
乐于解答相关问题,欢迎深入技术探讨

stm32平衡小车演示视频

你可能感兴趣的:(单片机,嵌入式,stm32)