这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » tensl------自平衡小车---PID角度环平衡了,纯理论推导还没有细调

共14条 1/2 1 2 跳转至

tensl------自平衡小车---PID角度环平衡了,纯理论推导还没有细调

高工
2015-05-31 16:35:12     打赏

好久没在论坛发帖了,不过还是时而关注EEPW论坛的,这周不算忙,花了一周时间大概搭了一辆小车,和大家一起交流学习,现在的工作画图写代码的机会越来越少了,怕时间久了都忘了!

顺便说一下,标题,贫民指的用的减速电机两块钱一个,贵族是编码器,14位的精度,分辨率0.0219°,之前做个项目用的也是这个芯片,160个这个编码器,用了片选,级联,加复用等手段才搞定%

目录

一、小车主体搭建*******************02楼

二、电路板画板打样*****************03楼

三、小车整体样子*******************04楼

四、小车原理图*********************11楼

五、编码器测试************************13楼

六、倾角计算分析******************16楼

七、PID之角度环粗调****************24楼


搜索

复制




关键词: 自平衡     MPU6050     磁旋转编码器    

高工
2015-05-31 16:52:37     打赏
2楼
小车主体,采用环氧树脂板加工的,电机采用玩具减速电机,某宝一大堆,两块多一个,轮子65mm的橡胶轮胎,都是很久以前玩的东西,电路板自己打样的,传感器也是用的6050,速度编码器采用的MZ48,芯片应该是As5048,14位精度,可以分辨0.0219°,其他的就是有什么用什么了;


轮子,电机,编码器

把这几个组装好了的样子!

还差一边组装;

侧面照;

正面照;

减速电机,不知道力矩够不够,小车重量不轻;

马上车架就要好了;

整车底照;


整车上面照;

搜索

复制


高工
2015-05-31 17:25:57     打赏
3楼

先传一张图片的原理图,回头在整理资料上传把!!!

PCB图

打样回来焊了一块:

搜索

复制


高工
2015-05-31 17:34:19     打赏
4楼

四楼继续占座!!!

来个组装好的整体照:

就差电池了,下周应该能到,我选个8.4V的锂电池,之前一直常买的,这次供应商送的!


搜索

复制


高工
2015-05-31 17:39:53     打赏
5楼

这周末正好在家,边玩了会游戏,边看着电影,把底层程序基本都写好了,调试各个模块时,发现MZ48编码器有一个有问题读不上数来,搞的心情全没了,回头再去找人要一个去;

下周不出差的话继续更新,一直占座,

哦,对了屏的程序还没写好Q!

搜索

复制


高工
2015-06-01 13:05:29     打赏
6楼
中午有点时间把原理图先上传一下吧!——回复可见内容——

搜索

复制


高工
2015-06-02 12:49:42     打赏
7楼

昨天换了一个MZ48,回去测试了一下,编码器OK了,采回来的数据比较稳定,应该能保证0.05°,主要由于自己做的车架固定的传感器安装精度不太高;

下面是采的数据:

编码器数据还可以,电源用的Tplink的适配器电压不是很稳定

板子上设计了四个灯,全闪是待机,点一下按键全灭进入平衡状态,单个等常亮是表示方向,两个灯亮是原地转圈


下面插一下主要代码:

主程序-测试版

s16 Gyro_x,Gyro_y,Gyro_z;
	u8 i;
	u16 Voltage = 0;
	Init_All();													//³õʼ»¯ËùÓÐÓ²¼þ
	while(1)
	{
		Voltage = 0.4032 * Get_Adc();			//µç³Øµçѹ£¨µ¥Î»0.01V£© 
		SPI1_CS = 0;
		for(i=0;i<SPI_Mz48;i++)
		{
			Mz48[i] = (SPI1_ReadWriteByte(0xFFFF) & 0x3FFF);	
			delay_us(1);
		}	
		SPI1_CS = 1;		
		printf("\n MZ48_1Êý¾Ý£º%d  MZ48_2Êý¾Ý£º%d  µç³Øµçѹ£º%d \n",Mz48[0],Mz48[1],Voltage);			// Ïò´®¿Ú´òÓ¡
//	/*
//		Gyro_x=getGyroX();  	   //XÖáÊý¾Ý
//		Gyro_y=getGyroY();  	   //YÖáÊý¾Ý
//		Gyro_z=getGyroZ();  	   //ZÖáÊý¾Ý
//	*/
//		Gyro_x=getAccX();  	   //XÖáÊý¾Ý
//		Gyro_y=getAccY();  	   //YÖáÊý¾Ý
//		Gyro_z=getAccZ();  	   //ZÖáÊý¾Ý
////		printf("\n xÖáÊý¾Ý£º%d  yÖáÊý¾Ý£º%d  zÖáÊý¾Ý£º%d \n",Gyro_x,Gyro_y,Gyro_z);			   		// Ïò´®¿Ú´òÓ¡	
		KEY_Scan();
		if(Mini_Balance)
		{
			LED1 = 1;
			LED2 = 1;
			LED3 = 1;
			LED4 = 1;
		}
		else
		{
			LED1 = ~LED1;
			LED2 = ~LED2;
			LED3 = ~LED3;
			LED4 = ~LED4;
		}
		delay_ms(500);		//ÉÔ×÷ÑÓʱ
	}	

 



