Skip to content
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

EKF Miscellaneous Improvements and Bug Fixes #5407

Closed
wants to merge 37 commits into from

Conversation

priseborough
Copy link
Contributor

@priseborough priseborough commented Dec 19, 2016

Allows use of range beacons simultaneously with GPS and optical flow
Fixes an error in the way that the Pozyx beacon system output is rotated into the local NED earth frame.
Makes the sensor buffer lengths adapt to the time delays to reduce output predictor errors
Uses the averaged, but unfiltered airspeed to reduce the effective time delay.
Fixes a potential bug that could allow the filter to start before the required sensor buffers are filled
Uses the time delay published by the GPS driver, instead of a value specified by a EKF parameter.
Updates EKF3 to allow copters to fly in non position aiding modes without a magnetometer.

TODO:

Add GPS_DELAY and GPS_DELAY2 parameters to the GPS library as discussed in #5405

FuseRngBcn();
} else {
// If we are using GPS, then GPS is the primary reference, but we continue to use the beacon data
// to calculate an indpendant position that is used to update the beacon position offset if we need to
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indpedant -> independent

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

enum resetDataSource {
DEFAULT=0, // Use best available data
GPS=1, // Use GPS if available
RNGBCN=2, // Use beacon range data if available
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says "Use X if available", but looking at code it will always use the selected source, available or not - I think the callers to resets are always taking tare of ensuring availability, but the comments here should reflect that, the responsibility is on the caller.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

rngBcnFuseDataReportIndex++;
printf("%6.2f\n",(double)receiverPos.x);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left-over debug?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

// Calculate the expected EKF time step
if (_ahrs->get_ins().get_sample_rate() > 0) {
dtEkfAvg = 1.0f / _ahrs->get_ins().get_sample_rate();
dtEkfAvg = fmaxf(dtEkfAvg,EKF_TARGET_DT);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason to not use our MAX definition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None, is there a benefit (other than consistency)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went through the EKF3 code and both fmaxf() and MAX() functions are being used for floating point constraints in different places. I want to be consistent, but before changing them all to one or the other, would like to know what the advantages and disadvantage are.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code or performance wise I think there's no benefit. I would prefer MAX for two reasons:

  • fmaxf is a C function and I prefer to avoid them and use the C++ ones instead, as sometimes there are conflicts
  • although it isn't the case with fmaxf, there can be cases where our math library provides functions that aren't available in all platforms, so I like that we use what our own library provides

In the end it is up to the developer, there is no rule here. I was mainly curious if there was some reason you needed to use fmaxf.

@@ -219,7 +214,7 @@ const AP_Param::GroupInfo NavEKF3::var_info[] = {

// @Param: HGT_DELAY
// @DisplayName: Height measurement delay (msec)
// @Description: This is the number of msec that the Height measurements lag behind the inertial measurements.
// @Description: This is the number of msec that the Height measurements lag behind the inertial measurements. The autpilot should be restarted after adjusting this parameter.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of all these comments in the description it should instead be added @RebootRequired: True

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

@priseborough priseborough changed the title EKF3 Miscellaneous Improvements EKF Miscellaneous Improvements and Bug Fixes Dec 21, 2016
@priseborough priseborough force-pushed the pr-ekf3Updates branch 3 times, most recently from c6e9250 to 52e9e42 Compare December 28, 2016 11:31
if (!use_compass()) {
if (onGround && (imuSampleTime_ms - lastSynthYawTime_ms > 1000)) {
if ((onGround || assume_zero_sideslip()) && (imuSampleTime_ms - lastSynthYawTime_ms > 140)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the comment I think this should be:

onGround || !assume_zero_sideslip()

Either we are on the ground and do it for all vehicles or we aren't and we do it for non-plane vehicles.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix

return false;
} else if (!_ahrs->get_gps().all_configured()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't see a reason to have this case. We should always succeed at configuring a GPS, unless the user requested to not configure it, in that case we should never opt out of the time delay, and instead should always be waiting until we succeed configuration.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree - provided the GPS library all_configured() function does not return false indefinitely for a GPS of an unknown type.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, will remove the timeout and also add the delay configuration parameters to the GPS library.

@WickedShell
Copy link
Contributor

WickedShell commented Dec 28, 2016 via email

@priseborough
Copy link
Contributor Author

priseborough commented Dec 28, 2016

I flight tested this on a copter with px4flow sensor enabled and all COMPASS_USE parameters set to 0.

Flight was stable with some heading drift at the start that disappeared as it did manage to learn the small Z gyro offset with some low speed manoeuvring. Here are the gyro bias estimates:
screen shot 2016-12-29 at 9 45 32 am

Flow innovations looked normal:
screen shot 2016-12-29 at 9 50 32 am

Magnetometer innovations were zero as expected:
screen shot 2016-12-29 at 9 52 35 am

// @Description: Controls the amount of GPS measurement delay that the autopilot compensates for. Set to zero to use the default delay for the detected GPS type.
// @Units: msec
// @Min: 0
// @Max: 250
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not Min/Max but @Range: 0 250

// @Description: Controls the amount of GPS measurement delay that the autopilot compensates for. Set to zero to use the default delay for the detected GPS type.
// @Units: msec
// @Min: 0
// @Max: 250
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

// @Param: DELAY_MS
// @DisplayName: GPS delay in milliseconds
// @Description: Controls the amount of GPS measurement delay that the autopilot compensates for. Set to zero to use the default delay for the detected GPS type.
// @Units: msec
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Units: milliseconds would be more consistent with what we call it in other libraries.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did a search through the code found the following usages in different places

milli-seconds
milliseconds
Milliseconds
msec (EKF libraries)

I will add patches to change them all to milliseconds

@rmackay9 rmackay9 added this to the AC 3.5.0 milestone Jan 9, 2017
Copy link

@roger-zhao roger-zhao left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, how this PR goes on? still not merge into master, right? I wonder that if or not I can fly copter in loiter mode with only GPS (no optical-flow) when this feature merged.

@priseborough
Copy link
Contributor Author

@roger-zhao I believe I have addressed review comments, so there is nothing more I can do from my end to get this in.

This PR is not required to fly in loiter mode with only GPS. Ardupilot has been able to do that for years.

@roger-zhao
Copy link

@priseborough , Sorry, Paul, It's my fault not express clearly what I thought, actually I mean if I can fly copter without compass(mightbe just initialize the heading when starting) and only with a good GPS in Loiter mode according to this PR, :). Again, tks!

Copy link
Member

@OXINARF OXINARF left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@priseborough we want to merge this soon so I made one last review and made two small comments.

Also, looking at #5603 I think there's a bug in:

Since it returns it should have a perf_end.

} else if (drivers[instance] == nullptr || state[instance].status == NO_GPS) {
// the user has not specified a value and we cannot determine it from the GPS type
// so return a default delay of 1 measurement interval
return 0.001f * (float)_rate_ms[instance];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Were you thinking of this for when a backend didn't have a lag value? Because this is going to be returned when there is no GPS connected to this instance (or it hasn't been properly detected yet), so basically should never be used.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was written before those changes. Will fix.

@@ -310,7 +310,8 @@ class AP_GPS
}

// the expected lag (in seconds) in the position and velocity readings from the gps
float get_lag() const { return 0.2f; }
float get_lag(uint8_t instance) const;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the EKF wants this in msec and the only current user is the AHRS_DCM, I would change the function to return in msec instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will have a look at it, but it would involve making changes in multiple files for no benefit other than a few bytes of storage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had a go at it, but ran into compiler errors associated with use of the override attribute on the get_lag function that I did not understand, so will tackle that separate to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The branch i attempted this with is here: https://github.com/priseborough/ardupilot/tree/temp

@priseborough
Copy link
Contributor Author

@OXINARF the perf counter is in the calling function for https://github.com/ArduPilot/ardupilot/blob/master/libraries/AP_NavEKF3/AP_NavEKF3_MagFusion.cpp#L437 , so no end required.
Will push a patch to fix the other.

Prevent bad values for GPS time delay pushing the GPS time stamp outside the range of IMU data contained in the buffer. If this occurs it can prevent the GPS measurements from being fused and cause loss of navigation.
Removes a leftover debug printf statement.
Fixes documentation errors.
Replace remaining fmaxf function calls with Ardupilot MAX function
Fixes bug that could leave it locked out of range finder use.
Copter operation without a magnetometer is limited to constant position and relative position modes only (no GPS or range beacon fusion permitted)
Copter optical flow operation without a magnetometer is permitted.
The ability of planes to takeoff/launch without a magnetometer and align the yaw using the GPS velocity is retained.
Do not time out and provide an escalating series of messages. We may need to adjust the time thresholds used for escalation.
Do not wait if the EKF is not using the GPS.
If the user sets a non-zero value of the delay it will be used in preference over the default value for that GPS type.
If the GPS type is unknown and the parameter is set to zero, then a default delay of 1 sample period will be used (eg 200ms for 5Hz).
The removed else if was going to be true when there is no GPS connected to this instance (or it hasn't been properly detected yet), so should never be used.
@OXINARF
Copy link
Member

OXINARF commented Jan 25, 2017

@OXINARF the perf counter is in the calling function for https://github.com/ArduPilot/ardupilot/blob/master/libraries/AP_NavEKF3/AP_NavEKF3_MagFusion.cpp#L437 , so no end required.

Sorry, you are right, I probably looked a second time at the EKF2 instead of looking at the EKF3.

When you push the fixes, please make a comment and I'll merge it. Thanks!

@priseborough
Copy link
Contributor Author

priseborough commented Jan 25, 2017

I've made changes for the review comments and rebased. The branch has been flown on a Pixhawk 2 with a bin/arducopter binary and px4fmu-v3 target

@OXINARF OXINARF self-assigned this Jan 25, 2017
} else if (drivers[instance] == nullptr || state[instance].status == NO_GPS) {
// the user has not specified a value and we cannot determine it from the GPS type
// so return a default delay of 1 measurement interval
return 0.001f * (float)_rate_ms[instance];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@priseborough This is actually wrong, we should check for a non-existent driver in the requested instance (it would be a wrong use of the function from the caller but we should prevent it here). I think we should return a default 200 ms in that case.
Would you prefer to use the _rate_ms in case a backend exists but doesn't have it's own defined lag (so every GPS except Ublox)? I can do that if you want.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user has specified a delay for that instance, then we should use it, otherwise, given we don't know what type of GPs it is, we should set the delay to one measurement interval (200msec for a 5Hz GPS).

@OXINARF
Copy link
Member

OXINARF commented Jan 26, 2017

@priseborough Can you check that you agree with https://github.com/ArduPilot/ardupilot/compare/master...OXINARF:review/5407?expand=1? It is basically this PR plus your changes to return lag in msec and my last commit changing the backend to return 1 measurement interval when the driver doesn't have a specific lag.

@priseborough
Copy link
Contributor Author

priseborough commented Jan 27, 2017

@OXINARF How about we get this PR in with the change required to make it work and then deal with 'nice to haves' like changing the units of lag from sec to msec in a later PR. I don't have time at the moment to deal with any more changes.

@rmackay9
Copy link
Contributor

Merged, thanks for the code and reviews!
I think @OXINARF and @priseborough are going to handle the remaining questions/comments as separate PRs.

@rmackay9 rmackay9 closed this Jan 27, 2017
@priseborough priseborough deleted the pr-ekf3Updates branch May 6, 2017 23:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants