1.BMI088惯性传感器介绍

1.1传感器原理图


传感器采用3.3V供电,使用SPI/IIC通讯模式(本文采用SPI通讯协议)。

1.2传感器功能介绍


***注:***这里提到的数据读取频率 2000Hz是陀螺仪的数据最快读取频率,其加速度计的数据最快读取频率为1600Hz,加速度测量单位g为重力加速度,陀螺仪测量单位°/s为角度单位,这里注意角度制和弧度制的区别,三角函数使用的是弧度制。
陀螺仪传感器内部寄存器对照表:

加速度传感器内部寄存器对照表:

***注意:***BMI088作为一款成熟的惯性器件,可以读取传感器当前工作温度,但是温度传感器挂载与加速度计部分,这也就是说如果准备做温度补偿,需要在读取加速度计数据的同时读取温度数据。
数据读取模式选择:读取频率、数据范围、以及滤波带宽的选择:
加速度计部分:


陀螺仪部分:


详细说明以及官方例程请见:
链接:https://pan.baidu.com/s/1OeIyNdDWo1UlggMcK_LXlg
提取码:6789
–来自百度网盘超级会员V4的分享

2.BMI088陀螺仪数据读取

2.1传感器初始化配置

BMI088.c文件:

/*!**************************************************** @file: BMI088.c* @brief: 用于配置BMI088陀螺仪 加速度计的各项参数并读取数据* @author:        * @date:2022/05/31* @note:   ****************************************************/
#include "BMI088.h"
#include "spi.h"
#define SPI1_ACC_Enable       {  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0
#define SPI1_ACC_Disable       {  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0
#define SPI1_GYRO_Enable     {  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);}//PA4 PB0
#define SPI1_GYRO_Disable     {  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);}//PA4 PB0#define CS_GYRO  0
#define CS_ACC   1#define BOARD_IMU 0
#define FLOAT_IMU 1/* 用于读取BMI088温度数据 */
#define BMI088_accel_read_muli_reg(reg, data, len) \{                                              \BMI088_ACCEL_NS_L();                       \BMI088_read_write_byte((reg) | 0x80);      \BMI088_read_muli_reg(reg, data, len);      \BMI088_ACCEL_NS_H();                       \}/*!**************************************************** @file: BMI088.c* @brief: 用于BMI088传感器中的软件延时* @author:        * @date:2022/05/31* @note:    ****************************************************/
static void BMI088_Delay(int times)
{delay_ms(times);
}/*!**************************************************** @file: BMI088.c* @brief: 通过SPI通讯总线读取和发送传感器数据* @author:        * @date:2022/05/31* @note:  ****************************************************/
static uint8_t BMI088_SPIReadSend(uint8_t data)
{uint8_t ret = 0xff;HAL_SPI_TransmitReceive(&hspi1, &data, &ret, 1, 0xffff);return ret;
}/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪的数据* @author:        * @date:2022/05/31* @note:   已经知道读取陀螺仪数据的函数,如果想使用数据,需要知道滤波函数的用法****************************************************/
static uint8_t BMI088_Read_GYRO(uint8_t Addr, int BOARD_OR_FLOAT)
{uint8_t val;SPI1_GYRO_EnableBMI088_SPIReadSend(Addr | 0x80);val = (uint8_t)(BMI088_SPIReadSend(0x00) & 0xFF);SPI1_GYRO_Disable;return val;
}/*!**************************************************** @file: BMI088.c* @brief: 用于读取加速度计的数据* @author:        * @date:2022/05/31* @note:  已经知道读取加速度计数据的函数,如果想使用数据,需要知道滤波函数的用法****************************************************/
static uint8_t BMI088_Read_ACC(uint8_t Addr, int BOARD_OR_FLOAT)
{uint8_t val;SPI1_ACC_EnableBMI088_SPIReadSend(Addr | 0x80);BMI088_SPIReadSend(0x00) ;val = (uint8_t)(BMI088_SPIReadSend(0x00) & 0xFF);SPI1_ACC_Disablereturn val;
}/*!**************************************************** @file: BMI088.c* @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法* @author:        * @date:2022/05/31* @note: ****************************************************/
static void BMI088_Write_Reg(uint8_t Addr, uint8_t Val, uint8_t ACC_OR_GYRO)
{if (ACC_OR_GYRO == CS_ACC){SPI1_ACC_Enable}else if (ACC_OR_GYRO == CS_GYRO){SPI1_GYRO_Enable}BMI088_SPIReadSend(Addr & 0x7f);BMI088_SPIReadSend(Val);if (ACC_OR_GYRO == CS_ACC){SPI1_ACC_Disable}else if (ACC_OR_GYRO == CS_GYRO){SPI1_GYRO_Disable}
}/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的加速度计* @author:        * @date:2022/05/31* @note: 配置加速度计产生中断的IO口的输出方式,数据输出频率1600hz加速度量程是 ±24g 有点大,目前的车无需这么大的量程****************************************************/
/*** @brief  * @retval  尝试降低采样率是否能提高数据稳定性* @date: 2021/10/17*/
int ret = 0;
static uint8_t BMI088_ACC_Congfig(int BOARD_OR_FLOAT)
{SPI1_ACC_Disable;BMI088_Write_Reg(0x7e, 0xb6, CS_ACC);//Soft Resetwhile (BMI088.acc_id != ACC_CHIP_ID) //Rising edge ,turn to spi{BMI088_Delay(100);BMI088.acc_id = BMI088_Read_ACC(0x00, BOARD_OR_FLOAT); //id:1E}BMI088_Delay(50);//> 1 ms ;ret = 0;while (ret != ACC_ON){ret = BMI088_Read_ACC(ACC_PWR_CTRL, BOARD_OR_FLOAT);BMI088_Write_Reg(ACC_PWR_CTRL, ACC_ON, CS_ACC);BMI088_Delay(5);}**/* 可根据实际使用和加速度寄存器表修改加速度计测量范围 */**while (BMI088_Read_ACC(ACC_RANG, BOARD_OR_FLOAT) != Plus_Minus_24G){BMI088_Write_Reg(ACC_RANG, Plus_Minus_24G, CS_ACC); //ACC Rang +- 24g;//BMI088_Delay(5);}while (BMI088_Read_ACC(0x40, BOARD_OR_FLOAT) != 0xBC){/* 可根据实际使用和加速度寄存器表修改加速度计数据读取频率 */BMI088_Write_Reg(0x40, 0xBC, CS_ACC); //BMI088_Delay(5);}while (BMI088_Read_ACC(0X53, BOARD_OR_FLOAT) != 0X08){BMI088_Write_Reg(0X53, 0X08, CS_ACC); //0000 1000 INT1 OUTPUT PUSH-PULL  Active lowBMI088_Delay(5);}while (BMI088_Read_ACC(0X54, BOARD_OR_FLOAT) != 0X08){BMI088_Write_Reg(0X54, 0X08, CS_ACC); //0000 1000 INT2 OUTPUT PUSH-PULL  Active lowBMI088_Delay(5);}while (BMI088_Read_ACC(0X58, BOARD_OR_FLOAT) != 0x44){BMI088_Write_Reg(0X58, 0x44, CS_ACC); //0100 0100 data ready interrupt to INT1 and INT2BMI088_Delay(5);}BMI088_Delay(20);//>1mswhile (BMI088_Read_ACC(ACC_PWR_CONF, BOARD_OR_FLOAT) != ACC_ACTIVE){BMI088_Write_Reg(ACC_PWR_CONF, ACC_ACTIVE, CS_ACC); //ACtive modeBMI088_Delay(600);//>50ms}return 0;
}/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪* @author:        * @date:2022/05/31* @note:  配置陀螺仪产生中断的IO口的输出方式,数据输出频率2000hz****************************************************/
static uint8_t BMI088_GYRO_Congfig(int BOARD_OR_FLOAT)
{SPI1_ACC_Disable;while (BMI088.gyro_id != GYRO_CHIP_ID){BMI088.gyro_id = BMI088_Read_GYRO(0x00, BOARD_OR_FLOAT); //0x0fBMI088_Delay(5);}while (BMI088_Read_GYRO(GYRO_RANG, BOARD_OR_FLOAT) != Plus_Minus_2000){BMI088_Write_Reg(GYRO_RANG, Plus_Minus_2000, CS_GYRO);// rang +-2000BMI088_Delay(5);}//bit #7 is Read Only/* 可根据陀螺仪寄存器对照表陀螺仪采样率是2000hz */BMI088_Write_Reg(GYRO_BANDWIDTH, ODR_1000_FD_116, CS_GYRO);while (BMI088_Read_GYRO(0X11, BOARD_OR_FLOAT) != 0x00){BMI088_Write_Reg(0X11, 0x00, CS_GYRO);//normalBMI088_Delay(5);}while (BMI088_Read_GYRO(0X15, BOARD_OR_FLOAT) != 0X80){BMI088_Write_Reg(0X15, 0X80, CS_GYRO);// //interruptBMI088_Delay(5);}while (BMI088_Read_GYRO(0X16, BOARD_OR_FLOAT) != 0X00){BMI088_Write_Reg(0X16, 0X00, CS_GYRO);//OUTPUT PUSH-PULL  Active lowBMI088_Delay(5);}while (BMI088_Read_GYRO(0X18, BOARD_OR_FLOAT) != 0X81){BMI088_Write_Reg(0X18, 0X81, CS_GYRO);//data ready interrupt to INT1 and INT2BMI088_Delay(5);}return 0;
}/*****************************以下几个函数用于读取BMI088传感器的温度数据****************************/
/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪加速度传感器高八位数据* @author:        * @date:2022/05/31* @note:    参考的大疆源码BMI088传感器的温度补偿控制温度传感器应该是挂载在加速度传感器上,所以读取温度需要使用加速度传感器****************************************************/
static void BMI088_ACCEL_NS_H(void)
{HAL_GPIO_WritePin(CS1_ACCEL_GPIO_Port, CS1_ACCEL_Pin, GPIO_PIN_SET);
}/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪加速度传感器低八位数据* @author:        * @date:2022/05/31* @note:   参考的大疆源码BMI088传感器的温度补偿控制温度传感器应该是挂载在加速度传感器上,所以读取温度需要使用加速度传感器****************************************************/
static void BMI088_ACCEL_NS_L(void)
{HAL_GPIO_WritePin(CS1_ACCEL_GPIO_Port, CS1_ACCEL_Pin, GPIO_PIN_RESET);
}/*!**************************************************** @file: BMI088.c* @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法* @author:        * @date:2022/05/31* @note: 该函数与 BMI088_Write_Reg 函数不同,使用的时候需要注意****************************************************/
static uint8_t BMI088_read_write_byte(uint8_t txdata)
{uint8_t rx_data;HAL_SPI_TransmitReceive(&hspi1, &txdata, &rx_data, 1, 1000);return rx_data;
}/*!**************************************************** @file: BMI088.c* @brief: 用于读取BMI088传感器中多个寄存器的数据* @author:        * @date:2022/05/31* @note:   参考的大疆源码BMI088传感器的温度补偿控制****************************************************/
static void BMI088_read_muli_reg(uint8_t reg, uint8_t *buf, uint8_t len)
{BMI088_read_write_byte(reg | 0x80);while (len != 0){*buf = BMI088_read_write_byte(0x55);buf++;len--;}
}
/***************************************************************************************************//*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪和加速度计* @author:        * @date:2022/05/31* @note: ****************************************************/
uint8_t BMI088_FLOAT_ACC_GYRO_Init(void)
{BMI088_ACC_Congfig(FLOAT_IMU);BMI088_GYRO_Congfig(FLOAT_IMU);return 1;
}/*!**************************************************** @file: BMI088.c* @brief: 用于读取传感器的温度* @author:        * @date: 2021/10/18* @note:  读取出来温度进行温度补偿****************************************************/
void BMI088_Read_TMP(float *temperate)
{int16_t bmi088_raw_temp;bmi088_raw_temp = (int16_t)((BMI088.temp_originalbuff[0] << 3) | (BMI088.temp_originalbuff[1] >> 5));if (bmi088_raw_temp > 1023){bmi088_raw_temp -= 2048;}*temperate = bmi088_raw_temp * BMI088_TEMP_FACTOR + BMI088_TEMP_OFFSET;
}/* 按键外部中断定义变量 */
extern uint8_t exit_flag;
extern uint8_t rising_falling_flag;/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪* @author:        * @date:2022/05/31* @note:    I/O外部中断回调函数,用于接收陀螺仪和加速度数据****************************************************/
/* 定义变量用于读取陀螺仪数据具体传输频率 */
int16_t Gyro_Cnt = 0;
void  HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if( mtime.Init_OK!=1)return;switch (GPIO_Pin){case GPIO_PIN_4://ACCBMI088.ACC.buff[0] = BMI088_Read_ACC(0X12, FLOAT_IMU);BMI088.ACC.buff[1] = BMI088_Read_ACC(0X13, FLOAT_IMU);BMI088.ACC.buff[2] = BMI088_Read_ACC(0X14, FLOAT_IMU);BMI088.ACC.buff[3] = BMI088_Read_ACC(0X15, FLOAT_IMU);BMI088.ACC.buff[4] = BMI088_Read_ACC(0X16, FLOAT_IMU);BMI088.ACC.buff[5] = BMI088_Read_ACC(0X17, FLOAT_IMU);**/* 用于读取传感器的温度 */BMI088_accel_read_muli_reg(BMI088_TEMP_M, BMI088.temp_originalbuff, 2);**break;case GPIO_PIN_5://GYROBMI088.GYRO.buff[0] = BMI088_Read_GYRO(0X02, FLOAT_IMU);BMI088.GYRO.buff[1] = BMI088_Read_GYRO(0X03, FLOAT_IMU);BMI088.GYRO.buff[2] = BMI088_Read_GYRO(0X04, FLOAT_IMU);BMI088.GYRO.buff[3] = BMI088_Read_GYRO(0X05, FLOAT_IMU);BMI088.GYRO.buff[4] = BMI088_Read_GYRO(0X06, FLOAT_IMU);BMI088.GYRO.buff[5] = BMI088_Read_GYRO(0X07, FLOAT_IMU);/* 陀螺仪的引脚触发中断一次,计数+1,用于确定陀螺仪传感器实际的传输频率break;default:break;}
}

BMI088.h文件:

/*!**************************************************** @file: BMI088.c* @brief: 用于配置BMI088陀螺仪 加速度计的各项参数并读取数据* @author:   * @date: 2022/05/31* @note:   ****************************************************/
#ifndef __BMI088_H__
#define __BMI088_H__#define ACC_CHIP_ID 0X1E#define ACC_PWR_CTRL  0X7D
#define ACC_OFF  0X00
#define ACC_ON  0X04#define ACC_PWR_CONF  0X7C
#define ACC_ACTIVE  0X00
#define ACC_SUSPEND  0X03/* 加速度量程范围设定 */
#define ACC_RANG  0X41
#define Plus_Minus_3G  0X00
#define Plus_Minus_6G  0X01
#define Plus_Minus_12G  0X02
#define Plus_Minus_24G  0X03/* 加速度信号输出频率设定 */
#define BMI088_ACC_ODR_SHFITS 0x0
#define BMI088_ACC_12_5_HZ (0x5 << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_25_HZ (0x6 << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_50_HZ (0x7 << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_100_HZ (0x8 << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_200_HZ (0x9 << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_400_HZ (0xA << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_800_HZ (0xB << BMI088_ACC_ODR_SHFITS)
#define BMI088_ACC_1600_HZ (0xC << BMI088_ACC_ODR_SHFITS)#define GYRO_CHIP_ID 0X0F#define GYRO_RANG  0X0F
#define Plus_Minus_2000  0X00
#define Plus_Minus_1000  0X01
#define Plus_Minus_500   0X02
#define Plus_Minus_250   0X03
#define Plus_Minus_125   0X04#define    GYRO_BANDWIDTH  0X10
/* 2000代表采样频率,532代表数据宽度 */
#define ODR_2000_FD_532  0X00
#define ODR_2000_FD_230  0X01
#define ODR_1000_FD_116  0X02
#define ODR_400_FD_47  0X03
#define ODR_200_FD_23  0X04
#define ODR_100_FD_12 0X05
#define ODR_200_FD_64 0X06
#define ODR_100_FD_32 0X07/* 温度读取 */
#define BMI088_TEMP_M 0x22#define BMI088_TEMP_L 0x23
#define BMI088_TEMP_FACTOR 0.125f
#define BMI088_TEMP_OFFSET 23.0f/*!**************************************************** @file: BMI088.c* @brief: 用于BMI088传感器中的软件延时* @author:   * @date: 2022/05/31* @note: ****************************************************/
static void BMI088_Delay(int times);/*!**************************************************** @file: BMI088.c* @brief: 通过SPI通讯总线读取和发送传感器数据* @author:   * @date: 2022/05/31* @note:   ****************************************************/
static uint8_t BMI088_SPIReadSend(uint8_t data);/*!**************************************************** @file: BMI088.c* @brief: 用于读取加速度计的数据* @author:   * @date: 2022/05/31* @note:   已经知道读取加速度计数据的函数,如果想使用数据,需要知道滤波函数的用法****************************************************/
static uint8_t BMI088_Read_ACC(uint8_t Addr, int BOARD_OR_FLOAT);/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪的数据* @author:   * @date: 2022/05/31* @note:   已经知道读取陀螺仪数据的函数,如果想使用数据,需要知道滤波函数的用法****************************************************/
static uint8_t BMI088_Read_GYRO(uint8_t Addr, int BOARD_OR_FLOAT);/*!**************************************************** @file: BMI088.c* @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法* @author:   * @date: 2022/05/31* @note:    ****************************************************/
static void BMI088_Write_Reg(uint8_t Addr, uint8_t Val, uint8_t ACC_OR_GYRO);/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的加速度计* @author:   * @date: 2022/05/31* @note:****************************************************/
static uint8_t BMI088_ACC_Congfig(int BOARD_OR_FLOAT);/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪* @author:   * @date: 2022/05/31* @note:****************************************************/
static uint8_t BMI088_GYRO_Congfig(int BOARD_OR_FLOAT);/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪加速度传感器高八位数据* @author:   * @date: 2022/05/31* @note:****************************************************/
static void BMI088_ACCEL_NS_H(void);/*!**************************************************** @file: BMI088.c* @brief: 用于读取陀螺仪加速度传感器低八位数据* @author:   * @date: 2022/05/31* @note:****************************************************/
static void BMI088_ACCEL_NS_L(void);/*!**************************************************** @file: BMI088.c* @brief: 用于写传感器配置,如果需要改变传感器参数使用该方法* @author:   * @date: 2022/05/31* @note:****************************************************/
static uint8_t BMI088_read_write_byte(uint8_t txdata);/*!**************************************************** @file: BMI088.c* @brief: 用于读取BMI088传感器中多个寄存器的数据* @author:   * @date: 2022/05/31* @note:****************************************************/
static void BMI088_read_muli_reg(uint8_t reg, uint8_t *buf, uint8_t len);/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪和加速度计* @author:   * @date: 2022/05/31* @note: ****************************************************/
uint8_t BMI088_FLOAT_ACC_GYRO_Init(void);/*!**************************************************** @file: BMI088.c* @brief: 用于配置初始化传感器中的陀螺仪和加速度计* @author:   * @date: 2022/05/31* @note: ****************************************************/
uint8_t BMI088_FLOAT_ACC_GYRO_Init(void);/*!**************************************************** @file: BMI088.c* @brief: 用于读取传感器的温度* @author:   * @date: 2021/10/18* @note:   读取出来温度进行温度补偿****************************************************/
void BMI088_Read_TMP(float *temperate);
#endif

以上部分主要根据加速度计和陀螺仪的寄存器对照表为参照,可根据个人实际使用状况进行配置,毕竟并不是所有场合都会出现±24g的重力加速度情况的。
BMI088传感器的基础配置程序和通过I/O中断读取的程序全部展示出来了,这里BMI088与MCU之间通讯方式为SPI,并采用的MCU上的硬件SPI进行读取,所以以上代码如果想顺利运行起来,需要事先完成硬件SPI总线配置,这里简单展示一下SPI的配置代码以及传感器的初始化函数:

/* SPI1通讯配置
*/
/** SPI主从模式设定       主机模式SPI方向设定             双向SPI通讯模式数据长度设定         8位数据长度时钟优先级设定       低优先级时钟阶段设定          一个时钟阶段对应一个边沿SPI-NSS引脚设定     软件NSS波特率预分频设定   64分配SPI通讯首位             主机标志位定时器模式              不使能CRC校验模式              不使能CRCPoly正常模式      10* @brief: 使用CbueMX配置生成的SPI通讯配置代码* @date: 2022/05/31* @note:
*/
void MX_SPI1_Init(void)
{hspi1.Instance = SPI1;hspi1.Init.Mode = SPI_MODE_MASTER;hspi1.Init.Direction = SPI_DIRECTION_2LINES;hspi1.Init.DataSize = SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;hspi1.Init.NSS = SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;hspi1.Init.TIMode = SPI_TIMODE_DISABLE;hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;hspi1.Init.CRCPolynomial = 10;if (HAL_SPI_Init(&hspi1) != HAL_OK){Error_Handler();}
}
/* 进一步对SPI进行配置,包括引脚映射初始化 */
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(spiHandle->Instance==SPI1){/* SPI1 clock enable */__HAL_RCC_SPI1_CLK_ENABLE();__HAL_RCC_GPIOB_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**SPI1 GPIO ConfigurationPB4     ------> SPI1_MISOPB3     ------> SPI1_SCKPA7     ------> SPI1_MOSI*/GPIO_InitStruct.Pin = GPIO_PIN_4|GPIO_PIN_3;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_7;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);}
}/* 本函数具体作用是取消SPI对以上功能的配置 */
void HAL_SPI_MspDeInit(SPI_HandleTypeDef* spiHandle)
{if(spiHandle->Instance==SPI1){/* Peripheral clock disable */__HAL_RCC_SPI1_CLK_DISABLE();/**SPI1 GPIO ConfigurationPB4     ------> SPI1_MISOPB3     ------> SPI1_SCKPA7     ------> SPI1_MOSI*/HAL_GPIO_DeInit(GPIOB, GPIO_PIN_4|GPIO_PIN_3);HAL_GPIO_DeInit(GPIOA, GPIO_PIN_7);}
}

