pixhawk Lacal_position_estimator数据流

一、Lacal_position_estimator与position_estimator_inav是并列关系,用于位置估计

具体选择过程应该是这样的,还没测验,仅供参考

1.cmake将Lacal_position_estimator编译进.px4

2.rcS中启动Lacal_position_estimator,令SYS_MC_EST_GROUP=1,或者将判断注释掉

二、处理的数据流,以光流为例

因为Lacal_position_estimator是用卡尔曼算法,笔者这方面还比较弱,只能先把数据流程整理下,具体的物理含义还不知

int local_position_estimator_thread_main(int argc, char *argv[])
{
	warnx("starting");
	using namespace control;
	BlockLocalPositionEstimator est;
	thread_running = true;
	while (!thread_should_exit) {
		est.update();
	}
	warnx("exiting.");
	thread_running = false;
	return 0;
}

跳转至est.update();

即void BlockLocalPositionEstimator::update()

以下皆工作于此循环中

while (!thread_should_exit) {
	est.update();
}

1.数据来源:

// see which updates are available
//订阅数据
bool flowUpdated = _sub_flow.updated();
bool paramsUpdated = _sub_param_update.updated();
bool baroUpdated = _sub_sensor.updated();
bool gpsUpdated = _gps_on.get() && _sub_gps.updated();
bool homeUpdated = _sub_home.updated();
bool visionUpdated = _vision_on.get() && _sub_vision_pos.updated();
bool mocapUpdated = _sub_mocap.updated();
bool lidarUpdated = (_sub_lidar != NULL) && _sub_lidar->updated();
bool sonarUpdated = (_sub_sonar != NULL) && _sub_sonar->updated();
// get new data
//获取新的数据
updateSubscriptions();

其原函数为

virtual void updateSubscriptions()
{
	Block::updateSubscriptions();
	if (getChildren().getHead() != NULL) { updateChildSubscriptions(); }
}

跳转至Block::updateSubscriptions();

void Block::updateSubscriptions()
{
	uORB::SubscriptionNode *sub = getSubscriptions().getHead();
	int count = 0;
	while (sub != NULL) {
		if (count++ > maxSubscriptionsPerBlock) {
			char name[blockNameLengthMax];
			getName(name, blockNameLengthMax);
			printf("exceeded max subscriptions for block: %s\n", name);
			break;
		}
		sub->update();
		sub = sub->getSibling();
	}
}

跳转至sub->update();

void SubscriptionBase::update(void *data)
{
	if (updated()) {
		int ret = orb_copy(_meta, _handle, data);
		if (ret != PX4_OK) { warnx("orb copy failed"); }
	}
}

于是通过while (sub != NULL) {}循环,将订阅的主题都copy下来了

2.状态预计

卡尔曼矩阵

_x(),状态向量

_u(),输入向量

_P(),状态协方差矩阵

2.1初始值(只运行一次)

initP();
_x.setZero();
_u.setZero();
_flowX = 0;
_flowY = 0;

Matrix<float, n_x, n_x>  _P; // state covariance matrix
void BlockLocalPositionEstimator::initP()
{
	_P.setZero();
	_P(X_x, X_x) = 1;
	_P(X_y, X_y) = 1;
	_P(X_z, X_z) = 1;
	_P(X_vx, X_vx) = 1;
	_P(X_vy, X_vy) = 1;
	_P(X_vz, X_vz) = 1;
	_P(X_bx, X_bx) = 1e-6;
	_P(X_by, X_by) = 1e-6;
	_P(X_bz, X_bz) = 1e-6;
	_P(X_tz, X_tz) = 1;
}
<img src="http://img.blog.csdn.net/20160703115049323?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />

2.2准备运算所需的矩阵或向量

输入向量_u

<pre name="code" class="cpp">if (_integrate.get() && _sub_att.get().R_valid) {
	Matrix3f R_att(_sub_att.get().R);
	Vector3f a(_sub_sensor.get().accelerometer_m_s2);
	_u = R_att * a;
	_u(U_az) += 9.81f; // add g
}

