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

GPS Blending (attempt2) #5841

Merged
merged 34 commits into from
Mar 13, 2017
Merged

Conversation

rmackay9
Copy link
Contributor

@rmackay9 rmackay9 commented Mar 9, 2017

This is an updated version of @priseborough's earlier PR: #5642

This PR adds the following:

  • GPS_AUTO_SWITCH parameter has new Blend ("2") option which blends the input from 2 GPSs into a 3rd "virtual" GPS. The blending is performed within the AP_GPS library. If successful the "primary_gps" is changed to the 3rd GPS (aka the virtual GPS). The existing options "0" and "1" are not functionally changed by this PR.
  • EKF2/EKF3 resets the horizontal and vertical height estimates if the primary GPS is changed.
  • DataFlash logging of 3rd GPS (GPS3, GPA3 messages)
  • Pre-arm check that GPSs (if present) are within 50m of each other (3 dimensional distance is used)
  • Pre-arm check that blending is healthy (if GPS_AUTO_SWITCH is set to 2)
  • SITL receives a new SIM_GP2_GLITCH vector for easier testing. One downside is that the glitch only applies to the virtual Ublox GPS. These commits can be removed from the PR if they're unacceptable.
  • a few unrelated commits to the AP_GPS and AP_NavEKF2/3 libraries to remove unused methods, fix comments. These can be moved to a separate PR if that would help with the review.

Previous explanation of the blending method from Paul:
GPS_AUTO_SWITCH type 2 is a soft switching/blending method using a weighted average of physical receivers to create a third 'virtual' GPS where:

  • The method is scaleable to more than 2 GPS receivers
  • A 'blended' location and velocity is calculated using a weighted average of the two receivers
  • Weights are calculated using the ratio of reported error variances.
  • A filtered location offset correction is calculated for each receiver relative to the 'blended' location and used to correct the output from each receiver.
  • If less than 2 GPS units are available the first GPS instance detected will be used.
  • If there is not enough error reporting to support calculation of the blending weights, the first receiver with the equal highest solution status value will be used . This can happen if one of the two receivers does not provide a position or speed accuracy.
  • The existing hard switch logic has been left untouched and is selected with GPS_AUTO_SWITCH = 1 the same as before.

This has been tested in SITL and flight tested.

rmackay9 and others added 24 commits March 9, 2017 11:25
If the GPS receiver selection changes and we are using GPS for height, the
vertical position will be reset to the new GPS height measurement.
correct output observer history when doing a GPS height reset
If the GPS receiver selection changes and we are using GPS for height, the vertical position will be reset to the new GPS height measurement.
correct output observer history when doing a GPS height reset
Add GPS and GPA reporting for blended solution
Allow GPS library to manage reporting for the blended solution
callers always specify an instance
No functional change
The frontend implementation was in the backend file
No functional change
Fix pre-existing bug in hard switch logic
Update GPS_AUTO_SWITCH description
protect against zero accuracy estimates returned by GPS drivers
Also minor spelling and parameter documentation fix
highest_supported_status will always return FIX_3D for blended or invalid instance
setHIL_Accuracy checks instance is 2 or less
send_mavlink_gps2_raw uses num_instances variable directly to avoid confusion with num_sensors
These functions are slightly long and make the .h file hard to read.  Also saves a small amount of flash space.
No functional change
backends become friends so they can continue to access parameters held in frontend
get_rate_ms made private because only used by frontend
Also moved static arrays higher in cpp file
Copter's GPS checks will override this
Allows removing some duplicate code
Copy link
Contributor

@WickedShell WickedShell left a comment

Choose a reason for hiding this comment

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

A couple of changes that were outlined here.

A weired scenario that I'm not sure if we need to explicitly handle it, but if you have 1 3D GPS and 1 2D GPS, you will weigh the speed/height accuracies from the 3D gps as perfect, but if the 2D GPS is providing what it thinks is a good accuracy then it will be blending its horizontal position over the other GPS's position. This is an extremely unlikely scenario however, particularly because if you can only acquire a 2D fix it's unlikely that it is a terribly good position that it found.

Wrote most of the comments before talking to @rmackay9 on mumble, and I think I deleted the comments that are no longer valid/handled but it's possible there are a couple here that have already been addressed and I've missed deleting them (or I later found the answer to it and forgot to delete it).

