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

Move GPS aggregation and blending to sensors #14447

Merged
merged 3 commits into from Sep 26, 2020

Conversation

dakejahl
Copy link
Contributor

Brought the work from this PR #13584 up to date with current master

Need to test still.

FYI @dagar @JacobCrabill

@TSC21
Copy link
Member

TSC21 commented Mar 20, 2020

@dakejahl the correct way of rebasing work is to rebase commits. Not to pick up commits from another developer and bring it together as your own. That removes the credit and effort from the other developer.

@dakejahl
Copy link
Contributor Author

Rebasing was a mess, this was much quicker, cleaner and easier. I am working with @dagar on this.

I could care less about credit so if that matters we can close this and dagar can unstage and reopen...

@TSC21
Copy link
Member

TSC21 commented Mar 20, 2020

Rebasing was a mess, this was much quicker, cleaner and easier. I am working with @dagar on this.

I could care less about credit so if that matters we can close this and dagar can unstage and reopen...

Cleaner it isn't. Easier probably is for sure. Well done rebasing takes effort and it's the right thing to do. Anyway if @dagar is fine with it, I don't oppose as it's not my work.

@dakejahl dakejahl force-pushed the pr-sensors_vehicle_gps_position branch 2 times, most recently from d0c3171 to a6237ba Compare March 20, 2020 20:07
@mrpollo
Copy link
Contributor

mrpollo commented Mar 20, 2020

@TSC21 Thanks for raising this issue 👍. After a quick Slack discussion with @dakejahl, we were able to find a proper solution.

@dakejahl, thanks for your remarkable contribution, and for addressing @TSC21 comments by adding @dagar as a co-author on your commits.

Great teamwork. 🎉

Screen Shot 2020-03-20 at 1 07 26 PM

@dakejahl
Copy link
Contributor Author

dakejahl commented Mar 20, 2020

Tested successfully using Neo V2 GPS connected to a Pixhawk4 and a UBX GPS connected to a pixracer configured as a CAN node connected to the Pixhawk4 over CAN.

  • Blending of both GPS receivers (only works after boot, if you hotplug one or the other it won't blend because hdop vdop and speed accuracy are not being sent over uavcan)
  • Unplug Neo V2, fall back to UBX
  • Unplug UBX, fall back to Neo V2
  • Unplug both, time out
  • Replug both back in, first connects to the better GPS (Neo V2), and then after some time begins to blend both again

@dakejahl
Copy link
Contributor Author

dakejahl commented Mar 20, 2020

Hmm looks like we don't publish hdop, vdop or s_variance_m_s over uavcan from the cannode gps, the uavcan Fix2 message doesn't even contain these fields... this is important to the logic in blend_gps_data()

What should we do about this? @dagar @JacobCrabill

		if (_param_sens_gps_mask.get() & BLEND_MASK_USE_SPD_ACC) {
			for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
				if (_gps_state[i].fix_type >= 3 && _gps_state[i].s_variance_m_s > 0.0f) {
					speed_accuracy_sum_sq += _gps_state[i].s_variance_m_s * _gps_state[i].s_variance_m_s;
				}
			}
		}

		// calculate the sum squared horizontal position accuracy across all GPS sensors
		float horizontal_accuracy_sum_sq = 0.0f;

		if (_param_sens_gps_mask.get() & BLEND_MASK_USE_HPOS_ACC) {
			for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
				if (_gps_state[i].fix_type >= 2 && _gps_state[i].eph > 0.0f) {
					horizontal_accuracy_sum_sq += _gps_state[i].eph * _gps_state[i].eph;
				}
			}
		}

		// calculate the sum squared vertical position accuracy across all GPS sensors
		float vertical_accuracy_sum_sq = 0.0f;

		if (_param_sens_gps_mask.get() & BLEND_MASK_USE_VPOS_ACC) {
			for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
				if (_gps_state[i].fix_type >= 3 && _gps_state[i].epv > 0.0f) {
					vertical_accuracy_sum_sq += _gps_state[i].epv * _gps_state[i].epv;
				}
			}
		}

		// Check if we can do blending using reported accuracy
		bool can_do_blending = (horizontal_accuracy_sum_sq > 0.0f || vertical_accuracy_sum_sq > 0.0f
					|| speed_accuracy_sum_sq > 0.0f);

		// if we can't do blending using reported accuracy, return false and hard switch logic will be used instead
		if (!can_do_blending) {
			return false;
		}

