PX4_ECL_EKF代码分析2

2023-05-16

写在前面

源码版本:1.6.0rc1
源码位置1:Firmware-1.6.0rc1\src\modules\ekf2_main.cpp
源码位置2:Firmware-1.6.0rc1\src\lib\ecl\EKF\

整体框架:
在这里插入图片描述
上图PX4的EKF代码框架,PX4的代码由两部分组成,一部分是在modules下的ekf2,另一部分是ecl代码库中EKF部分。

第一部分实现数据的订阅(subscribe)、整理、储存、经过处理的数据发布(publish)。
第二部分实现数据的处理。

第二部分:

bool Ekf::update()
{
	if (!_filter_initialised) {
		_filter_initialised = initialiseFilter();

		if (!_filter_initialised) {
			return false;
		}
	}
	// Only run the filter if IMU data in the buffer has been updated
	if (_imu_updated) {
		// perform state and covariance prediction for the main filter
		predictState();
		predictCovariance();
		
		// control fusion of observation data
		controlFusionModes();

		// run a separate filter for terrain estimation
		runTerrainEstimator();

	}
	// the output observer always runs
	calculateOutputStates();

	// check for NaN or inf on attitude states
	if (!ISFINITE(_state.quat_nominal(0)) || !ISFINITE(_output_new.quat_nominal(0))) {
		return false;
	}
	// We don't have valid data to output until tilt and yaw alignment is complete
	return _control_status.flags.tilt_align && _control_status.flags.yaw_align;
}

这个就是整个EKF代码的核心函数了,分别由几个函数组成,各自完成不同的功能。

在首次进入update()这个函数的时候,系统会对变量进行初始化initialiseFilter();这个函数只执行一次,跟进:

