|
0.png (35.91 KB, 下載次數(shù): 167)
下載附件
2016-5-8 19:26 上傳
兩輪自平衡小車全部的制作資料下載:
自平衡小車程序.rar
(13.1 MB, 下載次數(shù): 254)
2016-5-8 19:36 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
調(diào)試記錄:
2016.12.2
完成基本角度閉環(huán)程序,基本調(diào)節(jié)出角度的PD,
富民發(fā)現(xiàn)直立可能需要位置閉環(huán)+角度閉環(huán)+速度閉環(huán)。
2016.12.3 pm 13:00
完成基本速度閉環(huán)和位置閉環(huán)程序,基本可以按照設(shè)定方向前進(jìn),
只是中途的PID參數(shù)沒有調(diào)節(jié)好有停頓現(xiàn)象,開始藍(lán)牙控制模式。
2016.12.3 pm 14:43
完成基本的前進(jìn) 后退藍(lán)牙控制功能,就是有些時(shí)候出現(xiàn)過沖停頓。
下一步進(jìn)行轉(zhuǎn)彎控制程序的抒寫。
2016.12.3 pm 16:55
完成基本控制功能,前進(jìn)、后退、原地左轉(zhuǎn)、原地右轉(zhuǎn)、使用簡(jiǎn)單
的藍(lán)牙指令控制,0x01前進(jìn)、0x02后退、 0x03原地左轉(zhuǎn)、 0x04原
地右轉(zhuǎn)、0x00什么保持直立狀態(tài),下一步進(jìn)行直立調(diào)節(jié),優(yōu)化靜止
時(shí)的狀態(tài)。
2016.12.5 pm 13:50
加入了手機(jī)APP藍(lán)牙控制 出現(xiàn)問題 抖動(dòng)過大多次控制容易出現(xiàn)死機(jī)
現(xiàn)象,需要繼續(xù)直立PID調(diào)節(jié)參數(shù)。
2016.12.22 pm 17:49
加入了 模糊控制 參數(shù)調(diào)節(jié)的還算可以,只調(diào)節(jié)了直立參數(shù) 速度閉環(huán)
和位置閉環(huán)參數(shù)還沒有調(diào)節(jié)等待明天調(diào)節(jié)。
2016.12.31 am 11:13
所有功能都已完畢。直立、壁障、循跡、藍(lán)牙遙控、由于循跡采用雙線
導(dǎo)致有些時(shí)候不穩(wěn)定、不知道是機(jī)械愿意還是軟件原因?qū)е轮绷㈧o止時(shí)
有些抖動(dòng)。基本可以完成所有多需任務(wù)。
這個(gè)是去年做的一個(gè)兩輪自平衡循跡小車,小車采用兩片STM32,一塊負(fù)責(zé)圖像處理,另一塊負(fù)責(zé)對(duì)電機(jī)的控制。兩塊板子之間使用串口通信傳輸數(shù)據(jù)。
做這個(gè)車子學(xué)會(huì)了很多,最初兩塊板子之間串口通信有問題,程序會(huì)跑著跑著就跑飛,很是惱火。之后每次需要串口通信才打開中斷,解決了跑飛的問題。
以下是車子的圖片,和源碼。
085403fua2c2zuamfn309o.jpg.thumb.jpg (35 KB, 下載次數(shù): 172)
下載附件
2016-5-8 21:46 上傳
主程序下面是部分程序預(yù)覽(完整版本請(qǐng)下載本帖附件):
- #include "System_init.h"
- /*特別注意:flag變量 不可以更改 否則無法直立*/
- extern u8 flag;
- /**********主函數(shù)**********/
- int main(void)
- {
- system_init(); //整體系統(tǒng)初始化函數(shù)
- temp_data11 = 80;
- for(;;)
- {
- /*
- 函數(shù)說明:
- upright_Adjust函數(shù)。
- 功能:直立控制。
- 參數(shù)個(gè)數(shù):3個(gè)。
- 1)P參數(shù)。
- 2)I參數(shù)。
- 3)D參數(shù)。
- 此函數(shù)是用于直立的函數(shù)P是PID中的比例參數(shù)
- D是PID的微分參數(shù)、直立不用I積分參數(shù)。
- */
- /*
- 函數(shù)說明:
- speed_control函數(shù)。
- 功能:藍(lán)牙控制函數(shù)。
- 參數(shù)個(gè)數(shù):3個(gè)。
- 1)串口采集參數(shù)(不需要更改、放著就可以)
- 2)速度控制參數(shù)(可以更改最大40最小10)
- 3)轉(zhuǎn)角速度控制參數(shù)(可修改,最大40最小10)
- */
- SpeedL(3500);
- SpeedR(3500);
- if(1 == flag)
- {
-
- //upright_Adjust(400.0,0.0,25.0); //9.5
- /*特別注意:flag變量 不可以更改 否則無法直立*/
- flag = 0;
- }
- }
- }
復(fù)制代碼 以stm32f103rct6為例
測(cè)試串口通信數(shù)據(jù)
MPU數(shù)據(jù)進(jìn)行處理
檢測(cè)X軸加速度,Y軸角速度
參考網(wǎng)上例程
mpu6050.c文件:
- #include "MPU6050.h"
- #include "System_init.h"
- void I2C_Congiguration(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- I2C_InitTypeDef I2C_InitStructure;
- /* 使能?I22C1 有關(guān)的時(shí)鐘 */
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2,ENABLE);
-
- /* PB6-I2C2_SCL、PB7-I2C2_SDA*/
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 開漏輸出
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- /* I2C 配置 */
- I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
- I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
- I2C_InitStructure.I2C_OwnAddress1 = I2C2_MPU6050;
- I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
- I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
- I2C_InitStructure.I2C_ClockSpeed = I2C_Speed;
- /* 使I2C1 */
- I2C_Cmd(I2C2, ENABLE);
- /* I2C2 初始化 */
- I2C_Init(I2C2, &I2C_InitStructure);
- /*允許1字節(jié)1應(yīng)答模式*/
- I2C_AcknowledgeConfig(I2C2, ENABLE);
-
-
- }
- void MPU6050_Init(void)
- {
- delay_ms(100);
- I2C_WriteByte(PWR_MGMT_1,0x00);
- delay_ms(10);
- I2C_WriteByte(SMPLRT_DIV,0x07);
- delay_ms(10);
- I2C_WriteByte(CONFIG,0x06);
- delay_ms(10);
- I2C_WriteByte(GYRO_CONFIG,0x18);
- delay_ms(10);
- I2C_WriteByte(ACCEL_CONFIG,0x01);
- delay_ms(1000);
- }
- void I2C_WriteByte(uint8_t REG_Address, uint8_t Write_Data)
- {
- while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
- /* Send STRAT condition */
- I2C_GenerateSTART(I2C2, ENABLE);
- /* Test on EV5 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
- /* Send EEPROM address for write */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Transmitter);
-
- /* Test on EV6 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
-
- /* Send the EEPROM's internal address to write to */
- I2C_SendData(I2C2, REG_Address);
-
- /* Test on EV8 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
- /* Send the byte to be written */
- I2C_SendData(I2C2, Write_Data);
-
- /* Test on EV8 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
-
- /* Send STOP condition */
- I2C_GenerateSTOP(I2C2, ENABLE);
- I2C_WaitEepromStandbyState();
- }
- uint8_t I2C_ReadByte(uint8_t REG_Address)
- {
- uint8_t data_byte;
- //*((u8 *)0x4001080c) |=0x80;
- while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
-
-
- /* Send START condition */
- I2C_GenerateSTART(I2C2, ENABLE);
- //*((u8 *)0x4001080c) &=~0x80;
-
- /* Test on EV5 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
- /* Send EEPROM address for write */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Transmitter);
- /* Test on EV6 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
-
- /* Clear EV6 by setting again the PE bit */
- I2C_Cmd(I2C2, ENABLE);
- /* Send the EEPROM's internal address to write to */
- I2C_SendData(I2C2, REG_Address);
- /* Test on EV8 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
-
- /* Send STRAT condition a second time */
- I2C_GenerateSTART(I2C2, ENABLE);
-
- /* Test on EV5 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
-
- /* Send EEPROM address for read */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Receiver);
-
- /* Test on EV6 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
-
- /* While there is data to be read */
- /* Disable Acknowledgement */
- I2C_AcknowledgeConfig(I2C2, DISABLE);
-
- /* Send STOP Condition */
- I2C_GenerateSTOP(I2C2, ENABLE);
- /* Test on EV7 and clear it */
- if(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED))
- /* Read a byte from the EEPROM */
- data_byte = I2C_ReceiveData(I2C2);
- /* Enable Acknowledgement to be ready for another reception */
- I2C_AcknowledgeConfig(I2C2, ENABLE);
- //I2C_EE_WaitEepromStandbyState();
- return data_byte;
- }
- void I2C_ReadBuffer(uint8_t* Data_Buffer, uint8_t REG_Address, uint8_t Num_Byte)
- {
- //*((u8 *)0x4001080c) |=0x80;
- while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY)); // Added by Najoua 27/08/2008
-
-
- /* Send START condition */
- I2C_GenerateSTART(I2C2, ENABLE);
- //*((u8 *)0x4001080c) &=~0x80;
-
- /* Test on EV5 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
- /* Send EEPROM address for write */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Transmitter);
- /* Test on EV6 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
-
- /* Clear EV6 by setting again the PE bit */
- I2C_Cmd(I2C2, ENABLE);
- /* Send the EEPROM's internal address to write to */
- I2C_SendData(I2C2, REG_Address);
- /* Test on EV8 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
-
- /* Send STRAT condition a second time */
- I2C_GenerateSTART(I2C2, ENABLE);
-
- /* Test on EV5 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
-
- /* Send EEPROM address for read */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Receiver);
-
- /* Test on EV6 and clear it */
- while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
-
- /* While there is data to be read */
- while(Num_Byte)
- {
- if(Num_Byte == 1)
- {
- /* Disable Acknowledgement */
- I2C_AcknowledgeConfig(I2C2, DISABLE);
-
- /* Send STOP Condition */
- I2C_GenerateSTOP(I2C2, ENABLE);
- }
- /* Test on EV7 and clear it */
- if(I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED))
- {
- /* Read a byte from the EEPROM */
- *Data_Buffer = I2C_ReceiveData(I2C2);
- /* Point to the next location where the byte read will be saved */
- Data_Buffer++;
-
- /* Decrement the read bytes counter */
- Num_Byte--;
- }
- }
- /* Enable Acknowledgement to be ready for another reception */
- I2C_AcknowledgeConfig(I2C2, ENABLE);
- //I2C_EE_WaitEepromStandbyState();
- }
- void I2C_WaitEepromStandbyState(void)
- {
- vu16 SR1_Tmp = 0;
- do
- {
- /* Send START condition */
- I2C_GenerateSTART(I2C2, ENABLE);
- /* Read I2C2 SR1 register */
- SR1_Tmp = I2C_ReadRegister(I2C2, I2C_Register_SR1);
- /* Send EEPROM address for write */
- I2C_Send7bitAddress(I2C2, I2C2_MPU6050, I2C_Direction_Transmitter);
- }while(!(I2C_ReadRegister(I2C2, I2C_Register_SR1) & 0x0002));
-
- /* Clear AF flag */
- I2C_ClearFlag(I2C2, I2C_FLAG_AF);
- /* STOP condition */
- I2C_GenerateSTOP(I2C2, ENABLE); // Added by Najoua 27/08/2008
- }
復(fù)制代碼 pazzy.c文件:
- #include "pazzy.h"
- #include "System_init.h"
- #define FMAX 100 /*語言值的滿幅值*/
- //角度值
- int PFF[4]={0,8,16,24};
- /*輸入量D語言值特征點(diǎn)*/
- // 角速度
- int DFF[4]={0,16,45,80};
- /*輸出量U語言值特征點(diǎn)*/
- int UFF[7]={0,12,30};
- /*采用了調(diào)整因子的規(guī)則表,大誤差時(shí)偏重誤差,小誤差時(shí)偏重誤差變化*/
- /*a0=0.3,a1=0.55,a2=0.74,a3=0.89 */
- int rule[7][7]={
- //誤差變化率 -3,-2,-1, 0, 1, 2, 3 // 誤差
- { 2, 2, 2, 2, 2, 1, 1,}, // -3
- { 2, 1, 1, 1, 1, 1, 2,}, // -2
- { 2, 1, 0, 0, 0, 0, 0,}, // -1
- { 2, 2, 2, 2, 2, 2, 2,}, // 0
- { 0, 0, 0, 0, 0, 1, 2,}, // 1
- { 0, 1, 1, 1, 1, 1, 2,}, // 2
- { 1, 1, 2, 2, 2, 2, 2}}; // 3 // 3
- /**********************************************************/
- float Fuzzy(float P,float D) /*模糊運(yùn)算引擎*/
- {
- float U; /*偏差,偏差微分以及輸出值的精確量*/
- float PF[2],DF[2],UF[4]; /*偏差,偏差微分以及輸出值的隸屬度*/
- int Pn,Dn,Un[4];
- double temp1,temp2;
- /*隸屬度的確定*/
- /*根據(jù)PD的指定語言值獲得有效隸屬度*/
- if(P>-PFF[3] && P<pff[3])
- {
- if(P<=-PFF[2])
- {
- Pn=-2;
- PF[0]=FMAX*((float)(-PFF[2]-P)/(PFF[3]-PFF[2]));
- }
- else if(P<=-PFF[1])
- {
- Pn=-1;
- PF[0]=FMAX*((float)(-PFF[1]-P)/(PFF[2]-PFF[1]));
- }
- else if(P<=PFF[0])
- {
- Pn=0;
- PF[0]=FMAX*((float)(-PFF[0]-P)/(PFF[1]-PFF[0]));
- }
- else if(P<=PFF[1])
- {
- Pn=1; PF[0]=FMAX*((float)(PFF[1]-P)/(PFF[1]-PFF[0]));
- }
- else if(P<=PFF[2])
- {
- Pn=2; PF[0]=FMAX*((float)(PFF[2]-P)/(PFF[2]-PFF[1]));
- }
- else if(P<=PFF[3])
- {
- Pn=3; PF[0]= FMAX*((float)(PFF[3]-P)/(PFF[3]-PFF[2]));
- }
- }
- else if(P<=-PFF[3])
- {
- Pn=-2; PF[0]=FMAX;
- }
- else if(P>=PFF[3])
- {
- Pn=3; PF[0]=0;
- }
- PF[1]=FMAX-PF[0];
- if(D>-DFF[3] && D<dff[3])
- {
- if(D<=-DFF[2])
- {
- Dn=-2;DF[0]=FMAX*((float)(-DFF[2]-D)/(DFF[3]-DFF[2]));
- }
- else if(D<=-DFF[1])
- {
- Dn=-1;
- DF[0]=FMAX*((float)(-DFF[1]-D)/(DFF[2]-DFF[1]));
- }
- else if(D<=DFF[0])
- {
- Dn=0;
- DF[0]=FMAX*((float)(-DFF[0]-D)/(DFF[1]-DFF[0]));
- }
- else if(D<=DFF[1])
- {
- Dn=1;
- DF[0]=FMAX*((float)(DFF[1]-D)/(DFF[1]-DFF[0]));
- }
- else if(D<=DFF[2])
- {
- Dn=2; DF[0]=FMAX*((float)(DFF[2]-D)/(DFF[2]-DFF[1]));
- }
- else if(D<=DFF[3])
- {
- Dn=3; DF[0]=FMAX*((float)(DFF[3]-D)/(DFF[3]-DFF[2]));
- }
- }
- else if(D<=-DFF[3])
- {
- Dn=-2;
- DF[0]=FMAX;
- }
- else if(D>=DFF[3])
- {
- Dn=3;
- DF[0]=0;
- }
- DF[1]=FMAX-DF[0];
- /*使用誤差范圍優(yōu)化后的規(guī)則表rule[7][7]*/
- /*輸出值使用13個(gè)隸屬函數(shù),中心值由UFF[7]指定*/
- /*一般都是四個(gè)規(guī)則有效*/
- Un[0]=rule[Pn-1+3][Dn-1+3];
- Un[1]=rule[Pn+3][Dn-1+3];
- Un[2]=rule[Pn-1+3][Dn+3];
- Un[3]=rule[Pn+3][Dn+3];
- if(PF[0]<=DF[0])
- UF[0]=PF[0];
- else
- UF[0]=DF[0];
- if(PF[1]<=DF[0])
- UF[1]=PF[1];
- else
- UF[1]=DF[0];
- if(PF[0]<=DF[1])
- UF[2]=PF[0];
- else
- UF[2]=DF[1];
- if(PF[1]<=DF[1])
- UF[3]=PF[1];
- else
- UF[3]=DF[1];
- /*同隸屬函數(shù)輸出語言值求大*/
- if(Un[0]==Un[1])
- {
- if(UF[0]>UF[1])
- UF[1]=0;
- else
- UF[0]=0;
- }
- if(Un[0]==Un[2])
- {
- if(UF[0]>UF[2])
- UF[2]=0;
- else
- UF[0]=0;
- }
- if(Un[0]==Un[3])
- {
- if(UF[0]>UF[3])
- UF[3]=0;
- else
- UF[0]=0;
- }
- if(Un[1]==Un[2])
- {
- if(UF[1]>UF[2])
- UF[2]=0;
- else
- UF[1]=0;
- }
- if(Un[1]==Un[3])
- {
- if(UF[1]>UF[3])
- UF[3]=0;
- else
- UF[1]=0;
- }
- if(Un[2]==Un[3])
- {
- if(UF[2]>UF[3])
- UF[3]=0;
- else
- UF[2]=0;
- }
- /*重心法反模糊*/
- /*Un[]原值為輸出隸屬函數(shù)標(biāo)號(hào),轉(zhuǎn)換為隸屬函數(shù)值*/
- if(Un[0]>=0)
- Un[0]=UFF[Un[0]];
- else
- Un[0]=-UFF[-Un[0]];
- if(Un[1]>=0)
- Un[1]=UFF[Un[1]];
- else
- Un[1]=-UFF[-Un[1]];
- if(Un[2]>=0)
- Un[2]=UFF[Un[2]];
- else
- Un[2]=-UFF[-Un[2]];
- if(Un[3]>=0)
- Un[3]=UFF[Un[3]];
- else
- Un[3]=-UFF[-Un[3]];
- temp1=UF[0]*Un[0]+UF[1]*Un[1]+UF[2]*Un[2]+UF[3]*Un[3]; //因?yàn)檫x定隸屬函數(shù)為三角形,且對(duì)稱,故可以證明中心在中間的特征點(diǎn)上(橫坐標(biāo))。
- temp2=UF[0]+UF[1]+UF[2]+UF[3];
- U=temp1/temp2;
- return U; //最后的輸出
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|