【IMU】BMI160 Driver分析及使用

相关文章

1.《SPI通信协议介绍》
2.《STM32的SPI外设使用》
3.《【IMU】BMI160 Driver分析及使用》

1.什么是IMU?

IMU(英文:Inertial measurement unit,简称 IMU), 一般情况下,一个IMU内会装有三轴的陀螺仪和三个方向的加速度计,分别用来测量物体在三维空间中的角速度加速度,并以此解算出物体的姿态。为了提高可靠性,还可以为每个轴配备更多的传感器。一般而言IMU要安装在被测物体的重心上。

2.G-sensor工作原理

如图中的模型, 一个质量块两端通过弹簧进行固定。在没有加速度的情况下,弹簧不会发生形变,质量块静止。当产生加速度时,弹簧发生形变,质量块的位置会发生变化。 弹簧的形变量随着加速度的增大而增大。在弹簧的劲度系统 k 和质量块的质量 m已知的情况下,只要测量出弹簧的形变量,就可以求出系统的加速度。
在这里插入图片描述
G-sensor内部有 finger sets, 用来测量产生加速度读时质量块的位移。 每一个finger set 相当两个电容极板, 当有加速度时质量块会产生相对运动,而位移的变化会导致差分电容的变化。当然,具体的差分电容检测和计算加速度过程由G-sensor内部完成,我们只需要直接读取其转化后的值即可。G-sensor输出值也不是直接的加速度值,它的计量单位是通常用g表示,1g代表一个重力加速度,即9.8m/s^2。1g=1000mg。

G-sensor重要参数

  • 测量范围 Measurement Rang
    测量范围是传感器可以支持的输出加速度范围,通常用±g 表示。这就是G-sensor可以测量并准确输出的最大加速度。例如,一个测量范围是±8g G-sensor,它的输出一直到加速度达到±8g 时是线性的。

  • 灵敏度 Sensitivity
    灵敏度表示传感器输出随加速度(输入)变化的比例,它定义理想情况下加速度和传感器输出的直线关系。数字输出的传感器的灵敏度通常使用 LSB/g 表示。例如,一个灵敏度为S2g = 16384 LSB/g的G-sensor,若其Z轴输出为4205,则可计算出Z轴加速度为0.25g。(备注:参考BMI160 Datasheet)

  • 0g偏移 Zero-g Offset
    0g 偏置表示在没有加速度(零输入)时输出的测量值。不同型号的G-sensor的 Zero-g Offset 不同,同一型号的不同芯片的 0g-offset 也不同,甚至同一颗芯片中不同轴的 Zero-g Offset 也不同,是否需要校正要视具体应用而定。如果应用中只关心加速度的相对变化,而不关心加速度的具体数值,则不需要校正。如果是关心加速度的具体数值,而所选器件的 Zero-g Offset 又比较大,则必须要校正。某些G-sensor本身有 offset 寄存器,这是只需要把待校准的轴沿水平方向静止放置,测量其 0g 时的输出,并把这个值乘以-1 写入 offset 寄存器即可。如果G-sensor本身没有 offset 寄存器,则需要用户在自己的处理器中记录这个数值,并在实际的测量结果中减去这个 offset

  • 输出速率 ODR
    ODR(Output Data Rate),表示G-sensor的输出数据的刷新频率。ODR越高,输出数据更新越快,功耗越高。G-sensor的ODR往往都是可以配置的。(备注:BMI160 G-sensor最大刷新频率为1600Hz)

3.Gyro sensor工作原理

