Skip to content

fix(mavlink): select GPS_RAW_INT/GPS2_RAW instance via SENS_GPS_PRIME#27868

Draft
dakejahl wants to merge 1 commit into
PX4:mainfrom
dakejahl:dakejahl/mavlink-gps-prime
Draft

fix(mavlink): select GPS_RAW_INT/GPS2_RAW instance via SENS_GPS_PRIME#27868
dakejahl wants to merge 1 commit into
PX4:mainfrom
dakejahl:dakejahl/mavlink-gps-prime

Conversation

@dakejahl

Copy link
Copy Markdown
Contributor

GPS_RAW_INT and GPS2_RAW are hardcoded to sensor_gps instances 0 and 1. For CAN-connected receivers the instance numbering is a boot-order race, so in a moving-base + rover dual-RTK setup the receiver reported as the "main" GPS is random per boot. This resolves the reported receiver from SENS_GPS_PRIME instead, mirroring the vehicle_gps_position selection semantics: 0/1 select the uORB instance directly, 2–127 select a DroneCAN receiver by node ID (matched against device_id). GPS_RAW_INT reports the primary, GPS2_RAW the other receiver, and both re-point live on parameter updates.

  • new lib/gnss/SensorGpsSelector.hpp shared by both streams, and vehicle_gps_position now uses the same node_id_matches() instead of its own copy of the device_id decode; an unmatched node ID keeps retrying until the receiver enumerates on the bus, using the legacy 0/1 mapping in the meantime
  • each stream only reports data from its selected receiver — if the configured primary has no data, GPS_RAW_INT emits the existing NO_GPS keepalive instead of silently substituting the other receiver
  • SENS_GPS_PRIME description now documents the MAVLink reporting

EKF GPS selection is unaffected. Tested in SIH SITL with pymavlink: flipping SENS_GPS_PRIME live moves the receiver between the two messages (fix data follows the selection, NO_GPS keepalives on a dataless target), and unmatched node IDs / the default value keep today's behavior.

sensor_gps uORB instance numbering is boot-order dependent for CAN
receivers, so GPS_RAW_INT/GPS2_RAW showed a random receiver in dual-GPS
setups (e.g. moving base + rover RTK). Resolve the primary from
SENS_GPS_PRIME instead, matching the vehicle_gps_position selection
including DroneCAN node IDs (2-127). The node ID matching lives in
lib/gnss/SensorGpsSelector.hpp and is shared with vehicle_gps_position.
Each stream only reports its selected receiver and falls back to NO_GPS
keepalives if it has no data.

Signed-off-by: Jacob Dahl <dahl.jakejacob@gmail.com>
@github-actions github-actions Bot added kind:bug Something is broken or behaving incorrectly. scope:sensors Sensor pipeline, calibration, voting, or sensor validation. scope:mavlink MAVLink module, streams, commands, or protocol handling. scope:parameters Parameter definitions, metadata, migration, or defaults. labels Jul 10, 2026
@dakejahl dakejahl marked this pull request as draft July 10, 2026 22:37
@github-actions

Copy link
Copy Markdown
Contributor

🔎 FLASH Analysis

