ArduPilot开源代码之AP_DAL_InertialSensor

1. 源由

该类主要用于管理惯性传感器的数据,包括加速度计和陀螺仪。它提供了获取传感器数据和状态的方法,以及处理传感器消息的机制。

通过这些方法,可以访问传感器的当前状态、获取过滤后的数据以及处理新的传感器数据。

2. 框架设计

  • 该类通过多个方法对不同的传感器数据进行访问和操作,包括加速度计和陀螺仪。
  • 使用了消息处理机制,通过handle_message方法来更新传感器数据。
  • 提供了获取主要传感器参数的方法,例如循环频率、加速度计和陀螺仪的数量、位置偏移等。
  • 过滤后的数据通过私有成员变量存储,并通过公共方法提供访问接口。

2.1 类定义和成员变量

class AP_DAL_InertialSensor {
public:
    // 公共方法
    uint16_t get_loop_rate_hz(void) const { return _RISH.loop_rate_hz; }
    const Vector3f &get_imu_pos_offset(uint8_t instance) const { return pos[instance]; }
    uint8_t get_accel_count(void) const { return _RISH.accel_count; }
    uint8_t get_first_usable_accel(void) const { return _RISH.first_usable_accel; };
    bool use_accel(uint8_t instance) const { return _RISI[instance].use_accel; }
    const Vector3f &get_accel(uint8_t i) const { return accel_filtered[i]; }
    bool get_delta_velocity(uint8_t i, Vector3f &delta_velocity, float &delta_velocity_dt) const {
        delta_velocity = _RISI[i].delta_velocity;
        delta_velocity_dt = _RISI[i].delta_velocity_dt;
        return _RISI[i].get_delta_velocity_ret;
    }
    uint8_t get_gyro_count(void) const { return _RISH.gyro_count; }
    uint8_t get_first_usable_gyro(void) const { return _RISH.first_usable_gyro; };
    bool use_gyro(uint8_t instance) const { return _RISI[instance].use_gyro; }
    const Vector3f &get_gyro(uint8_t i) const { return gyro_filtered[i]; }
    const Vector3f &get_gyro() const { return get_gyro(_primary_gyro); }
    bool get_delta_angle(uint8_t i, Vector3f &delta_angle, float &delta_angle_dt) const {
        delta_angle = _RISI[i].delta_angle;
        delta_angle_dt = _RISI[i].delta_angle_dt;
        return _RISI[i].get_delta_angle_ret;
    }
    float get_loop_delta_t(void) const { return _RISH.loop_delta_t; }
    AP_DAL_InertialSensor();
    void start_frame();
    void handle_message(const log_RISH &msg) {
        _RISH = msg;
    }
    void handle_message(const log_RISI &msg) {
        _RISI[msg.instance] = msg;
        pos[msg.instance] = AP::ins().get_imu_pos_offset(msg.instance);
        update_filtered(msg.instance);
    }

private:
    struct log_RISH _RISH;
    struct log_RISI _RISI[INS_MAX_INSTANCES];
    float alpha;
    Vector3f pos[INS_MAX_INSTANCES];
    Vector3f gyro_filtered[INS_MAX_INSTANCES];
    Vector3f accel_filtered[INS_MAX_INSTANCES];
    uint8_t _primary_gyro;
    void update_filtered(uint8_t i);
};

2.2 公共方法

- `get_loop_rate_hz()`: 返回采样的循环频率。
- `get_imu_pos_offset(instance)`: 返回指定实例的IMU位置偏移。
- `get_accel_count()`: 返回加速度计数量。
- `get_first_usable_accel()`: 返回第一个可用加速度计的索引。
- `use_accel(instance)`: 检查是否使用指定实例的加速度计。
- `get_accel(i)`: 返回过滤后的加速度数据。
- `get_delta_velocity(i, delta_velocity, delta_velocity_dt)`: 获取指定实例的速度变化量及其时间间隔。
- `get_gyro_count()`: 返回陀螺仪数量。
- `get_first_usable_gyro()`: 返回第一个可用陀螺仪的索引。
- `use_gyro(instance)`: 检查是否使用指定实例的陀螺仪。
- `get_gyro(i)`: 返回过滤后的陀螺仪数据。
- `get_gyro()`: 返回主陀螺仪的数据。
- `get_delta_angle(i, delta_angle, delta_angle_dt)`: 获取指定实例的角度变化量及其时间间隔。
- `get_loop_delta_t()`: 返回主循环的时间间隔。