SPI初始化:

 	//SPI1¿Ú³õʼ»¯,·ÃÎÊMZ48
	RCC_APB2PeriphClockCmd(	RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_SPI1, ENABLE );	
	/* Configure SPI1 pins: SCK, MISO and MOSI */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  	//¸´ÓÃÍÆÍìÊä³ö
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	/* Configure I/O for MZ48 Chip select */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;  			//SPI1_CS
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  	//¸´ÓÃÍÆÍìÊä³ö
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	GPIO_SetBits(GPIOA,GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

	/* SPI1 configuration */
	SPI_Cmd(SPI1, DISABLE);
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  	//ÉèÖÃSPIµ¥Ïò»òÕßË«ÏòµÄÊý¾Ýģʽ:SPIÉèÖÃΪ˫ÏßË«ÏòÈ«Ë«¹¤
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//ÉèÖÃSPI¹¤×÷ģʽ:ÉèÖÃΪÖ÷SPI
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;	//ÉèÖÃSPIµÄÊý¾Ý´óС:SPI·¢ËͽÓÊÕ16λ֡½á¹¹
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;			//Ñ¡ÔñÁË´®ÐÐʱÖÓµÄÎÈ̬:ʱÖÓÐü¿ÕµÍ
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;		//Êý¾Ý²¶»ñÓÚµÚ¶þ¸öʱÖÓÑØ£¿£¿£¿£¨SPI_CPHA_1Edge£©
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;			//NSSÐźÅÓÉÓ²¼þ£¨NSS¹Ü½Å£©»¹ÊÇÈí¼þ£¨Ê¹ÓÃSSI룩¹ÜÀí:ÄÚ²¿NSSÐźÅÓÐSSIλ¿ØÖÆ
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;		//¶¨Ò岨ÌØÂÊÔ¤·ÖƵµÄÖµ:²¨ÌØÂÊÔ¤·ÖƵֵΪ2¼´@72MHzʱΪ36M
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//Ö¸¶¨Êý¾Ý´«Êä´ÓMSBλ»¹ÊÇLSBλ¿ªÊ¼:Êý¾Ý´«Êä´ÓMSBλ¿ªÊ¼
	SPI_InitStructure.SPI_CRCPolynomial = 7;			//CRCÖµ¼ÆËãµÄ¶àÏîʽ
	SPI_Init(SPI1, &SPI_InitStructure);  				//¸ù¾ÝSPI_InitStructÖÐÖ¸¶¨µÄ²ÎÊý³õʼ»¯ÍâÉèSPIx¼Ä´æÆ÷
	/* Enable SPI1  */
	SPI_Cmd(SPI1, ENABLE); 								//ʹÄÜSPIÍâÉè

搜索

复制


高工
2015-06-03 23:10:01     打赏
8楼

晚上睡觉前简单测了一下倾角的滤波融合,加速度不好控制,测试的效果一般,没感觉出不同滤波的差别:

我的代码注视部分贴上去老是乱码呢!

//*********************************************************
// 倾角计算
//*********************************************************
void Angle_Calcu(void)	 
{
	float Accel_x;	     		// X轴加速度值暂存 
	float Accel_z;	     		// Z轴加速度值暂存
	float Angle_ax;      		// 由加速度计算的倾斜角度
	float K,A,x1,x2,y1;
	float Vs[4];	
	//------加速度--------------------------

	Accel_x  = getAccX();	  																// 读取X轴加速度
	Accel_z  = getAccZ();	  																// 读取Z轴加速度	
	Angle_ax = atan((Accel_x * 1.0f) / (Accel_z * 1.0f)); 			// 去除零点偏移,计算得到角度(弧度)反正切  
	Angle_ax = (Angle_ax * 180 ) / 3.14 ;   								// 弧度转换为度
	Vs[0] = Angle_ax;
	//-------角速度-------------------------

	//范围为2000deg/s时,换算关系:16.4 LSB/(deg/s)

	Gyro_y = getGyroY();	      					//静止时角速度Y轴输出为-1左右
	Gyro_y = -(Gyro_y + 1)/16.4;         	//去除零点偏移,计算角速度值,负号为方向处理 


	//-------卡尔曼滤波融合-----------------------

	Kalman_Filter(Angle_ax,Gyro_y);       //卡尔曼滤波计算倾角
	Vs[1] = Angle;

	//-------一阶互补滤波-----------------------	
	K = 0.075;                          //对加速度计取值的权重
	A = K / (K + dt);
	Angle = A * (Angle + Gyro_y * dt) + (1-A) * Angle_ax;
	Vs[2] = Angle;

	//-------二阶互补滤波-----------------------		
	K = 0.5;
	x1 = (Angle_ax - Angle) * K * K;
	y1 = y1 + x1 * dt;
	x2 = y1 + 2 * K *(Angle_ax - Angle) + Gyro_y;
	Angle = Angle + x2 * dt;
	Vs[3] = Angle;
	printf("%f \t %f \t %f \t %f \t %f \n",Gyro_y,Vs[0],Vs[1],Vs[2],Vs[3]);			// 向串口打印

}

搜索

复制


高工
2015-06-03 23:12:14     打赏
9楼
果然是编译环境的问题,贴代码老是乱码可能是keil版本的事!!!

搜索

复制


高工
2015-06-09 23:00:25     打赏
10楼

今天发现一奇怪现象供电不足,导致系统全部复位,之后MPU6050一直不能工作了,断电重新上电控制板也不行,然后重新下载了一次程序又可以工作了,反复试了好多次都是这样的,求解释,谢谢了

补充供电不足是由于我用的路由器的9V适配器,输出0.6A,带两电机导致功率不够。

搜索

复制


共14条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]