ArduSub程序学习(11)--EKF实现逻辑①

news2024/12/23 17:22:58

1.read_AHRS()

进入EKF,路径ArduSub.cpp里面的fast_loop()里面的read_AHRS();

//从 AHRS(姿态与航向参考系统)中读取并更新与飞行器姿态有关的信息
void Sub::read_AHRS()
{
    // Perform IMU calculations and get attitude info
    //-----------------------------------------------
    // <true> tells AHRS to skip INS update as we have already done it in fast_loop()
    //告诉 AHRS 跳过惯性导航系统(INS)的更新,因为 INS 的更新已经在主循环的快速循环(fast_loop())中完成了。
    ahrs.update(true);
    ahrs_view.update(true);
}

2.update(ture)

负责更新AHRS的各个组件,并管理不同类型的扩展卡尔曼滤波器(EKF)

//通过EKF,读取姿态信息
void AP_AHRS_NavEKF::update(bool skip_ins_update)
{
    // support locked access functions to AHRS data
    //信号量锁定
    WITH_SEMAPHORE(_rsem);
    
    // drop back to normal priority if we were boosted by the INS
    // calling delay_microseconds_boost()
    //在完成传感器更新后,恢复调度器的正常优先级,之前可能使用过临时提升。
    hal.scheduler->boost_end();

    //更新DCM
    update_DCM(skip_ins_update);

    //针对SITL的条件编译
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
    update_SITL();
#endif

    //如果外部AHRS启用,则调用外部更新函数。
#if HAL_EXTERNAL_AHRS_ENABLED
    update_external();
#endif

    //hal.console->printf("Current EKF Type: %d\n", static_cast<int>(_ekf_type.get()));

    //EKF选择和执行
    if (_ekf_type == 2) {
        // if EK2 is primary then run EKF2 first to give it CPU
        // priority
#if HAL_NAVEKF2_AVAILABLE
        update_EKF2();
#endif
#if HAL_NAVEKF3_AVAILABLE
        update_EKF3();
#endif
    } else {
        // otherwise run EKF3 first
#if HAL_NAVEKF3_AVAILABLE
        update_EKF3();
#endif
#if HAL_NAVEKF2_AVAILABLE
        update_EKF2();
#endif
    }

#if AP_MODULE_SUPPORTED
    // call AHRS_update hook if any
    //如果支持任何模块,调用钩子以允许它们执行与AHRS相关的附加更新。
    AP_Module::call_hook_AHRS_update(*this);
#endif

    // push gyros if optical flow present
    //如果光流传感器可用,获取陀螺仪漂移(偏差)并用此信息更新光流系统。
    if (hal.opticalflow) {
        const Vector3f &exported_gyro_bias = get_gyro_drift();
        hal.opticalflow->push_gyro_bias(exported_gyro_bias.x, exported_gyro_bias.y);
    }

    if (_view != nullptr) {
        // update optional alternative attitude view
        //如果存在可选的替代视图,则更新该视图的姿态。
        _view->update(skip_ins_update);
    }

#if !HAL_MINIMIZE_FEATURES && AP_AHRS_NAVEKF_AVAILABLE
    // update NMEA output
    //如果未最小化功能且EKF可用,更新NMEA输出,这是用于海洋导航的标准。
    update_nmea_out();
#endif

    //检查当前活动EKF类型是否自上次更新以来发生变化
    EKFType active = active_EKF_type();
    //如果发生变化,则向地面控制站(GCS)发送关于当前活动EKF类型的消息。
    if (active != last_active_ekf_type) {
        last_active_ekf_type = active;
        const char *shortname = "???";
        switch ((EKFType)active) {
        case EKFType::NONE:
            shortname = "DCM";
            break;
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
        case EKFType::SITL:
            shortname = "SITL";
            break;
#endif
#if HAL_EXTERNAL_AHRS_ENABLED
        case EKFType::EXTERNAL:
            shortname = "External";
            break;
#endif
#if HAL_NAVEKF3_AVAILABLE
        case EKFType::THREE:
            shortname = "EKF3";
            break;
#endif
#if HAL_NAVEKF2_AVAILABLE
        case EKFType::TWO:
            shortname = "EKF2";
            break;
#endif
        }
        GCS_SEND_TEXT(MAV_SEVERITY_INFO, "AHRS: %s active", shortname);
    }
}

 2.1update_DCM(bool skip_ins_update)

        更新DCM(方向余弦矩阵,Direction Cosine Matrix)的作用是保持和更新飞行器或自主车辆的姿态信息,使得其在三维空间中的朝向能够持续精确地被估计和修正。

        陀螺仪在长时间运行时会产生漂移误差。更新DCM时,可以利用传感器(如加速度计、磁力计等)的测量值,计算与当前DCM表示的姿态之间的误差,并据此调整陀螺仪读数。通过这种方式,DCM能够起到校正漂移的作用,确保姿态估计的准确性。