bool Ekf::initialiseFilter()
{
	// Keep accumulating measurements until we have a minimum of 10 samples for the required sensors
    //继续累积测量,直到有至少10个样品为所需的传感器
	// Sum the IMU delta angle measurements
	imuSample imu_init = _imu_buffer.get_newest();
	_delVel_sum += imu_init.delta_vel;
	// Sum the magnetometer measurements
	//对磁强计的测量值求和
	if (_mag_buffer.pop_first_older_than(_imu_sample_delayed.time_us, &_mag_sample_delayed)) {
		if ((_mag_counter == 0) && (_mag_sample_delayed.time_us != 0)) {
			// initialise the counter when we start getting data from the buffer
			_mag_counter = 1;
		} else if ((_mag_counter != 0) && (_mag_sample_delayed.time_us != 0)) {
			// increment the sample count and apply a LPF to the measurement
			_mag_counter ++;

			// don't start using data until we can be certain all bad initial data has been flushed
			//在确定所有坏的初始数据都已被清除之前,不要开始使用数据
			if (_mag_counter == (uint8_t)(_obs_buffer_length + 1)) {
				// initialise filter states
				_mag_filt_state = _mag_sample_delayed.mag;

			} else if (_mag_counter > (uint8_t)(_obs_buffer_length + 1)) {
				// noise filter the data
				_mag_filt_state = _mag_filt_state * 0.9f + _mag_sample_delayed.mag * 0.1f;
			}
		}
	}

磁力计数据出栈

	// set the default height source from the adjustable parameter
	if (_hgt_counter == 0) {
		_primary_hgt_source = _params.vdist_sensor_type;
	}

上面代码,选择高度源,可以来自于气压计,GPG,视觉、(毫米波)超声波等。下面开始选择高度源

	// accumulate enough height measurements to be confident in the qulaity of the data
	//积累足够的高度测量值以对保证数据的质量
	if (_primary_hgt_source == VDIST_SENSOR_RANGE) {//使用超声波
		if (_range_buffer.pop_first_older_than(_imu_sample_delayed.time_us, &_range_sample_delayed)) {
			if ((_hgt_counter == 0) && (_range_sample_delayed.time_us != 0)) {
				// initialise the counter height fusion method when we start getting data from the buffer
				_control_status.flags.baro_hgt = false;
				_control_status.flags.gps_hgt = false;
				_control_status.flags.rng_hgt = true;//使能超声波标志位
				_control_status.flags.ev_hgt = false;
				_hgt_counter = 1;

			} else if ((_hgt_counter != 0) && (_range_sample_delayed.time_us != 0)) {
				// increment the sample count and apply a LPF to the measurement
				_hgt_counter ++;
				// don't start using data until we can be certain all bad initial data has been flushed
				if (_hgt_counter == (uint8_t)(_obs_buffer_length + 1)) {
					// initialise filter states
					_rng_filt_state = _range_sample_delayed.rng;

				} else if (_hgt_counter > (uint8_t)(_obs_buffer_length + 1)) {
					// noise filter the data
					_rng_filt_state = 0.9f * _rng_filt_state + 0.1f * _range_sample_delayed.rng;
				}
			}
		}//超声波数据出栈
	} else if (_primary_hgt_source == VDIST_SENSOR_BARO || _primary_hgt_source == VDIST_SENSOR_GPS) {//使用气压计或者GPS
		// if the user parameter specifies use of GPS for height we use baro height initially and switch to GPS
		//如果user参数指定高度使用GPS,我们首先使用气压高度,然后切换到GPS
		// later when it passes checks.
		if (_baro_buffer.pop_first_older_than(_imu_sample_delayed.time_us, &_baro_sample_delayed)) {
			if ((_hgt_counter == 0) && (_baro_sample_delayed.time_us != 0)) {
				// initialise the counter and height fusion method when we start getting data from the buffer
				_control_status.flags.baro_hgt = true;//使用气压计
				_control_status.flags.gps_hgt = false;
				_control_status.flags.rng_hgt = false;
				_hgt_counter = 1;

			} else if ((_hgt_counter != 0) && (_baro_sample_delayed.time_us != 0)) {
				// increment the sample count and apply a LPF to the measurement
				_hgt_counter ++;

				// don't start using data until we can be certain all bad initial data has been flushed
				if (_hgt_counter == (uint8_t)(_obs_buffer_length + 1)) {
					// initialise filter states
					_baro_hgt_offset = _baro_sample_delayed.hgt;

				} else if (_hgt_counter > (uint8_t)(_obs_buffer_length + 1)) {
					// noise filter the data
					_baro_hgt_offset = 0.9f * _baro_hgt_offset + 0.1f * _baro_sample_delayed.hgt;
				}
			}
		}
	} else if (_primary_hgt_source == VDIST_SENSOR_EV) {//使用视觉传感器
		_hgt_counter = _ev_counter;
	} else {
		return false;
	}
	// check to see if we have enough measurements and return false if not
	bool hgt_count_fail = _hgt_counter <= 2 * _obs_buffer_length;
	bool mag_count_fail = _mag_counter <= 2 * _obs_buffer_length;
	bool ev_count_fail = ((_params.fusion_mode & MASK_USE_EVPOS) || (_params.fusion_mode & MASK_USE_EVYAW)) && (_ev_counter <= 2 * _obs_buffer_length);
	
		if (hgt_count_fail || mag_count_fail || ev_count_fail) {
		return false;
	} else {
		// reset variables that are shared with post alignment GPS checks重置与后校准GPS检查共享的变量
		_gps_drift_velD = 0.0f;
		_gps_alt_ref = 0.0f;
		// Zero all of the states
		_state.vel.setZero();
		_state.pos.setZero();
		_state.gyro_bias.setZero();
		_state.accel_bias.setZero();
		_state.mag_I.setZero();
		_state.mag_B.setZero();
		_state.wind_vel.setZero();

检测是否有足够的测量数据,如果没有则返回 false,复位状态

// get initial roll and pitch estimate from delta velocity vector, assuming vehicle is static
//假设飞行器是静态的,从速度矢量得到初始横滚和俯仰估计
	float pitch = 0.0f;
	float roll = 0.0f;
	if (_delVel_sum.norm() > 0.001f) {
		_delVel_sum.normalize();
		pitch = asinf(_delVel_sum(0));
		roll = atan2f(-_delVel_sum(1), -_delVel_sum(2));
	} else {
		return false;
	}
// calculate initial tilt alignment
		matrix::Euler<float> euler_init(roll, pitch, 0.0f);
		_state.quat_nominal = Quaternion(euler_init);
		_output_new.quat_nominal = _state.quat_nominal;
		_R_to_earth = quat_to_invrotmat(_state.quat_nominal);

根据上面得到的初始pitch 、roll计算初始倾斜角,并更新机体系到导航系的旋转矩阵。

	Vector3f mag_init = _mag_filt_state;
	
	// calculate the initial magnetic field and yaw alignment
	_control_status.flags.yaw_align = resetMagHeading(mag_init);

磁力计数值初始化,进行偏航校准,后面的超声波作为高度源的代码没有粘贴直接跳过。

		// initialise the state covariance matrix
		initialiseCovariance();

协方差初始化函数,进去看一下:

void Ekf::initialiseCovariance()
{
	for (unsigned i = 0; i < _k_num_states; i++) {//首先是协方差矩阵内容清零,以便赋值
		for (unsigned j = 0; j < _k_num_states; j++) {
			P[i][j] = 0.0f;
		}
	}
	// calculate average prediction time step in sec//计算平均预测时间 单位 秒
	float dt = 0.001f * (float)FILTER_UPDATE_PERIOD_MS;

	// define the initial angle uncertainty as variances for a rotation vector
	//定义初始角度不确定度为旋转矢量的方差
	Vector3f rot_vec_var;
	rot_vec_var(2) = rot_vec_var(1) = rot_vec_var(0) = sq(_params.initial_tilt_err);

	//使用旋转向量方差初始化四元数协方差
	initialiseQuatCovariances(rot_vec_var);

	// velocity
	P[4][4] = sq(fmaxf(_params.gps_vel_noise, 0.01f));
	P[5][5] = P[4][4];
	P[6][6] = sq(1.5f) * P[4][4];

	// position
	P[7][7] = sq(fmaxf(_params.gps_pos_noise, 0.01f));
	P[8][8] = P[7][7];
	if (_control_status.flags.rng_hgt) {//使用超声波 (这里不使用)
		P[9][9] = sq(fmaxf(_params.range_noise, 0.01f));
	} else if (_control_status.flags.gps_hgt) {//用GPS
		float lower_limit = fmaxf(_params.gps_pos_noise, 0.01f);
		float upper_limit = fmaxf(_params.pos_noaid_noise, lower_limit);
		P[9][9] = sq(1.5f * math::constrain(_gps_sample_delayed.vacc, lower_limit, upper_limit));
	} else {
		P[9][9] = sq(fmaxf(_params.baro_noise, 0.01f));
	}

	// gyro bias
	P[10][10] = sq(_params.switch_on_gyro_bias * dt);
	P[11][11] = P[10][10];
	P[12][12] = P[10][10];

	// accel bias
	_prev_dvel_bias_var(0) = P[13][13] = sq(_params.switch_on_accel_bias * dt);
	_prev_dvel_bias_var(1) = P[14][14] = P[13][13];
	_prev_dvel_bias_var(2) = P[15][15] = P[13][13];
	
	// earth frame and body frame magnetic field
	// set to observation variance
	for (uint8_t index=16; index <= 21; index ++) {
		P[index][index] = sq(_params.mag_noise);
	}

	// wind
	P[22][22] = 1.0f;
	P[23][23] = 1.0f;
}

initialiseQuatCovariances(rot_vec_var);这个函数可以到matlab模型里面可以找到 ,编译后会生成此函数,matlab路径:

Firmware-1.6.0rc1\src\lib\ecl\EKF\matlab\Inertial Nav EKF\QuatErrTransferEquations.m

生成的.c文件也在同路径下。

	//	重置基本的融合超时计数器
		_time_last_hgt_fuse = _time_last_imu;
		_time_last_pos_fuse = _time_last_imu;
		_time_last_vel_fuse = _time_last_imu;
		_time_last_hagl_fuse = _time_last_imu;
		_time_last_of_fuse = _time_last_imu;
	// reset the output predictor state history to match the EKF initial values
	//重置输出预测器状态历史以匹配EKF初始值
		alignOutputFilter();
		return true;
	}
}//end bool Ekf::initialiseFilter();
void Ekf::alignOutputFilter()
{
	// calculate the quaternion delta between the output and EKF quaternions at the EKF fusion time horizon
	//在EKF融合时间层计算输出和EKF四元数之间的delta四元数
	Quaternion quat_inv = _state.quat_nominal.inversed();
	Quaternion q_delta =  _output_sample_delayed.quat_nominal * quat_inv;
	q_delta.normalize();

	// calculate the velocity and posiiton deltas between the output and EKF at the EKF fusion time horizon
	//在EKF融合时间层计算输出和EKF之间的速度和位置增量
	Vector3f vel_delta = _state.vel - _output_sample_delayed.vel;
	Vector3f pos_delta = _state.pos - _output_sample_delayed.pos;

	// loop through the output filter state history and add the deltas
	//循环遍历输出过滤器状态历史记录并添加增量
	outputSample output_states = {};
	unsigned output_length = _output_buffer.get_length();

	for (unsigned i = 0; i < output_length; i++) {
		output_states = _output_buffer.get_from_index(i);
		output_states.quat_nominal *= q_delta;
		output_states.quat_nominal.normalize();
		output_states.vel += vel_delta;
		output_states.pos += pos_delta;
		_output_buffer.push_to_index(i, output_states);
	}
}

