ArduPilot开源代码之AP_VisualOdom_Backend

news2024/10/6 3:40:40

ArduPilot开源代码之AP_VisualOdom_Backend

  • 1. 源由
  • 2. 类定义
    • 2.1 类与构造函数
    • 2.2 公共部分
    • 2.3 保护部分
    • 2.4 成员变量
  • 3. 重要例程
    • 3.1 AP_VisualOdom_Backend::healthy
    • 3.2 AP_VisualOdom_Backend::quality
    • 3.3 AP_VisualOdom_Backend::handle_vision_position_delta_msg
    • 3.4 AP_VisualOdom_Backend::get_reset_timestamp_ms
    • 3.5 AP_VisualOdom_Backend::get_type
  • 4. 日志记录
    • 4.1 AP_VisualOdom_Backend::Write_VisualOdom
    • 4.2 AP_VisualOdom_Backend::Write_VisualPosition
    • 4.3 AP_VisualOdom_Backend::Write_VisualVelocity
  • 4. 总结
  • 5. 参考资料

1. 源由

继续研读《ArduPilot开源飞控之AP_VisualOdom》关于AP_VisualOdom_Backend模版设备类。

其抽象了哪些共用方法和数据。

2. 类定义

AP_VisualOdom_Backend类作为视觉里程计处理的后端,与传感器交互,处理姿态和速度估计,并确保系统的健康。派生类需要实现关键功能,如处理姿态和速度估计,而基类提供实用函数并管理内部状态,如最后的重置时间戳和质量指标。