//更新姿态和航向参考系统(AHRS)中的方向余弦矩阵(DCM)。DCM是一种用来表示三维空间中物体姿态的数学模型。
void AP_AHRS_NavEKF::update_DCM(bool skip_ins_update)
{
    // we need to restore the old DCM attitude values as these are
    // used internally in DCM to calculate error values for gyro drift
    // correction
    //恢复旧的DCM姿态值:
    roll = _dcm_attitude.x;
    pitch = _dcm_attitude.y;
    yaw = _dcm_attitude.z;
    //更新DCM的内部数据,确保当前姿态和其他相关值同步。
    update_cd_values();

    AP_AHRS_DCM::update(skip_ins_update);

    // keep DCM attitude available for get_secondary_attitude()
    //将更新后的 roll、pitch 和 yaw 值重新赋值回 _dcm_attitude
    _dcm_attitude = {roll, pitch, yaw};
}

        ★★在使用EKF进行姿态估计的系统中,DCM通常作为备用机制存在。当EKF失效或者不稳定时,系统可以回退到DCM来提供可靠的姿态估计。通过不断更新DCM,系统可以确保即使在EKF不可用的情况下,仍然有一个稳定的姿态估计可用。 

if (_ekf_type == 2) {
    update_EKF2();
    update_EKF3();
} else {
    update_EKF3();
    update_EKF2();
}
update_DCM(skip_ins_update);
  • EKF2和EKF3 是不同的卡尔曼滤波器版本,它们可能分别处理不同的数据源或者计算策略。系统根据具体情况优先更新某个EKF,并依次更新另一个EKF。
  • DCM的更新 则在EKF更新后进行,确保即便EKF更新失败或不稳定,系统仍能通过DCM获得姿态数据。

        在一些导航系统中,DCM可能作为EKF的初始估计工具。由于DCM计算效率高,姿态估计在短期内较为准确,EKF可以使用DCM的估计值作为其初始状态,逐渐根据传感器数据和预测模型进行更复杂的修正。

        如果EKF在某些情况下出现问题(如传感器数据丢失、不可靠的传感器输入等),系统可以回退到DCM,继续保持姿态估计的基本功能。因此,DCM作为EKF的一种补充或者冗余备份,能够增强系统的鲁棒性。

2.2update_EKF2();

 这段代码实现了AP_AHRS_NavEKF::update_EKF2()函数,用于更新飞行器导航系统中使用的扩展卡尔曼滤波器2(EKF2)的状态。该函数主要负责初始化EKF2滤波器并在之后的每个周期内更新滤波器状态,获取姿态估计、陀螺仪漂移修正、加速度计数据等。