动态矩阵A

	// dynamics matrix
	Matrix<float, n_x, n_x>  A; // state dynamics matrix
	A.setZero();
	// derivative of position is velocity
	A(X_x, X_vx) = 1;
	A(X_y, X_vy) = 1;
	A(X_z, X_vz) = 1;

	// derivative of velocity is accelerometer acceleration
	// (in input matrix) - bias (in body frame)
	Matrix3f R_att(_sub_att.get().R);
	A(X_vx, X_bx) = -R_att(0, 0);
	A(X_vx, X_by) = -R_att(0, 1);
	A(X_vx, X_bz) = -R_att(0, 2);

	A(X_vy, X_bx) = -R_att(1, 0);
	A(X_vy, X_by) = -R_att(1, 1);
	A(X_vy, X_bz) = -R_att(1, 2);

	A(X_vz, X_bx) = -R_att(2, 0);
	A(X_vz, X_by) = -R_att(2, 1);
	A(X_vz, X_bz) = -R_att(2, 2);

输入矩阵B

	// input matrix
<span style="white-space:pre">	</span>Matrix<float, n_x, n_u>  B; // input matrix
	B.setZero();
	B(X_vx, U_ax) = 1;
	B(X_vy, U_ay) = 1;
	B(X_vz, U_az) = 1;

输入噪声协方差矩阵R

	// input noise covariance matrix
	Matrix<float, n_u, n_u> R;
	R.setZero();
	R(U_ax, U_ax) = _accel_xy_stddev.get() * _accel_xy_stddev.get();
	R(U_ay, U_ay) = _accel_xy_stddev.get() * _accel_xy_stddev.get();
	R(U_az, U_az) = _accel_z_stddev.get() * _accel_z_stddev.get();

系统过程噪声矩阵Q

	// process noise power matrix
	Matrix<float, n_x, n_x>  Q;
	Q.setZero();
	float pn_p_sq = _pn_p_noise_density.get() * _pn_p_noise_density.get();
	float pn_v_sq = _pn_v_noise_density.get() * _pn_v_noise_density.get();
	Q(X_x, X_x) = pn_p_sq;
	Q(X_y, X_y) = pn_p_sq;
	Q(X_z, X_z) = pn_p_sq;
	Q(X_vx, X_vx) = pn_v_sq;
	Q(X_vy, X_vy) = pn_v_sq;
	Q(X_vz, X_vz) = pn_v_sq;
	// technically, the noise is in the body frame,
	// but the components are all the same, so
	// ignoring for now
	float pn_b_sq = _pn_b_noise_density.get() * _pn_b_noise_density.get();
	Q(X_bx, X_bx) = pn_b_sq;
	Q(X_by, X_by) = pn_b_sq;
	Q(X_bz, X_bz) = pn_b_sq;
	// terrain random walk noise
	float pn_t_sq = _pn_t_noise_density.get() * _pn_t_noise_density.get();
	Q(X_tz, X_tz) = pn_t_sq;

连续时间的卡尔曼滤波器预测值

// continuous time kalman filter prediction
Vector<float, n_x> dx = (A * _x + B * _u) * getDt();

跟新-x,-P

// propagate
_x += dx; //状态向量
_P += (A * _P + _P * A.transpose() +B * R * B.transpose() + Q) * getDt();//状态协方差矩阵

输入是自定义的噪声矩阵、旋转矩阵和加速度向量,输出是-x(状态向量),-P(状态协方差矩阵)

3.矫正Correct

flowCorrect();

测量矩阵C

// flow measurement matrix and noise matrix
Matrix<float, n_y_flow, n_x> C;
C.setZero();
C(Y_flow_x, X_x) = 1;
C(Y_flow_y, X_y) = 1;

噪声矩阵R

