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 的相关文章

  • PX4源代码下载编译

    sudo git clone https github com PX4 PX4 Autopilot git recursivegit submodule update init recursivegit submodule update r
  • PX4飞控之PWM输出控制

    PX4飞控之PWM输出控制 多旋翼电调如好盈XRotor xff0c DJI通用电调等都支持PWM信号来传输控制信号 常用的400Hz电调信号对应周期2500us xff0c 一般使用高电平时间1000us 2000us为有效信号区间 xf
  • 从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模块设计之四:MAVLink简介

    PX4模块设计之四 xff1a MAVLink简介 1 MAVLink PX4 应用简介2 MAVLink v2 0新特性3 MAVLink协议版本4 MAVLink通信协议帧4 1 MAVLink v1 0 帧格式4 2 MAVLink
  • PX4模块设计之六:PX4-Fast RTPS(DDS)简介

    64 TOC PX4模块设计之六 xff1a PX4 Fast RTPS DDS 简介 基于PX4开源软件框架简明简介的框架设计 xff0c 逐步分析内部模块功能设计 PX4 Fast RTPS DDS 具有实时发布 订阅uORB消息接口
  • PX4模块设计之二十六:BatteryStatus模块

    PX4模块设计之二十六 xff1a BatteryStatus模块 1 BatteryStatus模块简介2 模块入口函数2 1 主入口battery status main2 2 自定义子命令custom command 3 Batter
  • mtk android 4.4 audio framework 代码分析(未完成)

    mtk android 4 4 audio framework 代码分析 未完成 xff0c 有需要的朋友可以参考下 mtk android 4 4 audio framework 代码分析 未完成 2 28 2015 3 01 24 PM
  • vlc代码分析(4)——mpgv的demux

    Mpgv c 是对mpeg vedio的解码部分 xff0c 从demux开始 xff0c 到sample到输出 其中 xff0c 核心部分是函数ParseMPEGBlock 两种数据格式 xff1a video format 是video
  • 关于github px4 gps 驱动的开发的总结

    源码编译上边已经写过文章了 遇到的几个问题 1 解决虚拟机不能共享文件夹的问题 一开始虚拟机的更新 vmware tools 是灰色的 xff0c 不能点 xff0c 然后通过关掉虚拟机 xff0c 然后再开启的时候 xff0c 在没有启动
  • px4_simple_example和uorb机制

    px4 simple app PX4 Autopilot src exampes px4 simple app xff0c 这个程序是用c语言调用orb API和poll机制订阅和发布通讯数据 xff0c 但是这个例子并不是既有接收又有发送
  • px4仿真无法起飞问题(Failsafe enabled: no datalink)

    报错信息 问题描述 xff1a 使用JMAVSim和gazebo仿真px4起飞时报错如下 xff1a WARN commander Failsafe enabled no datalink 说不安全 解决方法 打开QGC 就可以起飞了
  • PX4模块设计之二十七:LandDetector模块

    PX4模块设计之二十七 xff1a LandDetector模块 1 LandDetector模块简介2 模块入口函数2 1 主入口land detector main2 2 自定义子命令custom command 3 LandDetec
  • 485代码分析

    rs485 h ifndef RS485 H define RS485 H include 34 sys h 34 extern u8 RS485 RX BUF 64 接收缓冲 最大64个字节 extern u8 RS485 RX CNT
  • 步骤八:PX4使用cartographer与move_base进行自主建图导航

    首先老样子硬件如下 飞控 HOLYBRO PIXHAWK V4 PX4 机载电脑 jetson nano b01 激光雷达 思岚a2 前提 你已经完成了cartographer建图部分 能够正常输出map话题 前言 由于要参加中国机器人大赛
  • 【PX4 飞控剖析】06 树莓派加载安装ROS,Mavros以及PX4固件

    PX4 飞控剖析 06 树莓派加载安装Mavros以及PX4固件 1 树莓派 刷镜像1 1 用Win32DiskImager刷入ubuntu mate 16 04 2 desktop armhf raspberry pi的镜像 1 2 开机
  • 无人机PX4使用动捕系统mocap的位置实现控制+MAVROS

    动捕系统Optitrack xff0c 有很高的定位精度 xff0c 能够给无人机提供比较精确的位置信息 xff0c 因此如果实验室有条件 xff0c 都可以买一套动捕系统 动捕系统的原理 xff1a 光学式动作捕捉依靠一整套精密而复杂的光
  • 四、无人机知识笔记(初级:基本运动原理)

    笔记来源于 沈阳无距科技 工业级无人机的中国名片 编程外星人 目录 一 多旋翼直升机 二 基本飞行姿态 三 多旋翼飞行原理 四 反扭力与偏航运动 五 螺旋桨 六 有刷电机和无刷电机 七 电调与PWM信号 八 动力电池 九 遥控器 十 机架设
  • 【Unity问题&错误】list问题

    error CS0305 Using the generic type System Collections Generic List
  • 飞行姿态解算(三)

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

    Flash 存储器接口还有两个标准 CFI和JEDEC CFI为公共Flash接口 Common Flash Interface 用来帮助程序从Flash芯片中获取操作方式信息 而不用在程序中硬编码Flash的ID JEDEC用来帮助程序读

随机推荐

  • 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