这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » xxJian智能车DIY进程贴

共34条 2/4 1 2 3 4 跳转至
菜鸟
2015-05-26 13:30:01     打赏
11楼

[开发进程]实验三、通过Usart1显示小车角度、左右编码器、电池电压并分析

第一次接触平衡车,对控制电机方面是小白。借着活动举办方分享的全套代码,熟悉一下通过传感器进行单片机采样的几个重要的代码,其中分别是通过MPU6050得到的MCU主板的角度、通过编码器采集得到的电机转动速度、通过电阻分压得到的电池电压。其中前三个参数在控制小车的平衡中必不可少,而采集电池电压的作用主要是为了实时检测电池电压、有助于避免电池过放电。

好了,这次的实验所需要的实验材料是:EEPW平衡小车标配x1PL2302模块x1,还有可以使用串口的win7电脑及其所需软件分别是串口调试助手&VisualScope

主要原理说明

首先对比一下,VisualScope.exe(下文简称“VS.exe”)和上位机波形显(请在win7下以管理员的身份运行,不支持WIN8)示.exe(下文简称“上.exe”)的不同,当然只是个人理解而已!

1、 数据的通道数VS.exe最多支持4通道、而上.exe最多支持10通道。

2、 数据可靠性与快速型:VS.exe支持Check SumCRC16进行对数据的检验,而上.exe暂时没发现。因此不校验的上.exe是比较快速的显示波形的。

3、 界面的友好程度VS.exe支持Stretch功能,可以用鼠标将波形分别沿X轴和Y轴的放大。同时支持Move功能,将波形随意上下左右的平移。上.exe笔者接触了半天,没找到移动波形的方法。

也是第三个的区别,同时还不排除个人的偏见,让我偏爱VisualScope这款软件。

实验步骤:

在前面我已经介绍过VisualScope的使用(见本贴2楼) ,这次就直接放出代码。注意我改的工程是:Mini Balance V2.5 标准版源码(集成DMP 卡尔曼滤波 互补滤波)

首先在main.c初始化Flag_Show定义的地方,将该参数初始化为0

u8 Flag_Stop=1,Flag_Show=0;


然后,在show.c源文件中,将第64行以后的代码删除掉,改为下面的代码:

//=-----------------------------------------------------------------------
//this is xxJian code 1		
    unsigned short CRC_CHECK(unsigned char *Buf, unsigned char CRC_CNT)
    {
        unsigned short CRC_Temp;
        unsigned char i,j;
        CRC_Temp = 0xffff;

        for (i=0;i<CRC_CNT; i++){      
            CRC_Temp ^= Buf[i];
            for (j=0;j<8;j++) {
                if (CRC_Temp & 0x01)
                    CRC_Temp = (CRC_Temp >>1 ) ^ 0xa001;
                else
                    CRC_Temp = CRC_Temp >> 1;
            }
        }
        return(CRC_Temp);
    }
void VisualScope_Output(float data1 ,float data2 ,float data3 ,float data4)
{
		int temp[4] = {0};
		unsigned int temp1[4] = {0};
		uint8_t databuf[10] = {0};
		unsigned char i;
		unsigned short CRC16 = 0;

		temp[0] = (int)data1;
		temp[1] = (int)data2;
		temp[2] = (int)data3;
		temp[3] = (int)data4;

		temp1[0] = (unsigned int)temp[0] ;
		temp1[1] = (unsigned int)temp[1];
		temp1[2] = (unsigned int)temp[2];
		temp1[3] = (unsigned int)temp[3];
  
		for(i=0;i<4;i++) 
		{ 
			databuf[i*2] = (unsigned char)(temp1[i]%256); 
			databuf[i*2+1] = (unsigned char)(temp1[i]/256); 
		} 
		CRC16 = CRC_CHECK(databuf,8); 
		databuf[8] = CRC16%256; 
		databuf[9] = CRC16/256; 		
		for( i = 0 ; i < 10; i++) 
		{ 
			while((USART1->SR&0X40)==0);  
			USART1->DR = databuf[i]; 
		}
}
		//end of xxJian code 1	
//------------------------------------------------------------------------