<span style="white-space:pre">	</span>R.setZero();
	R(Y_flow_x, Y_flow_x) =
		_flow_xy_stddev.get() * _flow_xy_stddev.get();
	R(Y_flow_y, Y_flow_y) =
		_flow_xy_stddev.get() * _flow_xy_stddev.get();

剩余向量r

Vector<float, 2> r = y - C * _x;(_x来自上面的sonarCorrect()等)

剩余协方差(逆)

// residual covariance, (inverse)
Matrix<float, n_y_flow, n_y_flow> S_I =
	inv<float, n_y_flow>(C * _P * C.transpose() + R);( _P来自上面的sonarCorrect()等)

故障检测

// fault detection
float beta = (r.transpose() * (S_I * r))(0, 0);
if (beta > BETA_TABLE[n_y_flow]) {
	if (_flowFault < FAULT_MINOR) {
		//mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] flow fault,  beta %5.2f", double(beta));
		_flowFault = FAULT_MINOR;
	}
} else if (_flowFault) {
	_flowFault = FAULT_NONE;
	//mavlink_and_console_log_info(&mavlink_log_pub, "[lpe] flow OK");
}

光流矫正

if (_flowFault < fault_lvl_disable) {
	Matrix<float, n_x, n_y_flow> K =
		_P * C.transpose() * S_I;
	_x += K * r;    //跟新_x, 状态向量
	_P -= K * C * _P; //跟新_P, 状态协方差矩阵
} else {
	// reset flow integral to current estimate of position
	// if a fault occurred
	_flowX = _x(X_x);
	_flowY = _x(X_y);
}

4.发布状态

if (_altHomeInitialized) {
	// update all publications if possible
	publishLocalPos();
	publishEstimatorStatus();
	if (_canEstimateXY) {
		publishGlobalPos();
	}
}

publishLocalPos()发布这么多

_pub_lpos.get().timestamp = _timeStamp;
_pub_lpos.get().xy_valid = _canEstimateXY;
_pub_lpos.get().z_valid = _canEstimateZ;
_pub_lpos.get().v_xy_valid = _canEstimateXY;
_pub_lpos.get().v_z_valid = _canEstimateZ;
_pub_lpos.get().x = _x(X_x); 	// north
_pub_lpos.get().y = _x(X_y);  	// east
_pub_lpos.get().z = _x(X_z); 	// down
_pub_lpos.get().vx = _x(X_vx);  // north
_pub_lpos.get().vy = _x(X_vy);  // east
_pub_lpos.get().vz = _x(X_vz); 	// down
_pub_lpos.get().yaw = _sub_att.get().yaw;
_pub_lpos.get().xy_global = _sub_home.get().timestamp != 0; // need home for reference
_pub_lpos.get().z_global = _baroInitialized;
_pub_lpos.get().ref_timestamp = _sub_home.get().timestamp;
_pub_lpos.get().ref_lat = _map_ref.lat_rad * 180 / M_PI;
_pub_lpos.get().ref_lon = _map_ref.lon_rad * 180 / M_PI;
_pub_lpos.get().ref_alt = _sub_home.get().alt;
_pub_lpos.get().dist_bottom = agl();
_pub_lpos.get().dist_bottom_rate = -_x(X_vz);
_pub_lpos.get().surface_bottom_timestamp = _timeStamp;
_pub_lpos.get().dist_bottom_valid = _canEstimateZ;
_pub_lpos.get().eph = sqrtf(_P(X_x, X_x) + _P(X_y, X_y));
_pub_lpos.get().epv = sqrtf(_P(X_z, X_z));