注:这个类含有部分条件编译(#if)。

2.1 类与构造函数

class AP_VisualOdom_Backend
{
... ...

/*
  base class constructor. 
  This incorporates initialisation as well.
*/
AP_VisualOdom_Backend::AP_VisualOdom_Backend(AP_VisualOdom &frontend) :
    _frontend(frontend)
{
}

2.2 公共部分

  • 构造函数:

    AP_VisualOdom_Backend(AP_VisualOdom &frontend);
    

    构造函数初始化后端,接收一个AP_VisualOdom对象的引用,称为前端。

  • 健康检查:

    bool healthy() const;
    

    如果传感器正在接收数据并且状态良好,则返回true

  • 质量检查:

    int8_t quality() const { return _quality; }
    

    返回视觉里程计的质量,范围从-1到100。

  • 条件编译用于MAVLink:

    #if HAL_GCS_ENABLED
    void handle_vision_position_delta_msg(const mavlink_message_t &msg);
    #endif
    

    如果定义了HAL_GCS_ENABLED,处理MAVLink消息以获取视觉位置增量。

  • 姿态估计处理:

    virtual void handle_pose_estimate(uint64_t remote_time_us, uint32_t time_ms, float x, float y, float z, const Quaternion &attitude, float posErr, float angErr, uint8_t reset_counter, int8_t quality) = 0;
    

    纯虚函数,用于处理姿态估计。派生类必须实现此函数。

  • 视觉速度估计处理:

    virtual void handle_vision_speed_estimate(uint64_t remote_time_us, uint32_t time_ms, const Vector3f &vel, uint8_t reset_counter, int8_t quality) = 0;
    

    纯虚函数,用于处理视觉速度估计。派生类必须实现此函数。

  • 请求与AHRS对齐偏航:

    virtual void request_align_yaw_to_ahrs() {}
    

    虚函数,请求偏航与姿态和航向参考系统(AHRS)对齐。默认实现为空。

  • 请求与AHRS对齐位置:

    virtual void align_position_to_ahrs(bool align_xy, bool align_z) {}
    

    虚函数,请求位置与AHRS对齐。默认实现为空。

  • 起动检查:

    virtual bool pre_arm_check(char *failure_msg, uint8_t failure_msg_len) const { return true; }
    

    虚函数,执行起动前的检查。默认实现总是返回true

2.3 保护部分

  • 重置时间戳处理:

    uint32_t get_reset_timestamp_ms(uint8_t reset_counter);
    
  • 视觉里程计类型:

    AP_VisualOdom::VisualOdom_Type get_type(void) const { return _frontend.get_type(); }
    
  • 条件编译用于日志记录:

    #if HAL_LOGGING_ENABLED
    void Write_VisualOdom(float time_delta, const Vector3f &angle_delta, const Vector3f &position_delta, float confidence);
    void Write_VisualPosition(uint64_t remote_time_us, uint32_t time_ms, float x, float y, float z, float roll, float pitch, float yaw, float pos_err, float ang_err, uint8_t reset_counter, bool ignored, int8_t quality);
    void Write_VisualVelocity(uint64_t remote_time_us, uint32_t time_ms, const Vector3f &vel, uint8_t reset_counter, bool ignored, int8_t quality);
    #endif
    

2.4 成员变量

  • 前端引用:

    AP_VisualOdom &_frontend;
    
  • 最后更新时间:

    uint32_t _last_update_ms;
    
  • 重置计数器处理:

    uint8_t _last_reset_counter;
    uint32_t _reset_timestamp_ms;
    
  • 质量:

    int8_t _quality;
    

3. 重要例程

3.1 AP_VisualOdom_Backend::healthy

300ms内有数据更新,认为传感器健康。

#define AP_VISUALODOM_TIMEOUT_MS 300

// return true if sensor is basically healthy (we are receiving data)
bool AP_VisualOdom_Backend::healthy() const
{
    // healthy if we have received sensor messages within the past 300ms
    return ((AP_HAL::millis() - _last_update_ms) < AP_VISUALODOM_TIMEOUT_MS);
}

3.2 AP_VisualOdom_Backend::quality

    // return quality as a measure from -1 ~ 100
    // -1 means failed, 0 means unknown, 1 is worst, 100 is best
    int8_t quality() const { return _quality; }

3.3 AP_VisualOdom_Backend::handle_vision_position_delta_msg

AP_VisualOdom_Backend::handle_vision_position_delta_msg(const mavlink_message_t &msg)
|
|-- 解码消息
|   |-- mavlink_vision_position_delta_t packet;
|   |-- mavlink_msg_vision_position_delta_decode(&msg, &packet);
|
|-- 角度和位置增量的旋转应用
|   |-- const enum Rotation rot = _frontend.get_orientation();
|   |-- Vector3f angle_delta = Vector3f(packet.angle_delta[0], packet.angle_delta[1], packet.angle_delta[2]);
|   |   |-- angle_delta.rotate(rot);
|   |-- Vector3f position_delta = Vector3f(packet.position_delta[0], packet.position_delta[1], packet.position_delta[2]);
|   |   |-- position_delta.rotate(rot);
|
|-- 获取当前时间
|   |-- const uint32_t now_ms = AP_HAL::millis();
|   |-- _last_update_ms = now_ms;
|
|-- 发送到EKF (扩展卡尔曼滤波)
|   |
|   |-- 如果启用了AP_AHRS或日志记录
|   |   |-- const float time_delta_sec = packet.time_delta_usec * 1.0E-6;
|
|   |-- 如果启用了AP_AHRS
|   |   |-- AP::ahrs().writeBodyFrameOdom(packet.confidence,
|   |                                     position_delta,
|   |                                     angle_delta,
|   |                                     time_delta_sec,
|   |                                     now_ms,
|   |                                     _frontend.get_delay_ms(),
|   |                                     _frontend.get_pos_offset());
|
|-- 如果启用了日志记录
|   |-- Write_VisualOdom(time_delta_sec,
|                        angle_delta,
|                        position_delta,
|                        packet.confidence);
  1. 解码消息

    • 定义mavlink_vision_position_delta_t packet;
    • 调用mavlink_msg_vision_position_delta_decode(&msg, &packet);将消息解码到packet中。
  2. 角度和位置增量的旋转应用

    • 获取当前的旋转方式const enum Rotation rot = _frontend.get_orientation();
    • 创建Vector3f angle_delta并使用消息中的角度增量初始化。
      • 调用angle_delta.rotate(rot);应用旋转。
    • 创建Vector3f position_delta并使用消息中的位置增量初始化。
      • 调用position_delta.rotate(rot);应用旋转。
  3. 获取当前时间

    • 调用AP_HAL::millis();获取当前时间并保存到now_ms
    • 更新_last_update_ms为当前时间now_ms
  4. 发送到EKF

    • 如果启用了AP_AHRS或日志记录,计算时间增量const float time_delta_sec = packet.time_delta_usec * 1.0E-6;
    • 如果启用了AP_AHRS,调用AP::ahrs().writeBodyFrameOdom()方法,将姿态和位置增量数据发送到EKF。
      • 传递参数包括:置信度、位置增量、角度增量、时间增量、当前时间、前端的延迟和位置偏移。
  5. 日志记录

    • 如果启用了日志记录,调用Write_VisualOdom()方法记录传感器数据。
      • 传递参数包括:时间增量、角度增量、位置增量和置信度。

3.4 AP_VisualOdom_Backend::get_reset_timestamp_ms

// returns the system time of the last reset if reset_counter has not changed
// updates the reset timestamp to the current system time if the reset_counter has changed
uint32_t AP_VisualOdom_Backend::get_reset_timestamp_ms(uint8_t reset_counter)
{
    // update reset counter and timestamp if reset_counter has changed
    if (reset_counter != _last_reset_counter) {
        _last_reset_counter = reset_counter;
        _reset_timestamp_ms = AP_HAL::millis();
    }
    return _reset_timestamp_ms;
}

3.5 AP_VisualOdom_Backend::get_type

从前台类型中获取设备类型。

    AP_VisualOdom::VisualOdom_Type get_type(void) const {
        return _frontend.get_type();
    }

4. 日志记录

4.1 AP_VisualOdom_Backend::Write_VisualOdom

// Write visual odometry sensor data
void AP_VisualOdom_Backend::Write_VisualOdom(float time_delta, const Vector3f &angle_delta, const Vector3f &position_delta, float confidence)
{
    const struct log_VisualOdom pkt_visualodom {
        LOG_PACKET_HEADER_INIT(LOG_VISUALODOM_MSG),
        time_us             : AP_HAL::micros64(),
        time_delta          : time_delta,
        angle_delta_x       : angle_delta.x,
        angle_delta_y       : angle_delta.y,
        angle_delta_z       : angle_delta.z,
        position_delta_x    : position_delta.x,
        position_delta_y    : position_delta.y,
        position_delta_z    : position_delta.z,
        confidence          : confidence
    };
    AP::logger().WriteBlock(&pkt_visualodom, sizeof(log_VisualOdom));
}

4.2 AP_VisualOdom_Backend::Write_VisualPosition

// Write visual position sensor data.  x,y,z are in meters, angles are in degrees
void AP_VisualOdom_Backend::Write_VisualPosition(uint64_t remote_time_us, uint32_t time_ms, float x, float y, float z, float roll, float pitch, float yaw, float pos_err, float ang_err, uint8_t reset_counter, bool ignored, int8_t quality)
{
    const struct log_VisualPosition pkt_visualpos {
        LOG_PACKET_HEADER_INIT(LOG_VISUALPOS_MSG),
        time_us         : AP_HAL::micros64(),
        remote_time_us  : remote_time_us,
        time_ms         : time_ms,
        pos_x           : x,
        pos_y           : y,
        pos_z           : z,
        roll            : roll,
        pitch           : pitch,
        yaw             : yaw,
        pos_err         : pos_err,
        ang_err         : ang_err,
        reset_counter   : reset_counter,
        ignored         : (uint8_t)ignored,
        quality         : quality
    };
    AP::logger().WriteBlock(&pkt_visualpos, sizeof(log_VisualPosition));
}

4.3 AP_VisualOdom_Backend::Write_VisualVelocity

// Write visual velocity sensor data, velocity in NED meters per second
void AP_VisualOdom_Backend::Write_VisualVelocity(uint64_t remote_time_us, uint32_t time_ms, const Vector3f &vel, uint8_t reset_counter, bool ignored, int8_t quality)
{
    const struct log_VisualVelocity pkt_visualvel {
        LOG_PACKET_HEADER_INIT(LOG_VISUALVEL_MSG),
        time_us         : AP_HAL::micros64(),
        remote_time_us  : remote_time_us,
        time_ms         : time_ms,
        vel_x           : vel.x,
        vel_y           : vel.y,
        vel_z           : vel.z,
        vel_err         : _frontend.get_vel_noise(),
        reset_counter   : reset_counter,
        ignored         : (uint8_t)ignored,
        quality         : quality
    };
    AP::logger().WriteBlock(&pkt_visualvel, sizeof(log_VisualVelocity));
}

4. 总结

AP_VisualOdom_Backend类作为视觉里程计处理的后端模版,实现了通用的处理流程。因硬件设备驱动而已的API函数封装如下:

  • handle_pose_estimate
  • handle_vision_speed_estimate
  • request_align_yaw_to_ahrs
  • align_position_to_ahrs
  • pre_arm_check
    // consume vision pose estimate data and send to EKF. distances in meters
    // quality of -1 means failed, 0 means unknown, 1 is worst, 100 is best
    virtual void handle_pose_estimate(uint64_t remote_time_us, uint32_t time_ms, float x, float y, float z, const Quaternion &attitude, float posErr, float angErr, uint8_t reset_counter, int8_t quality) = 0;

    // consume vision velocity estimate data and send to EKF, velocity in NED meters per second
    // quality of -1 means failed, 0 means unknown, 1 is worst, 100 is best
    virtual void handle_vision_speed_estimate(uint64_t remote_time_us, uint32_t time_ms, const Vector3f &vel, uint8_t reset_counter, int8_t quality) = 0;

    // request sensor's yaw be aligned with vehicle's AHRS/EKF attitude
    virtual void request_align_yaw_to_ahrs() {}

    // handle request to align position with AHRS
    virtual void align_position_to_ahrs(bool align_xy, bool align_z) {}

    // arming check - by default no checks performed
    virtual bool pre_arm_check(char *failure_msg, uint8_t failure_msg_len) const { return true; }

5. 参考资料

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1904231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

redhat7.x 升级openssh至openssh-9.8p1

1.环境准备&#xff1a; OS系统&#xff1a;redhat 7.4 2.备份配置文件&#xff1a; cp -rf /etc/ssh /etc/ssh.bak cp -rf /usr/bin/openssl /usr/bin/openssl.bak cp -rf /etc/pam.d /etc/pam.d.bak cp -rf /usr/lib/systemd/system /usr/lib/systemd/system.bak 3.安装…

阿里云存储应用

如何做好权限控制 小浩在梳理门户网站静态资源时&#xff0c;发现有些资源是仅内部员工可访问&#xff0c;有些资源是特定的注册客户可访问&#xff0c;还有些资源是匿名客户也可以访问。针对不同场景、不同用户&#xff0c;小浩该如何规划企业门户网站静态资源的权限控制呢&a…

解析商场智能导视系统背后的科技:AR导航与大数据如何助力商业运营

在布局复杂的大型商场中&#xff0c;顾客常常面临寻找特定店铺的挑战。商场的规模庞大&#xff0c;店铺众多&#xff0c;使得顾客在享受购物乐趣的同时&#xff0c;也不得不面对寻路的难题。维小帮商场智能导航导视系统的电子地图、AR导航营销能为顾客提供更加便捷的购物体验。…

Linux—网络设置

目录 一、ifconfig——查看网络配置 1、查看网络接口信息 1.1、查看所有网络接口 1.2、查看具体的网络接口 2、修改网络配置 3、添加网络接口 4、禁用/激活网卡 二、hostname——查看主机名称 1、查看主机名称 2、临时修改主机名称 3、永久修改主机名称 4、查看本…

2023年了,还在手动px转rem吗?

px-to-rem 使用amfe-flexible和postcss-pxtorem在webpack中配置px转rem npm i amfe-flexible -Snpm i postcss-pxtorem -D在main.js中 import flexible from amfe-flexible Vue.use(flexible);index.html中 <meta name"viewport" content"widthdevice-w…

用 Echarts 画折线图

https://andi.cn/page/621503.html

Floyd判圈算法——环形链表(C++)

Floyd判圈算法(Floyd Cycle Detection Algorithm)&#xff0c;又称龟兔赛跑算法(Tortoise and Hare Algorithm)&#xff0c;是一个可以在有限状态机、迭代函数或者链表上判断是否存在环&#xff0c;求出该环的起点与长度的算法。 …

Java语言程序设计篇一

Java语言概述 Java语言起源编程语言最新排名名字起源Java语言发展历程Java语言的特点Java虚拟机垃圾回收Java语言规范Java技术简介Java程序的结构Java程序注意事项&#xff1a;注释编程风格练习 Java语言起源 1990年Sun公司提出一项绿色计划。1992年语言开发成功最初取名为Oak…

vue3使用方式汇总

1、引入iconfont阿里图库图标&#xff1a; 1.1 进入阿里图标网站&#xff1a; iconfont阿里&#xff1a;https://www.iconfont.cn/ 1.2 添加图标&#xff1a; 1.3 下载代码&#xff1a; 1.4 在vue3中配置代码&#xff1a; 将其代码复制到src/assets/fonts/目录下&#xff1…

大众点评2024年全球必吃榜清单

大众点评2024年全球必吃榜清单共2797家&#xff0c;奇怪的是官方并没有发布详细清单&#xff0c;只发布了新闻通稿介绍大概情况。这里做一些整理。 按城市分布情况&#xff0c;数量如下 上海 144 北京 137 成都 96 重庆 93 广州 81 深圳 79 武汉 69 苏州 67 杭州 61 …

应急响应--网站(web)入侵篡改指南

免责声明:本文... 目录 被入侵常见现象: 首要任务&#xff1a; 分析思路&#xff1a; 演示案例: IIS&.NET-注入-基于时间配合日志分析 Apache&PHP-漏洞-基于漏洞配合日志分析 Tomcat&JSP-弱口令-基于后门配合日志分析 (推荐) Webshell 查杀-常规后门&…

17_VGG深度学习图像分类算法

1.1 简介 VGG网络&#xff0c;全称为Visual Geometry Group网络&#xff0c;是由牛津大学的Visual Geometry Group和谷歌DeepMind的研究人员共同提出的深度卷积神经网络模型。这一模型因在2014年ILSVRC&#xff08;ImageNet大规模视觉识别挑战赛&#xff09;中取得图像分类任务…

昇思25天学习打卡营第4天|MindSpore数据集和数据变换

# 打卡 目录 # 打卡 Dateset&#xff1a;Pipeline 的起始 具体步骤 数据处理 Pipeline 代码例子 内置数据集的情况 自定义数据集的情况 可迭代的数据集 生成器 Transforms&#xff1a;数据预处理 代码例子 通用变换Compose 文本变换 Text Lambda变换 Dateset&…

STM32芯片系列与产品后缀解读

一. 产品系列 STM32单片机是一系列基于ARM Cortex-M内核的32位微控制器&#xff0c;广泛应用于嵌入式系统中。 STM32系列由STMicroelectronics&#xff08;意法半导体&#xff09;开发和生产&#xff0c;并凭借其灵活的设计、丰富的外设和强大的生态系统&#xff0c;成为嵌入式…

JVM专题之G1垃圾收集器下

索引(记录)的源码的工作流程图如下: CSet(Collection Set 回收集合) 收集集合(CSet)代表每次GC暂停时回收的一系列目标分区。在任意一次收集暂停中,CSet所有分区都会被释放,内部存活的对象都会被转移到分配的空闲分区中。因此无论是年轻代收集,还是混合收集,工作的机…

catia数控加工仿真铣平面粗加工

1&#xff0c;零件建模&#xff0c;毛坯建模 2 在毛坯上建立坐标系 3 添加资料刀具 4&#xff0c;双击对相关加工信息做设置 5 Roughing 加工设置 高亮红色区域是必选的&#xff0c;其他可以默认 6 完成加工仿真 7 加工余量

IntelliJ IDEA 同时多行同时编辑操作快捷键

首先 点击要编辑的地方,长按鼠标左键不放,同时按住 Ctrl Shift Alt,然后就可以进行多行编辑了

亲密数对C++函数

自定义函数 #include<bits/stdc.h> using namespace std; //求n的因子和自定义函数 int yinzihe(int n){//使用2~sqrt(n)成对求解因子和int r0,i;//变量 r 初始值为0&#xff0c;因为要存放因子和for(i2;i<sqrt(n);i) {//回顾sqrt()课程//如果 i 是 n 的因子&#xf…

用win的控制台去远程连接虚拟机linux的终端

以Ubuntu为例&#xff0c;首先确保Ubuntu已经安装了ssh服务 sudo apt-get install openssh-server输入密码 安装完毕后查看ssh状态是否开启 sudo systemctl status ssh 显示绿色激活状态&#xff0c;可以关闭或开启 对应start和stop winr打开win端控制台 输入 ssh -p 22 …

【Linux详解】进程等待 | 非阻塞轮询

引入&#xff1a; 为什么&#xff1f;是什么&#xff1f;怎么办 是什么&#xff1f; 进程等待是指父进程暂停自己的执行&#xff0c;直到某个特定的子进程结束或发生某些特定的事件。 为什么&#xff1f; 僵尸进程刀枪不入&#xff0c;不可被杀死&#xff0c;存在内存泄露…