void DataScope(void)
{   
//=-----------------------------------------------------------------------
	//this is xxJian code 2
		float Volt;
		Volt = Voltage/100;
		//end of xxJian code 2
//-----------------------------------------------------------------------------	

	  if(++Count==1)
		{	
		OLED_Clear();  
		OLED_Display_Off();		
		}	
		
//=-----------------------------------------------------------------------
                //this is the official source code		
		/*
		DataScope_Get_Channel_Data( Angle_Balance, 1 );
		DataScope_Get_Channel_Data( Encoder_Right, 2 );
		DataScope_Get_Channel_Data( Encoder_Left, 3 ); 
		DataScope_Get_Channel_Data( Voltage , 4 );   
		DataScope_Get_Channel_Data(0, 5 ); 
		DataScope_Get_Channel_Data(0 , 6 );
		DataScope_Get_Channel_Data(0, 7 );
		DataScope_Get_Channel_Data( 0, 8 ); 
		DataScope_Get_Channel_Data(0, 9 );  
		DataScope_Get_Channel_Data( 0 , 10);
		Send_Count = DataScope_Data_Generate(10);
		for( i = 0 ; i < Send_Count; i++) { while((USART1->SR&0X40)==0);  
		USART1->DR = DataScope_OutPut_Buffer[i]; 
		}
		*/
		//end of official source code 
//-----------------------------------------------------------------------------	

//=-----------------------------------------------------------------------
	//this is xxJian code 3
		VisualScope_Output(Angle_Balance,Encoder_Right,Encoder_Left,Volt);

		//end of xxJian code 3
//-----------------------------------------------------------------------------	
		delay_ms(50); //20HZ
}

 


值得注意的地方就是,int voltage这个参数,其实是实际的电压值乘以100。 也就是假如电池电压是12.50V,这个int voltage的值就是1250(不考虑误差)


经过在keil上编译,用串口下载的方法,将程序下载到STM32C8内。详细用串口下载的过程请看

STM32使用MCUISP下载程序教程http://forum.eepw.com.cn/thread/273193/1


实验结果

下载程序后,运行,要通过拨码开关将boot0置到on的位置。串口连接好,pl2302模块接到电脑上。打开VIsualScope将串口配置好,并点run.

然后就可以改变平衡小车的状态,观看通过传感器采集得到的数据的变化!





谢谢你的观看!如果有问题,可以留言,也可以QQ上联系!另外软件我已经放到群共享了。有需要请自行下载!


菜鸟
2015-05-26 14:36:48     打赏
12楼
[开发进程]实验四、通过蓝牙通信显示传感器数据并分析

实验三完成了传感器数据通过串口(USART1+PL2302模块)发送到电脑上,电脑使用上位机软件显示了数据的变化波形。本实验使用的是蓝牙通信将数据发送到电脑。

硬件需要:台式机电脑+蓝牙主模块(或者使用带有蓝牙2的手提电脑)。笔者使用的是台式机+前文的蓝牙控制器(单片机+蓝牙串口BC04-B)。在这个实验中,蓝牙控制器的功能只是接收到数据,并将数据通道串口发送到电脑上面。

软件代码:代码跟实验3的大致相同,唯一不同的地方就是show.c里面的USART1改为USART3。初始化在工程里面已经完成,将USART1改为USART3,说明使用的是连接蓝牙模块的USART3发送数据。

实验结果(意外)

在图中,就可以看到车子并不能边行走变将数据发送到蓝牙中。

图片中从左到右指示的是时间。图中的波形表示数据随着时间而发生变化。

波形表明,在Flag_stop =1 时候,车子是可以正常顺利的将数据通过蓝牙发送到电脑中,但是使用这工程代码,想在车子达到平衡的过程中通过蓝牙发送数据,就不是那么简单了,需要修改代码。

大概代码还需要进一步的优化



//----------------------------------------------------------------------------------------------------

//以下2015/5/26  15:05更新

//-----------------------------------------------------------------------------------------------------


//电机关闭后或者没有使用DMP时,开启上位机监控

这一行注释让我想到:这个故障会不会是滤波算法造成的。。。我没学这几个算法,总之先试试了


