-
Notifications
You must be signed in to change notification settings - Fork 13.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FlightTask: Fix ekf2 reset race condition during task switch #14692
Conversation
During a loss of GPS data when using GPS as primary height source, the height is reset to baro and the local position gets invalid at the same time. This triggers a switch to altitude flight task and a setpoint reset. This combination of events had the effect to ignore the height reset, the large sudden height error could create an abrupt change of altitude or even a crash. The ekf2 reset is now done at the beginning of each update call.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some questions, maybe we can quickly discuss.
{ | ||
_reset_counters.xy = _sub_vehicle_local_position.get().xy_reset_counter; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah clever so you went around the problem that the counters got initialized on task start with the new frame by not initializing them before the update and the first update now always initializes them given the reset counter is never exactly zero 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we be sure the reset counter is never zero when there's a valid estimate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you then get an e.g. _ekfResetHandlerPositionZ()
and _smoothing.setCurrentPosition(_position(2))
after every task switch which would override taking over the setpoint from the last task?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't you then get an e.g. _ekfResetHandlerPositionZ() and _smoothing.setCurrentPosition(_position(2)) after every task switch which would override taking over the setpoint from the last task?
Ouch, yes, this is correct and not something we want. I need to find an other solution, thanks...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, the previous value of the counters is transferred to from the previous to the next FlightTask using a get/set function
@@ -60,6 +60,7 @@ void FlightTaskTransition::checkSetpoints(vehicle_local_position_setpoint_s &set | |||
|
|||
bool FlightTaskTransition::update() | |||
{ | |||
FlightTask::update(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FlightTaskOffboard
and FlightTaskOrbit
need to call the base update as well.
Also to make it fully correct you need to logically and with the return value like for example here: https://github.com/PX4/Firmware/blob/2fca03e1bda313f86fd96d05130e830b9a2ee220/src/lib/flight_tasks/tasks/Manual/FlightTaskManual.cpp#L47
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I added it for FlightTaskOffboard
, but orbit inherits from Altitude, so it's not required
@MaEtUgR Should be good now. I tested in SITL that the reset works when EKF resets and that the counter is saved when you switch between tasks |
d1e6f4b
to
ca96289
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks correct to me, I just had some minor comments.
src/lib/flight_tasks/FlightTasks.hpp
Outdated
@@ -81,6 +81,12 @@ class FlightTasks | |||
*/ | |||
const vehicle_local_position_setpoint_s getPositionSetpoint(); | |||
|
|||
/** | |||
* Get the reset counters from the current task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name says that but I would probably ask myself what reset counters.
* Get the reset counters from the current task | |
* Get the estimation reference frame reset counters from the current task |
?
_reset_counters.z = _sub_vehicle_local_position.get().z_reset_counter; | ||
_reset_counters.vz = _sub_vehicle_local_position.get().vz_reset_counter; | ||
_reset_counters.quat = _sub_attitude.get().quat_reset_counter; | ||
_checkEkfResetCounters(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle you could leave the _checkEkfResetCounters()
call in the update Initialize. They would just be checked twice on activation then... works either way.
@@ -113,6 +121,9 @@ class FlightTask : public ModuleParams | |||
*/ | |||
const vehicle_local_position_setpoint_s getPositionSetpoint(); | |||
|
|||
const ekf_reset_counters_s getResetCounters() const { return _reset_counters; } | |||
void setResetCounters(ekf_reset_counters_s counters) { _reset_counters = counters; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
void setResetCounters(ekf_reset_counters_s counters) { _reset_counters = counters; } | |
void setResetCounters(const ekf_reset_counters_s &counters) { _reset_counters = counters; } |
@@ -153,7 +155,7 @@ bool FlightTaskOffboard::update() | |||
_position_setpoint.setNaN(); // Don't require any position/velocity setpoints | |||
_velocity_setpoint.setNaN(); | |||
_acceleration_setpoint = Vector3f(0.f, 0.f, 100.f); // High downwards acceleration to make sure there's no thrust | |||
return true; | |||
return ret; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
omg we should to get rid of these early returns, not here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's horrible :|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Everything addressed, thanks 👍
fixes #14677
During a loss of GPS data when using GPS as primary height source, the height is reset to baro and the local position gets invalid at the same time. This triggers a switch to altitude flight task and a setpoint reset.
This combination of events had the effect to ignore the height reset, the large sudden height error could create an abrupt change of altitude or even a crash.
The ekf2 reset is now done at the beginning of each update call.
The ekf reset without a correct compensation of the setpoint can lead to a crash.

