# sample_imu 使用说明

## 功能概述

sample_imu 是一个用于使用惯导传感器的命令行案例，主要实现了基于 IIO 接口对惯性测量单元（ IMU）数据的读取、处理和显示功能。\
通过该程序，用户可以方便地获取 IMU 传感器的加速度、陀螺仪和磁力计数据（ IMU 具备的才行），并进行相应的分析和应用。

### 软件架构说明

我们对 sample_imu 做了如下的软件设计

- __ 应用层 __： sample_imu.c 作为程序的入口，负责解析命令行参数、初始化传感器、处理用户输入的命令以及读取和显示传感器数据。
- __ 管理层 __： imu_manager.h 和 imu_manager.c 提供了传感器管理的接口和实现，包括列出可用传感器、初始化传感器、读取传感器数据、释放传感器资源等功能。
- __ 适配层 __: imu_interface.h 定义了读取传感器接口的结构体，为具体传感器做好统一。
- __ 传感器抽象层 __：这一层针对具体的传感器进行抽象实现，负责与底层的硬件 IIO 驱动进行交互，将硬件驱动提供的数据转换为上层可以使用的标准数据格式。

软件架构图：

![software_architecture_diagram.png](_static/_images/sample_imu/sample_imu_software_diagram.png)

### 代码位置及目录结构

SDK 中的位置：\
```/app/samples/platform_samples/sample_imu/``` \
该目录包含 sample_imu 源码。编译后会生成名为 sample_imu 的可执行文件，以及中间产物。
```
.
├── bmi08x.c
├── imu_interface.h
├── imu_manager.c
├── imu_manager.h
├── Makefile
└── sample_imu.c
```
以下是各个文件的详细介绍：
- __Makefile__：用于编译程序的 Makefile 文件，定义了编译规则和依赖关系。
- __sample_imu.c__：程序的主要源代码文件，包含了程序的入口函数 main，负责整个程序的流程控制。
- __imu_manager.h 、 imu_manager.c__：实现了传感器管理的功能，提供了统一的接口供应用层调用。
- __imu_interface.h__：定义了传感器驱动的接口指针，包括初始化、读取数据和释放资源等 函数指针。
- __bmi08x.c__：实现了 BMI08x 传感器抽象层，与 bmi08x 注册的 IIO 硬件驱动进行交付 具体实现了初始化、数据读取和资源释放等逻辑。
如果后续需要添加其他传感器，参考 bmi08x.c 的实现，和 imu_interface.h 接口。进行相应的实现即可。

### 工具位置及目录结构
板端可执行程序位置：\
```/app/platform_samples/sample_imu/sample_imu ``` \
该目录下包含编译后的可执行文件，使用的时候根据 [ 程序运行方法 ](#span-id-usage) 使用即可。

### 背景知识

惯性测量单元（ IMU）是一种用于测量物体的加速度、角速度和磁力等物理量的设备，通常由加速度计、陀螺仪和磁力计组成。加速度计用于测量物体在三个轴向上的加速度，陀螺仪用于测量物体的角速度，磁力计用于测量物体周围的磁场强度。通过对这些物理量的测量和分析，可以获取物体的姿态、运动状态等信息。需要注意的是，不是所有的 IMU 传感器都具备所有的传感器，行业中有单独售卖加速度计、陀螺仪和磁力计这三种传感器的，也有分六轴九轴等 IMU 进行售卖。

### API 流程说明

sample_imu 没有用到特定的 API ，使用的都是 kernel 中标准的接口，来构建的整个应用程序。所以更多是结合 sample_imu 中的函数对 API 流程进行说明。

1 、列出可用传感器：调用 list_available_sensors 函数，该函数会遍历支持的传感器驱动列表，并打印出所有支持的传感器名称。

2 、初始化传感器：调用 init_sensor 函数，传入传感器类型和参数，该函数会查找并验证对应的 IIO 设备，然后调用相应的驱动初始化函数进行传感器的初始化。

3 、读取传感器数据：调用 read_sensor_data 函数，传入传感器句柄和数据结构体指针，该函数会调用相应的传感器抽象层读取函数，将传感器数据读取到数据结构体中并打印。

4 、释放传感器资源：调用 release_sensor 函数，传入传感器句柄，该函数会调用相应的传感器抽象层释放函数，释放传感器占用的资源。


![api_process](_static/_images/sample_imu/sample_imu_api_process.png)



## 编译部署

### 编译
进入到 SDK 源码中。使用 Makefile 编译程序：
```
make
```
该命令会根据 Makefile 中的规则，将源代码编译成可执行文件 sample_imu。


### <span id="hardware-environment-setup"/> 硬件环境搭建

可以参考如下连接方式 ( 使用的传感器是 BMI08x)：

![40pin_connect](_static/_images/sample_imu/40_PIN_RDK_IMU_Module_X5_EVB.png)

确认硬件连接正确之后，我们还需要确认相应的驱动配置是否有打开。\

首先我们检查 dts， EVB 板子使用的是 x5-evb.dtsi 文件， 检查对应的 i2c5 节点是否有配置，如果没有，可以参考如下配置加上去
```
&i2c5 {
	status = "okay";
    ......
	bmi08a@19 {
		compatible = "bmi08xa";
		reg = <0x19>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};

	bmi08g@69 {
		compatible = "bmi08xg";
		reg = <0x69>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <6 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};
};
```

该 IMU 也支持 SPI 接口，如果要使用，也可以参考设备树的配置：
```
&spi1 {
	/*When dual chip select is used, the number of SPI chip selects must be set to 2.*/
	/*num-cs = <2>;*/
	status = "okay";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_spi1 &pinctrl_spi1_ssn1>;
	dma-names = "tx", "rx";
	dmas = <&axi_dmac 23>, <&axi_dmac 22>;

	bmi08g@0 {
		compatible = "bmi088_gyro";
		reg = <0>;
		spi-max-frequency = <5000000>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <6 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};

	bmi08a@1 {
		compatible = "bmi08a";
		reg = <1>;
		spi-max-frequency = <5000000>;
		interrupt-parent = <&ls_gpio1_porta>;
		interrupts = <4 IRQ_TYPE_EDGE_RISING>;
		status = "okay";
	};
};

```
注意，这里只能选择一个接口进行使用，所以设备树配置的时候，没有使用的接口，可以设置成 disabled 状态。

然后检查对应 deconfig ( 比如 EVB 默认使用的是 hobot_x5_soc_defconfig) 是否有开启
```
CONFIG_BMI08X_SUPPORT_I2C_BUS=m
CONFIG_BMI08X_SUPPORT_SPI_BUS=m
```
可以通过 menuconfig 去开启。\
搜索位置可以参考如下截图 \
![boot_menuconfig_search](_static/_images/sample_imu/boot_menuconfig_search.png)

打开方式可以参考如下截图 \
![boot_menuconfig_config](_static/_images/sample_imu/boot_menuconfig_choose_m.png)

最后编译整个镜像，刷机之后，检查一下该 IMU 是否有成功注册，可以通过如下两种办法检查：
（ 1 ）通过 LOG 检查
```
root@buildroot:~# dmesg | grep BS
[    0.084965] CPU features: detected: Speculative Store Bypassing Safe (SSBS)
               [I]\x016<BS_LOG><bmi08_i2c_probe><187>client->name:bmi08xa / addr: 0x19
               [I]\x016<BS_LOG><bmi08_i2c_probe><187>client->name:bmi08xg / addr: 0x69
               [I]\x016<BS_LOG><sensor_init><1057>accel initilized
               [I]\x016<BS_LOG><sensor_init><1064>gyro initilized
               [I]\x016<BS_LOG><sensor_init><1065>sensor initilized
               [I]\x016<BS_LOG><sensor_init><1072>soft reset done
               [I]\x016<BS_LOG><sensor_init><1080>config stream loaded successfully
               [I]\x016<BS_LOG><sensor_init><1090>Accel power mode set to NORMAL
               [I]\x016<BS_LOG><sensor_init><1099>Gyro power mode set to NORMAL
               [I]\x016<BS_LOG><bmi08_probe><2216>Acc chip ID : 0x1e, Gyro chip ID : 0xf
               [I]\x016<BS_LOG><bmi08_request_irq><544>ACC IRQ requested for pin : 56
               [I]\x016<BS_LOG><bmi08_probe><2227>ACC IRQ requested
               [I]\x016<BS_LOG><bmi08_gyr_request_irq><563>GYR IRQ requested for pin : 57
               [I]\x016<BS_LOG><bmi08_probe><2234>GYR IRQ requested
               [I]\x016<BS_LOG><bmi08_probe><2236>sensor bmi088 probed successfully
[    4.687140] CAM_SUBSYS soc:cam:cam_sys@0: [FRT:D] camsys_probe(0)
root@buildroot:~#
```
可以看到可以读到 sensor 的 id 了：\
```
[I]\x016<BS_LOG><bmi08_probe><2216>Acc chip ID : 0x1e, Gyro chip ID : 0xf

```

（ 2 ）通过检查 IIO 子系统中是否有成功注册上 IMU，例如我们可以到 iio 子系统中检查 name 节点：\
```
root@buildroot:~# cd /sys/bus/iio/devices/iio\:device1/
root@buildroot:/sys/bus/iio/devices/iio:device1# cat name
bmi08x
root@buildroot:/sys/bus/iio/devices/iio:device1#
```


### 程序部署
编译后可执行文件一般在源码同级目录下，即 /app/samples/platform_samples/sample_imu/ 目录下。
```
.
├── bmi08x.c
├── bmi08x.o
├── imu_interface.h
├── imu_manager.c
├── imu_manager.h
├── imu_manager.o
├── Makefile
├── sample_imu
├── sample_imu.c
└── sample_imu.o
```
本 sample 的可执行文件已经默认部署在板端 /app/platform_samples/sample_imu/sample_imu 位置。\
当然也可以将编译好的可执行文件复制到开发板的任意目录下，以便运行。

## 运行

### <span id="usage"/> 程序运行方法
直接运行可执行文件：

```
./sample_imu
```
或者使用命令行参数指定配置：
```
./sample_imu -n bmi08x
```
其中，-n 参数用于指定要使用的 IMU 传感器名称，默认值为 bmi08x。

### 程序参数选项说明
```
Usage: sample_imu [OPTIONS]
Options:
  -n <imu_name>         Specify IMU name (default: bmi08x)
  -h                    Show this help message
```
- -n <imu_name>：指定要使用的 IMU 传感器名称，例如 bmi08x。
- -h：显示帮助信息，列出所有可用的命令行参数和其说明。

### 运行效果
程序运行后，会显示一个命令菜单，用户可以输入相应的命令来获取传感器数据：

```
root@buildroot:/app/platform_samples/sample_imu# ./sample_imu
No IMU specified, using default: bmi08x
Using IMU: bmi08x

=== Detected IIO Devices ===
  Device: iio:device1     | Name: bmi08x
  Device: iio:device0     | Name: 34190000.adc
============================

Device validation passed at: /sys/bus/iio/devices/iio:device1
BMI08x: Initializing with params:

***************  Command Lists  ***************
 g    -- Get a single frame of imu data
 l    -- Get multiple frames of imu data
 q    -- Quit the program
 h    -- Print this help message
Enter command:
```
不带参数执行的时候，会默认选择 bmi08x 这颗 IMU，然后列举出所有 iio 下的 device name。\
如果正常初始化，则会来到读取数据的选项列表，中文说明如下：

- g：获取一帧 IMU 数据。
- l：获取多帧 IMU 数据，需要输入要获取的帧数。
- q：退出程序。
- h：显示帮助信息。

#### 获取一帧 IMU 数据运行效果：
```
***************  Command Lists  ***************
 g    -- Get a single frame of imu data
 l    -- Get multiple frames of imu data
 q    -- Quit the program
 h    -- Print this help message
Enter command: g
Data received (Frame 1):
  Accelerometer: [-117.836021, -118.283142, 9.569026] m/s ²
  Gyroscope:     [0.006392, -69.885605, 0.049002] rad/s
  Timestamp:     00:01:38.917.929

```

#### 获取多帧 IMU 数据运行效果（这里以 3 帧为例）：
```
***************  Command Lists  ***************
 g    -- Get a single frame of imu data
 l    -- Get multiple frames of imu data
 q    -- Quit the program
 h    -- Print this help message
Enter command: l
Enter number of frames to read: 100
Data received (Frame 1):
  Accelerometer: [-117.870140, -118.261597, 9.597756] m/s ²
  Gyroscope:     [0.019175, 0.010653, -69.857903] rad/s
  Timestamp:     00:01:50.861.640
Data received (Frame 2):
  Accelerometer: [-117.825249, -118.283142, 9.574412] m/s ²
  Gyroscope:     [0.014914, -69.857903, -69.887733] rad/s
  Timestamp:     00:01:50.867.500
Data received (Frame 3):
  Accelerometer: [-117.825249, -118.283142, 9.597756] m/s ²
  Gyroscope:     [-69.898384, 0.055394, -69.879211] rad/s
  Timestamp:     00:01:50.873.320
Data received (Frame 4):
  Accelerometer: [-117.818069, -118.283142, 9.597756] m/s ²
  Gyroscope:     [0.046872, -69.919693, -69.851517] rad/s
  Timestamp:     00:01:50.879.140

......


```
## 常见问题

**已经接上设备，但是没有识别到设备**

- 我们首先要保证硬件连接是正确的，检查 IMU 传感器与开发板之间的连线是否松动、短路或接错。\
可以参考开发板使用指南中的 40PIN 连接举例部分 进行检查。
- 其次，我们要检查驱动是否有向 iio 框架正常注册。 sample_imu 在运行的时候会列举 iio 下面 \
的所有设备，如果没有发现期望的设备，那么就需要检查驱动注册情况。
- 需要特别注意，该 sample_imu 暂时只包含了 bmi08x ，如果需要其他 IMU 的 sample，请先参考 \
驱动开发说明，基于 iio 框架下注册 IMU 之后，再结合 sample_imu 开发应用程序。