main.c改了一下滤波算法,以及在死循环内加上几行代码,让其在电机运行时候再进行蓝牙传输传感器数据。

u8 Way_Angle=2;

...

...

while(1)
{
...

//-------------------------------------------------------------------------

//这几行没有改动  begin

if(Flag_Stop==1||Way_Angle>1)
{
Temperature=Read_Temperature();
if(1==Flag_Show)        oled_show();
else                  DataScope();
}

//这几行没有改动  end


//-------------------------------------------------------------------------


if((Flag_Stop==0)&&(Way_Angle<30))
DataScope();
}

为小车更新一下代码看结果

上图是按键运行之前,OLED的第一行显示WAY-2 kalman (MPU6050滤波是用卡尔曼算法)。这是就没有使用USART3交换数据了  (绿色的万用板中,下面好多直插的IC的,那是单相逆变器的驱动电路,可以不管的


下图是按一下按键之后,小车自动保持平衡了。


下图是小车保持自平衡时候的数据

黄色蓝色都是编码器的数据。显示车轮是在较稳定的转动。

假如串口引出来的线碰到车轮了,车子的移动幅度就会减少。也可以试试将车放到草稿本上,更在不怎么移动了...


菜鸟
2015-05-27 16:07:00     打赏
13楼

[开发进程]实验五、蓝牙调试PID参数

实验背景:在经过对代码的初步学习以后,了解到影响小车直立是否成功的参数有(Mini Balance V2.5 标准版源码):

MiniBalance.c

49行的Bais=Angle+0; 这个0,是应该随着硬件变化而变化的(注释中已经说明了感谢工作人员的注释)。

50balance=35*Bias+Gyro*0.125; 350.125分别是直立PD控制的比例和微分参数。

79Velocity=Encoder*4+Encoder_Integral/140; 41/140分别是速度PI控制器的比例参数和积分参数。

124Turn=Turn_Bias_Integral*2+gyro/12; 21/12分别是转向PD控制器的比例参数和微分参数。

实验准备:首先必须调试好蓝牙通信,此时必须具备蓝牙通信APP或者其替代的上位机蓝牙通信工具。(实验中需要发送ascII码调节参数)。本实验使用安卓串口小助手app。适用的安卓手机是具有蓝牙3.0以及以下的,我的安卓版本是2.3.5,能正常运行。

安卓串口小助手下载链接:http://www.wavesen.com/downloadDis.asp?id=32

实验原理

在上面实验背景已经提到过,影响小车平衡效果的变量,看起来起码有7个。在实验过程中,我将直立PD控制器改为PID控制器,原因是:只有积分控制,具有使被控对象的输出等于给定值的作用。

因此我将背景中提到的代码都改了:

全局变量初始化:

float B_Kp=16.5,B_Ki=0.050,B_Kd=0.107,V_Kp=4,V_Ki= 0.0071,T_Kp=2,T_Kd=0.0833;

float AngleBias = -1.0;   



我将背景中提到的代码,改为:

Bias=Angle+AngleBias;

balance=B_Kp*Bias+Gyro*B_Kd + Balance_Integral*B_Ki

Velocity=Encoder*V_Kp+Encoder_Integral*V_Ki;

Turn=Turn_Bias_Integral*T_Kp+gyro*T_Kd;



仿照开源的代码中,通过接收多个数据来控制电机停止的方法,自己编写了接收’B’’p’’+’三个数来控制Balance子程序中比例参数的增加,依次类推,编写了多组指令来控制其他几个参数。

控制指令有以下:

指令 执行语句:

‘AB+’: AngleBias= AngleBias + 0.1;

‘AB-’: AngleBias= AngleBias - 0.1;

‘Bp+’: B_Kp= B_Kp+0.1;

‘Bp-’ : B_Kp= B_Kp-0.1;

‘Bi+’ :B_Ki=B_Ki+0.001;

‘Bi-’ : B_Ki=B_Ki-0.001;

‘Bd+’ : B_Kd=B_Kd+0.001;

‘Bd-’ : B_Kd=B_Kd-0.001;

‘Vp+’: V_Kp= V_Kp+0.1;

‘Vp-’ : V_Kp= V_Kp-0.1;

‘Vi+’ :V_Ki=V_Ki+0.001;

‘Vi-’ ::V_Ki=V_Ki-0.001;

‘Tp+’: B_Kp= B_Kp+0.1;

‘Tp-’ : B_Kp= B_Kp-0.1;

‘Td+’ : T_Kd=T_Kd+0.001;

‘Td-’ : T_Kd=T_Kd-0.001;

//上面的适合微调,比例参数都比积分、微分参数都大。因此每次只须调节0.1就够了。

积分、微分变量,每次调节的幅度是0.001

实验代码

首先说说,源代码好多警告都是说Statement unreachable的。

问题出在DataScope_DP.c这里,return x;后面还有break;警告就是在return 6;后的break;在任何时候都不会执行。

改为以下就没警告了。

//函数说明:生成 DataScopeV1.0 能正确识别的帧格式

//Channel_Number,需要发送的通道个数

//返回发送缓冲区数据个数

//返回0表示帧格式生成失败

unsigned char DataScope_Data_Generate(unsigned char Channel_Number)

{

       if ( (Channel_Number > 10) || (Channel_Number == 0) ) { return 0; }  //通道个数大于10或等于0,直接跳出,不执行函数

  else

  { 

        DataScope_OutPut_Buffer[0] = '$';  //帧头

             

        switch(Channel_Number)  

   {

               case 1:   DataScope_OutPut_Buffer[5]  =  5; return  6; //break;  

               case 2:   DataScope_OutPut_Buffer[9]  =  9; return 10; //break;

               case 3:   DataScope_OutPut_Buffer[13] = 13; return 14; //break;

               case 4:   DataScope_OutPut_Buffer[17] = 17; return 18; //break;

               case 5:   DataScope_OutPut_Buffer[21] = 21; return 22; //break;

               case 6:   DataScope_OutPut_Buffer[25] = 25; return 26; //break;

               case 7:   DataScope_OutPut_Buffer[29] = 29; return 30; //break;

               case 8:   DataScope_OutPut_Buffer[33] = 33; return 34; //break;

               case 9:   DataScope_OutPut_Buffer[37] = 37; return 38; //break;

     case 10:  DataScope_OutPut_Buffer[41] = 41; return 42; //break;

               default: break;

   }      

  }

       return 0;

}

 



另外蓝牙调试PID代码:

//Usart3.c我改为以下内容:

#include "main.h"
#include "usart3.h"
#include "MiniBalance.h"
/**************************************************************************
作者:平衡小车之家 
淘宝店铺:http://shop114407458.taobao.com/
**************************************************************************/
 u8 mode_data[8];
 u8 six_data_1[4]={6,5,4,0};
 u8 six_data_2[4]={4,5,6,0};

 //xxJian code 1 begins
 u8 TuningPIDdata[5];
 //xxJian code 1 ends
 
void uart3_init(u32 pclk2,u32 bound)
{  	 
	float temp;
	u16 mantissa;
	u16 fraction;	   
	temp=(float)(pclk2*1000000/2)/(bound*16);//得到USARTDIV
	mantissa=temp;				 //得到整数部分
	fraction=(temp-mantissa)*16; //得到小数部分	 
  mantissa<<=4;
	mantissa+=fraction; 
	//AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP;
	RCC->APB2ENR|=1<<3;   //使能PORTA口时钟  
	RCC->APB1ENR|=1<<18;  //使能串口时钟 
	GPIOB->CRH&=0XFFFF00FF; 
	GPIOB->CRH|=0X00008B00;//IO状态设置
	GPIOB->ODR|=1<<10;	  
	RCC->APB1RSTR|=1<<18;   //复位串口1
	RCC->APB1RSTR&=~(1<<18);//停止复位	   	   
	//波特率设置
 	USART3->BRR=mantissa; // 波特率设置	 
	USART3->CR1|=0X200C;  //1位停止,无校验位.
	//使能接收中断
	USART3->CR1|=1<<8;    //PE中断使能
	USART3->CR1|=1<<5;    //接收缓冲区非空中断使能	    	
	MY_NVIC_Init(1,3,USART3_IRQChannel,2);//组2,最低优先级 
}

/**************************************************************************
函数功能:串口3接收中断
入口参数:无
返回  值:无
作    者:平衡小车之家
**************************************************************************/
void USART3_IRQHandler(void)
{	
	if(USART3->SR&(1<<5))//接收到数据
	{	  
	  static	int uart_receive=0;//蓝牙接收相关变量
		uart_receive=USART3->DR; 
		if(uart_receive<10)    mode_data[0]=uart_receive;

			if((mode_data[0]==six_data_2[0]
			&&mode_data[1]==six_data_2[1]
			&&mode_data[2]==six_data_2[2]
			&&mode_data[3]==six_data_2[3])
			||(mode_data[0]==six_data_1[0]
			&&mode_data[1]==six_data_1[1]
			&&mode_data[2]==six_data_1[2]
			&&mode_data[3]==six_data_1[3]))
		{	
			Flag_Stop=!Flag_Stop;
			mode_data[0]=0;	mode_data[1]=0;	mode_data[2]=0;	mode_data[3]=0;
		}
		if(uart_receive==0x00)	Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车
		if(uart_receive==0x01)	Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前
		if(uart_receive==0x05)	Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后
		else if(uart_receive==0x02||uart_receive==0x03||uart_receive==0x04)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1;
		else if(uart_receive==0x06||uart_receive==0x07||uart_receive==0x08)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0;

		mode_data[7]=mode_data[6];
		mode_data[6]=mode_data[5];
		mode_data[5]=mode_data[4];
		mode_data[4]=mode_data[3];
		mode_data[3]=mode_data[2];
		mode_data[2]=mode_data[1];
		mode_data[1]=mode_data[0];
		
		
		//xxJian code 2 begins
		
		if(uart_receive>0x20)    TuningPIDdata[0]=uart_receive;
		
		
		//-------------------------------------------------------------
		//Angle Bias
		//update Angle Bias
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='B'
			&&TuningPIDdata[2]=='A')
		{	
			AngleBias = AngleBias + 0.1;	
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'A';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'n';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'g';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'l';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'e';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'a';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 's';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			if(AngleBias<0)	
			{				
				while((USART3->SR&0X40)==0);  
				USART3->DR = '-';
			}
			while((USART3->SR&0X40)==0);	
			if(AngleBias<0)	
				USART3->DR = (int32_t)-AngleBias%10+'0';
			else
				USART3->DR = (int32_t)AngleBias%10+'0';				
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  			
			if(AngleBias<0)			
				USART3->DR = (uint32_t)(-AngleBias*10)%10+'0';
			else
				USART3->DR = (uint32_t)(AngleBias*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';			
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='B'
			&&TuningPIDdata[2]=='A')
		{	
			AngleBias = AngleBias - 0.1;	
		while((USART3->SR&0X40)==0);  
				USART3->DR = 'A';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'n';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'g';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'l';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'e';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'a';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 's';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			if(AngleBias<0)	
			{				
				while((USART3->SR&0X40)==0);  
				USART3->DR = '-';
			}
			while((USART3->SR&0X40)==0);	
			if(AngleBias<0)	
				USART3->DR = (int32_t)-AngleBias%10+'0';
			else
				USART3->DR = (int32_t)AngleBias%10+'0';				
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  			
			if(AngleBias<0)			
				USART3->DR = (uint32_t)(-AngleBias*10)%10+'0';
			else
				USART3->DR = (uint32_t)(AngleBias*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
		}
		//-------------------------------------------------------------
		//Balance PID
		//update Balance Kp		
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='B')
		{	
			B_Kp = B_Kp + 0.1;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = B_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)B_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='B')
		{	
			B_Kp = B_Kp - 0.1;		
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = B_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)B_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';			
		}
		//update Balance Ki
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='i'
			&&TuningPIDdata[2]=='B')
		{	
			B_Ki = B_Ki + 0.001;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='i'
			&&TuningPIDdata[2]=='B')
		{	
			B_Ki = B_Ki - 0.001;		
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Ki*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';				
		}
		//update Balance Kd
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='d'
			&&TuningPIDdata[2]=='B')
		{	
			B_Kd = B_Kd + 0.001;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'd';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='d'
			&&TuningPIDdata[2]=='B')
		{	
			B_Kd = B_Kd - 0.001;		
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'B';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'd';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(B_Kd*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';				
		}
		//-------------------------------------------------------------
		//Velocity PID
		//update Velocity Kp
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='V')
		{	
			V_Kp = V_Kp + 0.1;	
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'V';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = V_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)V_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';			
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='V')
		{	
			V_Kp = V_Kp - 0.1;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'V';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = V_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)V_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
		}
		//update Velocity Ki
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='i'
			&&TuningPIDdata[2]=='V')
		{	
			V_Ki = V_Ki + 0.001;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'V';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';			
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='i'
			&&TuningPIDdata[2]=='V')
		{	
			V_Ki = V_Ki - 0.001;				
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'V';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'i';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(V_Ki*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
			
		}
		//-------------------------------------------------------------
		//Turn PID
		//update Turn Kp
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='T')
		{	
			T_Kp = T_Kp + 0.1;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'T';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = T_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)T_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='p'
			&&TuningPIDdata[2]=='T')
		{	
			T_Kp = T_Kp - 0.1;			
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'T';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'p';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = T_Kp/10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (int32_t)T_Kp%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kp*10)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';			
		}
		//update Turn Kd
		if(TuningPIDdata[0]=='+'
			&&TuningPIDdata[1]=='d'
			&&TuningPIDdata[2]=='T')
		{	
			T_Kd = T_Kd + 0.001;				
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'T';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'd';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';	
			
		}
		if(TuningPIDdata[0]=='-'
			&&TuningPIDdata[1]=='d'
			&&TuningPIDdata[2]=='T')
		{	
			T_Kd = T_Kd - 0.001;				
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'T';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '_';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'K';
			while((USART3->SR&0X40)==0);  
				USART3->DR = 'd';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '=';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '.';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*10)+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*100)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = (uint32_t)(T_Kd*1000)%10+'0';
			while((USART3->SR&0X40)==0);  
				USART3->DR = '\n';				
		}
		
		TuningPIDdata[4]=TuningPIDdata[3];
		TuningPIDdata[3]=TuningPIDdata[2];
		TuningPIDdata[2]=TuningPIDdata[1];
		TuningPIDdata[1]=TuningPIDdata[0];
		//xxJian code 2 ends
	}  		
		
} 

 