2.3 构造函数和其他方法

- `AP_DAL_InertialSensor()`: 构造函数,可能包含一些初始化逻辑(未展示具体实现)。
- `start_frame()`: 启动新的帧处理(具体实现未展示)。
- `handle_message(const log_RISH &msg)`: 处理RISH类型的消息,更新_RISH数据。
- `handle_message(const log_RISI &msg)`: 处理RISI类型的消息,更新_RISI数组中特定实例的数据,并更新位置和过滤后的数据。

2.4 私有成员变量

- `_RISH`: 存储整体的传感器头信息。  //Real-time Inertial Sensor Header
- `_RISI[]`: 存储各个传感器实例的信息。  //Real-time Inertial Sensor Instance
- `alpha`: 一个浮点型变量,可能用于滤波器。
- `pos[]`: 存储各个传感器的位置偏移。
- `gyro_filtered[]`: 存储各个传感器的过滤后的陀螺仪数据。
- `accel_filtered[]`: 存储各个传感器的过滤后的加速度数据。
- `_primary_gyro`: 存储主陀螺仪的索引。
- `update_filtered(uint8_t i)`: 更新特定传感器实例的过滤后的数据(具体实现未展示)。

3. 重要例程

3.1 InertialSensor-like 方法

3.1.1 get_loop_rate_hz

返回采样可用的选定循环频率(以赫兹为单位)

    uint16_t get_loop_rate_hz(void) const { return _RISH.loop_rate_hz; }

3.1.2 get_imu_pos_offset

获取IMU位置偏移值

    const Vector3f &get_imu_pos_offset(uint8_t instance) const {
        return pos[instance];
    }

3.2 accel 方法

3.2.1 get_accel_count

获取ACC实例数量

    uint8_t get_accel_count(void) const { return _RISH.accel_count; }

3.2.2 get_first_usable_accel

获取可用ACC实例

    uint8_t get_first_usable_accel(void) const { return _RISH.first_usable_accel; };

3.2.3 use_accel

获取ACC指定实例有效性

    bool use_accel(uint8_t instance) const { return _RISI[instance].use_accel; }

3.2.4 get_accel

获取指定ACC实例矢量值

    const Vector3f     &get_accel(uint8_t i) const { return accel_filtered[i]; }

3.2.5 get_delta_velocity

获取指定ACC实例delta值

    bool get_delta_velocity(uint8_t i, Vector3f &delta_velocity, float &delta_velocity_dt) const {
        delta_velocity = _RISI[i].delta_velocity;
        delta_velocity_dt = _RISI[i].delta_velocity_dt;
        return _RISI[i].get_delta_velocity_ret;
    }

3.3 gyro 方法

3.3.1 get_gyro_count

获取GYRO实例数量

    uint8_t get_gyro_count(void) const { return _RISH.gyro_count; }

3.3.2 get_first_usable_gyro

获取可用GYRO实例

    uint8_t get_first_usable_gyro(void) const { return _RISH.first_usable_gyro; };

3.3.3 use_gyro

获取GYRO指定实例有效性

    bool use_gyro(uint8_t instance) const { return _RISI[instance].use_gyro; }

3.3.4 get_gyro

获取指定GYRO实例矢量值 或 获取默认GYRO实例矢量值

    const Vector3f     &get_gyro(uint8_t i) const { return gyro_filtered[i]; }
    const Vector3f     &get_gyro() const { return get_gyro(_primary_gyro); }

3.3.5 get_delta_angle

获取指定GYRO实例delta值

    bool get_delta_angle(uint8_t i, Vector3f &delta_angle, float &delta_angle_dt) const {
        delta_angle = _RISI[i].delta_angle;
        delta_angle_dt = _RISI[i].delta_angle_dt;
        return _RISI[i].get_delta_angle_ret;
    }

3.4 其他函数

3.4.1 AP_DAL_InertialSensor

构造函数初始化实例编号

AP_DAL_InertialSensor::AP_DAL_InertialSensor()
{
    for (uint8_t i=0; i<ARRAY_SIZE(_RISI); i++) {
        _RISI[i].instance = i;
    }
}

