PX4位置估计源码分析

2023-05-16

写在前面

源码版本:1.6.0rc1
源码位置:Firmware-1.6.0rc1\src\modules\position_estimator_inav\position_estimator_inav_main.cpp

整体框架:
在这里插入图片描述
整个算法的核心思想是由地理坐标系下的加速度通过积分,来获得速度、位置信息;经过2次修正产生可利用的信息,第一次是利用传感器计算修正系数产生加速度的偏差修正加速度,第二次是利用修正系数修正位置;最后可利用速度经过加速度修正,可利用的位置经过了加速度和位置修正。加速度的修正过程是由机体测量的加速度通过减去偏差,再转换到地理坐标系;位置的修正统一利用inertial_filter_correct()函数。

滤波两个函数

函数位置:Firmware-1.6.0rc1\src\modules\position_estimator_inav\inertial_filter.cpp

//x[0]: 位置
//x[1]:速度
void inertial_filter_predict(float dt, float x[2], float acc)
{
	if (PX4_ISFINITE(dt)) {
		if (!PX4_ISFINITE(acc)) {
			acc = 0.0f;
		}
		x[0] += x[1] * dt + acc * dt * dt / 2.0f;
		x[1] += acc * dt;
	}
}

//e : 每个传感器所代表的动态误差(corr 型)
//i : i=0 弥补位置 i=1 弥补速度
//w : 这个传感器弥补所占的权重
void inertial_filter_correct(float e, float dt, float x[2], int i, float w)
{
	if (PX4_ISFINITE(e) && PX4_ISFINITE(w) && PX4_ISFINITE(dt)) {
	//ki * e *dt   相当于积分环节 用于消除静态误差
		float ewdt = e * w * dt;
		x[i] += ewdt;

		if (i == 0) {
			x[1] += w * ewdt;
		}
	}
}

第一个函数很好理解,就是利用物理公式 Pk = Pk-1 +Vkdt +1/2adt^2 Vk = Vk-1 + adt 得到预测的位置和速度。
第二个函数可以把它理解成一个积分环节,而积分环节作用是消除静态误差,e表示每个传感器的动态误差(corr型),i = 0 弥补位置,i = 1 弥补速度, w则是某个传感器弥补时候所占用的权重(因为不同传感器精度不同,所以所占权重也不同)。

PX4位置估计源码分析

由于代码篇幅过长,且是多个相同功能的传感器写在了同一个函数中,而我们只关注气压传感器、GPS传感器用于修正加速度计,其他传感器用的较少,所以雷达、视觉、mocap、传感器的源代码部分就不在做粘贴分析。

从功能函数入口开始 int position_estimator_inav_thread_main(int argc, char *argv[])

