Skip to content

Commit eef01b1

Browse files
AlexKlimajdakejahl
andauthored
AFBR scheduling fix (#25397)
* always reschedule from measurementReadyCallback, don't update range mode is processMeasurement fails, reschedule trigger faster if Argus_TriggerMeasurement fails, refactor mode switching logic, update perf counters * make format * make format exclude microstrain submodule --------- Co-authored-by: Jacob Dahl <dahl.jakejacob@gmail.com>
1 parent bb3fd29 commit eef01b1

File tree

3 files changed

+101
-84
lines changed

3 files changed

+101
-84
lines changed

Tools/astyle/files_to_check_code_style.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ exec find boards msg src platforms test \
1212
-path platforms/nuttx/NuttX -prune -o \
1313
-path platforms/qurt/dspal -prune -o \
1414
-path src/drivers/ins/ilabs -prune -o \
15+
-path src/drivers/ins/microstrain/mip_sdk -prune -o \
1516
-path src/drivers/ins/vectornav/libvnc -prune -o \
1617
-path src/drivers/uavcan/libdronecan -prune -o \
1718
-path src/drivers/uavcan/libuavcan -prune -o \

src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.cpp

Lines changed: 83 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -66,71 +66,44 @@ AFBRS50::~AFBRS50()
6666
Argus_DestroyHandle(_hnd);
6767

6868
perf_free(_sample_perf);
69-
perf_free(_comms_errors);
70-
perf_free(_not_ready_perf);
69+
perf_free(_callback_error);
70+
perf_free(_process_measurement_error);
71+
perf_free(_status_not_ready_perf);
72+
perf_free(_trigger_fail_perf);
7173
}
7274

7375
status_t AFBRS50::measurementReadyCallback(status_t status, argus_hnd_t *hnd)
7476
{
7577
// Called from the SPI comms thread context
78+
STATE state = STATE::COLLECT;
7679

7780
if (up_interrupt_context()) {
7881
// We cannot be in interrupt context
79-
g_dev->recordCommsError();
80-
return ERROR_FAIL;
82+
g_dev->recordCallbackError();
83+
status = ERROR_FAIL;
84+
state = STATE::TRIGGER;
8185
}
8286

8387
if ((g_dev == nullptr) || (status != STATUS_OK)) {
84-
g_dev->recordCommsError();
85-
return ERROR_FAIL;
88+
g_dev->recordCallbackError();
89+
status = ERROR_FAIL;
90+
state = STATE::TRIGGER;
8691
}
8792

88-
g_dev->scheduleCollect();
93+
g_dev->schedule(state);
8994

9095
return status;
9196
}
9297

93-
void AFBRS50::scheduleCollect()
98+
void AFBRS50::schedule(STATE state)
9499
{
95-
_state = STATE::COLLECT;
100+
_state = state;
96101
ScheduleNow();
97102
}
98103

99-
void AFBRS50::recordCommsError()
104+
void AFBRS50::recordCallbackError()
100105
{
101-
perf_count(_comms_errors);
102-
}
103-
104-
void AFBRS50::processMeasurement()
105-
{
106-
perf_count(_sample_perf);
107-
108-
argus_results_t res{};
109-
status_t evaluate_status = Argus_EvaluateData(_hnd, &res);
110-
111-
if ((evaluate_status != STATUS_OK) || (res.Status != STATUS_OK)) {
112-
perf_count(_comms_errors);
113-
return;
114-
}
115-
116-
uint32_t result_mm = res.Bin.Range / (Q9_22_ONE / 1000);
117-
float distance = static_cast<float>(result_mm) / 1000.f;
118-
int8_t quality = res.Bin.SignalQuality;
119-
120-
// Signal quality indicates 100% for good signals, 50% and lower for weak signals.
121-
// 1% is an errored signal (not reliable). Signal Quality of 0% is unknown.
122-
if (quality == 1) {
123-
quality = 0;
124-
}
125-
126-
if (distance > _max_distance) {
127-
distance = 0.0;
128-
quality = 0;
129-
}
130-
131-
_current_distance = distance;
132-
_current_quality = quality;
133-
_px4_rangefinder.update(((res.TimeStamp.sec * 1000000ULL) + res.TimeStamp.usec), distance, quality);
106+
perf_count(_callback_error);
134107
}
135108

136109
int AFBRS50::init()
@@ -235,6 +208,9 @@ int AFBRS50::init()
235208