陀螺仪是用来测量角速率的器件,在加速度功能基础上,可以进一步发展,构建陀螺仪。陀螺仪内部原理是这样的:对固定指施加电压,并交替改变电压,让一个质量块做振荡式来回运动,当旋转时,会产生科里奥利加速度,此时就可以对其进行测量;这有点类似于加速度计,解码方法大致相同,都会用到放大器。
在这里插入图片描述
Gyro-sensor重要参数

  • Measurement Range
    测量范围是传感器可以支持的输出测量范围,通常用°/s 表示。这就是Gyro-sensor可以测量并准确输出的最大角度速度。
  • 灵敏度 Sensitivity
    灵敏度表示传感器输出随角速度变化的比例,它定义理想情况下角速度和传感器输出的直线关系。数字输出的传感器的灵敏度通常使用 LSB/°/s 表示。例如,一个灵敏度为RFS2000 = 16.4LSB/°/s的Gyro-sensor,若其Z轴输出为53,则可计算出Z轴角速度为3.23°/s。(备注:参考BMI160 Datasheet)
  • 0速度偏移 Zero-rate Offset
    0速度偏置表示在没有角速度(零输入)时输出的测量值。可以通过OFFSET寄存器做补偿在误差比较大的情况下,其实也可以在用户应用层去做补偿。
  • 输出速率 ODR
    ODR(Output Data Rate),表示Gyro-sensor的输出数据的刷新频率。ODR越高,输出数据更新越快,功耗越高。Gyro-sensor的ODR往往都是可以配置的。(备注:BMI160 Gyro-sensor最大刷新频率为3200Hz)

4.BMI160硬件介绍

使用STM32F103+BMI160硬件平台,通过SPI接口来读写数据。
在这里插入图片描述
STM32F103与BMI160的引脚连接如下:

MCU Pin Num 功能描述 BMI160 Pin Num
GPIOA4 CS P12
GPIOA5 SCK P13
GPIOA6 MISO P1
GPIOA7 MOSI P14
GPIOB0 BMI160 INT1 P4

5.BMI160 FIFO的使用

  • 当使用FIFO时,可以通过对寄存器(0x24) FIFO_DATA执行一次突发读取来获取存储的数据。数据存储单元称为

  • FIFO的帧速率由通过寄存器(0x46~0x47) FIFO_CONFIG来配置Sensor的最大输出数据速率。

帧格式对于软件正确解析从FIFO中读出的信息非常重要。FIFO可以配置为头模式无头模式存储数据(见下图)。在数据采集过程中,当数据结构和Sensor数量都不发生变化时,通常采用无头模式。在这种情况下,可存储帧的数量可以最大化。相反,头模式适用于需要数据结构灵活性的情况,例如传感器(Accel & Gyro)在不同的ODR上运行,或者在运行期间动态地开关传感器。
在这里插入图片描述
由于Accel设置为1600Hz,Gyro设置为3200Hz,所以我这里使用的是Header Mode,FIFO数据头定义如下:
在这里插入图片描述
实际从FIFO读取的数据解析如下:
在这里插入图片描述

  • FIFO支持2个中断,FIFO full中断FIFO watermark中断。当FIFO满时发出FIFO满中断,下一个完整数据样本会导致FIFO溢出,从而导致样本被删除。从技术上讲,这意味着当FIFO中剩余的空间少于两个最大帧时,就会发出一个FIFO满中断。当fifo_byte_counter中的FIFO填充级别在寄存器(0x22~0x23) FIFO_LENGTH中高于预先配置的watermark阈值,FIFO watermark中断被触发。这个阈值在寄存器(0x46~0x47) FIFO_CONFIG中fifo_watermark来配置。
    可以调用API来配置,如下:
bmi160_set_fifo_wm(200, &sensor);

6.BMI160软件Driver

  • 通过4Line SPI初始化BMI160 Sensor
struct bmi160_dev sensor;

/* You may assign a chip select identifier to be handled later */
sensor.id = 0;
sensor.interface = BMI160_SPI_INTF;
sensor.read = user_spi_read;
sensor.write = user_spi_write;
sensor.delay_ms = user_delay_ms;


int8_t rslt = BMI160_OK;
rslt = bmi160_init(&sensor);
  • 配置accel和gyro sensors在普通模式
int8_t rslt = BMI160_OK;