//更新飞行器导航系统中使用的扩展卡尔曼滤波器2(EKF2)的状态
void AP_AHRS_NavEKF::update_EKF2(void)
{
    //hal.console->printf("_ekf2_started=%d\r\n",_ekf2_started);
   
    if (!_ekf2_started) {
        // wait 1 second for DCM to output a valid tilt error estimate
        //hal.console->printf("AAAAAA1\r\n");
         //等待1秒以便DCM输出有效的倾斜误差估计
        if (start_time_ms == 0) {
            start_time_ms = AP_HAL::millis();
        }
        // if we're doing Replay logging then don't allow any data
        // into the EKF yet.  Don't allow it to block us for long.
        // 检查看门狗是否重置并确保不长时间阻塞数据
        if (!hal.util->was_watchdog_reset()) {
            if (AP_HAL::millis() - start_time_ms < 5000) {
                //hal.console->printf("AAAAAA2\r\n");
                if (!AP::logger().allow_start_ekf()) {
                    return;
                }
            }
        }
         等待预设的启动延迟时间,然后初始化EKF2
        if (AP_HAL::millis() - start_time_ms > startup_delay_ms) {
            _ekf2_started = EKF2.InitialiseFilter();
        }
    }
    if (_ekf2_started) {
        //hal.console->printf("BBBBB1\r\n");
        //EKF2更新,融合传感器数据来更新姿态、速度和位置估计。
        EKF2.UpdateFilter();
        //hal.console->printf("BBBBB2\r\n");
        if (active_EKF_type() == EKFType::TWO) {
            //hal.console->printf("CCCCC1\r\n");
            Vector3f eulers;
            //矩阵更新
            EKF2.getRotationBodyToNED(_dcm_matrix);
            //姿态获取
            EKF2.getEulerAngles(-1,eulers);
            roll  = eulers.x;
            pitch = eulers.y;
            yaw   = eulers.z;

            update_cd_values();
            update_trig();

            // Use the primary EKF to select the primary gyro
            //陀螺仪漂移修正
            const int8_t primary_imu = EKF2.getPrimaryCoreIMUIndex();

            const AP_InertialSensor &_ins = AP::ins();

            // get gyro bias for primary EKF and change sign to give gyro drift
            // Note sign convention used by EKF is bias = measurement - truth
            //计算修正后的陀螺仪数据
            _gyro_drift.zero();
            EKF2.getGyroBias(-1,_gyro_drift);
            _gyro_drift = -_gyro_drift;

            // calculate corrected gyro estimate for get_gyro()
            _gyro_estimate.zero();
            if (primary_imu == -1 || !_ins.get_gyro_health(primary_imu)) {
                // the primary IMU is undefined so use an uncorrected default value from the INS library
                _gyro_estimate = _ins.get_gyro();
            } else {
                // use the same IMU as the primary EKF and correct for gyro drift
                _gyro_estimate = _ins.get_gyro(primary_imu) + _gyro_drift;
            }

            // get z accel bias estimate from active EKF (this is usually for the primary IMU)
            // 加速度计数据的处理与校正
            float abias = 0;
            EKF2.getAccelZBias(-1,abias);

            // This EKF is currently using primary_imu, and abias applies to only that IMU
            for (uint8_t i=0; i<_ins.get_accel_count(); i++) {
                Vector3f accel = _ins.get_accel(i);
                if (i == primary_imu) {
                    accel.z -= abias;
                }
                if (_ins.get_accel_health(i)) {
                    _accel_ef_ekf[i] = _dcm_matrix * get_rotation_autopilot_body_to_vehicle_body() * accel;
                }
            }
            _accel_ef_ekf_blended = _accel_ef_ekf[primary_imu>=0?primary_imu:_ins.get_primary_accel()];
            //滤波器状态更新
            nav_filter_status filt_state;
            EKF2.getFilterStatus(-1,filt_state);
            AP_Notify::flags.gps_fusion = filt_state.flags.using_gps; // Drives AP_Notify flag for usable GPS.
            AP_Notify::flags.gps_glitching = filt_state.flags.gps_glitching;
            AP_Notify::flags.have_pos_abs = filt_state.flags.horiz_pos_abs;
        }
    }
}

 

  • 初始化EKF2:函数首先检查EKF2是否启动,并在适当时机进行初始化。
  • 姿态和传感器数据更新:在EKF2成功启动后,获取姿态数据并修正陀螺仪和加速度计的漂移,确保姿态估计准确。
  • 滤波器状态和融合:不断更新EKF2的状态,结合传感器数据(如GPS)进行位置和姿态融合,确保系统导航的可靠性。

