当前位置:   article > 正文

【算法基础学习 4】互补滤波算法——PX4姿态估计_pixhawk 6c 互补滤波

pixhawk 6c 互补滤波

目录

应用场景

名词解释

陀螺仪

加速度计

磁力计(又叫磁罗盘)

坐标系

姿态表示

滤波原理

滤波主要过程

预备知识

预测

校正

加速度计校正

磁力计校正

更新四元数

源码分析

主程序运行流程图

函数功能简述

源码分析

头文件

using @@@

namespace attitude_estimator_q

类定义: class AttitudeEstimatorQ

构造函数   

析构函数

start();

print();

task_main_trampoline();

task_main();

update_parameters();

init();

update();

update_mag_declination();

attitude_estimator_q_main();


前言:多旋翼的姿态估计算法通常采用自适应显示互补滤波算法、扩展卡尔曼滤波算法、梯度下降算法等,以上三种方法均是对姿态解算的实现,采用的基本思路都是利用陀螺仪的动态稳定性来估计实时姿态,同时由于陀螺仪随时间积分累计漂移误差的固有缺陷,需找一个不随时间变化影响的传感器来估计姿态并进行修正标定。三种方法各有优缺点,互补与梯度算法更适用于处理性能受限的飞行器,例如微型四轴等采用低频Cortex-M0或M1的处理器,而在条件允许性能足够的情况下,建议考虑采用扩展卡尔曼滤波的算法。

PX4 源码中采用的是改进的互补滤波算法,在原有加速度计校准陀螺仪的基础上,增加磁力计和GPS数据进行更进一步的四元数校准补偿,它的优点是运算简单,因此成为PX4中默认的姿态解算算法)

通过下文介绍的多旋翼姿态估计来了解互补滤波算法

应用场景

本文中 mahony 的应用场景为 多旋翼无人机的姿态估计。 

 
陀螺仪、加速度计、MPU6050 详述

名词解释

陀螺仪

陀螺仪,测量角速度,具有高动态特性,它是一个间接测量角度的器件。它测量的是角度的导数,即角速度,要将角速度对时间积分才能得到角度。由于噪声等误差影响,在积分作用下不断积累,最终导致陀螺仪的低频干扰和漂移。

加速度计

输出当前加速度(包含重力加速度 g)的方向【也叫重力感应器】,在悬停时,输出为 g。由其测量原理导致的高频信号敏感,使得加速度计在振动环境中高频干扰较大。

磁力计(又叫磁罗盘)

输出为当前机体与地磁场的夹角。测量原理与指南针相似。低频特性较好,易受周围磁场干扰。 
磁力计的工作原理参考:http://blog.sina.com.cn/s/blog_402c071e0102v8ig.html

坐标系

  • 导航坐标系:在多旋翼中,又叫地球坐标系、地理坐标系。通常,采用北东地(NED)构成坐标系的 X,Y,Z 轴。
  • 机体坐标系 :固联在多旋翼飞行器上,即,坐标系原点定位于飞行器中心点(假设中心点与重心点重合)。

关于航空导航用到的坐标系,请参考 AIAA 系列丛书。在多旋翼中,因为只在低空飞行,且时间较短,只需要以上两个。

姿态表示

  • 欧拉角 :较直观,描述刚体在三维欧式空间中的姿态。此时,坐标系为机体坐标系,随着刚体的旋转而旋转。缺点:万向节锁。 
  • 四元数:由一组四维向量,表示刚体的三维旋转。适合用于计算机计算。 
  • 方向余弦矩阵DCM:用欧拉角余弦值或四元数,表示的坐标系的旋转。

滤波原理

互补滤波要求两个信号的干扰噪声处在不同的频率,通过设置两个滤波器的截止频率,确保融合后的信号能够覆盖需求频率。 
在 IMU 的姿态估计中,互补滤波器对陀螺仪(低频噪声)使用高通滤波;对加速度/磁力计(高频噪声)使用低频滤波。 
(此处尚未对传感器数据实测,噪声和有用频率未知。。。。待后期补足)

互补滤波中,两个滤波器的截止频率一致,此时就需要根据有用频率的值对其进行取舍。

机体水平时,加速度计无法测量绕 Z 轴的旋转量,即偏航角。磁力计也有同样问题,无法测得要磁轴的旋转量。故,需要加速度计和磁力计同时对陀螺仪进行校正。

滤波主要过程


式中,q^ 表示系统姿态估计的四元数表示; δ 是经过 PI 调节器产生的新息; e 表示实测的惯性向量 v¯ 和预测的向量v^ 之间的相对旋转(误差)。 
P(⋅) —— pure quaternion operator(四元数实部为0),表示只有旋转。

PI 调节器中:

参数 kp 用于控制加速度计和陀螺仪之间的交叉频率
参数 kI 用于校正陀螺仪误差


预备知识

主要是公式,不包含推导过程。。。。

欧拉角与机体角速度的关系:


旋转矩阵与机体角速度的关系:

四元数与机体角速度的关系:

参考:北航全权老师课件 第五章内容、惯性导航(秦永元)第九章内容。

预测

与卡尔曼滤波相似,互补滤波也分为预测-校正。 
在预测环节,由三轴陀螺仪测得的角速度,通过式(1)计算出四元数姿态预测。表示从地球坐标系到机体坐标系,或机体坐标系姿态在地球坐标系下的表示。

校正

在预测环节得到的四元数 ,通过加速度计和磁力计的值进行校正。该环节通常分为两部分:

通过加速度计得到 ,然后校正四元数中的横滚(roll)和俯仰(pitch)分量。
当磁力计可读时,通过 校正四元数中的偏航(yaw)分量。

加速度计校正

加速度计信号首先经过低通滤波器(消除高频噪声):


然后,对得到的结果进行归一化(normalized)


计算偏差:


式中, v表示重力向量在机体坐标系的向量。


此时,由 v 与加速度计向量垂直分量叉乘,得到误差值。【两个物理意义相同的向量,理论上叉乘为零】

磁力计校正

数据预处理与加速度计相同,先滤波,然后归一化,得到

1. 无 GPS 校准时:
计算误差:

式中,w 计算过程如下:

磁力计的输出(m)在机体坐标系下,将其转换到导航坐标系:

导航坐标系的 x 轴与正北对齐,故,可以将磁力计在 xoy 平面的投影折算到 x 轴。

再次变换到机体坐标系:


2. 有 GPS 校准时:
在 px4 中,磁力计使用 GPS 信息 [0,0,mag] 进行校准,故,公式与加速度计相同。


此时,由 w 与磁力计向量叉乘,得到误差值。【两个物理意义相同的向量,理论上叉乘为零】

更新四元数