实验结果

见视频

MniBalance V2.5 标准版源码互补滤波版本,这个例程下载完以后,小车前后平衡需要8cm


视频地址:http://player.youku.com/player.php/sid/XOTY1NTY3NzQ0/v.swf

在经过蓝牙调试PID实验之后,小车平衡前后的位置只有3cm左右!


视频地址:http://player.youku.com/player.php/sid/XOTY1NTY2NzM2/v.swf




实验过程中,明白了


Balance_Pwm =balance(Angle_Balance,Gyro_Balance);        //===平衡PID控制
Velocity_Pwm=velocity(Encoder_Left,Encoder_Right);       //===速度环PID控制
Turn_Pwm    =turn(Encoder_Left,Encoder_Right,Gyro_Turn); //===转向环PID控制

这三行代码在小车平衡中是缺一不可的。

注释掉速度环,小车两个轮子的速度就没收到控制了。。也就是速度失控

注释掉转向环,小车两个轮子的速度就不一样了。也就是转弯失控。


菜鸟
2015-05-27 19:42:13     打赏
14楼
蓝牙调试PID参数 长知识

菜鸟
2015-05-30 16:51:59     打赏
15楼
                       3cm左右摇动  能不能让它慢点呢

助工
2015-05-30 22:18:49     打赏
16楼
感谢楼主的辛勤劳动,谢谢找到警告这个的来源,可以看出楼主的深厚功底!日后望多多指教。楼主在直立中加了I值,这个其实效果应该不明显,而且系统已经是3个PID控制器联级了。再多的参数现场整定也麻烦。前后移动的问题,我觉得可能是小车的重心有点高,而且速度环PI(也可以理解成位置PD)参数需要细心调整,望楼主不吝赐教~

