sensors: move to WQ

Running the sensors module out of the same WQ thread as the estimator, position, and attitude controllers is a bit safer and prevents potential priority and starvation issues. There is a very small increase in latency (~50 us) between sensors and ekf2 execution (on average). This also saves a little bit of memory (~ 3 kB) and cpu (~1-1.5% depending on the board).
This commit is contained in:
Daniel Agar
2020-03-11 11:34:04 -04:00
committed by GitHub
parent 2b8eb736e1
commit 9cd8bb4f88
3 changed files with 181 additions and 169 deletions
@@ -124,11 +124,6 @@ typedef struct {
// wait for the sensor hub if its data is coming from it. // wait for the sensor hub if its data is coming from it.
#define SCHED_PRIORITY_ESTIMATOR (PX4_WQ_HP_BASE - 5) #define SCHED_PRIORITY_ESTIMATOR (PX4_WQ_HP_BASE - 5)
// The sensor hub conditions sensor data. It is not the fastest component
// in the controller chain, but provides easy-to-use data to the more
// complex downstream consumers
#define SCHED_PRIORITY_SENSOR_HUB (PX4_WQ_HP_BASE - 6)
// Position controllers typically are in a blocking wait on estimator data // Position controllers typically are in a blocking wait on estimator data
// so when new sensor data is available they will run last. Keeping them // so when new sensor data is available they will run last. Keeping them
// on a high priority ensures that they are the first process to be run // on a high priority ensures that they are the first process to be run
+180 -159
View File
@@ -54,11 +54,13 @@
#include <px4_platform_common/module_params.h> #include <px4_platform_common/module_params.h>
#include <px4_platform_common/posix.h> #include <px4_platform_common/posix.h>
#include <px4_platform_common/px4_config.h> #include <px4_platform_common/px4_config.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include <px4_platform_common/tasks.h> #include <px4_platform_common/tasks.h>
#include <px4_platform_common/time.h> #include <px4_platform_common/time.h>
#include <uORB/Publication.hpp> #include <uORB/Publication.hpp>
#include <uORB/PublicationMulti.hpp> #include <uORB/PublicationMulti.hpp>
#include <uORB/Subscription.hpp> #include <uORB/Subscription.hpp>
#include <uORB/SubscriptionCallback.hpp>
#include <uORB/topics/actuator_controls.h> #include <uORB/topics/actuator_controls.h>
#include <uORB/topics/airspeed.h> #include <uORB/topics/airspeed.h>
#include <uORB/topics/differential_pressure.h> #include <uORB/topics/differential_pressure.h>
@@ -82,7 +84,7 @@ using namespace time_literals;
* subtract 5 degrees in an attempt to account for the electrical upheating of the PCB * subtract 5 degrees in an attempt to account for the electrical upheating of the PCB
*/ */
#define PCB_TEMP_ESTIMATE_DEG 5.0f #define PCB_TEMP_ESTIMATE_DEG 5.0f
class Sensors : public ModuleBase<Sensors>, public ModuleParams class Sensors : public ModuleBase<Sensors>, public ModuleParams, public px4::ScheduledWorkItem
{ {
public: public:
explicit Sensors(bool hil_enabled); explicit Sensors(bool hil_enabled);
@@ -91,9 +93,6 @@ public:
/** @see ModuleBase */ /** @see ModuleBase */
static int task_spawn(int argc, char *argv[]); static int task_spawn(int argc, char *argv[]);
/** @see ModuleBase */
static Sensors *instantiate(int argc, char *argv[]);
/** @see ModuleBase */ /** @see ModuleBase */
static int custom_command(int argc, char *argv[]); static int custom_command(int argc, char *argv[]);
@@ -101,15 +100,25 @@ public:
static int print_usage(const char *reason = nullptr); static int print_usage(const char *reason = nullptr);
/** @see ModuleBase::run() */ /** @see ModuleBase::run() */
void run() override; void Run() override;
/** @see ModuleBase::print_status() */ /** @see ModuleBase::print_status() */
int print_status() override; int print_status() override;
bool init();
private: private:
const bool _hil_enabled; /**< if true, HIL is active */ const bool _hil_enabled; /**< if true, HIL is active */
bool _armed{false}; /**< arming status of the vehicle */ bool _armed{false}; /**< arming status of the vehicle */
hrt_abstime _last_config_update{0};
hrt_abstime _airdata_prev_timestamp{0};
hrt_abstime _sensor_combined_prev_timestamp{0};
hrt_abstime _magnetometer_prev_timestamp{0};
sensor_combined_s _sensor_combined{};
sensor_preflight_s _sensor_preflight{};
uORB::Subscription _actuator_ctrl_0_sub{ORB_ID(actuator_controls_0)}; /**< attitude controls sub */ uORB::Subscription _actuator_ctrl_0_sub{ORB_ID(actuator_controls_0)}; /**< attitude controls sub */
uORB::Subscription _diff_pres_sub{ORB_ID(differential_pressure)}; /**< raw differential pressure subscription */ uORB::Subscription _diff_pres_sub{ORB_ID(differential_pressure)}; /**< raw differential pressure subscription */
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; /**< notification of parameter updates */ uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; /**< notification of parameter updates */
@@ -117,10 +126,19 @@ private:
uORB::Publication<airspeed_s> _airspeed_pub{ORB_ID(airspeed)}; /**< airspeed */ uORB::Publication<airspeed_s> _airspeed_pub{ORB_ID(airspeed)}; /**< airspeed */
uORB::Publication<sensor_combined_s> _sensor_pub{ORB_ID(sensor_combined)}; /**< combined sensor data topic */ uORB::Publication<sensor_combined_s> _sensor_pub{ORB_ID(sensor_combined)}; /**< combined sensor data topic */
uORB::Publication<sensor_preflight_s> _sensor_preflight{ORB_ID(sensor_preflight)}; /**< sensor preflight topic */ uORB::Publication<sensor_preflight_s> _sensor_preflight_pub{ORB_ID(sensor_preflight)}; /**< sensor preflight topic */
uORB::Publication<vehicle_air_data_s> _airdata_pub{ORB_ID(vehicle_air_data)}; /**< combined sensor data topic */ uORB::Publication<vehicle_air_data_s> _airdata_pub{ORB_ID(vehicle_air_data)}; /**< combined sensor data topic */
uORB::Publication<vehicle_magnetometer_s> _magnetometer_pub{ORB_ID(vehicle_magnetometer)}; /**< combined sensor data topic */ uORB::Publication<vehicle_magnetometer_s> _magnetometer_pub{ORB_ID(vehicle_magnetometer)}; /**< combined sensor data topic */
uORB::SubscriptionCallbackWorkItem _sensor_gyro_integrated_sub[GYRO_COUNT_MAX] {
{this, ORB_ID(sensor_gyro_integrated), 0},
{this, ORB_ID(sensor_gyro_integrated), 1},
{this, ORB_ID(sensor_gyro_integrated), 2}
};
uint32_t _selected_sensor_device_id{0};
uint8_t _selected_sensor_sub_index{0};
perf_counter_t _loop_perf; /**< loop performance counter */ perf_counter_t _loop_perf; /**< loop performance counter */
DataValidator _airspeed_validator; /**< data validator to monitor airspeed */ DataValidator _airspeed_validator; /**< data validator to monitor airspeed */
@@ -183,6 +201,7 @@ private:
Sensors::Sensors(bool hil_enabled) : Sensors::Sensors(bool hil_enabled) :
ModuleParams(nullptr), ModuleParams(nullptr),
ScheduledWorkItem(MODULE_NAME, px4::wq_configurations::att_pos_ctrl),
_hil_enabled(hil_enabled), _hil_enabled(hil_enabled),
_loop_perf(perf_alloc(PC_ELAPSED, "sensors")), _loop_perf(perf_alloc(PC_ELAPSED, "sensors")),
_voted_sensors_update(_parameters, hil_enabled) _voted_sensors_update(_parameters, hil_enabled)
@@ -210,8 +229,15 @@ Sensors::~Sensors()
} }
} }
int bool Sensors::init()
Sensors::parameters_update() {
// initially run manually
ScheduleDelayed(10_ms);
return true;
}
int Sensors::parameters_update()
{ {
if (_armed) { if (_armed) {
return 0; return 0;
@@ -225,8 +251,7 @@ Sensors::parameters_update()
return PX4_OK; return PX4_OK;
} }
int int Sensors::adc_init()
Sensors::adc_init()
{ {
if (!_hil_enabled) { if (!_hil_enabled) {
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL #ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
@@ -253,7 +278,7 @@ Sensors::diff_pres_poll(const vehicle_air_data_s &raw)
float air_temperature_celsius = (diff_pres.temperature > -300.0f) ? diff_pres.temperature : float air_temperature_celsius = (diff_pres.temperature > -300.0f) ? diff_pres.temperature :
(raw.baro_temp_celcius - PCB_TEMP_ESTIMATE_DEG); (raw.baro_temp_celcius - PCB_TEMP_ESTIMATE_DEG);
airspeed_s airspeed; airspeed_s airspeed{};
airspeed.timestamp = diff_pres.timestamp; airspeed.timestamp = diff_pres.timestamp;
/* push data into validator */ /* push data into validator */
@@ -333,8 +358,7 @@ Sensors::parameter_update_poll(bool forced)
} }
} }
void void Sensors::adc_poll()
Sensors::adc_poll()
{ {
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL #ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
@@ -421,143 +445,173 @@ void Sensors::InitializeVehicleIMU()
} }
} }
void void Sensors::Run()
Sensors::run()
{ {
adc_init(); if (should_exit()) {
// clear all registered callbacks
for (auto &sub : _sensor_gyro_integrated_sub) {
sub.unregisterCallback();
}
sensor_combined_s raw = {}; _voted_sensors_update.deinit();
sensor_preflight_s preflt = {}; exit_and_cleanup();
vehicle_air_data_s airdata = {}; return;
vehicle_magnetometer_s magnetometer = {}; }
_voted_sensors_update.init(raw); // run once
if (_last_config_update == 0) {
adc_init();
_voted_sensors_update.init(_sensor_combined);
parameter_update_poll(true);
}
/* (re)load params and calibration */ perf_begin(_loop_perf);
parameter_update_poll(true);
/* get a set of initial values */ // backup schedule as a watchdog timeout
_voted_sensors_update.sensorsPoll(raw, airdata, magnetometer); ScheduleDelayed(10_ms);
sensor_gyro_integrated_s gyro_integrated;
_sensor_gyro_integrated_sub[_selected_sensor_sub_index].copy(&gyro_integrated);
// check vehicle status for changes to publication state
if (_vcontrol_mode_sub.updated()) {
vehicle_control_mode_s vcontrol_mode{};
if (_vcontrol_mode_sub.copy(&vcontrol_mode)) {
_armed = vcontrol_mode.flag_armed;
}
}
vehicle_air_data_s airdata{};
vehicle_magnetometer_s magnetometer{};
_voted_sensors_update.sensorsPoll(_sensor_combined, airdata, magnetometer);
// check analog airspeed
adc_poll();
diff_pres_poll(airdata); diff_pres_poll(airdata);
/* wakeup source */
px4_pollfd_struct_t poll_fds = {};
poll_fds.events = POLLIN;
uint64_t last_config_update = hrt_absolute_time(); // check failover and update subscribed sensor (if necessary)
_voted_sensors_update.checkFailover();
const uint32_t current_device_id = _voted_sensors_update.bestGyroID();
while (!should_exit()) { if (_selected_sensor_device_id != current_device_id) {
// clear all registered callbacks
/* use the best-voted gyro to pace output */ for (auto &sub : _sensor_gyro_integrated_sub) {
poll_fds.fd = _voted_sensors_update.bestGyroFd(); sub.unregisterCallback();
/* wait for up to 50ms for data (Note that this implies, we can have a fail-over time of 50ms,
* if a gyro fails) */
int pret = px4_poll(&poll_fds, 1, 50);
/* If pret == 0 it timed out but we should still do all checks and potentially copy
* other gyros. */
/* this is undesirable but not much we can do - might want to flag unhappy status */
if (pret < 0) {
/* if the polling operation failed because no gyro sensor is available yet,
* then attempt to subscribe once again
*/
if (_voted_sensors_update.numGyros() == 0) {
_voted_sensors_update.initializeSensors();
}
px4_usleep(1000);
continue;
} }
perf_begin(_loop_perf); for (int i = 0; i < GYRO_COUNT_MAX; i++) {
sensor_gyro_integrated_s report{};
/* check vehicle status for changes to publication state */ if (_sensor_gyro_integrated_sub[i].copy(&report)) {
if (_vcontrol_mode_sub.updated()) { if ((report.device_id != 0) && (report.device_id == current_device_id)) {
vehicle_control_mode_s vcontrol_mode{}; if (_sensor_gyro_integrated_sub[i].registerCallback()) {
_vcontrol_mode_sub.copy(&vcontrol_mode); // record selected sensor (array index)
_armed = vcontrol_mode.flag_armed; _selected_sensor_sub_index = i;
} _selected_sensor_device_id = current_device_id;
}
/* the timestamp of the raw struct is updated by the gyroPoll() method (this makes the gyro }
* a mandatory sensor) */
const uint64_t airdata_prev_timestamp = airdata.timestamp;
const uint64_t magnetometer_prev_timestamp = magnetometer.timestamp;
_voted_sensors_update.sensorsPoll(raw, airdata, magnetometer);
/* check analog airspeed */
adc_poll();
diff_pres_poll(airdata);
if (raw.timestamp > 0) {
_voted_sensors_update.setRelativeTimestamps(raw);
_sensor_pub.publish(raw);
if (airdata.timestamp != airdata_prev_timestamp) {
_airdata_pub.publish(airdata);
}
if (magnetometer.timestamp != magnetometer_prev_timestamp) {
_magnetometer_pub.publish(magnetometer);
}
_voted_sensors_update.checkFailover();
/* If the the vehicle is disarmed calculate the length of the maximum difference between
* IMU units as a consistency metric and publish to the sensor preflight topic
*/
if (!_armed) {
preflt.timestamp = hrt_absolute_time();
_voted_sensors_update.calcAccelInconsistency(preflt);
_voted_sensors_update.calcGyroInconsistency(preflt);
_voted_sensors_update.calcMagInconsistency(preflt);
_sensor_preflight.publish(preflt);
} }
} }
/* keep adding sensors as long as we are not armed,
* when not adding sensors poll for param updates
*/
if (!_armed && hrt_elapsed_time(&last_config_update) > 500_ms) {
_voted_sensors_update.initializeSensors();
InitializeVehicleIMU();
last_config_update = hrt_absolute_time();
} else {
/* check parameters for updates */
parameter_update_poll();
}
perf_end(_loop_perf);
} }
_voted_sensors_update.deinit(); if ((airdata.timestamp != 0) && (airdata.timestamp != _airdata_prev_timestamp)) {
_airdata_pub.publish(airdata);
_airdata_prev_timestamp = airdata.timestamp;
}
if ((magnetometer.timestamp != 0) && (magnetometer.timestamp != _magnetometer_prev_timestamp)) {
_magnetometer_pub.publish(magnetometer);
_magnetometer_prev_timestamp = magnetometer.timestamp;
if (!_armed) {
_voted_sensors_update.calcMagInconsistency(_sensor_preflight);
}
}
if (_sensor_combined.timestamp != _sensor_combined_prev_timestamp) {
_voted_sensors_update.setRelativeTimestamps(_sensor_combined);
_sensor_pub.publish(_sensor_combined);
_sensor_combined_prev_timestamp = _sensor_combined.timestamp;
// If the the vehicle is disarmed calculate the length of the maximum difference between
// IMU units as a consistency metric and publish to the sensor preflight topic
if (!_armed) {
_voted_sensors_update.calcAccelInconsistency(_sensor_preflight);
_voted_sensors_update.calcGyroInconsistency(_sensor_preflight);
_sensor_preflight.timestamp = hrt_absolute_time();
_sensor_preflight_pub.publish(_sensor_preflight);
}
}
// keep adding sensors as long as we are not armed,
// when not adding sensors poll for param updates
if (!_armed && hrt_elapsed_time(&_last_config_update) > 500_ms) {
_voted_sensors_update.initializeSensors();
InitializeVehicleIMU();
_last_config_update = hrt_absolute_time();
} else {
// check parameters for updates
parameter_update_poll();
}
perf_end(_loop_perf);
} }
int Sensors::task_spawn(int argc, char *argv[]) int Sensors::task_spawn(int argc, char *argv[])
{ {
/* start the task */ bool hil_enabled = false;
_task_id = px4_task_spawn_cmd("sensors", bool error_flag = false;
SCHED_DEFAULT,
SCHED_PRIORITY_SENSOR_HUB,
2000,
(px4_main_t)&run_trampoline,
(char *const *)argv);
if (_task_id < 0) { int myoptind = 1;
_task_id = -1; int ch;
return -errno; const char *myoptarg = nullptr;
while ((ch = px4_getopt(argc, argv, "h", &myoptind, &myoptarg)) != EOF) {
switch (ch) {
case 'h':
hil_enabled = true;
break;
case '?':
error_flag = true;
break;
default:
PX4_WARN("unrecognized flag");
error_flag = true;
break;
}
} }
return 0; if (error_flag) {
return PX4_ERROR;
}
Sensors *instance = new Sensors(hil_enabled);
if (instance) {
_object.store(instance);
_task_id = task_id_is_work_queue;
if (instance->init()) {
return PX4_OK;
}
} else {
PX4_ERR("alloc failed");
}
delete instance;
_object.store(nullptr);
_task_id = -1;
return PX4_ERROR;
} }
int Sensors::print_status() int Sensors::print_status()
@@ -623,39 +677,6 @@ It runs in its own thread and polls on the currently selected gyro topic.
return 0; return 0;
} }
Sensors *Sensors::instantiate(int argc, char *argv[])
{
bool hil_enabled = false;
bool error_flag = false;
int myoptind = 1;
int ch;
const char *myoptarg = nullptr;
while ((ch = px4_getopt(argc, argv, "h", &myoptind, &myoptarg)) != EOF) {
switch (ch) {
case 'h':
hil_enabled = true;
break;
case '?':
error_flag = true;
break;
default:
PX4_WARN("unrecognized flag");
error_flag = true;
break;
}
}
if (error_flag) {
return nullptr;
}
return new Sensors(hil_enabled);
}
extern "C" __EXPORT int sensors_main(int argc, char *argv[]) extern "C" __EXPORT int sensors_main(int argc, char *argv[])
{ {
return Sensors::main(argc, argv); return Sensors::main(argc, argv);
+1 -5
View File
@@ -125,11 +125,7 @@ public:
*/ */
void checkFailover(); void checkFailover();
int numGyros() const { return _gyro.subscription_count; } int bestGyroID() const { return _gyro_device_id[_gyro.last_best_vote]; }
int gyroFd(int idx) const { return _gyro.subscription[idx]; }
int bestGyroFd() const { return _gyro.subscription[_gyro.last_best_vote]; }
/** /**
* Calculates the magnitude in m/s/s of the largest difference between the primary and any other accel sensor * Calculates the magnitude in m/s/s of the largest difference between the primary and any other accel sensor