由加速度计和磁力计校准得到的误差值:

由该误差值得到修正值:(只有 ki 修正bias)

修正后的角速度值:

根据一阶龙格库塔方法求解一阶微分方程:

可以求出四元数微分方程的差分形式:

四元数规范化:


源码分析

该部分源码直接截取 px4 开源飞控源码(BSD证书)。 
px4 为 pixhawk 飞控的固件代码,内部涉及很多滤波及导航的算法。有较大参考价值。

源码,参考日期:20160603;

https://github.com/hsteinhaus/PX4Firmware/blob/master/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp

https://github.com/ArduPilot/PX4Firmware/blob/master/src/modules/attitude_estimator_q/attitude_estimator_q_main.cpp

           参数            默认值    

  • ATT_W_ACC     0.2f    加速度计权重
  • ATT_W_MAG    0.1f    磁力计权重
  • ATT_W_EXT_HDG    0.1f    外部航向权重
  • ATT_W_GYRO_BIAS    0.1f    陀螺仪偏差权重
  • ATT_MAG_DECL    0.0f    磁偏角(°)
  • ATT_MAG_DECL_A    1    启用基于GPS的自动磁偏角校正
  • ATT_EXT_HDG_M    0    外部航向模式
  • ATT_ACC_COMP    1    启用基于GPS速度的加速度补偿
  • ATT_BIAS_MAX    0.05f    陀螺仪偏差上限
  • ATT_VIBE_THRESH    0.2f    振动水平报警阈值

主程序运行流程图

函数功能简述

  • AttitudeEstimatorQ::AttitudeEstimatorQ();   构造函数,初始化参数;
  • AttitudeEstimatorQ::~AttitudeEstimatorQ(); 析构函数,杀掉所有任务;
  • int AttitudeEstimatorQ::start();   启动【attitude_estimator_q】进程,主函数入口: task_main_trampoline
  • void AttitudeEstimatorQ::print();  打印姿态信息;
  • void AttitudeEstimatorQ::task_main_trampoline(int argc, char *argv[])

  {

   attitude_estimator_q::instance->task_main();

  }

  • void AttitudeEstimatorQ::task_main();  主任务进程;
  • void AttitudeEstimatorQ::update_parameters(bool force);   

false: 查看参数是否更新;

true: 获取新参数, 并由磁偏角更新四元数;

  • bool AttitudeEstimatorQ::init();    由加速度计和磁力计初始化旋转矩阵,有GPS时,校正磁偏角。
  • bool AttitudeEstimatorQ::update(float dt);  调用init(); 互补滤波
  • void AttitudeEstimatorQ::update_mag_declination(float new_declination);  使用磁偏角更新四元数
  • int attitude_estimator_q_main(int argc, char *argv[]);

attitude_estimator_q { start }:实例化instance,运行instance->start();

attitude_estimator_q { stop }:delete instance,指针置空;

attitude_estimator_q { status}:instance->print(),打印姿态信息。


源码分析

此处源码逐行分析,可以使用 Ctrl+f 快速定位;
uORB 相关的数据结构,请参考 px4/Firmware/msg;

  1. /*代码前的注释段(L34~L40
  2.  * @file attitude_estimator_q_main.cpp
  3.  *
  4.  * Attitude estimator (quaternion based)
  5.  *姿态估计(基于四元数)
  6.  * @author Anton Babushkin <anton.babushkin@me.com>
  7.  */