px4_fmu-v5x [Total VM Diff: 360 byte (0.02 %)]
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  +0.0%    +360  +0.0%    +360    .text
    [NEW]    +144  [NEW]    +144    SensorGpsSelector::primary_instance()
    [NEW]     +60  [NEW]     +60    CSWTCH.1946
    [NEW]     +48  [NEW]     +48    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +42  [NEW]     +42    CSWTCH.2567
    +5.0%     +32  +5.0%     +32    MavlinkStreamGPS2Raw::send()
    +5.0%     +32  +5.0%     +32    MavlinkStreamGPSRawInt::send()
    [NEW]     +30  [NEW]     +30    SensorGpsSelector::read_param()
    +0.0%     +24  +0.0%     +24    [section .text]
    +0.0%     +24  +0.0%     +24    g_cromfs_image
    [NEW]     +15  [NEW]     +15    CSWTCH.3486
    [NEW]     +15  [NEW]     +15    CSWTCH.3487
     +14%      +8   +14%      +8    MavlinkStreamGPS2Raw::new_instance()
     +18%      +8   +18%      +8    MavlinkStreamGPS2Raw::~MavlinkStreamGPS2Raw()
     +14%      +8   +14%      +8    MavlinkStreamGPSRawInt::new_instance()
     +18%      +8   +18%      +8    MavlinkStreamGPSRawInt::~MavlinkStreamGPSRawInt()
   -100.4%      -2 -100.4%      -2    [3 Others]
    -6.2%      -4  -6.2%      -4    MavlinkMissionManager::init_offboard_mission()
    [DEL]     -15  [DEL]     -15    CSWTCH.3467
    [DEL]     -15  [DEL]     -15    CSWTCH.3468
    [DEL]     -42  [DEL]     -42    CSWTCH.2548
    [DEL]     -60  [DEL]     -60    CSWTCH.1934
  +0.0%    +101  [ = ]       0    .debug_abbrev
  +0.0%     +24  [ = ]       0    .debug_aranges
  +0.0%     +72  [ = ]       0    .debug_frame
  +0.0% +1.97Ki  [ = ]       0    .debug_info
  +0.0%    +707  [ = ]       0    .debug_line
   -85.7%      -6  [ = ]       0    [Unmapped]
    +0.0%    +713  [ = ]       0    [section .debug_line]
  +0.0%    +441  [ = ]       0    .debug_loclists
  +0.0%     +70  [ = ]       0    .debug_rnglists
    [NEW]      +3  [ = ]       0    [Unmapped]
    +0.0%     +67  [ = ]       0    [section .debug_rnglists]
  +0.0%    +433  [ = ]       0    .debug_str
  +0.8%      +2  [ = ]       0    .shstrtab
  +0.0%    +134  [ = ]       0    .strtab
    [DEL]     -12  [ = ]       0    CSWTCH.1934
    [NEW]     +12  [ = ]       0    CSWTCH.1946
    [DEL]     -12  [ = ]       0    CSWTCH.2548
    [NEW]     +12  [ = ]       0    CSWTCH.2567
    [DEL]     -24  [ = ]       0    CSWTCH.3467
    [DEL]     -24  [ = ]       0    CSWTCH.3468
    [NEW]     +24  [ = ]       0    CSWTCH.3486
    [NEW]     +24  [ = ]       0    CSWTCH.3487
    [NEW]     +54  [ = ]       0    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +43  [ = ]       0    SensorGpsSelector::primary_instance()
    [NEW]     +37  [ = ]       0    SensorGpsSelector::read_param()
  +0.0%    +144  [ = ]       0    .symtab
    [DEL]     -32  [ = ]       0    CSWTCH.1934
    [NEW]     +32  [ = ]       0    CSWTCH.1946
    [DEL]     -32  [ = ]       0    CSWTCH.2548
    [NEW]     +32  [ = ]       0    CSWTCH.2567
    [DEL]     -48  [ = ]       0    CSWTCH.3467
    [DEL]     -48  [ = ]       0    CSWTCH.3468
    [NEW]     +48  [ = ]       0    CSWTCH.3486
    [NEW]     +48  [ = ]       0    CSWTCH.3487
     +17%     +16  [ = ]       0    MavlinkStreamESCInfo::~MavlinkStreamESCInfo()
    [NEW]     +64  [ = ]       0    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +48  [ = ]       0    SensorGpsSelector::primary_instance()
    [NEW]     +16  [ = ]       0    SensorGpsSelector::read_param()
    +0.3%     +32  [ = ]       0    [section .symtab]
   -33.3%     -16  [ = ]       0    ___ZN4ListIP13MavlinkStreamE8IteratorppEv.isra.0_veneer
     +33%     +16  [ = ]       0    __hrt_elapsed_time_veneer
   -25.0%     -16  [ = ]       0    __nxsem_foreachholder.isra.0_veneer
     +50%     +16  [ = ]       0    __stm32_dmacapable_veneer
    -1.9%     -16  [ = ]       0    px4::wq_configurations::nav_and_controllers
   -33.3%     -16  [ = ]       0    sensors::VehicleGPSPosition::PrintStatus()
  -4.3%    -360  [ = ]       0    [Unmapped]
  +0.0% +4.05Ki  +0.0%    +360    TOTAL

