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

2023-05-16

写在前面:

这篇blog主要参考pixhawk的高度解算算法解读,并且加以扩展,扩展到其他传感器,其实里面处理好多只是记录了流程,至于里面实际物理意义并不是很清楚,也希望大牛能够指导一下。

概述:

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

这里传感器的作用就是计算一个校正系数来对加速度偏移量进行校正。

代码思路

1. 变量初始化。

float z_est[2] = { 0.0f, 0.0f }; // z轴的高度、速度
float acc[] = { 0.0f, 0.0f, 0.0f }; //地理坐标系(NED)的加速度数据
float acc_bias[] = { 0.0f, 0.0f, 0.0f }; // 机体坐标系下的加速度偏移量

float corr_baro = 0.0f;		// D
float corr_gps[3][2] = {
	{ 0.0f, 0.0f },		// N (pos, vel)
	{ 0.0f, 0.0f },		// E (pos, vel)
	{ 0.0f, 0.0f },		// D (pos, vel)
};
float corr_vision[3][2] = {
	{ 0.0f, 0.0f },		// N (pos, vel)
	{ 0.0f, 0.0f },		// E (pos, vel)
	{ 0.0f, 0.0f },		// D (pos, vel)
};
float corr_mocap[3][1] = {
	{ 0.0f },		// N (pos)
	{ 0.0f },		// E (pos)
	{ 0.0f },		// D (pos)
};
float corr_lidar = 0.0f;//据说是超声波
float corr_flow[] = { 0.0f, 0.0f };	// N E

bool gps_valid = false;			// GPS is valid
bool lidar_valid = false;		// lidar is valid
bool flow_valid = false;		// flow is valid
bool flow_accurate = false;		// flow should be accurate (this flag not updated if flow_valid == false)
bool vision_valid = false;		// vision is valid
bool mocap_valid = false;		// mocap is valid

2. 计算气压计高度的零点偏移,主要是取200个数据求平均。

baro_offset += sensor.baro_alt_meter;
baro_offset /= (float) baro_init_cnt;

3.各传感器计算得带各自的修正系数和权重

corr_baro = baro_offset - sensor.baro_alt_meter[0] - z_est[0];
corr_lidar = lidar_offset - dist_ground - z_est[0];
corr_flow[0] = flow_v[0] - x_est[1]; /* velocity correction */
corr_flow[1] = flow_v[1] - y_est[1];
corr_vision[0][0] = vision.x - x_est[0]; /* calculate correction for position */
corr_vision[1][0] = vision.y - y_est[0];
corr_vision[2][0] = vision.z - z_est[0];
corr_vision[0][1] = vision.vx - x_est[1]; /* calculate correction for velocity */
corr_vision[1][1] = vision.vy - y_est[1];
corr_vision[2][1] = vision.vz - z_est[1];
corr_mocap[0][0] = mocap.x - x_est[0]; /* calculate correction for position */
corr_mocap[1][0] = mocap.y - y_est[0];
corr_mocap[2][0] = mocap.z - z_est[0];
corr_gps[0][0] = gps_proj[0] - est_buf[est_i][0][0]; /* calculate correction for position */
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];
corr_gps[0][1] = gps.vel_n_m_s - est_buf[est_i][0][1];/* calculate correction for velocity */
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];
w_gps_xy = min_eph_epv / fmaxf(min_eph_epv, gps.eph);
w_gps_z = min_eph_epv / fmaxf(min_eph_epv, gps.epv);

4.判断是否超时

if ((flow_valid || lidar_valid) && t > (flow_time + flow_topic_timeout))
if (gps_valid && (t > (gps.timestamp_position + gps_topic_timeout)))
if (vision_valid && (t > (vision.timestamp_boot + vision_topic_timeout)))
if (mocap_valid && (t > (mocap.timestamp_boot + mocap_topic_timeout)))
if (lidar_valid && (t > (lidar_time + lidar_timeout)))

5.判断是用哪一个传感器