@JacobCrabill
Copy link
Member

My simple solution was just to use pdop for both hdop and vdop; I believe they're similar enough quantites that it works ok (if you're only using CAN GPS units, then it's totally fine). Definitely not perfect if you have another GPS with real hdop/vdop data, but I don't know of a better solution.

@mhkabir
Copy link
Member

mhkabir commented Mar 20, 2020

@JakeDahl can you fix these too: #6275

This is the best time to do this.

@dakejahl
Copy link
Contributor Author

dakejahl commented Mar 21, 2020

Tested successfully! After a days worth of debugging (mostly cannode side) this finally works.

  • Blending of both GPS receivers
  • Unplug Neo V2, fall back to UBX
  • Unplug UBX, fall back to Neo V2
  • Unplug both, time out
  • Replug both back in, first connects to the better GPS (Neo V2), and then after some time begins to blend both again

@JacobCrabill would you mind testing this on your end as well?

@dakejahl
Copy link
Contributor Author

@mhkabir I'm on a critical path right now. Would you mind making the changes you are requesting and just pushing up the commit? Otherwise I'd like to get this merged and keep chugging along with CAN stuff.

@dakejahl dakejahl changed the title [WIP] Move GPS aggregation and blending to sensors Move GPS aggregation and blending to sensors Mar 21, 2020
@dakejahl dakejahl force-pushed the pr-sensors_vehicle_gps_position branch from 10bdb4e to d4f89ca Compare March 21, 2020 03:13
@dakejahl dakejahl requested a review from dagar March 21, 2020 03:13
@LorenzMeier
Copy link
Member

@dakejahl If you care about your commits, please interactively rebase. Otherwise I will squash and merge your PRs as colloquial commits like "thanks clang" do not belong into an upstream open source project.

I would recommend to run make check_format and installing the pre-commit hook. That will make sure you're code style is always correct.

I will squash this PR since it seems appropriate to have single commit.

LorenzMeier
LorenzMeier previously approved these changes Mar 21, 2020
Copy link
Member

@LorenzMeier LorenzMeier left a comment

Choose a reason for hiding this comment

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

This looks architecturally correct to me (moving this into the work queue and "cleaning up" the resulting message flow from GPS -> fused estimate -> estimator), but I'd like to get the review of @CarlOlsson and @bresch on it.

@dakejahl
Copy link
Contributor Author

This log is less helpful than I thought it would be, but here it is.

  • Unplug NeoV2
  • Unplug UBX on CAN
  • Plug in NeoV2 (driver errors so it does not actually connect)
    nsh> WARN [gps] ubx msg 0x0104 invalid len 61458
  • Plug in UBX on CAN
  • Replug NeoV2
  • Observe blending of both GPS again

https://review.px4.io/plot_app?log=4b8998a9-428a-448c-b9bc-b4bdd722b8b9

@dakejahl dakejahl force-pushed the pr-sensors_vehicle_gps_position branch from 243a919 to 89e785b Compare March 21, 2020 17:49
@@ -52,7 +52,7 @@ using namespace time_literals;
const char *const UavcanGnssBridge::NAME = "gnss";

UavcanGnssBridge::UavcanGnssBridge(uavcan::INode &node) :
UavcanCDevSensorBridgeBase("uavcan_gnss", "/dev/uavcan/gnss", "/dev/gnss", ORB_ID(vehicle_gps_position)),
UavcanCDevSensorBridgeBase("uavcan_gnss", "/dev/uavcan/gnss", "/dev/gnss", ORB_ID(sensor_gps)),
Copy link
Member

Choose a reason for hiding this comment

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

In the future we should consider removing the use of CDev as a base class for UavcanSensorBridge; I don't think the CDev interfaces are used anymore. If they are, then ideally those sensor types would have a generic interface class like PX4Barometer / PX4Magnetometer.