在根据以上代码配置完SPI通讯之后,只需要调用如下函数,即可完成对BMI088传感器的所有初始化:

 BMI088_FLOAT_ACC_GYRO_Init();

陀螺仪数据读取.c文件

/*!**************************************************** @brief: 用于配置对陀螺仪加速度计进行单位换算* @note: ****************************************************/#include "BMI088.h"
//陀螺仪零偏矫正
mpu BMI088;/*** @brief     读取陀螺仪的数据        * @retval  将读取出来的数据赋值给原始数* @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 2000hz*/
void BMI088_Read_Gyro_Data(void)
{BMI088.gyro.origin [xx] = BMI088.GYRO.data[xx];BMI088.gyro.origin [yy] = BMI088.GYRO.data[yy];BMI088.gyro.origin [zz] = BMI088.GYRO.data[zz];
}/*** @brief   读取加速度计的数据        * @retval  将读取出来的数据赋值给原始数*    @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 1600hz*/
void BMI088_Read_Acc_Data(void)
{BMI088.acc.origin [xx] = BMI088.ACC.data[xx];BMI088.acc.origin [yy] = BMI088.ACC.data[yy];BMI088.acc.origin [zz] = BMI088.ACC.data[zz];
}/*** @brief   读取温度     * @retval  将读取出来的数据赋值给原始数*    @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 1600hz*/
void BMI088_Read_Tmp_Data(void)
{BMI088_Read_TMP(&BMI088.Temperature);
}/*!**************************************************** @file: MYGYROData.c* @brief:读取加速度,并转换为 m/(s^2)* @note:   ****************************************************/
void IMU_Read(void)
{mpu *mympu=&BMI088;BMI088_Read_Gyro_Data();   /* 读取陀螺仪数据 */BMI088_Read_Acc_Data();        /* 读取加速度数据 */mympu->gyro.dps[xx]  = mympu->gyro.origin[xx] * MPU_GYRO_TO_DPS;mympu->gyro.dps[yy]  = mympu->gyro.origin[yy] * MPU_GYRO_TO_DPS;mympu->gyro.dps[zz]  = mympu->gyro.origin[zz] * MPU_GYRO_TO_DPS;mympu->acc.m_s_2 [xx] = mympu->acc.origin[xx] * MPU_ACCE_M_S_2;mympu->acc.m_s_2 [yy] = mympu->acc.origin[yy] * MPU_ACCE_M_S_2;mympu->acc.m_s_2 [zz] = mympu->acc.origin[zz] * MPU_ACCE_M_S_2;
}