以上就是我对ECL库中EKF代码初始化函数的理解,有很多写在了注释里面,也有很多不理解的地方还在学习中,如有理解错误的地方请批评指正,欢迎一起学习填坑PX4,QQ:1103706199

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4_ECL_EKF代码分析2 的相关文章

  • 从Simulink到PX4——Simulink-PX4插件安装与环境搭建

    从Simulink到PX4 Simulink PX4插件安装与环境搭建 前言0 准备工作1 安装WSL2 Setting up the PX4 Toolchain on Windows3 Setting up the PX4 Tool Ch
  • PX4 ---- Indoor Flight

    文章目录 室内飞行ROS amp PX4Pose Data 飞机配置MAVROS 基于工训赛 VIO 飞行总结 室内飞行 ROS amp PX4 Pose Data 飞机配置 VIO 参考此处 xff0c 采用 T265 配置 相机与飞控机
  • PX4模块设计之十八:Logger模块

    PX4模块设计之十八 xff1a Logger模块 1 Logger模块简介2 模块入口函数2 1 主入口logger main2 2 自定义子命令Logger custom command2 3 日志主题uORB注册 3 重要实现函数3
  • PX4模块设计之二十一:uORB消息管理模块

    PX4模块设计之二十一 xff1a uORB消息管理模块 1 uORB模块构建模式2 uORB消息管理函数2 1 状态查询2 2 资源利用2 3 模块启动2 4 模块停止3 uORB消息接口3 1 消息主题注册3 2 消息主题去注册3 3
  • PX4模块设计之三十:Hysteresis类

    PX4模块设计之三十 xff1a Hysteresis类 1 Hysteresis类简介2 Hysteresis类成员变量介绍3 Hysteresis类迟滞逻辑4 Hysteresis类重要方法4 1 Hysteresis bool ini
  • PX4模块设计之三十四:ControlAllocator模块

    PX4模块设计之三十四 xff1a ControlAllocator模块 1 ControlAllocator模块简介2 模块入口函数2 1 主入口control allocator main2 2 自定义子命令custom command
  • PX4模块设计之三十九:Commander模块

    PX4模块设计之三十九 xff1a Commander模块 1 Commander模块简介2 模块入口函数2 1 主入口commander main2 2 自定义子命令custom command 3 Commander模块重要函数3 1
  • PX4模块设计之四十五:param模块

    PX4模块设计之四十五 xff1a param模块 1 param模块简介2 模块入口函数param main3 重要函数列表4 总结5 参考资料 1 param模块简介 Description Command to access and
  • Android Audio代码分析 - Audio Strategy

    frameworks base services AudioFlinger cpp status t AudioFlinger PlaybackThread Track start status t status 61 NO ERROR L
  • px4仿真无法起飞问题(Failsafe enabled: no datalink)

    报错信息 问题描述 xff1a 使用JMAVSim和gazebo仿真px4起飞时报错如下 xff1a WARN commander Failsafe enabled no datalink 说不安全 解决方法 打开QGC 就可以起飞了
  • 步骤三:PX4,Mavros的下载安装及代码测试

    1 安装Mavros sudo apt install ros melodic mavros ros melodic mavros extras 2 安装Mavros相关的 geographiclib dataset 此处已经加了ghpro
  • PX4通过参数脚本给飞控导入参数

    PX4通过参数脚本给飞控导入参数 先找一架正常能飞的无人机连接地面站 在参数页面右上角点击工具 gt 保存到文件 保存的时候文件名注明参数的相关信息 然后将需要加载参数的无人机连接至地面站 xff0c 注意需要加载参数的无人机必须和保存的参
  • GCC Coverage代码分析-GCC如何编译生成gcov/gcov-dump程序及其bug分析

    本博客 http blog csdn net livelylittlefish 贴出作者 阿波 相关研究 学习内容所做的笔记 欢迎广大朋友指正 Content 0 序 1 编译gcov gcov dump 2 额外的话 3 gcov dum
  • 【Unity问题&错误】list问题

    error CS0305 Using the generic type System Collections Generic List
  • 静态代码分析工具清单:开源篇

    http hao jobbole com static code analysis tool list opensource lang utm source blog jobbole com utm medium sidebar resou
  • 让开发自动化: 用 Eclipse 插件提高代码质量

    2007 年 1 月 29 日 如果能在构建代码前发现代码中潜在的问题会怎么样呢 很有趣的是 Eclipse 插件中就有这样的工具 比如 JDepend 和 CheckStyle 它们能帮您在软件问题暴露前发现这些问题 在 让开发自动化 的
  • 飞行姿态解算(三)

    继之前研究了一些飞行姿态理论方面的问题后 又找到了之前很流行的一段外国大神写的代码 来分析分析 第二篇文章的最后 讲到了文章中的算法在实际使用中有重大缺陷 大家都知道 分析算法理论的时候很多情况下我们没有考虑太多外界干扰的情况 原因是很多情
  • linux下代码分析工具Splint

    1 C代码静态分析工具 Its4 读取一个或多个 C C 源程序 将每个源程序分割成函数标志流 然后检查生成的标志是否存在于漏洞数据库中 从而得到每个源程序的所有错误警告列表 并带有相关的描 述 其规则库vulns i4d定义了各种函数的危
  • java代码分析及分析工具

    一个项目从搭建开始 开发的初期往往思路比较清晰 代码也比较清晰 随着时间的推移 业务越来越复杂 代码也就面临着耦合 冗余 甚至杂乱 到最后谁都不敢碰 作为一个互联网电子商务网站的业务支撑系统 业务复杂不言而喻 从09年开始一直沿用到现在 中
  • Nmap源码分析(主机发现)

    Nmap源码分析 主机发现 2012年8月9日 Nmap在进行真正的端口扫描之前 通常需要确定目标主机是否在线 主机发现过程 以免发送大量探测包到不在线的主机 主机发现作为Nmap的基本功能之一 用户也可以单独运用 例如 仅仅需要确定局域网