publishEstimatorStatus()发布这么多

	_pub_est_status.get().timestamp = _timeStamp;
	for (int i = 0; i < n_x; i++) {
		_pub_est_status.get().states[i] = _x(i);
		_pub_est_status.get().covariances[i] = _P(i, i);
	}	_pub_est_status.get().n_states = n_x;
	_pub_est_status.get().nan_flags = 0;
	_pub_est_status.get().health_flags =
		((_baroFault > fault_lvl_disable) << SENSOR_BARO)
		+ ((_gpsFault > fault_lvl_disable) << SENSOR_GPS)
		+ ((_lidarFault > fault_lvl_disable) << SENSOR_LIDAR)
		+ ((_flowFault > fault_lvl_disable) << SENSOR_FLOW)
		+ ((_sonarFault > fault_lvl_disable) << SENSOR_SONAR)
		+ ((_visionFault > fault_lvl_disable) << SENSOR_VISION)
		+ ((_mocapFault > fault_lvl_disable) << SENSOR_MOCAP);
	_pub_est_status.get().timeout_flags =
		(_baroInitialized << SENSOR_BARO)
		+ (_gpsInitialized << SENSOR_GPS)
		+ (_flowInitialized << SENSOR_FLOW)
		+ (_lidarInitialized << SENSOR_LIDAR)
		+ (_sonarInitialized << SENSOR_SONAR)
		+ (_visionInitialized << SENSOR_VISION)
		+ (_mocapInitialized << SENSOR_MOCAP);

publishGlobalPos()发布这么多

		_pub_gpos.get().timestamp = _timeStamp;
		_pub_gpos.get().time_utc_usec = _sub_gps.get().time_utc_usec;
		_pub_gpos.get().lat = lat;
		_pub_gpos.get().lon = lon;
		_pub_gpos.get().alt = alt;
		_pub_gpos.get().vel_n = _x(X_vx);
		_pub_gpos.get().vel_e = _x(X_vy);
		_pub_gpos.get().vel_d = _x(X_vz);
		_pub_gpos.get().yaw = _sub_att.get().yaw;
		_pub_gpos.get().eph = sqrtf(_P(X_x, X_x) + _P(X_y, X_y));
		_pub_gpos.get().epv = sqrtf(_P(X_z, X_z));
		_pub_gpos.get().terrain_alt = _altHome - _x(X_tz);
		_pub_gpos.get().terrain_alt_valid = _canEstimateT;
		_pub_gpos.get().dead_reckoning = !_canEstimateXY && !_xyTimeout;
		_pub_gpos.get().pressure_alt = _sub_sensor.get().baro_alt_meter[0];
时间: 2024-11-06 13:59:37

pixhawk Lacal_position_estimator数据流的相关文章

pixhawk position_estimator_inav.cpp思路整理及数据流

写在前面: 这篇blog主要参考pixhawk的高度解算算法解读,并且加以扩展,扩展到其他传感器,其实里面处理好多只是记录了流程,至于里面实际物理意义并不是很清楚,也希望大牛能够指导一下. 概述: 整个算法的核心思想是由地理坐标系下的加速度通过积分,来获得速度.位置信息:经过2次修正产生可利用的信息,第一次是利用传感器计算修正系数产生加速度的偏差修正加速度,第二次是利用修正系数修正位置:最后可利用速度经过加速度修正,可利用的位置经过了加速度和位置修正.加速度的修正过程是由机体测量的加速度通过减去

pixhawk入门知识

Pixhawk是一种先进的自动驾驶仪,由PX4开放硬件项目设计和3D机器人制造.它具有来自ST公司先进的处理器和传感器技术,以及NuttX实时操作系统,能够实现惊人的性能,灵活性和可靠性控制任何自主飞行器.Pixhawk旗舰版模块将伴随着新的外设选项,包括数字空速传感器,外部多色LED指示灯支持和外部磁强计.所有的外围设备自动检测和配置. 该Pixhawk系统的优点包括:集成多线程,类似Unix / Linux类的编程环境:全新的自动驾驶功能,如任务和飞行行为的Lua脚本:一个自定义PX4驱动层

[pixhawk笔记]2-飞行模式