陀螺仪数据读取.h文件

/*!**************************************************** @file: MYGYROData.c* @brief: 用于配置对陀螺仪加速度计进行数据单位换算* @note: ****************************************************/
#define BMI088 BMI088
#define xx 0
#define yy 1
#define zz 2#define G_Z 0/*陀螺仪加速度计去零漂方式选择*/#define MPU_ACC_CALOFFSET_AUTO
#define  MPU_GROY_CALOFFSET_AUTO
/*---------------------------------------------*/#define XAISN   (3)  //3个坐标
#define ITEMS  6
#define MPU9250_FILTER_NUM   4
#define MPU_CORRECTION_FLASH     0x0800F000        //存储校正数据的FLASH地址,SIZE=6*3*4字节
#define GG 9.8                                                          // 重力加速?
/* 现在量程设定为±6g */
#define MPU_ACCE_M_S_2 (24.0 * GG / 32768.0) //单位换算,将LSB化为m/(s^2),GG前面的"X"需根据量程修改
#define MPU_GYRO_TO_DPS (2000 / 32768.0)    //单位换算,将LSB化为 gegree/s
#define MPU_MAGN_TO_GS (4800 / 16384.0 / 100.0)            //单位换算,将LSB化为Gs
#define MPU_MAGN_TO_UT (4800 / 16384.0)            //单位换算,将GS化为UT
#define MPU_TEMP_K (0.002995177763f)            //degC/LSBtypedef struct _accdata
{short origin[XAISN];  //原始值float offset[XAISN];      //零偏值float offset_max[XAISN];  //零偏值最大值float offset_min[XAISN];  //零偏值最小值float calibration[XAISN]; //校准值float filter[XAISN];      //滑动平均滤波值float m_s_2[XAISN];      //米每二次方秒
} accdata;
typedef struct _gyrodata
{short origin[XAISN];  //原始值float offset_max[XAISN];  //零偏值最大值float offset_min[XAISN];  //零偏值最小值float offset[XAISN];      //零偏值float calibration[XAISN]; //校准值float filter[XAISN];      //滑动平均滤波值float dps[XAISN];         //度每秒float radps[XAISN];       //弧度每秒/* 2022-01-11 加入滑动滤波 */float last_filter[XAISN];
} gyrodata;struct _mpu
{accdata acc;gyrodata gyro;float Temperature;uint8_t acc_id, gyro_id;union{int16_t data[3];uint8_t buff[6];} ACC, GYRO;uint8_t temp_originalbuff[2];uint8_t gyro_times;uint8_t acc_times;enum{ReadingACC,ReadingGYRO,IDLE,} state;float pitch;float roll;float yaw;float lastyaw;/* 记录陀螺仪累计旋转多少度 */float yawsum;/* 陀螺仪动态数据矫正 */uint8_t DynamicOffsetEnable; // 是否进行动态校准标志位int32_t DynamicTmp[3];                // 动态数据累加uint32_t DynamicTimes;             // 校准时间计数uint16_t OffsetCnt;                        // 校准周期uint16_t OffsetErrorRange;       // 校准误差范围float gyro_z;int16_t yaw_turns;
};typedef struct _mpu mpu;
extern mpu BMI088;/*** @brief  读取陀螺仪的数据        * @retval  将读取出来的数据赋值给原始数* @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 2000hz*/
void BMI088_Read_Gyro_Data(void);/*** @brief   读取加速度计的数据        * @retval  将读取出来的数据赋值给原始数*    @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 1600hz*/
void BMI088_Read_Acc_Data(void);/*** @brief    读取温度     * @retval  将读取出来的数据赋值给原始数*    @note   data数据长度是3  原始数据长度是3  采集出来的数据就是原始数据* @attention 从这开始实际的频率编程 1600hz*/
void BMI088_Read_Tmp_Data(void);/*!**************************************************** @file: MYGYROData.c* @brief:读取加速度,并转换为 m/(s^2)* @note:    ****************************************************/
void IMU_Read(void);