236209
void AFBRS50::Run()
237210
{
211+
perf_end(_loop_perf);
212+
perf_begin(_loop_perf);
213+
238214
if (_parameter_update_sub.updated()) {
239215
parameter_update_s param_update;
240216
_parameter_update_sub.copy(&param_update);
@@ -264,15 +240,14 @@ void AFBRS50::Run()
264240
// Enable interrupt on falling edge
265241
px4_arch_configgpio(BROADCOM_AFBR_S50_S2PI_IRQ);
266242

267-
// TODO: delay after configure?
268243
_state = STATE::TRIGGER;
269244
ScheduleDelayed(_measurement_inverval);
270245
}
271246
break;
272247

273248
case STATE::TRIGGER: {
274249
if (Argus_GetStatus(_hnd) != STATUS_IDLE) {
275-
perf_count(_not_ready_perf);
250+
perf_count(_status_not_ready_perf);
276251
ScheduleDelayed(_measurement_inverval / 4);
277252
return;
278253
}
@@ -281,22 +256,19 @@ void AFBRS50::Run()
281256
status_t status = Argus_TriggerMeasurement(_hnd, measurementReadyCallback);
282257

283258
if (status != STATUS_OK) {
284-
perf_count(_not_ready_perf);
285-
// Reschedule another trigger
259+
perf_count(_trigger_fail_perf);
286260
_state = STATE::TRIGGER;
287-
ScheduleDelayed(_measurement_inverval / 4);
261+
ScheduleDelayed(1_ms); // Try again immediately
288262
}
289263

290264
// We don't reschedule, the trigger callback will schedule a collect
291265
}
292266
break;
293267

294268
case STATE::COLLECT: {
295-
// Process and publish the measurement
296-
processMeasurement();
297-
298-
// Change measurement rate and mode based on range
299-
updateMeasurementRateFromRange();
269+
if (processMeasurement()) {
270+
updateMeasurementRateFromRange();
271+
}
300272

301273
_state = STATE::TRIGGER;
302274

@@ -316,41 +288,76 @@ void AFBRS50::Run()
316288
}
317289
}
318290