菜鸟
2015-06-01 19:07:56     打赏
17楼

[开发进程]实验六、绕圈圈与绕8字走

本实验的目让小车苯苯的一直绕圈子走

实验背景:小车源代码中,已经实现了小车绕原地转弯、前进以及后退。绕原地转弯就是一个轮子转动速率很少,另外一个转动速率相对大,就能实现绕原地转弯的效果。假如自己另外设置代码,使得小车前进的同时,又转弯,就可以实现简单的例如绕圈圈在走这样的效果。当然也感谢小车的开源代码!没有代码的开源,本试验也不能完成。

实验原理以及相关代码

智能小车相关程序运行过程:

各部分模块初始化->5ms进入一次中断计算相关代码让车子运行(包括前进、后退、左转、右转)[通过配置定时器3实现]

定时器3中断子程序执行代码主中跟本实验有关的就是:

int turn(int encoder_left,int encoder_right,float gyro);//转向控制


以及

int velocity(int encoder_left,int encoder_right);




个人认为,其中MiniBalance.c的第120行代码中,Turn_Amplitude明显就是转向的速度。另外velocity子程序中第7274行代码中的Movement就是前进后退的速度。

如果想要走8字,前进速度以及转弯速度必须要控制好。两个速度影响着绕的8字的形状。