if (!gps.all_consistent(distance_m)) {
if (report) {
GCS_MAVLINK::send_statustext_all(MAV_SEVERITY_CRITICAL,
"PreArm: GPSs inconsistent by %4.1fm",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we fit "positions" in this text if possible, just for maximum user clarity.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One issue with making long descriptions is that, at least on the mission planner, most users will view them on the HUD which is not very wide. The message is already at it's maximum length so any additional characters are simply at the expense of characters at the end of the message.
In any case, I've changed it to "PreArm: GPS positions differ by %4.1fm"

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks! I admit I only ever plan these messages to be relative to the statustext length. MP could break into 2 lines anything that is to long to just fit in the HUD, but thats a separate thing, and has its own complications with doing that.

@@ -149,6 +165,7 @@ const AP_Param::GroupInfo AP_GPS::var_info[] = {
// @Description: Controls how often the GPS should provide a position update. Lowering below 5Hz is not allowed
// @Units: milliseconds
// @Values: 100:10Hz,125:8Hz,200:5Hz
// @Range: 100 200
Copy link
Contributor

Choose a reason for hiding this comment

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

Realistically range 50 is coming as the lower number for this, I wonder if we should just set that here now. (It's a valid value as well)

Copy link
Contributor Author

@rmackay9 rmackay9 Mar 10, 2017

Choose a reason for hiding this comment

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

Are there actually GPSs that have a 20Hz update rate? I don't think I've ever seen one. In any case, I've now set the lower limit on this parameter description to 50. Of course, as we all know, these parameter ranges are not absolute limits. They are just guidelines to the GCS to help keep users picking reasonable values. They can be overridden on the full parameter lists.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah there are, Septentrio is capable of 20Hz updates, and there are some other units on the market that do it as well. Now the relative value of these positions is a bit up for debate, but they are definitely out there and can be acquired now :)

Copy link
Contributor

@WickedShell WickedShell Mar 10, 2017

Choose a reason for hiding this comment

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

Sorry to be a nag, you updated RATE_MS but not RATE_MS2 as well

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, that's cool. thanks for cathing that. fixed.

_omega_lpf = 1.0f / constrain_float(_blend_tc, 5.0f, 30.0f);

// sanity check update rate
for (uint8_t i=0; i<GPS_MAX_RECEIVERS; i++) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why bother with this? You have already protected against callers with the get_rate_ms() function, which means at this point you could safely remove this logic for code space reasons.

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've added this start-up override of the parameter value so that there is some small feedback to the user that the value they input for the RATE_MS was invalid.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would probably show up more to the user as "the parameter system isn't saving what I set this parameter to, help it's broken!" :)

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, if the user sets it incorrectly, I imagine that's how we will hear from them. If I go ahead with removing the code, we likely won't hear from them at all and the user will be none the wiser that what they've requested isn't being done. It's a slight "peep" of a warning on a mistake that probably isn't vehicle threatening in any case.

@@ -1269,7 +1269,7 @@ AP_GPS_UBLOX::_configure_rate(void)
{
struct ubx_cfg_nav_rate msg;
// require a minimum measurement rate of 5Hz
msg.measure_rate_ms = MIN(gps._rate_ms[state.instance], MINIMUM_MEASURE_RATE_MS);
msg.measure_rate_ms = MIN(gps._rate_ms[state.instance], GPS_MAX_RATE_MS);
Copy link
Contributor

Choose a reason for hiding this comment

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

This should just be get_rate_ms() might as well enforce this as a common interface, and again reduce code size/changes for differences.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, done.

AP_Int8 _min_elevation;
AP_Int8 _raw_data;
AP_Int8 _gnss_mode[GPS_MAX_RECEIVERS];
AP_Int16 _rate_ms[GPS_MAX_RECEIVERS];
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add a comment indicating that this should never be directly dereferenced and instead to always utilize get_rate_ms() for any caller who needs the information.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sure, added the comment.

{
// initialise the blended states so we can accumulate the results using the weightings for each GPS receiver
state[GPS_MAX_RECEIVERS].instance = GPS_MAX_RECEIVERS;
state[GPS_MAX_RECEIVERS].status = NO_GPS;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit pick: NO_FIX would be better.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed, thanks

@@ -157,9 +174,8 @@ class AP_GPS
return status(primary_instance);
}

// Query the highest status this GPS supports
// Query the highest status this GPS supports (always reports GPS_OK_FIX_3D for the blended GPS)
Copy link
Contributor

Choose a reason for hiding this comment

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

Somewhat the same question asked earlier, why is the blended only 3D_GPS? Shouldn't it instead be the higher of the 2 options it could be blending?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This "highest_supported_status" is only called for the real GPSs and it's only used in order to decide whether we should send RTK info to the GCS. I think we don't want to send RTK data for the virtual blended GPS in any case so I've just added the warning and within the function protected against a dangerous access to unallocated memory.

Copy link
Contributor

Choose a reason for hiding this comment

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

The only reason I think that maybe the RTK should be audited is for any future user. We wouldn't ever send the blended instance anyways because it would never be index 0 or 1, which is the required index for those two.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Let's escalate this to @tridge. It doesn't seem useful to me and this PR is tough enough as it is. If @tridge says let's add it then I'll go ahead and do it.

Copy link
Contributor

Choose a reason for hiding this comment

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

We don't have to do it by any means, I'm just trying to hold for as consistent an API without having to read all the special cases from the header file every time :)

@@ -786,10 +786,14 @@ Format characters in the format string for binary log messages
"GPS", "QBIHBcLLefffB", "TimeUS,Status,GMS,GWk,NSats,HDop,Lat,Lng,Alt,Spd,GCrs,VZ,U" }, \
{ LOG_GPS2_MSG, sizeof(log_GPS), \
"GPS2", "QBIHBcLLefffB", "TimeUS,Status,GMS,GWk,NSats,HDop,Lat,Lng,Alt,Spd,GCrs,VZ,U" }, \
{ LOG_GPS3_MSG, sizeof(log_GPS), \
Copy link
Contributor

Choose a reason for hiding this comment

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

I know I suggested GPS/GPA 3 but should we maybe make these be GPSB/GPAB for the blended instance? That way log tools can always assume which is the blended instance?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sure, changed to GPSB and GPAB.

// position shift to the controllers.
primary_instance = i;
_last_instance_swap_ms = now;
if (_output_is_blended) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We should only do this if the _blend_health is considered healthy. There is a race condition where a poorly configured GPS (say 2.5Hz) could get us in/out of blending every other message from the 5Hz or higher GPS. We don't want to be swapping between the blended and non blended GPS every 200 msec's. (Particularly since we might be swapping between instance 1, 2 or blend every 200 msec's freely).

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, seems like a good idea, added!

@@ -65,7 +80,8 @@ const AP_Param::GroupInfo AP_GPS::var_info[] = {
// @Param: AUTO_SWITCH
// @DisplayName: Automatic Switchover Setting
// @Description: Automatic switchover to GPS reporting best lock
// @Values: 0:Disabled,1:Enabled
// @Values: 0:Disabled,1:UseBest,2:Blend
// @RebootRequired: True
Copy link
Contributor

Choose a reason for hiding this comment

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

If we fix the arming check problem I believe this can no longer be a reboot required flag?

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, removed.

@rmackay9 rmackay9 force-pushed the prise-gpsblending3 branch 3 times, most recently from c35f0ea to 81ca80f Compare March 10, 2017 07:22
This includes these changes:
RATE_MS, RATE_MS2 parameter description Range minimum reduced to 50
_blend_health_counter is reset to 0 if blending is disabled
GPS_MAX_RECEIVERS is replaced with GPS_BLENDED_INSTANCE where appropriate
simplify all_consistent functions check of number of receivers
calc_blended_weights fix for initial check of how many receivers we have
remove unnecessary setting of GPS last time when blending fails
remove RebootRequired from AUTO_SWITCH param description
This silences a warning from eclipse
No functional change
@rmackay9 rmackay9 dismissed WickedShell’s stale review March 13, 2017 00:10

I think we've cleared all of @WickedShells comments..

@rmackay9 rmackay9 merged commit 3e628f3 into ArduPilot:master Mar 13, 2017
@rmackay9 rmackay9 deleted the prise-gpsblending3 branch April 3, 2020 01:24
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

3 participants