以上代码如何使用将在第三章进行展现。

3.BMI088陀螺仪数据处理:

通过碰撞测试发现,180s时间内BMI088会产生15度的0点漂移,碰撞时的振动以及底盘加减速带来的冲击确实会使得陀螺仪0点发生漂移,但是加减速带来的冲击对陀螺仪的数据影响最大,也就是说在车运动过程中突然换因为惯性打滑导致车体的振动对传感器数据的影响更大。
决定使用MATLAB调用FFT函数,观测信号频谱图,根据信号频谱确定基波频率和主要谐波频率,然后使用二阶低通滤波算法,确定采样频率和截止频率,将滤波效果最大化,提高代码的运行效率。
4096点FFT的MATLAB代码如下:

clear  all
clc%测试代码
%t = 0:0.005:1;  %时间间隔为0.005 采样频率为200hz
%x= sin(2*pi*30*t)+sin(2*pi*500*t);   %N = 4096; %使用1024点快速傅里叶变换
filename = '33.xlsx';    %读取数据
x = xlsread(filename);
f=x;
subplot(121);
plot(f);                            %画出原始信号的波形图
ylabel('幅值');
xlabel('时间');
title('原始信号');
y=abs(fft(f,N));   %对原始信号进行离散傅里叶变换,参加DFT的采样点个数为Nff=200*(0:(N/2-1))/N;              %计算变换后不同点所对应的频率值    N点只需打印一半即可,另一半是对称的subplot(122);
plot(ff,y(1:(N/2)));                    %画出信号的频谱图
ylabel('功率谱密度');
xlabel('频率');
title('信号功率谱图')

