🌈個人主頁:羽晨同學
💫個人格言:“成為自己未來的主人~”?
傳感器原理
此外,用陀螺儀獲取x,y,z軸的加速度。
初始化
我們現在對MPU6050進行初始化,MPU6050通過I2C總線與單片機進行通信,通過的是PB8和PB9,并且PB8和PB9需要通過重映射,才可以發揮出I2C總線的功能。
//
// @簡介: 對MPU6050進行初始化
//
void App_Mpu6050_Init(void)
{//1. 初始化I2C總線,PB8、PB9 -I2C1//將I2C1的引腳重映射到PB8到PB9RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_I2C1,ENABLE);//初始化PB8和PB9 - AF_ODRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);}
這個是對I2C1的初始化
//2. 初始化I2C1// 開啟I2C1的時鐘RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);//設置I2C的參數I2C_InitTypeDef I2C_InitStruct = {0};I2C_InitStruct.I2C_ClockSpeed = 400000;//I2C通信速度I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;//占空比I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;I2C_Init(I2C1,&I2C_InitStruct);
我們對I2C1的速度設置為40000hz,也就是快速模式,然后選擇的I2C的模式是標準I2C模式,占空比為2比1.我們選用快速模式的時候,一般選擇的占空比就是2比1的。
寄存器部分
接下來,我們要配置寄存器部分。
所以,我們接下來封裝一下讀寫寄存器的函數。
//
// @簡介:寫寄存器函數
// @參數 reg - 要寫入的寄存器的地址
// @參數 value - 要寫入的值
//
static void reg_write(uint8_t reg,uint8_t value)
{uint8_t bytesToSend[] = {reg,value};My_I2C_SendBytes(I2C1,0xd0,bytesToSend,2);
}
//
// @簡介:讀寄存器函數
// @參數 reg - 要讀取的寄存器的地址
// @返回值:表示讀取到的值
//
static uint8_t reg_read(uint8_t reg)
{My_I2C_SendBytes(I2C1,0xd0,®,1);uint8_t regValue;My_I2C_ReceiveBytes(I2C1,0xd0,®Value,1);return regValue;
}
然后,我們對寄存器的參數進行配置
// 2. 設置MPU6050的參數reg_write(0x6b,0x80);//復位Delay(100);reg_write(0x1b,0x18);//將陀螺儀的量程設置為+-2000°/sreg_write(0x1c,0x00);//將加速度計的量程設置為+-2g
接下來,我們對MPU6050的值進行更新
//
//@簡介: MPU6050的數據更新函數
//
void App_MPU6050_Update(void)
{int16_t ax_raw = (int16_t)((reg_read(0x3b)<<8)+reg_read(0x3c));//ax的原始數據int16_t ay_raw = (int16_t)((reg_read(0x3d)<<8)+reg_read(0x3e));//ay的原始數據int16_t az_raw = (int16_t)((reg_read(0x3f)<<8)+reg_read(0x40));//az的原始數據int16_t temperature_raw = (int16_t)((reg_read(0x41)<<8)+reg_read(0x42));//溫度的原始數據int16_t gx_raw = (int16_t)((reg_read(0x43)<<8)+reg_read(0x44));//gx的原始數據int16_t gy_raw = (int16_t)((reg_read(0x45)<<8)+reg_read(0x46));//gy的原始數據int16_t gz_raw = (int16_t)((reg_read(0x47)<<8)+reg_read(0x48));//gz的原始數據
}
然后我們對數值進行更新:
void App_MPU6050_Update(void)
{int16_t ax_raw = (int16_t)((reg_read(0x3b)<<8)+reg_read(0x3c));//ax的原始數據int16_t ay_raw = (int16_t)((reg_read(0x3d)<<8)+reg_read(0x3e));//ay的原始數據int16_t az_raw = (int16_t)((reg_read(0x3f)<<8)+reg_read(0x40));//az的原始數據ax = ax_raw * 6.1035e-5f;ay = ay_raw * 6.1035e-5f;az = az_raw * 6.1035e-5f;int16_t temperature_raw = (int16_t)((reg_read(0x41)<<8)+reg_read(0x42));//溫度的原始數據//temperature = temperature_raw/340 +36.53;//MPU6050temperature = temperature_raw/333.87f+21.0f;//MPU6500int16_t gx_raw = (int16_t)((reg_read(0x43)<<8)+reg_read(0x44));//gx的原始數據int16_t gy_raw = (int16_t)((reg_read(0x45)<<8)+reg_read(0x46));//gy的原始數據int16_t gz_raw = (int16_t)((reg_read(0x47)<<8)+reg_read(0x48));//gz的原始數據 gx = gx_raw * 6.1035e-2f;gy = gy_raw * 6.1035e-2f;gz = gz_raw * 6.1035e-2f;
}
然后我們創建一個接口函數,將更新到的值進行導出
float App_MPU6050_GetAx(void)
{return ax;
}
float App_MPU6050_GetAy(void)
{return ay;
}
float App_MPU6050_GetAz(void)
{return az;
}
float App_MPU6050_Temperature(void)
{return temperature;
}
float App_MPU6050_GetGx(void)
{return gx;
}
float App_MPU6050_GetGy(void)
{return gy;
}
float App_MPU6050_GetGz(void)
{return gz;
}
解算歐拉角
陀螺儀解算歐拉角
static float yaw,pitch,roll;//單位是°
//
// @簡介:MPU6050的進程函數,計算歐拉角
//
void App_MPU6050_Proc(void)
{static uint32_t nxt = 0;//下次程序運行的時間if(GetTick() < nxt) return;App_MPU6050_Update();//通過陀螺儀的測量結果計算歐拉角yaw = yaw + gz * 0.005;pitch = pitch + gx * 0.005;roll = roll - gy * 0.005;nxt += 5;
}
//
這樣,我們就會每5ms來執行一次這個程序
為了簡化這個步驟,我們也可以這樣子寫
//
// @簡介:MPU6050的進程函數,計算歐拉角
//
void App_MPU6050_Proc(void)
{PERIODIC(5);App_MPU6050_Update();//通過陀螺儀的測量結果計算歐拉角yaw = yaw + gz * 0.005;pitch = pitch + gx * 0.005;roll = roll - gy * 0.005;}
接下來,我們對這個部分進行測試
//
// @簡介: 用來測試歐拉角
//
void MPU6050_EularAngleTest(void)
{App_Usart_Init();App_Mpu6050_Init(); while(1){App_MPU6050_Proc();Uasrt2_Proc();}}
static void Uasrt2_Proc(void)
{PERIODIC(10)float ax = App_MPU6050_GetAx();float ay = App_MPU6050_GetAy();float az = App_MPU6050_GetAz();float temperature = App_MPU6050_Temperature();float gx = App_MPU6050_GetGx();float gy = App_MPU6050_GetGy();float gz = App_MPU6050_GetGz();float yaw = App_MPU6050_GetYaw();float pitch = App_MPU6050_GetPitch();float roll = App_MPU6050_GetRoll();My_USART_Printf(USART2,"%f,%f,%f,%f,%f,%f,%f,%f,%f,%f\n",ax,ay,az,temperature,gx,gy,gz,yaw,pitch,roll);
}
加速度計解算歐拉角
我們一般是會使用加速度計來計算俯仰角和翻滾角,一般不會使用加速度計來計算偏航角,因為重力對于平面上的影響是非常小的。重力向量在設備坐標系中的投影變化,直接反映了設備的Pitch和Roll角度。重力是這些角度的“絕對參考”。重力向量與設備的偏航角是完全解耦的,它不提供任何關于偏航方向的信息。所以我們不會用來計算偏航角。
//通過加速度計解算歐拉角yaw = 0;pitch = atan2(ay,az) / 3.1415927f * 180.0f;roll = atan2(ax,az) / 3.1415927f * 180.0f;
用陀螺儀是有漂移問題的,而加速度計有噪聲,所以我們用互補濾波器來解決這種問題。
//
// @簡介:MPU6050的進程函數,計算歐拉角
//
void App_MPU6050_Proc(void)
{PERIODIC(5);App_MPU6050_Update();//通過陀螺儀的測量結果計算歐拉角float yaw_g = yaw + gz * 0.005;float pitch_g = pitch + gx * 0.005;float roll_g = roll - gy * 0.005;//通過加速度計解算歐拉角float yaw_a = 0;float pitch_a = atan2(ay,az) / 3.1415927f * 180.0f;float roll_a = atan2(ax,az) / 3.1415927f * 180.0f;//使用互補濾波器yaw = yaw_g;pitch = 0.95238 * pitch_g + (1-0.95238) * pitch_a;roll = 0.95238 * roll_g + (1-0.95238) * roll_a;
}
好了,今天的內容就到這里,明天再見