int position_estimator_inav_thread_main(int argc, char *argv[])
{
	orb_advert_t mavlink_log_pub = nullptr;

	float x_est[2] = { 0.0f, 0.0f };	// pos, vel //估计值estimate
	float y_est[2] = { 0.0f, 0.0f };	// pos, vel
	float z_est[2] = { 0.0f, 0.0f };	// pos, vel

	float est_buf[EST_BUF_SIZE][3][2];	// estimated position buffer
	float R_buf[EST_BUF_SIZE][3][3];	// rotation matrix buffer
	float R_gps[3][3];					// rotation matrix for GPS correction moment
	memset(est_buf, 0, sizeof(est_buf));
	memset(R_buf, 0, sizeof(R_buf));
	memset(R_gps, 0, sizeof(R_gps));
	int buf_ptr = 0;

	static const float min_eph_epv = 2.0f;	// min EPH/EPV, used for weight calculation
	static const float max_eph_epv = 20.0f;	// max EPH/EPV acceptable for estimation

	float eph = max_eph_epv;
	float epv = 1.0f;//水平因子越小代表获得的数据准确度越高

	float x_est_prev[2], y_est_prev[2], z_est_prev[2];
	memset(x_est_prev, 0, sizeof(x_est_prev));
	memset(y_est_prev, 0, sizeof(y_est_prev));
	memset(z_est_prev, 0, sizeof(z_est_prev));

	int baro_init_cnt = 0;
	int baro_init_num = 200;
	float baro_offset = 0.0f;		// baro offset for reference altitude, initialized on start, then adjusted

	hrt_abstime accel_timestamp = 0;
	hrt_abstime baro_timestamp = 0;

	bool ref_inited = false;
	hrt_abstime ref_init_start = 0;
	const hrt_abstime ref_init_delay = 1000000;	// wait for 1s after 3D fix
	
	uint16_t accel_updates = 0;
	uint16_t baro_updates = 0;
	uint16_t gps_updates = 0;
	uint16_t attitude_updates = 0;
	
	hrt_abstime updates_counter_start = hrt_absolute_time();
	hrt_abstime pub_last = hrt_absolute_time();
	hrt_abstime t_prev = 0;
	/* store error when sensor updates, but correct on each time step to avoid jumps in estimated value */
	float acc[] = { 0.0f, 0.0f, 0.0f };	// N E D
	float acc_bias[] = { 0.0f, 0.0f, 0.0f };	// body frame//静态误差
	float corr_baro = 0.0f;		//D 
	float corr_gps[3][2] = {//动态误差correction
		{ 0.0f, 0.0f },		// N (pos, vel)
		{ 0.0f, 0.0f },		// E (pos, vel)
		{ 0.0f, 0.0f },		// D (pos, vel)
	};
	float w_gps_xy = 1.0f;//动态调节参数
	float w_gps_z = 1.0f;

开头定义了很多变量,用于之后的计算,变量意义注释都有,没啥好说的。

/* subscribe */
	int parameter_update_sub = orb_subscribe(ORB_ID(parameter_update));
	int actuator_sub = orb_subscribe(ORB_ID_VEHICLE_ATTITUDE_CONTROLS);
	int armed_sub = orb_subscribe(ORB_ID(actuator_armed));
	int sensor_combined_sub = orb_subscribe(ORB_ID(sensor_combined));
	int vehicle_attitude_sub = orb_subscribe(ORB_ID(vehicle_attitude));
	int optical_flow_sub = orb_subscribe(ORB_ID(optical_flow));
	int vehicle_gps_position_sub = orb_subscribe(ORB_ID(vehicle_gps_position));
	int vision_position_estimate_sub = orb_subscribe(ORB_ID(vision_position_estimate));
	int att_pos_mocap_sub = orb_subscribe(ORB_ID(att_pos_mocap));
	int distance_sensor_sub = orb_subscribe(ORB_ID(distance_sensor));
	int vehicle_rate_sp_sub = orb_subscribe(ORB_ID(vehicle_rates_setpoint));

	/* advertise */
	orb_advert_t vehicle_local_position_pub = orb_advertise(ORB_ID(vehicle_local_position), &local_pos);
	orb_advert_t vehicle_global_position_pub = NULL;
struct position_estimator_inav_params params;
	memset(&params, 0, sizeof(params));
	struct position_estimator_inav_param_handles pos_inav_param_handles;
	/* initialize parameter handles */
	inav_parameters_init(&pos_inav_param_handles);

	/* first parameters read at start up */
	struct parameter_update_s param_update;
	orb_copy(ORB_ID(parameter_update), parameter_update_sub,
		 &param_update); /* read from param topic to clear updated flag */
	/* first parameters update */
	inav_parameters_update(&pos_inav_param_handles, &params);

订阅及公告一些数据,参数初始化及参数更新。

	px4_pollfd_struct_t fds_init[1] = {};
	fds_init[0].fd = sensor_combined_sub;
	fds_init[0].events = POLLIN;

定义阻塞等待某个消息,消息名称为:sensor_combined_sub。

/* wait for initial baro value */
	bool wait_baro = true;
	TerrainEstimator terrain_estimator;

	thread_running = true;
	hrt_abstime baro_wait_for_sample_time = hrt_absolute_time();
	
	while (wait_baro && !thread_should_exit) {
		int ret = px4_poll(&fds_init[0], 1, 1000);
		if (ret < 0) {
			/* poll error */
			mavlink_log_info(&mavlink_log_pub, "[inav] poll error on init");
		} else if (hrt_absolute_time() - baro_wait_for_sample_time > MAX_WAIT_FOR_BARO_SAMPLE) {
			wait_baro = false;
			mavlink_log_info(&mavlink_log_pub, "[inav] timed out waiting for a baro sample");

		} else if (ret > 0) {
			if (fds_init[0].revents & POLLIN) {
				orb_copy(ORB_ID(sensor_combined), sensor_combined_sub, &sensor);

				if (wait_baro && sensor.timestamp + sensor.baro_timestamp_relative != baro_timestamp) {
					baro_timestamp = sensor.timestamp + sensor.baro_timestamp_relative;
					baro_wait_for_sample_time = hrt_absolute_time();
					/* mean calculation over several measurements */
					if (baro_init_cnt < baro_init_num) {
						if (PX4_ISFINITE(sensor.baro_alt_meter)) {
							baro_offset += sensor.baro_alt_meter;
							baro_init_cnt++;
						}
					} else {
						wait_baro = false;
						baro_offset /= (float) baro_init_cnt;
						local_pos.z_valid = true;
						local_pos.v_z_valid = true;
					}
				}
			}
		} else {
			PX4_WARN("INAV poll timeout");
		}
	}//只是上电运行一次

阻塞等待消息句柄为:sensor_combined_sub的数据,获取气压值,200次求平均值。(注意:这个循环上电只会循环一次,循环结束会将wait_baro这个bool变量置为false)

下面将进入功能函数的主循环。

/* main loop */
px4_pollfd_struct_t fds[1];
fds[0].fd = vehicle_attitude_sub;
fds[0].events = POLLIN;

while (!thread_should_exit) {
	int ret = px4_poll(fds, 1, 20); // wait maximal 20 ms = 50 Hz minimum rate
	hrt_abstime t = hrt_absolute_time();

	if (ret < 0) {
		/* poll error */
		mavlink_log_info(&mavlink_log_pub, "[inav] poll error on init");
		continue;

	} else if (ret > 0) {
		/* act on attitude updates */

		/* vehicle attitude */
		orb_copy(ORB_ID(vehicle_attitude), vehicle_attitude_sub, &att);
		attitude_updates++;

		bool updated;

		/* parameter update */
		//参数更新
		orb_check(parameter_update_sub, &updated);
		if (updated) {
			struct parameter_update_s update;
			orb_copy(ORB_ID(parameter_update), parameter_update_sub, &update);
			inav_parameters_update(&pos_inav_param_handles, &params);
		}

		/* actuator */
		orb_check(actuator_sub, &updated);

		if (updated) {
			orb_copy(ORB_ID_VEHICLE_ATTITUDE_CONTROLS, actuator_sub, &actuator);
		}
		
		/* armed */
		orb_check(armed_sub, &updated);
		if (updated) {
			orb_copy(ORB_ID(actuator_armed), armed_sub, &armed);
		}

		/* sensor combined */
		orb_check(sensor_combined_sub, &updated);

		matrix::Dcmf R = matrix::Quatf(att.q);//姿态矩阵R

		if (updated) {
			orb_copy(ORB_ID(sensor_combined), sensor_combined_sub, &sensor);

			if (sensor.timestamp + sensor.accelerometer_timestamp_relative != accel_timestamp) {
				/* correct accel bias */
				sensor.accelerometer_m_s2[0] -= acc_bias[0];
				sensor.accelerometer_m_s2[1] -= acc_bias[1];
				sensor.accelerometer_m_s2[2] -= acc_bias[2];

				/* transform acceleration vector from body frame to NED frame */
				for (int i = 0; i < 3; i++) {
					acc[i] = 0.0f;

					for (int j = 0; j < 3; j++) {
						acc[i] += R(i, j) * sensor.accelerometer_m_s2[j];
						//acc 表示地理坐标系下准确加速度
					}
				}

				acc[2] += CONSTANTS_ONE_G;//z轴弥补1G重力加速度

				accel_timestamp = sensor.timestamp + sensor.accelerometer_timestamp_relative;
				accel_updates++;
			}
			if (sensor.timestamp + sensor.baro_timestamp_relative != baro_timestamp) {
				//高度差(气压计动态误差 corr型) = 起飞点高度 - 气压计当前高度 - z轴估计高度(负)
				//baro_offset:气压计上电初值,即起飞前气压
				//sensor.baro_alt_meter:气压计测得的当前气压高度
				corr_baro = baro_offset - sensor.baro_alt_meter - z_est[0];
				
				baro_timestamp = sensor.timestamp + sensor.baro_timestamp_relative;
				baro_updates++;
			}
		}

代码开头又定义了一个需要阻塞等待的消息,其消息句柄为:vehicle_attitude_sub。这段代码的作用就是开篇给出的整体框架中的一部分(如下图),其中 加速度计获得的是机体坐标系下的加速度值,加速度的偏差(acc_bias)也要是机体系下的偏差,而后面用于积分的真实加速度(acc)是地理系下的加速度,所以要乘以旋转矩阵。

这里先提出一个问题:acc_bias[x] 从哪里获得?
在这里插入图片描述
每个传感器都有两种误差 : 静态误差 动态误差(corr) 其中静态误差可以通过静止之后取平均值得到并储存,但是动态误差需要事实计算得到。

在上面这段代码最后,通过 高度差(气压计动态误差 corr型) = 起飞点高度 - 气压计当前高度 - z轴估计高度(负) 得到气压计 的corr(动态误差),下面代码也是获取其他传感器(雷达、视觉、光流、mocap、GPS)的corr,这里只粘贴出GPS如何获取的corr。

/* vehicle GPS position */
orb_check(vehicle_gps_position_sub, &updated);
if (updated) {
	orb_copy(ORB_ID(vehicle_gps_position), vehicle_gps_position_sub, &gps);
	bool reset_est = false;
	
	/* hysteresis for GPS quality */
	if (gps_valid) {
		if (gps.eph > max_eph_epv || gps.epv > max_eph_epv || gps.fix_type < 3) {
			gps_valid = false;
			mavlink_log_info(&mavlink_log_pub, "[inav] GPS signal lost");
			warnx("[inav] GPS signal lost");
		}

	} else {
		if (gps.eph < max_eph_epv * 0.7f && gps.epv < max_eph_epv * 0.7f && gps.fix_type >= 3) {
			gps_valid = true;
			reset_est = true;
			mavlink_log_info(&mavlink_log_pub, "[inav] GPS signal found");
			warnx("[inav] GPS signal found");
		}
	}

上面部分是检测GPS数据是否有更新,并且每次使用GPS数据前都要判断GPS数据是否有效,(在上一次有效的时候判断本次是否无效,在上一次无效的时候判断本次是否有效),判断标准:GPS的定位因子是否在合理范围内,GPS提供的定位卫星是否>=3。

if (gps_valid) {
	double lat = gps.lat * 1e-7;
	double lon = gps.lon * 1e-7;
	float alt = gps.alt * 1e-3;

	/* initialize reference position if needed */
	if (!ref_inited) {//初始化GPS 数据
		if (ref_init_start == 0) {
			ref_init_start = t;

		} else if (t > ref_init_start + ref_init_delay) {
			ref_inited = true;

			/* set position estimate to (0, 0, 0), use GPS velocity for XY */
			x_est[0] = 0.0f;
			x_est[1] = gps.vel_n_m_s;
			y_est[0] = 0.0f;
			y_est[1] = gps.vel_e_m_s;

			local_pos.ref_lat = lat;
			local_pos.ref_lon = lon;
			local_pos.ref_alt = alt + z_est[0];
			local_pos.ref_timestamp = t;

			/* initialize projection */
			map_projection_init(&ref, lat, lon);
			// XXX replace this print
			warnx("init ref: lat=%.7f, lon=%.7f, alt=%8.4f", (double)lat, (double)lon, (double)alt);
			mavlink_log_info(&mavlink_log_pub, "[inav] init ref: %.7f, %.7f, %8.4f", (double)lat, (double)lon, (double)alt);
		}
	}

这一部分上电只会运行一次,通过ref_inited变量判断GPS是否初始化,初始化完成后会将其赋值true。

	if (ref_inited) {
		/* project GPS lat lon to plane */
		float gps_proj[2];
		map_projection_project(&ref, lat, lon, &(gps_proj[0]), &(gps_proj[1]));
	
		/* reset position estimate when GPS becomes good */
		if (reset_est) {
			x_est[0] = gps_proj[0];
			x_est[1] = gps.vel_n_m_s;
			y_est[0] = gps_proj[1];
			y_est[1] = gps.vel_e_m_s;
		}
	
		/* calculate index of estimated values in buffer */
		int est_i = buf_ptr - 1 - min(EST_BUF_SIZE - 1, max(0, (int)(params.delay_gps * 1000000.0f / PUB_INTERVAL)));
	
		if (est_i < 0) {
			est_i += EST_BUF_SIZE;
		}
	
		/* calculate correction for position */
		//位置corr计算 GPS值 - 估计值
		corr_gps[0][0] = gps_proj[0] - est_buf[est_i][0][0];
		corr_gps[1][0] = gps_proj[1] - est_buf[est_i][1][0];
		corr_gps[2][0] = local_pos.ref_alt - alt - est_buf[est_i][2][0];
	
		/* calculate correction for velocity */
		//速度corr计算  GPS值 - 估计值
		if (gps.vel_ned_valid) {
			corr_gps[0][1] = gps.vel_n_m_s - est_buf[est_i][0][1];
			corr_gps[1][1] = gps.vel_e_m_s - est_buf[est_i][1][1];
			corr_gps[2][1] = gps.vel_d_m_s - est_buf[est_i][2][1];
	
		} else {
			corr_gps[0][1] = 0.0f;
			corr_gps[1][1] = 0.0f;
			corr_gps[2][1] = 0.0f;
		}
	
			/* save rotation matrix at this moment */
			memcpy(R_gps, R_buf[est_i], sizeof(R_gps));
			//计算动态权重,分母部分min_eph_epv = 2,gps.eph:水平定位因子、fmaxf(x1,x2)取两着最大
			//定位因子越小,定位精度越高,当gps.eph > min_eph_epv 相当于放大分母,使得整体权重缩小
			w_gps_xy = min_eph_epv / fmaxf(min_eph_epv, gps.eph);
			w_gps_z = min_eph_epv / fmaxf(min_eph_epv, gps.epv);
		}//end if ref_inited.
	
	} //end if gps_valid
	else {
		/* no GPS lock */
		memset(corr_gps, 0, sizeof(corr_gps));
		ref_init_start = 0;
	}
		gps_updates++;
	}
}	

w_gps_xy:GPS水平定位权重,w_gps_z:GPS垂直定位权重(看注释)

因为GPS有时延,所以计算的并不是本时刻的corr。

est_i = buf_ptr - 1 - min(EST_BUF_SIZE - 1, max(0, (int)(params.delay_gps * 1000000.0f / PUB_INTERVAL)));

这样一句话是将时间戳向前移步。

//当程序走到这里时候已经获取所有传感器的corr型
//下面就是这个corr型怎么使用

matrix::Dcm<float> R = matrix::Quatf(att.q);//得到旋转矩阵
//先判断上面计算的corr型是否在合理范围内
		/* check for timeout on GPS topic */
		if (gps_valid && (t > (gps.timestamp + gps_topic_timeout))) {
			gps_valid = false;
			warnx("GPS timeout");
			mavlink_log_info(&mavlink_log_pub, "[inav] GPS timeout");
		}
		float dt = t_prev > 0 ? (t - t_prev) / 1000000.0f : 0.0f;
		dt = fmaxf(fminf(0.02, dt), 0.0002);		// constrain dt from 0.2 to 20 ms
		t_prev = t;
		
		/* increase EPH/EPV on each step */
		if (eph < 0.000001f) { //get case where eph is 0 -> would stay 0
			eph = 0.001;
		}
		if (eph < max_eph_epv) {
			eph *= 1.0f + dt;
		}
		if (epv < 0.000001f) { //get case where epv is 0 -> would stay 0
			epv = 0.001;
		}
		if (epv < max_eph_epv) {
			epv += 0.005f * dt;	// add 1m to EPV each 200s (baro drift)
//判断使用哪一个传感器(这里因为篇幅限制,只粘贴出GPS的定义变量)
/* use GPS if it's valid and reference position initialized */
bool use_gps_xy = ref_inited && gps_valid && params.w_xy_gps_p > MIN_VALID_W;
bool use_gps_z = ref_inited && gps_valid && params.w_z_gps_p > MIN_VALID_W;
bool can_estimate_xy = (eph < max_eph_epv) || use_gps_xy || use_flow || use_vision_xy || use_mocap;

float w_xy_gps_p = params.w_xy_gps_p * w_gps_xy;
float w_xy_gps_v = params.w_xy_gps_v * w_gps_xy;
float w_z_gps_p = params.w_z_gps_p * w_gps_z;
float w_z_gps_v = params.w_z_gps_v * w_gps_z;

上面这段代码,首先通过姿态数据中定义旋转矩阵,判断上面计算的GPS的corr是否有效,(判断标准,GPS是否有效,GPS数据获取是否超时),并改变每次获取GPS之后的定位因子精度(我的理解:认为连续获取的GPS数据,越往后面的数据准确度越低),其次,定义一些使用GPS的标志位(需满足1. GPS已经初始化、2.GPS数据有效、3. GPS权重大于最小值。),最后计算动态权重(其中包含两部分 1.h文件中自带的权重 这些是定值、2.刚刚计算的动态权重)。

/* baro offset correction */
		if (use_gps_z) {
			float offs_corr = corr_gps[2][0] * w_z_gps_p * dt;
			baro_offset += offs_corr;
			corr_baro += offs_corr;
		}

		/* accelerometer bias correction for GPS (use buffered rotation matrix) */
		float accel_bias_corr[3] = { 0.0f, 0.0f, 0.0f };

		if (use_gps_xy) {//地理坐标系下的
			accel_bias_corr[0] -= corr_gps[0][0] * w_xy_gps_p * w_xy_gps_p;
			accel_bias_corr[0] -= corr_gps[0][1] * w_xy_gps_v;
			accel_bias_corr[1] -= corr_gps[1][0] * w_xy_gps_p * w_xy_gps_p;
			accel_bias_corr[1] -= corr_gps[1][1] * w_xy_gps_v;
		}

		if (use_gps_z) {//我认为这里可能不用gps的z轴去计算加速度z轴动态误差,而是用下面的气压计
			accel_bias_corr[2] -= corr_gps[2][0] * w_z_gps_p * w_z_gps_p;
			accel_bias_corr[2] -= corr_gps[2][1] * w_z_gps_v;
		}
		
		//	这一部分可以看到z轴用气压计去融合的加速度计  而上面用的是GPS的z轴融合的加速度计
		//	在代码中没有雷达就会用气压计去融合加速度计z轴数据
		if (use_lidar) {
			accel_bias_corr[2] -= corr_lidar * params.w_z_lidar * params.w_z_lidar;

		} else {
			accel_bias_corr[2] -= corr_baro * params.w_z_baro * params.w_z_baro;
		}
	*/
		/* transform error vector from NED frame to body frame */
		for (int i = 0; i < 3; i++) {
			float c = 0.0f;

			for (int j = 0; j < 3; j++) {
				c += R_gps[j][i] * accel_bias_corr[j];
			}

			if (PX4_ISFINITE(c)) {
				acc_bias[i] += c * params.w_acc_bias * dt;//用于下一次 acc 矫正
			}
		}

		/* inertial filter prediction for altitude */
		inertial_filter_predict(dt, z_est, acc[2]);
		
		/* inertial filter correction for altitude */
		if (use_lidar) {
			inertial_filter_correct(corr_lidar, dt, z_est, 0, params.w_z_lidar);

		} else {//这里同样我认为会使用气压计去校正z轴,而不是用下面的GPS
			inertial_filter_correct(corr_baro, dt, z_est, 0, params.w_z_baro);
		}

		if (use_gps_z) {
			epv = fminf(epv, gps.epv);

			inertial_filter_correct(corr_gps[2][0], dt, z_est, 0, w_z_gps_p);
			inertial_filter_correct(corr_gps[2][1], dt, z_est, 1, w_z_gps_v);
		}

inav里面高度估计算法的理解:主要是用 acc.z 二次积分得到高度,但是 mpu6000 直接得到的 acc.z 并不能直接使用,所以用气压计算出一个矫正系数用来矫正 acc.z,然后二次积分得到高度,然后用气压计得到的高度直接矫正高度。也就是 说里面有 2 次矫正。这里得到的acc_bias[ ]用于下一次加速度计测量值减去的偏差(校正加速度)。

下面校正xy轴。

if (can_estimate_xy) {
			/* inertial filter prediction for position */
			inertial_filter_predict(dt, x_est, acc[0]);//先预测
			inertial_filter_predict(dt, y_est, acc[1]);

			if (!(PX4_ISFINITE(x_est[0]) && PX4_ISFINITE(x_est[1]) && PX4_ISFINITE(y_est[0]) && PX4_ISFINITE(y_est[1]))) {
				write_debug_log("BAD ESTIMATE AFTER PREDICTION", dt, x_est, y_est, z_est, x_est_prev, y_est_prev, z_est_prev,
						acc, corr_gps, w_xy_gps_p, w_xy_gps_v, corr_mocap, w_mocap_p,
						corr_vision, w_xy_vision_p, w_z_vision_p, w_xy_vision_v);
				memcpy(x_est, x_est_prev, sizeof(x_est));
				memcpy(y_est, y_est_prev, sizeof(y_est));
			}
			if (use_gps_xy) {//后校正
				eph = fminf(eph, gps.eph);

				inertial_filter_correct(corr_gps[0][0], dt, x_est, 0, w_xy_gps_p);
				inertial_filter_correct(corr_gps[1][0], dt, y_est, 0, w_xy_gps_p);

				if (gps.vel_ned_valid && t < gps.timestamp + gps_topic_timeout) {
					inertial_filter_correct(corr_gps[0][1], dt, x_est, 1, w_xy_gps_v);
					inertial_filter_correct(corr_gps[1][1], dt, y_est, 1, w_xy_gps_v);
				}
			}
			else {
			/* gradually reset xy velocity estimates */
			inertial_filter_correct(-x_est[1], dt, x_est, 1, params.w_xy_res_v);
			inertial_filter_correct(-y_est[1], dt, y_est, 1, params.w_xy_res_v);
		}

先预测,后校正的形式,预测函数与校正函数就是前文提到的两个函数。

在后面是一个冗余切换的保护机制这里没有粘贴。

	if (t > pub_last + PUB_INTERVAL) {
			pub_last = t;

			/* push current estimate to buffer */
			est_buf[buf_ptr][0][0] = x_est[0];
			est_buf[buf_ptr][0][1] = x_est[1];
			est_buf[buf_ptr][1][0] = y_est[0];
			est_buf[buf_ptr][1][1] = y_est[1];
			est_buf[buf_ptr][2][0] = z_est[0];
			est_buf[buf_ptr][2][1] = z_est[1];

			/* push current rotation matrix to buffer */
			memcpy(R_buf[buf_ptr], &R._data[0][0], sizeof(R._data));

			buf_ptr++;

			if (buf_ptr >= EST_BUF_SIZE) {
				buf_ptr = 0;
			}
			
			/* publish local position */
			local_pos.xy_valid = can_estimate_xy;
			local_pos.v_xy_valid = can_estimate_xy;
			local_pos.xy_global = local_pos.xy_valid && use_gps_xy;
			local_pos.z_global = local_pos.z_valid && use_gps_z;
			local_pos.x = x_est[0];
			local_pos.vx = x_est[1];
			local_pos.y = y_est[0];
			local_pos.vy = y_est[1];
			local_pos.z = z_est[0];
			local_pos.vz = z_est[1];
			matrix::Eulerf euler(R);
			local_pos.yaw = euler.psi();
			local_pos.dist_bottom_valid = dist_bottom_valid;
			local_pos.eph = eph;
			local_pos.epv = epv;

			if (local_pos.dist_bottom_valid) {
				local_pos.dist_bottom = dist_ground;
				local_pos.dist_bottom_rate = - z_est[1];
			}

			local_pos.timestamp = t;

			orb_publish(ORB_ID(vehicle_local_position), vehicle_local_position_pub, &local_pos);

			if (local_pos.xy_global && local_pos.z_global) {
				/* publish global position */
				global_pos.timestamp = t;
				global_pos.time_utc_usec = gps.time_utc_usec;

				double est_lat, est_lon;
				map_projection_reproject(&ref, local_pos.x, local_pos.y, &est_lat, &est_lon);

				global_pos.lat = est_lat;
				global_pos.lon = est_lon;
				global_pos.alt = local_pos.ref_alt - local_pos.z;

				global_pos.vel_n = local_pos.vx;
				global_pos.vel_e = local_pos.vy;
				global_pos.vel_d = local_pos.vz;

				global_pos.yaw = local_pos.yaw;

				global_pos.eph = eph;
				global_pos.epv = epv;

				if (terrain_estimator.is_valid()) {
					global_pos.terrain_alt = global_pos.alt - terrain_estimator.get_distance_to_ground();
					global_pos.terrain_alt_valid = true;

				} else {
					global_pos.terrain_alt_valid = false;
				}

				global_pos.pressure_alt = sensor.baro_alt_meter;

				if (vehicle_global_position_pub == NULL) {
					vehicle_global_position_pub = orb_advertise(ORB_ID(vehicle_global_position), &global_pos);

				} else {
					orb_publish(ORB_ID(vehicle_global_position), vehicle_global_position_pub, &global_pos);
				}
			}
		}
	}

数据填充、发布

总结:

  1. 变量初始化
  2. 计算气压计高度的零点偏移,主要是取 200 个数据求平均
  3. 各传感器计算得带各自的修正系数和权重
  4. 判断是否超时
  5. 判断是用哪一个传感器
  6. 计算权重
  7. 根据使用的传感器计算加速度偏差
  8. 预计位置
  9. 修正位置
  10. 发布

以上是个人对PX4位置估计的源码理解,同时也参考了阿木实验室better的理解思路,如有不正确的地方感谢提出批评指正,欢迎一起讨论学习QQ:1103706199。

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

PX4位置估计源码分析 的相关文章

  • pixhawk: px4代码初学分析:追溯电机控制--pwm输出

    追溯电机控制 pwm输出 正常工作状态下pwm输出过程简述 xff1a 其他状态下pwm输出 xff1a 正常工作状态下pwm输出过程简述 xff1a 姿态解算部分得出姿态控制量通过px4io cpp把姿态控制量发送给IOIO串口读取姿态控
  • 下载并构建PX4

    根据官方的文档 xff0c PX4下载和构建的方式有两种 xff1a Linux系列的Console模式 xff08 当然也支持Windows下的MINGW32 xff09 和Windows模式 在Windows平台下 xff0c 我们习惯
  • PX4二次开发中查无资料的踩坑总结

    写在前 xff1a 2021年9月下旬开始摸索px4飞控的二次开发 xff0c 从C 43 43 零基础到第一个修改算法后的版本稳定运行 xff0c 大概用了2个月 xff0c 从12月初改用新版本px4源码到现在又过去了约1个月 xff0
  • px4自定义mavlink收不到消息的问题

    px4版本1 12稳定版 最近在做px4二次开发相关工作 按照网上的一些教程自定义了一个mavlink消息用来控制无人机 按照教程里面的单独开了一个xml来定义消息 最后生成的消息在px4端通过流传输的方式自己写的客户端可以收到消息 但是客
  • 【2020-8-9】APM,PX4,GAZEBO,MAVLINK,MAVROS,ROS之间的关系以及科研设备选型

    0 概述 无人机自主飞行平台可以分为四个部分 xff1a 动力平台 xff0c 飞行控制器 xff0c 机载电脑和模拟平台 动力平台 xff1a 负责执行飞行任务 xff0c 包括螺旋桨 电机 机架等 xff0c 用于科研的一般都是F380
  • px4: v2的主板刷写v2的固件

    v2的主板刷写v2的固件 fengxuewei 64 fengxuewei Legion Y7000 2019 PG0 src Firmware changwei rc span class token function make span
  • 关于PX4中的高度若干问题

    飞行的高度是如何测量的 xff1f 地面的高度和海平面的高度差别很大 xff0c 飞控又是如何有效判别进行降落的 xff1f 这是我脑子里的疑问 搜索的一圈发现很少有人讨论这方面的问题 xff0c 于是本次我就直接看一下源代码 xff0c
  • PX4代码学习系列博客(6)——offboard模式位置控制代码分析

    分析offboard模式的代码需要用到以下几个模块 local position estimator mavlink mc pos control mc att control mixer 程序数据走向 mavlink 一般的offboar
  • PX4源代码下载编译

    sudo git clone https github com PX4 PX4 Autopilot git recursivegit submodule update init recursivegit submodule update r
  • PX4 ---- Mixer

    文章目录 Mixer 混合控制 作用输入输出装载混控文件MAVROS代码解析总结示例MAINAUX Mixer 混合控制 作用 经过位置控制和姿态控制后 xff0c 控制量通过 actuator controls发布 xff0c 其中 co
  • PX4 ---- Indoor Flight

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

    PX4模块设计之十三 xff1a WorkQueue设计 1 WorkQueue启动2 WorkQueue接口2 1 基本接口2 2 辅助接口2 3 WorkQueue任务函数2 3 1 Flat Build2 3 2 Protected
  • PX4模块设计之十八:Logger模块

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

    PX4模块设计之二十三 xff1a 自定义FlightTask Step1 创建飞行模式文件夹Step2 创建飞行模式源代码和CMakeLists txt文件Step3 更新CMakeLists txt文件Step4 更新FlightTas
  • PX4模块设计之三十:Hysteresis类

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

    PX4模块设计之三十六 xff1a MulticopterPositionControl模块 1 MulticopterPositionControl模块简介2 模块入口函数2 1 主入口mc pos control main2 2 自定义
  • PX4模块设计之四十三:icm20689模块

    PX4模块设计之四十三 xff1a icm20689模块 1 icm20689模块简介2 模块入口函数2 1 主入口icm20689 main2 2 自定义子命令custom command2 3 模块状态print status 重载 3
  • px4_simple_example和uorb机制

    px4 simple app PX4 Autopilot src exampes px4 simple app xff0c 这个程序是用c语言调用orb API和poll机制订阅和发布通讯数据 xff0c 但是这个例子并不是既有接收又有发送
  • PX4飞控之自主返航(RTL)控制逻辑

    本文基于PX4飞控1 5 5版本 xff0c 分析导航模块中自护返航模式的控制逻辑和算法 自主返航模式和导航中的其他模式一样 xff0c 在Navigator main函数中一旦触发case vehicle status s NAVIGAT
  • PX4通过参数脚本给飞控导入参数

    PX4通过参数脚本给飞控导入参数 先找一架正常能飞的无人机连接地面站 在参数页面右上角点击工具 gt 保存到文件 保存的时候文件名注明参数的相关信息 然后将需要加载参数的无人机连接至地面站 xff0c 注意需要加载参数的无人机必须和保存的参

随机推荐

  • 查看自己电脑被别人U盘拷贝文件

    windows 43 R reg query HKLM System currentcontrolset enum usbstor s gt c usb txt FriendlyName 第二种是使用USBViewer USBViewer
  • 普罗米修斯-docker安装

    1 只有一台服务器 xff0c 所以使用docker来进行试验 安装docker curl fsSL https get docker com bash s docker mirror Aliyun 查看安装版本 docker versio
  • netty参数设置

    1 通用参数 CONNECT TIMEOUT MILLIS Netty参数 xff0c 连接超时毫秒数 xff0c 默认值30000毫秒即30秒 MAX MESSAGES PER READ Netty参数 xff0c 一次Loop读取的最大
  • git 删除远程文件目录

    git rm r cached 文件夹名称 git add git commit m 34 aa 34 git push origin master
  • 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