/* 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;
/* use VISION if it's valid and has a valid weight parameter */
bool use_vision_xy = vision_valid && params.w_xy_vision_p > MIN_VALID_W;
bool use_vision_z = vision_valid && params.w_z_vision_p > MIN_VALID_W;
/* use MOCAP if it's valid and has a valid weight parameter */
bool use_mocap = mocap_valid && params.w_mocap_p > MIN_VALID_W && params.att_ext_hdg_m == mocap_heading; //check if external heading is mocap
if (params.disable_mocap) { //disable mocap if fake gps is used
	use_mocap = false;
}
/* use flow if it's valid and (accurate or no GPS available) */
bool use_flow = flow_valid && (flow_accurate || !use_gps_xy);
/* use LIDAR if it's valid and lidar altitude estimation is enabled */
use_lidar = lidar_valid && params.enable_lidar_alt_est;

6.计算权重

float flow_q = flow.quality / 255.0f;
float flow_q_weight = (flow_q - params.flow_q_min) / (1.0f - params.flow_q_min);
w_flow = PX4_R(att.R, 2, 2) * flow_q_weight / fmaxf(1.0f, flow_dist);
if (!flow_accurate) {
	w_flow *= 0.05f;
}

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;

float w_xy_vision_p = params.w_xy_vision_p;
float w_xy_vision_v = params.w_xy_vision_v;
float w_z_vision_p = params.w_z_vision_p;

float w_mocap_p = params.w_mocap_p;
/* reduce GPS weight if optical flow is good */
if (use_flow && flow_accurate) {
	w_xy_gps_p *= params.w_gps_flow;
	w_xy_gps_v *= params.w_gps_flow;
}
/* 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 };

7.根据使用的传感器计算加速度偏差

		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) {
			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;
		}

		/* 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;
			}
		}

		/* accelerometer bias correction for VISION (use buffered rotation matrix) */
		accel_bias_corr[0] = 0.0f;
		accel_bias_corr[1] = 0.0f;
		accel_bias_corr[2] = 0.0f;

		if (use_vision_xy) {
			accel_bias_corr[0] -= corr_vision[0][0] * w_xy_vision_p * w_xy_vision_p;
			accel_bias_corr[0] -= corr_vision[0][1] * w_xy_vision_v;
			accel_bias_corr[1] -= corr_vision[1][0] * w_xy_vision_p * w_xy_vision_p;
			accel_bias_corr[1] -= corr_vision[1][1] * w_xy_vision_v;
		}

		if (use_vision_z) {
			accel_bias_corr[2] -= corr_vision[2][0] * w_z_vision_p * w_z_vision_p;
		}

		/* accelerometer bias correction for MOCAP (use buffered rotation matrix) */
		accel_bias_corr[0] = 0.0f;
		accel_bias_corr[1] = 0.0f;
		accel_bias_corr[2] = 0.0f;

		if (use_mocap) {
			accel_bias_corr[0] -= corr_mocap[0][0] * w_mocap_p * w_mocap_p;
			accel_bias_corr[1] -= corr_mocap[1][0] * w_mocap_p * w_mocap_p;
			accel_bias_corr[2] -= corr_mocap[2][0] * w_mocap_p * w_mocap_p;
		}

		/* 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 += PX4_R(att.R, j, i) * accel_bias_corr[j];
			}

			if (PX4_ISFINITE(c)) {
				acc_bias[i] += c * params.w_acc_bias * dt;
			}
		}

		/* accelerometer bias correction for flow and baro (assume that there is no delay) */
		accel_bias_corr[0] = 0.0f;
		accel_bias_corr[1] = 0.0f;
		accel_bias_corr[2] = 0.0f;

		if (use_flow) {
			accel_bias_corr[0] -= corr_flow[0] * params.w_xy_flow;
			accel_bias_corr[1] -= corr_flow[1] * params.w_xy_flow;
		}

		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 += PX4_R(att.R, j, i) * accel_bias_corr[j];
			}

			if (PX4_ISFINITE(c)) {
				acc_bias[i] += c * params.w_acc_bias * dt;
			}
		}