得出部分数据频谱图如下所示(左侧为原始数据,右侧为数据频谱图):





这里就不公开数据集了,因为采用不同的测试平台,采集到的数据波形可能是不同的,通过观察以上频谱图可以确定基波频率在0-5Hz,10Hz附近的信号频率即可认为是高频谐波,于是采用二阶低通滤波的方式,采样频率设定为50hz,截止频率设置为10hz,传感器中断读取频率为1000hz,滤波算法执行频率为500hz,采用积分的方法,以0.002s为单位时间进行积分,最终得到当前效果,在运行过程中,启动停止,突然换向以及撞击所造成的陀螺仪数据抖动,基本上可以说完全消除,不旋转只撞击的情况下,240s内yaw轴数据可以稳定在1.5°以内。
二阶低通滤波代码如下:

/*** @brief  二阶低通滤波函数       * @param[in]   对应传感器   * @param[in]   样本数据频率* @param[in]   截止频率* @retval         none* @note*/
void LPF2pSetCutoffFreq(int index, float sample_freq, float cutoff_freq)
{LPF *lpf;lpf = &lpf4[index];float fr = 0;float ohm = 0;float c = 0;fr = sample_freq / cutoff_freq;ohm = tanf(M_PI_F / fr);c = 1.0f + 2.0f * cosf(M_PI_F / 4.0f) * ohm + ohm * ohm;/* 直接给出截止频率减少运算步骤 */lpf->_cutoff_freq1 = cutoff_freq;if (lpf->_cutoff_freq1 > 0.0f){lpf->_b01 = ohm * ohm / c;lpf->_b11 = 2.0f * lpf->_b01;lpf->_b21 = lpf->_b01;lpf->_a11 = 2.0f * (ohm * ohm - 1.0f) / c;lpf->_a21 = (1.0f - 2.0f * cosf(M_PI_F / 4.0f) * ohm + ohm * ohm) / c;}
}/*** @brief  二阶低通滤波函数   * @param[in]   对应传感器   * @param[in]   样本数据* @retval 二阶低通滤波函数*/
float LPF2pApply(int index, float sample)
{LPF *lpf;lpf = &lpf4[index];float delay_element_0 = 0, output = 0;if (lpf->_cutoff_freq1 <= 0.0f){// no filteringreturn sample;}else{delay_element_0 = sample - lpf->_delay_element_11 * lpf->_a11 - lpf->_delay_element_21 * lpf->_a21;// do the filteringif (isnan(delay_element_0) || isinf(delay_element_0)){// don't allow bad values to propogate via the filterdelay_element_0 = sample;}output = delay_element_0 * lpf->_b01 + lpf->_delay_element_11 * lpf->_b11 + lpf->_delay_element_21 * lpf->_b21;lpf->_delay_element_21 = lpf->_delay_element_11;lpf->_delay_element_11 = delay_element_0;// return the value.  Should be no need to check limitsreturn output;}
}

在采用二阶低通滤波之后,发现如果因为其它原因带来的尖峰数据会对陀螺仪Yaw轴积分结果造成影响,这里先对原始数据进行平滑滤波处理,平滑滤波之后再进行二次低通滤波,最终对数据积分得到Yaw轴角度:
平滑滤波处理:

/*!**************************************************** @file: IMU.c* @brief: 对陀螺仪的数据进行处理* @date: 2021/12/25****************************************************/
#define BMI088_FILTER_NUM   10
#define BMI088_ITEMS  3
void IMU_Filter(void)
{u8 i;/* 平滑滤波数组参数定义 */int32_t FILT_TMP[BMI088_ITEMS] = {0};static int16_t FILT_BUF[BMI088_ITEMS][BMI088_FILTER_NUM] = {0};BMI088_Read_Gyro_Data();    /* 读取陀螺仪数据 */for(i=BMI088_FILTER_NUM - 1;i>=1;i--){FILT_BUF[zz][i] = FILT_BUF[zz][i-1];}FILT_BUF[zz][0] = BMI088.gyro.origin[zz];for(i=0; i<BMI088_FILTER_NUM; i++){FILT_TMP[zz] += FILT_BUF[zz][i];}BMI088.gyro.last_filter[zz] = (float)(FILT_TMP[zz])/(float)BMI088_FILTER_NUM;  /* 滑动滤波 */BMI088.gyro.filter[zz] = LPF2pApply(GYRO_Z_LPF, BMI088.gyro.last_filter[zz]);    /* 二阶低通滤波 */BMI088.gyro.dps[zz] = BMI088.gyro.filter[zz] * MPU_GYRO_TO_DPS;    /* 得到角速度,单位:度/s */
}

经过处理后对数据进行积分,解算Yaw轴角度:

/*!**************************************************** @file: IMU.c* @brief:先处理零漂,然后进行陀螺仪数据处理使用积分方法对角速度数据进行积分计算yaw轴变化* @note: ****************************************************/
#define d_t 0.002f  //间隔2ms进行积分
#define Zero_Offset_Coun  (1 / d_t)   //去零漂
int16_t g_GetZero_Offset = 0;
float Gyroz_offset = 0.0f;
void IMU_Normalization(void)
{/* 计算零漂 */if( g_GetZero_Offset < Zero_Offset_Coun){Gyroz_offset += BMI088.gyro.dps[zz] * d_t;     /* 进行积分 */g_GetZero_Offset++;}BMI088.gyro.dps[zz] -= Gyroz_offset;   /* 除去零漂 *//* 零偏去除之后通过积分计算角度 */if(g_GetZero_Offset > Zero_Offset_Coun){BMI088.lastyaw += BMI088.gyro.dps[zz] * d_t;     /* 积分结算Yaw轴角度 */BMI088.gyro_z = BMI088.gyro.dps[zz];       /* 传递当前角速度数值 */}/* 将角度限制在±180° */if(BMI088.lastyaw > 180.0f){BMI088.lastyaw = BMI088.lastyaw - 360;BMI088.yaw_turns ++;}else if(BMI088.lastyaw < -180.0f){BMI088.lastyaw = BMI088.lastyaw + 360;BMI088.yaw_turns --;     }elseBMI088.lastyaw = BMI088.lastyaw;
}

截止到当前部分,针对于BMI088传感器的传感器配置、陀螺仪数据读取以及陀螺仪数据处理三方面内容基本上完整了。

4.BMI088陀螺仪温度补偿

这里的温度补偿不做过多赘述,采用普通的PID算法,在之前第二章提到的数据读取中,通过引脚中断的方式与加速度计一同读取出来当前温度,与设定温度进行PID控制即可,注意这里的温度控制频率尽量要高于数据处理的频率或者相等,但是最好不要比数据处理的频率低:

/*** @brief  温控任务    * @param[in] * @note:*/
void imu_temp_control_task(void)
{uint16_t tempPWM;/* 粗略计算5s,系统开始运行 */static uint32_t time = 0;//pid calculate. PID计算/* 温度读取 */BMI088_Read_Tmp_Data();PID_calc(&imu_temp_pid,BMI088.Temperature,40.0f);if (imu_temp_pid.out < 0.0f){imu_temp_pid.out = 0.0f;}tempPWM = (uint16_t)imu_temp_pid.out;  WenDuBuChang_PWM(tempPWM);if(BMI088.Temperature >= 40){/* 当读取的温度数据第一次大于40之后陀螺仪开始正常工作 */mtime.Temp_OK = 1;}
}

5.BMI088陀螺仪总结

总的来说改款陀螺仪的稳定性还是非常高的,比传统的MPU6050拥有更高的精度和更强的稳定性,但是存在的唯一的缺陷就是,该陀螺仪的陀螺仪数据读取频率和加速度计的读取频率,只有在400hz及以下时达成一致,这显然是非常难受的一件事,在高频段,陀螺仪采样频率是2000、1000、400hz,加速度计的采样率是1600、800、400hz,如果使用加速度计进行数据融合采用互补滤波的算法校准结算欧拉角,显然这种不同频的数据读取影响是非常大的,本人也是在尝试了多个融合算法之后发现,两个传感器数据不同步对结算的影响真的不小,所以根据实际应用场景,选择了对Yaw轴角速度进行积分结算出Yaw轴角度进行使用。

陀螺仪数据处理(BMI088)相关推荐

  1. (学习日记)2023.06.06

    写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈. 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈. 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录, ...

  2. 什么是陀螺仪的dr算法_陀螺仪与加速传感器数据的融合算法解析

    1.加速度计数据处理 为了实现代步车平平衡和运动控制,首先应该得到足够精确机器人车身倾角信息.根据两轮处自平衡车的应用环境,一般使用加速度器和陀螺仪两种传感器来采集代步车的姿态信息. 加速度计可能测量 ...

  3. 【51单片机】MPU6050陀螺仪控制舵机设计

    文章目录 一.主要功能 二.硬件资源 1.硬件准备 2.硬件连接 三.软件设计 1.软件结构 2.主要代码 四.实验现象 联系作者 一.主要功能 系统运行后,LCD1602显示MPU6050检测的欧拉 ...

  4. 平衡小车卡尔曼滤波算法

    最近研究STM32的自平衡小车,发现有两座必过的大山,一为卡尔曼滤波,二为PID算法. 网上看了很多关于卡尔曼滤波的代码,感觉写得真不咋地.一怒之下,自己重写,不废话,贴代码 [pre lang=&q ...

  5. 基于stm32的无人机控制系统设计

    基于stm32的无人机控制系统设计 **==整篇文章有两万字左右,字数太多了,实在是懒得全部放在这上面来,太废时间了.需要完整论文可主页联系==** 第一章 前言 1.1项目背景和意义 1.2国内外发 ...

  6. 从零开始写STM32平衡小车代码,从0到1

    从零开始写STM32平衡小车代码,从0到1 教你从零开始写STM32平衡小车代码 前言: 本人也是学生,只是分享一下自己的设计思路与代码教学. 这次STM32平衡小车是基于STM32CubeMX软件生 ...

  7. 【开源飞控】匿名飞控TI版解析(1)

    准备电赛的飞控题,买来了匿名的飞控学习一下,这里整理了一下匿名飞控中比较关键的几部分,学习了一下原理,然后代码解读都写注释里了,篇幅较长. 目录 一.遥控器信号接收 1.代码解读 2.ppm原理 二. ...

  8. STM32 Cubemax(十一) ——JY901陀螺仪数据的读取与简单数据处理

    STM32 Cubemax(十一) --JY901陀螺仪数据的读取与简单数据处理 文章目录 STM32 Cubemax(十一) --JY901陀螺仪数据的读取与简单数据处理 前言 JY901简单介绍 ...

  9. ardupilot BMI088加速度陀螺仪学习

    目录 文章目录 目录 摘要 1.BMI088简介 1.加速度特性 2.陀螺仪特性 3.安装方向及接线 4.常用的寄存器 1.加速度寄存器 2.陀螺仪寄存器 2.BMI088代码学习 1.BMI088初 ...

最新文章

  1. RT-Thread的位图调度算法分析(最新版)
  2. 创建型模式——工厂模式
  3. java 文件缓冲区_Java开发笔记(八十六)通过缓冲区读写文件
  4. ue默认高亮mysql_UE设置打开文件的默认高亮语言
  5. 工作流实战_14_flowable_已办任务列表查询
  6. jquery ajax xml attribute,获得jQuery ajax和asp.net webmethod xml响应工作
  7. JavaScript中BOM操作
  8. openwrt挂载u盘(ntfs)_如何在 Bitcoin 的源码基础上生成一条自己的链 08:将bitcoin移植到openwrt...
  9. 手机摇一摇功能音量大小跟系统音量一致
  10. CSS之设置p段落中的文字与页面左侧缩进两个字符!...
  11. java lambda表达式详解_java8新特性-Lambda表达式的详解(从0开始)
  12. 【原译】什么是TCHAR,WCHAR,LPSTR,LPWSTR,LPCTSTR.等等
  13. python 点击按钮回去entry值_python中tkinter入门之Checkbutton,Radiobutton和Entry
  14. java dateutils工具类_DateUtils 日期工具类
  15. 想回味Windows95?模拟器+浏览器搞定
  16. Unity3D游戏开发之反编译AssetBundle提取游戏资源
  17. 搭建无iDP证书的Xcode环境
  18. Retrofit2+RxJava2+ButterKnife框架搭建步骤
  19. 家谱网站 php,家谱网站大全
  20. UVA - 10118 Free Candies(记忆化搜索/状压)

热门文章

  1. pycharm+ideavim
  2. pygame 安装不上
  3. C语言零基础项目:打飞机游戏,300行源码分享+详细思路
  4. android+闪屏启动优化,Android分享笔记(2) APP启动时闪屏
  5. SpringBoot+Vue讲解系列介绍(本专辑实体书已出版)
  6. 手机游戏引擎 Cocos2d-x
  7. matlab预处理光谱数据,一种近红外光谱数据预处理方法与流程
  8. 100天精通Python(基础篇)——第17天:类属性和类方法
  9. 5g理论速度_严肃科普:5G的速度到底能有多快?
  10. python 中setattr()函数