if ((gps1_updated && _gps_select_index == 0) || (gps2_updated && _gps_select_index == 1)) {
_gps_new_output_data = true;
// Second, compare GPS's with best fix and take the one with most satellites
uint8_t max_sats = 0;
Copy link
Member

Choose a reason for hiding this comment

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

This was just the quickest/simplest heuristic I came up with for picking which GPS was best; we could also use an accuracy measurement if all GPSs are publishing compatible quantities.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is it possible for a GPS unit to report "No fix" (fix_type == 0) while still reporting some number of satellites?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

And vice versa, reporting "3D fix" while having zero satellites?

Copy link
Member

Choose a reason for hiding this comment

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

If one GPS doesn't have a fix while another does, this will automatically discard the GPS without the fix (only the GPSs with the "best fix" will be sorted through).

Copy link
Member

Choose a reason for hiding this comment

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

And as to 0 satellites... I doubt that would happen, but I could see a case where two different units both have a 3D fix with multiple satellites, but the one with fewer satellites could have a better speed/position accuracy estimate than the one with more satellites. Unlikely perhaps, but plausible.

Copy link
Member

Choose a reason for hiding this comment

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

@dakejahl could you add me as a co-author on this commit, seeing as I did the original blending modifications here?

Copy link
Member

Choose a reason for hiding this comment

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

I've likely already made a mess of things with squashed commits. Happy to restore credit.

@lukegluke
Copy link
Contributor

lukegluke commented Aug 9, 2020

Hi all,

While working with rovers with GPS RTK precision it turned out that 1E-7 degrees precision for lat and long was not enough in several specific cases. I suppose it's worst (at least in this PR) to discuss proposal to make lat and lon as double (and alt as float) in sensor_gps.msg:

double lat		# Latitude in degrees
double lon		# Longitude in degrees
float alt		# Altitude in meters above MSL
float alt_ellipsoid 	# Altitude in meters above Ellipsoid

Yes, I understand that 1e-7 precision is quite good (1.11 cm at equator) and enough for many general drones use cases, but I believe that losing precision in gps drivers straight away on parsing is not good thing for px4 framework and mitigates its universality and customization potential!

Another argument - that in different calculations (especially in ekf) px4 internally already use lat, lon as doubles converting them on input and output every time back and forward from deg/1e-7deg (and m/mm for alt). I don't know how much, but I suppose CPU will be reduced a little, just by increasing RAM usage for 8 bytes * (GPS receivers number).
Obviously, 1e-7 precision can still be used as output in legacy things, like current gps mavlink messages.

Most disadvantage - it will break all log analyzes that use vehicle_gps_position (but anyway finally they have to correct parser to sensor_gps anyway, right?)

Also I would like to suggest here to add dgps_age field to sensor_gps.msg (and fill it in MavlinkStreamGPS2Raw) and parsed it in drivers where available (for example in @bys1123 PR GpsDrivers #58 NMEA-0183)

@dagar
Copy link
Member

dagar commented Aug 23, 2020

Time to finally bring this in!

@dagar
Copy link
Member

dagar commented Aug 23, 2020

@lukegluke I haven't reviewed the various GPS receivers, but from a PX4 message standpoint I don't currently see a reason to be opposed to moving latitude and longitude to double precision floating point. Computationally we're already working with lat/lon in double and the difference in message size is pretty minor for a relatively low rate message like this.

I would propose we get this PR safely into master and do an immediate followup pass.

@dagar dagar force-pushed the pr-sensors_vehicle_gps_position branch from 6d57642 to 27e4597 Compare August 23, 2020 18:07
@dagar
Copy link
Member

dagar commented Aug 23, 2020

Rebased on current master and GPSDrivers submodule updated to latest.

@dagar
Copy link
Member

dagar commented Aug 23, 2020

I've added parameter migration for the changes.

  • EKF2_GPS_MASK -> SENS_GPS_MASK
  • EKF2_GPS_TAU -> SENS_GPS_TAU

@dagar dagar force-pushed the pr-sensors_vehicle_gps_position branch 3 times, most recently from bc1dca8 to 07ff168 Compare August 23, 2020 19:10
@dagar
Copy link
Member

dagar commented Aug 23, 2020

Later we should move the GPS position offset configuration to out of EKF2 and into the sensors module handled per instance.

  • EKF2_GPS_POS_{X, Y, Z}

One question is if we actually shift the sensor_gps data before publishing (vehicle_gps_position) or publish it as metadata for the estimator to handle.

@CarlOlsson I believe this is how we should properly handle your GPS offset issue.

@dagar
Copy link
Member

dagar commented Aug 23, 2020

We don't have to do it in this PR, but ideally we'd finally get some unit testing for the actual GPS blending logic here after another incremental refactor.

 - N x sensor_gps => vehicle_gps_position
 - blending is now configurable with SENS_GPS_MASK and SENS_GPS_TAU
@dagar dagar force-pushed the pr-sensors_vehicle_gps_position branch from 07ff168 to ee42faf Compare August 23, 2020 22:30
@bresch
Copy link
Member

bresch commented Aug 24, 2020

One question is if we actually shift the sensor_gps data before publishing (vehicle_gps_position) or publish it as metadata for the estimator to handle.

I'm in favor of sending the gps measurements without any modification and send the metadata such that the estimator can perform all the required corrections: removing tangential velocity requires gyro data.

@CarlOlsson
Copy link
Contributor

I'm in favor of sending the gps measurements without any modification and send the metadata such that the estimator can perform all the required corrections: removing tangential velocity requires gyro data.

Me too, otherwise we get a strong coupling between the health of the estimator and the "raw" gps data

src/modules/sensors/vehicle_gps_position/CMakeLists.txt Outdated Show resolved Hide resolved
double lat_deg_now = (double)_gps_state[i].lat * 1.0e-7;
double lon_deg_now = (double)_gps_state[i].lon * 1.0e-7;
double lat_deg_res, lon_deg_res;
add_vector_to_global_position(lat_deg_now, lon_deg_now, _NE_pos_offset_m[i](0), _NE_pos_offset_m[i](1), &lat_deg_res,
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should modify the GPS individual readings; IMO, the blending logic should create a blended output from all the receivers but not adjust each GPS solution, why do we do that?

Copy link
Member

Choose a reason for hiding this comment

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

@dakejahl @JacobCrabill any comment here? I don't believe I modified any of the logic when I did the original extraction in #13584, although obviously it's been a while...

Copy link
Member

Choose a reason for hiding this comment

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

Ok, looks like this isn't modified from what ekf2 is currently doing.

I don't think we should modify the GPS individual readings; IMO, the blending logic should create a blended output from all the receivers but not adjust each GPS solution

I agree, storing some of this incremental state was one of my criticisms of the original gps blending work in ekf2, but it was a bit more confusing going between uORB vehicle_gps_position -> ecl/EKF gps_message and then back to ekf_gps_position (nearly identical to vehicle_gps_position). Let me see if I can eliminate it this time.

Comment on lines +647 to +673
// Convert each GPS position to a local NEU offset relative to the reference position
// which is defined as the positon of the blended solution calculated from non offset corrected data
Vector2f blended_NE_offset_m;
blended_NE_offset_m.zero();
float blended_alt_offset_mm = 0.0f;

for (uint8_t i = 0; i < GPS_MAX_RECEIVERS; i++) {
if (_blend_weights[i] > 0.0f) {
// calculate the horizontal offset
Vector2f horiz_offset{};
get_vector_to_next_waypoint((_gps_blended_state.lat / 1.0e7),
(_gps_blended_state.lon / 1.0e7),
(_gps_output[i].lat / 1.0e7),
(_gps_output[i].lon / 1.0e7),
&horiz_offset(0),
&horiz_offset(1));

// sum weighted offsets
blended_NE_offset_m += horiz_offset * _blend_weights[i];

// calculate vertical offset
float vert_offset = (float)(_gps_output[i].alt - _gps_blended_state.alt);

// sum weighted offsets
blended_alt_offset_mm += vert_offset * _blend_weights[i];
}
}
Copy link
Member

Choose a reason for hiding this comment

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

Co-authored-by: Mathieu Bresciani <brescianimathieu@gmail.com>
@dagar dagar force-pushed the pr-sensors_vehicle_gps_position branch from 25ff582 to 614facf Compare August 24, 2020 21:18
@JacobCrabill
Copy link
Member

I'll give this a review soon

@dagar
Copy link
Member

dagar commented Sep 25, 2020

In order to prevent this from dragging out even longer I'm going to revert this branch to the last "good" tested state and get it rebased and merged immediately. Having it merged unblocks further GpsDriver updates and helps with multi-ekf. I'll then restore the cleanup fixes in a new PR we can test incrementally.

@dagar dagar force-pushed the pr-sensors_vehicle_gps_position branch from 614facf to ab0217b Compare September 26, 2020 02:08
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