本文翻译自px4官方开发文档:https://dev.px4.io/en/concept/flight_modes.html  ,有不对之处,敬请指正. pixhawk的飞行模式如下: MANUAL(手动模式) 固定翼/车/船 MANUAL(手动模式):飞手控制输入直接到输出混控器 STABILIZED(增稳模式):飞手控制作为俯仰和滚转角度指令和手动的偏航指令(角度or速率?) 多轴 ACRO(特技模式):飞手输入直接到滚转.俯仰和偏航速率指令,油门直接到输出混控器 RATTITUDE(觉得是

Java中I/O流之数据流

Java 中的数据流: 对于某问题:将一个 long 类型的数据写到文件中,有办法吗?    转字符串 → 通过 getbytes() 写进去,费劲,而且在此过程中 long 类型的数需要不断地转换. 现在,Java 中的数据流能够很好的解决这个问题(不需要转换,直接写进去) 1. DataInputStream 与 DataOutputStream 分别继承自 InputStream.OutputStream, 它属于处理流,需要分别套接在 InputStream.OutputStream 类

angular2系列教程(九)Jsonp、URLSearchParams、中断选择数据流

大家好,今天我们要讲的是http模块的第二部分,主要学习ng2中Jsonp.URLSearchParams.observable中断选择数据流的用法. 例子 例子的第一个程序,上节课已经讲过了.这节课我们学习第二个程序,从wiki的api中跨域获取数据,可实现300毫秒内中断和选择最近请求等炫酷功能,这些功能都来自于observable! 运行方法: 在http目录或者上级目录起个服务即可: http-server 没有则需要安装http-server: sudo npm install htt

pixhawk编译过程

好久没有编译过PIXHAWK了,由于项目需要,又买了一个pixhawk2,由于每次编译都会出现新的问题,这次写帖子将过程记录下来. 环境:WIN10+Ubuntu16.04 64位(VMware Workstation 12 Pro虚拟机). 基本按照pixhawk的Devguide里面给的步骤,将遇到的问题和解决方法给出,希望能帮助到遇到这些问题的同学. 使用下列命令将用户加入dialout用户组: sudo usermod -a -G dialout $USER 然后,下载并运行工具链安装脚

vue.js学习之组件数据流详解

本文和大家分享的主要是vue.js组件数据流相关内容,一起来看看吧,希望对大家学习vue.js有所帮助. 一.组件 组件,可以说是现代前端框架中必不可少的组成部分.使用组件,不仅能极大地提高代码的复用率和开发者的开发效率,对于代码后期的维护也有着非常重要的意义.前端开发,由于历史遗留原因,WebComponent 虽然好用,但其发展情况却受到极大地限制,和很多新兴的前端技术一样,可望而不可即.基于这样的情况,聪明的开发者们尝试通过框架内部集成相应的功能来完成组件化,各种现代前端框架基本上都有各自

数据流: DataInputStream 和 DataOutputStream

/* * 1.数据流: DataInputStream 和 DataOutputStream 一对. * 1) DataInputStream 数据的字节输入流: DataOutputStream 数据的字节输出流. * 2) 功能: 实现八种基本类型数据的输入/输出. 同时,也可实现字符串的输入/输出. * 3) 特点: 八种基本类型的数据在输入/输出时,会保持类型不变. * 因此,这种流特别适合在网络上实现基本类型数据和字符串的传递. * * 4) 方法: * readByte() writ

NTFS数据流编辑器NtfsStreamsEditor 2

NTFS是微软Windows NT内核的系列操作系统支持的.一个特别为网络和磁盘配额.文件加密等管理安全特性设计的磁盘格式.NTFS比FAT文件系统更加稳定,更加安全,功能也更为强大. 通过命令“convert 分区盘符: /fs:ntfs”,可将FAT格式分区的文件系统转换为NTFS文件系统. NTFS交换数据流(alternate data streams,简称ADS)是NTFS磁盘格式的一个特性,在NTFS文件系统下,每个文件都可以存在多个数据流,就是说除了主文件流之外还可以有许多非主文件