-
Notifications
You must be signed in to change notification settings - Fork 14.9k
Extend SENS_GPS_PRIME usage for UAVCAN GNSS devices #26126
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
base: main
Are you sure you want to change the base?
Conversation
🔎 FLASH Analysispx4_fmu-v5x [Total VM Diff: 144 byte (0.01 %)]px4_fmu-v6x [Total VM Diff: 160 byte (0.01 %)]Updated: 2025-12-19T07:24:31 |
MaEtUgR
left a comment
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.
Why aren't all GPS instances published as they are available and the sensor module selects like how it is done for every sensor and GNSS modules until now? This pr scrambles the responsibility of selecting the primary GNSS module over sensors module and UAVCAN driver by making assumptions about the uORB instance order which is not guaranteed depending on advertising order which can be seen from the lengthy error messages in the code.
I assume sensor_gps.device_id contains the UAVCAN node ID in some way and that's how e.g. magnetometers get prioritized. Why do it completely different for GNSS receivers?
39593a7 to
9507095
Compare
|
@MaEtUgR Thanks for the feedback and pointers, i've rewrote it into a much nicher implementation |
dakejahl
left a comment
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 for the fix. Going forward we should try to move away from using "instances" of things. We should instead favor device_id, and then we don't need to map between the two.
src/modules/sensors/vehicle_gps_position/VehicleGPSPosition.cpp
Outdated
Show resolved
Hide resolved
src/modules/sensors/vehicle_gps_position/VehicleGPSPosition.cpp
Outdated
Show resolved
Hide resolved
MaEtUgR
left a comment
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.
Much much nicer!! Thanks for trying out the suggested architecture 🙏 🙏
The only thing I'd still improve is to only read the parameter and set the primary GPS in one place. It's now not only on parameter changes that the function setPrimaryInstance() can get called and it just increases complexity to do that in two places making assumptions about the range. But everything is at a much higher level now 🙏
| if (device_id.devid_s.bus_type == device::Device::DeviceBusType_UAVCAN | ||
| && device_id.devid_s.address == static_cast<uint8_t>(gps_prime)) { | ||
| _gps_blending.setPrimaryInstance(i); | ||
| } |
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.
Is there any reason to restrict this to only DroneCAN devices? If we use the full device id struct/uint32, it could match any GPS device. I don't see why this setting should assume a specific bus type.
Maybe it's slightly more advanced to set up, but I think anyone manually assigning DroneCAN IDs is an advanced enough user that they can find the full device ID of the GNSS receiver.
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.
@oystub
for Serial GPS devices its already handled in the existing implementation. this is just an extension of that functionality to DroneCAN devices. or am i missing your point?
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.
struct DeviceStructure {
DeviceBusType bus_type : 3;
uint8_t bus: 5; // which instance of the bus type
uint8_t address; // address on the bus (eg. I2C address)
uint8_t devtype; // device class specific device type
};
union DeviceId {
struct DeviceStructure devid_s;
uint32_t devid{0};
};
Also, since the 8 MSB are free, there isn't any problem having all possible IDs fit in a signed int32 parameter. (edit: which is obviously the case with how we do mag/imu calibration ids anyway)
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.
@Claudio-Chies Assume a DroneCAN GNSS receiver with node id 125.
I think it would be nicer to set the parameter to 8748291, which represents:
Bus Type: 3 (UAVCAN), Bus: 0, Address: 125, DevType: 0x85 (DRV_GPS_DEVTYPE_UAVCAN)
Then, the additional logic doesn't have to be coupled specifically to dronecan, and it could be used to set any device to primary.
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.
IMO this is nicer than handling serial and DroneCAN devices separately, and would also work with things like MAVLink or simulation GNSS receivers.
Technically DRV_MAG_DEVTYPE_HMC5883=1 but since bustype 0 represents DeviceBusType_UNKNOWN, I think it works well to keep the 0 and 1 values to mean instance ids, and anything larger device ids.
(And it allows all possible DroneCAN IDs, even 1)
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 do agree that this would more uniquely specify which device, but how would you then surface this to the user in the GCS? to encode all that info into binary is not really user friendly. or the question would be if that would avoid conflicts which could not be avoided in this setup. (aside from the obvious NodeID1).
then two GPS's with the same node id on separate buses would be possible, is the main thing which comes to my mind.
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.
My suggestion is to just have the raw device ID as a user parameter, e.g. 8748291, like for the mag calibration IDs. But one would have to run sensors status or look at a log to easily find this ID. However, I completely agree that this is a tradeoff between "ease of use for the most common use case" and clean architecture (not having a special case for uavcan). I think most people that want to use this feature, probably also understand device IDs well enough to set it, even if it uses the full device id.
The "same node id, different buses" would also apply to magnetometer calibration btw, if we start populating the "bus" field, as suggested in #26135. So it is kind of already something to consider, even if we keep this field as a "simple" node id.
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.
We could improve the output of uavcan status to show more information
Sensor 'gnss':
name: uavcan_gnss
channel 0: node id 116 --> instance 0
channel 1: node id 52 --> instance 1
We could show full device_id and breakdown of what it means
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.
If we're going to switch from instance to device_id let's do that in another PR. This is a good intermediate step.
|
Btw, your PR also fixes this old bug that I have forgotten to follow up 👍
|
|
We should probably also clearly specify the behavior if the parameter is set to an ID that isn't connected to the system. For example if a GNSS receiver is swapped so that there are two instances, but none match the specified id. I would believe this to be a pretty common situation. Ideally, this should at least provide some sort of warning? |
067d165 to
6fc57a7
Compare
|
No flaws found |
|
@Claudio-Chies looks like you've got some of the latest commits from main tangled up in here. For syncing with main I would suggest using the |
Co-authored-by: Matthias Grob <maetugr@gmail.com>
Co-authored-by: Øyvind Taksdal Stubhaug <o_github@oystub.com>
6fc57a7 to
0ce1bbf
Compare
|
@dakejahl yea i hate the update branch functionality from the WebUI, it tends to mess things up afterwards. |
Co-authored-by: Matthias Grob <maetugr@gmail.com>
| if (device_id.devid_s.bus_type == device::Device::DeviceBusType_UAVCAN | ||
| && device_id.devid_s.address == static_cast<uint8_t>(gps_prime)) { | ||
| _gps_blending.setPrimaryInstance(i); | ||
| } |
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.
If we're going to switch from instance to device_id let's do that in another PR. This is a good intermediate step.
Solved Problem
When using multiple UAVCAN GNSS modules, users were not able to set the primary one as they would be able to with serial modules
Solution
With this i extend the usage of the SENS_GPS_PRIME to GNSS devices, whereby the parameter now works as follows:
-1 : Auto (equal priority for all instances)
0 : Main serial GPS instance
1 : Secondary serial GPS instance
2-127 : UAVCAN module node ID
also changed the default behavior to be automatic. because a default value of 0 with an all UAVCAN setup is not ideal.
Changelog Entry
For release notes:
Limitations
the only limiation is that the GNSS module cant have static NodeID 1, which is a valid NodeID bus is usualy the autopilot
Test coverage