本页目录

  • 如何放置
  • 输入和输出
  • 管道流程
  • 限制
  • 请求的报告速率
  • 示例中使用的高速率原始流
  • 批处理
  • 数据包字段和报告语义
  • 用法
  • 按硬件报告可用性
  • 校准与外部参数
  • 处理后的输出变换
  • 读取多个IMU数据流
  • 功能示例
  • 参考

IMU

Supported on:RVC2RVC4
IMU(惯性测量单元)节点可用于接收设备上IMU芯片的数据。Luxonis设备根据平台代次使用不同的IMU堆栈:IMU芯片通过SPI连接到RVC。请参阅OAK硬件文档以检查您的OAK相机是否集成了IMU。

如何放置

Python

Python
1pipeline = dai.Pipeline()
2imu = pipeline.create(dai.node.IMU)

C++

C++
1dai::Pipeline pipeline;
2auto imu = pipeline.create<dai::node::IMU>();

输入和输出

管道流程

通常的IMU节点流程是:
  1. 创建 dai::node::IMU
  2. 以请求的速率启用一个或多个 IMUSensor 报告
  3. 使用 setBatchReportThreshold()setMaxBatchReports() 配置批处理
  4. 从主机输出队列消费 IMUData 数据包

限制

  • 在搭载BNO08X的RVC2设备上,由于传感器硬件限制,陀螺仪频率超过400 Hz时可能偶尔出现抖动。

请求的报告速率

imu.enableIMUSensor(..., reportRate) 接受以Hz为单位的请求报告速率。实际运行时行为取决于IMU和平台:
  • 在搭载BNO08X的RVC2设备上,请求的速率会向上舍入到下一个支持的速率。
  • 在搭载BMI270的RVC2设备上,请求的速率会向下舍入到下一个支持的速率。超过400 Hz的请求目前最高约为250 Hz。
  • 在搭载LSM6DSV + AK09919的RVC4设备上,将已验证的运行时速率视为平台特定的,而不是假设硅片最大ODR直接映射到主机流速率。
有关每个传感器的详细运行时行为和硬件特性,请参阅IMU硬件参考

示例中使用的高速率原始流

当前的 depthai-core IMU示例和测试使用以下原始流速率进行高速率捕获:
  • ACCELEROMETER_RAW480 Hz
  • GYROSCOPE_RAW400 Hz

批处理

IMU节点在将数据包发送到主机之前对其进行批处理。
  • setBatchReportThreshold(N) 设置允许设备发送批处理之前应准备好的最小IMU数据包数量
  • setMaxBatchReports(M) 设置每个批处理中包含的最大数据包数量
更高的批处理可以减少主机开销,并在USB带宽或主机调度成为瓶颈时有所帮助。

数据包字段和报告语义

每个 IMUData 消息包含一个或多个 IMUPacket 条目。每个数据包仅携带在节点配置中启用的报告的字段。典型字段包括:
  • acceleroMeter
  • gyroscope
  • magneticField
  • rotationVector
使用如下报告系列:
  • *_RAW:传感器原生坐标系中的直接传感器输出
  • *_UNCALIBRATED:使用 imuExtrinsics 旋转到Luxonis RDF坐标系,未应用IMU校准参数
  • *_CALIBRATED:旋转到Luxonis RDF坐标系并使用IMU校准参数校正
  • 融合输出,如 ROTATION_VECTORGAME_ROTATION_VECTOR:从传感器内部处理路径转发

用法

Python

Python
1pipeline = dai.Pipeline()
2imu = pipeline.create(dai.node.IMU)
3
4# 启用 ACCELEROMETER_RAW 和 GYROSCOPE_RAW,速率为 100 Hz
5imu.enableIMUSensor([dai.IMUSensor.ACCELEROMETER_RAW, dai.IMUSensor.GYROSCOPE_RAW], 100)
6# 超过此阈值时,数据包将以 X 个为一组批量发送,前提是主机未阻塞且 USB 带宽可用
7imu.setBatchReportThreshold(1)
8# 每批的最大 IMU 数据包数,达到此数量时设备将阻塞发送,直到主机能够接收
9# 如果小于或等于 batchReportThreshold,则发送始终在设备端阻塞
10# 有助于减少设备 CPU 负载和丢失的数据包数,如果设备端因多个节点而导致 CPU 负载较高
11imu.setMaxBatchReports(10)

C++