相关代码:

注意:本代码在Mini Balance V2.5 标准版源码的基础上修改。

修改1

Main.c第六行:

u8 Way_Angle=2;




修改原因:=1的话,电机运行以后,OLED就不会刷新了,我不想,所以我喜欢改为2

修改2

MiniBalance.c中,第21行开始到TIM1_UP_TIM16_IRQHandler函数结束,改为以下内容。

int FiveMsCount=0;

void TIM1_UP_TIM16_IRQHandler(void)  
{    
	if(TIM1->SR&0X0001)//5ms定时中断
	{   
			if(FiveMsCount<500)
			{
				Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=1;
			}
			else if(FiveMsCount==500)
			{
				Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;
			}	
			else if(FiveMsCount<1000)
			{
				Flag_Qian=1,Flag_Hou=0,Flag_Left=1,Flag_Right=0;
			}
			else if(FiveMsCount>=1000)
			{
				FiveMsCount=0;
				Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;
			}
			FiveMsCount++;
			
		  TIM1->SR&=~(1<<0);                                       //===清除定时器1中断标志位		 
			readEncoder();                                           //===读取编码器的值
  		Led_Flash(400);                                          //===LED闪烁;	
  		Get_battery_volt();                                      //===获取电池电压	          
			key(100);                                                //===扫描按键状态
		  Get_Angle(Way_Angle);                                    //===更新姿态	
 			Balance_Pwm =balance(Angle_Balance,Gyro_Balance);        //===平衡PID控制	
 			Velocity_Pwm=velocity(Encoder_Left,Encoder_Right);       //===速度环PID控制
 	    Turn_Pwm    =turn(Encoder_Left,Encoder_Right,Gyro_Turn); //===转向环PID控制     
 		  Moto1=Balance_Pwm+Velocity_Pwm-Turn_Pwm;                 //===计算左轮电机最终PWM
 	  	Moto2=Balance_Pwm+Velocity_Pwm+Turn_Pwm;                 //===计算右轮电机最终PWM
   		Xianfu_Pwm();                                            //===PWM限幅
      if(Turn_Off(Angle_Balance,Voltage)==0)                   //===如果不存在异常
 			Set_Pwm(Moto1,Moto2);                                    //===赋值给PWM寄存器    		
	}       
} 

 