px4_fmu-v6x [Total VM Diff: 368 byte (0.02 %)]
    FILE SIZE        VM SIZE    
 --------------  -------------- 
  +0.0%    +368  +0.0%    +368    .text
    [NEW]    +144  [NEW]    +144    SensorGpsSelector::primary_instance()
    [NEW]     +60  [NEW]     +60    CSWTCH.1946
    [NEW]     +48  [NEW]     +48    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +42  [NEW]     +42    CSWTCH.2567
    +0.0%     +36  +0.0%     +36    g_cromfs_image
    +5.0%     +32  +5.0%     +32    MavlinkStreamGPS2Raw::send()
    +5.0%     +32  +5.0%     +32    MavlinkStreamGPSRawInt::send()
    [NEW]     +30  [NEW]     +30    SensorGpsSelector::read_param()
    +0.0%     +16  +0.0%     +16    [section .text]
    [NEW]     +15  [NEW]     +15    CSWTCH.3486
    [NEW]     +15  [NEW]     +15    CSWTCH.3487
     +14%      +8   +14%      +8    MavlinkStreamGPS2Raw::new_instance()
     +18%      +8   +18%      +8    MavlinkStreamGPS2Raw::~MavlinkStreamGPS2Raw()
     +14%      +8   +14%      +8    MavlinkStreamGPSRawInt::new_instance()
     +18%      +8   +18%      +8    MavlinkStreamGPSRawInt::~MavlinkStreamGPSRawInt()
    +4.8%      +4  +4.8%      +4    FlightTask
   -100.9%      -6 -100.9%      -6    [4 Others]
    [DEL]     -15  [DEL]     -15    CSWTCH.3467
    [DEL]     -15  [DEL]     -15    CSWTCH.3468
    [DEL]     -42  [DEL]     -42    CSWTCH.2548
    [DEL]     -60  [DEL]     -60    CSWTCH.1934
  +0.0%    +101  [ = ]       0    .debug_abbrev
  +0.0%     +24  [ = ]       0    .debug_aranges
  +0.0%     +72  [ = ]       0    .debug_frame
  +0.0% +1.97Ki  [ = ]       0    .debug_info
  +0.0%    +715  [ = ]       0    .debug_line
     +67%      +2  [ = ]       0    [Unmapped]
    +0.0%    +713  [ = ]       0    [section .debug_line]
  +0.0%    +441  [ = ]       0    .debug_loclists
  +0.0%     +66  [ = ]       0    .debug_rnglists
   -33.3%      -1  [ = ]       0    [Unmapped]
    +0.0%     +67  [ = ]       0    [section .debug_rnglists]
  +0.0%    +433  [ = ]       0    .debug_str
  +0.9%      +2  [ = ]       0    .shstrtab
  +0.0%    +134  [ = ]       0    .strtab
    [DEL]     -12  [ = ]       0    CSWTCH.1934
    [NEW]     +12  [ = ]       0    CSWTCH.1946
    [DEL]     -12  [ = ]       0    CSWTCH.2548
    [NEW]     +12  [ = ]       0    CSWTCH.2567
    [DEL]     -24  [ = ]       0    CSWTCH.3467
    [DEL]     -24  [ = ]       0    CSWTCH.3468
    [NEW]     +24  [ = ]       0    CSWTCH.3486
    [NEW]     +24  [ = ]       0    CSWTCH.3487
    [NEW]     +54  [ = ]       0    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +43  [ = ]       0    SensorGpsSelector::primary_instance()
    [NEW]     +37  [ = ]       0    SensorGpsSelector::read_param()
  +0.0%    +144  [ = ]       0    .symtab
    [DEL]     -32  [ = ]       0    CSWTCH.1934
    [NEW]     +32  [ = ]       0    CSWTCH.1946
    [DEL]     -32  [ = ]       0    CSWTCH.2548
    [NEW]     +32  [ = ]       0    CSWTCH.2567
    [DEL]     -48  [ = ]       0    CSWTCH.3467
    [DEL]     -48  [ = ]       0    CSWTCH.3468
    [NEW]     +48  [ = ]       0    CSWTCH.3486
    [NEW]     +48  [ = ]       0    CSWTCH.3487
     +17%     +16  [ = ]       0    MavlinkStreamESCInfo::~MavlinkStreamESCInfo()
    [NEW]     +64  [ = ]       0    SensorGpsSelector::SensorGpsSelector()
    [NEW]     +48  [ = ]       0    SensorGpsSelector::primary_instance()
    [NEW]     +16  [ = ]       0    SensorGpsSelector::read_param()
    +0.3%     +32  [ = ]       0    [section .symtab]
    -1.9%     -16  [ = ]       0    px4::wq_configurations::nav_and_controllers
   -33.3%     -16  [ = ]       0    sensors::VehicleGPSPosition::PrintStatus()
  -6.9%    -368  [ = ]       0    [Unmapped]
  +0.0% +4.05Ki  +0.0%    +368    TOTAL

Updated: 2026-07-10T22:38:26

@dakejahl

Copy link
Copy Markdown
Contributor Author

@wrsolichin want to give this a try?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude needs review kind:bug Something is broken or behaving incorrectly. scope:mavlink MAVLink module, streams, commands, or protocol handling. scope:parameters Parameter definitions, metadata, migration, or defaults. scope:sensors Sensor pipeline, calibration, voting, or sensor validation.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant