Browse Source

decoupled lidar from flow and used it for altitude estimation. qgc params added to enable it.

sbg
ChristophTobler 9 years ago committed by Lorenz Meier
parent
commit
6650bca35b
  1. 155
      src/modules/position_estimator_inav/position_estimator_inav_main.cpp
  2. 13
      src/modules/position_estimator_inav/position_estimator_inav_params.cpp
  3. 2
      src/modules/position_estimator_inav/position_estimator_inav_params.h

155
src/modules/position_estimator_inav/position_estimator_inav_main.cpp

@ -261,8 +261,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
int baro_init_cnt = 0; int baro_init_cnt = 0;
int baro_init_num = 200; int baro_init_num = 200;
float baro_offset = 0.0f; // baro offset for reference altitude, initialized on start, then adjusted float baro_offset = 0.0f; // baro offset for reference altitude, initialized on start, then adjusted
float surface_offset = 0.0f; // ground level offset from reference altitude
float surface_offset_rate = 0.0f; // surface offset change rate
hrt_abstime accel_timestamp = 0; hrt_abstime accel_timestamp = 0;
hrt_abstime baro_timestamp = 0; hrt_abstime baro_timestamp = 0;
@ -310,14 +308,18 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
{ 0.0f }, // D (pos) { 0.0f }, // D (pos)
}; };
float dist_ground = 0.0f; //variables for lidar altitude estimation
float dist_ground_filtered = 0.0f;
float corr_lidar = 0.0f; float corr_lidar = 0.0f;
float corr_lidar_filtered = 0.0f; float lidar_offset = 0.0f;
int lidar_offset_count = 0;
bool lidar_first = true;
bool use_lidar = false;
bool use_lidar_prev = false;
float corr_flow[] = { 0.0f, 0.0f }; // N E float corr_flow[] = { 0.0f, 0.0f }; // N E
float w_flow = 0.0f; float w_flow = 0.0f;
float lidar_prev = 0.0f;
//hrt_abstime flow_prev = 0; // time of last flow measurement
hrt_abstime lidar_time = 0; // time of last lidar measurement (not filtered) hrt_abstime lidar_time = 0; // time of last lidar measurement (not filtered)
hrt_abstime lidar_valid_time = 0; // time of last lidar measurement used for correction (filtered) hrt_abstime lidar_valid_time = 0; // time of last lidar measurement used for correction (filtered)
@ -327,6 +329,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
float flow_gyrospeed_filtered[] = { 0.0f, 0.0f, 0.0f }; float flow_gyrospeed_filtered[] = { 0.0f, 0.0f, 0.0f };
float att_gyrospeed_filtered[] = { 0.0f, 0.0f, 0.0f }; float att_gyrospeed_filtered[] = { 0.0f, 0.0f, 0.0f };
float yaw_comp[] = { 0.0f, 0.0f }; float yaw_comp[] = { 0.0f, 0.0f };
hrt_abstime flow_time = 0;
bool gps_valid = false; // GPS is valid bool gps_valid = false; // GPS is valid
bool lidar_valid = false; // lidar is valid bool lidar_valid = false; // lidar is valid
@ -455,7 +458,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
attitude_updates++; attitude_updates++;
bool updated; bool updated;
bool updated2;
/* parameter update */ /* parameter update */
orb_check(parameter_update_sub, &updated); orb_check(parameter_update_sub, &updated);
@ -519,62 +521,61 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
} }
} }
/* optical flow */
orb_check(optical_flow_sub, &updated);
orb_check(distance_sensor_sub, &updated2);
/* lidar alt estimation */
orb_check(distance_sensor_sub, &updated);
/* update lidar separately, needed by terrain estimator */ /* update lidar separately, needed by terrain estimator */
if (updated2) { if (updated) {
orb_copy(ORB_ID(distance_sensor), distance_sensor_sub, &lidar); orb_copy(ORB_ID(distance_sensor), distance_sensor_sub, &lidar);
} }
if (updated && updated2) { if (updated && lidar.current_distance > 0.2f && lidar.current_distance < 10.0f && (PX4_R(att.R, 2, 2) > 0.7f)) { //check if altitude estimation for lidar is enabled and new sensor data
orb_copy(ORB_ID(optical_flow), optical_flow_sub, &flow);
if (!use_lidar_prev && use_lidar)
/* calculate time from previous update */ lidar_first = true;
// float flow_dt = flow_prev > 0 ? (flow.flow_timestamp - flow_prev) * 1e-6f : 0.1f; use_lidar_prev = use_lidar;
// flow_prev = flow.flow_timestamp;
lidar_time = t;
if ((lidar.current_distance > 0.21f) && dist_ground = lidar.current_distance * PX4_R(att.R, 2, 2); //vertical distance
(lidar.current_distance < 4.0f) &&
/*(PX4_R(att.R, 2, 2) > 0.7f) &&*/ if (lidar_first) {
(fabsf(lidar.current_distance - lidar_prev) > FLT_EPSILON)) { lidar_first = false;
dist_ground_filtered = dist_ground;
lidar_time = t; lidar_offset = dist_ground_filtered + z_est[0];
lidar_prev = lidar.current_distance; mavlink_log_info(mavlink_fd, "[inav] LIDAR: new ground offset");
corr_lidar = lidar.current_distance + surface_offset + z_est[0]; warnx("[inav] LIDAR: new ground offset");
corr_lidar_filtered += (corr_lidar - corr_lidar_filtered) * params.lidar_filt; }
if (fabsf(corr_lidar) > params.lidar_err) { corr_lidar = lidar_offset - dist_ground - z_est[0];
/* correction is too large: spike or new ground level? */
if (fabsf(corr_lidar - corr_lidar_filtered) > params.lidar_err) { if (fabsf(corr_lidar) > params.lidar_err) { //check for spike
/* spike detected, ignore */ corr_lidar = 0;
corr_lidar = 0.0f; lidar_valid = false;
lidar_valid = false; lidar_offset_count++;
if (lidar_offset_count > 3) { //if consecutive bigger/smaller measurements -> new ground offset -> reinit
} else { lidar_first = true;
/* new ground level */ lidar_offset_count = 0;
surface_offset -= corr_lidar;
surface_offset_rate = 0.0f;
corr_lidar = 0.0f;
corr_lidar_filtered = 0.0f;
lidar_valid_time = t;
lidar_valid = true;
local_pos.surface_bottom_timestamp = t;
mavlink_log_info(mavlink_fd, "[inav] new surface level: %d", (int)surface_offset);
}
} else {
/* correction is ok, use it */
lidar_valid_time = t;
lidar_valid = true;
} }
} else {
dist_ground_filtered = (1 - params.lidar_filt) * dist_ground_filtered + params.lidar_filt * dist_ground;
corr_lidar = lidar_offset - dist_ground_filtered - z_est[0];
lidar_valid = true;
lidar_offset_count = 0;
lidar_valid_time = t;
} }
}
/* optical flow */
orb_check(optical_flow_sub, &updated);
if (updated && lidar_valid) {
orb_copy(ORB_ID(optical_flow), optical_flow_sub, &flow);
flow_time = t;
float flow_q = flow.quality / 255.0f; float flow_q = flow.quality / 255.0f;
float dist_bottom = - z_est[0] - surface_offset; //lidar.current_distance; float dist_bottom = lidar.current_distance;
if (dist_bottom > 0.21f && flow_q > params.flow_q_min) { if (dist_bottom > 0.21f && flow_q > params.flow_q_min && PX4_R(att.R, 2, 2) > 0.7f) {
/* distance to surface */ /* distance to surface */
//float flow_dist = dist_bottom / PX4_R(att.R, 2, 2); //use this if using sonar //float flow_dist = dist_bottom / PX4_R(att.R, 2, 2); //use this if using sonar
float flow_dist = dist_bottom; //use this if using lidar float flow_dist = dist_bottom; //use this if using lidar
@ -591,7 +592,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
flow_accurate = fabsf(body_v_est[1] / flow_dist - att.rollspeed) < max_flow && flow_accurate = fabsf(body_v_est[1] / flow_dist - att.rollspeed) < max_flow &&
fabsf(body_v_est[0] / flow_dist + att.pitchspeed) < max_flow; fabsf(body_v_est[0] / flow_dist + att.pitchspeed) < max_flow;
/*calculate offset of flow-gyro using already calibrated gyro from autopilot*/ /*calculate offset of flow-gyro using already calibrated gyro from autopilot*/
flow_gyrospeed[0] = flow.gyro_x_rate_integral/(float)flow.integration_timespan*1000000.0f; 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[1] = flow.gyro_y_rate_integral/(float)flow.integration_timespan*1000000.0f;
@ -631,10 +631,12 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
flow_ang[0] = (flow.pixel_flow_x_integral - flow.gyro_x_rate_integral)/(float)flow.integration_timespan*1000000.0f + gyro_offset_filtered[0] - yaw_comp[0];//flow.flow_raw_x * params.flow_k / 1000.0f / flow_dt; flow_ang[0] = (flow.pixel_flow_x_integral - flow.gyro_x_rate_integral)/(float)flow.integration_timespan*1000000.0f + gyro_offset_filtered[0] - yaw_comp[0];//flow.flow_raw_x * params.flow_k / 1000.0f / flow_dt;
flow_ang[1] = (flow.pixel_flow_y_integral - flow.gyro_y_rate_integral)/(float)flow.integration_timespan*1000000.0f + gyro_offset_filtered[1] - yaw_comp[1];//flow.flow_raw_y * params.flow_k / 1000.0f / flow_dt; flow_ang[1] = (flow.pixel_flow_y_integral - flow.gyro_y_rate_integral)/(float)flow.integration_timespan*1000000.0f + gyro_offset_filtered[1] - yaw_comp[1];//flow.flow_raw_y * params.flow_k / 1000.0f / flow_dt;
/* flow measurements vector */ /* flow measurements vector */
float flow_m[3]; float flow_m[3];
flow_m[0] = -flow_ang[0] * flow_dist; flow_m[0] = -flow_ang[0] * flow_dist;
flow_m[1] = -flow_ang[1] * flow_dist; flow_m[1] = -flow_ang[1] * flow_dist;
flow_m[2] = z_est[1]; flow_m[2] = z_est[1];
/* velocity in NED */ /* velocity in NED */
float flow_v[2] = { 0.0f, 0.0f }; float flow_v[2] = { 0.0f, 0.0f };
@ -780,6 +782,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
if (gps.eph > max_eph_epv || gps.epv > max_eph_epv || gps.fix_type < 3) { if (gps.eph > max_eph_epv || gps.epv > max_eph_epv || gps.fix_type < 3) {
gps_valid = false; gps_valid = false;
mavlink_log_info(mavlink_fd, "[inav] GPS signal lost"); mavlink_log_info(mavlink_fd, "[inav] GPS signal lost");
warnx("[inav] GPS signal lost");
} }
} else { } else {
@ -787,6 +790,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
gps_valid = true; gps_valid = true;
reset_est = true; reset_est = true;
mavlink_log_info(mavlink_fd, "[inav] GPS signal found"); mavlink_log_info(mavlink_fd, "[inav] GPS signal found");
warnx("[inav] GPS signal found");
} }
} }
@ -829,10 +833,12 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
/* reset position estimate when GPS becomes good */ /* reset position estimate when GPS becomes good */
if (reset_est) { if (reset_est) {
x_est[0] = gps_proj[0]; x_est[0] = gps_proj[0];
x_est[1] = gps.vel_n_m_s; x_est[1] = gps.vel_n_m_s;
y_est[0] = gps_proj[1]; y_est[0] = gps_proj[1];
y_est[1] = gps.vel_e_m_s; y_est[1] = gps.vel_e_m_s;
} }
/* calculate index of estimated values in buffer */ /* calculate index of estimated values in buffer */
@ -876,9 +882,8 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
} }
/* check for timeout on FLOW topic */ /* check for timeout on FLOW topic */
if ((flow_valid || lidar_valid) && t > flow.timestamp + flow_topic_timeout) { if ((flow_valid || lidar_valid) && t > (flow_time + flow_topic_timeout)) {
flow_valid = false; flow_valid = false;
lidar_valid = false;
warnx("FLOW timeout"); warnx("FLOW timeout");
mavlink_log_info(mavlink_fd, "[inav] FLOW timeout"); mavlink_log_info(mavlink_fd, "[inav] FLOW timeout");
} }
@ -906,8 +911,9 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
/* check for lidar measurement timeout */ /* check for lidar measurement timeout */
if (lidar_valid && (t > (lidar_time + lidar_timeout))) { if (lidar_valid && (t > (lidar_time + lidar_timeout))) {
corr_lidar = 0.0f;
lidar_valid = false; lidar_valid = false;
warnx("LIDAR timeout");
mavlink_log_info(mavlink_fd, "[inav] LIDAR timeout");
} }
float dt = t_prev > 0 ? (t - t_prev) / 1000000.0f : 0.0f; float dt = t_prev > 0 ? (t - t_prev) / 1000000.0f : 0.0f;
@ -942,22 +948,13 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
/* use flow if it's valid and (accurate or no GPS available) */ /* use flow if it's valid and (accurate or no GPS available) */
bool use_flow = flow_valid && (flow_accurate || !use_gps_xy); 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;
bool can_estimate_xy = (eph < max_eph_epv) || use_gps_xy || use_flow || use_vision_xy || use_mocap; bool can_estimate_xy = (eph < max_eph_epv) || use_gps_xy || use_flow || use_vision_xy || use_mocap;
bool dist_bottom_valid = (t < lidar_valid_time + lidar_valid_timeout); bool dist_bottom_valid = (t < lidar_valid_time + lidar_valid_timeout);
if (dist_bottom_valid) {
/* surface distance prediction */
surface_offset += surface_offset_rate * dt;
/* surface distance correction */
if (lidar_valid) {
surface_offset_rate -= corr_lidar * 0.5f * params.w_z_lidar * params.w_z_lidar * dt;
surface_offset -= corr_lidar * params.w_z_lidar * dt;
}
}
float w_xy_gps_p = params.w_xy_gps_p * w_gps_xy; 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_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_p = params.w_z_gps_p * w_gps_z;
@ -1054,13 +1051,17 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
accel_bias_corr[0] = 0.0f; accel_bias_corr[0] = 0.0f;
accel_bias_corr[1] = 0.0f; accel_bias_corr[1] = 0.0f;
accel_bias_corr[2] = 0.0f; accel_bias_corr[2] = 0.0f;
if (use_flow) { if (use_flow) {
accel_bias_corr[0] -= corr_flow[0] * params.w_xy_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[1] -= corr_flow[1] * params.w_xy_flow;
} }
accel_bias_corr[2] -= corr_baro * params.w_z_baro * params.w_z_baro; 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 */ /* transform error vector from NED frame to body frame */
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
@ -1074,7 +1075,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
acc_bias[i] += c * params.w_acc_bias * dt; acc_bias[i] += c * params.w_acc_bias * dt;
} }
} }
/* inertial filter prediction for altitude */ /* inertial filter prediction for altitude */
inertial_filter_predict(dt, z_est, acc[2]); inertial_filter_predict(dt, z_est, acc[2]);
@ -1086,7 +1087,11 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
} }
/* inertial filter correction for altitude */ /* inertial filter correction for altitude */
inertial_filter_correct(corr_baro, dt, z_est, 0, params.w_z_baro); 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) { if (use_gps_z) {
epv = fminf(epv, gps.epv); epv = fminf(epv, gps.epv);
@ -1257,8 +1262,8 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
local_pos.epv = epv; local_pos.epv = epv;
if (local_pos.dist_bottom_valid) { if (local_pos.dist_bottom_valid) {
local_pos.dist_bottom = -z_est[0] - surface_offset; local_pos.dist_bottom = dist_ground;
local_pos.dist_bottom_rate = - z_est[1] - surface_offset_rate; local_pos.dist_bottom_rate = - z_est[1];
} }
local_pos.timestamp = t; local_pos.timestamp = t;

13
src/modules/position_estimator_inav/position_estimator_inav_params.cpp

@ -324,6 +324,17 @@ PARAM_DEFINE_FLOAT(INAV_FLOW_DIST_Y, 0.0f);
*/ */
PARAM_DEFINE_FLOAT(INAV_DISAB_MOCAP, 0); PARAM_DEFINE_FLOAT(INAV_DISAB_MOCAP, 0);
/**
* Enable LIDAR for altitude estimation
*
* Enable LIDAR for altitude estimation
*
* @min 0
* @max 1
* @group Position Estimator INAV
*/
PARAM_DEFINE_FLOAT(INAV_LIDAR_EST, 0);
/** /**
* Disable vision input * Disable vision input
* *
@ -376,6 +387,7 @@ int inav_parameters_init(struct position_estimator_inav_param_handles *h)
h->flow_module_offset_x = param_find("INAV_FLOW_DIST_X"); h->flow_module_offset_x = param_find("INAV_FLOW_DIST_X");
h->flow_module_offset_y = param_find("INAV_FLOW_DIST_Y"); h->flow_module_offset_y = param_find("INAV_FLOW_DIST_Y");
h->disable_mocap = param_find("INAV_DISAB_MOCAP"); h->disable_mocap = param_find("INAV_DISAB_MOCAP");
h->enable_lidar_alt_est = param_find("INAV_LIDAR_EST");
return 0; return 0;
} }
@ -408,6 +420,7 @@ int inav_parameters_update(const struct position_estimator_inav_param_handles *h
param_get(h->flow_module_offset_x, &(p->flow_module_offset_x)); param_get(h->flow_module_offset_x, &(p->flow_module_offset_x));
param_get(h->flow_module_offset_y, &(p->flow_module_offset_y)); param_get(h->flow_module_offset_y, &(p->flow_module_offset_y));
param_get(h->disable_mocap, &(p->disable_mocap)); param_get(h->disable_mocap, &(p->disable_mocap));
param_get(h->enable_lidar_alt_est, &(p->enable_lidar_alt_est));
return 0; return 0;
} }

2
src/modules/position_estimator_inav/position_estimator_inav_params.h

@ -68,6 +68,7 @@ struct position_estimator_inav_params {
float flow_module_offset_x; float flow_module_offset_x;
float flow_module_offset_y; float flow_module_offset_y;
int32_t disable_mocap; int32_t disable_mocap;
int32_t enable_lidar_alt_est;
}; };
struct position_estimator_inav_param_handles { struct position_estimator_inav_param_handles {
@ -97,6 +98,7 @@ struct position_estimator_inav_param_handles {
param_t flow_module_offset_x; param_t flow_module_offset_x;
param_t flow_module_offset_y; param_t flow_module_offset_y;
param_t disable_mocap; param_t disable_mocap;
param_t enable_lidar_alt_est;
}; };
#define CBRK_NO_VISION_KEY 328754 #define CBRK_NO_VISION_KEY 328754

Loading…
Cancel
Save