2.3 update_EKF3();

AP_AHRS_NavEKF::update_EKF3() 函数实现了扩展卡尔曼滤波器3(EKF3)的更新流程。它与 update_EKF2() 类似,但专门用于 EKF3 的处理。主要功能包括初始化滤波器、更新姿态数据、陀螺仪漂移修正、加速度计偏置校正等。

未完待续~~

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

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

相关文章

WinForm程序嵌入Web网页

文章目录 前言一、三方库或控件的选择测试二、Microsoft Edge WebView2安装、使用步骤1.安装2.使用 前言 由于此项目需要winform客户端嵌入web网页并于JAVA端交互数据&#xff0c;所以研究了一下嵌入web网页这部分&#xff0c;趟了一遍雷&#xff0c;这里做下记录。 一、三方库…

软件设计之Maven(2)

软件设计之Maven(2) 路线图推荐&#xff1a; 【Java学习路线-极速版】【Java架构师技术图谱】 尚硅谷新版Maven教程&#xff08;高效入门maven&#xff0c;上手又快又稳&#xff09; 资料可以去尚硅谷官网免费领取 学习内容&#xff1a; 依赖管理版本统一及维护依赖范围Buil…

Comfyui 学习笔记1

如果图像输出被裁剪&#xff0c;则需要使用PrepImageForClipVision&#xff0c;来设置图像距离上边沿的位置. 决定绘画的作用区域&#xff0c;后面的KSample只作用到 mask标记的范围。 图像位置偏移了&#xff0c;可以考虑通过Image crop 裁剪 IPAdapter face 提取时&…

基于Python大数据可视化的白酒数据推荐及数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Java并发:互斥锁,读写锁,公平锁,Condition,StampedLock

阅读本文之前可以看一看 Java 多线程基础&#xff1a; Java&#xff1a;多线程&#xff08;进程线程&#xff0c;线程状态&#xff0c;创建线程&#xff0c;线程操作&#xff09; Java&#xff1a;多线程&#xff08;同步死锁&#xff0c;锁&原子变量&#xff0c;线程通信&…

《Linux从小白到高手》理论篇(二):Linux的目录结构和磁盘管理

List item 本篇主要介绍Linux的目录结构和磁盘管理相关的命令。 Linux目录结构 在Linux的世界里&#xff0c;一切皆文件&#xff0c;连目录也不例外。linux的文件系统是采用级层式的树状目录结构&#xff0c;在此结构中的最上层是根目录“/”&#xff08;相当于windows下的&…

【VUE】案例:商场会员管理系统

编写vuedfr实现对会员进行基本增删改查 1. drf项目初始化 请求&#xff1a; POST http://127/0.0.0.1:8000/api/auth/ {"username":"cqn", "password":"123"}返回&#xff1a; {"username":"cqn", "token&q…

开源 AI 智能名片 O2O 商城小程序与抖音:品牌传播的新机遇与挑战

摘要&#xff1a;本文探讨了开源 AI 智能名片 O2O 商城小程序在品牌传播中的作用&#xff0c;以及与抖音平台相结合所带来的机遇与挑战。分析了抖音如何利用算法适配品牌调性为门店找到目标消费者&#xff0c;放大品牌势能&#xff0c;同时阐述了新品牌在抖音上进行品牌传播的优…

后端返回内容有换行标识,前端如何识别换行

<br/>的话 用 v-html \n 可以用css样式 white-space: pre-wrap 后端返回结果 前端

集成电路发展的两条主线

集成电路发展的两条主线&#xff0c; 1、增大晶圆尺寸&#xff0c;6、8、12英寸 晶圆尺寸不断增大&#xff0c;其设备要求不断增大。目前主流的8英寸&#xff0c;12英寸正在发展 2、芯片工艺制程不断减小

基于Hive和Hadoop的用电量分析系统