/* Select the Output data rate, range of accelerometer sensor */
sensor.accel_cfg.odr = BMI160_ACCEL_ODR_1600HZ;
sensor.accel_cfg.range = BMI160_ACCEL_RANGE_2G;
sensor.accel_cfg.bw = BMI160_ACCEL_BW_NORMAL_AVG4;

/* Select the power mode of accelerometer sensor */
sensor.accel_cfg.power = BMI160_ACCEL_NORMAL_MODE;

/* Select the Output data rate, range of Gyroscope sensor */
sensor.gyro_cfg.odr = BMI160_GYRO_ODR_3200HZ;
sensor.gyro_cfg.range = BMI160_GYRO_RANGE_2000_DPS;
sensor.gyro_cfg.bw = BMI160_GYRO_BW_NORMAL_MODE;

/* Select the power mode of Gyroscope sensor */
sensor.gyro_cfg.power = BMI160_GYRO_NORMAL_MODE; 

/* Set the sensor configuration */
rslt = bmi160_set_sens_conf(&sensor);
  • 配置FIFO和Watermark中断
#define ACCEL_SWITCH_UNIT(x)  ((float)(x*9.8)/16384)  	// Sensivity S2g ex:(x*9.8)/(0x8000/2)
#define GYRO_SWITCH_UNIT(x)   ((float)x/16.4)   		// RFS2000 ex: (x*2000)/0x7fff

/* Declare memory to store the raw FIFO buffer information */
#define FIFO_BUF_MAX_SIZE		800
static uint8_t fifo_buff[FIFO_BUF_MAX_SIZE];
struct bmi160_fifo_frame fifo_frame;

static void app_bmi160_fifo_watermark_int_cfg(void)
{
    
    
	struct bmi160_int_settg int_config;
	
	/* Select the Interrupt channel/pin */
	int_config.int_channel = BMI160_INT_CHANNEL_1;// Interrupt channel/pin 1
	
	/* Select the Interrupt type */
	int_config.int_type = BMI160_ACC_GYRO_FIFO_WATERMARK_INT;// Choosing Step Detector interrupt
	/* Select the interrupt channel/pin settings */
	int_config.int_pin_settg.output_en = BMI160_ENABLE;// Enabling interrupt pins to act as output pin
	int_config.int_pin_settg.output_mode = BMI160_DISABLE;// Choosing push-pull mode for interrupt pin
	int_config.int_pin_settg.output_type = BMI160_ENABLE;// Choosing active High output
	int_config.int_pin_settg.edge_ctrl = BMI160_ENABLE;// Choosing edge triggered output
	int_config.int_pin_settg.input_en = BMI160_DISABLE;// Disabling interrupt pin to act as input
	int_config.int_pin_settg.latch_dur =BMI160_LATCH_DUR_NONE;// non-latched output

	int_config.fifo_full_int_en = BMI160_ENABLE;
	int_config.fifo_wtm_int_en = BMI160_ENABLE;
	
	/* Set the Step Detector interrupt */
	bmi160_set_int_config(&int_config, &sensor); /* sensor is an instance of the structure bmi160_dev */


	/* Modify the FIFO buffer instance and link to the device instance */
	fifo_frame.data = fifo_buff;
	fifo_frame.length = FIFO_BUF_MAX_SIZE;
	sensor.fifo = &fifo_frame;
	/* Configure the sensor's FIFO settings */
	bmi160_set_fifo_config(BMI160_FIFO_ACCEL | BMI160_FIFO_GYRO | BMI160_FIFO_HEADER | BMI160_FIFO_TAG_INT1,
					BMI160_ENABLE, &sensor);

	bmi160_set_fifo_wm(200, &sensor);
}

