概述
MPU6050是一個(gè)3軸陀螺儀(測角加速度)和3軸加速度計(jì)(測量線加速度)的測量芯片
內(nèi)部自帶運(yùn)算單元(DMP),可以輸出經(jīng)姿態(tài)融合計(jì)算后的四元數(shù)(一種表示旋轉(zhuǎn)的方法)
而且MPU6050的價(jià)格較低(10r以下),常被用于精度不高的場合作為姿態(tài)感知的芯片
如經(jīng)典項(xiàng)目平衡車,某年電賽題目風(fēng)力擺等
MPU6050可以獲取的數(shù)據(jù)為3軸的角加速度和三軸加速度,為了得到平常使用的歐拉角或者四元數(shù),需要根據(jù)這些數(shù)據(jù)進(jìn)行姿態(tài)解算
可以在單片機(jī)內(nèi)部進(jìn)行姿態(tài)解算,如使用 卡爾曼濾波 但是這樣會占用大量單片機(jī)資源,因此常用MPU6050自帶的運(yùn)算單元來進(jìn)行解算
注意,本文的代碼借是將 正點(diǎn)原子,大魚電子,DMP的官方庫 進(jìn)行了整合修改,并非100%原創(chuàng)
注意,本文的代碼借是將 正點(diǎn)原子,大魚電子,DMP的官方庫 進(jìn)行了整合修改,并非100%原創(chuàng)
注意,本文的代碼借是將 正點(diǎn)原子,大魚電子,DMP的官方庫 進(jìn)行了整合修改,并非100%原創(chuàng)
硬件設(shè)計(jì)
使用官方數(shù)據(jù)手冊給出的電路圖進(jìn)行設(shè)計(jì),實(shí)測可以使用
要注意CPOUT(20腳)的電容,這是個(gè)電荷泵電容,一定要使用2.2nF,不然會出現(xiàn)不穩(wěn)定
MPU6050使用標(biāo)準(zhǔn)I2C通信,建議在I2C加外部上拉電阻(也可以將單片機(jī)內(nèi)設(shè)為開漏上拉輸出)
6,7號引腳連接的是地磁計(jì)的用于修正偏航角(Yaw),同樣是I2C通信
封裝是比較難焊的QFN-24,建議使用風(fēng)槍或者加熱臺焊接(用烙鐵太折磨人了)
這是對應(yīng)的角加速度和加速度的方向,以及解算后的歐拉角
另外因?yàn)橛布?偏航角(Yaw)會出現(xiàn)偏移,這是無可避免的,可以通過外接地磁計(jì)改善
軟件設(shè)計(jì)
I2C通信
MPU6050的I2C從器件地址是依據(jù)AD0(9號引腳)的電平而變化的
AD0引腳為低電平(通過10K電阻接地)則地址是 0x68 << 1 = 0xD0 (也就是常說的除最低位外的地址)
AD0引腳為高電平則地址是 0x69 << 1 = 0xD2 (也就是常說的除最低位外的地址)
最后一位和標(biāo)準(zhǔn)I2C一樣是根據(jù)讀寫來確定的
地址要特別注意,容易出錯(cuò)
I2C協(xié)議沒什么好說的,請看這篇博客
傳送門
通過宏定義來選擇硬件和軟件I2C
/*
硬件I2C模式
需要:
1.I2C
I2C
(默認(rèn)設(shè)置)
標(biāo)準(zhǔn)模式
時(shí)鐘頻率100kHz
地址長度7bit
不用填寫設(shè)備地址
取消下方注釋
*/
// extern I2C_HandleTypeDef hi2c2;
// #define MPU6050_I2C_Handle hi2c2
// #define MPU6050_Hardware_I2C
/*
軟件I2C模式
需要:
1.GPIO 2個(gè)
均為開漏輸出(上不上拉取決于外部電路)
最高等級
取消下方注釋,按照自己的管腳更改即可
*/
#define MPU6050_Software_I2C
#ifdef MPU6050_Software_I2C
#define I2C_Group_SCL GPIOA // I2C的時(shí)鐘GPIO組號
#define I2C_SCL GPIO_PIN_0 // I2C時(shí)鐘的GPIO端口號
#define I2C_Group_SDA GPIOA // I2C的數(shù)據(jù)GPIO組號
#define I2C_SDA GPIO_PIN_1 // I2C數(shù)據(jù)的GPIO端口號
#define I2C_Write_SCL(x) HAL_GPIO_WritePin(I2C_Group_SCL, I2C_SCL, x)
#define I2C_Write_SDA(x) HAL_GPIO_WritePin(I2C_Group_SDA, I2C_SDA, x)
#define I2C_Read_SCL() HAL_GPIO_ReadPin(I2C_Group_SCL, I2C_SCL)
#define I2C_Read_SDA() HAL_GPIO_ReadPin(I2C_Group_SDA, I2C_SDA)
#endif
#include "mpuiic.h"
#if defined(MPU6050_Software_I2C)
/**
* @brief 一段延遲
* @param 無
* @return 無
* @author HZ12138
* @date 2022-07-27 08:53:30
*/
void I2C_Delay()
{
int z = 0xff;
while (z--)
;
}
/**
* @brief 產(chǎn)生I2C起始信號
* @param 無
* @return 無
* @author HZ12138
* @date 2022-07-27 08:54:48
*/
void I2C_Start(void)
{
I2C_Write_SDA(GPIO_PIN_SET); //需在SCL之前設(shè)定
I2C_Write_SCL(GPIO_PIN_SET); // SCL->高
I2C_Delay(); //延時(shí)
I2C_Write_SDA(GPIO_PIN_RESET); // SDA由1->0,產(chǎn)生開始信號
I2C_Delay(); //延時(shí)
I2C_Write_SCL(GPIO_PIN_RESET); // SCL->低
}
/**
* @brief 產(chǎn)生I2C結(jié)束信號
* @param 無
* @return 無
* @author HZ12138
* @date 2022-07-27 08:57:03
*/
void I2C_End(void)
{
I2C_Write_SDA(GPIO_PIN_RESET); //在SCL之前拉低
I2C_Write_SCL(GPIO_PIN_SET); // SCL->高
I2C_Delay(); //延時(shí)
I2C_Write_SDA(GPIO_PIN_SET); // SDA由0->1,產(chǎn)生結(jié)束信號
I2C_Delay(); //延時(shí)
}
/**
* @brief 發(fā)送應(yīng)答碼
* @param ack:0 應(yīng)答 1 不應(yīng)達(dá)
* @return 無
* @author HZ12138
* @date 2022-07-27 09:03:38
*/
void IIC_Send_ACK(uint8_t ack)
{
if (ack == 1)
I2C_Write_SDA(GPIO_PIN_SET); //產(chǎn)生應(yīng)答電平
else
I2C_Write_SDA(GPIO_PIN_RESET);
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET); //發(fā)送應(yīng)答信號
I2C_Delay(); //延時(shí)至少4us
I2C_Write_SCL(GPIO_PIN_RESET); //整個(gè)期間保持應(yīng)答信號
}
/**
* @brief 接受應(yīng)答碼
* @param 無
* @return 應(yīng)答碼 0 應(yīng)答 1 不應(yīng)達(dá)
* @author HZ12138
* @date 2022-07-27 09:04:28
*/
uint8_t IIC_Get_ACK(void)
{
uint8_t ret; //用來接收返回值
I2C_Write_SDA(GPIO_PIN_SET); //電阻上拉,進(jìn)入讀
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET); //進(jìn)入應(yīng)答檢測
I2C_Delay(); //至少延時(shí)4us
ret = I2C_Read_SDA(); //保存應(yīng)答信號
I2C_Write_SCL(GPIO_PIN_RESET);
return ret;
}
/**
* @brief I2C寫1Byte
* @param dat:1Byte數(shù)據(jù)
* @return 應(yīng)答結(jié)果 0 應(yīng)答 1 不應(yīng)達(dá)
* @author HZ12138
* @date 2022-07-27 09:05:14
*/
uint8_t I2C_SendByte(uint8_t dat)
{
uint8_t ack;
for (int i = 0; i < 8; i++)
{
// 高在前低在后
if (dat & 0x80)
I2C_Write_SDA(GPIO_PIN_SET);
else
I2C_Write_SDA(GPIO_PIN_RESET);
I2C_Delay();
I2C_Write_SCL(GPIO_PIN_SET);
I2C_Delay(); //延時(shí)至少4us
I2C_Write_SCL(GPIO_PIN_RESET);
dat <<= 1; //低位向高位移動
}
ack = IIC_Get_ACK();
return ack;
}
/**
* @brief I2C讀取1Byte數(shù)據(jù)
* @param ack:應(yīng)答 0 應(yīng)答 1 不應(yīng)達(dá)
* @return 接受到的數(shù)據(jù)
* @author HZ12138
* @date 2022-07-27 09:06:13
*/
uint8_t I2C_ReadByte(uint8_t ack)
{
uint8_t ret = 0;
// OLED_Read_SDA() 設(shè)置輸入方向
I2C_Write_SDA(GPIO_PIN_SET);
for (int i = 0; i < 8; i++)
{
ret <<= 1;
I2C_Write_SCL(GPIO_PIN_SET);
I2C_Delay();
// 高在前低在后
if (I2C_Read_SDA())
{
ret++;
}
I2C_Write_SCL(GPIO_PIN_RESET);
I2C_Delay();
}
IIC_Send_ACK(ack);
return ret;
}
#endif
/**
* @brief MUP6050 I2C連續(xù)寫
* @param addr:器件地址
* @param reg:寄存器地址
* @param len:長度
* @param buf:緩沖區(qū)地址
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 15:47:11
*/
uint8_t MPU_Write_Len(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
#if defined(MPU6050_Software_I2C)
uint8_t i;
I2C_Start();
I2C_SendByte((addr << 1) | 0); //發(fā)送器件地址+寫命令
I2C_SendByte(reg); //寫寄存器地址
for (i = 0; i < len; i++)
{
I2C_SendByte(buf[i]); //發(fā)送數(shù)據(jù)
}
I2C_End();
return 0;
#elif defined(MPU6050_Hardware_I2C)
HAL_I2C_Mem_Write(&MPU6050_I2C_Handle, MPU_WRITE, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 0xfff);
return 0;
#endif
}
/**
* @brief MUP6050 I2C連續(xù)讀
* @param addr:器件地址
* @param reg:寄存器地址
* @param len:長度
* @param buf:緩沖區(qū)地址
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 15:47:11
*/
uint8_t MPU_Read_Len(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
#if defined(MPU6050_Software_I2C)
I2C_Start();
I2C_SendByte((addr << 1) | 0); //發(fā)送器件地址+寫命令
I2C_SendByte(reg); //寫寄存器地址
I2C_Start();
I2C_SendByte((addr << 1) | 1); //發(fā)送器件地址+讀命令
while (len)
{
if (len == 1)
*buf = I2C_ReadByte(1); //讀數(shù)據(jù),發(fā)送nACK
else
*buf = I2C_ReadByte(0); //讀數(shù)據(jù),發(fā)送ACK
len--;
buf++;
}
I2C_End(); //產(chǎn)生一個(gè)停止條件
return 0;
#elif defined(MPU6050_Hardware_I2C)
HAL_I2C_Mem_Read(&MPU6050_I2C_Handle, MPU_READ, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 0xfff);
HAL_Delay(1);
return 0;
#endif
}
/**
* @brief MUP6050 I2C寫一個(gè)字節(jié)
* @param reg:寄存器地址
* @param data:數(shù)據(jù)
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 15:47:11
*/
uint8_t MPU_Write_Byte(uint8_t reg, uint8_t data)
{
#if defined(MPU6050_Software_I2C)
I2C_Start();
I2C_SendByte((MPU_ADDR << 1) | 0); //發(fā)送器件地址+寫命令
I2C_SendByte(reg); //寫寄存器地址
I2C_SendByte(data); //發(fā)送數(shù)據(jù)
I2C_End();
return 0;
#elif defined(MPU6050_Hardware_I2C)
return HAL_I2C_Mem_Write(&MPU6050_I2C_Handle, (MPU_ADDR << 1), reg, 1, &data, 1, 0xfff);
#endif
}
/**
* @brief MUP6050 I2C寫一個(gè)字節(jié)
* @param reg:寄存器地址
* @return 讀取到的數(shù)據(jù)
* @author HZ12138
* @date 2022-08-08 15:47:11
*/
uint8_t MPU_Read_Byte(uint8_t reg)
{
#if defined(MPU6050_Software_I2C)
uint8_t res;
I2C_Start();
I2C_SendByte((MPU_ADDR << 1) | 0); //發(fā)送器件地址+寫命令
I2C_SendByte(reg); //寫寄存器地址
I2C_Start();
I2C_SendByte((MPU_ADDR << 1) | 1); //發(fā)送器件地址+讀命令
res = I2C_ReadByte(1); //讀取數(shù)據(jù),發(fā)送nACK
I2C_End(); //產(chǎn)生一個(gè)停止條件
return res;
#elif defined(MPU6050_Hardware_I2C)
uint8_t zj;
HAL_I2C_Mem_Read(&MPU6050_I2C_Handle, (MPU_ADDR << 1), reg, 1, &zj, 1, 0xfff);
return zj;
#endif
}
特別注意:使用軟件I2C時(shí)請注意延遲函數(shù),不要過快(通信失敗),不要過慢(通信時(shí)間長)
void I2C_Delay()
MPU6050設(shè)置
這部分是借鑒自正點(diǎn)原子的內(nèi)容
#include "mpu6050.h"
#include "delay.h"
#include "usart.h"
#include "i2c.h"
#include "Print.h"
/**
* @brief 初始化MPU6050
* @param 無
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 14:51:59
*/
uint8_t MPU_Init(void)
{
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X80); //復(fù)位MPU6050
HAL_Delay(100);
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X00); //喚醒MPU6050
MPU_Set_Gyro_Fsr(3); //陀螺儀傳感器,±2000dps
MPU_Set_Accel_Fsr(0); //加速度傳感器,±2g
MPU_Set_Rate(50); //設(shè)置采樣率50Hz
MPU_Write_Byte(MPU_INT_EN_REG, 0X00); //關(guān)閉所有中斷
MPU_Write_Byte(MPU_USER_CTRL_REG, 0X00); // I2C主模式關(guān)閉
MPU_Write_Byte(MPU_FIFO_EN_REG, 0X00); //關(guān)閉FIFO
MPU_Write_Byte(MPU_INTBP_CFG_REG, 0X80); // INT引腳低電平有效
MPU_Read_Byte(MPU_DEVICE_ID_REG);
MPU_Write_Byte(MPU_PWR_MGMT1_REG, 0X01); //設(shè)置CLKSEL,PLL X軸為參考
MPU_Write_Byte(MPU_PWR_MGMT2_REG, 0X00); //加速度與陀螺儀都工作
MPU_Set_Rate(200); //設(shè)置采樣率為50Hz
return 0;
}
//設(shè)置MPU6050陀螺儀傳感器滿量程范圍
// fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
return MPU_Write_Byte(MPU_GYRO_CFG_REG, fsr << 3); //設(shè)置陀螺儀滿量程范圍
}
//設(shè)置MPU6050加速度傳感器滿量程范圍
// fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
return MPU_Write_Byte(MPU_ACCEL_CFG_REG, fsr << 3); //設(shè)置加速度傳感器滿量程范圍
}
//設(shè)置MPU6050的數(shù)字低通濾波器
// lpf:數(shù)字低通濾波頻率(Hz)
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
uint8_t MPU_Set_LPF(uint16_t lpf)
{
uint8_t data = 0;
if (lpf >= 188)
data = 1;
else if (lpf >= 98)
data = 2;
else if (lpf >= 42)
data = 3;
else if (lpf >= 20)
data = 4;
else if (lpf >= 10)
data = 5;
else
data = 6;
return MPU_Write_Byte(MPU_CFG_REG, data); //設(shè)置數(shù)字低通濾波器
}
//設(shè)置MPU6050的采樣率(假定Fs=1KHz)
// rate:4~1000(Hz)
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
uint8_t MPU_Set_Rate(uint16_t rate)
{
uint8_t data;
if (rate > 1000)
rate = 1000;
if (rate < 4)
rate = 4;
data = 1000 / rate - 1;
data = MPU_Write_Byte(MPU_SAMPLE_RATE_REG, data); //設(shè)置數(shù)字低通濾波器
return MPU_Set_LPF(rate / 2); //自動設(shè)置LPF為采樣率的一半
}
//得到溫度值
//返回值:溫度值(擴(kuò)大了100倍)
short MPU_Get_Temperature(void)
{
uint8_t buf[2];
short raw;
float temp;
MPU_Read_Len(MPU_ADDR, MPU_TEMP_OUTH_REG, 2, buf);
raw = ((uint16_t)buf[0] << 8) | buf[1];
temp = 36.53 + ((double)raw) / 340;
return temp * 100;
;
}
//得到陀螺儀值(原始值)
// gx,gy,gz:陀螺儀x,y,z軸的原始讀數(shù)(帶符號)
//返回值:0,成功
// 其他,錯(cuò)誤代碼
uint8_t MPU_Get_Gyroscope(short *gx, short *gy, short *gz)
{
uint8_t buf[6], res;
res = MPU_Read_Len(MPU_ADDR, MPU_GYRO_XOUTH_REG, 6, buf);
if (res == 0)
{
*gx = ((uint16_t)buf[0] << 8) | buf[1];
*gy = ((uint16_t)buf[2] << 8) | buf[3];
*gz = ((uint16_t)buf[4] << 8) | buf[5];
}
return res;
}
//得到加速度值(原始值)
// gx,gy,gz:陀螺儀x,y,z軸的原始讀數(shù)(帶符號)
//返回值:0,成功
// 其他,錯(cuò)誤代碼
uint8_t MPU_Get_Accelerometer(short *ax, short *ay, short *az)
{
uint8_t buf[6], res;
res = MPU_Read_Len(MPU_ADDR, MPU_ACCEL_XOUTH_REG, 6, buf);
if (res == 0)
{
*ax = ((uint16_t)buf[0] << 8) | buf[1];
*ay = ((uint16_t)buf[2] << 8) | buf[3];
*az = ((uint16_t)buf[4] << 8) | buf[5];
}
return res;
;
}
比較常用的是
short MPU_Get_Temperature(void)
獲取溫度
uint8_t MPU_Get_Gyroscope(short *gx, short *gy, short *gz)
獲取角加速度
uint8_t MPU_Get_Accelerometer(short *ax, short *ay, short *az)
獲取線加速度
這是MPU6050的初始化函數(shù),將器件ID的校驗(yàn)去掉了(因?yàn)槲疫@邊有個(gè)品牌的芯片讀取ID不正確但可以正常使用)
在程序開始時(shí)調(diào)用即可
uint8_t MPU_Init(void)
DMP設(shè)置
這部分是來自官方庫
DMP部分是不開源的,不然也不需要使用官方庫了
需要更改
inv_mpu.c
里的幾個(gè)API,關(guān)于時(shí)間,I2C和打印信息的部分
需要將
int mpu_init(void)
函數(shù)(在inv_mpu.c
)中的這段注釋并改成這個(gè)(光標(biāo)選中的)
重寫讀取歐拉角和初始化函數(shù),主要是去掉了幾個(gè)驗(yàn)證
/**
* @brief 初始化DMP
* @param 無
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 14:50:05
*/
uint8_t mpu_dmp_init(void)
{
uint8_t res = 0;
if (mpu_init() == 0) //初始化MPU6050
{
res = mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL); //設(shè)置所需要的傳感器
if (res)
return 1;
res = mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL); //設(shè)置FIFO
if (res)
return 2;
res = mpu_set_sample_rate(DEFAULT_MPU_HZ); //設(shè)置采樣率
if (res)
return 3;
res = dmp_load_motion_driver_firmware(); //加載dmp固件
if (res)
return 4;
res = dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation)); //設(shè)置陀螺儀方向
if (res)
return 5;
res = dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP | //設(shè)置dmp功能
DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO |
DMP_FEATURE_GYRO_CAL);
if (res)
return 6;
res = dmp_set_fifo_rate(DEFAULT_MPU_HZ); //設(shè)置DMP輸出速率(最大不超過200Hz)
if (res)
return 7;
res = run_self_test(); //自檢
// if(res)return 8;
res = mpu_set_dmp_state(1); //使能DMP
if (res)
return 9;
}
else
return 10;
return 0;
}
/**
* @brief 得到DMP處理后的歐拉角
* @param pitch:俯仰角( -90° - 90° )
* @param roll:橫滾角( -180° - 180° )
* @param yaw:航向角( -180° - 180° )
* @return 狀態(tài) 0成功 其他失敗
* @author HZ12138
* @date 2022-08-08 14:46:44
*/
uint8_t mpu_dmp_get_data(float *pitch, float *roll, float *yaw)
{
float q0 = 1.0f, q1 = 0.0f, q2 = 0.0f, q3 = 0.0f;
unsigned long sensor_timestamp;
short gyro[3], accel[3], sensors;
unsigned char more;
long quat[4];
if (dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more))
return 1;
/* Gyro and accel data are written to the FIFO by the DMP in chip frame and hardware units.
* This behavior is convenient because it keeps the gyro and accel outputs of dmp_read_fifo and mpu_read_fifo consistent.
**/
/*if (sensors & INV_XYZ_GYRO )
send_packet(PACKET_TYPE_GYRO, gyro);
if (sensors & INV_XYZ_ACCEL)
send_packet(PACKET_TYPE_ACCEL, accel); */
/* Unlike gyro and accel, quaternions are written to the FIFO in the body frame, q30.
* The orientation is set by the scalar passed to dmp_set_orientation during initialization.
**/
if (sensors & INV_WXYZ_QUAT)
{
q0 = quat[0] / q30; // q30格式轉(zhuǎn)換為浮點(diǎn)數(shù)
q1 = quat[1] / q30;
q2 = quat[2] / q30;
q3 = quat[3] / q30;
//計(jì)算得到俯仰角/橫滾角/航向角
*pitch = asin(-2 * q1 * q3 + 2 * q0 * q2) * 57.3; // pitch
*roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2 * q2 + 1) * 57.3; // roll
*yaw = atan2(2 * (q1 * q2 + q0 * q3), q0 * q0 + q1 * q1 - q2 * q2 - q3 * q3) * 57.3; // yaw
}
else
return 2;
return 0;
}
其他部分來自大魚電子的移植庫,無其他修改了
常用的函數(shù)就2個(gè)
DMP初始化函數(shù)
uint8_t mpu_dmp_init(void)
獲取歐拉角函數(shù)
uint8_t mpu_dmp_get_data(float *pitch, float *roll, float *yaw)
注意
1 通過DMP解算出的歐拉角順序是 Z-Y-X (這個(gè)很重要)
2.因?yàn)闆]有地磁計(jì),所以z(yow)的零點(diǎn)漂移會很嚴(yán)重,基本上沒法看
3.mpu6050是相對位置,是基于上電時(shí)的位置計(jì)算的(但是好像DMP有自己的修正算法,可以讓數(shù)據(jù)幾乎保持絕對)
4.盡量在水平位置上電,即使dmp有修正也會出現(xiàn)10°以上的誤差
成品
GitHub文章來源:http://www.zghlxwxcb.cn/news/detail-446219.html
百度網(wǎng)盤文章來源地址http://www.zghlxwxcb.cn/news/detail-446219.html
到了這里,關(guān)于【STM32F4系列】【HAL庫】【模塊介紹】MPU6050設(shè)置與DMP庫使用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!