C++
1dai::Pipeline pipeline;
2auto imu = pipeline.create<dai::node::IMU>();
3
4// 启用 ACCELEROMETER_RAW 和 GYROSCOPE_RAW,速率为 100 Hz
5imu->enableIMUSensor({dai::IMUSensor::ACCELEROMETER_RAW, dai::IMUSensor::GYROSCOPE_RAW}, 100);
6// 超过此阈值时,数据包将以 X 个为一组批量发送,前提是主机未阻塞且 USB 带宽可用
7imu->setBatchReportThreshold(1);
8// 每批的最大 IMU 数据包数,达到此数量时设备将阻塞发送,直到主机能够接收
9// 如果小于或等于 batchReportThreshold,则发送始终在设备端阻塞
10// 有助于减少设备 CPU 负载和丢失的数据包数,如果设备端因多个节点而导致 CPU 负载较高
11imu->setMaxBatchReports(10);

按硬件报告可用性

报告系列IMUSensorBNO08XBMI270LSM6DSVAK09919备注
原始加速度ACCELEROMETER_RAW原始加速度计数据流
Luxonis 坐标系中的加速度计(无 IMU 校准参数)ACCELEROMETER_UNCALIBRATEDRAW -> UNCALIBRATED 应用 imuExtrinsics。这是统一的 IMU 坐标系加速度计路径。
Luxonis 坐标系中的加速度计(含 IMU 校准参数)ACCELEROMETER_CALIBRATED需要运行时校准负载中存在 IMU 校准参数。
原始角速度GYROSCOPE_RAW原始陀螺仪数据流
Luxonis 坐标系中的陀螺仪(无 IMU 校准参数)GYROSCOPE_UNCALIBRATEDRAW -> UNCALIBRATED 应用 imuExtrinsics。在较旧设备上,预计开箱即用。
Luxonis 坐标系中的陀螺仪(含 IMU 校准参数)GYROSCOPE_CALIBRATED需要运行时校准负载中存在 IMU 校准参数。
原始磁场MAGNETOMETER_RAW在 RVC4 上,原始磁力计数据来自 AK09919 配套传感器。
处理后的磁场MAGNETOMETER_CALIBRATED, MAGNETOMETER_UNCALIBRATED在目标硬件上验证处理后的磁力计输出的公共枚举/文档字符串仍为 BNO08X 样式。
导出的加速度输出LINEAR_ACCELERATION, GRAVITY在目标硬件上验证BNO08X 直接暴露这些。对于非 BNO 路径,在目标设备上验证可用性并进行分支处理。
融合姿态输出ROTATION_VECTOR, GAME_ROTATION_VECTOR, GEOMAGNETIC_ROTATION_VECTOR, ARVR_STABILIZED_ROTATION_VECTOR, ARVR_STABILIZED_GAME_ROTATION_VECTOR在目标硬件上验证无独立支持这些是传感器融合输出,并非由 IMU 节点在主机端完成的融合。

校准与外部参数

使用 device.readCalibration() 从设备读取出厂校准负载。使用 device.getCalibration()device.setCalibration() 处理运行时校准覆盖。对于处理后的惯性输出,请使用以下模型:
  • RAW -> UNCALIBRATED:使用 imuExtrinsics 将传感器原生坐标系对齐到 Luxonis RDF 坐标系
  • UNCALIBRATED -> CALIBRATED:应用 IMU 校准参数中设置的加速度计或陀螺仪校准
  • 因此 ACCELEROMETER_UNCALIBRATEDGYROSCOPE_UNCALIBRATED 共享统一的 IMU 坐标系路径
  • ACCELEROMETER_CALIBRATEDGYROSCOPE_CALIBRATED 在此基础上添加运行时校准校正

处理后的输出变换

RAW -> UNCALIBRATED

Python
1import depthai as dai
2import numpy as np
3
4with dai.Pipeline() as pipeline:
5    imu = pipeline.create(dai.node.IMU)
6    imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_RAW, 100)
7    imu_q = imu.out.createOutputQueue(maxSize=10, blocking=False)
8
9    device = pipeline.getDefaultDevice()
10    calib = device.readCalibration()
11    imu_to_cam = np.array(calib.getImuToCameraExtrinsics(dai.CameraBoardSocket.CAM_A, False))
12    R_imu_to_cam = imu_to_cam[:3, :3]
13
14    pipeline.start()
15    pkt = imu_q.get().packets[0]
16    raw = np.array([pkt.acceleroMeter.x, pkt.acceleroMeter.y, pkt.acceleroMeter.z])
17    uncalibrated = R_imu_to_cam @ raw

UNCALIBRATED -> CALIBRATED

