@@ -42,147 +42,159 @@ void AuxGlobalPosition::update(Ekf &ekf, const estimator::imuSample &imu_delayed
4242
4343#if defined(MODULE_NAME)
4444
45- if (_aux_global_position_sub.updated ()) {
45+ for (int instance = 0 ; instance < MAX_AGP_IDS; instance++) {
46+ if (_aux_global_position_subs[instance].updated ()) {
4647
47- vehicle_global_position_s aux_global_position{};
48- _aux_global_position_sub .copy (&aux_global_position);
48+ aux_global_position_s aux_global_position{};
49+ _aux_global_position_subs[instance] .copy (&aux_global_position);
4950
50- const int64_t time_us = aux_global_position.timestamp_sample - static_cast <int64_t >(_param_ekf2_agp_delay.get () * 1000 );
51+ const uint8_t sensor_id = aux_global_position.id ;
52+ const int slot = mapSensorIdToSlot (sensor_id);
5153
52- AuxGlobalPositionSample sample{};
53- sample.time_us = time_us;
54- sample.latitude = aux_global_position.lat ;
55- sample.longitude = aux_global_position.lon ;
56- sample.altitude_amsl = aux_global_position.alt ;
57- sample.eph = aux_global_position.eph ;
58- sample.epv = aux_global_position.epv ;
59- sample.lat_lon_reset_counter = aux_global_position.lat_lon_reset_counter ;
54+ if (slot >= MAX_AGP_IDS) {
55+ // All parameter slots are full, cannot handle this sensor. Set ID of unused slot to 0
56+ continue ;
57+ }
58+
59+ const int64_t time_us = aux_global_position.timestamp_sample - static_cast <int64_t >(getDelayParam (slot) * 1000 );
6060
61- _aux_global_position_buffer.push (sample);
61+ AuxGlobalPositionSample sample{};
62+ sample.time_us = time_us;
63+ sample.id = sensor_id;
64+ sample.latitude = aux_global_position.lat ;
65+ sample.longitude = aux_global_position.lon ;
66+ sample.altitude_amsl = aux_global_position.alt ;
67+ sample.eph = aux_global_position.eph ;
68+ sample.epv = aux_global_position.epv ;
69+ sample.lat_lon_reset_counter = aux_global_position.lat_lon_reset_counter ;
6270
63- _time_last_buffer_push = imu_delayed.time_us ;
71+ _sources[slot].buffer .push (sample);
72+ _sources[slot].time_last_buffer_push = imu_delayed.time_us ;
73+ }
6474 }
6575
6676#endif // MODULE_NAME
6777
68- AuxGlobalPositionSample sample;
78+ for (int slot = 0 ; slot < MAX_AGP_IDS; slot++) {
79+ SourceData &source = _sources[slot];
80+ AuxGlobalPositionSample sample;
6981
70- if (_aux_global_position_buffer.pop_first_older_than (imu_delayed.time_us , &sample)) {
71-
72- if (!(_param_ekf2_agp_ctrl.get () & static_cast <int32_t >(Ctrl::kHPos ))) {
73- return ;
74- }
82+ if (source.buffer .pop_first_older_than (imu_delayed.time_us , &sample)) {
7583
76- estimator_aid_source2d_s &aid_src = _aid_src_aux_global_position;
77- const LatLonAlt position (sample.latitude , sample.longitude , sample.altitude_amsl );
78- const Vector2f innovation = (ekf.getLatLonAlt () - position).xy (); // altitude measurements are not used
79-
80- // relax the upper observation noise limit which prevents bad measurements perturbing the position estimate
81- float pos_noise = math::max (sample.eph , _param_ekf2_agp_noise.get (), 0 .01f );
82- const float pos_var = sq (pos_noise);
83- const Vector2f pos_obs_var (pos_var, pos_var);
84-
85- ekf.updateAidSourceStatus (aid_src,
86- sample.time_us , // sample timestamp
87- matrix::Vector2d (sample.latitude , sample.longitude ), // observation
88- pos_obs_var, // observation variance
89- innovation, // innovation
90- Vector2f (ekf.getPositionVariance ()) + pos_obs_var, // innovation variance
91- math::max (_param_ekf2_agp_gate.get (), 1 .f )); // innovation gate
92-
93- const bool starting_conditions = PX4_ISFINITE (sample.latitude ) && PX4_ISFINITE (sample.longitude )
94- && ekf.control_status_flags ().yaw_align ;
95- const bool continuing_conditions = starting_conditions
96- && ekf.global_origin_valid ();
97-
98- switch (_state) {
99- case State::kStopped :
100-
101- /* FALLTHROUGH */
102- case State::kStarting :
103- if (starting_conditions) {
104- _state = State::kStarting ;
105-
106- if (ekf.global_origin_valid ()) {
107- const bool fused = ekf.fuseHorizontalPosition (aid_src);
108- bool reset = false ;
109-
110- if (!fused && isResetAllowed (ekf)) {
111- ekf.resetHorizontalPositionTo (sample.latitude , sample.longitude , Vector2f (aid_src.observation_variance ));
112- ekf.resetAidSourceStatusZeroInnovation (aid_src);
113- reset = true ;
114- }
84+ if (!(getCtrlParam (slot) & static_cast <int32_t >(Ctrl::kHPos ))) {
85+ continue ;
86+ }
11587
116- if (fused || reset) {
117- ekf.enableControlStatusAuxGpos ();
118- _reset_counters.lat_lon = sample.lat_lon_reset_counter ;
119- _state = State::kActive ;
120- }
88+ estimator_aid_source2d_s &aid_src = source.aid_src ;
89+ const LatLonAlt position (sample.latitude , sample.longitude , sample.altitude_amsl );
90+ const Vector2f innovation = (ekf.getLatLonAlt () - position).xy (); // altitude measurements are not used
91+
92+ float pos_noise = math::max (sample.eph , getNoiseParam (slot), 0 .01f );
93+ const float pos_var = sq (pos_noise);
94+ const Vector2f pos_obs_var (pos_var, pos_var);
95+
96+ ekf.updateAidSourceStatus (aid_src,
97+ sample.time_us , // sample timestamp
98+ matrix::Vector2d (sample.latitude , sample.longitude ), // observation
99+ pos_obs_var, // observation variance
100+ innovation, // innovation
101+ Vector2f (ekf.getPositionVariance ()) + pos_obs_var, // innovation variance
102+ math::max (getGateParam (slot), 1 .f )); // innovation gate
103+
104+ const bool starting_conditions = PX4_ISFINITE (sample.latitude ) && PX4_ISFINITE (sample.longitude )
105+ && ekf.control_status_flags ().yaw_align ;
106+ const bool continuing_conditions = starting_conditions
107+ && ekf.global_origin_valid ();
108+
109+ switch (source.state ) {
110+ case State::kStopped :
111+
112+ /* FALLTHROUGH */
113+ case State::kStarting :
114+ if (starting_conditions) {
115+ source.state = State::kStarting ;
116+
117+ if (ekf.global_origin_valid ()) {
118+ const bool fused = ekf.fuseHorizontalPosition (aid_src);
119+ bool reset = false ;
120+
121+ if (!fused && isResetAllowed (ekf, slot)) {
122+ ekf.resetHorizontalPositionTo (sample.latitude , sample.longitude , Vector2f (aid_src.observation_variance ));
123+ ekf.resetAidSourceStatusZeroInnovation (aid_src);
124+ reset = true ;
125+ }
126+
127+ if (fused || reset) {
128+ ekf.enableControlStatusAuxGpos ();
129+ source.reset_counters .lat_lon = sample.lat_lon_reset_counter ;
130+ source.state = State::kActive ;
131+ }
121132
122- } else {
123- // Try to initialize using measurement
124- if (ekf.resetGlobalPositionTo (sample.latitude , sample.longitude , sample.altitude_amsl , pos_var,
125- sq (sample.epv ))) {
126- ekf.resetAidSourceStatusZeroInnovation (aid_src);
127- ekf.enableControlStatusAuxGpos ();
128- _reset_counters.lat_lon = sample.lat_lon_reset_counter ;
129- _state = State::kActive ;
133+ } else {
134+ // Try to initialize using measurement
135+ if (ekf.resetGlobalPositionTo (sample.latitude , sample.longitude , sample.altitude_amsl , pos_var,
136+ sq (sample.epv ))) {
137+ ekf.resetAidSourceStatusZeroInnovation (aid_src);
138+ ekf.enableControlStatusAuxGpos ();
139+ source.reset_counters .lat_lon = sample.lat_lon_reset_counter ;
140+ source.state = State::kActive ;
141+ }
130142 }
131143 }
132- }
133144
134- break ;
145+ break ;
135146
136- case State::kActive :
137- if (continuing_conditions) {
138- ekf.fuseHorizontalPosition (aid_src);
147+ case State::kActive :
148+ if (continuing_conditions) {
149+ ekf.fuseHorizontalPosition (aid_src);
139150
140- if (isTimedOut (aid_src.time_last_fuse , imu_delayed.time_us , ekf._params .reset_timeout_max )
141- || (_reset_counters .lat_lon != sample.lat_lon_reset_counter )) {
142- if (isResetAllowed (ekf)) {
151+ if (isTimedOut (aid_src.time_last_fuse , imu_delayed.time_us , ekf._params .reset_timeout_max )
152+ || (source. reset_counters .lat_lon != sample.lat_lon_reset_counter )) {
153+ if (isResetAllowed (ekf, slot )) {
143154
144- ekf.resetHorizontalPositionTo (sample.latitude , sample.longitude , Vector2f (aid_src.observation_variance ));
155+ ekf.resetHorizontalPositionTo (sample.latitude , sample.longitude , Vector2f (aid_src.observation_variance ));
145156
146- ekf.resetAidSourceStatusZeroInnovation (aid_src);
157+ ekf.resetAidSourceStatusZeroInnovation (aid_src);
147158
148- _reset_counters .lat_lon = sample.lat_lon_reset_counter ;
159+ source. reset_counters .lat_lon = sample.lat_lon_reset_counter ;
149160
150- } else {
151- ekf.disableControlStatusAuxGpos ();
152- _state = State::kStopped ;
161+ } else {
162+ ekf.disableControlStatusAuxGpos ();
163+ source.state = State::kStopped ;
164+ }
153165 }
154- }
155166
156- } else {
157- ekf.disableControlStatusAuxGpos ();
158- _state = State::kStopped ;
159- }
167+ } else {
168+ ekf.disableControlStatusAuxGpos ();
169+ source. state = State::kStopped ;
170+ }
160171
161- break ;
172+ break ;
162173
163- default :
164- break ;
165- }
174+ default :
175+ break ;
176+ }
166177
167178#if defined(MODULE_NAME)
168- aid_src.timestamp = hrt_absolute_time ();
169- _estimator_aid_src_aux_global_position_pub .publish (aid_src);
179+ aid_src.timestamp = hrt_absolute_time ();
180+ source. aid_src_pub .publish (aid_src);
170181
171- _test_ratio_filtered = math::max (fabsf (aid_src.test_ratio_filtered [0 ]), fabsf (aid_src.test_ratio_filtered [1 ]));
182+ source. test_ratio_filtered = math::max (fabsf (aid_src.test_ratio_filtered [0 ]), fabsf (aid_src.test_ratio_filtered [1 ]));
172183#endif // MODULE_NAME
173184
174- } else if ((_state != State::kStopped ) && isTimedOut (_time_last_buffer_push, imu_delayed.time_us , (uint64_t )5e6 )) {
175- ekf.disableControlStatusAuxGpos ();
176- _state = State::kStopped ;
177- ECL_WARN (" Aux global position data stopped" );
185+ } else if ((source.state != State::kStopped ) && isTimedOut (source.time_last_buffer_push , imu_delayed.time_us , (uint64_t )5e6 )) {
186+ ekf.disableControlStatusAuxGpos ();
187+ source.state = State::kStopped ;
188+ ECL_WARN (" Aux global position data stopped for slot %d (sensor ID %d)" , slot, getIdParam (slot));
189+ }
178190 }
179191}
180192
181- bool AuxGlobalPosition::isResetAllowed (const Ekf &ekf) const
193+ bool AuxGlobalPosition::isResetAllowed (const Ekf &ekf, int slot ) const
182194{
183- return ((static_cast <Mode>(_param_ekf2_agp_mode. get ( )) == Mode::kAuto )
195+ return ((static_cast <Mode>(getModeParam (slot )) == Mode::kAuto )
184196 && !ekf.isOtherSourceOfHorizontalPositionAidingThan (ekf.control_status_flags ().aux_gpos ))
185- || ((static_cast <Mode>(_param_ekf2_agp_mode. get ( )) == Mode::kDeadReckoning )
197+ || ((static_cast <Mode>(getModeParam (slot )) == Mode::kDeadReckoning )
186198 && !ekf.isOtherSourceOfHorizontalAidingThan (ekf.control_status_flags ().aux_gpos ));
187199}
188200
0 commit comments