本项目是一个基于大数据技术的用电量分析系统&#xff0c;旨在为用户提供全面的电力消耗信息和深入的用电量分析。系统采用 Hadoop 平台进行大规模数据存储和处理&#xff0c;利用 MapReduce 进行数据分析和处理&#xff0c;通过 Sqoop 实现数据的导入导出&#xff0c;以 Spark…

quill富文本插入表格quill-better-table

使用quill-better-table插件&#xff0c;官网GitCode - 全球开发者的开源社区,开源代码托管平台 安装 首先quill-better-table插件&#xff0c;官网有写需要 quills v2.0.0-dev3 我这里使用的是 quills v2.0.0-dev4&#xff0c;自行安装 然后就是安装我们的插件 quill-bett…

【项目资料】项目售后服务方案(Word)

1.1 售后服务方案 概述 售后服务体系 售后服务流程 售后服务承诺 售后服务计划 技术支持响应承诺 售后服务响应时间 1.2 项目培训方案 项目培训体系 项目培训管理 培训目的与措施 项目培训安排 培训告知下达 培训人员贯彻 培训签到表 软件全套资料部分文档清单&#xff1a; 工作…

10款超好用的文档加密软件|2024企业文档加密软件分享

在信息安全日益受到重视的今天&#xff0c;选择合适的文档加密软件至关重要。以下是2024年值得关注的10款超好用的文档加密软件&#xff0c;帮助企业提升数据安全性。 1. Ping32文档加密软件 Ping32专注于文档加密&#xff0c;采用强大的AES加密技术&#xff0c;确保敏感信息在…

领夹式无线麦克风哪个品牌好,口碑最好的领夹麦克风品牌推荐

对于追求专业音频录制的创作者而言&#xff0c;无线领夹麦克风不仅是录制设备&#xff0c;更是表达自我的艺术工具。从市场反馈中&#xff0c;我们发现西圣、大疆、罗德等品牌深受消费者喜爱。不过我看事情不能只看一面&#xff0c;在市场繁荣的表象下&#xff0c;一些劣质产品…

单片机的两种看门狗原理解析——IWDG和WWDG

一、IWDG独立开门狗的主要性能 计时机制&#xff1a; 递减计数器 独立开门狗的初始频率&#xff1a; LSI低速内部时钟&#xff1a;RC震荡器&#xff0c;40kHz 独立开门狗是以LSI为初始频率的&#xff0c;所以独立开门狗的初始时钟频率取决与单片机本身&#xff0c;因此在使…

Charles(青花瓷)抓取https请求

文章目录 前言Charles&#xff08;青花瓷&#xff09;抓取https请求 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不会太差&#xff0c;实在白嫖的话&…

【工具分享】Chimera勒索病毒解密工具

前言 Chimera勒索软件首次出现在2015年&#xff0c;最初是在德国被发现。该勒索软件不仅加密受害者的文件&#xff0c;还威胁如果不支付赎金&#xff0c;就会将被盗的数据公开发布。这种“双重勒索”策略使得Chimera在众多勒索软件中脱颖而出。Chimera通常通过钓鱼邮件传播&am…

第五部分:6---信号的递达

目录 信号的递达流程&#xff1a; 信号在什么时候递达&#xff1f; 用户态和内核态&#xff1a; 内核态、用户态在页表的映射关系&#xff1a; 操作系统如何得知当前执行状态是用户态还是内核态&#xff1f; 操作系统如何处理被捕捉的信号&#xff1f; 信号的递达流程&am…

Python PyQt5 在frame中生成多个QLabel控件和彻底销毁QLabel控件

文章目录 步骤 1: 创建主窗口和布局步骤 2: 添加QLabel到QFrame步骤 3: 销毁QLabel示例代码 在PyQt5中&#xff0c;在QFrame或任何其他容器控件中生成多个QLabel控件并通过一个标志位或方法来彻底销毁这些QLabel控件是相对直接的操作。以下是一个简单的示例&#xff0c;展示了如…