3.4.2 get_loop_delta_t

返回主循环的时间增量(以秒为单位)

    float get_loop_delta_t(void) const { return _RISH.loop_delta_t; }

3.4.3 start_frame

AP_DAL::start_frame
 └──> AP_DAL_InertialSensor::start_frame
void AP_DAL_InertialSensor::start_frame()
{
    const auto &ins = AP::ins();

    const log_RISH old_RISH = _RISH;

    // 更新主循环的频率(以 Hz 为单位)
    _RISH.loop_rate_hz = ins.get_loop_rate_hz();
    // 更新第一个可用陀螺仪的索引
    _RISH.first_usable_gyro = ins.get_first_usable_gyro();
    // 更新主循环的时间增量(以秒为单位)
    _RISH.loop_delta_t = ins.get_loop_delta_t();
    // 更新第一个可用加速度计的索引
    _RISH.first_usable_accel = ins.get_first_usable_accel();
    // 更新加速度计的数量
    _RISH.accel_count = ins.get_accel_count();
    // 更新陀螺仪的数量
    _RISH.gyro_count = ins.get_gyro_count();
    // 如果 RISH 结构体内容有变化,则写入重播数据块
    WRITE_REPLAY_BLOCK_IFCHANGED(RISH, _RISH, old_RISH);

    // 遍历每个传感器
    for (uint8_t i=0; i<ARRAY_SIZE(_RISI); i++) {
        log_RISI &RISI = _RISI[i];
        const log_RISI old_RISI = RISI;

        // 加速度计数据
        RISI.use_accel = ins.use_accel(i);
        if (RISI.use_accel) {
            // 获取加速度计的速度增量及其时间增量
            RISI.get_delta_velocity_ret = ins.get_delta_velocity(i, RISI.delta_velocity, RISI.delta_velocity_dt);
        }

        // 陀螺仪数据
        RISI.use_gyro = ins.use_gyro(i);
        if (RISI.use_gyro) {
            // 获取陀螺仪的角度增量及其时间增量
            RISI.get_delta_angle_ret = ins.get_delta_angle(i, RISI.delta_angle, RISI.delta_angle_dt);
        }

        update_filtered(i);

        // 如果 RISI 结构体内容有变化,则写入重播数据块
        WRITE_REPLAY_BLOCK_IFCHANGED(RISI, RISI, old_RISI);

        // 更新传感器的位置偏移
        pos[i] = ins.get_imu_pos_offset(i);
    }
}

3.4.4 handle_message

AP_DAL::handle_message
 └──> AP_DAL_InertialSensor::handle_message
    void handle_message(const log_RISH &msg) {
        _RISH = msg;
    }

3.4.5 update_filtered

更新滤波后的陀螺仪和加速度计数据

void AP_DAL_InertialSensor::update_filtered(uint8_t i)
{
if (!is_positive(alpha)) {
// 为EKF滤波后的加速度计和陀螺仪使用恒定的10Hz,使EKF独立于INS滤波器设置
const float cutoff_hz = 10.0;
alpha = calc_lowpass_alpha_dt(get_loop_delta_t(), cutoff_hz);
}
if (is_positive(_RISI[i].delta_angle_dt)) {
gyro_filtered[i] += ((_RISI[i].delta_angle/_RISI[i].delta_angle_dt) - gyro_filtered[i]) * alpha;
}
if (is_positive(_RISI[i].delta_velocity_dt)) {
accel_filtered[i] += ((_RISI[i].delta_velocity/_RISI[i].delta_velocity_dt) - accel_filtered[i]) * alpha;
}
}

4. 总结

AP_DAL_InertialSensor主要管理了加速度计和陀螺仪数据,并提供访问接口进行直接状态访问。

5. 参考资料

【1】ArduPilot开源飞控系统之简单介绍
【2】ArduPilot之开源代码Task介绍
【3】ArduPilot飞控启动&运行过程简介
【4】ArduPilot之开源代码Library&Sketches设计
【5】ArduPilot之开源代码Sensor Drivers设计
【6】ArduPilot开源代码之EKF系列研读
【7】ArduPilot开源代码之AP_DAL研读系列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值