Python
1import depthai as dai
2import numpy as np
3
4imu_calibration = [
5    [1.0, 0.0, 0.0, 0.125],
6    [0.0, 1.0, 0.0, 0.000],
7    [0.0, 0.0, 1.0, 0.000],
8]
9
10with dai.Pipeline() as pipeline:
11    imu = pipeline.create(dai.node.IMU)
12    imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_UNCALIBRATED, 100)
13    imu_q = imu.out.createOutputQueue(maxSize=10, blocking=False)
14
15    pipeline.start()
16    pkt = imu_q.get().packets[0]
17    uncalibrated = np.array([pkt.acceleroMeter.x, pkt.acceleroMeter.y, pkt.acceleroMeter.z])
18
19    calibration = np.array(imu_calibration)
20    calibrated = calibration[:, :3] @ uncalibrated + calibration[:, 3]

读取多个IMU数据流

如果目标硬件支持所选的报告,您可以启用多个IMU报告家族,并仅读取已请求的字段。

Python

Python
1import depthai as dai
2
3with dai.Pipeline() as pipeline:
4    imu = pipeline.create(dai.node.IMU)
5
6    imu.enableIMUSensor(dai.IMUSensor.ACCELEROMETER_RAW, 100)
7    imu.enableIMUSensor(dai.IMUSensor.GYROSCOPE_RAW, 100)
8    imu.enableIMUSensor(dai.IMUSensor.MAGNETOMETER_RAW, 100)
9
10    imu.setBatchReportThreshold(1)
11    imu.setMaxBatchReports(10)
12
13    imu_q = imu.out.createOutputQueue(maxSize=50, blocking=False)
14
15    pipeline.start()
16    while pipeline.isRunning():
17        imu_data = imu_q.get()
18        for pkt in imu_data.packets:
19            a = pkt.acceleroMeter
20            g = pkt.gyroscope
21            m = pkt.magneticField

C++

C++
1#include "depthai/depthai.hpp"
2
3int main() {
4    dai::Pipeline pipeline;
5    auto imu = pipeline.create<dai::node::IMU>();
6
7    imu->enableIMUSensor(dai::IMUSensor::ACCELEROMETER_RAW, 100);
8    imu->enableIMUSensor(dai::IMUSensor::GYROSCOPE_RAW, 100);
9    imu->enableIMUSensor(dai::IMUSensor::MAGNETOMETER_RAW, 100);
10
11    imu->setBatchReportThreshold(1);
12    imu->setMaxBatchReports(10);
13
14    auto imuQ = imu->out.createOutputQueue(50, false);
15
16    pipeline.start();
17    while(pipeline.isRunning()) {
18        auto data = imuQ->get<dai::IMUData>();
19        for(const auto& pkt : data->packets) {
20            const auto& a = pkt.acceleroMeter;
21            const auto& g = pkt.gyroscope;
22            const auto& m = pkt.magneticField;
23        }
24    }
25}

功能示例

参考

class

dai::node::IMU

#include IMU.hpp
variable
Output out
Outputs IMUData message that carries IMU packets.
variable
Input mockIn
Mock IMU data for replaying recorded data
function
void enableIMUSensor(IMUSensorConfig sensorConfig)
Enable a new IMU sensor with explicit configuration
function
void enableIMUSensor(const std::vector< IMUSensorConfig > & sensorConfigs)
Enable a list of IMU sensors with explicit configuration
function
void enableIMUSensor(IMUSensor sensor, uint32_t reportRate)
Enable a new IMU sensor with default configuration
function
void enableIMUSensor(const std::vector< IMUSensor > & sensors, uint32_t reportRate)
Enable a list of IMU sensors with default configuration
function
void setBatchReportThreshold(std::int32_t batchReportThreshold)
Above this packet threshold data will be sent to host, if queue is not blocked
function
std::int32_t getBatchReportThreshold()
Above this packet threshold data will be sent to host, if queue is not blocked
function
void setMaxBatchReports(std::int32_t maxBatchReports)
Maximum number of IMU packets in a batch report
function
std::int32_t getMaxBatchReports()
Maximum number of IMU packets in a batch report
function
void enableFirmwareUpdate(bool enable)
Whether to perform firmware update or not. Default value: false.
inline function
DeviceNodeCRTP()
inline function
DeviceNodeCRTP(const std::shared_ptr< Device > & device)
inline function
DeviceNodeCRTP(std::unique_ptr< Properties > props)
inline function
DeviceNodeCRTP(std::unique_ptr< Properties > props, bool confMode)
inline function
DeviceNodeCRTP(const std::shared_ptr< Device > & device, std::unique_ptr< Properties > props, bool confMode)

需要帮助?

请前往 OAKChina 官网 获取技术支持或解答您的任何疑问。