319-
// TODO: fix this logic
320-
// Require 3 readings on same side of fence to mode switch
321-
// Require 3_s after ground_contact in vehicle_land_detected before switching to long range mode
291+
bool AFBRS50::processMeasurement()
292+
{
293+
perf_count(_sample_perf);
294+
295+
argus_results_t res{};
296+
status_t evaluate_status = Argus_EvaluateData(_hnd, &res);
297+
298+
if ((evaluate_status != STATUS_OK) || (res.Status != STATUS_OK)) {
299+
perf_count(_process_measurement_error);
300+
return 0;
301+
}
302+
303+
uint32_t result_mm = res.Bin.Range / (Q9_22_ONE / 1000);
304+
float distance = static_cast<float>(result_mm) / 1000.f;
305+
int8_t quality = res.Bin.SignalQuality;
306+
307+
// Signal quality indicates 100% for good signals, 50% and lower for weak signals.
308+
// 1% is an errored signal (not reliable). Signal Quality of 0% is unknown.
309+
if (quality == 1) {
310+
quality = 0;
311+
}
312+
313+
if (distance > _max_distance * 1.5f) {
314+
distance = 0.0;
315+
quality = 0;
316+
}
317+
318+
_current_distance = distance;
319+
_current_quality = quality;
320+
_px4_rangefinder.update(((res.TimeStamp.sec * 1000000ULL) + res.TimeStamp.usec), distance, quality);
321+
return 1;
322+
}
323+
324+
// TODO: Require 3 consecutive readings on same side of fence to mode switch
322325
void AFBRS50::updateMeasurementRateFromRange()
323326
{
324-
// only update mode if _current_distance is a valid measurement and if the last rate switch was more than 1 second ago
325-
if ((_current_distance > 0) && (_current_quality > 0) && ((hrt_absolute_time() - _last_rate_switch) > 1_s)) {
327+
bool valid_distance = (_current_distance > 0) && (_current_quality > 0);
328+
bool switch_allowed = hrt_elapsed_time(&_last_rate_switch) > 1_s;
326329

327-
status_t status = STATUS_OK;
330+
if (valid_distance && switch_allowed) {
328331

329-
if ((_current_distance >= (_p_sens_afbr_thresh.get() + _p_sens_afbr_hyster.get()))
330-
&& (_current_rate != (uint32_t)_p_sens_afbr_l_rate.get())) {
332+
bool above_threshold = _current_distance >= (_p_sens_afbr_thresh.get() + _p_sens_afbr_hyster.get());
333+
bool in_long_range_mode = _current_rate == _p_sens_afbr_l_rate.get();
331334

332-
_current_rate = (uint32_t)_p_sens_afbr_l_rate.get();
333-
status = setRateAndDfm(_current_rate, DFM_MODE_8X);
335+
bool below_threshold = _current_distance <= (_p_sens_afbr_thresh.get() - _p_sens_afbr_hyster.get());
336+
bool in_short_range_mode = _current_rate == _p_sens_afbr_s_rate.get();
337+
338+
if (above_threshold && !in_long_range_mode) {
339+
340+
_current_rate = _p_sens_afbr_l_rate.get();
341+
auto status = setRateAndDfm(_current_rate, DFM_MODE_8X);
334342

335343
if (status != STATUS_OK) {
336-
PX4_ERR("set_rate status not okay: %i", (int)status);
344+
PX4_ERR("set_rate status not okay: %ld", status);
337345

338346
} else {
339-
PX4_INFO("switched to long range rate: %i", (int)_current_rate);
347+
PX4_INFO("switched to long range rate: %d", _current_rate);
340348
_last_rate_switch = hrt_absolute_time();
341349
}
342350

343-
} else if ((_current_distance <= (_p_sens_afbr_thresh.get() - _p_sens_afbr_hyster.get()))
344-
&& (_current_rate != (uint32_t)_p_sens_afbr_s_rate.get())) {
351+
} else if (below_threshold && !in_short_range_mode) {
345352

346-
_current_rate = (uint32_t)_p_sens_afbr_s_rate.get();
347-
status = setRateAndDfm(_current_rate, DFM_MODE_OFF);
353+
_current_rate = _p_sens_afbr_s_rate.get();
354+
auto status = setRateAndDfm(_current_rate, DFM_MODE_OFF);
348355

349356
if (status != STATUS_OK) {
350-
PX4_ERR("set_rate status not okay: %i", (int)status);
357+
PX4_ERR("set_rate status not okay: %ld", status);
351358

352359
} else {
353-
PX4_INFO("switched to short range rate: %i", (int)_current_rate);
360+
PX4_INFO("switched to short range rate: %d", _current_rate);
354361
_last_rate_switch = hrt_absolute_time();
355362
}
356363
}
@@ -441,8 +448,11 @@ argus_mode_t AFBRS50::argusModeFromParameter()
441448
void AFBRS50::printInfo()
442449
{
443450
perf_print_counter(_sample_perf);
444-
perf_print_counter(_comms_errors);
445-
perf_print_counter(_not_ready_perf);
451+
perf_print_counter(_callback_error);
452+
perf_print_counter(_process_measurement_error);
453+
perf_print_counter(_status_not_ready_perf);
454+
perf_print_counter(_trigger_fail_perf);
455+
perf_print_counter(_loop_perf);
446456
PX4_INFO_RAW("distance: %.3fm\n", (double)_current_distance);
447457
PX4_INFO_RAW("rate: %u Hz\n", (uint)(1000000 / _measurement_inverval));
448458
}

src/drivers/distance_sensor/broadcom/afbrs50/AFBRS50.hpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,21 @@ class AFBRS50 : public ModuleParams, public px4::ScheduledWorkItem
5151
AFBRS50(const uint8_t device_orientation = distance_sensor_s::ROTATION_DOWNWARD_FACING);
5252
~AFBRS50() override;
5353

54+
enum class STATE : uint8_t {
55+
CONFIGURE,
56+
TRIGGER,
57+
COLLECT,
58+
};
59+
5460
int init();
5561
void printInfo();
5662

5763
private:
5864
void Run() override;
5965

60-
void recordCommsError();
61-
void scheduleCollect();
62-
void processMeasurement();
66+
void recordCallbackError();
67+
void schedule(STATE state);
68+
bool processMeasurement();
6369
void updateMeasurementRateFromRange();
6470

6571
static status_t measurementReadyCallback(status_t status, argus_hnd_t *hnd);
@@ -70,24 +76,24 @@ class AFBRS50 : public ModuleParams, public px4::ScheduledWorkItem
7076
private:
7177
argus_hnd_t *_hnd {nullptr};
7278

73-
enum class STATE : uint8_t {
74-
CONFIGURE,
75-
TRIGGER,
76-
COLLECT,
77-
} _state{STATE::CONFIGURE};
79+
STATE _state{STATE::CONFIGURE};
7880

7981
PX4Rangefinder _px4_rangefinder;
8082

8183
hrt_abstime _last_rate_switch{0};
8284

8385
perf_counter_t _sample_perf{perf_alloc(PC_COUNT, MODULE_NAME": sample count")};
84-
perf_counter_t _comms_errors{perf_alloc(PC_COUNT, MODULE_NAME": comms error")};
85-
perf_counter_t _not_ready_perf{perf_alloc(PC_COUNT, MODULE_NAME": not ready")};
86+
perf_counter_t _callback_error{perf_alloc(PC_COUNT, MODULE_NAME": callback error")};
87+
perf_counter_t _process_measurement_error{perf_alloc(PC_COUNT, MODULE_NAME": process measure error")};
88+
perf_counter_t _status_not_ready_perf{perf_alloc(PC_COUNT, MODULE_NAME": not ready")};
89+
perf_counter_t _trigger_fail_perf{perf_alloc(PC_COUNT, MODULE_NAME": trigger fail")};
90+
perf_counter_t _loop_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": loop interval")};
91+
8692

8793
float _current_distance{0};
8894
int8_t _current_quality{0};
8995
float _max_distance{30.f};
90-
uint32_t _current_rate{0};
96+
int _current_rate{0};
9197

9298
hrt_abstime _trigger_time{0};
9399

0 commit comments

Comments
 (0)