头文件

  1. (l42~l76
  2. #include <px4_config.h>
  3. #include <px4_posix.h>//add missing check;
  4. #include <unistd.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #include <stdbool.h>
  8. #include <poll.h>
  9. #include <fcntl.h>
  10. #include <float.h>
  11. #include <errno.h>
  12. #include <limits.h>
  13. #include <math.h>
  14. #include <uORB/uORB.h>
  15. #include <uORB/topics/sensor_combined.h>
  16. #include <uORB/topics/vehicle_attitude.h>
  17. #include <uORB/topics/control_state.h>
  18. #include <uORB/topics/vehicle_control_mode.h>
  19. #include <uORB/topics/vehicle_global_position.h>
  20. #include <uORB/topics/vision_position_estimate.h>//视觉位置估计, 未找到文件【待查】;
  21. #include <uORB/topics/att_pos_mocap.h>//mocap-->vicon;
  22. #include <uORB/topics/airspeed.h>
  23. #include <uORB/topics/parameter_update.h>
  24. #include <uORB/topics/estimator_status.h>
  25. #include <drivers/drv_hrt.h>
  26. #include <mathlib/mathlib.h>
  27. #include <mathlib/math/filter/LowPassFilter2p.hpp>
  28. #include <lib/geo/geo.h>
  29. #include <lib/ecl/validation/data_validator_group.h>
  30. #include <systemlib/systemlib.h>
  31. #include <systemlib/param/param.h>
  32. #include <systemlib/perf_counter.h>
  33. #include <systemlib/err.h>
  34. #include <systemlib/mavlink_log.h>


using @@@

  1. (l78~l82)
  2. extern "C" __EXPORT int attitude_estimator_q_main(int argc, char *argv[]);
  3. using math::Vector;
  4. using math::Matrix;
  5. using math::Quaternion;

此处,extern “C” 表示以 C 格式编译; __EXPORT 表示 将函数名输出到链接器(Linker); using 关键字 表示引入名称到 using 说明出现的声明区域。。

__export 
This keyword aids those programming Microsoft Windows. __export causes the function name to be exported to the linker.

namespace attitude_estimator_q

  1. (l84~l89)
  2. class AttitudeEstimatorQ;
  3. namespace attitude_estimator_q
  4. {
  5. AttitudeEstimatorQ *instance;
  6. }//定义命名空间,通过命名空间调用instance;

类定义: class AttitudeEstimatorQ

 

  1.     (l92~l210)
  2. class AttitudeEstimatorQ
  3. {//类定义; 
  4. public:
  5.     AttitudeEstimatorQ();
  6.     //构造函数
  7.     ~AttitudeEstimatorQ();
  8.     //析构函数
  9.      int        start();
  10.     //开始任务,成功--返回OK;
  11.     static void task_main_trampoline(int argc, char *argv[]);
  12.     //跳转到 task_main() ,未使用传入参数;static函数只能被本文件中的函数调用;
  13.     void        task_main();
  14.     void        print();
  15. private:
  16.     static constexpr float _dt_max = 0.02;//最大时间间隔;
  17.     //constexpr(constant expression)常数表达式,c11新关键字;
  18.     //优化语法检查和编译速度;
  19.     bool        _task_should_exit = false;
  20.     //如果为 true ,任务退出;
  21.     int     _control_task = -1;
  22.     //进程ID, 默认-1表示没有任务;
  23.     int     _sensors_sub = -1;//sensor_combined subscribe(订阅);
  24.     int     _params_sub = -1;//parameter_update subscribe;
  25.     int     _vision_sub = -1;//视觉位置估计;
  26.     int     _mocap_sub = -1;//vicon姿态位置估计;
  27.     int     _airspeed_sub = -1;//airspeed subscribe;
  28.     int     _global_pos_sub = -1;//vehicle_global_position subscribe;
  29.     orb_advert_t    _att_pub = nullptr;//vehicle_attitude publish(发布);
  30.     orb_advert_t    _ctrl_state_pub = nullptr;//发布控制状态主题control_state;
  31.     orb_advert_t    _est_state_pub = nullptr;//estimator_status
  32.     struct {
  33.         param_t w_acc;//ATT_W_ACC
  34.         param_t w_mag;//ATT_W_MAG
  35.         param_t w_ext_hdg;//ATT_W_EXT_HDG 外部航向权重;
  36.         param_t w_gyro_bias;//ATT_W_GYRO_BIAS
  37.         param_t mag_decl;//ATT_MAG_DECL
  38.         param_t mag_decl_auto;//ATT_MAG_DECL_A 磁偏角自动校正;
  39.         param_t acc_comp;//ATT_ACC_COMP
  40.         param_t bias_max;//ATT_BIAS_MAX 陀螺仪偏差上限;
  41.         param_t vibe_thresh;//ATT_VIBE_THRESH 振动报警阈值;
  42.         param_t ext_hdg_mode;//ATT_EXT_HDG_M 外部航向模式;
  43.     }       _params_handles;
  44.     //有用参数的句柄;
  45.     float       _w_accel = 0.0f;
  46.     //ATT_W_ACC >>> w_acc >>> _w_accel;
  47.     float       _w_mag = 0.0f;
  48.     float       _w_ext_hdg = 0.0f;
  49.     float       _w_gyro_bias = 0.0f;
  50.     float       _mag_decl = 0.0f;
  51.     bool        _mag_decl_auto = false;
  52.     bool        _acc_comp = false;
  53.     float       _bias_max = 0.0f;
  54.     float       _vibration_warning_threshold = 1.0f;//振动警告阈值;
  55.     hrt_abstime _vibration_warning_timestamp = 0;
  56.     int     _ext_hdg_mode = 0;
  57.     Vector<3>   _gyro;//陀螺仪;
  58.     Vector<3>   _accel;//加速度计;
  59.     Vector<3>   _mag;//磁力计;
  60.     vision_position_estimate_s _vision = {};//buffer;
  61.     Vector<3>   _vision_hdg;
  62.     att_pos_mocap_s _mocap = {};//buffer;
  63.     Vector<3>   _mocap_hdg;
  64.     airspeed_s _airspeed = {};//buffer;
  65.     Quaternion  _q;//四元数;
  66.     Vector<3>   _rates;//姿态角速度;
  67.     Vector<3>   _gyro_bias;//陀螺仪偏差;
  68.     vehicle_global_position_s _gpos = {};//buffer;
  69.     Vector<3>   _vel_prev;//前一时刻的速度:
  70.     Vector<3>   _pos_acc;//加速度(body frame??)
  71.     DataValidatorGroup _voter_gyro;//数据验证,剔除异常值;
  72.     DataValidatorGroup _voter_accel;
  73.     DataValidatorGroup _voter_mag;
  74.     //姿态速度的二阶低通滤波器;
  75.     math::LowPassFilter2p _lp_roll_rate;
  76.     math::LowPassFilter2p _lp_pitch_rate;
  77.     math::LowPassFilter2p _lp_yaw_rate;
  78.     //绝对时间(ms)
  79.     hrt_abstime _vel_prev_t = 0;//前一时刻计算速度时的绝对时间;
  80.     bool        _inited = false;//初始化标识;
  81.     bool        _data_good = false;//数据可用;
  82.     bool        _failsafe = false;//故障保护;
  83.     bool        _vibration_warning = false;//振动警告;
  84.     bool        _ext_hdg_good = false;//外部航向可用;
  85.     orb_advert_t    _mavlink_log_pub = nullptr;//mavlink log advert;
  86.     //performance measuring tools (counters)
  87.     perf_counter_t _update_perf;
  88.     perf_counter_t _loop_perf;//未看到使用。。。;
  89.     void update_parameters(bool force);//更新参数;
  90.     int update_subscriptions();//未使用【待查??】
  91.     bool init();
  92.     bool update(float dt);
  93.     // 偏航角旋转后,立即更新磁偏角;
  94.     void update_mag_declination(float new_declination);
  95. };

构造函数
   

  1. (l213~l235)
  2. AttitudeEstimatorQ::AttitudeEstimatorQ() :
  3.     _vel_prev(0, 0, 0),
  4.     _pos_acc(0, 0, 0),
  5.     _voter_gyro(3),//数据成员3个;
  6.     _voter_accel(3),
  7.     _voter_mag(3),
  8.     _lp_roll_rate(250.0f, 30.0f),//低通滤波(采样频率,截止频率);
  9.     _lp_pitch_rate(250.0f, 30.0f),
  10.     _lp_yaw_rate(250.0f, 20.0f)
  11. {
  12.     _voter_mag.set_timeout(200000);//磁力计超时;
  13.     //读取Attitude_estimator_q_params.c中的参数;
  14.     _params_handles.w_acc       = param_find("ATT_W_ACC");
  15.     _params_handles.w_mag       = param_find("ATT_W_MAG");
  16.     _params_handles.w_ext_hdg   = param_find("ATT_W_EXT_HDG");//外部航向权重;
  17.     _params_handles.w_gyro_bias = param_find("ATT_W_GYRO_BIAS");
  18.     _params_handles.mag_decl    = param_find("ATT_MAG_DECL");
  19.     _params_handles.mag_decl_auto   = param_find("ATT_MAG_DECL_A");//磁偏角自动校正;
  20.     _params_handles.acc_comp    = param_find("ATT_ACC_COMP");
  21.     _params_handles.bias_max    = param_find("ATT_BIAS_MAX");//陀螺仪偏差上限;
  22.     _params_handles.vibe_thresh = param_find("ATT_VIBE_THRESH");//振动警告阈值;
  23.     _params_handles.ext_hdg_mode    = param_find("ATT_EXT_HDG_M");
  24. }

析构函数

  1. l240~l262
  2. AttitudeEstimatorQ::~AttitudeEstimatorQ()
  3. {//杀掉所有任务;
  4.     if (_control_task != -1) {
  5.         /* task wakes up every 100ms or so at the longest */
  6.         _task_should_exit = true;
  7.         /* wait for a second for the task to quit at our request */
  8.         unsigned i = 0;
  9.         do {
  10.             /* wait 20ms */
  11.             usleep(20000);
  12.             /* if we have given up, kill it */
  13.             if (++i > 50) {
  14.                 px4_task_delete(_control_task);
  15.                 break;
  16.             }
  17.         } while (_control_task != -1);
  18.     }
  19.     attitude_estimator_q::instance = nullptr;
  20. }

start();

  1. l264~l282
  2. int AttitudeEstimatorQ::start()
  3. {
  4.     ASSERT(_control_task == -1);
  5.     /* start the task */
  6.     //启动任务,返回进程ID;
  7.     _control_task = px4_task_spawn_cmd("attitude_estimator_q",/*name*/
  8.                        SCHED_DEFAULT,/*任务调度程序*/
  9.                        SCHED_PRIORITY_MAX - 5,/*优先级*/
  10.                        2500,/*栈大小*/
  11.                        (px4_main_t)&AttitudeEstimatorQ::task_main_trampoline,/*主函数入口*/
  12.                        nullptr);
  13.     if (_control_task < 0) {
  14.         warn("task start failed");
  15.         return -errno;
  16.     }
  17.     return OK;
  18. }

print();

  1. l284~l292
  2. void AttitudeEstimatorQ::print()
  3. {//打印当前姿态信息;
  4.     warnx("gyro status:");
  5.     _voter_gyro.print();
  6.     warnx("accel status:");
  7.     _voter_accel.print();
  8.     warnx("mag status:");
  9.     _voter_mag.print();
  10. }

task_main_trampoline();

  1. l294~l297
  2. void AttitudeEstimatorQ::task_main_trampoline(int argc, char *argv[])
  3. {
  4.     attitude_estimator_q::instance->task_main();
  5. }

task_main();

  1. l299~l655
  2. void AttitudeEstimatorQ::task_main()
  3. {
  4. #ifdef __PX4_POSIX
  5. //记录事件执行所花费的时间,performance counters;
  6.     perf_counter_t _perf_accel(perf_alloc_once(PC_ELAPSED, "sim_accel_delay"));
  7.     perf_counter_t _perf_mpu(perf_alloc_once(PC_ELAPSED, "sim_mpu_delay"));
  8.     perf_counter_t _perf_mag(perf_alloc_once(PC_ELAPSED, "sim_mag_delay"));
  9. #endif
  10. //从uORB订阅主题;
  11.     _sensors_sub = orb_subscribe(ORB_ID(sensor_combined));
  12. //订阅传感器读数,包含数据参见:Firmware/msg/sensor_combined.msg
  13.     _vision_sub = orb_subscribe(ORB_ID(vision_position_estimate));//视觉;
  14.     _mocap_sub = orb_subscribe(ORB_ID(att_pos_mocap));//vicon; 
  15.     _airspeed_sub = orb_subscribe(ORB_ID(airspeed));//空速,见Firmware/msg/airspeed.msg;
  16.     _params_sub = orb_subscribe(ORB_ID(parameter_update));//bool saved;
  17.     _global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position));//位置估计值(GPS);
  18.     update_parameters(true);//获取新参数;
  19.     hrt_abstime last_time = 0;
  20.     px4_pollfd_struct_t fds[1] = {};
  21.     fds[0].fd = _sensors_sub;//文件描述符;
  22.     fds[0].events = POLLIN;//读取事件标识;
  23.     //POLLIN: data other than high-priority data may be read without blocking;
  24.     while (!_task_should_exit) {
  25.         int ret = px4_poll(fds, 1, 1000);
  26.         //timeout = 1000; fds_size = 1; 详见Linux的poll函数;
  27.         //对字符设备读写;
  28.         if (ret < 0) {
  29.             // Poll error, sleep and try again
  30.             usleep(10000);
  31.             PX4_WARN("Q POLL ERROR");
  32.             continue;
  33.         } else if (ret == 0) {
  34.             // Poll timeout, do nothing
  35.             PX4_WARN("Q POLL TIMEOUT");
  36.             continue;
  37.         }
  38.         update_parameters(false);//检查orb是否更新;
  39.         // Update sensors
  40.         sensor_combined_s sensors;
  41.         int best_gyro = 0;
  42.         int best_accel = 0;
  43.         int best_mag = 0;
  44.         if (!orb_copy(ORB_ID(sensor_combined), _sensors_sub, &sensors)) {
  45.             // Feed validator with recent sensor data
  46.             //(put)将最近的传感器数据送入验证组(DataValidatorGroup)
  47.             for (unsigned i = 0; i < (sizeof(sensors.gyro_timestamp) / sizeof(sensors.gyro_timestamp[0])); i++) {
  48.             //遍历每个陀螺仪数据;
  49.                 /* ignore empty fields */
  50.                 //忽略空值;
  51.                 if (sensors.gyro_timestamp[i] > 0) {
  52.                     float gyro[3];
  53.                     for (unsigned j = 0; j < 3; j++) {
  54.                         if (sensors.gyro_integral_dt[i] > 0) {
  55.                         //delta time 大于零;
  56.                             gyro[j] = (double)sensors.gyro_integral_rad[i * 3 + j] / (sensors.gyro_integral_dt[i] / 1e6);
  57.                             //=角度/时间(1e6用于us->s转换);
  58.                         } else {
  59.                             /* fall back to angular rate */
  60.                             //没有数据更新,回退;
  61.                             gyro[j] = sensors.gyro_rad_s[i * 3 + j];
  62.                         }
  63.                     }
  64.                     _voter_gyro.put(i, sensors.gyro_timestamp[i], &gyro[0], sensors.gyro_errcount[i], sensors.gyro_priority[i]);
  65.                     //最后一个参数gyro_priority[]用于支持传感器优先级;
  66.                 }
  67.                 /* ignore empty fields */
  68.                 if (sensors.accelerometer_timestamp[i] > 0) {
  69.                     _voter_accel.put(i, sensors.accelerometer_timestamp[i], &sensors.accelerometer_m_s2[i * 3],
  70.                              sensors.accelerometer_errcount[i], sensors.accelerometer_priority[i]);
  71.                 }
  72.                 //NED 坐标系下, 单位 m/s^2
  73.                 /* ignore empty fields */
  74.                 if (sensors.magnetometer_timestamp[i] > 0) {
  75.                     _voter_mag.put(i, sensors.magnetometer_timestamp[i], &sensors.magnetometer_ga[i * 3],
  76.                                sensors.magnetometer_errcount[i], sensors.magnetometer_priority[i]);
  77.                 }
  78.                 //NED 坐标系下, 单位 Gauss
  79.             }
  80.             // Get best measurement values
  81.             //获取最佳测量值(DataValidatorGroup)
  82.             hrt_abstime curr_time = hrt_absolute_time();
  83.             _gyro.set(_voter_gyro.get_best(curr_time, &best_gyro));
  84.             _accel.set(_voter_accel.get_best(curr_time, &best_accel));
  85.             _mag.set(_voter_mag.get_best(curr_time, &best_mag));
  86.             if (_accel.length() < 0.01f) {
  87.                 warnx("WARNING: degenerate accel!");
  88.                 continue;
  89.             }
  90.             //退化,即非满秩,此处为奇异值(0);
  91.             if (_mag.length() < 0.01f) {
  92.                 warnx("WARNING: degenerate mag!");
  93.                 continue;
  94.             }//同上;
  95.             _data_good = true;//数据可用;
  96.             if (!_failsafe) {
  97.                 uint32_t flags = DataValidator::ERROR_FLAG_NO_ERROR;
  98. #ifdef __PX4_POSIX
  99.                 perf_end(_perf_accel);//执行事件结束,计算均值方差等;
  100.                 perf_end(_perf_mpu);
  101.                 perf_end(_perf_mag);
  102. #endif
  103.                 if (_voter_gyro.failover_count() > 0) {
  104.                 //陀螺仪数据故障计数大于0, 记录错误日志;
  105.                     _failsafe = true;
  106.                     flags = _voter_gyro.failover_state();
  107.                     mavlink_and_console_log_emergency(&_mavlink_log_pub, "Gyro #%i failure :%s%s%s%s%s!",
  108.                                       _voter_gyro.failover_index(),
  109.                                       ((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
  110.                                       ((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
  111.                                       ((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
  112.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
  113.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
  114.                 }
  115.                 if (_voter_accel.failover_count() > 0) {
  116.                 //同上,故障日志;
  117.                     _failsafe = true;
  118.                     flags = _voter_accel.failover_state();
  119.                     mavlink_and_console_log_emergency(&_mavlink_log_pub, "Accel #%i failure :%s%s%s%s%s!",
  120.                                       _voter_accel.failover_index(),
  121.                                       ((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
  122.                                       ((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
  123.                                       ((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
  124.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
  125.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
  126.                 }
  127.                 if (_voter_mag.failover_count() > 0) {
  128.                 //同上,故障日志;
  129.                     _failsafe = true;
  130.                     flags = _voter_mag.failover_state();
  131.                     mavlink_and_console_log_emergency(&_mavlink_log_pub, "Mag #%i failure :%s%s%s%s%s!",
  132.                                       _voter_mag.failover_index(),
  133.                                       ((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " No data" : ""),
  134.                                       ((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " Stale data" : ""),
  135.                                       ((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " Data timeout" : ""),
  136.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " High error count" : ""),
  137.                                       ((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " High error density" : ""));
  138.                 }
  139.                 if (_failsafe) {
  140.                 //故障安全机制;
  141.                     mavlink_and_console_log_emergency(&_mavlink_log_pub, "SENSOR FAILSAFE! RETURN TO LAND IMMEDIATELY");
  142.                 }
  143.             }
  144.             //若启用振动报警,且振动级别超过设定阈值,触发报警; 
  145.             //振动级别由数据的方均根(RMS)给出;
  146.             if (!_vibration_warning && (_voter_gyro.get_vibration_factor(curr_time) > _vibration_warning_threshold ||
  147.                             _voter_accel.get_vibration_factor(curr_time) > _vibration_warning_threshold ||
  148.                             _voter_mag.get_vibration_factor(curr_time) > _vibration_warning_threshold)) {
  149.                 if (_vibration_warning_timestamp == 0) {
  150.                     _vibration_warning_timestamp = curr_time;
  151.                 } else if (hrt_elapsed_time(&_vibration_warning_timestamp) > 10000000) {
  152.                     _vibration_warning = true;
  153.                     mavlink_and_console_log_critical(&_mavlink_log_pub, "HIGH VIBRATION! g: %d a: %d m: %d",
  154.                                      (int)(100 * _voter_gyro.get_vibration_factor(curr_time)),
  155.                                      (int)(100 * _voter_accel.get_vibration_factor(curr_time)),
  156.                                      (int)(100 * _voter_mag.get_vibration_factor(curr_time)));
  157.                 }
  158.             } else {
  159.                 _vibration_warning_timestamp = 0;
  160.             }
  161.         }
  162.         // Update vision and motion capture heading
  163.         //更新视觉和vicon航向
  164.         bool vision_updated = false;
  165.         orb_check(_vision_sub, &vision_updated);
  166.         bool mocap_updated = false;
  167.         orb_check(_mocap_sub, &mocap_updated);
  168.         if (vision_updated) {
  169.             orb_copy(ORB_ID(vision_position_estimate), _vision_sub, &_vision);//将订阅主题的内容复制到buffer(_vision)中;
  170.             math::Quaternion q(_vision.q);
  171.             math::Matrix<3, 3> Rvis = q.to_dcm();
  172.             math::Vector<3> v(1.0f, 0.0f, 0.4f);
  173.             //没看出 v 向量具体含义,疑似磁偏校正;
  174.             // Rvis is Rwr (robot respect to world) while v is respect to world.
  175.             // Hence Rvis must be transposed having (Rwr)' * Vw
  176.             // Rrw * Vw = vn. This way we have consistency
  177.             _vision_hdg = Rvis.transposed() * v;
  178.         }
  179.         //通过视觉得到的姿态估计q->Rvis,将v转换到机体坐标系;
  180.         if (mocap_updated) {
  181.             orb_copy(ORB_ID(att_pos_mocap), _mocap_sub, &_mocap);
  182.             math::Quaternion q(_mocap.q);
  183.             math::Matrix<3, 3> Rmoc = q.to_dcm();
  184.             math::Vector<3> v(1.0f, 0.0f, 0.4f);
  185.             // Rmoc is Rwr (robot respect to world) while v is respect to world.
  186.             // Hence Rmoc must be transposed having (Rwr)' * Vw
  187.             // Rrw * Vw = vn. This way we have consistency
  188.             _mocap_hdg = Rmoc.transposed() * v;
  189.         }
  190.         // Update airspeed
  191.         bool airspeed_updated = false;
  192.         orb_check(_airspeed_sub, &airspeed_updated);
  193.         if (airspeed_updated) {
  194.             orb_copy(ORB_ID(airspeed), _airspeed_sub, &_airspeed);
  195.         }
  196.         // Check for timeouts on data
  197.         if (_ext_hdg_mode == 1) {
  198.             _ext_hdg_good = _vision.timestamp_boot > 0 && (hrt_elapsed_time(&_vision.timestamp_boot) < 500000);
  199.         } else if (_ext_hdg_mode == 2) {
  200.             _ext_hdg_good = _mocap.timestamp_boot > 0 && (hrt_elapsed_time(&_mocap.timestamp_boot) < 500000);
  201.         }
  202.         bool gpos_updated;
  203.         orb_check(_global_pos_sub, &gpos_updated);
  204.         if (gpos_updated) {
  205.             orb_copy(ORB_ID(vehicle_global_position), _global_pos_sub, &_gpos);
  206.             if (_mag_decl_auto && _gpos.eph < 20.0f && hrt_elapsed_time(&_gpos.timestamp) < 1000000) {
  207.                 /* set magnetic declination automatically */
  208.                                 update_mag_declination(math::radians(get_mag_declination(_gpos.lat, _gpos.lon)));
  209.             }
  210.             //磁偏自动校正,且水平偏差的标准差小于20,根据位置估计值(GPS)(vehicle_global_position)校正磁偏角;
  211.             //get_mag_declination()函数查表得到地磁偏角,进行补偿。
  212.         }
  213.         if (_acc_comp && _gpos.timestamp != 0 && hrt_absolute_time() < _gpos.timestamp + 20000 && _gpos.eph < 5.0f && _inited) {
  214.             /* position data is actual */
  215.             //基于GPS的位置信息,微分得到加速度值;
  216.             if (gpos_updated) {
  217.                 Vector<3> vel(_gpos.vel_n, _gpos.vel_e, _gpos.vel_d);
  218.                 /* velocity updated */
  219.                 if (_vel_prev_t != 0 && _gpos.timestamp != _vel_prev_t) {
  220.                     float vel_dt = (_gpos.timestamp - _vel_prev_t) / 1000000.0f;//时间间隔,单位(s)
  221.                     /* calculate acceleration in body frame */
  222.                     _pos_acc = _q.conjugate_inversed((vel - _vel_prev) / vel_dt);
  223.                 }//由ned坐标系下的速度求出机体坐标系下的加速度;
  224.                 _vel_prev_t = _gpos.timestamp;
  225.                 _vel_prev = vel;
  226.             }
  227.         } else {
  228.             /* position data is outdated, reset acceleration */
  229.             //位置信息已过时,重置;
  230.             _pos_acc.zero();
  231.             _vel_prev.zero();
  232.             _vel_prev_t = 0;
  233.         }
  234.         /* time from previous iteration */
  235.         hrt_abstime now = hrt_absolute_time();
  236.         float dt = (last_time > 0) ? ((now  - last_time) / 1000000.0f) : 0.00001f;//用极小值0.00001表示零,预防除零错误;
  237.         last_time = now;
  238.         if (dt > _dt_max) {
  239.             dt = _dt_max;
  240.         }//时间间隔上限;
  241.         if (!update(dt)) {
  242.             continue;
  243.         }//调用update(dt),**互补滤波**,更新四元数;
  244.         //############若不熟悉update(),请转到函数查看;
  245.         Vector<3> euler = _q.to_euler();
  246.         struct vehicle_attitude_s att = {};
  247.         att.timestamp = sensors.timestamp;
  248.         att.roll = euler(0);
  249.         att.pitch = euler(1);
  250.         att.yaw = euler(2);
  251.         att.rollspeed = _rates(0);
  252.         att.pitchspeed = _rates(1);
  253.         att.yawspeed = _rates(2);
  254.         for (int i = 0; i < 3; i++) {
  255.             att.g_comp[i] = _accel(i) - _pos_acc(i);
  256.         }//补偿重力向量;
  257.         /* copy offsets */
  258.         memcpy(&att.rate_offsets, _gyro_bias.data, sizeof(att.rate_offsets));
  259.         //memcpy(*dest,*src,size);
  260.         Matrix<3, 3> R = _q.to_dcm();
  261.         /* copy rotation matrix */
  262.         memcpy(&att.R[0], R.data, sizeof(att.R));
  263.         att.R_valid = true;
  264.         memcpy(&att.q[0], _q.data, sizeof(att.q));
  265.         att.q_valid = true;
  266.         //获取姿态振动, RMS;
  267.         att.rate_vibration = _voter_gyro.get_vibration_factor(hrt_absolute_time());
  268.         att.accel_vibration = _voter_accel.get_vibration_factor(hrt_absolute_time());
  269.         att.mag_vibration = _voter_mag.get_vibration_factor(hrt_absolute_time());
  270.         /* the instance count is not used here */
  271.         int att_inst;
  272.         orb_publish_auto(ORB_ID(vehicle_attitude), &_att_pub, &att, &att_inst, ORB_PRIO_HIGH);
  273.         //广播姿态信息;
  274.         {//使用当前姿态,更新control_state,并发布;
  275.             struct control_state_s ctrl_state = {};
  276.             ctrl_state.timestamp = sensors.timestamp;
  277.             /* attitude quaternions for control state */
  278.             ctrl_state.q[0] = _q(0);
  279.             ctrl_state.q[1] = _q(1);
  280.             ctrl_state.q[2] = _q(2);
  281.             ctrl_state.q[3] = _q(3);
  282.             /* attitude rates for control state */
  283.             //低通滤波,输入参数为当前值;
  284.             ctrl_state.roll_rate = _lp_roll_rate.apply(_rates(0));
  285.             ctrl_state.pitch_rate = _lp_pitch_rate.apply(_rates(1));
  286.             ctrl_state.yaw_rate = _lp_yaw_rate.apply(_rates(2));
  287.             /* Airspeed - take airspeed measurement directly here as no wind is estimated */
  288.             if (PX4_ISFINITE(_airspeed.indicated_airspeed_m_s) && hrt_absolute_time() - _airspeed.timestamp < 1e6
  289.                 && _airspeed.timestamp > 0) {
  290.                 ctrl_state.airspeed = _airspeed.indicated_airspeed_m_s;
  291.                 ctrl_state.airspeed_valid = true;
  292.             } else {
  293.                 ctrl_state.airspeed_valid = false;
  294.             }
  295.             /* the instance count is not used here */
  296.             int ctrl_inst;
  297.             /* publish to control state topic */
  298.             //发布控制状态主题,control_state.msg。
  299.             orb_publish_auto(ORB_ID(control_state), &_ctrl_state_pub, &ctrl_state, &ctrl_inst, ORB_PRIO_HIGH);
  300.         }
  301.         {
  302.             struct estimator_status_s est = {};
  303.             est.timestamp = sensors.timestamp;
  304.             est.vibe[0] = _voter_accel.get_vibration_offset(est.timestamp, 0);
  305.             est.vibe[1] = _voter_accel.get_vibration_offset(est.timestamp, 1);
  306.             est.vibe[2] = _voter_accel.get_vibration_offset(est.timestamp, 2);
  307.             /* the instance count is not used here */
  308.             int est_inst;
  309.             /* publish to control state topic */
  310.             orb_publish_auto(ORB_ID(estimator_status), &_est_state_pub, &est, &est_inst, ORB_PRIO_HIGH);
  311.         }
  312.     }
  313. }


update_parameters();

  1. l657~l686
  2. void AttitudeEstimatorQ::update_parameters(bool force)
  3. {
  4.     bool updated = force;
  5.     if (!updated) {
  6.         orb_check(_params_sub, &updated);//查看参数是否更新;
  7.     }
  8.     if (updated) {//获取新参数;
  9.         parameter_update_s param_update;
  10.         orb_copy(ORB_ID(parameter_update), _params_sub, ¶m_update);
  11.         param_get(_params_handles.w_acc, &_w_accel);
  12.         param_get(_params_handles.w_mag, &_w_mag);
  13.         param_get(_params_handles.w_ext_hdg, &_w_ext_hdg);
  14.         param_get(_params_handles.w_gyro_bias, &_w_gyro_bias);
  15.         float mag_decl_deg = 0.0f;
  16.         param_get(_params_handles.mag_decl, &mag_decl_deg);
  17.         update_mag_declination(math::radians(mag_decl_deg));
  18.         int32_t mag_decl_auto_int;
  19.         param_get(_params_handles.mag_decl_auto, &mag_decl_auto_int);
  20.         _mag_decl_auto = mag_decl_auto_int != 0;//自动磁偏角校正;
  21.         int32_t acc_comp_int;
  22.         param_get(_params_handles.acc_comp, &acc_comp_int);
  23.         _acc_comp = acc_comp_int != 0;
  24.         param_get(_params_handles.bias_max, &_bias_max);//陀螺仪偏差上限;
  25.         param_get(_params_handles.vibe_thresh, &_vibration_warning_threshold);//振动警告阈值;
  26.         param_get(_params_handles.ext_hdg_mode, &_ext_hdg_mode);
  27.     }
  28. }

init();

1、k 为导航坐标系(NED)的 z 轴(D)在机体坐标系中的表示;

导航系中,D正方向朝下;

2、i 为导航坐标系(NED)的 x 轴(N)在机体坐标系;

i = (_mag - k * (_mag * k)); //施密特正交化;


//因 向量 k 已归一化,故分母等于1;

3、为导航坐标系(NED)的 yy 轴(E)在机体坐标系;

j = k % i //叉乘求正交向量; 

4、构造旋转矩阵 R
R.set_row(0, i); R.set_row(1, j); R.set_row(2, k);


5、转换为四元数 qq ,根据设定校正磁偏,归一化;

  1. l688~l728
  2. bool AttitudeEstimatorQ::init()
  3. {
  4.     // Rotation matrix can be easily constructed from acceleration and mag field vectors
  5.     // 'k' is Earth Z axis (Down) unit vector in body frame
  6.     Vector<3> k = -_accel;
  7.     k.normalize();
  8.     // 'i' is Earth X axis (North) unit vector in body frame, orthogonal with 'k'
  9.     Vector<3> i = (_mag - k * (_mag * k));
  10.     i.normalize();
  11.     // 'j' is Earth Y axis (East) unit vector in body frame, orthogonal with 'k' and 'i'
  12.     Vector<3> j = k % i;
  13.     // Fill rotation matrix
  14.     Matrix<3, 3> R;
  15.     R.set_row(0, i);
  16.     R.set_row(1, j);
  17.     R.set_row(2, k);
  18.     // Convert to quaternion
  19.     _q.from_dcm(R);
  20.     // Compensate for magnetic declination
  21.     Quaternion decl_rotation;
  22.     decl_rotation.from_yaw(_mag_decl);
  23.     _q = decl_rotation * _q;
  24.     _q.normalize();
  25.     if (PX4_ISFINITE(_q(0)) && PX4_ISFINITE(_q(1)) &&
  26.         PX4_ISFINITE(_q(2)) && PX4_ISFINITE(_q(3)) &&
  27.         _q.length() > 0.95f && _q.length() < 1.05f) {
  28.         _inited = true;
  29.     } else {
  30.         _inited = false;
  31.     }
  32.     return _inited;
  33. }

update();


1、init();//执行一次;

由加速度计和磁力计初始化旋转矩阵和四元数;

2、mag_earth = _q.conjugate(_mag);

不使用外部航向,或外部航向异常时,采用磁力计校准; 
将磁力计读数从机体坐标系转换到导航坐标系; 

3、mag_err = _wrap_pi(atan2f(mag_earth(1), mag_earth(0)) - _mag_decl);

将磁力计的读数由向量换算到角度; 该角度减去磁偏,得到磁场偏差; 
_mag_decl 由GPS得到; 
**atan2f: 2 表示两个输入参数; 支持四象限内角度换算; 输出弧度值; 
**_wrap_pi: 将(0~2pi)的角度映射到(-pi~pi);

4、corr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mag_err)) * _w_mag;

将磁场偏差转换到机体坐标系,并乘以其对应权重; 
 

5、_q.normalize();

四元数归一化; 
这里的归一化用于校正update_mag_declination后的偏差。

corr += (k % (_accel - _pos_acc).normalized()) * _w_accel;

6、向量 k 是重力加速度向量(0,0,1)转换到机体坐标系; 
_accel 是加速度计的读数; 
_pos_acc 是由位置估计(GPS) 微分得到的加速度; 
_accel - _pos_acc 表示飞行器加速度向量减去其水平分量; 
k 与 (_accel - _pos_acc)叉乘,得到偏差; 


7、_gyro_bias += corr * (_w_gyro_bias * dt);

得到陀螺仪修正值 
此处修正值为 mahony 滤波的 pi 控制器的 积分部分; 
因为 _gyro_bias 不归零,故不断累积; 

8、_rates = _gyro + _gyro_bias;

_rates 表示角速度; 


9、corr += _rates;

这里的 corr = (Ea+Em) + (Ea+Em)*dt + gyro; 
个人认为这里的 corr 才是更新后的角速度;

10、_q += _q.derivative(corr) * dt;

更新四元数,derivative为求导函数,使用一阶龙格库塔求导。 

  1. l730~l817
  2. bool AttitudeEstimatorQ::update(float dt)
  3. {
  4.     if (!_inited) {
  5.         if (!_data_good) {
  6.             return false;
  7.         }
  8.         return init();
  9.     }
  10.     Quaternion q_last = _q;//保存上一状态,以便恢复;
  11.     // Angular rate of correction
  12.     Vector<3> corr;//初始化元素为0;
  13.     //_ext_hdg_good表示外部航向数据可用;
  14.     if (_ext_hdg_mode > 0 && _ext_hdg_good) {
  15.         if (_ext_hdg_mode == 1) {
  16.             // Vision heading correction
  17.             //视觉航向校正;
  18.             // Project heading to global frame and extract XY component
  19.             //将航向投影到导航坐标系,提取XY分量;
  20.             Vector<3> vision_hdg_earth = _q.conjugate(_vision_hdg);
  21.             float vision_hdg_err = _wrap_pi(atan2f(vision_hdg_earth(1), vision_hdg_earth(0)));
  22.             // Project correction to body frame
  23.             corr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -vision_hdg_err)) * _w_ext_hdg;
  24.         }
  25.         if (_ext_hdg_mode == 2) {
  26.             // Mocap heading correction
  27.             // Project heading to global frame and extract XY component
  28.             Vector<3> mocap_hdg_earth = _q.conjugate(_mocap_hdg);
  29.             float mocap_hdg_err = _wrap_pi(atan2f(mocap_hdg_earth(1), mocap_hdg_earth(0)));
  30.             // Project correction to body frame
  31.             corr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mocap_hdg_err)) * _w_ext_hdg;
  32.         }
  33.     }
  34.     if (_ext_hdg_mode == 0  || !_ext_hdg_good) {
  35.         // Magnetometer correction
  36.         // Project mag field vector to global frame and extract XY component
  37.         Vector<3> mag_earth = _q.conjugate(_mag);
  38.         float mag_err = _wrap_pi(atan2f(mag_earth(1), mag_earth(0)) - _mag_decl);
  39.         // Project magnetometer correction to body frame
  40.         corr += _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, -mag_err)) * _w_mag;
  41.     }
  42.     _q.normalize();
  43.     // Accelerometer correction
  44.     // Project 'k' unit vector of earth frame to body frame
  45.     // Vector<3> k = _q.conjugate_inversed(Vector<3>(0.0f, 0.0f, 1.0f));
  46.     // Optimized version with dropped zeros
  47.     Vector<3> k(
  48.         2.0f * (_q(1) * _q(3) - _q(0) * _q(2)),
  49.         2.0f * (_q(2) * _q(3) + _q(0) * _q(1)),
  50.         (_q(0) * _q(0) - _q(1) * _q(1) - _q(2) * _q(2) + _q(3) * _q(3))
  51.     );
  52.     corr += (k % (_accel - _pos_acc).normalized()) * _w_accel;
  53.     // Gyro bias estimation
  54.     _gyro_bias += corr * (_w_gyro_bias * dt);
  55.     for (int i = 0; i < 3; i++) {//陀螺仪最大偏差上限;
  56.         _gyro_bias(i) = math::constrain(_gyro_bias(i), -_bias_max, _bias_max);
  57.     }
  58.     _rates = _gyro + _gyro_bias;
  59.     // Feed forward gyro
  60.     corr += _rates;
  61.     // Apply correction to state
  62.     _q += _q.derivative(corr) * dt;
  63.     // Normalize quaternion
  64.     _q.normalize();
  65.     //判断四元数是否发散,若发散,则沿用之前的四元数;
  66.     if (!(PX4_ISFINITE(_q(0)) && PX4_ISFINITE(_q(1)) &&
  67.           PX4_ISFINITE(_q(2)) && PX4_ISFINITE(_q(3)))) {
  68.         // Reset quaternion to last good state
  69.         _q = q_last;
  70.         _rates.zero();
  71.         _gyro_bias.zero();
  72.         return false;
  73.     }
  74.     return true;
  75. }


update_mag_declination();

  1. l819~l832
  2. void AttitudeEstimatorQ::update_mag_declination(float new_declination)
  3. {
  4.     // Apply initial declination or trivial rotations without changing estimation
  5.     //忽略微小旋转;
  6.     if (!_inited || fabsf(new_declination - _mag_decl) < 0.0001f) {
  7.         _mag_decl = new_declination;
  8.     } else {
  9.         // Immediately rotate current estimation to avoid gyro bias growth
  10.         //磁偏超过一定值后,校正姿态;
  11.         Quaternion decl_rotation;
  12.         decl_rotation.from_yaw(new_declination - _mag_decl);
  13.         //由磁偏角度转化为四元数;
  14.         _q = decl_rotation * _q;
  15.         //四元数相乘表示角度相加;
  16.         _mag_decl = new_declination;
  17.     }
  18. }


attitude_estimator_q_main();

  1. l834~l890
  2. int attitude_estimator_q_main(int argc, char *argv[])
  3. {//外部调用接口;
  4.     if (argc < 2) {
  5.         warnx("usage: attitude_estimator_q {start|stop|status}");
  6.         return 1;
  7.     }
  8.     if (!strcmp(argv[1], "start")) {
  9.         if (attitude_estimator_q::instance != nullptr) {
  10.             warnx("already running");
  11.             return 1;
  12.         }
  13.         //实例化,instance;
  14.         attitude_estimator_q::instance = new AttitudeEstimatorQ;
  15.         if (attitude_estimator_q::instance == nullptr) {
  16.             warnx("alloc failed");
  17.             return 1;
  18.         }
  19.         if (OK != attitude_estimator_q::instance->start()) {
  20.             delete attitude_estimator_q::instance;
  21.             attitude_estimator_q::instance = nullptr;
  22.             warnx("start failed");
  23.             return 1;
  24.         }
  25.         return 0;
  26.     }
  27.     if (!strcmp(argv[1], "stop")) {
  28.         if (attitude_estimator_q::instance == nullptr) {
  29.             warnx("not running");
  30.             return 1;
  31.         }
  32.         //删除实例化对象,指针置空;
  33.         delete attitude_estimator_q::instance;
  34.         attitude_estimator_q::instance = nullptr;
  35.         return 0;
  36.     }
  37.     //打印当前姿态信息;
  38.     if (!strcmp(argv[1], "status")) {
  39.         if (attitude_estimator_q::instance) {
  40.             attitude_estimator_q::instance->print();
  41.             warnx("running");
  42.             return 0;
  43.         } else {
  44.             warnx("not running");
  45.             return 1;
  46.         }
  47.     }
  48.     warnx("unrecognized command");
  49.     return 1;
  50. }



原文:https://blog.csdn.net/luoshi006/article/details/51513580 
 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Guff_9hys/article/detail/849740
推荐阅读
相关标签
  

闽ICP备14008679号