mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-06-30 14:00:34 +08:00
Merge remote-tracking branch 'px4/ekf_home_init' into navigator_cleanup_ekf_home_init
Conflicts: src/modules/commander/commander.cpp src/modules/mc_pos_control/mc_pos_control_main.cpp src/modules/navigator/navigator_main.cpp src/modules/uORB/topics/vehicle_global_position.h
This commit is contained in:
Binary file not shown.
Binary file not shown.
@@ -6,7 +6,7 @@
|
||||
#
|
||||
# Start the attitude and position estimator
|
||||
#
|
||||
fw_att_pos_estimator start
|
||||
ekf_att_pos_estimator start
|
||||
|
||||
#
|
||||
# Start attitude controller
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#
|
||||
|
||||
attitude_estimator_ekf start
|
||||
#ekf_att_pos_estimator start
|
||||
position_estimator_inav start
|
||||
|
||||
mc_att_control start
|
||||
|
||||
@@ -35,6 +35,12 @@ then
|
||||
param set MPC_TILT_MAX 1.0
|
||||
param set MPC_LAND_SPEED 1.0
|
||||
param set MPC_LAND_TILT 0.3
|
||||
|
||||
param set PE_VELNE_NOISE 0.5
|
||||
param set PE_VELNE_NOISE 0.7
|
||||
param set PE_POSNE_NOISE 0.5
|
||||
param set PE_POSD_NOISE 1.0
|
||||
|
||||
fi
|
||||
|
||||
set PWM_RATE 400
|
||||
|
||||
@@ -70,7 +70,7 @@ MODULES += modules/gpio_led
|
||||
# Estimation modules (EKF/ SO3 / other filters)
|
||||
#
|
||||
MODULES += modules/attitude_estimator_ekf
|
||||
MODULES += modules/fw_att_pos_estimator
|
||||
MODULES += modules/ekf_att_pos_estimator
|
||||
MODULES += modules/position_estimator_inav
|
||||
#MODULES += examples/flow_position_estimator
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ MODULES += modules/gpio_led
|
||||
#
|
||||
MODULES += modules/attitude_estimator_ekf
|
||||
MODULES += modules/attitude_estimator_so3
|
||||
MODULES += modules/fw_att_pos_estimator
|
||||
MODULES += modules/ekf_att_pos_estimator
|
||||
MODULES += modules/position_estimator_inav
|
||||
MODULES += examples/flow_position_estimator
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@ void frsky_send_frame2(int uart)
|
||||
float course = 0, lat = 0, lon = 0, speed = 0, alt = 0;
|
||||
char lat_ns = 0, lon_ew = 0;
|
||||
int sec = 0;
|
||||
if (global_pos.global_valid) {
|
||||
if (global_pos.timestamp != 0 && hrt_absolute_time() < global_pos.timestamp + 20000) {
|
||||
time_t time_gps = global_pos.time_gps_usec / 1000000;
|
||||
struct tm *tm_gps = gmtime(&time_gps);
|
||||
|
||||
|
||||
+73
-125
@@ -1,9 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
||||
* Author: Thomas Gubler <thomasgubler@student.ethz.ch>
|
||||
* Julian Oes <joes@student.ethz.ch>
|
||||
* Lorenz Meier <lm@inf.ethz.ch>
|
||||
* Copyright (C) 2012, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -42,6 +39,7 @@
|
||||
* @author Thomas Gubler <thomasgubler@student.ethz.ch>
|
||||
* @author Julian Oes <joes@student.ethz.ch>
|
||||
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||
*/
|
||||
|
||||
#include <geo/geo.h>
|
||||
@@ -52,124 +50,58 @@
|
||||
#include <math.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Azimuthal Equidistant Projection
|
||||
* formulas according to: http://mathworld.wolfram.com/AzimuthalEquidistantProjection.html
|
||||
*/
|
||||
|
||||
/* values for map projection */
|
||||
static double phi_1;
|
||||
static double sin_phi_1;
|
||||
static double cos_phi_1;
|
||||
static double lambda_0;
|
||||
static double scale;
|
||||
|
||||
__EXPORT void map_projection_init(double lat_0, double lon_0) //lat_0, lon_0 are expected to be in correct format: -> 47.1234567 and not 471234567
|
||||
__EXPORT void map_projection_init(struct map_projection_reference_s *ref, double lat_0, double lon_0) //lat_0, lon_0 are expected to be in correct format: -> 47.1234567 and not 471234567
|
||||
{
|
||||
/* notation and formulas according to: http://mathworld.wolfram.com/AzimuthalEquidistantProjection.html */
|
||||
phi_1 = lat_0 / 180.0 * M_PI;
|
||||
lambda_0 = lon_0 / 180.0 * M_PI;
|
||||
|
||||
sin_phi_1 = sin(phi_1);
|
||||
cos_phi_1 = cos(phi_1);
|
||||
|
||||
/* calculate local scale by using the relation of true distance and the distance on plane */ //TODO: this is a quick solution, there are probably easier ways to determine the scale
|
||||
|
||||
/* 1) calculate true distance d on sphere to a point: http://www.movable-type.co.uk/scripts/latlong.html */
|
||||
|
||||
double lat1 = phi_1;
|
||||
double lon1 = lambda_0;
|
||||
|
||||
double lat2 = phi_1 + 0.5 / 180 * M_PI;
|
||||
double lon2 = lambda_0 + 0.5 / 180 * M_PI;
|
||||
double sin_lat_2 = sin(lat2);
|
||||
double cos_lat_2 = cos(lat2);
|
||||
double d = acos(sin(lat1) * sin_lat_2 + cos(lat1) * cos_lat_2 * cos(lon2 - lon1)) * CONSTANTS_RADIUS_OF_EARTH;
|
||||
|
||||
/* 2) calculate distance rho on plane */
|
||||
double k_bar = 0;
|
||||
double c = acos(sin_phi_1 * sin_lat_2 + cos_phi_1 * cos_lat_2 * cos(lon2 - lambda_0));
|
||||
|
||||
if (0 != c)
|
||||
k_bar = c / sin(c);
|
||||
|
||||
double x2 = k_bar * (cos_lat_2 * sin(lon2 - lambda_0)); //Projection of point 2 on plane
|
||||
double y2 = k_bar * ((cos_phi_1 * sin_lat_2 - sin_phi_1 * cos_lat_2 * cos(lon2 - lambda_0)));
|
||||
double rho = sqrt(pow(x2, 2) + pow(y2, 2));
|
||||
|
||||
scale = d / rho;
|
||||
ref->lat = lat_0 / 180.0 * M_PI;
|
||||
ref->lon = lon_0 / 180.0 * M_PI;
|
||||
|
||||
ref->sin_lat = sin(ref->lat);
|
||||
ref->cos_lat = cos(ref->lat);
|
||||
}
|
||||
|
||||
__EXPORT void map_projection_project(double lat, double lon, float *x, float *y)
|
||||
__EXPORT void map_projection_project(struct map_projection_reference_s *ref, double lat, double lon, float *x, float *y)
|
||||
{
|
||||
/* notation and formulas accoring to: http://mathworld.wolfram.com/AzimuthalEquidistantProjection.html */
|
||||
double phi = lat / 180.0 * M_PI;
|
||||
double lambda = lon / 180.0 * M_PI;
|
||||
double lat_rad = lat / 180.0 * M_PI;
|
||||
double lon_rad = lon / 180.0 * M_PI;
|
||||
|
||||
double sin_phi = sin(phi);
|
||||
double cos_phi = cos(phi);
|
||||
double sin_lat = sin(lat_rad);
|
||||
double cos_lat = cos(lat_rad);
|
||||
double cos_d_lon = cos(lon_rad - ref->lon);
|
||||
|
||||
double k_bar = 0;
|
||||
/* using small angle approximation (formula in comment is without aproximation) */
|
||||
double c = acos(sin_phi_1 * sin_phi + cos_phi_1 * cos_phi * (1 - pow((lambda - lambda_0), 2) / 2)); //double c = acos( sin_phi_1 * sin_phi + cos_phi_1 * cos_phi * cos(lambda - lambda_0) );
|
||||
double c = acos(ref->sin_lat * sin_lat + ref->cos_lat * cos_lat * cos_d_lon);
|
||||
double k = (c == 0.0) ? 1.0 : (c / sin(c));
|
||||
|
||||
if (0 != c)
|
||||
k_bar = c / sin(c);
|
||||
|
||||
/* using small angle approximation (formula in comment is without aproximation) */
|
||||
*y = k_bar * (cos_phi * (lambda - lambda_0)) * scale;//*y = k_bar * (cos_phi * sin(lambda - lambda_0)) * scale;
|
||||
*x = k_bar * ((cos_phi_1 * sin_phi - sin_phi_1 * cos_phi * (1 - pow((lambda - lambda_0), 2) / 2))) * scale; // *x = k_bar * ((cos_phi_1 * sin_phi - sin_phi_1 * cos_phi * cos(lambda - lambda_0))) * scale;
|
||||
|
||||
// printf("%phi_1=%.10f, lambda_0 =%.10f\n", phi_1, lambda_0);
|
||||
*x = k * (ref->cos_lat * sin_lat - ref->sin_lat * cos_lat * cos_d_lon) * CONSTANTS_RADIUS_OF_EARTH;
|
||||
*y = k * cos_lat * sin(lon_rad - ref->lon) * CONSTANTS_RADIUS_OF_EARTH;
|
||||
}
|
||||
|
||||
__EXPORT void map_projection_reproject(float x, float y, double *lat, double *lon)
|
||||
__EXPORT void map_projection_reproject(struct map_projection_reference_s *ref, float x, float y, double *lat, double *lon)
|
||||
{
|
||||
/* notation and formulas accoring to: http://mathworld.wolfram.com/AzimuthalEquidistantProjection.html */
|
||||
|
||||
double x_descaled = x / scale;
|
||||
double y_descaled = y / scale;
|
||||
|
||||
double c = sqrt(pow(x_descaled, 2) + pow(y_descaled, 2));
|
||||
float x_rad = x / CONSTANTS_RADIUS_OF_EARTH;
|
||||
float y_rad = y / CONSTANTS_RADIUS_OF_EARTH;
|
||||
double c = sqrtf(x_rad * x_rad + y_rad * y_rad);
|
||||
double sin_c = sin(c);
|
||||
double cos_c = cos(c);
|
||||
|
||||
double lat_sphere = 0;
|
||||
double lat_rad;
|
||||
double lon_rad;
|
||||
|
||||
if (c != 0)
|
||||
lat_sphere = asin(cos_c * sin_phi_1 + (x_descaled * sin_c * cos_phi_1) / c);
|
||||
else
|
||||
lat_sphere = asin(cos_c * sin_phi_1);
|
||||
|
||||
// printf("lat_sphere = %.10f\n",lat_sphere);
|
||||
|
||||
double lon_sphere = 0;
|
||||
|
||||
if (phi_1 == M_PI / 2) {
|
||||
//using small angle approximation (formula in comment is without aproximation)
|
||||
lon_sphere = (lambda_0 - y_descaled / x_descaled); //lon_sphere = (lambda_0 + atan2(-y_descaled, x_descaled));
|
||||
|
||||
} else if (phi_1 == -M_PI / 2) {
|
||||
//using small angle approximation (formula in comment is without aproximation)
|
||||
lon_sphere = (lambda_0 + y_descaled / x_descaled); //lon_sphere = (lambda_0 + atan2(y_descaled, x_descaled));
|
||||
if (c != 0.0) {
|
||||
lat_rad = asin(cos_c * ref->sin_lat + (x_rad * sin_c * ref->cos_lat) / c);
|
||||
lon_rad = (ref->lon + atan2(y_rad * sin_c, c * ref->cos_lat * cos_c - x_rad * ref->sin_lat * sin_c));
|
||||
|
||||
} else {
|
||||
|
||||
lon_sphere = (lambda_0 + atan2(y_descaled * sin_c , c * cos_phi_1 * cos_c - x_descaled * sin_phi_1 * sin_c));
|
||||
//using small angle approximation
|
||||
// double denominator = (c * cos_phi_1 * cos_c - x_descaled * sin_phi_1 * sin_c);
|
||||
// if(denominator != 0)
|
||||
// {
|
||||
// lon_sphere = (lambda_0 + (y_descaled * sin_c) / denominator);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// ...
|
||||
// }
|
||||
lat_rad = ref->lat;
|
||||
lon_rad = ref->lon;
|
||||
}
|
||||
|
||||
// printf("lon_sphere = %.10f\n",lon_sphere);
|
||||
|
||||
*lat = lat_sphere * 180.0 / M_PI;
|
||||
*lon = lon_sphere * 180.0 / M_PI;
|
||||
|
||||
*lat = lat_rad * 180.0 / M_PI;
|
||||
*lon = lon_rad * 180.0 / M_PI;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,7 +139,7 @@ __EXPORT float get_bearing_to_next_waypoint(double lat_now, double lon_now, doub
|
||||
return theta;
|
||||
}
|
||||
|
||||
__EXPORT void get_vector_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next, float* v_n, float* v_e)
|
||||
__EXPORT void get_vector_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next, float *v_n, float *v_e)
|
||||
{
|
||||
double lat_now_rad = lat_now * M_DEG_TO_RAD;
|
||||
double lon_now_rad = lon_now * M_DEG_TO_RAD;
|
||||
@@ -222,7 +154,7 @@ __EXPORT void get_vector_to_next_waypoint(double lat_now, double lon_now, double
|
||||
*v_e = CONSTANTS_RADIUS_OF_EARTH * sin(d_lon) * cos(lat_next_rad);
|
||||
}
|
||||
|
||||
__EXPORT void get_vector_to_next_waypoint_fast(double lat_now, double lon_now, double lat_next, double lon_next, float* v_n, float* v_e)
|
||||
__EXPORT void get_vector_to_next_waypoint_fast(double lat_now, double lon_now, double lat_next, double lon_next, float *v_n, float *v_e)
|
||||
{
|
||||
double lat_now_rad = lat_now * M_DEG_TO_RAD;
|
||||
double lon_now_rad = lon_now * M_DEG_TO_RAD;
|
||||
@@ -248,7 +180,7 @@ __EXPORT void add_vector_to_global_position(double lat_now, double lon_now, floa
|
||||
|
||||
// Additional functions - @author Doug Weibel <douglas.weibel@colorado.edu>
|
||||
|
||||
__EXPORT int get_distance_to_line(struct crosstrack_error_s * crosstrack_error, double lat_now, double lon_now, double lat_start, double lon_start, double lat_end, double lon_end)
|
||||
__EXPORT int get_distance_to_line(struct crosstrack_error_s *crosstrack_error, double lat_now, double lon_now, double lat_start, double lon_start, double lat_end, double lon_end)
|
||||
{
|
||||
// This function returns the distance to the nearest point on the track line. Distance is positive if current
|
||||
// position is right of the track and negative if left of the track as seen from a point on the track line
|
||||
@@ -265,7 +197,7 @@ __EXPORT int get_distance_to_line(struct crosstrack_error_s * crosstrack_error,
|
||||
crosstrack_error->bearing = 0.0f;
|
||||
|
||||
// Return error if arguments are bad
|
||||
if (lat_now == 0.0d || lon_now == 0.0d || lat_start == 0.0d || lon_start == 0.0d || lat_end == 0.0d || lon_end == 0.0d) return return_value;
|
||||
if (lat_now == 0.0d || lon_now == 0.0d || lat_start == 0.0d || lon_start == 0.0d || lat_end == 0.0d || lon_end == 0.0d) { return return_value; }
|
||||
|
||||
bearing_end = get_bearing_to_next_waypoint(lat_now, lon_now, lat_end, lon_end);
|
||||
bearing_track = get_bearing_to_next_waypoint(lat_start, lon_start, lat_end, lon_end);
|
||||
@@ -296,8 +228,8 @@ __EXPORT int get_distance_to_line(struct crosstrack_error_s * crosstrack_error,
|
||||
}
|
||||
|
||||
|
||||
__EXPORT int get_distance_to_arc(struct crosstrack_error_s * crosstrack_error, double lat_now, double lon_now, double lat_center, double lon_center,
|
||||
float radius, float arc_start_bearing, float arc_sweep)
|
||||
__EXPORT int get_distance_to_arc(struct crosstrack_error_s *crosstrack_error, double lat_now, double lon_now, double lat_center, double lon_center,
|
||||
float radius, float arc_start_bearing, float arc_sweep)
|
||||
{
|
||||
// This function returns the distance to the nearest point on the track arc. Distance is positive if current
|
||||
// position is right of the arc and negative if left of the arc as seen from the closest point on the arc and
|
||||
@@ -316,29 +248,29 @@ __EXPORT int get_distance_to_arc(struct crosstrack_error_s * crosstrack_error, d
|
||||
crosstrack_error->bearing = 0.0f;
|
||||
|
||||
// Return error if arguments are bad
|
||||
if (lat_now == 0.0d || lon_now == 0.0d || lat_center == 0.0d || lon_center == 0.0d || radius == 0.0d) return return_value;
|
||||
if (lat_now == 0.0d || lon_now == 0.0d || lat_center == 0.0d || lon_center == 0.0d || radius == 0.0d) { return return_value; }
|
||||
|
||||
|
||||
if (arc_sweep >= 0) {
|
||||
bearing_sector_start = arc_start_bearing;
|
||||
bearing_sector_end = arc_start_bearing + arc_sweep;
|
||||
|
||||
if (bearing_sector_end > 2.0f * M_PI_F) bearing_sector_end -= M_TWOPI_F;
|
||||
if (bearing_sector_end > 2.0f * M_PI_F) { bearing_sector_end -= M_TWOPI_F; }
|
||||
|
||||
} else {
|
||||
bearing_sector_end = arc_start_bearing;
|
||||
bearing_sector_start = arc_start_bearing - arc_sweep;
|
||||
|
||||
if (bearing_sector_start < 0.0f) bearing_sector_start += M_TWOPI_F;
|
||||
if (bearing_sector_start < 0.0f) { bearing_sector_start += M_TWOPI_F; }
|
||||
}
|
||||
|
||||
in_sector = false;
|
||||
|
||||
// Case where sector does not span zero
|
||||
if (bearing_sector_end >= bearing_sector_start && bearing_now >= bearing_sector_start && bearing_now <= bearing_sector_end) in_sector = true;
|
||||
if (bearing_sector_end >= bearing_sector_start && bearing_now >= bearing_sector_start && bearing_now <= bearing_sector_end) { in_sector = true; }
|
||||
|
||||
// Case where sector does span zero
|
||||
if (bearing_sector_end < bearing_sector_start && (bearing_now > bearing_sector_start || bearing_now < bearing_sector_end)) in_sector = true;
|
||||
if (bearing_sector_end < bearing_sector_start && (bearing_now > bearing_sector_start || bearing_now < bearing_sector_end)) { in_sector = true; }
|
||||
|
||||
// If in the sector then calculate distance and bearing to closest point
|
||||
if (in_sector) {
|
||||
@@ -394,8 +326,8 @@ __EXPORT int get_distance_to_arc(struct crosstrack_error_s * crosstrack_error, d
|
||||
}
|
||||
|
||||
__EXPORT float get_distance_to_point_global_wgs84(double lat_now, double lon_now, float alt_now,
|
||||
double lat_next, double lon_next, float alt_next,
|
||||
float *dist_xy, float *dist_z)
|
||||
double lat_next, double lon_next, float alt_next,
|
||||
float *dist_xy, float *dist_z)
|
||||
{
|
||||
double current_x_rad = lat_next / 180.0 * M_PI;
|
||||
double current_y_rad = lon_next / 180.0 * M_PI;
|
||||
@@ -419,8 +351,8 @@ __EXPORT float get_distance_to_point_global_wgs84(double lat_now, double lon_now
|
||||
|
||||
|
||||
__EXPORT float mavlink_wpm_distance_to_point_local(float x_now, float y_now, float z_now,
|
||||
float x_next, float y_next, float z_next,
|
||||
float *dist_xy, float *dist_z)
|
||||
float x_next, float y_next, float z_next,
|
||||
float *dist_xy, float *dist_z)
|
||||
{
|
||||
float dx = x_now - x_next;
|
||||
float dy = y_now - y_next;
|
||||
@@ -442,15 +374,19 @@ __EXPORT float _wrap_pi(float bearing)
|
||||
int c = 0;
|
||||
while (bearing >= M_PI_F) {
|
||||
bearing -= M_TWOPI_F;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (bearing < -M_PI_F) {
|
||||
bearing += M_TWOPI_F;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return bearing;
|
||||
@@ -466,15 +402,19 @@ __EXPORT float _wrap_2pi(float bearing)
|
||||
int c = 0;
|
||||
while (bearing >= M_TWOPI_F) {
|
||||
bearing -= M_TWOPI_F;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (bearing < 0.0f) {
|
||||
bearing += M_TWOPI_F;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return bearing;
|
||||
@@ -490,15 +430,19 @@ __EXPORT float _wrap_180(float bearing)
|
||||
int c = 0;
|
||||
while (bearing >= 180.0f) {
|
||||
bearing -= 360.0f;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (bearing < -180.0f) {
|
||||
bearing += 360.0f;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return bearing;
|
||||
@@ -514,15 +458,19 @@ __EXPORT float _wrap_360(float bearing)
|
||||
int c = 0;
|
||||
while (bearing >= 360.0f) {
|
||||
bearing -= 360.0f;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
c = 0;
|
||||
while (bearing < 0.0f) {
|
||||
bearing += 360.0f;
|
||||
if (c++ > 3)
|
||||
|
||||
if (c++ > 3) {
|
||||
return NAN;
|
||||
}
|
||||
}
|
||||
|
||||
return bearing;
|
||||
|
||||
+22
-16
@@ -1,9 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
||||
* Author: Thomas Gubler <thomasgubler@student.ethz.ch>
|
||||
* Julian Oes <joes@student.ethz.ch>
|
||||
* Lorenz Meier <lm@inf.ethz.ch>
|
||||
* Copyright (C) 2012, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -42,6 +39,7 @@
|
||||
* @author Thomas Gubler <thomasgubler@student.ethz.ch>
|
||||
* @author Julian Oes <joes@student.ethz.ch>
|
||||
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||
* Additional functions - @author Doug Weibel <douglas.weibel@colorado.edu>
|
||||
*/
|
||||
|
||||
@@ -67,6 +65,14 @@ struct crosstrack_error_s {
|
||||
float bearing; // Bearing in radians to closest point on line/arc
|
||||
} ;
|
||||
|
||||
/* lat/lon are in radians */
|
||||
struct map_projection_reference_s {
|
||||
double lat;
|
||||
double lon;
|
||||
double sin_lat;
|
||||
double cos_lat;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the map transformation.
|
||||
*
|
||||
@@ -74,7 +80,7 @@ struct crosstrack_error_s {
|
||||
* @param lat in degrees (47.1234567°, not 471234567°)
|
||||
* @param lon in degrees (8.1234567°, not 81234567°)
|
||||
*/
|
||||
__EXPORT void map_projection_init(double lat_0, double lon_0);
|
||||
__EXPORT void map_projection_init(struct map_projection_reference_s *ref, double lat_0, double lon_0);
|
||||
|
||||
/**
|
||||
* Transforms a point in the geographic coordinate system to the local azimuthal equidistant plane
|
||||
@@ -83,7 +89,7 @@ __EXPORT void map_projection_init(double lat_0, double lon_0);
|
||||
* @param lat in degrees (47.1234567°, not 471234567°)
|
||||
* @param lon in degrees (8.1234567°, not 81234567°)
|
||||
*/
|
||||
__EXPORT void map_projection_project(double lat, double lon, float *x, float *y);
|
||||
__EXPORT void map_projection_project(struct map_projection_reference_s *ref, double lat, double lon, float *x, float *y);
|
||||
|
||||
/**
|
||||
* Transforms a point in the local azimuthal equidistant plane to the geographic coordinate system
|
||||
@@ -93,7 +99,7 @@ __EXPORT void map_projection_project(double lat, double lon, float *x, float *y)
|
||||
* @param lat in degrees (47.1234567°, not 471234567°)
|
||||
* @param lon in degrees (8.1234567°, not 81234567°)
|
||||
*/
|
||||
__EXPORT void map_projection_reproject(float x, float y, double *lat, double *lon);
|
||||
__EXPORT void map_projection_reproject(struct map_projection_reference_s *ref, float x, float y, double *lat, double *lon);
|
||||
|
||||
/**
|
||||
* Returns the distance to the next waypoint in meters.
|
||||
@@ -115,30 +121,30 @@ __EXPORT float get_distance_to_next_waypoint(double lat_now, double lon_now, dou
|
||||
*/
|
||||
__EXPORT float get_bearing_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next);
|
||||
|
||||
__EXPORT void get_vector_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next, float* v_n, float* v_e);
|
||||
__EXPORT void get_vector_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next, float *v_n, float *v_e);
|
||||
|
||||
__EXPORT void get_vector_to_next_waypoint_fast(double lat_now, double lon_now, double lat_next, double lon_next, float* v_n, float* v_e);
|
||||
__EXPORT void get_vector_to_next_waypoint_fast(double lat_now, double lon_now, double lat_next, double lon_next, float *v_n, float *v_e);
|
||||
|
||||
__EXPORT void add_vector_to_global_position(double lat_now, double lon_now, float v_n, float v_e, double *lat_res, double *lon_res);
|
||||
|
||||
__EXPORT int get_distance_to_line(struct crosstrack_error_s * crosstrack_error, double lat_now, double lon_now, double lat_start, double lon_start, double lat_end, double lon_end);
|
||||
__EXPORT int get_distance_to_line(struct crosstrack_error_s *crosstrack_error, double lat_now, double lon_now, double lat_start, double lon_start, double lat_end, double lon_end);
|
||||
|
||||
__EXPORT int get_distance_to_arc(struct crosstrack_error_s * crosstrack_error, double lat_now, double lon_now, double lat_center, double lon_center,
|
||||
float radius, float arc_start_bearing, float arc_sweep);
|
||||
__EXPORT int get_distance_to_arc(struct crosstrack_error_s *crosstrack_error, double lat_now, double lon_now, double lat_center, double lon_center,
|
||||
float radius, float arc_start_bearing, float arc_sweep);
|
||||
|
||||
/*
|
||||
* Calculate distance in global frame
|
||||
*/
|
||||
__EXPORT float get_distance_to_point_global_wgs84(double lat_now, double lon_now, float alt_now,
|
||||
double lat_next, double lon_next, float alt_next,
|
||||
float *dist_xy, float *dist_z);
|
||||
double lat_next, double lon_next, float alt_next,
|
||||
float *dist_xy, float *dist_z);
|
||||
|
||||
/*
|
||||
* Calculate distance in local frame (NED)
|
||||
*/
|
||||
__EXPORT float mavlink_wpm_distance_to_point_local(float x_now, float y_now, float z_now,
|
||||
float x_next, float y_next, float z_next,
|
||||
float *dist_xy, float *dist_z);
|
||||
float x_next, float y_next, float z_next,
|
||||
float *dist_xy, float *dist_z);
|
||||
|
||||
__EXPORT float _wrap_180(float bearing);
|
||||
__EXPORT float _wrap_360(float bearing);
|
||||
|
||||
@@ -1,815 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file KalmanNav.cpp
|
||||
*
|
||||
* Kalman filter navigation code
|
||||
*/
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
#include "KalmanNav.hpp"
|
||||
#include <systemlib/err.h>
|
||||
#include <geo/geo.h>
|
||||
|
||||
// constants
|
||||
// Titterton pg. 52
|
||||
static const float omega = 7.2921150e-5f; // earth rotation rate, rad/s
|
||||
static const float R0 = 6378137.0f; // earth radius, m
|
||||
static const float g0 = 9.806f; // standard gravitational accel. m/s^2
|
||||
static const int8_t ret_ok = 0; // no error in function
|
||||
static const int8_t ret_error = -1; // error occurred
|
||||
|
||||
KalmanNav::KalmanNav(SuperBlock *parent, const char *name) :
|
||||
SuperBlock(parent, name),
|
||||
// subscriptions
|
||||
_sensors(&getSubscriptions(), ORB_ID(sensor_combined), 5), // limit to 200 Hz
|
||||
_gps(&getSubscriptions(), ORB_ID(vehicle_gps_position), 100), // limit to 10 Hz
|
||||
_param_update(&getSubscriptions(), ORB_ID(parameter_update), 1000), // limit to 1 Hz
|
||||
// publications
|
||||
_pos(&getPublications(), ORB_ID(vehicle_global_position)),
|
||||
_localPos(&getPublications(), ORB_ID(vehicle_local_position)),
|
||||
_att(&getPublications(), ORB_ID(vehicle_attitude)),
|
||||
// timestamps
|
||||
_pubTimeStamp(hrt_absolute_time()),
|
||||
_predictTimeStamp(hrt_absolute_time()),
|
||||
_attTimeStamp(hrt_absolute_time()),
|
||||
_outTimeStamp(hrt_absolute_time()),
|
||||
// frame count
|
||||
_navFrames(0),
|
||||
// miss counts
|
||||
_miss(0),
|
||||
// accelerations
|
||||
fN(0), fE(0), fD(0),
|
||||
// state
|
||||
phi(0), theta(0), psi(0),
|
||||
vN(0), vE(0), vD(0),
|
||||
lat(0), lon(0), alt(0),
|
||||
lat0(0), lon0(0), alt0(0),
|
||||
// parameters for ground station
|
||||
_vGyro(this, "V_GYRO"),
|
||||
_vAccel(this, "V_ACCEL"),
|
||||
_rMag(this, "R_MAG"),
|
||||
_rGpsVel(this, "R_GPS_VEL"),
|
||||
_rGpsPos(this, "R_GPS_POS"),
|
||||
_rGpsAlt(this, "R_GPS_ALT"),
|
||||
_rPressAlt(this, "R_PRESS_ALT"),
|
||||
_rAccel(this, "R_ACCEL"),
|
||||
_magDip(this, "ENV_MAG_DIP"),
|
||||
_magDec(this, "ENV_MAG_DEC"),
|
||||
_g(this, "ENV_G"),
|
||||
_faultPos(this, "FAULT_POS"),
|
||||
_faultAtt(this, "FAULT_ATT"),
|
||||
_attitudeInitialized(false),
|
||||
_positionInitialized(false),
|
||||
_attitudeInitCounter(0)
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
F.zero();
|
||||
G.zero();
|
||||
V.zero();
|
||||
HAtt.zero();
|
||||
RAtt.zero();
|
||||
HPos.zero();
|
||||
RPos.zero();
|
||||
|
||||
// initial state covariance matrix
|
||||
P0.identity();
|
||||
P0 *= 0.01f;
|
||||
P = P0;
|
||||
|
||||
// initial state
|
||||
phi = 0.0f;
|
||||
theta = 0.0f;
|
||||
psi = 0.0f;
|
||||
vN = 0.0f;
|
||||
vE = 0.0f;
|
||||
vD = 0.0f;
|
||||
lat = 0.0f;
|
||||
lon = 0.0f;
|
||||
alt = 0.0f;
|
||||
|
||||
// initialize rotation quaternion with a single raw sensor measurement
|
||||
_sensors.update();
|
||||
q = init(
|
||||
_sensors.accelerometer_m_s2[0],
|
||||
_sensors.accelerometer_m_s2[1],
|
||||
_sensors.accelerometer_m_s2[2],
|
||||
_sensors.magnetometer_ga[0],
|
||||
_sensors.magnetometer_ga[1],
|
||||
_sensors.magnetometer_ga[2]);
|
||||
|
||||
// initialize dcm
|
||||
C_nb = q.to_dcm();
|
||||
|
||||
// HPos is constant
|
||||
HPos(0, 3) = 1.0f;
|
||||
HPos(1, 4) = 1.0f;
|
||||
HPos(2, 6) = 1.0e7f * M_RAD_TO_DEG_F;
|
||||
HPos(3, 7) = 1.0e7f * M_RAD_TO_DEG_F;
|
||||
HPos(4, 8) = 1.0f;
|
||||
HPos(5, 8) = 1.0f;
|
||||
|
||||
// initialize all parameters
|
||||
updateParams();
|
||||
}
|
||||
|
||||
math::Quaternion KalmanNav::init(float ax, float ay, float az, float mx, float my, float mz)
|
||||
{
|
||||
float initialRoll, initialPitch;
|
||||
float cosRoll, sinRoll, cosPitch, sinPitch;
|
||||
float magX, magY;
|
||||
float initialHdg, cosHeading, sinHeading;
|
||||
|
||||
initialRoll = atan2(-ay, -az);
|
||||
initialPitch = atan2(ax, -az);
|
||||
|
||||
cosRoll = cosf(initialRoll);
|
||||
sinRoll = sinf(initialRoll);
|
||||
cosPitch = cosf(initialPitch);
|
||||
sinPitch = sinf(initialPitch);
|
||||
|
||||
magX = mx * cosPitch + my * sinRoll * sinPitch + mz * cosRoll * sinPitch;
|
||||
|
||||
magY = my * cosRoll - mz * sinRoll;
|
||||
|
||||
initialHdg = atan2f(-magY, magX);
|
||||
|
||||
cosRoll = cosf(initialRoll * 0.5f);
|
||||
sinRoll = sinf(initialRoll * 0.5f);
|
||||
|
||||
cosPitch = cosf(initialPitch * 0.5f);
|
||||
sinPitch = sinf(initialPitch * 0.5f);
|
||||
|
||||
cosHeading = cosf(initialHdg * 0.5f);
|
||||
sinHeading = sinf(initialHdg * 0.5f);
|
||||
|
||||
float q0 = cosRoll * cosPitch * cosHeading + sinRoll * sinPitch * sinHeading;
|
||||
float q1 = sinRoll * cosPitch * cosHeading - cosRoll * sinPitch * sinHeading;
|
||||
float q2 = cosRoll * sinPitch * cosHeading + sinRoll * cosPitch * sinHeading;
|
||||
float q3 = cosRoll * cosPitch * sinHeading - sinRoll * sinPitch * cosHeading;
|
||||
|
||||
return math::Quaternion(q0, q1, q2, q3);
|
||||
|
||||
}
|
||||
|
||||
void KalmanNav::update()
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
struct pollfd fds[1];
|
||||
fds[0].fd = _sensors.getHandle();
|
||||
fds[0].events = POLLIN;
|
||||
|
||||
// poll for new data
|
||||
int ret = poll(fds, 1, 1000);
|
||||
|
||||
if (ret < 0) {
|
||||
// XXX this is seriously bad - should be an emergency
|
||||
return;
|
||||
|
||||
} else if (ret == 0) { // timeout
|
||||
return;
|
||||
}
|
||||
|
||||
// get new timestamp
|
||||
uint64_t newTimeStamp = hrt_absolute_time();
|
||||
|
||||
// check updated subscriptions
|
||||
if (_param_update.updated()) updateParams();
|
||||
|
||||
bool gpsUpdate = _gps.updated();
|
||||
bool sensorsUpdate = _sensors.updated();
|
||||
|
||||
// get new information from subscriptions
|
||||
// this clears update flag
|
||||
updateSubscriptions();
|
||||
|
||||
// initialize attitude when sensors online
|
||||
if (!_attitudeInitialized && sensorsUpdate) {
|
||||
if (correctAtt() == ret_ok) _attitudeInitCounter++;
|
||||
|
||||
if (_attitudeInitCounter > 100) {
|
||||
warnx("initialized EKF attitude");
|
||||
warnx("phi: %8.4f, theta: %8.4f, psi: %8.4f",
|
||||
double(phi), double(theta), double(psi));
|
||||
_attitudeInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize position when gps received
|
||||
if (!_positionInitialized &&
|
||||
_attitudeInitialized && // wait for attitude first
|
||||
gpsUpdate &&
|
||||
_gps.fix_type > 2
|
||||
//&& _gps.counter_pos_valid > 10
|
||||
) {
|
||||
vN = _gps.vel_n_m_s;
|
||||
vE = _gps.vel_e_m_s;
|
||||
vD = _gps.vel_d_m_s;
|
||||
setLatDegE7(_gps.lat);
|
||||
setLonDegE7(_gps.lon);
|
||||
setAltE3(_gps.alt);
|
||||
// set reference position for
|
||||
// local position
|
||||
lat0 = lat;
|
||||
lon0 = lon;
|
||||
alt0 = alt;
|
||||
// XXX map_projection has internal global
|
||||
// states that multiple things could change,
|
||||
// should make map_projection take reference
|
||||
// lat/lon and not have init
|
||||
map_projection_init(lat0, lon0);
|
||||
_positionInitialized = true;
|
||||
warnx("initialized EKF state with GPS");
|
||||
warnx("vN: %8.4f, vE: %8.4f, vD: %8.4f, lat: %8.4f, lon: %8.4f, alt: %8.4f",
|
||||
double(vN), double(vE), double(vD),
|
||||
lat, lon, double(alt));
|
||||
}
|
||||
|
||||
// prediction step
|
||||
// using sensors timestamp so we can account for packet lag
|
||||
float dt = (_sensors.timestamp - _predictTimeStamp) / 1.0e6f;
|
||||
//printf("dt: %15.10f\n", double(dt));
|
||||
_predictTimeStamp = _sensors.timestamp;
|
||||
|
||||
// don't predict if time greater than a second
|
||||
if (dt < 1.0f) {
|
||||
predictState(dt);
|
||||
predictStateCovariance(dt);
|
||||
// count fast frames
|
||||
_navFrames += 1;
|
||||
}
|
||||
|
||||
// count times 100 Hz rate isn't met
|
||||
if (dt > 0.01f) _miss++;
|
||||
|
||||
// gps correction step
|
||||
if (_positionInitialized && gpsUpdate) {
|
||||
correctPos();
|
||||
}
|
||||
|
||||
// attitude correction step
|
||||
if (_attitudeInitialized // initialized
|
||||
&& sensorsUpdate // new data
|
||||
&& _sensors.timestamp - _attTimeStamp > 1e6 / 50 // 50 Hz
|
||||
) {
|
||||
_attTimeStamp = _sensors.timestamp;
|
||||
correctAtt();
|
||||
}
|
||||
|
||||
// publication
|
||||
if (newTimeStamp - _pubTimeStamp > 1e6 / 50) { // 50 Hz
|
||||
_pubTimeStamp = newTimeStamp;
|
||||
|
||||
updatePublications();
|
||||
}
|
||||
|
||||
// output
|
||||
if (newTimeStamp - _outTimeStamp > 10e6) { // 0.1 Hz
|
||||
_outTimeStamp = newTimeStamp;
|
||||
//printf("nav: %4d Hz, miss #: %4d\n",
|
||||
// _navFrames / 10, _miss / 10);
|
||||
_navFrames = 0;
|
||||
_miss = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void KalmanNav::updatePublications()
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
// global position publication
|
||||
_pos.timestamp = _pubTimeStamp;
|
||||
_pos.time_gps_usec = _gps.timestamp_position;
|
||||
_pos.global_valid = true;
|
||||
_pos.lat = lat * M_RAD_TO_DEG;
|
||||
_pos.lon = lon * M_RAD_TO_DEG;
|
||||
_pos.alt = float(alt);
|
||||
_pos.vel_n = vN;
|
||||
_pos.vel_e = vE;
|
||||
_pos.vel_d = vD;
|
||||
_pos.yaw = psi;
|
||||
|
||||
// local position publication
|
||||
float x;
|
||||
float y;
|
||||
bool landed = alt < (alt0 + 0.1); // XXX improve?
|
||||
map_projection_project(lat, lon, &x, &y);
|
||||
_localPos.timestamp = _pubTimeStamp;
|
||||
_localPos.xy_valid = true;
|
||||
_localPos.z_valid = true;
|
||||
_localPos.v_xy_valid = true;
|
||||
_localPos.v_z_valid = true;
|
||||
_localPos.x = x;
|
||||
_localPos.y = y;
|
||||
_localPos.z = alt0 - alt;
|
||||
_localPos.vx = vN;
|
||||
_localPos.vy = vE;
|
||||
_localPos.vz = vD;
|
||||
_localPos.yaw = psi;
|
||||
_localPos.xy_global = true;
|
||||
_localPos.z_global = true;
|
||||
_localPos.ref_timestamp = _pubTimeStamp;
|
||||
_localPos.ref_lat = getLatDegE7();
|
||||
_localPos.ref_lon = getLonDegE7();
|
||||
_localPos.ref_alt = 0;
|
||||
_localPos.landed = landed;
|
||||
|
||||
// attitude publication
|
||||
_att.timestamp = _pubTimeStamp;
|
||||
_att.roll = phi;
|
||||
_att.pitch = theta;
|
||||
_att.yaw = psi;
|
||||
_att.rollspeed = _sensors.gyro_rad_s[0];
|
||||
_att.pitchspeed = _sensors.gyro_rad_s[1];
|
||||
_att.yawspeed = _sensors.gyro_rad_s[2];
|
||||
// TODO, add gyro offsets to filter
|
||||
_att.rate_offsets[0] = 0.0f;
|
||||
_att.rate_offsets[1] = 0.0f;
|
||||
_att.rate_offsets[2] = 0.0f;
|
||||
|
||||
for (int i = 0; i < 3; i++) for (int j = 0; j < 3; j++)
|
||||
_att.R[i][j] = C_nb(i, j);
|
||||
|
||||
for (int i = 0; i < 4; i++) _att.q[i] = q(i);
|
||||
|
||||
_att.R_valid = true;
|
||||
_att.q_valid = true;
|
||||
|
||||
// selectively update publications,
|
||||
// do NOT call superblock do-all method
|
||||
if (_positionInitialized) {
|
||||
_pos.update();
|
||||
_localPos.update();
|
||||
}
|
||||
|
||||
if (_attitudeInitialized)
|
||||
_att.update();
|
||||
}
|
||||
|
||||
int KalmanNav::predictState(float dt)
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
// trig
|
||||
float sinL = sinf(lat);
|
||||
float cosL = cosf(lat);
|
||||
float cosLSing = cosf(lat);
|
||||
|
||||
// prevent singularity
|
||||
if (fabsf(cosLSing) < 0.01f) {
|
||||
if (cosLSing > 0) cosLSing = 0.01;
|
||||
else cosLSing = -0.01;
|
||||
}
|
||||
|
||||
// attitude prediction
|
||||
if (_attitudeInitialized) {
|
||||
Vector<3> w(_sensors.gyro_rad_s);
|
||||
|
||||
// attitude
|
||||
q = q + q.derivative(w) * dt;
|
||||
|
||||
// renormalize quaternion if needed
|
||||
if (fabsf(q.length() - 1.0f) > 1e-4f) {
|
||||
q.normalize();
|
||||
}
|
||||
|
||||
// C_nb update
|
||||
C_nb = q.to_dcm();
|
||||
|
||||
// euler update
|
||||
Vector<3> euler = C_nb.to_euler();
|
||||
phi = euler.data[0];
|
||||
theta = euler.data[1];
|
||||
psi = euler.data[2];
|
||||
|
||||
// specific acceleration in nav frame
|
||||
Vector<3> accelB(_sensors.accelerometer_m_s2);
|
||||
Vector<3> accelN = C_nb * accelB;
|
||||
fN = accelN(0);
|
||||
fE = accelN(1);
|
||||
fD = accelN(2);
|
||||
}
|
||||
|
||||
// position prediction
|
||||
if (_positionInitialized) {
|
||||
// neglects angular deflections in local gravity
|
||||
// see Titerton pg. 70
|
||||
float R = R0 + float(alt);
|
||||
float LDot = vN / R;
|
||||
float lDot = vE / (cosLSing * R);
|
||||
float rotRate = 2 * omega + lDot;
|
||||
|
||||
// XXX position prediction using speed
|
||||
float vNDot = fN - vE * rotRate * sinL +
|
||||
vD * LDot;
|
||||
float vDDot = fD - vE * rotRate * cosL -
|
||||
vN * LDot + _g.get();
|
||||
float vEDot = fE + vN * rotRate * sinL +
|
||||
vDDot * rotRate * cosL;
|
||||
|
||||
// rectangular integration
|
||||
vN += vNDot * dt;
|
||||
vE += vEDot * dt;
|
||||
vD += vDDot * dt;
|
||||
lat += double(LDot * dt);
|
||||
lon += double(lDot * dt);
|
||||
alt += double(-vD * dt);
|
||||
}
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
int KalmanNav::predictStateCovariance(float dt)
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
// trig
|
||||
float sinL = sinf(lat);
|
||||
float cosL = cosf(lat);
|
||||
float cosLSq = cosL * cosL;
|
||||
float tanL = tanf(lat);
|
||||
|
||||
// prepare for matrix
|
||||
float R = R0 + float(alt);
|
||||
float RSq = R * R;
|
||||
|
||||
// F Matrix
|
||||
// Titterton pg. 291
|
||||
|
||||
F(0, 1) = -(omega * sinL + vE * tanL / R);
|
||||
F(0, 2) = vN / R;
|
||||
F(0, 4) = 1.0f / R;
|
||||
F(0, 6) = -omega * sinL;
|
||||
F(0, 8) = -vE / RSq;
|
||||
|
||||
F(1, 0) = omega * sinL + vE * tanL / R;
|
||||
F(1, 2) = omega * cosL + vE / R;
|
||||
F(1, 3) = -1.0f / R;
|
||||
F(1, 8) = vN / RSq;
|
||||
|
||||
F(2, 0) = -vN / R;
|
||||
F(2, 1) = -omega * cosL - vE / R;
|
||||
F(2, 4) = -tanL / R;
|
||||
F(2, 6) = -omega * cosL - vE / (R * cosLSq);
|
||||
F(2, 8) = vE * tanL / RSq;
|
||||
|
||||
F(3, 1) = -fD;
|
||||
F(3, 2) = fE;
|
||||
F(3, 3) = vD / R;
|
||||
F(3, 4) = -2 * (omega * sinL + vE * tanL / R);
|
||||
F(3, 5) = vN / R;
|
||||
F(3, 6) = -vE * (2 * omega * cosL + vE / (R * cosLSq));
|
||||
F(3, 8) = (vE * vE * tanL - vN * vD) / RSq;
|
||||
|
||||
F(4, 0) = fD;
|
||||
F(4, 2) = -fN;
|
||||
F(4, 3) = 2 * omega * sinL + vE * tanL / R;
|
||||
F(4, 4) = (vN * tanL + vD) / R;
|
||||
F(4, 5) = 2 * omega * cosL + vE / R;
|
||||
F(4, 6) = 2 * omega * (vN * cosL - vD * sinL) +
|
||||
vN * vE / (R * cosLSq);
|
||||
F(4, 8) = -vE * (vN * tanL + vD) / RSq;
|
||||
|
||||
F(5, 0) = -fE;
|
||||
F(5, 1) = fN;
|
||||
F(5, 3) = -2 * vN / R;
|
||||
F(5, 4) = -2 * (omega * cosL + vE / R);
|
||||
F(5, 6) = 2 * omega * vE * sinL;
|
||||
F(5, 8) = (vN * vN + vE * vE) / RSq;
|
||||
|
||||
F(6, 3) = 1 / R;
|
||||
F(6, 8) = -vN / RSq;
|
||||
|
||||
F(7, 4) = 1 / (R * cosL);
|
||||
F(7, 6) = vE * tanL / (R * cosL);
|
||||
F(7, 8) = -vE / (cosL * RSq);
|
||||
|
||||
F(8, 5) = -1;
|
||||
|
||||
// G Matrix
|
||||
// Titterton pg. 291
|
||||
G(0, 0) = -C_nb(0, 0);
|
||||
G(0, 1) = -C_nb(0, 1);
|
||||
G(0, 2) = -C_nb(0, 2);
|
||||
G(1, 0) = -C_nb(1, 0);
|
||||
G(1, 1) = -C_nb(1, 1);
|
||||
G(1, 2) = -C_nb(1, 2);
|
||||
G(2, 0) = -C_nb(2, 0);
|
||||
G(2, 1) = -C_nb(2, 1);
|
||||
G(2, 2) = -C_nb(2, 2);
|
||||
|
||||
G(3, 3) = C_nb(0, 0);
|
||||
G(3, 4) = C_nb(0, 1);
|
||||
G(3, 5) = C_nb(0, 2);
|
||||
G(4, 3) = C_nb(1, 0);
|
||||
G(4, 4) = C_nb(1, 1);
|
||||
G(4, 5) = C_nb(1, 2);
|
||||
G(5, 3) = C_nb(2, 0);
|
||||
G(5, 4) = C_nb(2, 1);
|
||||
G(5, 5) = C_nb(2, 2);
|
||||
|
||||
// continuous prediction equations
|
||||
// for discrete time EKF
|
||||
// http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
P = P + (F * P + P * F.transposed() + G * V * G.transposed()) * dt;
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
int KalmanNav::correctAtt()
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
// trig
|
||||
float cosPhi = cosf(phi);
|
||||
float cosTheta = cosf(theta);
|
||||
// float cosPsi = cosf(psi);
|
||||
float sinPhi = sinf(phi);
|
||||
float sinTheta = sinf(theta);
|
||||
// float sinPsi = sinf(psi);
|
||||
|
||||
// mag predicted measurement
|
||||
// choosing some typical magnetic field properties,
|
||||
// TODO dip/dec depend on lat/ lon/ time
|
||||
//float dip = _magDip.get() / M_RAD_TO_DEG_F; // dip, inclination with level
|
||||
float dec = _magDec.get() / M_RAD_TO_DEG_F; // declination, clockwise rotation from north
|
||||
|
||||
// compensate roll and pitch, but not yaw
|
||||
// XXX take the vectors out of the C_nb matrix to avoid singularities
|
||||
math::Matrix<3,3> C_rp;
|
||||
C_rp.from_euler(phi, theta, 0.0f);//C_nb.transposed();
|
||||
|
||||
// mag measurement
|
||||
Vector<3> magBody(_sensors.magnetometer_ga);
|
||||
|
||||
// transform to earth frame
|
||||
Vector<3> magNav = C_rp * magBody;
|
||||
|
||||
// calculate error between estimate and measurement
|
||||
// apply declination correction for true heading as well.
|
||||
float yMag = -atan2f(magNav(1),magNav(0)) - psi - dec;
|
||||
if (yMag > M_PI_F) yMag -= 2*M_PI_F;
|
||||
if (yMag < -M_PI_F) yMag += 2*M_PI_F;
|
||||
|
||||
// accel measurement
|
||||
Vector<3> zAccel(_sensors.accelerometer_m_s2);
|
||||
float accelMag = zAccel.length();
|
||||
zAccel.normalize();
|
||||
|
||||
// ignore accel correction when accel mag not close to g
|
||||
Matrix<4,4> RAttAdjust = RAtt;
|
||||
|
||||
bool ignoreAccel = fabsf(accelMag - _g.get()) > 1.1f;
|
||||
|
||||
if (ignoreAccel) {
|
||||
RAttAdjust(1, 1) = 1.0e10;
|
||||
RAttAdjust(2, 2) = 1.0e10;
|
||||
RAttAdjust(3, 3) = 1.0e10;
|
||||
|
||||
} else {
|
||||
//printf("correcting attitude with accel\n");
|
||||
}
|
||||
|
||||
// accel predicted measurement
|
||||
Vector<3> zAccelHat = (C_nb.transposed() * Vector<3>(0, 0, -_g.get())).normalized();
|
||||
|
||||
// calculate residual
|
||||
Vector<4> y(yMag, zAccel(0) - zAccelHat(0), zAccel(1) - zAccelHat(1), zAccel(2) - zAccelHat(2));
|
||||
|
||||
// HMag
|
||||
HAtt(0, 2) = 1;
|
||||
|
||||
// HAccel
|
||||
HAtt(1, 1) = cosTheta;
|
||||
HAtt(2, 0) = -cosPhi * cosTheta;
|
||||
HAtt(2, 1) = sinPhi * sinTheta;
|
||||
HAtt(3, 0) = sinPhi * cosTheta;
|
||||
HAtt(3, 1) = cosPhi * sinTheta;
|
||||
|
||||
// compute correction
|
||||
// http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
Matrix<4, 4> S = HAtt * P * HAtt.transposed() + RAttAdjust; // residual covariance
|
||||
Matrix<9, 4> K = P * HAtt.transposed() * S.inversed();
|
||||
Vector<9> xCorrect = K * y;
|
||||
|
||||
// check correciton is sane
|
||||
for (size_t i = 0; i < xCorrect.get_size(); i++) {
|
||||
float val = xCorrect(i);
|
||||
|
||||
if (isnan(val) || isinf(val)) {
|
||||
// abort correction and return
|
||||
warnx("numerical failure in att correction");
|
||||
// reset P matrix to P0
|
||||
P = P0;
|
||||
return ret_error;
|
||||
}
|
||||
}
|
||||
|
||||
// correct state
|
||||
if (!ignoreAccel) {
|
||||
phi += xCorrect(PHI);
|
||||
theta += xCorrect(THETA);
|
||||
}
|
||||
|
||||
psi += xCorrect(PSI);
|
||||
|
||||
// attitude also affects nav velocities
|
||||
if (_positionInitialized) {
|
||||
vN += xCorrect(VN);
|
||||
vE += xCorrect(VE);
|
||||
vD += xCorrect(VD);
|
||||
}
|
||||
|
||||
// update state covariance
|
||||
// http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
P = P - K * HAtt * P;
|
||||
|
||||
// fault detection
|
||||
float beta = y * (S.inversed() * y);
|
||||
|
||||
if (beta > _faultAtt.get()) {
|
||||
warnx("fault in attitude: beta = %8.4f", (double)beta);
|
||||
warnx("y:"); y.print();
|
||||
}
|
||||
|
||||
// update quaternions from euler
|
||||
// angle correction
|
||||
q.from_euler(phi, theta, psi);
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
int KalmanNav::correctPos()
|
||||
{
|
||||
using namespace math;
|
||||
|
||||
// residual
|
||||
Vector<6> y;
|
||||
y(0) = _gps.vel_n_m_s - vN;
|
||||
y(1) = _gps.vel_e_m_s - vE;
|
||||
y(2) = double(_gps.lat) - double(lat) * 1.0e7 * M_RAD_TO_DEG;
|
||||
y(3) = double(_gps.lon) - double(lon) * 1.0e7 * M_RAD_TO_DEG;
|
||||
y(4) = _gps.alt / 1.0e3f - alt;
|
||||
y(5) = _sensors.baro_alt_meter - alt;
|
||||
|
||||
// compute correction
|
||||
// http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
Matrix<6,6> S = HPos * P * HPos.transposed() + RPos; // residual covariance
|
||||
Matrix<9,6> K = P * HPos.transposed() * S.inversed();
|
||||
Vector<9> xCorrect = K * y;
|
||||
|
||||
// check correction is sane
|
||||
for (size_t i = 0; i < xCorrect.get_size(); i++) {
|
||||
float val = xCorrect(i);
|
||||
|
||||
if (!isfinite(val)) {
|
||||
// abort correction and return
|
||||
warnx("numerical failure in gps correction");
|
||||
// fallback to GPS
|
||||
vN = _gps.vel_n_m_s;
|
||||
vE = _gps.vel_e_m_s;
|
||||
vD = _gps.vel_d_m_s;
|
||||
setLatDegE7(_gps.lat);
|
||||
setLonDegE7(_gps.lon);
|
||||
setAltE3(_gps.alt);
|
||||
// reset P matrix to P0
|
||||
P = P0;
|
||||
return ret_error;
|
||||
}
|
||||
}
|
||||
|
||||
// correct state
|
||||
vN += xCorrect(VN);
|
||||
vE += xCorrect(VE);
|
||||
vD += xCorrect(VD);
|
||||
lat += double(xCorrect(LAT));
|
||||
lon += double(xCorrect(LON));
|
||||
alt += xCorrect(ALT);
|
||||
|
||||
// update state covariance
|
||||
// http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
P = P - K * HPos * P;
|
||||
|
||||
// fault detetcion
|
||||
float beta = y * (S.inversed() * y);
|
||||
|
||||
static int counter = 0;
|
||||
if (beta > _faultPos.get() && (counter % 10 == 0)) {
|
||||
warnx("fault in gps: beta = %8.4f", (double)beta);
|
||||
warnx("Y/N: vN: %8.4f, vE: %8.4f, lat: %8.4f, lon: %8.4f, alt: %8.4f, baro: %8.4f",
|
||||
double(y(0) / sqrtf(RPos(0, 0))),
|
||||
double(y(1) / sqrtf(RPos(1, 1))),
|
||||
double(y(2) / sqrtf(RPos(2, 2))),
|
||||
double(y(3) / sqrtf(RPos(3, 3))),
|
||||
double(y(4) / sqrtf(RPos(4, 4))),
|
||||
double(y(5) / sqrtf(RPos(5, 5))));
|
||||
}
|
||||
counter++;
|
||||
|
||||
return ret_ok;
|
||||
}
|
||||
|
||||
void KalmanNav::updateParams()
|
||||
{
|
||||
using namespace math;
|
||||
using namespace control;
|
||||
SuperBlock::updateParams();
|
||||
|
||||
// gyro noise
|
||||
V(0, 0) = _vGyro.get(); // gyro x, rad/s
|
||||
V(1, 1) = _vGyro.get(); // gyro y
|
||||
V(2, 2) = _vGyro.get(); // gyro z
|
||||
|
||||
// accel noise
|
||||
V(3, 3) = _vAccel.get(); // accel x, m/s^2
|
||||
V(4, 4) = _vAccel.get(); // accel y
|
||||
V(5, 5) = _vAccel.get(); // accel z
|
||||
|
||||
// magnetometer noise
|
||||
float noiseMin = 1e-6f;
|
||||
float noiseMagSq = _rMag.get() * _rMag.get();
|
||||
|
||||
if (noiseMagSq < noiseMin) noiseMagSq = noiseMin;
|
||||
|
||||
RAtt(0, 0) = noiseMagSq; // normalized direction
|
||||
|
||||
// accelerometer noise
|
||||
float noiseAccelSq = _rAccel.get() * _rAccel.get();
|
||||
|
||||
// bound noise to prevent singularities
|
||||
if (noiseAccelSq < noiseMin) noiseAccelSq = noiseMin;
|
||||
|
||||
RAtt(1, 1) = noiseAccelSq; // normalized direction
|
||||
RAtt(2, 2) = noiseAccelSq;
|
||||
RAtt(3, 3) = noiseAccelSq;
|
||||
|
||||
// gps noise
|
||||
float R = R0 + float(alt);
|
||||
float cosLSing = cosf(lat);
|
||||
|
||||
// prevent singularity
|
||||
if (fabsf(cosLSing) < 0.01f) {
|
||||
if (cosLSing > 0) cosLSing = 0.01;
|
||||
else cosLSing = -0.01;
|
||||
}
|
||||
|
||||
float noiseVel = _rGpsVel.get();
|
||||
float noiseLatDegE7 = 1.0e7f * M_RAD_TO_DEG_F * _rGpsPos.get() / R;
|
||||
float noiseLonDegE7 = noiseLatDegE7 / cosLSing;
|
||||
float noiseGpsAlt = _rGpsAlt.get();
|
||||
float noisePressAlt = _rPressAlt.get();
|
||||
|
||||
// bound noise to prevent singularities
|
||||
if (noiseVel < noiseMin) noiseVel = noiseMin;
|
||||
|
||||
if (noiseLatDegE7 < noiseMin) noiseLatDegE7 = noiseMin;
|
||||
|
||||
if (noiseLonDegE7 < noiseMin) noiseLonDegE7 = noiseMin;
|
||||
|
||||
if (noiseGpsAlt < noiseMin) noiseGpsAlt = noiseMin;
|
||||
|
||||
if (noisePressAlt < noiseMin) noisePressAlt = noiseMin;
|
||||
|
||||
RPos(0, 0) = noiseVel * noiseVel; // vn
|
||||
RPos(1, 1) = noiseVel * noiseVel; // ve
|
||||
RPos(2, 2) = noiseLatDegE7 * noiseLatDegE7; // lat
|
||||
RPos(3, 3) = noiseLonDegE7 * noiseLonDegE7; // lon
|
||||
RPos(4, 4) = noiseGpsAlt * noiseGpsAlt; // h
|
||||
RPos(5, 5) = noisePressAlt * noisePressAlt; // h
|
||||
// XXX, note that RPos depends on lat, so updateParams should
|
||||
// be called if lat changes significantly
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file KalmanNav.hpp
|
||||
*
|
||||
* kalman filter navigation code
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
//#define MATRIX_ASSERT
|
||||
//#define VECTOR_ASSERT
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <mathlib/mathlib.h>
|
||||
#include <controllib/blocks.hpp>
|
||||
#include <controllib/block/BlockParam.hpp>
|
||||
#include <uORB/Subscription.hpp>
|
||||
#include <uORB/Publication.hpp>
|
||||
|
||||
#include <uORB/topics/vehicle_attitude.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
#include <uORB/topics/vehicle_local_position.h>
|
||||
#include <uORB/topics/sensor_combined.h>
|
||||
#include <uORB/topics/vehicle_gps_position.h>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
|
||||
#include <drivers/drv_accel.h>
|
||||
#include <drivers/drv_gyro.h>
|
||||
#include <drivers/drv_mag.h>
|
||||
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/**
|
||||
* Kalman filter navigation class
|
||||
* http://en.wikipedia.org/wiki/Extended_Kalman_filter
|
||||
* Discrete-time extended Kalman filter
|
||||
*/
|
||||
class KalmanNav : public control::SuperBlock
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
KalmanNav(SuperBlock *parent, const char *name);
|
||||
|
||||
/**
|
||||
* Deconstuctor
|
||||
*/
|
||||
|
||||
virtual ~KalmanNav() {};
|
||||
|
||||
math::Quaternion init(float ax, float ay, float az, float mx, float my, float mz);
|
||||
|
||||
/**
|
||||
* The main callback function for the class
|
||||
*/
|
||||
void update();
|
||||
|
||||
|
||||
/**
|
||||
* Publication update
|
||||
*/
|
||||
virtual void updatePublications();
|
||||
|
||||
/**
|
||||
* State prediction
|
||||
* Continuous, non-linear
|
||||
*/
|
||||
int predictState(float dt);
|
||||
|
||||
/**
|
||||
* State covariance prediction
|
||||
* Continuous, linear
|
||||
*/
|
||||
int predictStateCovariance(float dt);
|
||||
|
||||
/**
|
||||
* Attitude correction
|
||||
*/
|
||||
int correctAtt();
|
||||
|
||||
/**
|
||||
* Position correction
|
||||
*/
|
||||
int correctPos();
|
||||
|
||||
/**
|
||||
* Overloaded update parameters
|
||||
*/
|
||||
virtual void updateParams();
|
||||
protected:
|
||||
// kalman filter
|
||||
math::Matrix<9,9> F; /**< Jacobian(f,x), where dx/dt = f(x,u) */
|
||||
math::Matrix<9,6> G; /**< noise shaping matrix for gyro/accel */
|
||||
math::Matrix<9,9> P; /**< state covariance matrix */
|
||||
math::Matrix<9,9> P0; /**< initial state covariance matrix */
|
||||
math::Matrix<6,6> V; /**< gyro/ accel noise matrix */
|
||||
math::Matrix<4,9> HAtt; /**< attitude measurement matrix */
|
||||
math::Matrix<4,4> RAtt; /**< attitude measurement noise matrix */
|
||||
math::Matrix<6,9> HPos; /**< position measurement jacobian matrix */
|
||||
math::Matrix<6,6> RPos; /**< position measurement noise matrix */
|
||||
// attitude
|
||||
math::Matrix<3,3> C_nb; /**< direction cosine matrix from body to nav frame */
|
||||
math::Quaternion q; /**< quaternion from body to nav frame */
|
||||
// subscriptions
|
||||
uORB::Subscription<sensor_combined_s> _sensors; /**< sensors sub. */
|
||||
uORB::Subscription<vehicle_gps_position_s> _gps; /**< gps sub. */
|
||||
uORB::Subscription<parameter_update_s> _param_update; /**< parameter update sub. */
|
||||
// publications
|
||||
uORB::Publication<vehicle_global_position_s> _pos; /**< position pub. */
|
||||
uORB::Publication<vehicle_local_position_s> _localPos; /**< local position pub. */
|
||||
uORB::Publication<vehicle_attitude_s> _att; /**< attitude pub. */
|
||||
// time stamps
|
||||
uint64_t _pubTimeStamp; /**< output data publication time stamp */
|
||||
uint64_t _predictTimeStamp; /**< prediction time stamp */
|
||||
uint64_t _attTimeStamp; /**< attitude correction time stamp */
|
||||
uint64_t _outTimeStamp; /**< output time stamp */
|
||||
// frame count
|
||||
uint16_t _navFrames; /**< navigation frames completed in output cycle */
|
||||
// miss counts
|
||||
uint16_t _miss; /**< number of times fast prediction loop missed */
|
||||
// accelerations
|
||||
float fN, fE, fD; /**< navigation frame acceleration */
|
||||
// states
|
||||
enum {PHI = 0, THETA, PSI, VN, VE, VD, LAT, LON, ALT}; /**< state enumeration */
|
||||
float phi, theta, psi; /**< 3-2-1 euler angles */
|
||||
float vN, vE, vD; /**< navigation velocity, m/s */
|
||||
double lat, lon; /**< lat, lon radians */
|
||||
// parameters
|
||||
float alt; /**< altitude, meters */
|
||||
double lat0, lon0; /**< reference latitude and longitude */
|
||||
float alt0; /**< refeerence altitude (ground height) */
|
||||
control::BlockParamFloat _vGyro; /**< gyro process noise */
|
||||
control::BlockParamFloat _vAccel; /**< accelerometer process noise */
|
||||
control::BlockParamFloat _rMag; /**< magnetometer measurement noise */
|
||||
control::BlockParamFloat _rGpsVel; /**< gps velocity measurement noise */
|
||||
control::BlockParamFloat _rGpsPos; /**< gps position measurement noise */
|
||||
control::BlockParamFloat _rGpsAlt; /**< gps altitude measurement noise */
|
||||
control::BlockParamFloat _rPressAlt; /**< press altitude measurement noise */
|
||||
control::BlockParamFloat _rAccel; /**< accelerometer measurement noise */
|
||||
control::BlockParamFloat _magDip; /**< magnetic inclination with level */
|
||||
control::BlockParamFloat _magDec; /**< magnetic declination, clockwise rotation */
|
||||
control::BlockParamFloat _g; /**< gravitational constant */
|
||||
control::BlockParamFloat _faultPos; /**< fault detection threshold for position */
|
||||
control::BlockParamFloat _faultAtt; /**< fault detection threshold for attitude */
|
||||
// status
|
||||
bool _attitudeInitialized;
|
||||
bool _positionInitialized;
|
||||
uint16_t _attitudeInitCounter;
|
||||
// accessors
|
||||
int32_t getLatDegE7() { return int32_t(lat * 1.0e7 * M_RAD_TO_DEG); }
|
||||
void setLatDegE7(int32_t val) { lat = val / 1.0e7 / M_RAD_TO_DEG; }
|
||||
int32_t getLonDegE7() { return int32_t(lon * 1.0e7 * M_RAD_TO_DEG); }
|
||||
void setLonDegE7(int32_t val) { lon = val / 1.0e7 / M_RAD_TO_DEG; }
|
||||
int32_t getAltE3() { return int32_t(alt * 1.0e3); }
|
||||
void setAltE3(int32_t val) { alt = double(val) / 1.0e3; }
|
||||
};
|
||||
@@ -1,157 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||
* Author: James Goppert
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file kalman_main.cpp
|
||||
* Combined attitude / position estimator.
|
||||
*
|
||||
* @author James Goppert
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <systemlib/systemlib.h>
|
||||
#include <systemlib/param/param.h>
|
||||
#include <systemlib/err.h>
|
||||
#include <drivers/drv_hrt.h>
|
||||
#include <math.h>
|
||||
#include "KalmanNav.hpp"
|
||||
|
||||
static bool thread_should_exit = false; /**< Deamon exit flag */
|
||||
static bool thread_running = false; /**< Deamon status flag */
|
||||
static int daemon_task; /**< Handle of deamon task / thread */
|
||||
|
||||
/**
|
||||
* Deamon management function.
|
||||
*/
|
||||
extern "C" __EXPORT int att_pos_estimator_ekf_main(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Mainloop of deamon.
|
||||
*/
|
||||
int kalman_demo_thread_main(int argc, char *argv[]);
|
||||
|
||||
/**
|
||||
* Print the correct usage.
|
||||
*/
|
||||
static void usage(const char *reason);
|
||||
|
||||
static void
|
||||
usage(const char *reason)
|
||||
{
|
||||
if (reason)
|
||||
fprintf(stderr, "%s\n", reason);
|
||||
|
||||
warnx("usage: att_pos_estimator_ekf {start|stop|status} [-p <additional params>]");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The deamon app only briefly exists to start
|
||||
* the background job. The stack size assigned in the
|
||||
* Makefile does only apply to this management task.
|
||||
*
|
||||
* The actual stack size should be set in the call
|
||||
* to task_create().
|
||||
*/
|
||||
int att_pos_estimator_ekf_main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
if (argc < 1)
|
||||
usage("missing command");
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
|
||||
if (thread_running) {
|
||||
warnx("already running");
|
||||
/* this is not an error */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
thread_should_exit = false;
|
||||
|
||||
daemon_task = task_spawn_cmd("att_pos_estimator_ekf",
|
||||
SCHED_DEFAULT,
|
||||
SCHED_PRIORITY_MAX - 30,
|
||||
8192,
|
||||
kalman_demo_thread_main,
|
||||
(argv) ? (const char **)&argv[2] : (const char **)NULL);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "stop")) {
|
||||
thread_should_exit = true;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "status")) {
|
||||
if (thread_running) {
|
||||
warnx("is running\n");
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
warnx("not started\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
usage("unrecognized command");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int kalman_demo_thread_main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
warnx("starting");
|
||||
|
||||
using namespace math;
|
||||
|
||||
thread_running = true;
|
||||
|
||||
KalmanNav nav(NULL, "KF");
|
||||
|
||||
while (!thread_should_exit) {
|
||||
nav.update();
|
||||
}
|
||||
|
||||
warnx("exiting.");
|
||||
|
||||
thread_running = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
############################################################################
|
||||
#
|
||||
# Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in
|
||||
# the documentation and/or other materials provided with the
|
||||
# distribution.
|
||||
# 3. Neither the name PX4 nor the names of its contributors may be
|
||||
# used to endorse or promote products derived from this software
|
||||
# without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
############################################################################
|
||||
|
||||
#
|
||||
# Full attitude / position Extended Kalman Filter
|
||||
#
|
||||
|
||||
MODULE_COMMAND = att_pos_estimator_ekf
|
||||
|
||||
SRCS = kalman_main.cpp \
|
||||
KalmanNav.cpp \
|
||||
params.c
|
||||
@@ -1,49 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2012, 2013 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#include <systemlib/param/param.h>
|
||||
|
||||
/*PARAM_DEFINE_FLOAT(NAME,0.0f);*/
|
||||
PARAM_DEFINE_FLOAT(KF_V_GYRO, 0.008f);
|
||||
PARAM_DEFINE_FLOAT(KF_V_ACCEL, 1.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_MAG, 0.8f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_GPS_VEL, 0.5f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_GPS_POS, 2.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_GPS_ALT, 3.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_PRESS_ALT, 0.1f);
|
||||
PARAM_DEFINE_FLOAT(KF_R_ACCEL, 1.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_FAULT_POS, 10.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_FAULT_ATT, 10.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_ENV_G, 9.765f);
|
||||
PARAM_DEFINE_FLOAT(KF_ENV_MAG_DIP, 60.0f);
|
||||
PARAM_DEFINE_FLOAT(KF_ENV_MAG_DEC, 0.0f);
|
||||
@@ -407,7 +407,7 @@ const unsigned int loop_interval_alarm = 6500; // loop interval in microseconds
|
||||
vel(2) = gps.vel_d_m_s;
|
||||
}
|
||||
|
||||
} else if (ekf_params.acc_comp == 2 && global_pos.global_valid && hrt_absolute_time() < global_pos.timestamp + 500000) {
|
||||
} else if (ekf_params.acc_comp == 2 && gps.eph_m < 5.0f && global_pos.timestamp != 0 && hrt_absolute_time() < global_pos.timestamp + 20000) {
|
||||
vel_valid = true;
|
||||
if (global_pos_updated) {
|
||||
vel_t = global_pos.timestamp;
|
||||
|
||||
@@ -117,7 +117,7 @@ extern struct system_load_s system_load;
|
||||
#define STICK_ON_OFF_HYSTERESIS_TIME_MS 1000
|
||||
#define STICK_ON_OFF_COUNTER_LIMIT (STICK_ON_OFF_HYSTERESIS_TIME_MS*COMMANDER_MONITORING_LOOPSPERMSEC)
|
||||
|
||||
#define POSITION_TIMEOUT 1000000 /**< consider the local or global position estimate invalid after 1s */
|
||||
#define POSITION_TIMEOUT 30000 /**< consider the local or global position estimate invalid after 30ms */
|
||||
#define RC_TIMEOUT 500000
|
||||
#define DIFFPRESS_TIMEOUT 2000000
|
||||
|
||||
@@ -153,6 +153,7 @@ static bool on_usb_power = false;
|
||||
|
||||
static float takeoff_alt = 5.0f;
|
||||
static int parachute_enabled = 0;
|
||||
static float eph_epv_threshold = 5.0f;
|
||||
|
||||
static struct vehicle_status_s status;
|
||||
static struct actuator_armed_s armed;
|
||||
@@ -194,7 +195,7 @@ void usage(const char *reason);
|
||||
/**
|
||||
* React to commands that are sent e.g. from the mavlink module.
|
||||
*/
|
||||
bool handle_command(struct vehicle_status_s *status, struct vehicle_command_s *cmd, struct actuator_armed_s *armed);
|
||||
bool handle_command(struct vehicle_status_s *status, const struct safety_s *safety, struct vehicle_command_s *cmd, struct actuator_armed_s *armed, struct home_position_s *home, struct vehicle_global_position_s *global_pos, orb_advert_t *home_pub);
|
||||
|
||||
/**
|
||||
* Mainloop of commander.
|
||||
@@ -378,7 +379,7 @@ transition_result_t arm_disarm(bool arm, const int mavlink_fd, const char* armed
|
||||
return arming_res;
|
||||
}
|
||||
|
||||
bool handle_command(struct vehicle_status_s *status, const struct safety_s *safety, struct vehicle_command_s *cmd, struct actuator_armed_s *armed)
|
||||
bool handle_command(struct vehicle_status_s *status, const struct safety_s *safety, struct vehicle_command_s *cmd, struct actuator_armed_s *armed, struct home_position_s *home, struct vehicle_global_position_s *global_pos, orb_advert_t *home_pub)
|
||||
{
|
||||
/* result of the command */
|
||||
enum VEHICLE_CMD_RESULT result = VEHICLE_CMD_RESULT_UNSUPPORTED;
|
||||
@@ -534,6 +535,51 @@ bool handle_command(struct vehicle_status_s *status, const struct safety_s *safe
|
||||
}
|
||||
break;
|
||||
|
||||
case VEHICLE_CMD_DO_SET_HOME: {
|
||||
bool use_current = cmd->param1 > 0.5f;
|
||||
if (use_current) {
|
||||
/* use current position */
|
||||
if (status->condition_global_position_valid) {
|
||||
home->lat = global_pos->lat;
|
||||
home->lon = global_pos->lon;
|
||||
home->alt = global_pos->alt;
|
||||
|
||||
home->timestamp = hrt_absolute_time();
|
||||
|
||||
result = VEHICLE_CMD_RESULT_ACCEPTED;
|
||||
|
||||
} else {
|
||||
result = VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* use specified position */
|
||||
home->lat = cmd->param5;
|
||||
home->lon = cmd->param6;
|
||||
home->alt = cmd->param7;
|
||||
|
||||
home->timestamp = hrt_absolute_time();
|
||||
|
||||
result = VEHICLE_CMD_RESULT_ACCEPTED;
|
||||
}
|
||||
|
||||
if (result == VEHICLE_CMD_RESULT_ACCEPTED) {
|
||||
warnx("home: lat = %.7f, lon = %.7f, alt = %.2f ", home->lat, home->lon, (double)home->alt);
|
||||
mavlink_log_info(mavlink_fd, "[cmd] home: %.7f, %.7f, %.2f", home->lat, home->lon, (double)home->alt);
|
||||
|
||||
/* announce new home position */
|
||||
if (*home_pub > 0) {
|
||||
orb_publish(ORB_ID(home_position), *home_pub, home);
|
||||
|
||||
} else {
|
||||
*home_pub = orb_advertise(ORB_ID(home_position), home);
|
||||
}
|
||||
|
||||
/* mark home position as set */
|
||||
status->condition_home_position_valid = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case VEHICLE_CMD_PREFLIGHT_REBOOT_SHUTDOWN:
|
||||
case VEHICLE_CMD_PREFLIGHT_CALIBRATION:
|
||||
case VEHICLE_CMD_PREFLIGHT_SET_SENSOR_OFFSETS:
|
||||
@@ -566,6 +612,7 @@ int commander_thread_main(int argc, char *argv[])
|
||||
commander_initialized = false;
|
||||
|
||||
bool arm_tune_played = false;
|
||||
bool was_armed = false;
|
||||
|
||||
/* set parameters */
|
||||
param_t _param_sys_type = param_find("MAV_TYPE");
|
||||
@@ -877,9 +924,6 @@ int commander_thread_main(int argc, char *argv[])
|
||||
orb_copy(ORB_ID(vehicle_global_position), global_position_sub, &global_position);
|
||||
}
|
||||
|
||||
/* update condition_global_position_valid */
|
||||
check_valid(global_position.timestamp, POSITION_TIMEOUT, global_position.global_valid, &(status.condition_global_position_valid), &status_changed);
|
||||
|
||||
/* update local position estimate */
|
||||
orb_check(local_position_sub, &updated);
|
||||
|
||||
@@ -888,8 +932,53 @@ int commander_thread_main(int argc, char *argv[])
|
||||
orb_copy(ORB_ID(vehicle_local_position), local_position_sub, &local_position);
|
||||
}
|
||||
|
||||
/* update condition_global_position_valid */
|
||||
/* hysteresis for EPH/EPV */
|
||||
bool eph_epv_good;
|
||||
if (status.condition_global_position_valid) {
|
||||
if (global_position.eph > eph_epv_threshold * 2.0f || global_position.epv > eph_epv_threshold * 2.0f) {
|
||||
eph_epv_good = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (global_position.eph < eph_epv_threshold && global_position.epv < eph_epv_threshold) {
|
||||
eph_epv_good = true;
|
||||
}
|
||||
}
|
||||
check_valid(global_position.timestamp, POSITION_TIMEOUT, eph_epv_good, &(status.condition_global_position_valid), &status_changed);
|
||||
|
||||
/* check if GPS fix is ok */
|
||||
|
||||
/* update home position */
|
||||
if (!status.condition_home_position_valid && status.condition_global_position_valid && !armed.armed &&
|
||||
(global_position.eph < eph_epv_threshold) && (global_position.epv < eph_epv_threshold)) {
|
||||
|
||||
home.lat = global_position.lat;
|
||||
home.lon = global_position.lon;
|
||||
home.alt = global_position.alt;
|
||||
|
||||
home.x = local_position.x;
|
||||
home.y = local_position.y;
|
||||
home.z = local_position.z;
|
||||
|
||||
warnx("home: lat = %.7f, lon = %.7f, alt = %.2f ", home.lat, home.lon, (double)home.alt);
|
||||
mavlink_log_info(mavlink_fd, "[cmd] home: %.7f, %.7f, %.2f", home.lat, home.lon, (double)home.alt);
|
||||
|
||||
/* announce new home position */
|
||||
if (home_pub > 0) {
|
||||
orb_publish(ORB_ID(home_position), home_pub, &home);
|
||||
|
||||
} else {
|
||||
home_pub = orb_advertise(ORB_ID(home_position), &home);
|
||||
}
|
||||
|
||||
/* mark home position as set */
|
||||
status.condition_home_position_valid = true;
|
||||
tune_positive(true);
|
||||
}
|
||||
|
||||
/* update condition_local_position_valid and condition_local_altitude_valid */
|
||||
check_valid(local_position.timestamp, POSITION_TIMEOUT, local_position.xy_valid, &(status.condition_local_position_valid), &status_changed);
|
||||
check_valid(local_position.timestamp, POSITION_TIMEOUT, local_position.xy_valid && eph_epv_good, &(status.condition_local_position_valid), &status_changed);
|
||||
check_valid(local_position.timestamp, POSITION_TIMEOUT, local_position.z_valid, &(status.condition_local_altitude_valid), &status_changed);
|
||||
|
||||
static bool published_condition_landed_fw = false;
|
||||
@@ -964,7 +1053,7 @@ int commander_thread_main(int argc, char *argv[])
|
||||
status_changed = true;
|
||||
}
|
||||
|
||||
/* update subsystem */
|
||||
/* update position setpoint triplet */
|
||||
orb_check(pos_sp_triplet_sub, &updated);
|
||||
|
||||
if (updated) {
|
||||
@@ -1033,45 +1122,6 @@ int commander_thread_main(int argc, char *argv[])
|
||||
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_gps_position), gps_sub, &gps_position);
|
||||
/* check if GPS fix is ok */
|
||||
float hdop_threshold_m = 4.0f;
|
||||
float vdop_threshold_m = 8.0f;
|
||||
|
||||
/*
|
||||
* If horizontal dilution of precision (hdop / eph)
|
||||
* and vertical diluation of precision (vdop / epv)
|
||||
* are below a certain threshold (e.g. 4 m), AND
|
||||
* home position is not yet set AND the last GPS
|
||||
* GPS measurement is not older than two seconds AND
|
||||
* the system is currently not armed, set home
|
||||
* position to the current position.
|
||||
*/
|
||||
|
||||
if (!status.condition_home_position_valid && gps_position.fix_type >= 3 &&
|
||||
(gps_position.eph_m < hdop_threshold_m) && (gps_position.epv_m < vdop_threshold_m) &&
|
||||
(hrt_absolute_time() < gps_position.timestamp_position + POSITION_TIMEOUT) && !armed.armed
|
||||
&& global_position.global_valid) {
|
||||
|
||||
/* copy position data to uORB home message, store it locally as well */
|
||||
home.lat = global_position.lat;
|
||||
home.lon = global_position.lon;
|
||||
home.alt = global_position.alt;
|
||||
|
||||
warnx("home: lat = %.7f, lon = %.7f, alt = %.4f ", home.lat, home.lon, (double)home.alt);
|
||||
mavlink_log_info(mavlink_fd, "[cmd] home: %.7f, %.7f, %.4f", home.lat, home.lon, (double)home.alt);
|
||||
|
||||
/* announce new home position */
|
||||
if (home_pub > 0) {
|
||||
orb_publish(ORB_ID(home_position), home_pub, &home);
|
||||
|
||||
} else {
|
||||
home_pub = orb_advertise(ORB_ID(home_position), &home);
|
||||
}
|
||||
|
||||
/* mark home position as set */
|
||||
status.condition_home_position_valid = true;
|
||||
tune_positive(true);
|
||||
}
|
||||
}
|
||||
|
||||
/* start RC input check */
|
||||
@@ -1171,30 +1221,27 @@ int commander_thread_main(int argc, char *argv[])
|
||||
mavlink_log_critical(mavlink_fd, "ERROR: main state transition denied");
|
||||
}
|
||||
|
||||
if (sp_man.mode_switch == SWITCH_POS_ON) {
|
||||
/* set navigation state */
|
||||
/* RETURN switch, overrides MISSION switch */
|
||||
if (sp_man.return_switch == SWITCH_POS_ON) {
|
||||
/* switch to RTL if not already landed after RTL and home position set */
|
||||
status.set_nav_state = NAVIGATION_STATE_RTL;
|
||||
|
||||
/* set navigation state */
|
||||
/* RETURN switch, overrides MISSION switch */
|
||||
if (sp_man.return_switch == SWITCH_POS_ON) {
|
||||
/* switch to RTL if not already landed after RTL and home position set */
|
||||
status.set_nav_state = NAVIGATION_STATE_RTL;
|
||||
|
||||
} else {
|
||||
/* MISSION switch */
|
||||
if (sp_man.mission_switch == SWITCH_POS_ON) {
|
||||
/* stick is in LOITER position */
|
||||
status.set_nav_state = NAVIGATION_STATE_LOITER;
|
||||
} else {
|
||||
/* MISSION switch */
|
||||
if (sp_man.loiter_switch == SWITCH_POS_ON) {
|
||||
/* stick is in LOITER position */
|
||||
status.set_nav_state = NAVIGATION_STATE_LOITER;
|
||||
|
||||
} else if (sp_man.mission_switch != SWITCH_POS_NONE) {
|
||||
/* stick is in MISSION position */
|
||||
status.set_nav_state = NAVIGATION_STATE_MISSION;
|
||||
}
|
||||
/* XXX: I don't understand this */
|
||||
//else if ((sp_man.return_switch == SWITCH_POS_OFF || sp_man.return_switch == SWITCH_POS_MIDDLE) &&
|
||||
// pos_sp_triplet.nav_state == NAVIGATION_STATE_RTL) {
|
||||
// /* RETURN switch is in normal mode, no MISSION switch mapped, interrupt if in RTL state */
|
||||
// status.set_nav_state = NAV_STATE_MISSION;
|
||||
// }
|
||||
} else if (sp_man.loiter_switch != SWITCH_POS_NONE) {
|
||||
/* stick is in MISSION position */
|
||||
status.set_nav_state = NAVIGATION_STATE_MISSION;
|
||||
|
||||
} else if ((sp_man.return_switch == SWITCH_POS_OFF || sp_man.return_switch == SWITCH_POS_MIDDLE) &&
|
||||
pos_sp_triplet.nav_state == NAV_STATE_RTL) {
|
||||
/* RETURN switch is in normal mode, no MISSION switch mapped, interrupt if in RTL state */
|
||||
status.set_nav_state = NAVIGATION_STATE_MISSION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1222,10 +1269,15 @@ int commander_thread_main(int argc, char *argv[])
|
||||
|
||||
} else {
|
||||
/* failsafe for manual modes */
|
||||
transition_result_t res = failsafe_state_transition(&status, FAILSAFE_STATE_RTL);
|
||||
transition_result_t res = TRANSITION_DENIED;
|
||||
|
||||
if (!status.condition_landed) {
|
||||
/* vehicle is not landed, try to perform RTL */
|
||||
res = failsafe_state_transition(&status, FAILSAFE_STATE_RTL);
|
||||
}
|
||||
|
||||
if (res == TRANSITION_DENIED) {
|
||||
/* RTL not allowed (no global position estimate), try LAND */
|
||||
/* RTL not allowed (no global position estimate) or not wanted, try LAND */
|
||||
res = failsafe_state_transition(&status, FAILSAFE_STATE_LAND);
|
||||
|
||||
if (res == TRANSITION_DENIED) {
|
||||
@@ -1259,7 +1311,7 @@ int commander_thread_main(int argc, char *argv[])
|
||||
orb_copy(ORB_ID(vehicle_command), cmd_sub, &cmd);
|
||||
|
||||
/* handle it */
|
||||
if (handle_command(&status, &safety, &cmd, &armed))
|
||||
if (handle_command(&status, &safety, &cmd, &armed, &home, &global_position, &home_pub))
|
||||
status_changed = true;
|
||||
}
|
||||
|
||||
@@ -1274,7 +1326,36 @@ int commander_thread_main(int argc, char *argv[])
|
||||
if (arming_state_changed) {
|
||||
status_changed = true;
|
||||
mavlink_log_info(mavlink_fd, "[cmd] arming state: %s", arming_states_str[status.arming_state]);
|
||||
|
||||
/* update home position on arming if at least 2s from commander start spent to avoid setting home on in-air restart */
|
||||
if (armed.armed && !was_armed && hrt_absolute_time() > start_time + 2000000 && status.condition_global_position_valid &&
|
||||
(global_position.eph < eph_epv_threshold) && (global_position.epv < eph_epv_threshold)) {
|
||||
|
||||
// TODO remove code duplication
|
||||
home.lat = global_position.lat;
|
||||
home.lon = global_position.lon;
|
||||
home.alt = global_position.alt;
|
||||
|
||||
home.x = local_position.x;
|
||||
home.y = local_position.y;
|
||||
home.z = local_position.z;
|
||||
|
||||
warnx("home: lat = %.7f, lon = %.7f, alt = %.2f ", home.lat, home.lon, (double)home.alt);
|
||||
mavlink_log_info(mavlink_fd, "[cmd] home: %.7f, %.7f, %.2f", home.lat, home.lon, (double)home.alt);
|
||||
|
||||
/* announce new home position */
|
||||
if (home_pub > 0) {
|
||||
orb_publish(ORB_ID(home_position), home_pub, &home);
|
||||
|
||||
} else {
|
||||
home_pub = orb_advertise(ORB_ID(home_position), &home);
|
||||
}
|
||||
|
||||
/* mark home position as set */
|
||||
status.condition_home_position_valid = true;
|
||||
}
|
||||
}
|
||||
was_armed = armed.armed;
|
||||
|
||||
if (main_state_changed) {
|
||||
status_changed = true;
|
||||
@@ -1620,8 +1701,11 @@ set_control_mode()
|
||||
control_mode.flag_control_auto_enabled = true;
|
||||
control_mode.flag_control_rates_enabled = true;
|
||||
control_mode.flag_control_attitude_enabled = true;
|
||||
control_mode.flag_control_position_enabled = true;
|
||||
control_mode.flag_control_velocity_enabled = true;
|
||||
|
||||
/* in failsafe LAND mode position may be not available */
|
||||
control_mode.flag_control_position_enabled = status.condition_local_position_valid;
|
||||
control_mode.flag_control_velocity_enabled = status.condition_local_position_valid;
|
||||
|
||||
control_mode.flag_control_altitude_enabled = true;
|
||||
control_mode.flag_control_climb_rate_enabled = true;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+107
-16
@@ -20,7 +20,7 @@ public:
|
||||
float z;
|
||||
|
||||
float length(void) const;
|
||||
Vector3f zero(void) const;
|
||||
void zero(void);
|
||||
};
|
||||
|
||||
class Mat3f
|
||||
@@ -33,6 +33,7 @@ public:
|
||||
|
||||
Mat3f();
|
||||
|
||||
void identity();
|
||||
Mat3f transpose(void) const;
|
||||
};
|
||||
|
||||
@@ -45,14 +46,9 @@ Vector3f operator*(Vector3f vecIn1, float sclIn1);
|
||||
|
||||
void swap_var(float &d1, float &d2);
|
||||
|
||||
const unsigned int n_states = 21;
|
||||
const unsigned int n_states = 23;
|
||||
const unsigned int data_buffer_size = 50;
|
||||
|
||||
const float covTimeStepMax = 0.07f; // maximum time allowed between covariance predictions
|
||||
const float covDelAngMax = 0.02f; // maximum delta angle between covariance predictions
|
||||
|
||||
// extern bool staticMode;
|
||||
|
||||
enum GPS_FIX {
|
||||
GPS_FIX_NOFIX = 0,
|
||||
GPS_FIX_2D = 2,
|
||||
@@ -82,6 +78,88 @@ public:
|
||||
AttPosEKF();
|
||||
~AttPosEKF();
|
||||
|
||||
|
||||
|
||||
/* ##############################################
|
||||
*
|
||||
* M A I N F I L T E R P A R A M E T E R S
|
||||
*
|
||||
* ########################################### */
|
||||
|
||||
/*
|
||||
* parameters are defined here and initialised in
|
||||
* the InitialiseParameters() (which is just 20 lines down)
|
||||
*/
|
||||
|
||||
float covTimeStepMax; // maximum time allowed between covariance predictions
|
||||
float covDelAngMax; // maximum delta angle between covariance predictions
|
||||
float rngFinderPitch; // pitch angle of laser range finder in radians. Zero is aligned with the Z body axis. Positive is RH rotation about Y body axis.
|
||||
|
||||
float yawVarScale;
|
||||
float windVelSigma;
|
||||
float dAngBiasSigma;
|
||||
float dVelBiasSigma;
|
||||
float magEarthSigma;
|
||||
float magBodySigma;
|
||||
float gndHgtSigma;
|
||||
|
||||
float vneSigma;
|
||||
float vdSigma;
|
||||
float posNeSigma;
|
||||
float posDSigma;
|
||||
float magMeasurementSigma;
|
||||
float airspeedMeasurementSigma;
|
||||
|
||||
float gyroProcessNoise;
|
||||
float accelProcessNoise;
|
||||
|
||||
float EAS2TAS; // ratio f true to equivalent airspeed
|
||||
|
||||
void InitialiseParameters()
|
||||
{
|
||||
covTimeStepMax = 0.07f; // maximum time allowed between covariance predictions
|
||||
covDelAngMax = 0.02f; // maximum delta angle between covariance predictions
|
||||
rngFinderPitch = 0.0f; // pitch angle of laser range finder in radians. Zero is aligned with the Z body axis. Positive is RH rotation about Y body axis.
|
||||
EAS2TAS = 1.0f;
|
||||
|
||||
yawVarScale = 1.0f;
|
||||
windVelSigma = 0.1f;
|
||||
dAngBiasSigma = 5.0e-7f;
|
||||
dVelBiasSigma = 1e-4f;
|
||||
magEarthSigma = 3.0e-4f;
|
||||
magBodySigma = 3.0e-4f;
|
||||
gndHgtSigma = 0.02f; // assume 2% terrain gradient 1-sigma
|
||||
|
||||
vneSigma = 0.2f;
|
||||
vdSigma = 0.3f;
|
||||
posNeSigma = 2.0f;
|
||||
posDSigma = 2.0f;
|
||||
|
||||
magMeasurementSigma = 0.05;
|
||||
airspeedMeasurementSigma = 1.4f;
|
||||
gyroProcessNoise = 1.4544411e-2f;
|
||||
accelProcessNoise = 0.5f;
|
||||
}
|
||||
|
||||
struct {
|
||||
unsigned obsIndex;
|
||||
float MagPred[3];
|
||||
float SH_MAG[9];
|
||||
float q0;
|
||||
float q1;
|
||||
float q2;
|
||||
float q3;
|
||||
float magN;
|
||||
float magE;
|
||||
float magD;
|
||||
float magXbias;
|
||||
float magYbias;
|
||||
float magZbias;
|
||||
float R_MAG;
|
||||
Mat3f DCM;
|
||||
} magstate;
|
||||
|
||||
|
||||
// Global variables
|
||||
float KH[n_states][n_states]; // intermediate result used for covariance updates
|
||||
float KHP[n_states][n_states]; // intermediate result used for covariance updates
|
||||
@@ -96,6 +174,7 @@ public:
|
||||
float statesAtHgtTime[n_states]; // States at the effective measurement time for the hgtMea measurement
|
||||
float statesAtMagMeasTime[n_states]; // filter satates at the effective measurement time
|
||||
float statesAtVtasMeasTime[n_states]; // filter states at the effective measurement time
|
||||
float statesAtRngTime[n_states]; // filter states at the effective measurement time
|
||||
|
||||
Vector3f correctedDelAng; // delta angles about the xyz body axes corrected for errors (rad)
|
||||
Vector3f correctedDelVel; // delta velocities along the XYZ body axes corrected for errors (m/s)
|
||||
@@ -104,6 +183,10 @@ public:
|
||||
float accNavMag; // magnitude of navigation accel (- used to adjust GPS obs variance (m/s^2)
|
||||
Vector3f earthRateNED; // earths angular rate vector in NED (rad/s)
|
||||
Vector3f angRate; // angular rate vector in XYZ body axes measured by the IMU (rad/s)
|
||||
|
||||
Mat3f Tbn; // transformation matrix from body to NED coordinates
|
||||
Mat3f Tnb; // transformation amtrix from NED to body coordinates
|
||||
|
||||
Vector3f accel; // acceleration vector in XYZ body axes measured by the IMU (m/s^2)
|
||||
Vector3f dVelIMU;
|
||||
Vector3f dAngIMU;
|
||||
@@ -115,26 +198,28 @@ public:
|
||||
float velNED[3]; // North, East, Down velocity obs (m/s)
|
||||
float posNE[2]; // North, East position obs (m)
|
||||
float hgtMea; // measured height (m)
|
||||
float rngMea; // Ground distance
|
||||
float posNED[3]; // North, East Down position (m)
|
||||
|
||||
float innovMag[3]; // innovation output
|
||||
float varInnovMag[3]; // innovation variance output
|
||||
Vector3f magData; // magnetometer flux radings in X,Y,Z body axes
|
||||
float innovVtas; // innovation output
|
||||
float innovRng; ///< Range finder innovation
|
||||
float varInnovVtas; // innovation variance output
|
||||
float VtasMeas; // true airspeed measurement (m/s)
|
||||
float latRef; // WGS-84 latitude of reference point (rad)
|
||||
float lonRef; // WGS-84 longitude of reference point (rad)
|
||||
double latRef; // WGS-84 latitude of reference point (rad)
|
||||
double lonRef; // WGS-84 longitude of reference point (rad)
|
||||
float hgtRef; // WGS-84 height of reference point (m)
|
||||
bool refSet; ///< flag to indicate if the reference position has been set
|
||||
Vector3f magBias; // states representing magnetometer bias vector in XYZ body axes
|
||||
uint8_t covSkipCount; // Number of state prediction frames (IMU daya updates to skip before doing the covariance prediction
|
||||
float EAS2TAS; // ratio f true to equivalent airspeed
|
||||
unsigned covSkipCount; // Number of state prediction frames (IMU daya updates to skip before doing the covariance prediction
|
||||
|
||||
// GPS input data variables
|
||||
float gpsCourse;
|
||||
float gpsVelD;
|
||||
float gpsLat;
|
||||
float gpsLon;
|
||||
double gpsLat;
|
||||
double gpsLon;
|
||||
float gpsHgt;
|
||||
uint8_t GPSstatus;
|
||||
|
||||
@@ -148,11 +233,13 @@ public:
|
||||
bool fuseHgtData; // this boolean causes the hgtMea obs to be fused
|
||||
bool fuseMagData; // boolean true when magnetometer data is to be fused
|
||||
bool fuseVtasData; // boolean true when airspeed data is to be fused
|
||||
bool fuseRngData; ///< true when range data is fused
|
||||
|
||||
bool onGround; ///< boolean true when the flight vehicle is on the ground (not flying)
|
||||
bool staticMode; ///< boolean true if no position feedback is fused
|
||||
bool useAirspeed; ///< boolean true if airspeed data is being used
|
||||
bool useCompass; ///< boolean true if magnetometer data is being used
|
||||
bool useRangeFinder; ///< true when rangefinder is being used
|
||||
|
||||
struct ekf_status_report current_ekf_state;
|
||||
struct ekf_status_report last_ekf_error;
|
||||
@@ -172,6 +259,10 @@ void FuseMagnetometer();
|
||||
|
||||
void FuseAirspeed();
|
||||
|
||||
void FuseRangeFinder();
|
||||
|
||||
void FuseOpticalFlow();
|
||||
|
||||
void zeroRows(float (&covMat)[n_states][n_states], uint8_t first, uint8_t last);
|
||||
|
||||
void zeroCols(float (&covMat)[n_states][n_states], uint8_t first, uint8_t last);
|
||||
@@ -192,7 +283,7 @@ void StoreStates(uint64_t timestamp_ms);
|
||||
* time-wise where valid states were updated and invalid remained at the old
|
||||
* value.
|
||||
*/
|
||||
int RecallStates(float statesForFusion[n_states], uint64_t msec);
|
||||
int RecallStates(float *statesForFusion, uint64_t msec);
|
||||
|
||||
void ResetStoredStates();
|
||||
|
||||
@@ -206,7 +297,7 @@ static void quat2eul(float (&eul)[3], const float (&quat)[4]);
|
||||
|
||||
static void calcvelNED(float (&velNED)[3], float gpsCourse, float gpsGndSpd, float gpsVelD);
|
||||
|
||||
static void calcposNED(float (&posNED)[3], float lat, float lon, float hgt, float latRef, float lonRef, float hgtRef);
|
||||
static void calcposNED(float (&posNED)[3], double lat, double lon, float hgt, double latRef, double lonRef, float hgtRef);
|
||||
|
||||
static void calcLLH(float (&posNED)[3], float lat, float lon, float hgt, float latRef, float lonRef, float hgtRef);
|
||||
|
||||
@@ -218,7 +309,7 @@ void OnGroundCheck();
|
||||
|
||||
void CovarianceInit();
|
||||
|
||||
void InitialiseFilter(float (&initvelNED)[3]);
|
||||
void InitialiseFilter(float (&initvelNED)[3], double referenceLat, double referenceLon, float referenceHgt);
|
||||
|
||||
float ConstrainFloat(float val, float min, float max);
|
||||
|
||||
+217
-54
@@ -73,6 +73,7 @@
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/estimator_status.h>
|
||||
#include <uORB/topics/actuator_armed.h>
|
||||
#include <uORB/topics/home_position.h>
|
||||
#include <systemlib/param/param.h>
|
||||
#include <systemlib/err.h>
|
||||
#include <geo/geo.h>
|
||||
@@ -90,7 +91,7 @@
|
||||
*
|
||||
* @ingroup apps
|
||||
*/
|
||||
extern "C" __EXPORT int fw_att_pos_estimator_main(int argc, char *argv[]);
|
||||
extern "C" __EXPORT int ekf_att_pos_estimator_main(int argc, char *argv[]);
|
||||
|
||||
__EXPORT uint32_t millis();
|
||||
|
||||
@@ -102,8 +103,6 @@ uint32_t millis()
|
||||
return IMUmsec;
|
||||
}
|
||||
|
||||
static void print_status();
|
||||
|
||||
class FixedwingEstimator
|
||||
{
|
||||
public:
|
||||
@@ -152,6 +151,7 @@ private:
|
||||
int _params_sub; /**< notification of parameter updates */
|
||||
int _manual_control_sub; /**< notification of manual control updates */
|
||||
int _mission_sub;
|
||||
int _home_sub; /**< home position as defined by commander / user */
|
||||
|
||||
orb_advert_t _att_pub; /**< vehicle attitude */
|
||||
orb_advert_t _global_pos_pub; /**< global position */
|
||||
@@ -177,6 +177,8 @@ private:
|
||||
struct sensor_combined_s _sensor_combined;
|
||||
#endif
|
||||
|
||||
struct map_projection_reference_s _pos_ref;
|
||||
|
||||
float _baro_ref; /**< barometer reference altitude */
|
||||
float _baro_gps_offset; /**< offset between GPS and baro */
|
||||
|
||||
@@ -190,6 +192,7 @@ private:
|
||||
|
||||
bool _initialized;
|
||||
bool _gps_initialized;
|
||||
uint64_t _gps_start_time;
|
||||
|
||||
int _mavlink_fd;
|
||||
|
||||
@@ -199,6 +202,18 @@ private:
|
||||
int32_t height_delay_ms;
|
||||
int32_t mag_delay_ms;
|
||||
int32_t tas_delay_ms;
|
||||
float velne_noise;
|
||||
float veld_noise;
|
||||
float posne_noise;
|
||||
float posd_noise;
|
||||
float mag_noise;
|
||||
float gyro_pnoise;
|
||||
float acc_pnoise;
|
||||
float gbias_pnoise;
|
||||
float abias_pnoise;
|
||||
float mage_pnoise;
|
||||
float magb_pnoise;
|
||||
float eas_noise;
|
||||
} _parameters; /**< local copies of interesting parameters */
|
||||
|
||||
struct {
|
||||
@@ -207,6 +222,18 @@ private:
|
||||
param_t height_delay_ms;
|
||||
param_t mag_delay_ms;
|
||||
param_t tas_delay_ms;
|
||||
param_t velne_noise;
|
||||
param_t veld_noise;
|
||||
param_t posne_noise;
|
||||
param_t posd_noise;
|
||||
param_t mag_noise;
|
||||
param_t gyro_pnoise;
|
||||
param_t acc_pnoise;
|
||||
param_t gbias_pnoise;
|
||||
param_t abias_pnoise;
|
||||
param_t mage_pnoise;
|
||||
param_t magb_pnoise;
|
||||
param_t eas_noise;
|
||||
} _parameter_handles; /**< handles for interesting parameters */
|
||||
|
||||
AttPosEKF *_ekf;
|
||||
@@ -279,6 +306,25 @@ FixedwingEstimator::FixedwingEstimator() :
|
||||
_local_pos_pub(-1),
|
||||
_estimator_status_pub(-1),
|
||||
|
||||
_att({}),
|
||||
_gyro({}),
|
||||
_accel({}),
|
||||
_mag({}),
|
||||
_airspeed({}),
|
||||
_baro({}),
|
||||
_vstatus({}),
|
||||
_global_pos({}),
|
||||
_local_pos({}),
|
||||
_gps({}),
|
||||
|
||||
_gyro_offsets({}),
|
||||
_accel_offsets({}),
|
||||
_mag_offsets({}),
|
||||
|
||||
#ifdef SENSOR_COMBINED_SUB
|
||||
_sensor_combined({}),
|
||||
#endif
|
||||
|
||||
_baro_ref(0.0f),
|
||||
_baro_gps_offset(0.0f),
|
||||
|
||||
@@ -300,13 +346,25 @@ FixedwingEstimator::FixedwingEstimator() :
|
||||
_velocity_z_filtered(0.0f)
|
||||
{
|
||||
|
||||
_mavlink_fd = open(MAVLINK_LOG_DEVICE, 0);
|
||||
last_run = hrt_absolute_time();
|
||||
|
||||
_parameter_handles.vel_delay_ms = param_find("PE_VEL_DELAY_MS");
|
||||
_parameter_handles.pos_delay_ms = param_find("PE_POS_DELAY_MS");
|
||||
_parameter_handles.height_delay_ms = param_find("PE_HGT_DELAY_MS");
|
||||
_parameter_handles.mag_delay_ms = param_find("PE_MAG_DELAY_MS");
|
||||
_parameter_handles.tas_delay_ms = param_find("PE_TAS_DELAY_MS");
|
||||
_parameter_handles.velne_noise = param_find("PE_VELNE_NOISE");
|
||||
_parameter_handles.veld_noise = param_find("PE_VELD_NOISE");
|
||||
_parameter_handles.posne_noise = param_find("PE_POSNE_NOISE");
|
||||
_parameter_handles.posd_noise = param_find("PE_POSD_NOISE");
|
||||
_parameter_handles.mag_noise = param_find("PE_MAG_NOISE");
|
||||
_parameter_handles.gyro_pnoise = param_find("PE_GYRO_PNOISE");
|
||||
_parameter_handles.acc_pnoise = param_find("PE_ACC_PNOISE");
|
||||
_parameter_handles.gbias_pnoise = param_find("PE_GBIAS_PNOISE");
|
||||
_parameter_handles.abias_pnoise = param_find("PE_ABIAS_PNOISE");
|
||||
_parameter_handles.mage_pnoise = param_find("PE_MAGE_PNOISE");
|
||||
_parameter_handles.magb_pnoise = param_find("PE_MAGB_PNOISE");
|
||||
_parameter_handles.eas_noise = param_find("PE_EAS_NOISE");
|
||||
|
||||
/* fetch initial parameter values */
|
||||
parameters_update();
|
||||
@@ -320,6 +378,10 @@ FixedwingEstimator::FixedwingEstimator() :
|
||||
if (fd > 0) {
|
||||
res = ioctl(fd, GYROIOCGSCALE, (long unsigned int)&_gyro_offsets);
|
||||
close(fd);
|
||||
|
||||
if (res) {
|
||||
warnx("G SCALE FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(ACCEL_DEVICE_PATH, O_RDONLY);
|
||||
@@ -327,6 +389,10 @@ FixedwingEstimator::FixedwingEstimator() :
|
||||
if (fd > 0) {
|
||||
res = ioctl(fd, ACCELIOCGSCALE, (long unsigned int)&_accel_offsets);
|
||||
close(fd);
|
||||
|
||||
if (res) {
|
||||
warnx("A SCALE FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(MAG_DEVICE_PATH, O_RDONLY);
|
||||
@@ -334,6 +400,10 @@ FixedwingEstimator::FixedwingEstimator() :
|
||||
if (fd > 0) {
|
||||
res = ioctl(fd, MAGIOCGSCALE, (long unsigned int)&_mag_offsets);
|
||||
close(fd);
|
||||
|
||||
if (res) {
|
||||
warnx("M SCALE FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,6 +441,36 @@ FixedwingEstimator::parameters_update()
|
||||
param_get(_parameter_handles.height_delay_ms, &(_parameters.height_delay_ms));
|
||||
param_get(_parameter_handles.mag_delay_ms, &(_parameters.mag_delay_ms));
|
||||
param_get(_parameter_handles.tas_delay_ms, &(_parameters.tas_delay_ms));
|
||||
param_get(_parameter_handles.velne_noise, &(_parameters.velne_noise));
|
||||
param_get(_parameter_handles.veld_noise, &(_parameters.veld_noise));
|
||||
param_get(_parameter_handles.posne_noise, &(_parameters.posne_noise));
|
||||
param_get(_parameter_handles.posd_noise, &(_parameters.posd_noise));
|
||||
param_get(_parameter_handles.mag_noise, &(_parameters.mag_noise));
|
||||
param_get(_parameter_handles.gyro_pnoise, &(_parameters.gyro_pnoise));
|
||||
param_get(_parameter_handles.acc_pnoise, &(_parameters.acc_pnoise));
|
||||
param_get(_parameter_handles.gbias_pnoise, &(_parameters.gbias_pnoise));
|
||||
param_get(_parameter_handles.abias_pnoise, &(_parameters.abias_pnoise));
|
||||
param_get(_parameter_handles.mage_pnoise, &(_parameters.mage_pnoise));
|
||||
param_get(_parameter_handles.magb_pnoise, &(_parameters.magb_pnoise));
|
||||
param_get(_parameter_handles.eas_noise, &(_parameters.eas_noise));
|
||||
|
||||
if (_ekf) {
|
||||
// _ekf->yawVarScale = 1.0f;
|
||||
// _ekf->windVelSigma = 0.1f;
|
||||
_ekf->dAngBiasSigma = _parameters.gbias_pnoise;
|
||||
_ekf->dVelBiasSigma = _parameters.abias_pnoise;
|
||||
_ekf->magEarthSigma = _parameters.mage_pnoise;
|
||||
_ekf->magBodySigma = _parameters.magb_pnoise;
|
||||
// _ekf->gndHgtSigma = 0.02f;
|
||||
_ekf->vneSigma = _parameters.velne_noise;
|
||||
_ekf->vdSigma = _parameters.veld_noise;
|
||||
_ekf->posNeSigma = _parameters.posne_noise;
|
||||
_ekf->posDSigma = _parameters.posd_noise;
|
||||
_ekf->magMeasurementSigma = _parameters.mag_noise;
|
||||
_ekf->gyroProcessNoise = _parameters.gyro_pnoise;
|
||||
_ekf->accelProcessNoise = _parameters.acc_pnoise;
|
||||
_ekf->airspeedMeasurementSigma = _parameters.eas_noise;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -400,6 +500,7 @@ float dt = 0.0f; // time lapsed since last covariance prediction
|
||||
void
|
||||
FixedwingEstimator::task_main()
|
||||
{
|
||||
_mavlink_fd = open(MAVLINK_LOG_DEVICE, 0);
|
||||
|
||||
_ekf = new AttPosEKF();
|
||||
|
||||
@@ -415,6 +516,7 @@ FixedwingEstimator::task_main()
|
||||
_gps_sub = orb_subscribe(ORB_ID(vehicle_gps_position));
|
||||
_vstatus_sub = orb_subscribe(ORB_ID(vehicle_status));
|
||||
_params_sub = orb_subscribe(ORB_ID(parameter_update));
|
||||
_home_sub = orb_subscribe(ORB_ID(home_position));
|
||||
|
||||
/* rate limit vehicle status updates to 5Hz */
|
||||
orb_set_interval(_vstatus_sub, 200);
|
||||
@@ -434,6 +536,7 @@ FixedwingEstimator::task_main()
|
||||
orb_set_interval(_sensor_combined_sub, 4);
|
||||
#endif
|
||||
|
||||
/* sets also parameters in the EKF object */
|
||||
parameters_update();
|
||||
|
||||
/* set initial filter state */
|
||||
@@ -469,12 +572,19 @@ FixedwingEstimator::task_main()
|
||||
fds[1].events = POLLIN;
|
||||
#endif
|
||||
|
||||
hrt_abstime start_time = hrt_absolute_time();
|
||||
|
||||
bool newDataGps = false;
|
||||
bool newAdsData = false;
|
||||
bool newDataMag = false;
|
||||
|
||||
// Reset relevant structs
|
||||
_gps = {};
|
||||
|
||||
#ifndef SENSOR_COMBINED_SUB
|
||||
_gyro = {};
|
||||
#else
|
||||
_sensor_combined = {};
|
||||
#endif
|
||||
|
||||
while (!_task_should_exit) {
|
||||
|
||||
/* wait for up to 500ms for data */
|
||||
@@ -538,21 +648,28 @@ FixedwingEstimator::task_main()
|
||||
last_run = _gyro.timestamp;
|
||||
|
||||
/* guard against too large deltaT's */
|
||||
if (deltaT > 1.0f)
|
||||
if (!isfinite(deltaT) || deltaT > 1.0f || deltaT < 0.000001f) {
|
||||
deltaT = 0.01f;
|
||||
}
|
||||
|
||||
|
||||
// Always store data, independent of init status
|
||||
/* fill in last data set */
|
||||
_ekf->dtIMU = deltaT;
|
||||
|
||||
_ekf->angRate.x = _gyro.x;
|
||||
_ekf->angRate.y = _gyro.y;
|
||||
_ekf->angRate.z = _gyro.z;
|
||||
if (isfinite(_gyro.x) &&
|
||||
isfinite(_gyro.y) &&
|
||||
isfinite(_gyro.z)) {
|
||||
_ekf->angRate.x = _gyro.x;
|
||||
_ekf->angRate.y = _gyro.y;
|
||||
_ekf->angRate.z = _gyro.z;
|
||||
}
|
||||
|
||||
_ekf->accel.x = _accel.x;
|
||||
_ekf->accel.y = _accel.y;
|
||||
_ekf->accel.z = _accel.z;
|
||||
if (accel_updated) {
|
||||
_ekf->accel.x = _accel.x;
|
||||
_ekf->accel.y = _accel.y;
|
||||
_ekf->accel.z = _accel.z;
|
||||
}
|
||||
|
||||
_ekf->dAngIMU = 0.5f * (angRate + lastAngRate) * dtIMU;
|
||||
_ekf->lastAngRate = angRate;
|
||||
@@ -578,23 +695,31 @@ FixedwingEstimator::task_main()
|
||||
IMUmsec = _sensor_combined.timestamp / 1e3f;
|
||||
|
||||
float deltaT = (_sensor_combined.timestamp - last_run) / 1e6f;
|
||||
last_run = _sensor_combined.timestamp;
|
||||
|
||||
/* guard against too large deltaT's */
|
||||
if (deltaT > 1.0f || deltaT < 0.000001f)
|
||||
if (!isfinite(deltaT) || deltaT > 1.0f || deltaT < 0.000001f) {
|
||||
deltaT = 0.01f;
|
||||
}
|
||||
|
||||
last_run = _sensor_combined.timestamp;
|
||||
|
||||
// Always store data, independent of init status
|
||||
/* fill in last data set */
|
||||
_ekf->dtIMU = deltaT;
|
||||
|
||||
_ekf->angRate.x = _sensor_combined.gyro_rad_s[0];
|
||||
_ekf->angRate.y = _sensor_combined.gyro_rad_s[1];
|
||||
_ekf->angRate.z = _sensor_combined.gyro_rad_s[2];
|
||||
if (isfinite(_sensor_combined.gyro_rad_s[0]) &&
|
||||
isfinite(_sensor_combined.gyro_rad_s[1]) &&
|
||||
isfinite(_sensor_combined.gyro_rad_s[2])) {
|
||||
_ekf->angRate.x = _sensor_combined.gyro_rad_s[0];
|
||||
_ekf->angRate.y = _sensor_combined.gyro_rad_s[1];
|
||||
_ekf->angRate.z = _sensor_combined.gyro_rad_s[2];
|
||||
}
|
||||
|
||||
_ekf->accel.x = _sensor_combined.accelerometer_m_s2[0];
|
||||
_ekf->accel.y = _sensor_combined.accelerometer_m_s2[1];
|
||||
_ekf->accel.z = _sensor_combined.accelerometer_m_s2[2];
|
||||
if (accel_updated) {
|
||||
_ekf->accel.x = _sensor_combined.accelerometer_m_s2[0];
|
||||
_ekf->accel.y = _sensor_combined.accelerometer_m_s2[1];
|
||||
_ekf->accel.z = _sensor_combined.accelerometer_m_s2[2];
|
||||
}
|
||||
|
||||
_ekf->dAngIMU = 0.5f * (_ekf->angRate + lastAngRate) * _ekf->dtIMU;
|
||||
lastAngRate = _ekf->angRate;
|
||||
@@ -643,6 +768,9 @@ FixedwingEstimator::task_main()
|
||||
|
||||
} else {
|
||||
|
||||
/* store time of valid GPS measurement */
|
||||
_gps_start_time = hrt_absolute_time();
|
||||
|
||||
/* check if we had a GPS outage for a long time */
|
||||
if (hrt_elapsed_time(&last_gps) > 5 * 1000 * 1000) {
|
||||
_ekf->ResetPosition();
|
||||
@@ -663,6 +791,21 @@ FixedwingEstimator::task_main()
|
||||
_ekf->gpsLat = math::radians(_gps.lat / (double)1e7);
|
||||
_ekf->gpsLon = math::radians(_gps.lon / (double)1e7) - M_PI;
|
||||
_ekf->gpsHgt = _gps.alt / 1e3f;
|
||||
|
||||
// if (_gps.s_variance_m_s > 0.25f && _gps.s_variance_m_s < 100.0f * 100.0f) {
|
||||
// _ekf->vneSigma = sqrtf(_gps.s_variance_m_s);
|
||||
// } else {
|
||||
// _ekf->vneSigma = _parameters.velne_noise;
|
||||
// }
|
||||
|
||||
// if (_gps.p_variance_m > 0.25f && _gps.p_variance_m < 100.0f * 100.0f) {
|
||||
// _ekf->posNeSigma = sqrtf(_gps.p_variance_m);
|
||||
// } else {
|
||||
// _ekf->posNeSigma = _parameters.posne_noise;
|
||||
// }
|
||||
|
||||
// warnx("vel: %8.4f pos: %8.4f", _gps.s_variance_m_s, _gps.p_variance_m);
|
||||
|
||||
newDataGps = true;
|
||||
|
||||
}
|
||||
@@ -730,6 +873,8 @@ FixedwingEstimator::task_main()
|
||||
*/
|
||||
int check = _ekf->CheckAndBound();
|
||||
|
||||
const char* ekfname = "[ekf] ";
|
||||
|
||||
switch (check) {
|
||||
case 0:
|
||||
/* all ok */
|
||||
@@ -738,26 +883,38 @@ FixedwingEstimator::task_main()
|
||||
{
|
||||
const char* str = "NaN in states, resetting";
|
||||
warnx("%s", str);
|
||||
mavlink_log_critical(_mavlink_fd, str);
|
||||
mavlink_log_critical(_mavlink_fd, "%s%s", ekfname, str);
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
const char* str = "stale IMU data, resetting";
|
||||
warnx("%s", str);
|
||||
mavlink_log_critical(_mavlink_fd, str);
|
||||
mavlink_log_critical(_mavlink_fd, "%s%s", ekfname, str);
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
const char* str = "switching dynamic / static state";
|
||||
const char* str = "switching to dynamic state";
|
||||
warnx("%s", str);
|
||||
mavlink_log_critical(_mavlink_fd, str);
|
||||
mavlink_log_critical(_mavlink_fd, "%s%s", ekfname, str);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
const char* str = "unknown reset condition";
|
||||
warnx("%s", str);
|
||||
mavlink_log_critical(_mavlink_fd, "%s%s", ekfname, str);
|
||||
}
|
||||
}
|
||||
|
||||
// If non-zero, we got a problem
|
||||
// XXX trap for testing
|
||||
if (check == 1) {
|
||||
errx(1, "NUMERIC ERROR IN FILTER");
|
||||
}
|
||||
|
||||
// If non-zero, we got a filter reset
|
||||
if (check) {
|
||||
|
||||
struct ekf_status_report ekf_report;
|
||||
@@ -773,7 +930,7 @@ FixedwingEstimator::task_main()
|
||||
rep.kalman_gain_nan = ekf_report.kalmanGainsNaN;
|
||||
|
||||
// Copy all states or at least all that we can fit
|
||||
int i = 0;
|
||||
unsigned i = 0;
|
||||
unsigned ekf_n_states = (sizeof(ekf_report.states) / sizeof(ekf_report.states[0]));
|
||||
unsigned max_states = (sizeof(rep.states) / sizeof(rep.states[0]));
|
||||
rep.n_states = (ekf_n_states < max_states) ? ekf_n_states : max_states;
|
||||
@@ -789,6 +946,7 @@ FixedwingEstimator::task_main()
|
||||
} else {
|
||||
_estimator_status_pub = orb_advertise(ORB_ID(estimator_status), &rep);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -800,22 +958,28 @@ FixedwingEstimator::task_main()
|
||||
// XXX we rather want to check all updated
|
||||
|
||||
|
||||
if (hrt_elapsed_time(&start_time) > 100000) {
|
||||
if (hrt_elapsed_time(&_gps_start_time) > 50000) {
|
||||
|
||||
if (!_gps_initialized && (_ekf->GPSstatus == 3)) {
|
||||
// bool home_set;
|
||||
// orb_check(_home_sub, &home_set);
|
||||
// struct home_position_s home;
|
||||
// orb_copy(ORB_ID(home_position), _home_sub, &home);
|
||||
|
||||
if (!_gps_initialized && _gps.fix_type > 2) {
|
||||
_ekf->velNED[0] = _gps.vel_n_m_s;
|
||||
_ekf->velNED[1] = _gps.vel_e_m_s;
|
||||
_ekf->velNED[2] = _gps.vel_d_m_s;
|
||||
|
||||
double lat = _gps.lat * 1e-7;
|
||||
double lon = _gps.lon * 1e-7;
|
||||
float alt = _gps.alt * 1e-3;
|
||||
// GPS is in scaled integers, convert
|
||||
double lat = _gps.lat / 1.0e7;
|
||||
double lon = _gps.lon / 1.0e7;
|
||||
float alt = _gps.alt / 1e3f;
|
||||
|
||||
_ekf->InitialiseFilter(_ekf->velNED);
|
||||
_ekf->InitialiseFilter(_ekf->velNED, math::radians(lat), math::radians(lon) - M_PI, alt);
|
||||
|
||||
// Initialize projection
|
||||
_local_pos.ref_lat = _gps.lat;
|
||||
_local_pos.ref_lon = _gps.lon;
|
||||
_local_pos.ref_lon = _gps.alt;
|
||||
_local_pos.ref_alt = alt;
|
||||
_local_pos.ref_timestamp = _gps.timestamp_position;
|
||||
|
||||
@@ -825,9 +989,10 @@ FixedwingEstimator::task_main()
|
||||
_ekf->baroHgt = _baro.altitude - _baro_ref;
|
||||
_baro_gps_offset = _baro_ref - _local_pos.ref_alt;
|
||||
|
||||
// XXX this is not multithreading safe
|
||||
map_projection_init(lat, lon);
|
||||
mavlink_log_info(_mavlink_fd, "[position estimator] init ref: lat=%.7f, lon=%.7f, alt=%.2f", lat, lon, alt);
|
||||
map_projection_init(&_pos_ref, lat, lon);
|
||||
mavlink_log_info(_mavlink_fd, "[ekf] ref: LA %.4f,LO %.4f,ALT %.2f", lat, lon, (double)alt);
|
||||
warnx("[ekf] HOME/REF: LA %8.4f,LO %8.4f,ALT %8.2f V: %8.4f %8.4f %8.4f", lat, lon, (double)alt,
|
||||
(double)_ekf->velNED[0], (double)_ekf->velNED[1], (double)_ekf->velNED[2]);
|
||||
|
||||
_gps_initialized = true;
|
||||
|
||||
@@ -841,7 +1006,7 @@ FixedwingEstimator::task_main()
|
||||
|
||||
_ekf->posNE[0] = _ekf->posNED[0];
|
||||
_ekf->posNE[1] = _ekf->posNED[1];
|
||||
_ekf->InitialiseFilter(_ekf->velNED);
|
||||
_ekf->InitialiseFilter(_ekf->velNED, 0.0, 0.0, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -875,10 +1040,10 @@ FixedwingEstimator::task_main()
|
||||
|
||||
// perform a covariance prediction if the total delta angle has exceeded the limit
|
||||
// or the time limit will be exceeded at the next IMU update
|
||||
if ((dt >= (covTimeStepMax - _ekf->dtIMU)) || (_ekf->summedDelAng.length() > covDelAngMax)) {
|
||||
if ((dt >= (_ekf->covTimeStepMax - _ekf->dtIMU)) || (_ekf->summedDelAng.length() > _ekf->covDelAngMax)) {
|
||||
_ekf->CovariancePrediction(dt);
|
||||
_ekf->summedDelAng = _ekf->summedDelAng.zero();
|
||||
_ekf->summedDelVel = _ekf->summedDelVel.zero();
|
||||
_ekf->summedDelAng.zero();
|
||||
_ekf->summedDelVel.zero();
|
||||
dt = 0.0f;
|
||||
}
|
||||
|
||||
@@ -1062,18 +1227,16 @@ FixedwingEstimator::task_main()
|
||||
|
||||
_global_pos.timestamp = _local_pos.timestamp;
|
||||
|
||||
_global_pos.baro_valid = true;
|
||||
_global_pos.global_valid = true;
|
||||
|
||||
if (_local_pos.xy_global) {
|
||||
double est_lat, est_lon;
|
||||
map_projection_reproject(_local_pos.x, _local_pos.y, &est_lat, &est_lon);
|
||||
map_projection_reproject(&_pos_ref, _local_pos.x, _local_pos.y, &est_lat, &est_lon);
|
||||
_global_pos.lat = est_lat;
|
||||
_global_pos.lon = est_lon;
|
||||
_global_pos.time_gps_usec = _gps.time_gps_usec;
|
||||
_global_pos.eph = _gps.eph;
|
||||
_global_pos.epv = _gps.epv;
|
||||
}
|
||||
|
||||
/* set valid values even if position is not valid */
|
||||
if (_local_pos.v_xy_valid) {
|
||||
_global_pos.vel_n = _local_pos.vx;
|
||||
_global_pos.vel_e = _local_pos.vy;
|
||||
@@ -1084,10 +1247,7 @@ FixedwingEstimator::task_main()
|
||||
|
||||
/* local pos alt is negative, change sign and add alt offset */
|
||||
_global_pos.alt = _local_pos.ref_alt + (-_local_pos.z);
|
||||
|
||||
if (_local_pos.z_valid) {
|
||||
_global_pos.baro_alt = _local_pos.ref_alt - _baro_gps_offset - _local_pos.z;
|
||||
}
|
||||
_global_pos.rel_alt = (-_local_pos.z);
|
||||
|
||||
if (_local_pos.v_z_valid) {
|
||||
_global_pos.vel_d = _local_pos.vz;
|
||||
@@ -1095,6 +1255,9 @@ FixedwingEstimator::task_main()
|
||||
|
||||
_global_pos.yaw = _local_pos.yaw;
|
||||
|
||||
_global_pos.eph = _gps.eph_m;
|
||||
_global_pos.epv = _gps.epv_m;
|
||||
|
||||
_global_pos.timestamp = _local_pos.timestamp;
|
||||
|
||||
/* lazily publish the global position only once available */
|
||||
@@ -1125,7 +1288,7 @@ FixedwingEstimator::start()
|
||||
ASSERT(_estimator_task == -1);
|
||||
|
||||
/* start the task */
|
||||
_estimator_task = task_spawn_cmd("fw_att_pos_estimator",
|
||||
_estimator_task = task_spawn_cmd("ekf_att_pos_estimator",
|
||||
SCHED_DEFAULT,
|
||||
SCHED_PRIORITY_MAX - 40,
|
||||
6000,
|
||||
@@ -1159,7 +1322,7 @@ FixedwingEstimator::print_status()
|
||||
// 15-17: Earth Magnetic Field Vector - gauss (North, East, Down)
|
||||
// 18-20: Body Magnetic Field Vector - gauss (X,Y,Z)
|
||||
|
||||
printf("dtIMU: %8.6f dt: %8.6f IMUmsec: %d\n", _ekf->dtIMU, dt, (int)IMUmsec);
|
||||
printf("dtIMU: %8.6f dt: %8.6f IMUmsec: %d\n", (double)_ekf->dtIMU, (double)dt, (int)IMUmsec);
|
||||
printf("dvel: %8.6f %8.6f %8.6f accel: %8.6f %8.6f %8.6f\n", (double)_ekf->dVelIMU.x, (double)_ekf->dVelIMU.y, (double)_ekf->dVelIMU.z, (double)_ekf->accel.x, (double)_ekf->accel.y, (double)_ekf->accel.z);
|
||||
printf("dang: %8.4f %8.4f %8.4f dang corr: %8.4f %8.4f %8.4f\n" , (double)_ekf->dAngIMU.x, (double)_ekf->dAngIMU.y, (double)_ekf->dAngIMU.z, (double)_ekf->correctedDelAng.x, (double)_ekf->correctedDelAng.y, (double)_ekf->correctedDelAng.z);
|
||||
printf("states (quat) [1-4]: %8.4f, %8.4f, %8.4f, %8.4f\n", (double)_ekf->states[0], (double)_ekf->states[1], (double)_ekf->states[2], (double)_ekf->states[3]);
|
||||
@@ -1231,10 +1394,10 @@ int FixedwingEstimator::trip_nan() {
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fw_att_pos_estimator_main(int argc, char *argv[])
|
||||
int ekf_att_pos_estimator_main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 1)
|
||||
errx(1, "usage: fw_att_pos_estimator {start|stop|status}");
|
||||
errx(1, "usage: ekf_att_pos_estimator {start|stop|status}");
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2013, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file fw_att_pos_estimator_params.c
|
||||
*
|
||||
* Parameters defined by the attitude and position estimator task
|
||||
*
|
||||
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <systemlib/param/param.h>
|
||||
|
||||
/*
|
||||
* Estimator parameters, accessible via MAVLink
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Velocity estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the velocity estimate from GPS.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_VEL_DELAY_MS, 230);
|
||||
|
||||
/**
|
||||
* Position estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the position estimate from GPS.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_POS_DELAY_MS, 210);
|
||||
|
||||
/**
|
||||
* Height estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the height estimate from the barometer.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_HGT_DELAY_MS, 350);
|
||||
|
||||
/**
|
||||
* Mag estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the magnetic field estimate from
|
||||
* the magnetometer.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_MAG_DELAY_MS, 30);
|
||||
|
||||
/**
|
||||
* True airspeeed estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the airspeed estimate.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_TAS_DELAY_MS, 210);
|
||||
|
||||
/**
|
||||
* GPS vs. barometric altitude update weight
|
||||
*
|
||||
* RE-CHECK this.
|
||||
*
|
||||
* @min 0.0
|
||||
* @max 1.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_GPS_ALT_WGT, 0.9f);
|
||||
|
||||
/**
|
||||
* Airspeed measurement noise.
|
||||
*
|
||||
* Increasing this value will make the filter trust this sensor
|
||||
* less and trust other sensors more.
|
||||
*
|
||||
* @min 0.5
|
||||
* @max 5.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_EAS_NOISE, 1.4f);
|
||||
|
||||
/**
|
||||
* Velocity measurement noise in north-east (horizontal) direction.
|
||||
*
|
||||
* Generic default: 0.3, multicopters: 0.5, ground vehicles: 0.5
|
||||
*
|
||||
* @min 0.05
|
||||
* @max 5.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_VELNE_NOISE, 0.3f);
|
||||
|
||||
/**
|
||||
* Velocity noise in down (vertical) direction
|
||||
*
|
||||
* Generic default: 0.5, multicopters: 0.7, ground vehicles: 0.7
|
||||
*
|
||||
* @min 0.05
|
||||
* @max 5.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_VELD_NOISE, 0.5f);
|
||||
|
||||
/**
|
||||
* Position noise in north-east (horizontal) direction
|
||||
*
|
||||
* Generic defaults: 0.5, multicopters: 0.5, ground vehicles: 0.5
|
||||
*
|
||||
* @min 0.1
|
||||
* @max 10.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_POSNE_NOISE, 0.5f);
|
||||
|
||||
/**
|
||||
* Position noise in down (vertical) direction
|
||||
*
|
||||
* Generic defaults: 0.5, multicopters: 1.0, ground vehicles: 1.0
|
||||
*
|
||||
* @min 0.1
|
||||
* @max 10.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_POSD_NOISE, 0.5f);
|
||||
|
||||
/**
|
||||
* Magnetometer measurement noise
|
||||
*
|
||||
* Generic defaults: 0.05, multicopters: 0.05, ground vehicles: 0.05
|
||||
*
|
||||
* @min 0.1
|
||||
* @max 10.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_MAG_NOISE, 0.05f);
|
||||
|
||||
/**
|
||||
* Gyro process noise
|
||||
*
|
||||
* Generic defaults: 0.015, multicopters: 0.015, ground vehicles: 0.015.
|
||||
* This noise controls how much the filter trusts the gyro measurements.
|
||||
* Increasing it makes the filter trust the gyro less and other sensors more.
|
||||
*
|
||||
* @min 0.001
|
||||
* @max 0.05
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_GYRO_PNOISE, 0.015f);
|
||||
|
||||
/**
|
||||
* Accelerometer process noise
|
||||
*
|
||||
* Generic defaults: 0.25, multicopters: 0.25, ground vehicles: 0.25.
|
||||
* Increasing this value makes the filter trust the accelerometer less
|
||||
* and other sensors more.
|
||||
*
|
||||
* @min 0.05
|
||||
* @max 1.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_ACC_PNOISE, 0.25f);
|
||||
|
||||
/**
|
||||
* Gyro bias estimate process noise
|
||||
*
|
||||
* Generic defaults: 1e-07f, multicopters: 1e-07f, ground vehicles: 1e-07f.
|
||||
* Increasing this value will make the gyro bias converge faster but noisier.
|
||||
*
|
||||
* @min 0.0000001
|
||||
* @max 0.00001
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_GBIAS_PNOISE, 1e-07f);
|
||||
|
||||
/**
|
||||
* Accelerometer bias estimate process noise
|
||||
*
|
||||
* Generic defaults: 0.0001f, multicopters: 0.0001f, ground vehicles: 0.0001f.
|
||||
* Increasing this value makes the bias estimation faster and noisier.
|
||||
*
|
||||
* @min 0.0001
|
||||
* @max 0.001
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_ABIAS_PNOISE, 0.0001f);
|
||||
|
||||
/**
|
||||
* Magnetometer earth frame offsets process noise
|
||||
*
|
||||
* Generic defaults: 0.0001, multicopters: 0.0001, ground vehicles: 0.0001.
|
||||
* Increasing this value makes the magnetometer earth bias estimate converge
|
||||
* faster but also noisier.
|
||||
*
|
||||
* @min 0.0001
|
||||
* @max 0.01
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_MAGE_PNOISE, 0.0003f);
|
||||
|
||||
/**
|
||||
* Magnetometer body frame offsets process noise
|
||||
*
|
||||
* Generic defaults: 0.0003, multicopters: 0.0003, ground vehicles: 0.0003.
|
||||
* Increasing this value makes the magnetometer body bias estimate converge faster
|
||||
* but also noisier.
|
||||
*
|
||||
* @min 0.0001
|
||||
* @max 0.01
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_MAGB_PNOISE, 0.0003f);
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
# Main Attitude and Position Estimator for Fixed Wing Aircraft
|
||||
#
|
||||
|
||||
MODULE_COMMAND = fw_att_pos_estimator
|
||||
MODULE_COMMAND = ekf_att_pos_estimator
|
||||
|
||||
SRCS = fw_att_pos_estimator_main.cpp \
|
||||
fw_att_pos_estimator_params.c \
|
||||
@@ -782,7 +782,7 @@ FixedwingAttitudeControl::task_main()
|
||||
_actuators.control[1] = (isfinite(pitch_u)) ? pitch_u + _parameters.trim_pitch : _parameters.trim_pitch;
|
||||
if (!isfinite(pitch_u)) {
|
||||
warnx("pitch_u %.4f, _yaw_ctrl.get_desired_rate() %.4f, airspeed %.4f, airspeed_scaling %.4f, roll_sp %.4f, pitch_sp %.4f, _roll_ctrl.get_desired_rate() %.4f, _pitch_ctrl.get_desired_rate() %.4f att_sp.roll_body %.4f",
|
||||
pitch_u, _yaw_ctrl.get_desired_rate(), airspeed, airspeed_scaling, roll_sp, pitch_sp, _roll_ctrl.get_desired_rate(), _pitch_ctrl.get_desired_rate(), _att_sp.roll_body);
|
||||
(double)pitch_u, (double)_yaw_ctrl.get_desired_rate(), (double)airspeed, (double)airspeed_scaling, (double)roll_sp, (double)pitch_sp, (double)_roll_ctrl.get_desired_rate(), (double)_pitch_ctrl.get_desired_rate(), (double)_att_sp.roll_body);
|
||||
}
|
||||
|
||||
float yaw_u = _yaw_ctrl.control_bodyrate(_att.roll, _att.pitch,
|
||||
@@ -791,16 +791,16 @@ FixedwingAttitudeControl::task_main()
|
||||
_parameters.airspeed_min, _parameters.airspeed_max, airspeed, airspeed_scaling, lock_integrator);
|
||||
_actuators.control[2] = (isfinite(yaw_u)) ? yaw_u + _parameters.trim_yaw : _parameters.trim_yaw;
|
||||
if (!isfinite(yaw_u)) {
|
||||
warnx("yaw_u %.4f", yaw_u);
|
||||
warnx("yaw_u %.4f", (double)yaw_u);
|
||||
}
|
||||
|
||||
/* throttle passed through */
|
||||
_actuators.control[3] = (isfinite(throttle_sp)) ? throttle_sp : 0.0f;
|
||||
if (!isfinite(throttle_sp)) {
|
||||
warnx("throttle_sp %.4f", throttle_sp);
|
||||
warnx("throttle_sp %.4f", (double)throttle_sp);
|
||||
}
|
||||
} else {
|
||||
warnx("Non-finite setpoint roll_sp: %.4f, pitch_sp %.4f", roll_sp, pitch_sp);
|
||||
warnx("Non-finite setpoint roll_sp: %.4f, pitch_sp %.4f", (double)roll_sp, (double)pitch_sp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,117 +0,0 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2013, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* 3. Neither the name PX4 nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
/**
|
||||
* @file fw_att_pos_estimator_params.c
|
||||
*
|
||||
* Parameters defined by the attitude and position estimator task
|
||||
*
|
||||
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <systemlib/param/param.h>
|
||||
|
||||
/*
|
||||
* Estimator parameters, accessible via MAVLink
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Velocity estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the velocity estimate from GPS.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_VEL_DELAY_MS, 230);
|
||||
|
||||
/**
|
||||
* Position estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the position estimate from GPS.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_POS_DELAY_MS, 210);
|
||||
|
||||
/**
|
||||
* Height estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the height estimate from the barometer.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_HGT_DELAY_MS, 350);
|
||||
|
||||
/**
|
||||
* Mag estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the magnetic field estimate from
|
||||
* the magnetometer.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_MAG_DELAY_MS, 30);
|
||||
|
||||
/**
|
||||
* True airspeeed estimate delay
|
||||
*
|
||||
* The delay in milliseconds of the airspeed estimate.
|
||||
*
|
||||
* @min 0
|
||||
* @max 1000
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_INT32(PE_TAS_DELAY_MS, 210);
|
||||
|
||||
/**
|
||||
* GPS vs. barometric altitude update weight
|
||||
*
|
||||
* RE-CHECK this.
|
||||
*
|
||||
* @min 0.0
|
||||
* @max 1.0
|
||||
* @group Position Estimator
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(PE_GPS_ALT_WGT, 0.9f);
|
||||
|
||||
@@ -189,9 +189,18 @@ mavlink_send_uart_bytes(mavlink_channel_t channel, const uint8_t *ch, int length
|
||||
/* If the wait until transmit flag is on, only transmit after we've received messages.
|
||||
Otherwise, transmit all the time. */
|
||||
if (instance->should_transmit()) {
|
||||
ssize_t ret = write(uart, ch, desired);
|
||||
|
||||
/* check if there is space in the buffer, let it overflow else */
|
||||
if (!ioctl(uart, FIONWRITE, (unsigned long)&buf_free)) {
|
||||
|
||||
if (desired > buf_free) {
|
||||
desired = buf_free;
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t ret = write(uart, ch, desired);
|
||||
if (ret != desired) {
|
||||
// XXX do something here, but change to using FIONWRITE and OS buf size for detection
|
||||
warnx("TX FAIL");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -257,6 +257,7 @@ MavlinkReceiver::handle_message_optical_flow(mavlink_message_t *msg)
|
||||
memset(&f, 0, sizeof(f));
|
||||
|
||||
f.timestamp = hrt_absolute_time();
|
||||
f.flow_timestamp = flow.time_usec;
|
||||
f.flow_raw_x = flow.flow_x;
|
||||
f.flow_raw_y = flow.flow_y;
|
||||
f.flow_comp_x_m = flow.flow_comp_m_x;
|
||||
@@ -751,7 +752,6 @@ MavlinkReceiver::handle_message_hil_state_quaternion(mavlink_message_t *msg)
|
||||
memset(&hil_global_pos, 0, sizeof(hil_global_pos));
|
||||
|
||||
hil_global_pos.timestamp = timestamp;
|
||||
hil_global_pos.global_valid = true;
|
||||
hil_global_pos.lat = hil_state.lat;
|
||||
hil_global_pos.lon = hil_state.lon;
|
||||
hil_global_pos.alt = hil_state.alt / 1000.0f;
|
||||
@@ -759,6 +759,8 @@ MavlinkReceiver::handle_message_hil_state_quaternion(mavlink_message_t *msg)
|
||||
hil_global_pos.vel_e = hil_state.vy / 100.0f;
|
||||
hil_global_pos.vel_d = hil_state.vz / 100.0f;
|
||||
hil_global_pos.yaw = hil_attitude.yaw;
|
||||
hil_global_pos.eph = 2.0f;
|
||||
hil_global_pos.epv = 4.0f;
|
||||
|
||||
if (_global_pos_pub < 0) {
|
||||
_global_pos_pub = orb_advertise(ORB_ID(vehicle_global_position), &hil_global_pos);
|
||||
@@ -770,19 +772,22 @@ MavlinkReceiver::handle_message_hil_state_quaternion(mavlink_message_t *msg)
|
||||
|
||||
/* local position */
|
||||
{
|
||||
double lat = hil_state.lat * 1e-7;
|
||||
double lon = hil_state.lon * 1e-7;
|
||||
|
||||
if (!_hil_local_proj_inited) {
|
||||
_hil_local_proj_inited = true;
|
||||
_hil_local_alt0 = hil_state.alt / 1000.0f;
|
||||
map_projection_init(hil_state.lat, hil_state.lon);
|
||||
map_projection_init(&_hil_local_proj_ref, hil_state.lat, hil_state.lon);
|
||||
hil_local_pos.ref_timestamp = timestamp;
|
||||
hil_local_pos.ref_lat = hil_state.lat;
|
||||
hil_local_pos.ref_lon = hil_state.lon;
|
||||
hil_local_pos.ref_lat = lat;
|
||||
hil_local_pos.ref_lon = lon;
|
||||
hil_local_pos.ref_alt = _hil_local_alt0;
|
||||
}
|
||||
|
||||
float x;
|
||||
float y;
|
||||
map_projection_project(hil_state.lat * 1e-7, hil_state.lon * 1e-7, &x, &y);
|
||||
map_projection_project(&_hil_local_proj_ref, lat, lon, &x, &y);
|
||||
hil_local_pos.timestamp = timestamp;
|
||||
hil_local_pos.xy_valid = true;
|
||||
hil_local_pos.z_valid = true;
|
||||
|
||||
@@ -142,4 +142,5 @@ private:
|
||||
uint64_t _old_timestamp;
|
||||
bool _hil_local_proj_inited;
|
||||
float _hil_local_alt0;
|
||||
struct map_projection_reference_s _hil_local_proj_ref;
|
||||
};
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (c) 2013 PX4 Development Team. All rights reserved.
|
||||
* Author: @author Anton Babushkin <anton.babushkin@me.com>
|
||||
* Copyright (c) 2013, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -40,6 +39,8 @@
|
||||
* Output of velocity controller is thrust vector that splitted to thrust direction
|
||||
* (i.e. rotation matrix for multicopter orientation) and thrust module (i.e. multicopter thrust itself).
|
||||
* Controller doesn't use Euler angles for work, they generated only for more human-friendly control and logging.
|
||||
*
|
||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||
*/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
@@ -62,9 +63,10 @@
|
||||
#include <uORB/topics/vehicle_control_mode.h>
|
||||
#include <uORB/topics/actuator_armed.h>
|
||||
#include <uORB/topics/parameter_update.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
#include <uORB/topics/vehicle_local_position.h>
|
||||
#include <uORB/topics/position_setpoint_triplet.h>
|
||||
#include <uORB/topics/vehicle_global_velocity_setpoint.h>
|
||||
#include <uORB/topics/vehicle_local_position_setpoint.h>
|
||||
#include <systemlib/param/param.h>
|
||||
#include <systemlib/err.h>
|
||||
#include <systemlib/systemlib.h>
|
||||
@@ -114,20 +116,21 @@ private:
|
||||
int _params_sub; /**< notification of parameter updates */
|
||||
int _manual_sub; /**< notification of manual control updates */
|
||||
int _arming_sub; /**< arming status of outputs */
|
||||
int _global_pos_sub; /**< vehicle local position */
|
||||
int _local_pos_sub; /**< vehicle local position */
|
||||
int _pos_sp_triplet_sub; /**< position setpoint triplet */
|
||||
|
||||
orb_advert_t _att_sp_pub; /**< attitude setpoint publication */
|
||||
orb_advert_t _pos_sp_triplet_pub; /**< position setpoint triplet publication */
|
||||
orb_advert_t _global_vel_sp_pub; /**< vehicle global velocity setpoint */
|
||||
orb_advert_t _local_pos_sp_pub; /**< vehicle local position setpoint publication */
|
||||
orb_advert_t _global_vel_sp_pub; /**< vehicle global velocity setpoint publication */
|
||||
|
||||
struct vehicle_attitude_s _att; /**< vehicle attitude */
|
||||
struct vehicle_attitude_setpoint_s _att_sp; /**< vehicle attitude setpoint */
|
||||
struct manual_control_setpoint_s _manual; /**< r/c channel data */
|
||||
struct vehicle_control_mode_s _control_mode; /**< vehicle control mode */
|
||||
struct actuator_armed_s _arming; /**< actuator arming status */
|
||||
struct vehicle_global_position_s _global_pos; /**< vehicle global position */
|
||||
struct vehicle_local_position_s _local_pos; /**< vehicle local position */
|
||||
struct position_setpoint_triplet_s _pos_sp_triplet; /**< vehicle global position setpoint triplet */
|
||||
struct vehicle_local_position_setpoint_s _local_pos_sp; /**< vehicle local position setpoint */
|
||||
struct vehicle_global_velocity_setpoint_s _global_vel_sp; /**< vehicle global velocity setpoint */
|
||||
|
||||
struct {
|
||||
@@ -166,14 +169,15 @@ private:
|
||||
math::Vector<3> sp_offs_max;
|
||||
} _params;
|
||||
|
||||
double _lat_sp;
|
||||
double _lon_sp;
|
||||
float _alt_sp;
|
||||
struct map_projection_reference_s _ref_pos;
|
||||
float _ref_alt;
|
||||
hrt_abstime _ref_timestamp;
|
||||
|
||||
bool _reset_lat_lon_sp;
|
||||
bool _reset_pos_sp;
|
||||
bool _reset_alt_sp;
|
||||
bool _use_global_alt; /**< switch between global (AMSL) and barometric altitudes */
|
||||
|
||||
math::Vector<3> _pos;
|
||||
math::Vector<3> _pos_sp;
|
||||
math::Vector<3> _vel;
|
||||
math::Vector<3> _vel_sp;
|
||||
math::Vector<3> _vel_prev; /**< velocity on previous step */
|
||||
@@ -196,9 +200,13 @@ private:
|
||||
static float scale_control(float ctl, float end, float dz);
|
||||
|
||||
/**
|
||||
* Reset lat/lon to current position
|
||||
* Update reference for local position projection
|
||||
*/
|
||||
void reset_lat_lon_sp();
|
||||
void update_ref();
|
||||
/**
|
||||
* Reset position setpoint to current position
|
||||
*/
|
||||
void reset_pos_sp();
|
||||
|
||||
/**
|
||||
* Reset altitude setpoint to current altitude
|
||||
@@ -246,31 +254,32 @@ MulticopterPositionControl::MulticopterPositionControl() :
|
||||
_params_sub(-1),
|
||||
_manual_sub(-1),
|
||||
_arming_sub(-1),
|
||||
_global_pos_sub(-1),
|
||||
_local_pos_sub(-1),
|
||||
_pos_sp_triplet_sub(-1),
|
||||
|
||||
/* publications */
|
||||
_att_sp_pub(-1),
|
||||
_pos_sp_triplet_pub(-1),
|
||||
_local_pos_sp_pub(-1),
|
||||
_global_vel_sp_pub(-1),
|
||||
|
||||
_lat_sp(0.0),
|
||||
_lon_sp(0.0),
|
||||
_alt_sp(0.0f),
|
||||
_ref_alt(0.0f),
|
||||
_ref_timestamp(0),
|
||||
|
||||
_reset_lat_lon_sp(true),
|
||||
_reset_alt_sp(true),
|
||||
_use_global_alt(false)
|
||||
_reset_pos_sp(true),
|
||||
_reset_alt_sp(true)
|
||||
{
|
||||
memset(&_att, 0, sizeof(_att));
|
||||
memset(&_att_sp, 0, sizeof(_att_sp));
|
||||
memset(&_manual, 0, sizeof(_manual));
|
||||
memset(&_control_mode, 0, sizeof(_control_mode));
|
||||
memset(&_arming, 0, sizeof(_arming));
|
||||
memset(&_global_pos, 0, sizeof(_global_pos));
|
||||
memset(&_local_pos, 0, sizeof(_local_pos));
|
||||
memset(&_pos_sp_triplet, 0, sizeof(_pos_sp_triplet));
|
||||
memset(&_local_pos_sp, 0, sizeof(_local_pos_sp));
|
||||
memset(&_global_vel_sp, 0, sizeof(_global_vel_sp));
|
||||
|
||||
memset(&_ref_pos, 0, sizeof(_ref_pos));
|
||||
|
||||
_params.pos_p.zero();
|
||||
_params.vel_p.zero();
|
||||
_params.vel_i.zero();
|
||||
@@ -279,6 +288,8 @@ MulticopterPositionControl::MulticopterPositionControl() :
|
||||
_params.vel_ff.zero();
|
||||
_params.sp_offs_max.zero();
|
||||
|
||||
_pos.zero();
|
||||
_pos_sp.zero();
|
||||
_vel.zero();
|
||||
_vel_sp.zero();
|
||||
_vel_prev.zero();
|
||||
@@ -337,15 +348,18 @@ MulticopterPositionControl::parameters_update(bool force)
|
||||
|
||||
orb_check(_params_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(parameter_update), _params_sub, ¶m_upd);
|
||||
}
|
||||
|
||||
if (updated || force) {
|
||||
param_get(_params_handles.thr_min, &_params.thr_min);
|
||||
param_get(_params_handles.thr_max, &_params.thr_max);
|
||||
param_get(_params_handles.tilt_max, &_params.tilt_max);
|
||||
_params.tilt_max = math::radians(_params.tilt_max);
|
||||
param_get(_params_handles.land_speed, &_params.land_speed);
|
||||
param_get(_params_handles.land_tilt_max, &_params.land_tilt_max);
|
||||
_params.land_tilt_max = math::radians(_params.land_tilt_max);
|
||||
|
||||
float v;
|
||||
param_get(_params_handles.xy_p, &v);
|
||||
@@ -392,33 +406,39 @@ MulticopterPositionControl::poll_subscriptions()
|
||||
|
||||
orb_check(_att_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_attitude), _att_sub, &_att);
|
||||
}
|
||||
|
||||
orb_check(_att_sp_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_attitude_setpoint), _att_sp_sub, &_att_sp);
|
||||
}
|
||||
|
||||
orb_check(_control_mode_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_control_mode), _control_mode_sub, &_control_mode);
|
||||
}
|
||||
|
||||
orb_check(_manual_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(manual_control_setpoint), _manual_sub, &_manual);
|
||||
}
|
||||
|
||||
orb_check(_arming_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(actuator_armed), _arming_sub, &_arming);
|
||||
}
|
||||
|
||||
orb_check(_global_pos_sub, &updated);
|
||||
orb_check(_local_pos_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
orb_copy(ORB_ID(vehicle_global_position), _global_pos_sub, &_global_pos);
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_local_position), _local_pos_sub, &_local_pos);
|
||||
}
|
||||
}
|
||||
|
||||
float
|
||||
@@ -442,13 +462,40 @@ MulticopterPositionControl::task_main_trampoline(int argc, char *argv[])
|
||||
}
|
||||
|
||||
void
|
||||
MulticopterPositionControl::reset_lat_lon_sp()
|
||||
MulticopterPositionControl::update_ref()
|
||||
{
|
||||
if (_reset_lat_lon_sp) {
|
||||
_reset_lat_lon_sp = false;
|
||||
_lat_sp = _global_pos.lat;
|
||||
_lon_sp = _global_pos.lon;
|
||||
mavlink_log_info(_mavlink_fd, "[mpc] reset lat/lon sp: %.7f, %.7f", _lat_sp, _lon_sp);
|
||||
if (_local_pos.ref_timestamp != _ref_timestamp) {
|
||||
double lat_sp, lon_sp;
|
||||
float alt_sp;
|
||||
|
||||
if (_ref_timestamp != 0) {
|
||||
/* calculate current position setpoint in global frame */
|
||||
map_projection_reproject(&_ref_pos, _pos_sp(0), _pos_sp(1), &lat_sp, &lon_sp);
|
||||
alt_sp = _ref_alt - _pos_sp(2);
|
||||
}
|
||||
|
||||
/* update local projection reference */
|
||||
map_projection_init(&_ref_pos, _local_pos.ref_lat, _local_pos.ref_lon);
|
||||
_ref_alt = _local_pos.ref_alt;
|
||||
|
||||
if (_ref_timestamp != 0) {
|
||||
/* reproject position setpoint to new reference */
|
||||
map_projection_project(&_ref_pos, lat_sp, lon_sp, &_pos_sp.data[0], &_pos_sp.data[1]);
|
||||
_pos_sp(2) = -(alt_sp - _ref_alt);
|
||||
}
|
||||
|
||||
_ref_timestamp = _local_pos.ref_timestamp;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MulticopterPositionControl::reset_pos_sp()
|
||||
{
|
||||
if (_reset_pos_sp) {
|
||||
_reset_pos_sp = false;
|
||||
_pos_sp(0) = _pos(0);
|
||||
_pos_sp(1) = _pos(1);
|
||||
mavlink_log_info(_mavlink_fd, "[mpc] reset pos sp: %.2f, %.2f", (double)_pos_sp(0), (double)_pos_sp(1));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -457,25 +504,8 @@ MulticopterPositionControl::reset_alt_sp()
|
||||
{
|
||||
if (_reset_alt_sp) {
|
||||
_reset_alt_sp = false;
|
||||
_alt_sp = _use_global_alt ? _global_pos.alt : _global_pos.baro_alt;
|
||||
mavlink_log_info(_mavlink_fd, "[mpc] reset alt (%s) sp: %.2f", _use_global_alt ? "AMSL" : "baro", (double)_alt_sp);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MulticopterPositionControl::select_alt(bool global)
|
||||
{
|
||||
if (global != _use_global_alt) {
|
||||
_use_global_alt = global;
|
||||
|
||||
if (global) {
|
||||
/* switch from barometric to global altitude */
|
||||
_alt_sp += _global_pos.alt - _global_pos.baro_alt;
|
||||
|
||||
} else {
|
||||
/* switch from global to barometric altitude */
|
||||
_alt_sp += _global_pos.baro_alt - _global_pos.alt;
|
||||
}
|
||||
_pos_sp(2) = _pos(2);
|
||||
mavlink_log_info(_mavlink_fd, "[mpc] reset alt sp: %.2f", -(double)_pos_sp(2));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,7 +526,7 @@ MulticopterPositionControl::task_main()
|
||||
_params_sub = orb_subscribe(ORB_ID(parameter_update));
|
||||
_manual_sub = orb_subscribe(ORB_ID(manual_control_setpoint));
|
||||
_arming_sub = orb_subscribe(ORB_ID(actuator_armed));
|
||||
_global_pos_sub = orb_subscribe(ORB_ID(vehicle_global_position));
|
||||
_local_pos_sub = orb_subscribe(ORB_ID(vehicle_local_position));
|
||||
_pos_sp_triplet_sub = orb_subscribe(ORB_ID(position_setpoint_triplet));
|
||||
|
||||
parameters_update(true);
|
||||
@@ -527,8 +557,7 @@ MulticopterPositionControl::task_main()
|
||||
/* wakeup source */
|
||||
struct pollfd fds[1];
|
||||
|
||||
/* Setup of loop */
|
||||
fds[0].fd = _global_pos_sub;
|
||||
fds[0].fd = _local_pos_sub;
|
||||
fds[0].events = POLLIN;
|
||||
|
||||
while (!_task_should_exit) {
|
||||
@@ -536,8 +565,9 @@ MulticopterPositionControl::task_main()
|
||||
int pret = poll(&fds[0], (sizeof(fds) / sizeof(fds[0])), 500);
|
||||
|
||||
/* timed out - periodic check for _task_should_exit */
|
||||
if (pret == 0)
|
||||
if (pret == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* this is undesirable but not much we can do */
|
||||
if (pret < 0) {
|
||||
@@ -554,7 +584,7 @@ MulticopterPositionControl::task_main()
|
||||
|
||||
if (_control_mode.flag_armed && !was_armed) {
|
||||
/* reset setpoints and integrals on arming */
|
||||
_reset_lat_lon_sp = true;
|
||||
_reset_pos_sp = true;
|
||||
_reset_alt_sp = true;
|
||||
reset_int_z = true;
|
||||
reset_int_xy = true;
|
||||
@@ -562,28 +592,25 @@ MulticopterPositionControl::task_main()
|
||||
|
||||
was_armed = _control_mode.flag_armed;
|
||||
|
||||
update_ref();
|
||||
|
||||
if (_control_mode.flag_control_altitude_enabled ||
|
||||
_control_mode.flag_control_position_enabled ||
|
||||
_control_mode.flag_control_climb_rate_enabled ||
|
||||
_control_mode.flag_control_velocity_enabled) {
|
||||
|
||||
_vel(0) = _global_pos.vel_n;
|
||||
_vel(1) = _global_pos.vel_e;
|
||||
_vel(2) = _global_pos.vel_d;
|
||||
_pos(0) = _local_pos.x;
|
||||
_pos(1) = _local_pos.y;
|
||||
_pos(2) = _local_pos.z;
|
||||
|
||||
_vel(0) = _local_pos.vx;
|
||||
_vel(1) = _local_pos.vy;
|
||||
_vel(2) = _local_pos.vz;
|
||||
|
||||
sp_move_rate.zero();
|
||||
|
||||
float alt = _global_pos.alt;
|
||||
|
||||
/* select control source */
|
||||
if (_control_mode.flag_control_manual_enabled) {
|
||||
/* select altitude source and update setpoint */
|
||||
select_alt(_global_pos.global_valid);
|
||||
|
||||
if (!_use_global_alt) {
|
||||
alt = _global_pos.baro_alt;
|
||||
}
|
||||
|
||||
/* manual control */
|
||||
if (_control_mode.flag_control_altitude_enabled) {
|
||||
/* reset alt setpoint to current altitude if needed */
|
||||
@@ -594,8 +621,8 @@ MulticopterPositionControl::task_main()
|
||||
}
|
||||
|
||||
if (_control_mode.flag_control_position_enabled) {
|
||||
/* reset lat/lon setpoint to current position if needed */
|
||||
reset_lat_lon_sp();
|
||||
/* reset position setpoint to current position if needed */
|
||||
reset_pos_sp();
|
||||
|
||||
/* move position setpoint with roll/pitch stick */
|
||||
sp_move_rate(0) = _manual.pitch;
|
||||
@@ -615,74 +642,47 @@ MulticopterPositionControl::task_main()
|
||||
sp_move_rate = R_yaw_sp * sp_move_rate.emult(_params.vel_max);
|
||||
|
||||
/* move position setpoint */
|
||||
add_vector_to_global_position(_lat_sp, _lon_sp, sp_move_rate(0) * dt, sp_move_rate(1) * dt, &_lat_sp, &_lon_sp);
|
||||
_alt_sp -= sp_move_rate(2) * dt;
|
||||
_pos_sp += sp_move_rate * dt;
|
||||
|
||||
/* check if position setpoint is too far from actual position */
|
||||
math::Vector<3> pos_sp_offs;
|
||||
pos_sp_offs.zero();
|
||||
|
||||
if (_control_mode.flag_control_position_enabled) {
|
||||
get_vector_to_next_waypoint_fast(_global_pos.lat, _global_pos.lon, _lat_sp, _lon_sp, &pos_sp_offs.data[0], &pos_sp_offs.data[1]);
|
||||
pos_sp_offs(0) /= _params.sp_offs_max(0);
|
||||
pos_sp_offs(1) /= _params.sp_offs_max(1);
|
||||
pos_sp_offs(0) = (_pos_sp(0) - _pos(0)) / _params.sp_offs_max(0);
|
||||
pos_sp_offs(1) = (_pos_sp(1) - _pos(1)) / _params.sp_offs_max(1);
|
||||
}
|
||||
|
||||
if (_control_mode.flag_control_altitude_enabled) {
|
||||
pos_sp_offs(2) = -(_alt_sp - alt) / _params.sp_offs_max(2);
|
||||
pos_sp_offs(2) = (_pos_sp(2) - _pos(2)) / _params.sp_offs_max(2);
|
||||
}
|
||||
|
||||
float pos_sp_offs_norm = pos_sp_offs.length();
|
||||
|
||||
if (pos_sp_offs_norm > 1.0f) {
|
||||
pos_sp_offs /= pos_sp_offs_norm;
|
||||
add_vector_to_global_position(_global_pos.lat, _global_pos.lon, pos_sp_offs(0) * _params.sp_offs_max(0), pos_sp_offs(1) * _params.sp_offs_max(1), &_lat_sp, &_lon_sp);
|
||||
_alt_sp = alt - pos_sp_offs(2) * _params.sp_offs_max(2);
|
||||
}
|
||||
|
||||
/* fill position setpoint triplet */
|
||||
_pos_sp_triplet.previous.valid = true;
|
||||
_pos_sp_triplet.current.valid = true;
|
||||
_pos_sp_triplet.next.valid = true;
|
||||
|
||||
// _pos_sp_triplet.nav_state = NAV_STATE_NONE;
|
||||
_pos_sp_triplet.current.type = SETPOINT_TYPE_NORMAL;
|
||||
_pos_sp_triplet.current.lat = _lat_sp;
|
||||
_pos_sp_triplet.current.lon = _lon_sp;
|
||||
_pos_sp_triplet.current.alt = _alt_sp;
|
||||
_pos_sp_triplet.current.yaw = _att_sp.yaw_body;
|
||||
_pos_sp_triplet.current.loiter_radius = 0.0f;
|
||||
_pos_sp_triplet.current.loiter_direction = 1.0f;
|
||||
_pos_sp_triplet.current.pitch_min = 0.0f;
|
||||
|
||||
/* publish position setpoint triplet */
|
||||
if (_pos_sp_triplet_pub > 0) {
|
||||
orb_publish(ORB_ID(position_setpoint_triplet), _pos_sp_triplet_pub, &_pos_sp_triplet);
|
||||
|
||||
} else {
|
||||
_pos_sp_triplet_pub = orb_advertise(ORB_ID(position_setpoint_triplet), &_pos_sp_triplet);
|
||||
_pos_sp = _pos + pos_sp_offs.emult(_params.sp_offs_max);
|
||||
}
|
||||
|
||||
} else {
|
||||
/* always use AMSL altitude for AUTO */
|
||||
select_alt(true);
|
||||
|
||||
/* AUTO */
|
||||
bool updated;
|
||||
orb_check(_pos_sp_triplet_sub, &updated);
|
||||
|
||||
if (updated)
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(position_setpoint_triplet), _pos_sp_triplet_sub, &_pos_sp_triplet);
|
||||
}
|
||||
|
||||
if (_pos_sp_triplet.current.valid) {
|
||||
/* in case of interrupted mission don't go to waypoint but stay at current position */
|
||||
_reset_lat_lon_sp = true;
|
||||
_reset_pos_sp = true;
|
||||
_reset_alt_sp = true;
|
||||
|
||||
/* update position setpoint */
|
||||
_lat_sp = _pos_sp_triplet.current.lat;
|
||||
_lon_sp = _pos_sp_triplet.current.lon;
|
||||
_alt_sp = _pos_sp_triplet.current.alt;
|
||||
/* project setpoint to local frame */
|
||||
map_projection_project(&_ref_pos,
|
||||
_pos_sp_triplet.current.lat, _pos_sp_triplet.current.lon,
|
||||
&_pos_sp.data[0], &_pos_sp.data[1]);
|
||||
_pos_sp(2) = -(_pos_sp_triplet.current.alt - _ref_alt);
|
||||
|
||||
/* update yaw setpoint if needed */
|
||||
if (isfinite(_pos_sp_triplet.current.yaw)) {
|
||||
@@ -691,11 +691,25 @@ MulticopterPositionControl::task_main()
|
||||
|
||||
} else {
|
||||
/* no waypoint, loiter, reset position setpoint if needed */
|
||||
reset_lat_lon_sp();
|
||||
reset_pos_sp();
|
||||
reset_alt_sp();
|
||||
}
|
||||
}
|
||||
|
||||
/* fill local position setpoint */
|
||||
_local_pos_sp.x = _pos_sp(0);
|
||||
_local_pos_sp.y = _pos_sp(1);
|
||||
_local_pos_sp.z = _pos_sp(2);
|
||||
_local_pos_sp.yaw = _att_sp.yaw_body;
|
||||
|
||||
/* publish local position setpoint */
|
||||
if (_local_pos_sp_pub > 0) {
|
||||
orb_publish(ORB_ID(vehicle_local_position_setpoint), _local_pos_sp_pub, &_local_pos_sp);
|
||||
|
||||
} else {
|
||||
_local_pos_sp_pub = orb_advertise(ORB_ID(vehicle_local_position_setpoint), &_local_pos_sp);
|
||||
}
|
||||
|
||||
if (!_control_mode.flag_control_manual_enabled && _pos_sp_triplet.current.valid && _pos_sp_triplet.current.type == SETPOINT_TYPE_IDLE) {
|
||||
/* idle state, don't run controller and set zero thrust */
|
||||
R.identity();
|
||||
@@ -719,9 +733,7 @@ MulticopterPositionControl::task_main()
|
||||
|
||||
} else {
|
||||
/* run position & altitude controllers, calculate velocity setpoint */
|
||||
math::Vector<3> pos_err;
|
||||
get_vector_to_next_waypoint_fast(_global_pos.lat, _global_pos.lon, _lat_sp, _lon_sp, &pos_err.data[0], &pos_err.data[1]);
|
||||
pos_err(2) = -(_alt_sp - alt);
|
||||
math::Vector<3> pos_err = _pos_sp - _pos;
|
||||
|
||||
_vel_sp = pos_err.emult(_params.pos_p) + sp_move_rate.emult(_params.vel_ff);
|
||||
|
||||
@@ -731,7 +743,7 @@ MulticopterPositionControl::task_main()
|
||||
}
|
||||
|
||||
if (!_control_mode.flag_control_position_enabled) {
|
||||
_reset_lat_lon_sp = true;
|
||||
_reset_pos_sp = true;
|
||||
_vel_sp(0) = 0.0f;
|
||||
_vel_sp(1) = 0.0f;
|
||||
}
|
||||
@@ -837,8 +849,9 @@ MulticopterPositionControl::task_main()
|
||||
/* limit max tilt and min lift when landing */
|
||||
tilt_max = _params.land_tilt_max;
|
||||
|
||||
if (thr_min < 0.0f)
|
||||
if (thr_min < 0.0f) {
|
||||
thr_min = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* limit min lift */
|
||||
@@ -929,8 +942,9 @@ MulticopterPositionControl::task_main()
|
||||
thrust_int(2) += vel_err(2) * _params.vel_i(2) * dt;
|
||||
|
||||
/* protection against flipping on ground when landing */
|
||||
if (thrust_int(2) > 0.0f)
|
||||
if (thrust_int(2) > 0.0f) {
|
||||
thrust_int(2) = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate attitude setpoint from thrust vector */
|
||||
@@ -989,6 +1003,18 @@ MulticopterPositionControl::task_main()
|
||||
_att_sp.roll_body = euler(0);
|
||||
_att_sp.pitch_body = euler(1);
|
||||
/* yaw already used to construct rot matrix, but actual rotation matrix can have different yaw near singularity */
|
||||
|
||||
} else if (!_control_mode.flag_control_manual_enabled) {
|
||||
/* autonomous altitude control without position control (failsafe landing),
|
||||
* force level attitude, don't change yaw */
|
||||
R.from_euler(0.0f, 0.0f, _att_sp.yaw_body);
|
||||
|
||||
/* copy rotation matrix to attitude setpoint topic */
|
||||
memcpy(&_att_sp.R_body[0][0], R.data, sizeof(_att_sp.R_body));
|
||||
_att_sp.R_valid = true;
|
||||
|
||||
_att_sp.roll_body = 0.0f;
|
||||
_att_sp.pitch_body = 0.0f;
|
||||
}
|
||||
|
||||
_att_sp.thrust = thrust_abs;
|
||||
@@ -1011,7 +1037,7 @@ MulticopterPositionControl::task_main()
|
||||
} else {
|
||||
/* position controller disabled, reset setpoints */
|
||||
_reset_alt_sp = true;
|
||||
_reset_lat_lon_sp = true;
|
||||
_reset_pos_sp = true;
|
||||
reset_int_z = true;
|
||||
reset_int_xy = true;
|
||||
}
|
||||
@@ -1050,18 +1076,21 @@ MulticopterPositionControl::start()
|
||||
|
||||
int mc_pos_control_main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 1)
|
||||
if (argc < 1) {
|
||||
errx(1, "usage: mc_pos_control {start|stop|status}");
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
|
||||
if (pos_control::g_control != nullptr)
|
||||
if (pos_control::g_control != nullptr) {
|
||||
errx(1, "already running");
|
||||
}
|
||||
|
||||
pos_control::g_control = new MulticopterPositionControl;
|
||||
|
||||
if (pos_control::g_control == nullptr)
|
||||
if (pos_control::g_control == nullptr) {
|
||||
errx(1, "alloc failed");
|
||||
}
|
||||
|
||||
if (OK != pos_control::g_control->start()) {
|
||||
delete pos_control::g_control;
|
||||
@@ -1073,8 +1102,9 @@ int mc_pos_control_main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "stop")) {
|
||||
if (pos_control::g_control == nullptr)
|
||||
if (pos_control::g_control == nullptr) {
|
||||
errx(1, "not running");
|
||||
}
|
||||
|
||||
delete pos_control::g_control;
|
||||
pos_control::g_control = nullptr;
|
||||
|
||||
@@ -100,6 +100,7 @@ PARAM_DEFINE_FLOAT(MPC_Z_VEL_D, 0.0f);
|
||||
*
|
||||
* Maximum vertical velocity in AUTO mode and endpoint for stabilized modes (SEATBELT, EASY).
|
||||
*
|
||||
* @unit m/s
|
||||
* @min 0.0
|
||||
* @group Multicopter Position Control
|
||||
*/
|
||||
@@ -155,6 +156,7 @@ PARAM_DEFINE_FLOAT(MPC_XY_VEL_D, 0.01f);
|
||||
*
|
||||
* Maximum horizontal velocity in AUTO mode and endpoint for position stabilized mode (EASY).
|
||||
*
|
||||
* @unit m/s
|
||||
* @min 0.0
|
||||
* @group Multicopter Position Control
|
||||
*/
|
||||
@@ -176,15 +178,17 @@ PARAM_DEFINE_FLOAT(MPC_XY_FF, 0.5f);
|
||||
*
|
||||
* Limits maximum tilt in AUTO and EASY modes.
|
||||
*
|
||||
* @unit deg
|
||||
* @min 0.0
|
||||
* @max 1.57
|
||||
* @max 90.0
|
||||
* @group Multicopter Position Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(MPC_TILT_MAX, 1.0f);
|
||||
PARAM_DEFINE_FLOAT(MPC_TILT_MAX, 45.0f);
|
||||
|
||||
/**
|
||||
* Landing descend rate
|
||||
*
|
||||
* @unit m/s
|
||||
* @min 0.0
|
||||
* @group Multicopter Position Control
|
||||
*/
|
||||
@@ -195,8 +199,9 @@ PARAM_DEFINE_FLOAT(MPC_LAND_SPEED, 1.0f);
|
||||
*
|
||||
* Limits maximum tilt on landing.
|
||||
*
|
||||
* @unit deg
|
||||
* @min 0.0
|
||||
* @max 1.57
|
||||
* @max 90.0
|
||||
* @group Multicopter Position Control
|
||||
*/
|
||||
PARAM_DEFINE_FLOAT(MPC_LAND_TILT, 0.3f);
|
||||
PARAM_DEFINE_FLOAT(MPC_LAND_TILT, 15.0f);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2013 Anton Babushkin. All rights reserved.
|
||||
* Author: Anton Babushkin <rk3dov@gmail.com>
|
||||
* Copyright (C) 2013, 2014 PX4 Development Team. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,6 +34,8 @@
|
||||
/**
|
||||
* @file position_estimator_inav_main.c
|
||||
* Model-identification based position estimator for multirotors
|
||||
*
|
||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
@@ -57,6 +58,7 @@
|
||||
#include <uORB/topics/vehicle_local_position.h>
|
||||
#include <uORB/topics/vehicle_global_position.h>
|
||||
#include <uORB/topics/vehicle_gps_position.h>
|
||||
#include <uORB/topics/home_position.h>
|
||||
#include <uORB/topics/optical_flow.h>
|
||||
#include <mavlink/mavlink_log.h>
|
||||
#include <poll.h>
|
||||
@@ -95,8 +97,9 @@ static void usage(const char *reason);
|
||||
*/
|
||||
static void usage(const char *reason)
|
||||
{
|
||||
if (reason)
|
||||
if (reason) {
|
||||
fprintf(stderr, "%s\n", reason);
|
||||
}
|
||||
|
||||
fprintf(stderr, "usage: position_estimator_inav {start|stop|status} [-v]\n\n");
|
||||
exit(1);
|
||||
@@ -112,8 +115,9 @@ static void usage(const char *reason)
|
||||
*/
|
||||
int position_estimator_inav_main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 1)
|
||||
if (argc < 1) {
|
||||
usage("missing command");
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "start")) {
|
||||
if (thread_running) {
|
||||
@@ -125,8 +129,9 @@ int position_estimator_inav_main(int argc, char *argv[])
|
||||
verbose_mode = false;
|
||||
|
||||
if (argc > 1)
|
||||
if (!strcmp(argv[2], "-v"))
|
||||
if (!strcmp(argv[2], "-v")) {
|
||||
verbose_mode = true;
|
||||
}
|
||||
|
||||
thread_should_exit = false;
|
||||
position_estimator_inav_task = task_spawn_cmd("position_estimator_inav",
|
||||
@@ -163,16 +168,19 @@ int position_estimator_inav_main(int argc, char *argv[])
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void write_debug_log(const char *msg, float dt, float x_est[3], float y_est[3], float z_est[3], float corr_acc[3], float corr_gps[3][2], float w_xy_gps_p, float w_xy_gps_v) {
|
||||
void write_debug_log(const char *msg, float dt, float x_est[3], float y_est[3], float z_est[3], float x_est_prev[3], float y_est_prev[3], float z_est_prev[3], float corr_acc[3], float corr_gps[3][2], float w_xy_gps_p, float w_xy_gps_v)
|
||||
{
|
||||
FILE *f = fopen("/fs/microsd/inav.log", "a");
|
||||
|
||||
if (f) {
|
||||
char *s = malloc(256);
|
||||
unsigned n = snprintf(s, 256, "%llu %s\n\tdt=%.5f x_est=[%.5f %.5f %.5f] y_est=[%.5f %.5f %.5f] z_est=[%.5f %.5f %.5f]\n", hrt_absolute_time(), msg, dt, x_est[0], x_est[1], x_est[2], y_est[0], y_est[1], y_est[2], z_est[0], z_est[1], z_est[2]);
|
||||
unsigned n = snprintf(s, 256, "%llu %s\n\tdt=%.5f x_est=[%.5f %.5f %.5f] y_est=[%.5f %.5f %.5f] z_est=[%.5f %.5f %.5f] x_est_prev=[%.5f %.5f %.5f] y_est_prev=[%.5f %.5f %.5f] z_est_prev=[%.5f %.5f %.5f]\n", hrt_absolute_time(), msg, dt, x_est[0], x_est[1], x_est[2], y_est[0], y_est[1], y_est[2], z_est[0], z_est[1], z_est[2], x_est_prev[0], x_est_prev[1], x_est_prev[2], y_est_prev[0], y_est_prev[1], y_est_prev[2], z_est_prev[0], z_est_prev[1], z_est_prev[2]);
|
||||
fwrite(s, 1, n, f);
|
||||
n = snprintf(s, 256, "\tacc_corr=[%.5f %.5f %.5f] gps_pos_corr=[%.5f %.5f %.5f] gps_vel_corr=[%.5f %.5f %.5f] w_xy_gps_p=%.5f w_xy_gps_v=%.5f\n", corr_acc[0], corr_acc[1], corr_acc[2], corr_gps[0][0], corr_gps[1][0], corr_gps[2][0], corr_gps[0][1], corr_gps[1][1], corr_gps[2][1], w_xy_gps_p, w_xy_gps_v);
|
||||
fwrite(s, 1, n, f);
|
||||
free(s);
|
||||
}
|
||||
|
||||
fsync(fileno(f));
|
||||
fclose(f);
|
||||
}
|
||||
@@ -191,6 +199,11 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
float y_est[3] = { 0.0f, 0.0f, 0.0f };
|
||||
float z_est[3] = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
float x_est_prev[3], y_est_prev[3], z_est_prev[3];
|
||||
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
|
||||
@@ -206,6 +219,9 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
bool ref_inited = false;
|
||||
hrt_abstime ref_init_start = 0;
|
||||
const hrt_abstime ref_init_delay = 1000000; // wait for 1s after 3D fix
|
||||
struct map_projection_reference_s ref;
|
||||
memset(&ref, 0, sizeof(ref));
|
||||
hrt_abstime home_timestamp = 0;
|
||||
|
||||
uint16_t accel_updates = 0;
|
||||
uint16_t baro_updates = 0;
|
||||
@@ -238,7 +254,11 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
float corr_flow[] = { 0.0f, 0.0f }; // N E
|
||||
float w_flow = 0.0f;
|
||||
|
||||
static float min_eph_epv = 2.0f; // min EPH/EPV, used for weight calculation
|
||||
static float max_eph_epv = 10.0f; // max EPH/EPV acceptable for estimation
|
||||
|
||||
float sonar_prev = 0.0f;
|
||||
hrt_abstime flow_prev = 0; // time of last flow measurement
|
||||
hrt_abstime sonar_time = 0; // time of last sonar measurement (not filtered)
|
||||
hrt_abstime sonar_valid_time = 0; // time of last sonar measurement used for correction (filtered)
|
||||
hrt_abstime xy_src_time = 0; // time of last available position data
|
||||
@@ -257,6 +277,8 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
memset(&sensor, 0, sizeof(sensor));
|
||||
struct vehicle_gps_position_s gps;
|
||||
memset(&gps, 0, sizeof(gps));
|
||||
struct home_position_s home;
|
||||
memset(&home, 0, sizeof(home));
|
||||
struct vehicle_attitude_s att;
|
||||
memset(&att, 0, sizeof(att));
|
||||
struct vehicle_local_position_s local_pos;
|
||||
@@ -274,10 +296,11 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
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 home_position_sub = orb_subscribe(ORB_ID(home_position));
|
||||
|
||||
/* advertise */
|
||||
orb_advert_t vehicle_local_position_pub = orb_advertise(ORB_ID(vehicle_local_position), &local_pos);
|
||||
orb_advert_t vehicle_global_position_pub = orb_advertise(ORB_ID(vehicle_global_position), &global_pos);
|
||||
orb_advert_t vehicle_global_position_pub = -1;
|
||||
|
||||
struct position_estimator_inav_params params;
|
||||
struct position_estimator_inav_param_handles pos_inav_param_handles;
|
||||
@@ -325,7 +348,6 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
mavlink_log_info(mavlink_fd, "[inav] baro offs: %.2f", baro_offset);
|
||||
local_pos.z_valid = true;
|
||||
local_pos.v_z_valid = true;
|
||||
global_pos.baro_valid = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -425,6 +447,10 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(optical_flow), optical_flow_sub, &flow);
|
||||
|
||||
/* calculate time from previous update */
|
||||
float flow_dt = flow_prev > 0 ? (flow.flow_timestamp - flow_prev) * 1e-6f : 0.1f;
|
||||
flow_prev = flow.flow_timestamp;
|
||||
|
||||
if (flow.ground_distance_m > 0.31f && flow.ground_distance_m < 4.0f && att.R[2][2] > 0.7 && flow.ground_distance_m != sonar_prev) {
|
||||
sonar_time = t;
|
||||
sonar_prev = flow.ground_distance_m;
|
||||
@@ -475,10 +501,10 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
flow_accurate = fabsf(body_v_est[1] / flow_dist - att.rollspeed) < max_flow &&
|
||||
fabsf(body_v_est[0] / flow_dist + att.pitchspeed) < max_flow;
|
||||
|
||||
/* convert raw flow to angular flow */
|
||||
/* convert raw flow to angular flow (rad/s) */
|
||||
float flow_ang[2];
|
||||
flow_ang[0] = flow.flow_raw_x * params.flow_k;
|
||||
flow_ang[1] = flow.flow_raw_y * params.flow_k;
|
||||
flow_ang[0] = flow.flow_raw_x * params.flow_k / 1000.0f / flow_dt;
|
||||
flow_ang[1] = flow.flow_raw_y * params.flow_k / 1000.0f / flow_dt;
|
||||
/* flow measurements vector */
|
||||
float flow_m[3];
|
||||
flow_m[0] = -flow_ang[0] * flow_dist;
|
||||
@@ -503,8 +529,9 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
|
||||
/* if flow is not accurate, reduce weight for it */
|
||||
// TODO make this more fuzzy
|
||||
if (!flow_accurate)
|
||||
if (!flow_accurate) {
|
||||
w_flow *= 0.05f;
|
||||
}
|
||||
|
||||
flow_valid = true;
|
||||
|
||||
@@ -516,32 +543,73 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
flow_updates++;
|
||||
}
|
||||
|
||||
/* home position */
|
||||
orb_check(home_position_sub, &updated);
|
||||
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(home_position), home_position_sub, &home);
|
||||
|
||||
if (home.timestamp != home_timestamp) {
|
||||
home_timestamp = home.timestamp;
|
||||
|
||||
double est_lat, est_lon;
|
||||
float est_alt;
|
||||
|
||||
if (ref_inited) {
|
||||
/* calculate current estimated position in global frame */
|
||||
est_alt = local_pos.ref_alt - local_pos.z;
|
||||
map_projection_reproject(&ref, local_pos.x, local_pos.y, &est_lat, &est_lon);
|
||||
}
|
||||
|
||||
/* update reference */
|
||||
map_projection_init(&ref, home.lat, home.lon);
|
||||
|
||||
/* update baro offset */
|
||||
baro_offset += home.alt - local_pos.ref_alt;
|
||||
|
||||
local_pos.ref_lat = home.lat;
|
||||
local_pos.ref_lon = home.lon;
|
||||
local_pos.ref_alt = home.alt;
|
||||
local_pos.ref_timestamp = home.timestamp;
|
||||
|
||||
if (ref_inited) {
|
||||
/* reproject position estimate with new reference */
|
||||
map_projection_project(&ref, est_lat, est_lon, &x_est[0], &y_est[0]);
|
||||
z_est[0] = -(est_alt - local_pos.ref_alt);
|
||||
}
|
||||
|
||||
ref_inited = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* vehicle GPS position */
|
||||
orb_check(vehicle_gps_position_sub, &updated);
|
||||
|
||||
if (updated) {
|
||||
orb_copy(ORB_ID(vehicle_gps_position), vehicle_gps_position_sub, &gps);
|
||||
|
||||
if (gps.fix_type >= 3) {
|
||||
/* hysteresis for GPS quality */
|
||||
if (gps_valid) {
|
||||
if (gps.eph_m > 10.0f || gps.epv_m > 20.0f) {
|
||||
gps_valid = false;
|
||||
mavlink_log_info(mavlink_fd, "[inav] GPS signal lost");
|
||||
}
|
||||
bool reset_est = false;
|
||||
|
||||
} else {
|
||||
if (gps.eph_m < 5.0f && gps.epv_m < 10.0f) {
|
||||
gps_valid = true;
|
||||
mavlink_log_info(mavlink_fd, "[inav] GPS signal found");
|
||||
}
|
||||
/* hysteresis for GPS quality */
|
||||
if (gps_valid) {
|
||||
if (gps.eph_m > max_eph_epv * 1.5f || gps.epv_m > max_eph_epv * 1.5f || gps.fix_type < 3) {
|
||||
gps_valid = false;
|
||||
mavlink_log_info(mavlink_fd, "[inav] GPS signal lost");
|
||||
}
|
||||
|
||||
} else {
|
||||
gps_valid = false;
|
||||
if (gps.eph_m < max_eph_epv && gps.epv_m < max_eph_epv && gps.fix_type >= 3) {
|
||||
gps_valid = true;
|
||||
reset_est = true;
|
||||
mavlink_log_info(mavlink_fd, "[inav] GPS signal found");
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (ref_init_start == 0) {
|
||||
@@ -549,18 +617,25 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
|
||||
} else if (t > ref_init_start + ref_init_delay) {
|
||||
ref_inited = true;
|
||||
/* reference GPS position */
|
||||
double lat = gps.lat * 1e-7;
|
||||
double lon = gps.lon * 1e-7;
|
||||
float alt = gps.alt * 1e-3;
|
||||
/* update baro offset */
|
||||
baro_offset -= z_est[0];
|
||||
|
||||
local_pos.ref_lat = gps.lat;
|
||||
local_pos.ref_lon = gps.lon;
|
||||
local_pos.ref_alt = alt + z_est[0];
|
||||
/* 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;
|
||||
x_est[2] = accel_NED[0];
|
||||
y_est[0] = 0.0f;
|
||||
y_est[1] = gps.vel_e_m_s;
|
||||
z_est[0] = 0.0f;
|
||||
y_est[2] = accel_NED[1];
|
||||
|
||||
local_pos.ref_lat = lat;
|
||||
local_pos.ref_lon = lon;
|
||||
local_pos.ref_alt = alt;
|
||||
local_pos.ref_timestamp = t;
|
||||
|
||||
/* initialize projection */
|
||||
map_projection_init(lat, lon);
|
||||
map_projection_init(&ref, lat, lon);
|
||||
warnx("init ref: lat=%.7f, lon=%.7f, alt=%.2f", lat, lon, alt);
|
||||
mavlink_log_info(mavlink_fd, "[inav] init ref: lat=%.7f, lon=%.7f, alt=%.2f", lat, lon, alt);
|
||||
}
|
||||
@@ -569,11 +644,22 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
if (ref_inited) {
|
||||
/* project GPS lat lon to plane */
|
||||
float gps_proj[2];
|
||||
map_projection_project(gps.lat * 1e-7, gps.lon * 1e-7, &(gps_proj[0]), &(gps_proj[1]));
|
||||
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;
|
||||
x_est[2] = accel_NED[0];
|
||||
y_est[0] = gps_proj[1];
|
||||
y_est[1] = gps.vel_e_m_s;
|
||||
y_est[2] = accel_NED[1];
|
||||
}
|
||||
|
||||
/* calculate correction for position */
|
||||
corr_gps[0][0] = gps_proj[0] - x_est[0];
|
||||
corr_gps[1][0] = gps_proj[1] - y_est[0];
|
||||
corr_gps[2][0] = local_pos.ref_alt - gps.alt * 1e-3 - z_est[0];
|
||||
corr_gps[2][0] = local_pos.ref_alt - alt - z_est[0];
|
||||
|
||||
/* calculate correction for velocity */
|
||||
if (gps.vel_ned_valid) {
|
||||
@@ -587,8 +673,8 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
corr_gps[2][1] = 0.0f;
|
||||
}
|
||||
|
||||
w_gps_xy = 2.0f / fmaxf(2.0f, gps.eph_m);
|
||||
w_gps_z = 4.0f / fmaxf(4.0f, gps.epv_m);
|
||||
w_gps_xy = min_eph_epv / fmaxf(min_eph_epv, gps.eph_m);
|
||||
w_gps_z = min_eph_epv / fmaxf(min_eph_epv, gps.epv_m);
|
||||
}
|
||||
|
||||
} else {
|
||||
@@ -704,23 +790,34 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
/* inertial filter prediction for altitude */
|
||||
inertial_filter_predict(dt, z_est);
|
||||
|
||||
if (!(isfinite(z_est[0]) && isfinite(z_est[1]) && isfinite(z_est[2]))) {
|
||||
write_debug_log("BAD ESTIMATE AFTER Z PREDICTION", dt, x_est, y_est, z_est, x_est_prev, y_est_prev, z_est_prev, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
memcpy(z_est, z_est_prev, sizeof(z_est));
|
||||
}
|
||||
|
||||
/* inertial filter correction for altitude */
|
||||
inertial_filter_correct(corr_baro, dt, z_est, 0, params.w_z_baro);
|
||||
inertial_filter_correct(corr_gps[2][0], dt, z_est, 0, w_z_gps_p);
|
||||
inertial_filter_correct(corr_acc[2], dt, z_est, 2, params.w_z_acc);
|
||||
|
||||
float x_est_prev[3], y_est_prev[3];
|
||||
if (!(isfinite(z_est[0]) && isfinite(z_est[1]) && isfinite(z_est[2]))) {
|
||||
write_debug_log("BAD ESTIMATE AFTER Z CORRECTION", dt, x_est, y_est, z_est, x_est_prev, y_est_prev, z_est_prev, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
memcpy(z_est, z_est_prev, sizeof(z_est));
|
||||
memset(corr_acc, 0, sizeof(corr_acc));
|
||||
memset(corr_gps, 0, sizeof(corr_gps));
|
||||
corr_baro = 0;
|
||||
|
||||
memcpy(x_est_prev, x_est, sizeof(x_est));
|
||||
memcpy(y_est_prev, y_est, sizeof(y_est));
|
||||
} else {
|
||||
memcpy(z_est_prev, z_est, sizeof(z_est));
|
||||
}
|
||||
|
||||
if (can_estimate_xy) {
|
||||
/* inertial filter prediction for position */
|
||||
inertial_filter_predict(dt, x_est);
|
||||
inertial_filter_predict(dt, y_est);
|
||||
|
||||
if (!isfinite(x_est[0]) || !isfinite(y_est[0])) {
|
||||
write_debug_log("BAD ESTIMATE AFTER PREDICTION", dt, x_est, y_est, z_est, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
if (!(isfinite(x_est[0]) && isfinite(x_est[1]) && isfinite(x_est[2]) && isfinite(y_est[0]) && isfinite(y_est[1]) && isfinite(y_est[2]))) {
|
||||
write_debug_log("BAD ESTIMATE AFTER PREDICTION", dt, x_est, y_est, z_est, x_est_prev, y_est_prev, z_est_prev, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
memcpy(x_est, x_est_prev, sizeof(x_est));
|
||||
memcpy(y_est, y_est_prev, sizeof(y_est));
|
||||
}
|
||||
@@ -744,13 +841,17 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
if (!isfinite(x_est[0]) || !isfinite(y_est[0])) {
|
||||
write_debug_log("BAD ESTIMATE AFTER CORRECTION", dt, x_est, y_est, z_est, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
if (!(isfinite(x_est[0]) && isfinite(x_est[1]) && isfinite(x_est[2]) && isfinite(y_est[0]) && isfinite(y_est[1]) && isfinite(y_est[2]))) {
|
||||
write_debug_log("BAD ESTIMATE AFTER CORRECTION", dt, x_est, y_est, z_est, x_est_prev, y_est_prev, z_est_prev, corr_acc, corr_gps, w_xy_gps_p, w_xy_gps_v);
|
||||
memcpy(x_est, x_est_prev, sizeof(x_est));
|
||||
memcpy(y_est, y_est_prev, sizeof(y_est));
|
||||
memset(corr_acc, 0, sizeof(corr_acc));
|
||||
memset(corr_gps, 0, sizeof(corr_gps));
|
||||
memset(corr_flow, 0, sizeof(corr_flow));
|
||||
|
||||
} else {
|
||||
memcpy(x_est_prev, x_est, sizeof(x_est));
|
||||
memcpy(y_est_prev, y_est, sizeof(y_est));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -808,7 +909,7 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
if (t > pub_last + pub_interval) {
|
||||
pub_last = t;
|
||||
/* publish local position */
|
||||
local_pos.xy_valid = can_estimate_xy && use_gps_xy;
|
||||
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;
|
||||
@@ -831,40 +932,35 @@ int position_estimator_inav_thread_main(int argc, char *argv[])
|
||||
|
||||
orb_publish(ORB_ID(vehicle_local_position), vehicle_local_position_pub, &local_pos);
|
||||
|
||||
/* publish global position */
|
||||
global_pos.global_valid = local_pos.xy_global;
|
||||
if (local_pos.xy_global && local_pos.z_global) {
|
||||
/* publish global position */
|
||||
global_pos.timestamp = t;
|
||||
global_pos.time_gps_usec = gps.time_gps_usec;
|
||||
|
||||
if (local_pos.xy_global) {
|
||||
double est_lat, est_lon;
|
||||
map_projection_reproject(local_pos.x, local_pos.y, &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.time_gps_usec = gps.time_gps_usec;
|
||||
}
|
||||
global_pos.alt = local_pos.ref_alt - local_pos.z;
|
||||
|
||||
/* set valid values even if position is not valid */
|
||||
if (local_pos.v_xy_valid) {
|
||||
global_pos.vel_n = local_pos.vx;
|
||||
global_pos.vel_e = local_pos.vy;
|
||||
}
|
||||
|
||||
if (local_pos.z_global) {
|
||||
global_pos.alt = local_pos.ref_alt - local_pos.z;
|
||||
}
|
||||
|
||||
if (local_pos.z_valid) {
|
||||
global_pos.baro_alt = baro_offset - local_pos.z;
|
||||
}
|
||||
|
||||
if (local_pos.v_z_valid) {
|
||||
global_pos.vel_d = local_pos.vz;
|
||||
|
||||
global_pos.yaw = local_pos.yaw;
|
||||
|
||||
// TODO implement dead-reckoning
|
||||
global_pos.eph = gps.eph_m;
|
||||
global_pos.epv = gps.epv_m;
|
||||
|
||||
if (vehicle_global_position_pub < 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
global_pos.yaw = local_pos.yaw;
|
||||
|
||||
global_pos.timestamp = t;
|
||||
|
||||
orb_publish(ORB_ID(vehicle_global_position), vehicle_global_position_pub, &global_pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ PARAM_DEFINE_FLOAT(INAV_W_XY_ACC, 20.0f);
|
||||
PARAM_DEFINE_FLOAT(INAV_W_XY_FLOW, 5.0f);
|
||||
PARAM_DEFINE_FLOAT(INAV_W_GPS_FLOW, 0.1f);
|
||||
PARAM_DEFINE_FLOAT(INAV_W_ACC_BIAS, 0.05f);
|
||||
PARAM_DEFINE_FLOAT(INAV_FLOW_K, 0.0165f);
|
||||
PARAM_DEFINE_FLOAT(INAV_FLOW_K, 0.15f);
|
||||
PARAM_DEFINE_FLOAT(INAV_FLOW_Q_MIN, 0.5f);
|
||||
PARAM_DEFINE_FLOAT(INAV_SONAR_FILT, 0.05f);
|
||||
PARAM_DEFINE_FLOAT(INAV_SONAR_ERR, 0.5f);
|
||||
|
||||
@@ -960,6 +960,7 @@ int sdlog2_thread_main(int argc, char *argv[])
|
||||
log_msg.msg_type = LOG_STAT_MSG;
|
||||
log_msg.body.log_STAT.main_state = (uint8_t) buf_status.main_state;
|
||||
log_msg.body.log_STAT.arming_state = (uint8_t) buf_status.arming_state;
|
||||
log_msg.body.log_STAT.failsafe_state = (uint8_t) buf_status.failsafe_state;
|
||||
log_msg.body.log_STAT.battery_remaining = buf_status.battery_remaining;
|
||||
log_msg.body.log_STAT.battery_warning = (uint8_t) buf_status.battery_warning;
|
||||
log_msg.body.log_STAT.landed = (uint8_t) buf_status.condition_landed;
|
||||
@@ -1101,8 +1102,8 @@ int sdlog2_thread_main(int argc, char *argv[])
|
||||
log_msg.body.log_LPOS.vx = buf.local_pos.vx;
|
||||
log_msg.body.log_LPOS.vy = buf.local_pos.vy;
|
||||
log_msg.body.log_LPOS.vz = buf.local_pos.vz;
|
||||
log_msg.body.log_LPOS.ref_lat = buf.local_pos.ref_lat;
|
||||
log_msg.body.log_LPOS.ref_lon = buf.local_pos.ref_lon;
|
||||
log_msg.body.log_LPOS.ref_lat = buf.local_pos.ref_lat * 1e7;
|
||||
log_msg.body.log_LPOS.ref_lon = buf.local_pos.ref_lon * 1e7;
|
||||
log_msg.body.log_LPOS.ref_alt = buf.local_pos.ref_alt;
|
||||
log_msg.body.log_LPOS.xy_flags = (buf.local_pos.xy_valid ? 1 : 0) | (buf.local_pos.v_xy_valid ? 2 : 0) | (buf.local_pos.xy_global ? 8 : 0);
|
||||
log_msg.body.log_LPOS.z_flags = (buf.local_pos.z_valid ? 1 : 0) | (buf.local_pos.v_z_valid ? 2 : 0) | (buf.local_pos.z_global ? 8 : 0);
|
||||
@@ -1130,8 +1131,8 @@ int sdlog2_thread_main(int argc, char *argv[])
|
||||
log_msg.body.log_GPOS.vel_n = buf.global_pos.vel_n;
|
||||
log_msg.body.log_GPOS.vel_e = buf.global_pos.vel_e;
|
||||
log_msg.body.log_GPOS.vel_d = buf.global_pos.vel_d;
|
||||
log_msg.body.log_GPOS.baro_alt = buf.global_pos.baro_alt;
|
||||
log_msg.body.log_GPOS.flags = (buf.global_pos.baro_valid ? 1 : 0) | (buf.global_pos.global_valid ? 2 : 0);
|
||||
log_msg.body.log_GPOS.eph = buf.global_pos.eph;
|
||||
log_msg.body.log_GPOS.epv = buf.global_pos.epv;
|
||||
LOGBUFFER_WRITE_AND_COUNT(GPOS);
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ struct log_ATTC_s {
|
||||
struct log_STAT_s {
|
||||
uint8_t main_state;
|
||||
uint8_t arming_state;
|
||||
uint8_t failsafe_state;
|
||||
float battery_remaining;
|
||||
uint8_t battery_warning;
|
||||
uint8_t landed;
|
||||
@@ -210,8 +211,8 @@ struct log_GPOS_s {
|
||||
float vel_n;
|
||||
float vel_e;
|
||||
float vel_d;
|
||||
float baro_alt;
|
||||
uint8_t flags;
|
||||
float eph;
|
||||
float epv;
|
||||
};
|
||||
|
||||
/* --- GPSP - GLOBAL POSITION SETPOINT --- */
|
||||
@@ -351,13 +352,13 @@ static const struct log_format_s log_formats[] = {
|
||||
LOG_FORMAT(LPSP, "ffff", "X,Y,Z,Yaw"),
|
||||
LOG_FORMAT(GPS, "QBffLLfffff", "GPSTime,FixType,EPH,EPV,Lat,Lon,Alt,VelN,VelE,VelD,Cog"),
|
||||
LOG_FORMAT(ATTC, "ffff", "Roll,Pitch,Yaw,Thrust"),
|
||||
LOG_FORMAT(STAT, "BBfBB", "MainState,ArmState,BatRem,BatWarn,Landed"),
|
||||
LOG_FORMAT(RC, "ffffffffB", "Ch0,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Count"),
|
||||
LOG_FORMAT(STAT, "BBBfBB", "MainState,ArmState,FailsafeState,BatRem,BatWarn,Landed"),
|
||||
LOG_FORMAT(RC, "ffffffffBB", "Ch0,Ch1,Ch2,Ch3,Ch4,Ch5,Ch6,Ch7,Count,SignalLost"),
|
||||
LOG_FORMAT(OUT0, "ffffffff", "Out0,Out1,Out2,Out3,Out4,Out5,Out6,Out7"),
|
||||
LOG_FORMAT(AIRS, "fff", "IndSpeed,TrueSpeed,AirTemp"),
|
||||
LOG_FORMAT(ARSP, "fff", "RollRateSP,PitchRateSP,YawRateSP"),
|
||||
LOG_FORMAT(FLOW, "hhfffBB", "RawX,RawY,CompX,CompY,Dist,Q,SensID"),
|
||||
LOG_FORMAT(GPOS, "LLfffffB", "Lat,Lon,Alt,VelN,VelE,VelD,BaroAlt,Flags"),
|
||||
LOG_FORMAT(GPOS, "LLffffff", "Lat,Lon,Alt,VelN,VelE,VelD,EPH,EPV"),
|
||||
LOG_FORMAT(GPSP, "BLLffBfbf", "NavState,Lat,Lon,Alt,Yaw,Type,LoitR,LoitDir,PitMin"),
|
||||
LOG_FORMAT(ESC, "HBBBHHHHHHfH", "count,nESC,Conn,N,Ver,Adr,Volt,Amp,RPM,Temp,SetP,SetPRAW"),
|
||||
LOG_FORMAT(GVSP, "fff", "VX,VY,VZ"),
|
||||
|
||||
@@ -594,13 +594,13 @@ PARAM_DEFINE_INT32(RC_MAP_RETURN_SW, 0);
|
||||
PARAM_DEFINE_INT32(RC_MAP_ASSIST_SW, 0);
|
||||
|
||||
/**
|
||||
* Mission switch channel mapping.
|
||||
* Loiter switch channel mapping.
|
||||
*
|
||||
* @min 0
|
||||
* @max 18
|
||||
* @group Radio Calibration
|
||||
*/
|
||||
PARAM_DEFINE_INT32(RC_MAP_MISSIO_SW, 0);
|
||||
PARAM_DEFINE_INT32(RC_MAP_LOITER_SW, 0);
|
||||
|
||||
//PARAM_DEFINE_INT32(RC_MAP_OFFB_SW, 0);
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ private:
|
||||
int rc_map_mode_sw;
|
||||
int rc_map_return_sw;
|
||||
int rc_map_assisted_sw;
|
||||
int rc_map_mission_sw;
|
||||
int rc_map_loiter_sw;
|
||||
|
||||
// int rc_map_offboard_ctrl_mode_sw;
|
||||
|
||||
@@ -297,7 +297,7 @@ private:
|
||||
param_t rc_map_mode_sw;
|
||||
param_t rc_map_return_sw;
|
||||
param_t rc_map_assisted_sw;
|
||||
param_t rc_map_mission_sw;
|
||||
param_t rc_map_loiter_sw;
|
||||
|
||||
// param_t rc_map_offboard_ctrl_mode_sw;
|
||||
|
||||
@@ -508,7 +508,7 @@ Sensors::Sensors() :
|
||||
|
||||
/* optional mode switches, not mapped per default */
|
||||
_parameter_handles.rc_map_assisted_sw = param_find("RC_MAP_ASSIST_SW");
|
||||
_parameter_handles.rc_map_mission_sw = param_find("RC_MAP_MISSIO_SW");
|
||||
_parameter_handles.rc_map_loiter_sw = param_find("RC_MAP_LOITER_SW");
|
||||
|
||||
// _parameter_handles.rc_map_offboard_ctrl_mode_sw = param_find("RC_MAP_OFFB_SW");
|
||||
|
||||
@@ -654,7 +654,7 @@ Sensors::parameters_update()
|
||||
warnx("%s", paramerr);
|
||||
}
|
||||
|
||||
if (param_get(_parameter_handles.rc_map_mission_sw, &(_parameters.rc_map_mission_sw)) != OK) {
|
||||
if (param_get(_parameter_handles.rc_map_loiter_sw, &(_parameters.rc_map_loiter_sw)) != OK) {
|
||||
warnx("%s", paramerr);
|
||||
}
|
||||
|
||||
@@ -682,7 +682,7 @@ Sensors::parameters_update()
|
||||
_rc.function[MODE] = _parameters.rc_map_mode_sw - 1;
|
||||
_rc.function[RETURN] = _parameters.rc_map_return_sw - 1;
|
||||
_rc.function[ASSISTED] = _parameters.rc_map_assisted_sw - 1;
|
||||
_rc.function[MISSION] = _parameters.rc_map_mission_sw - 1;
|
||||
_rc.function[LOITER] = _parameters.rc_map_loiter_sw - 1;
|
||||
|
||||
_rc.function[FLAPS] = _parameters.rc_map_flaps - 1;
|
||||
|
||||
@@ -1416,7 +1416,7 @@ Sensors::rc_poll()
|
||||
/* mode switches */
|
||||
manual.mode_switch = get_rc_switch_position(MODE);
|
||||
manual.assisted_switch = get_rc_switch_position(ASSISTED);
|
||||
manual.mission_switch = get_rc_switch_position(MISSION);
|
||||
manual.loiter_switch = get_rc_switch_position(LOITER);
|
||||
manual.return_switch = get_rc_switch_position(RETURN);
|
||||
|
||||
/* publish manual_control_setpoint topic */
|
||||
|
||||
@@ -59,10 +59,13 @@ struct home_position_s
|
||||
{
|
||||
uint64_t timestamp; /**< Timestamp (microseconds since system boot) */
|
||||
|
||||
//bool altitude_is_relative; // TODO what means home relative altitude? we need clear definition of reference altitude then
|
||||
double lat; /**< Latitude in degrees */
|
||||
double lon; /**< Longitude in degrees */
|
||||
float alt; /**< Altitude in meters */
|
||||
|
||||
float x; /**< X coordinate in meters */
|
||||
float y; /**< Y coordinate in meters */
|
||||
float z; /**< Z coordinate in meters */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -79,7 +79,7 @@ struct manual_control_setpoint_s {
|
||||
switch_pos_t mode_switch; /**< mode 3 position switch (mandatory): manual, assisted, auto */
|
||||
switch_pos_t return_switch; /**< land 2 position switch (mandatory): land, no effect */
|
||||
switch_pos_t assisted_switch; /**< assisted 2 position switch (optional): seatbelt, simple */
|
||||
switch_pos_t mission_switch; /**< mission 2 position switch (optional): mission, loiter */
|
||||
switch_pos_t loiter_switch; /**< mission 2 position switch (optional): mission, loiter */
|
||||
}; /**< manual control inputs */
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,6 +57,7 @@ struct optical_flow_s {
|
||||
|
||||
uint64_t timestamp; /**< in microseconds since system start */
|
||||
|
||||
uint64_t flow_timestamp; /**< timestamp from flow sensor */
|
||||
int16_t flow_raw_x; /**< flow in pixels in X direction, not rotation-compensated */
|
||||
int16_t flow_raw_y; /**< flow in pixels in Y direction, not rotation-compensated */
|
||||
float flow_comp_x_m; /**< speed over ground in meters, rotation-compensated */
|
||||
|
||||
@@ -65,7 +65,7 @@ enum RC_CHANNELS_FUNCTION {
|
||||
MODE = 4,
|
||||
RETURN = 5,
|
||||
ASSISTED = 6,
|
||||
MISSION = 7,
|
||||
LOITER = 7,
|
||||
OFFBOARD_MODE = 8,
|
||||
FLAPS = 9,
|
||||
AUX_1 = 10,
|
||||
|
||||
@@ -61,12 +61,8 @@
|
||||
* e.g. control inputs of the vehicle in a Kalman-filter implementation.
|
||||
*/
|
||||
struct vehicle_global_position_s {
|
||||
uint64_t timestamp; /**< Time of this estimate, in microseconds since system start */
|
||||
|
||||
bool global_valid; /**< true if position satisfies validity criteria of estimator */
|
||||
bool baro_valid; /**< true if baro_alt is valid (vel_d is also valid in this case) */
|
||||
|
||||
uint64_t time_gps_usec; /**< GPS timestamp in microseconds */
|
||||
uint64_t timestamp; /**< Time of this estimate, in microseconds since system start */
|
||||
uint64_t time_gps_usec; /**< GPS timestamp in microseconds */
|
||||
double lat; /**< Latitude in degrees */
|
||||
double lon; /**< Longitude in degrees */
|
||||
float alt; /**< Altitude AMSL in meters */
|
||||
@@ -74,8 +70,8 @@ struct vehicle_global_position_s {
|
||||
float vel_e; /**< Ground east velocity, m/s */
|
||||
float vel_d; /**< Ground downside velocity, m/s */
|
||||
float yaw; /**< Yaw in radians -PI..+PI. */
|
||||
|
||||
float baro_alt; /**< Barometric altitude (not raw baro but fused with accelerometer) */
|
||||
float eph;
|
||||
float epv;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/****************************************************************************
|
||||
*
|
||||
* Copyright (C) 2012 PX4 Development Team. All rights reserved.
|
||||
* Author: @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
@@ -35,6 +34,9 @@
|
||||
/**
|
||||
* @file vehicle_local_position.h
|
||||
* Definition of the local fused NED position uORB topic.
|
||||
*
|
||||
* @author Lorenz Meier <lm@inf.ethz.ch>
|
||||
* @author Anton Babushkin <anton.babushkin@me.com>
|
||||
*/
|
||||
|
||||
#ifndef TOPIC_VEHICLE_LOCAL_POSITION_H_
|
||||
@@ -72,8 +74,8 @@ struct vehicle_local_position_s {
|
||||
bool xy_global; /**< true if position (x, y) is valid and has valid global reference (ref_lat, ref_lon) */
|
||||
bool z_global; /**< true if z is valid and has valid global reference (ref_alt) */
|
||||
uint64_t ref_timestamp; /**< Time when reference position was set */
|
||||
int32_t ref_lat; /**< Reference point latitude in 1E7 degrees */
|
||||
int32_t ref_lon; /**< Reference point longitude in 1E7 degrees */
|
||||
double ref_lat; /**< Reference point latitude in degrees */
|
||||
double ref_lon; /**< Reference point longitude in degrees */
|
||||
float ref_alt; /**< Reference altitude AMSL in meters, MUST be set to current (not at reference point!) ground level */
|
||||
bool landed; /**< true if vehicle is landed */
|
||||
/* Distance to surface */
|
||||
|
||||
Reference in New Issue
Block a user