原理:中断程序每5ms执行一次,这里就按照500*5ms的时间改变一次转弯的方向,这里500*5ms差不多绕着0字转了刚刚好的一圈。


假如需要绕着圈圈走,那就直接使用

Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=1;

 

而不必往另外一个方向绕圈圈了。


修改3

MiniBalance.c中,在int turn(int encoder_left,int encoder_right,float gyro);函数内的

Turn_Amplitude=1500/Way_Angle+800;




改为:

Turn_Amplitude=300/Way_Angle;




减慢转弯速度。主要是我不喜欢小车走太快。。。

代码修改就这么简单。。


修改4:另外也可以通过手机来控制实现小车绕圈圈走,方法:

将Usart3.c内Usart3中断子程序中的内容部分(下面代码已注释掉的部分),改为下面没有注释的代码:


	
		/*original
		if(uart_receive==0x00)	Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车
		if(uart_receive==0x01)	Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前
		
		if(uart_receive==0x05)	Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后
		else if(uart_receive==0x02||uart_receive==0x03||uart_receive==0x04)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1;
		else if(uart_receive==0x06||uart_receive==0x07||uart_receive==0x08)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0;
		*/
		if(uart_receive==0x00)	Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车
		if(uart_receive==0x01)	Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前
		else if(uart_receive==0x02)	Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=1;//////////////前转右
		else if(uart_receive==0x03)	Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1;//////////////原地转右
		else if(uart_receive==0x04)	Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=1;//////////////后转右
		else if(uart_receive==0x05)	Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后
		else if(uart_receive==0x06)	Flag_Qian=0,Flag_Hou=1,Flag_Left=1,Flag_Right=0;//////////////后转左
		else if(uart_receive==0x07)	Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0;//////////////原地转左
		else if(uart_receive==0x08)	Flag_Qian=1,Flag_Hou=0,Flag_Left=1,Flag_Right=0;//////////////前转左
		