这里得到的acc_bias[]用于前面程序(500行左右)(2016.08.23加)

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

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

				if (sensor.accelerometer_timestamp[0] != accel_timestamp) {
					if (att.R_valid) {
						/* 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] += PX4_R(att.R, i, j) * sensor.accelerometer_m_s2[j];
							}
						}

						acc[2] += CONSTANTS_ONE_G;

					} else {
						memset(acc, 0, sizeof(acc));
					}

					accel_timestamp = sensor.accelerometer_timestamp[0];
					accel_updates++;
				}
这里得到修正后的加速度,之后用此加速度进行一次、二次积分得到预计速度和位置(2016.08.23加)

8.预计位置

/* inertial filter prediction for altitude */
if (can_estimate_xy) {
{
inertial_filter_predict(dt, x_est, acc[0]);
inertial_filter_predict(dt, y_est, acc[1]);
}
inertial_filter_predict(dt, z_est, acc[2]);

函数解析

这里x_esty_estz_est通过float x[2]传进来来后,经过函数处理直接传回来给x_esty_estz_est(这里和C语法有点不同,但是不这么解释就说不过去了)

void inertial_filter_predict(float dt, float x[2], float acc)
{
	if (isfinite(dt)) {
		if (!isfinite(acc)) {
			acc = 0.0f;
		}
		x[0] += x[1] * dt + acc * dt * dt / 2.0f;
		x[1] += acc * dt;
	}
}

9.修正位置

利用传感器得到的速度和位置修正

/* inertial filter correction for altitude */
if (use_lidar) {
	inertial_filter_correct(corr_lidar, dt, z_est, 0, params.w_z_lidar);
} else {
	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);
}
if (use_vision_z) {
	epv = fminf(epv, epv_vision);
	inertial_filter_correct(corr_vision[2][0], dt, z_est, 0, w_z_vision_p);
}
if (use_mocap) {
	epv = fminf(epv, epv_mocap);
	inertial_filter_correct(corr_mocap[2][0], dt, z_est, 0, w_mocap_p);
}
if (can_estimate_xy) {
	/* inertial filter correction for position */
	if (use_flow) {
		eph = fminf(eph, eph_flow);
		inertial_filter_correct(corr_flow[0], dt, x_est, 1, params.w_xy_flow * w_flow);
		inertial_filter_correct(corr_flow[1], dt, y_est, 1, params.w_xy_flow * w_flow);
	}
	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_velocity + 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);
		}
	}
	if (use_vision_xy) {
		eph = fminf(eph, eph_vision);
		inertial_filter_correct(corr_vision[0][0], dt, x_est, 0, w_xy_vision_p);
		inertial_filter_correct(corr_vision[1][0], dt, y_est, 0, w_xy_vision_p);
		if (w_xy_vision_v > MIN_VALID_W) {
			inertial_filter_correct(corr_vision[0][1], dt, x_est, 1, w_xy_vision_v);
			inertial_filter_correct(corr_vision[1][1], dt, y_est, 1, w_xy_vision_v);
		}
	}
	if (use_mocap) {
		eph = fminf(eph, eph_mocap);
		inertial_filter_correct(corr_mocap[0][0], dt, x_est, 0, w_mocap_p);
		inertial_filter_correct(corr_mocap[1][0], dt, y_est, 0, w_mocap_p);
	}
}
/* run terrain estimator */
terrain_estimator.predict(dt, &att, &sensor, &lidar);
函数解析
e是修正系数;dt周期时间;x[2]是2个float型成员的数组,x[0]是位置,x[1]是速度;
i表示修正是位置还是速度,0是修正位置,1是修正速度;w是权重系数
这里x_est、y_est、z_est通过float x[2]传进来来后,经过函数处理直接传回来给x_est、y_est、z_est(这里和C语法有点不同,但是不这么解释就说不过去了)
void inertial_filter_correct(float e, float dt, float x[2], int i, float w)
{
	if (isfinite(e) && isfinite(w) && isfinite(dt)) {
		float ewdt = e * w * dt;
		x[i] += ewdt;

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

10.发布

			/* 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];
			local_pos.yaw = att.yaw;
			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[0];

				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);
				}
			}

常用传感器

气压+加速度=高度(此部分摘自http://blog.sina.com.cn/s/blog_8fe4f2f40102wo50.html)

1. 变量初始化。

float z_est[2] = { 0.0f, 0.0f }; // z轴的高度、速度
float acc[] = { 0.0f, 0.0f, 0.0f }; //地理坐标系(NED)的加速度数据
float acc_bias[] = { 0.0f, 0.0f, 0.0f }; //机体坐标系下的加速度偏移量
float corr_baro = 0.0f; // 气压计校正系数

2. 计算气压计高度的零点偏移,主要是取200个数据求平均。

baro_offset += sensor.baro_alt_meter;
baro_offset /= (float) baro_init_cnt;

3. 将传感器获取的机体加速度数据转换到地理坐标系下。

加速度数据要先去除偏移量;

sensor.accelerometer_m_s2[0] -=acc_bias[0];
sensor.accelerometer_m_s2[1] -= acc_bias[1];
sensor.accelerometer_m_s2[2] -=acc_bias[2];

然后转换坐标系;

acc[i] += PX4_R(att.R, i, j) *sensor.accelerometer_m_s2[j];

地理坐标系下的z轴加速度是有重力加速度的,因此补偿上去。

acc[2] += CONSTANTS_ONE_G;

4. 计算气压计的校正系数

corr_baro = baro_offset -sensor.baro_alt_meter - z_est[0];

5. 加速度偏移向量校正

accel_bias_corr[2] -= corr_baro *params.w_z_baro * params.w_z_baro;

6. 将偏移向量转换到机体坐标系

c += PX4_R(att.R, j, i) *accel_bias_corr[j];

acc_bias[i] += c * params.w_acc_bias * dt;

7. 加速度推算高度

inertial_filter_predict(dt, z_est, acc[2]);

8. 气压计校正系数进行校正

inertial_filter_correct(corr_baro, dt,z_est, 0, params.w_z_baro);

光流

orb_copy(ORB_ID(optical_flow), optical_flow_sub, &flow);
if (fabs(rates_setpoint.pitch) < rate_threshold) {
	//warnx("[inav] test ohne comp");
	flow_ang[0] = (flow.pixel_flow_x_integral / (float)flow.integration_timespan * 1000000.0f) * params.flow_k;//for now the flow has to be scaled (to small)
}
else {
	//warnx("[inav] test mit comp");
	//calculate flow [rad/s] and compensate for rotations (and offset of flow-gyro)
	flow_ang[0] = ((flow.pixel_flow_x_integral - flow.gyro_x_rate_integral) / (float)flow.integration_timespan * 1000000.0f
		       + gyro_offset_filtered[0]) * params.flow_k;//for now the flow has to be scaled (to small)
}
if (fabs(rates_setpoint.roll) < rate_threshold) {
	flow_ang[1] = (flow.pixel_flow_y_integral / (float)flow.integration_timespan * 1000000.0f) * params.flow_k;//for now the flow has to be scaled (to small)
}
else {
	//calculate flow [rad/s] and compensate for rotations (and offset of flow-gyro)
	flow_ang[1] = ((flow.pixel_flow_y_integral - flow.gyro_y_rate_integral) / (float)flow.integration_timespan * 1000000.0f
		       + gyro_offset_filtered[1]) * params.flow_k;//for now the flow has to be scaled (to small)
}

得出flow_ang[]


float dist_bottom = lidar.current_distance; 
float flow_dist = dist_bottom; 
所以说光流的距离来自lidar,也就是超声波
gyro_offset_filtered[0] = flow_gyrospeed_filtered[0] - att_gyrospeed_filtered[0];
gyro_offset_filtered[1] = flow_gyrospeed_filtered[1] - att_gyrospeed_filtered[1];
gyro_offset_filtered[2] = flow_gyrospeed_filtered[2] - att_gyrospeed_filtered[2];
flow_gyrospeed[0] = flow.gyro_x_rate_integral / (float)flow.integration_timespan * 1000000.0f;
flow_gyrospeed[1] = flow.gyro_y_rate_integral / (float)flow.integration_timespan * 1000000.0f;
flow_gyrospeed[2] = flow.gyro_z_rate_integral / (float)flow.integration_timespan * 1000000.0f;
yaw_comp[0] = - params.flow_module_offset_y * (flow_gyrospeed[2] - gyro_offset_filtered[2]);
yaw_comp[1] = params.flow_module_offset_x * (flow_gyrospeed[2] - gyro_offset_filtered[2]);

PX4_R(att.R, i, j)的意思是(att.R[i* 3 + j])

if (fabs(rates_setpoint.yaw) < rate_threshold) {
	flow_m[0] = -flow_ang[0] * flow_dist;
	flow_m[1] = -flow_ang[1] * flow_dist;
} else {
	flow_m[0] = -flow_ang[0] * flow_dist - yaw_comp[0] * params.flow_k;
	flow_m[1] = -flow_ang[1] * flow_dist - yaw_comp[1] * params.flow_k;
}

得出flow_m[]光流测量向量

flow_m[2] = z_est[1];
for (int i = 0; i < 2; i++) {
	for (int j = 0; j < 3; j++) {
		flow_v[i] += PX4_R(att.R, i, j) * flow_m[j];
	}
}
corr_flow[0] = flow_v[0] - x_est[1];
corr_flow[1] = flow_v[1] - y_est[1];

得出corr_flow[]


accel_bias_corr[0] -= corr_flow[0] * params.w_xy_flow;
accel_bias_corr[1] -= corr_flow[1] * params.w_xy_flow;

得出accel_bias_corr[]


PX4_R(att.R, i, j)的意思是(att.R[i* 3 + j])

/* 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 += PX4_R(att.R, j, i) * accel_bias_corr[j];
	}
	if (PX4_ISFINITE(c)) {
		acc_bias[i] += c * params.w_acc_bias * dt;
	}
}

得出acc_bias[]

inertial_filter_predict(dt, x_est, acc[0]);
inertial_filter_predict(dt, y_est, acc[1]);

得出x_est、y_est

inertial_filter_correct(corr_flow[0], dt, x_est, 1, params.w_xy_flow * w_flow);
inertial_filter_correct(corr_flow[1], dt, y_est, 1, params.w_xy_flow * w_flow);

得出修正后的x_est、y_est

GPS

orb_copy(ORB_ID(vehicle_gps_position), vehicle_gps_position_sub, &gps);
float alt = gps.alt * 1e-3;
local_pos.ref_alt = alt + z_est[0];
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];
map_projection_project(&ref, lat, lon, &(gps_proj[0]), &(gps_proj[1]));
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];
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];

得出corr_gps[][]

bool use_gps_xy = ref_inited && gps_valid && params.w_xy_gps_p > MIN_VALID_W;
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;
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;

得出accel_bias_corr[]


/* push current rotation matrix to buffer */
memcpy(R_buf[buf_ptr], att.R, sizeof(att.R));
/* save rotation matrix at this moment */
memcpy(R_gps, R_buf[est_i], sizeof(R_gps));
/* 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_bias[]

// gps[a][b],a=0则为x方向,a=1则为y方向,a=2则为z方向
//b=0则为位置,b=1则为速度
inertial_filter_predict(dt, z_est, acc[2]);

得出z_est

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);

得出修正后的z_est

inertial_filter_predict(dt, x_est, acc[0]);
inertial_filter_predict(dt, y_est, acc[1]);
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);
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);

  


如果您觉得此文对您的发展有用,请随意打赏。 

您的鼓励将是笔者书写高质量文章的最大动力^_^!!


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

pixhawk position_estimator_inav.cpp思路整理及数据流 的相关文章

  • 在 Android 中更改 ImageView 的位置时出现问题

    我似乎无法改变一个人的立场ImageView在我的安卓应用程序中 当我将代码放置在特定方法中时 就会发生这种情况 如下所述 我正在使用室内图集 http www indooratlas com 我的 android 项目中的库 我下载了示例
  • 从 FF/Webkit 中的像素位置创建折叠范围

    使用 JavaScript 我想从像素位置创建一个折叠范围 以便在文档流中在此位置标识的范围之后插入新节点 这可以通过文本范围Internet Explorer 中的对象 移动到点 x y 方法 如何在 FireFox 和 Webkit 中
  • 将元素从容器中分离出来

    我将所有内容包装在具有固定宽度的容器元素中 但我有一个 div 我想 突破 该容器以跨越页面的整个宽度 http dabblet com gist 3207168 http dabblet com gist 3207168 正如您在该示例中
  • 在Python中写入打开的文件时的分割函数[重复]

    这个问题在这里已经有答案了 所以我有一个程序 我应该在其中获取一个外部文件 用 python 打开它 然后分隔每个单词和每个标点符号 包括逗号 撇号和句号 然后我应该将该文件保存为文本中每个单词和标点符号出现时的整数位置 例如 我喜欢编码
  • 如何使用jQuery查找父元素中某个子元素的位置号

    我有一个 div 包含其他几个包含图像的 div 它看起来像这样 div div class imgHldr img src foo bar png div div class imgHldr img src foo bar png div
  • 锚链接着陆位置错误

    可能是一个愚蠢的问题 但老实说我无法理解这里出了什么问题 http harrisonfjord com thinkinc http harrisonfjord com thinkinc 我目前正在建设的网站 我想在以下位置创建一个锚链接ht
  • iPhone 802.11 扫描

    我正在开发一个室内位置使用 wifi 的系统 但是我在使用苹果库时遇到了问题 曾经是私人的 现在是公共的 我在哪里使用代码 libHandle dlopen System Library SystemConfiguration IPConf
  • jQuery FancyBox:滚动时弹出窗口相对于窗口的固定位置

    我怎样才能固定的位置fancybox http fancybox net api滚动页面时屏幕上弹出窗口 这个插件中有没有任何选项或者我必须使用它来定义它css 来自API page http fancybox net api center
  • IE 6 与位置:固定

    位置 已修复 不适用于 Internet Explorer 6 我无法真正理解在 google 上找到的修复程序 我需要它在 IE6 IE7 IE8 和 FireFox 3 0 中工作
  • 以编程方式设置 LinearLayout 的重力

    我已按照说明为 Unity 制作新的 AdMob 插件 广告显示正确 但底部位置有问题 它们显示在屏幕顶部 我已将重力设置为底部 对于 FrameLayout 但横幅广告再次显示在屏幕顶部 我没有任何带有 LinearLayout Fram
  • CSS 位置元素“固定”在滚动容器内

    我想知道是否有人找到了解决方案 我正在寻找一种将元素附加到滚动容器顶部的解决方案 HTML div class container div class header title div div class element div about
  • 文本环绕绝对定位的 div

    我知道有一些关于类似主题的问题 但它们主要涉及浮动 div 图像 我需要将图像 和 div 绝对定位 向右 但我只想让文本围绕它流动 如果我浮动 div 但我无法将其放置在我想要的位置 它会起作用 因为文本只是在图片后面流动 div cla
  • 是否可以在同一个 html 页面中多次使用相对位置?

    我在主页上使用 相对位置 和 绝对位置 我有一个使用上述母版页的页面 并且我尝试在此页面中再次对其他 2 个元素使用 相对位置 和 绝对位置 但该页面中下面的元素 绝对位置 是不是根据其上方的元素放置的 相对位置 而是指母版页中元素的 相对
  • Android:如何获取RecyclerView当前的X偏移量?

    我正在使用一个Scrollview对于无限的 时间选择器轮播 发现这不是最好的方法 最后一个问题 https stackoverflow com questions 26341587 horizontalscrollview customa
  • 如何使 jQuery Sticky Float 插件对页面更改做出实时反应?

    我一直在寻找非常精彩的 stickyfloat 插件 http plugins jquery com files stickyfloat 0 htm http plugins jquery com files stickyfloat 0 h
  • javascript模拟鼠标点击特定位置

    我现在需要如何自动触发按钮上的鼠标单击事件 我有这个但不起作用 window setInterval function simulateClick 2000 function simulateClick var evt document c
  • 如何在 OpenOffice BASIC 宏中通过鼠标单击获取文档坐标

    背景 我想在我用鼠标单击或悬停的位置 使用按键激活时 粘贴 如 CTRL V 任何内容 最好是图像 形状 我不知道该怎么做获取我单击的文档 X Y 上的位置 Apache OpenOffice SDraw Document OpenOffi
  • 绝对位置在固定位置内不起作用

    div div div div Both main and inner集装箱取走position fixed 内胆的制作方法position absolute和主容器position fixed 你需要定义top right bottom
  • 如何从主体上的 onClick 事件获取鼠标单击的绝对位置?

    我试图获取鼠标单击相对于浏览器 主体的绝对位置 顶部和左侧 not主体内的任何父元素 我有一个绑定到 body 的侦听器 但 e pageX 和 e pageY 为我提供了相对于 div 的位置 请注意 我可以利用 jQuery 和 YUI
  • 在视口中保留绝对定位的元素(jquery)

    我现在正在开发一个带有很多工具提示的网站 我想确保工具提示始终完全显示在视口中 我知道有工具提示插件 但它们对我不起作用 因为工具提示是通过 css 完成的 而且我不能全部更改 任何想要获得工具提示的元素都会被赋予一个position re

随机推荐

  • ELK-ElasticSearch权威指南笔记

    ELK ElasticSearch笔记 文章目录 ELK ElasticSearch笔记 前言测试工具 语法索引 xff0c 文档和类型文档元数据检索索引里文档数据查看当前节点的所有 Index查看所有index的mapping 映射 查看
  • 关于JAVA中内存溢出的解决办法

    关于JAVA中内存溢出的解决办法 J2ee应用系统是运行在J2EE应用服务器上的 xff0c 而j2ee应用服务器又是运行在JVM上的 xff0c 生成环境中JVM参数的优化和设置对于J2EE应用系统性能有着决定性的作用 要优化系统 xff
  • ireport的使用总结

    ireport的使用总结 截图居然都没显示出来 xff0c 如有需要可以到 xff08 http download csdn net detail czp0608 4140640 xff09 下载 相信很多java程序员们 xff0c 在开
  • 卡尔曼滤波C代码分析

    文章下载地址 xff1a http wenku baidu com view 3c42b7733186bceb18e8bb29
  • 作为一个新人,怎样学习嵌入式Linux?

    作为一个新人 xff0c 怎样学习嵌入式Linux xff1f 被问过太多次 xff0c 特写这篇文章来回答一下 在学习嵌入式Linux之前 xff0c 肯定要有C语言基础 汇编基础有没有无所谓 就那么几条汇编指令 xff0c 用到了一看就
  • pixhawk启动脚本分析

    Nuttx系统启动是由ardupilot mk PX4 ROMFS init d里的rcS和rc APM完成的 笔者阅读了rcS和rc APM xff0c 该脚本类似C语言 xff0c 并做了相关注释 主要是一些设备自检 xff0c 启动各
  • pixhawk ArduPilot_main启动与运行分析

    上节分析 2 个系统启动脚本 xff0c 一个是 ardupilot mk PX4 ROMFS init d 里的 rcS xff0c 另一个是 rc APM xff0c 这个脚本在 rcS 里得到了调用 xff0c 也就是说 xff0c
  • pixhawk make文件分析

    由于笔者没学过Linux等系统 xff0c 对make文件所知甚少 xff0c 本节分析可能有大量错误 xff0c 只提供参考 xff0c 随着技术积累 xff0c 以后会回过头改正错误的地方 xff0c 也非常欢迎提出指导意见 其中分析大
  • pixhawk 从main开始分析传感器数据如何流动起来,以GPS为例

    void Copter loop scheduler run time available gt MAIN LOOP MICROS 0u time available 本文以GPS数据为代表 xff0c 分析数据如何从硬件驱动层慢慢的流到主
  • pixhawk uORB初步分析

    再次编辑 xff0c 因为发现大神的解析 xff0c 添加在最后 xff0c 若一般人我不告诉他 根据自己理解画的流程图 xff1a xff08 2016 05 29加 xff09 由于上节分析GPS涉及到AP GPS PX4 read函数
  • pixhawk硬件构架

    1 Phxhawk连接线路 2 Phxhawk硬件芯片列表 处理器 STM32F427 VIT6 168 Mhz 256 KB RAM 2 MB 闪存 100Pin 32位 STM32F100C8T6 xff08 48Pin xff09 故
  • ELK-日志收集工具nxlog

    ELK 日志收集工具nxlog 文章目录 ELK 日志收集工具nxlog 前言安装语法宏变量 通用模块指令格式Module 模块名FlowControlInputType 指定输入类型OutputType xff1a 指定输出类型Exec
  • pixhawk原生码rcS分析

    代码执行流程 1 编译时将 cmake configs nuttx px4fmu v2 default cmake 文件中配置的模块全部编译并烧写到固件中去 2 地面站的配置会在 flash 中生成 fs mtd params 文件 xff
  • pixhawk win编译环境搭建

    经过笔者亲自试验搭建win编译环境 xff0c 试验成功 xff0c 以下为具体步骤 问题和解决方案 其实Linux下编译会快很多 xff0c 对于后期开发会缩短等待编译的时间 xff0c 正在尝试搭建Linux编译环境 1 pixhawk
  • pixhawk PX4FMU和PX4IO最底层启动过程分析

    首先 xff0c 大体了解PX4IO 与PX4FMU各自的任务 PX4IO STM32F100 为PIXHAWK 中专用于处理输入输出的部分 输入为支持的各类遥控器 PPM SPKT DSM SBUS 输出为电调的PWM 驱动信号 它与PX
  • pixhawk 姿态与控制部分的记录

    此篇是把之前看到的资料总结整理一遍 xff0c 大部分是搬砖 xff0c 也加入了自己的一点思考 xff0c 写的过程中晕了好多次 xff0c 先大体记录下来 xff0c 肯定有错误 xff0c 日后再改正吧 关于pixhawk程序执行流程
  • pixhawk 光流--位置估计--姿态估计--位置控制--姿态控制

    本文是边分析边写的 xff0c 顺便就记录下了分析的思路 xff0c 并不是按照教材那种思路介绍性的 xff0c 而是按照程序员分析程序的思路来的 所以读者跟着看有些地方看了意义不大 xff0c 但是这种程序分析的思路还是可以借鉴的 xff
  • pixhawk 整体架构的认识

    此篇blog的目的是对px4工程有一个整体认识 xff0c 对各个信号的流向有个了解 xff0c 以及控制算法采用的控制框架 PX4自动驾驶仪软件 可分为三大部分 xff1a 实时操作系统 中间件和飞行控制栈 1 NuttX实时操作系统 提
  • pixhawk mc_pos_control.cpp源码解读

    好久没跟新blog了 xff0c 这段时期边调试边看程序 xff0c 所以有点慢 要开始着手调试了 这篇blog是顺着上一篇pixhawk 整体架构的认识写的 xff0c 接下来看程序的话 xff0c 打算把各个功能模块理解一遍 xff0c
  • pixhawk position_estimator_inav.cpp思路整理及数据流

    写在前面 xff1a 这篇blog主要参考pixhawk的高度解算算法解读 xff0c 并且加以扩展 xff0c 扩展到其他传感器 xff0c 其实里面处理好多只是记录了流程 xff0c 至于里面实际物理意义并不是很清楚 xff0c 也希望