int8_t fifo_accel_gyro_header_time_data(struct bmi160_dev *dev)
{
    
    
	int8_t rslt = 0;
	//uint16_t index = 0;

	struct bmi160_sensor_data accel_data[12]; // 300 bytes / ~7bytes per frame ~ 42 data frames	
	uint8_t accel_frames_req = 12; 
	uint8_t accel_index;
	
	/* Declare instances of the sensor data structure to store the parsed FIFO data */
	struct bmi160_sensor_data gyro_data[12]; // 300 bytes / ~7bytes per frame ~ 42 data frames	
	uint8_t gyro_frames_req = 12; 
	uint8_t gyro_index;
	
	/* Read data from the sensor's FIFO and store it the FIFO buffer,"fifo_buff" */
	printf("\n USER REQUESTED FIFO LENGTH : %d\n",dev->fifo->length);
	rslt = bmi160_get_fifo_data(dev);

	if (rslt == BMI160_OK) {
    
    
		printf("\n AVAILABLE FIFO LENGTH : %d\n",dev->fifo->length);
		/* Print the raw FIFO data */
		/*for (index = 0; index < dev->fifo->length; index++) {
			printf("\n FIFO DATA INDEX[%d] = 0x%02x", index,
				dev->fifo->data[index]);
		}
		*/
		
		/* ##################################GYRO DATA######################################### */			
		/* Parse the FIFO data to extract gyro data from the FIFO buffer */
		printf("\n REQUESTED GYRO DATA FRAMES : %d\n ",gyro_frames_req);
		rslt = bmi160_extract_gyro(gyro_data, &gyro_frames_req, dev);

		if (rslt == BMI160_OK) {
    
    
			printf("\n AVAILABLE GYRO DATA FRAMES : %d\n ",gyro_frames_req);
			
			/* Print the parsed gyro data from the FIFO buffer */
			for (gyro_index = 0; gyro_index < gyro_frames_req; gyro_index++) {
    
    
				printf("\nFIFO GYRO FRAME[%d]",gyro_index);
				printf("\nGYRO X: %.2f°/s\t Y: %.2f°/s\t Z: %.2f°/s"
					,GYRO_SWITCH_UNIT(gyro_data[gyro_index].x),GYRO_SWITCH_UNIT(gyro_data[gyro_index].y)
					,GYRO_SWITCH_UNIT(gyro_data[gyro_index].z));
			}
		} else {
    
    
			printf("\n Gyro data extraction failed");
		}


		/* ##################################ACCEL DATA######################################### */			
		printf("\n REQUESTED ACCEL DATA FRAMES : %d\n ",accel_frames_req);
		rslt = bmi160_extract_accel(accel_data, &accel_frames_req, dev);	
		if (rslt == BMI160_OK) {
    
    
			printf("\n AVAILABLE ACCEL DATA FRAMES : %d\n ",accel_frames_req);
			
			/* Print the parsed accel data from the FIFO buffer */
			for (accel_index = 0; accel_index < accel_frames_req; accel_index++) {
    
    
				printf("\nFIFO ACCEL FRAME[%d]",accel_index);
				printf("\nACCEL X: %.2fg/s \t Y: %.2fg/s \t Z: %.2fg/s"
					,ACCEL_SWITCH_UNIT(accel_data[accel_index].x), ACCEL_SWITCH_UNIT(accel_data[accel_index].y)
					,ACCEL_SWITCH_UNIT(accel_data[accel_index].z));
			}
		} else {
    
    
			printf("\n Accel data extraction failed");
		}
	} else {
    
    
		printf("\n Reading FIFO data failed");
	}

	return rslt;
}

7.验证结果

在这里插入图片描述

8.资料下载地址

移植成功的完整代码下载地址如下:
https://download.csdn.net/download/ZHONGCAI0901/13218801
官网下载的BMI160 datasheet和Driver:
https://download.csdn.net/download/ZHONGCAI0901/13256127

9.参考资料

《G-sensor概述及常用芯片整理》
《MEMS陀螺仪工作原理》

猜你喜欢

转载自blog.csdn.net/ZHONGCAI0901/article/details/110491101
BMI
IMU