视频地址:http://player.youku.com/player.php/sid/XMTI1MjQ4Mzc5Mg==/v.swf

助工
2015-06-02 12:25:56     打赏
18楼

你的视频是怎么上传的?

楼主大哥


菜鸟
2015-06-03 13:15:14     打赏
19楼


[开发进程]实验七、超声波实验



第一部分,电机不转观察超声波测距的结果

实验代码使用Mini Balance V2.5 顶配版源码。

实验原理:Windows上面,只要调用printf()函数就可以往命令上中显示数字符号,聪明的ARM开发人员,将自己编了printf(),使用方法跟Windows上面的一样,只不过所须显示的数据是通过串口输出。

Usart1.c中,可以看到,工程设计者自定义了fputc()这函数,可以估计printf()内真正实现输出char的也是通过调用fputc

/************************************************************/

/*串口printf必备程序*/

/************************************************************/

int fputc(int ch, FILE *f)

{

    USART1->DR=(u8)ch;

    while((USART1->SR&0X40)==0);

    return ch;

} 



要使用printf()这个自定义的函数,都必须将Use MicroLIB选上。过程:

右键工程->Options for target->TargetTarget页面内的Code Generation内选中Use MicroLIB

通过改变USARTx,就可以将prtinf()输出的串口改变。例如在这例程中可以将USART1改为USART3,即可以实现蓝牙调试。

实验步骤:

Mini Balance V2.5 顶配版源码的基础上,要修改的地方有以下几个:

修改1main.c18行,改为:u8 Flag_Bizhang=1;

修改1原因:工程设计者设计成使得用户改变Flag_Bizhang这个参数,来决定小车是否在代码运行中执行超声波测距的代码。另外值得注意的是,//=====如果Flag_Bizhang1,则把TIM2初始化为超声波接口 然后不采集左路编码器,通过右路编码器和陀螺仪间接算出左路车轮速度 //=====如果Flag_Bizhang0,则把TIM2初始化为编码器接口

以上绿色的地方就是工程设计者的注释。十分赞!

修改2MiniBalance.c262printf("&d \r\n",Distance);

修改2 原因:原本这行代码被注释掉了,我取消注释以后,是这个结果(真是超出预料):



仔细看后,才发现应该改为:printf("%d \r\n",Distance);

修改后才会出现正确的结果:



OLED中第一行就是距离(JULI  xxxx)

第二部分,蔽障自平衡小车

待续……

超声波模块是网上买的5块钱不够的,可能质量不过关,平衡开始以后,偶尔就会出现往后走的情况。估计是数据测量错误了。。。

暂时就这样,这段时间改的代码都是小东西,模块还没深入学习,是这样的了。。。


菜鸟
2015-06-03 22:28:28     打赏
20楼
深度扩展啊

共34条 2/4 1 2 3 4 跳转至

回复

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