随机推荐

  • git删除远程分支

    branch 1 列出分支 xff0c a参数是列出所有分支 xff0c 包括远程分支 git branch a 2 创建一个本地分支 git branch branchname 3 创建一个分支 xff0c 并切换到该分支 git che
  • maven命令上传第三方包

    mvn deploy deploy file Dmaven test skip 61 true DgroupId 61 sdk的groupId DartifactId 61 包的名称 Dversion 61 版本号 如 xff1a 0 0
  • 解决图片上传权限问题

    linux默认umask为022 xff0c 对应权限为755 xff0c 其它用户可读可执行 可以vim etc profile xff0c 搜索umusk关键字查看 if UID gt 199 amp amp 34 96 usr bin
  • 微信小程序 解决 wx.request同步问题 方便开发 Promise方式

  • Python经典书籍有哪些?这份书单送给你_黑马程序员

    文章目录 一 Python 基础 01 Python编程 xff1a 从入门到实践 xff08 第2版 xff09 02 Python编程快速上手 xff08 第2版 xff09 03 Python编程初学者指南 04 笨方法 学Pytho
  • 记忆的方法

    1 第一招 xff0c 在背书的时候 xff0c 用双手捂住你的耳朵 xff0c 并且大声的朗读 研究表明 xff0c 用手捂着耳朵来朗读的话 xff0c 声音是直接通过骨骼来传输到内耳 xff0c 对大脑刺激会更加强烈 xff0c 记忆也
  • ssh登录服务器缓慢问题

    问题描述 问题刚开始是由pod启动失败 xff0c 报错unable to ensure pod container exists failed to create container for kubepods burstable pod8
  • UCOSIII学习-任务管理

    UCOSIII学习 任务管理 1 UCOSIII 任务组成2 UCOSIII 默认系统任务3 UCOSIII 任务状态4 任务堆栈1 任务堆栈的创建2 任务堆栈初始化 5 任务控制块1 任务控制块创建2 任务控制块初始化 6 任务就绪表1
  • ubuntu(Linux)配置允许远程登陆

    安装ubuntu后默认不可以以root方式登录系统 xff0c 需要做以下配置 1 使用sudo i 命令可以让用户切换到root用户 xff0c guo用户是安装ubuntu时配置的用户 xff0c 因人而异 xff1b 2 配置root
  • python带下划线的变量和函数

    参考文献 xff1a https blog csdn net AI S YE article details 44685139
  • ADD,COPY,ENTRYPOINT和cmd

    Dockerfile中有关信息 xff1a ADD与COPY区别 add 1 对压缩包进行解压2 可以在后面直接跟文件地址 copy xff1a 把本地的文件copy到容器里面 ENTRYPOINT与CMD区别 1 第一种解释 xff08
  • docker实例操作

    很多东西都是借鉴各位大神的 xff0c 也不知道具体是谁或是哪个链接 xff0c 很抱歉 两者同为目前版本中个人和小团队常用的服务级操作系统 xff0c 在线提供的软件库中可以很方便的安装到很多开源的软件及库 两者都使用bash作为基础sh
  • 三、FreeRTOS任务管理--常用函数

    任务的基本概念 FreeRTOS 的任务可认为是一系列独立任务的集合 每个任务在自己的环境中运行 在任何时刻 xff0c 只有一个任务得到运行 xff0c FreeRTOS 调度器决定运行哪个任务 调度器会不断的启动 停止每一个任务 xff
  • 七、FreeRTOS事件和常用函数接口

    基本概念 事件是一种实现任务间通信的机制 xff0c 主要用于实现多任务间的同步 xff0c 但事件通信只能是事件类型的通信 xff0c 无数据传输 与信号量不同的是 xff0c 它可以实现一对多 xff0c 多对多的同步 即一个任务可以等
  • PX4姿态估计源码分析

    写在前面 今天入坑PX4开始学习PX4代码 xff0c pixhawk硬件是可以支持PX4 ardupilot两套固件 我用的是1 6 0rc1版本代码 代码位置 xff1a Firmware1 6 0rc1 src modules att
  • PX4位置估计源码分析

    写在前面 源码版本 xff1a 1 6 0rc1 源码位置 xff1a Firmware 1 6 0rc1 src modules position estimator inav position estimator inav main c
  • ROS入门笔记(二):ROS安装与环境配置及卸载(重点)

    ROS入门笔记 xff08 二 xff09 xff1a ROS安装与环境配置及卸载 xff08 重点 xff09 文章目录 1 ROS安装步骤1 1 ROS版本1 2 确定Ubuntu版本号1 3 安装ROS1 3 1 Ubuntu初始环境
  • windows安装Java环境及Flightplot分析PX4飞行日志

    写在前面 用Flightplot分析PX4飞行日志 xff0c 不管是windows还是Ubuntu都需要安装对应的Java环境 xff08 我用的是win10家庭版 xff09 1 下载安装java环境 xff1a a 下载 点击地址进行
  • PX4_ECL_EKF代码分析1

    写在前面 源码版本 xff1a 1 6 0rc1 源码位置1 xff1a Firmware 1 6 0rc1 src modules ekf2 main cpp 源码位置2 xff1a Firmware 1 6 0rc1 src lib e
  • PX4_ECL_EKF代码分析2

    写在前面 源码版本 xff1a 1 6 0rc1 源码位置1 xff1a Firmware 1 6 0rc1 src modules ekf2 main cpp 源码位置2 xff1a Firmware 1 6 0rc1 src lib e