PX4 Firmware
PX4 Autopilot Software http://px4.io
voted_sensors_update.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2016 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 
34 /**
35  * @file voted_sensors_update.cpp
36  *
37  * @author Beat Kueng <beat-kueng@gmx.net>
38  */
39 
40 #include "voted_sensors_update.h"
41 
42 #include <systemlib/mavlink_log.h>
43 
44 #include <uORB/Subscription.hpp>
45 #include <conversion/rotation.h>
46 #include <ecl/geo/geo.h>
47 
48 #define MAG_ROT_VAL_INTERNAL -1
49 #define CAL_ERROR_APPLY_CAL_MSG "FAILED APPLYING %s CAL #%u"
50 
51 using namespace sensors;
52 using namespace DriverFramework;
53 using namespace matrix;
54 
55 VotedSensorsUpdate::VotedSensorsUpdate(const Parameters &parameters, bool hil_enabled)
56  : _parameters(parameters), _hil_enabled(hil_enabled)
57 {
58  for (unsigned i = 0; i < 3; i++) {
59  _corrections.gyro_scale_0[i] = 1.0f;
60  _corrections.accel_scale_0[i] = 1.0f;
61  _corrections.gyro_scale_1[i] = 1.0f;
62  _corrections.accel_scale_1[i] = 1.0f;
63  _corrections.gyro_scale_2[i] = 1.0f;
64  _corrections.accel_scale_2[i] = 1.0f;
65  }
66 
70 
71  _baro.voter.set_timeout(300000);
72  _mag.voter.set_timeout(300000);
74 
75  if (_hil_enabled) { // HIL has less accurate timing so increase the timeouts a bit
76  _gyro.voter.set_timeout(500000);
77  _accel.voter.set_timeout(500000);
78  }
79 }
80 
82 {
83  raw.accelerometer_timestamp_relative = sensor_combined_s::RELATIVE_TIMESTAMP_INVALID;
84  raw.timestamp = 0;
85 
87 
88  _corrections_changed = true; //make sure to initially publish the corrections topic
89  _selection_changed = true;
90 
91  return 0;
92 }
93 
95 {
100 }
101 
103 {
104  for (int i = 0; i < _gyro.subscription_count; i++) {
106  }
107 
108  for (int i = 0; i < _accel.subscription_count; i++) {
110  }
111 
112  for (int i = 0; i < _mag.subscription_count; i++) {
114  }
115 
116  for (int i = 0; i < _baro.subscription_count; i++) {
118  }
119 }
120 
122 {
123  /* fine tune board offset */
124  Dcmf board_rotation_offset = Eulerf(
125  M_DEG_TO_RAD_F * _parameters.board_offset[0],
126  M_DEG_TO_RAD_F * _parameters.board_offset[1],
127  M_DEG_TO_RAD_F * _parameters.board_offset[2]);
128 
129  _board_rotation = board_rotation_offset * get_rot_matrix((enum Rotation)_parameters.board_rotation);
130 
131  // initialze all mag rotations with the board rotation in case there is no calibration data available
132  for (int topic_instance = 0; topic_instance < MAG_COUNT_MAX; ++topic_instance) {
133  _mag_rotation[topic_instance] = _board_rotation;
134  }
135 
136  /* Load & apply the sensor calibrations.
137  * IMPORTANT: we assume all sensor drivers are running and published sensor data at this point
138  */
139 
140  /* temperature compensation */
142 
143  /* gyro */
144  for (uint8_t topic_instance = 0; topic_instance < _gyro.subscription_count; ++topic_instance) {
145 
146  uORB::SubscriptionData<sensor_gyro_s> report{ORB_ID(sensor_gyro), topic_instance};
147 
148  int temp = _temperature_compensation.set_sensor_id_gyro(report.get().device_id, topic_instance);
149 
150  if (temp < 0) {
151  PX4_ERR("%s temp compensation init: failed to find device ID %u for instance %i", "gyro", report.get().device_id,
152  topic_instance);
153 
154  _corrections.gyro_mapping[topic_instance] = 0;
155 
156  } else {
157  _corrections.gyro_mapping[topic_instance] = temp;
158 
159  }
160  }
161 
162 
163  /* accel */
164  for (uint8_t topic_instance = 0; topic_instance < _accel.subscription_count; ++topic_instance) {
165 
166  uORB::SubscriptionData<sensor_accel_s> report{ORB_ID(sensor_accel), topic_instance};
167 
168  int temp = _temperature_compensation.set_sensor_id_accel(report.get().device_id, topic_instance);
169 
170  if (temp < 0) {
171  PX4_ERR("%s temp compensation init: failed to find device ID %u for instance %i", "accel", report.get().device_id,
172  topic_instance);
173 
174  _corrections.accel_mapping[topic_instance] = 0;
175 
176  } else {
177  _corrections.accel_mapping[topic_instance] = temp;
178 
179  }
180  }
181 
182 
183  /* baro */
184  for (uint8_t topic_instance = 0; topic_instance < _baro.subscription_count; ++topic_instance) {
185 
186  uORB::SubscriptionData<sensor_baro_s> report{ORB_ID(sensor_baro), topic_instance};
187 
188  int temp = _temperature_compensation.set_sensor_id_baro(report.get().device_id, topic_instance);
189 
190  if (temp < 0) {
191  PX4_ERR("%s temp compensation init: failed to find device ID %u for instance %i", "baro", report.get().device_id,
192  topic_instance);
193 
194  _corrections.baro_mapping[topic_instance] = 0;
195 
196  } else {
197  _corrections.baro_mapping[topic_instance] = temp;
198 
199  }
200  }
201 
202 
203  /* set offset parameters to new values */
204  bool failed = false;
205  char str[30] {};
206  unsigned gyro_count = 0;
207  unsigned accel_count = 0;
208  unsigned gyro_cal_found_count = 0;
209  unsigned accel_cal_found_count = 0;
210 
211  /* run through all gyro sensors */
212  for (unsigned driver_index = 0; driver_index < GYRO_COUNT_MAX; driver_index++) {
213  _gyro.enabled[driver_index] = true;
214 
215  (void)sprintf(str, "%s%u", GYRO_BASE_DEVICE_PATH, driver_index);
216 
217  DevHandle h;
218  DevMgr::getHandle(str, h);
219 
220  if (!h.isValid()) {
221  continue;
222  }
223 
224  uint32_t driver_device_id = h.ioctl(DEVIOCGDEVICEID, 0);
225  bool config_ok = false;
226 
227  /* run through all stored calibrations that are applied at the driver level*/
228  for (unsigned i = 0; i < GYRO_COUNT_MAX; i++) {
229  /* initially status is ok per config */
230  failed = false;
231 
232  (void)sprintf(str, "CAL_GYRO%u_ID", i);
233  int32_t device_id = 0;
234  failed = failed || (OK != param_get(param_find(str), &device_id));
235 
236  (void)sprintf(str, "CAL_GYRO%u_EN", i);
237  int32_t device_enabled = 1;
238  failed = failed || (OK != param_get(param_find(str), &device_enabled));
239 
240  if (failed) {
241  continue;
242  }
243 
244  if (driver_index == 0 && device_id > 0) {
245  gyro_cal_found_count++;
246  }
247 
248  /* if the calibration is for this device, apply it */
249  if ((uint32_t)device_id == driver_device_id) {
250  _gyro.enabled[driver_index] = (device_enabled == 1);
251 
252  if (!_gyro.enabled[driver_index]) { _gyro.priority[driver_index] = 0; }
253 
254  struct gyro_calibration_s gscale = {};
255 
256  (void)sprintf(str, "CAL_GYRO%u_XOFF", i);
257 
258  failed = failed || (OK != param_get(param_find(str), &gscale.x_offset));
259 
260  (void)sprintf(str, "CAL_GYRO%u_YOFF", i);
261 
262  failed = failed || (OK != param_get(param_find(str), &gscale.y_offset));
263 
264  (void)sprintf(str, "CAL_GYRO%u_ZOFF", i);
265 
266  failed = failed || (OK != param_get(param_find(str), &gscale.z_offset));
267 
268  (void)sprintf(str, "CAL_GYRO%u_XSCALE", i);
269 
270  failed = failed || (OK != param_get(param_find(str), &gscale.x_scale));
271 
272  (void)sprintf(str, "CAL_GYRO%u_YSCALE", i);
273 
274  failed = failed || (OK != param_get(param_find(str), &gscale.y_scale));
275 
276  (void)sprintf(str, "CAL_GYRO%u_ZSCALE", i);
277 
278  failed = failed || (OK != param_get(param_find(str), &gscale.z_scale));
279 
280  if (failed) {
281  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "gyro", i);
282 
283  } else {
284  /* apply new scaling and offsets */
285  config_ok = applyGyroCalibration(h, &gscale, device_id);
286 
287  if (!config_ok) {
288  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "gyro ", i);
289  }
290  }
291 
292  break;
293  }
294  }
295 
296  if (config_ok) {
297  gyro_count++;
298  }
299  }
300 
301  // There are less gyros than calibrations
302  // reset the board calibration and fail the initial load
303  if (gyro_count < gyro_cal_found_count) {
304 
305  // run through all stored calibrations and reset them
306  for (unsigned i = 0; i < GYRO_COUNT_MAX; i++) {
307 
308  int32_t device_id = 0;
309  (void)sprintf(str, "CAL_GYRO%u_ID", i);
310  (void)param_set(param_find(str), &device_id);
311  }
312  }
313 
314  /* run through all accel sensors */
315  for (unsigned driver_index = 0; driver_index < ACCEL_COUNT_MAX; driver_index++) {
316  _accel.enabled[driver_index] = true;
317 
318  (void)sprintf(str, "%s%u", ACCEL_BASE_DEVICE_PATH, driver_index);
319 
320  DevHandle h;
321  DevMgr::getHandle(str, h);
322 
323  if (!h.isValid()) {
324  continue;
325  }
326 
327  uint32_t driver_device_id = h.ioctl(DEVIOCGDEVICEID, 0);
328  bool config_ok = false;
329 
330  /* run through all stored calibrations */
331  for (unsigned i = 0; i < ACCEL_COUNT_MAX; i++) {
332  /* initially status is ok per config */
333  failed = false;
334 
335  (void)sprintf(str, "CAL_ACC%u_ID", i);
336  int32_t device_id = 0;
337  failed = failed || (OK != param_get(param_find(str), &device_id));
338 
339  (void)sprintf(str, "CAL_ACC%u_EN", i);
340  int32_t device_enabled = 1;
341  failed = failed || (OK != param_get(param_find(str), &device_enabled));
342 
343  if (failed) {
344  continue;
345  }
346 
347  if (driver_index == 0 && device_id > 0) {
348  accel_cal_found_count++;
349  }
350 
351  /* if the calibration is for this device, apply it */
352  if ((uint32_t)device_id == driver_device_id) {
353  _accel.enabled[driver_index] = (device_enabled == 1);
354 
355  if (!_accel.enabled[driver_index]) { _accel.priority[driver_index] = 0; }
356 
357  struct accel_calibration_s ascale = {};
358 
359  (void)sprintf(str, "CAL_ACC%u_XOFF", i);
360 
361  failed = failed || (OK != param_get(param_find(str), &ascale.x_offset));
362 
363  (void)sprintf(str, "CAL_ACC%u_YOFF", i);
364 
365  failed = failed || (OK != param_get(param_find(str), &ascale.y_offset));
366 
367  (void)sprintf(str, "CAL_ACC%u_ZOFF", i);
368 
369  failed = failed || (OK != param_get(param_find(str), &ascale.z_offset));
370 
371  (void)sprintf(str, "CAL_ACC%u_XSCALE", i);
372 
373  failed = failed || (OK != param_get(param_find(str), &ascale.x_scale));
374 
375  (void)sprintf(str, "CAL_ACC%u_YSCALE", i);
376 
377  failed = failed || (OK != param_get(param_find(str), &ascale.y_scale));
378 
379  (void)sprintf(str, "CAL_ACC%u_ZSCALE", i);
380 
381  failed = failed || (OK != param_get(param_find(str), &ascale.z_scale));
382 
383  if (failed) {
384  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "accel", i);
385 
386  } else {
387  /* apply new scaling and offsets */
388  config_ok = applyAccelCalibration(h, &ascale, device_id);
389 
390  if (!config_ok) {
391  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "accel ", i);
392  }
393  }
394 
395  break;
396  }
397  }
398 
399  if (config_ok) {
400  accel_count++;
401  }
402  }
403 
404  // There are less accels than calibrations
405  // reset the board calibration and fail the initial load
406  if (accel_count < accel_cal_found_count) {
407 
408  // run through all stored calibrations and reset them
409  for (unsigned i = 0; i < ACCEL_COUNT_MAX; i++) {
410 
411  int32_t device_id = 0;
412  (void)sprintf(str, "CAL_ACC%u_ID", i);
413  (void)param_set(param_find(str), &device_id);
414  }
415  }
416 
417  /* run through all mag sensors
418  * Because we store the device id in _mag_device_id, we need to get the id via uorb topic since
419  * the DevHandle method does not work on POSIX.
420  */
421 
422  /* first we have to reset all possible mags, since we are looping through the uORB instances instead of the drivers,
423  * and not all uORB instances have to be published yet at the initial call of parametersUpdate()
424  */
425  for (int i = 0; i < MAG_COUNT_MAX; i++) {
426  _mag.enabled[i] = true;
427  }
428 
429  for (int topic_instance = 0; topic_instance < MAG_COUNT_MAX
430  && topic_instance < _mag.subscription_count; ++topic_instance) {
431 
432  struct mag_report report;
433 
434  if (orb_copy(ORB_ID(sensor_mag), _mag.subscription[topic_instance], &report) != 0) {
435  continue;
436  }
437 
438  int topic_device_id = report.device_id;
439  bool is_external = report.is_external;
440  _mag_device_id[topic_instance] = topic_device_id;
441 
442  // find the driver handle that matches the topic_device_id
443  DevHandle h;
444 
445  for (unsigned driver_index = 0; driver_index < MAG_COUNT_MAX; ++driver_index) {
446 
447  (void)sprintf(str, "%s%u", MAG_BASE_DEVICE_PATH, driver_index);
448 
449  DevMgr::getHandle(str, h);
450 
451  if (!h.isValid()) {
452  /* the driver is not running, continue with the next */
453  continue;
454  }
455 
456  int driver_device_id = h.ioctl(DEVIOCGDEVICEID, 0);
457 
458  if (driver_device_id == topic_device_id) {
459  break; // we found the matching driver
460 
461  } else {
462  DevMgr::releaseHandle(h);
463  }
464  }
465 
466  bool config_ok = false;
467 
468  /* run through all stored calibrations */
469  for (unsigned i = 0; i < MAG_COUNT_MAX; i++) {
470  /* initially status is ok per config */
471  failed = false;
472 
473  (void)sprintf(str, "CAL_MAG%u_ID", i);
474  int32_t device_id = 0;
475  failed = failed || (OK != param_get(param_find(str), &device_id));
476 
477  (void)sprintf(str, "CAL_MAG%u_EN", i);
478  int32_t device_enabled = 1;
479  failed = failed || (OK != param_get(param_find(str), &device_enabled));
480 
481  if (failed) {
482  continue;
483  }
484 
485  /* if the calibration is for this device, apply it */
486  if ((uint32_t)device_id == _mag_device_id[topic_instance]) {
487  _mag.enabled[topic_instance] = (device_enabled == 1);
488 
489  // the mags that were published after the initial parameterUpdate
490  // would be given the priority even if disabled. Reset it to 0 in this case
491  if (!_mag.enabled[topic_instance]) { _mag.priority[topic_instance] = 0; }
492 
493  struct mag_calibration_s mscale = {};
494 
495  (void)sprintf(str, "CAL_MAG%u_XOFF", i);
496 
497  failed = failed || (OK != param_get(param_find(str), &mscale.x_offset));
498 
499  (void)sprintf(str, "CAL_MAG%u_YOFF", i);
500 
501  failed = failed || (OK != param_get(param_find(str), &mscale.y_offset));
502 
503  (void)sprintf(str, "CAL_MAG%u_ZOFF", i);
504 
505  failed = failed || (OK != param_get(param_find(str), &mscale.z_offset));
506 
507  (void)sprintf(str, "CAL_MAG%u_XSCALE", i);
508 
509  failed = failed || (OK != param_get(param_find(str), &mscale.x_scale));
510 
511  (void)sprintf(str, "CAL_MAG%u_YSCALE", i);
512 
513  failed = failed || (OK != param_get(param_find(str), &mscale.y_scale));
514 
515  (void)sprintf(str, "CAL_MAG%u_ZSCALE", i);
516 
517  failed = failed || (OK != param_get(param_find(str), &mscale.z_scale));
518 
519  (void)sprintf(str, "CAL_MAG%u_ROT", i);
520 
521  int32_t mag_rot;
522 
523  param_get(param_find(str), &mag_rot);
524 
525  if (is_external) {
526 
527  /* check if this mag is still set as internal, otherwise leave untouched */
528  if (mag_rot < 0) {
529  /* it was marked as internal, change to external with no rotation */
530  mag_rot = 0;
531  param_set_no_notification(param_find(str), &mag_rot);
532  }
533 
534  } else {
535  /* mag is internal - reset param to -1 to indicate internal mag */
536  if (mag_rot != MAG_ROT_VAL_INTERNAL) {
537  mag_rot = MAG_ROT_VAL_INTERNAL;
538  param_set_no_notification(param_find(str), &mag_rot);
539  }
540  }
541 
542  /* now get the mag rotation */
543  if (mag_rot >= 0) {
544  // Set external magnetometers to use the parameter value
545  _mag_rotation[topic_instance] = get_rot_matrix((enum Rotation)mag_rot);
546 
547  } else {
548  // Set internal magnetometers to use the board rotation
549  _mag_rotation[topic_instance] = _board_rotation;
550  }
551 
552  if (failed) {
553  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "mag", i);
554 
555  } else {
556 
557  /* apply new scaling and offsets */
558  config_ok = applyMagCalibration(h, &mscale, device_id);
559 
560  if (!config_ok) {
561  PX4_ERR(CAL_ERROR_APPLY_CAL_MSG, "mag ", i);
562  }
563  }
564 
565  break;
566  }
567  }
568  }
569 
570 }
571 
573 {
576 
577  for (int uorb_index = 0; uorb_index < _accel.subscription_count; uorb_index++) {
578  bool accel_updated;
579  orb_check(_accel.subscription[uorb_index], &accel_updated);
580 
581  if (accel_updated) {
582  sensor_accel_s accel_report;
583 
584  int ret = orb_copy(ORB_ID(sensor_accel), _accel.subscription[uorb_index], &accel_report);
585 
586  if (ret != PX4_OK || accel_report.timestamp == 0) {
587  continue; //ignore invalid data
588  }
589 
590  if (!_accel.enabled[uorb_index]) {
591  continue;
592  }
593 
594  // First publication with data
595  if (_accel.priority[uorb_index] == 0) {
596  int32_t priority = 0;
597  orb_priority(_accel.subscription[uorb_index], &priority);
598  _accel.priority[uorb_index] = (uint8_t)priority;
599  }
600 
601  _accel_device_id[uorb_index] = accel_report.device_id;
602 
603  Vector3f accel_data;
604 
605  if (accel_report.integral_dt != 0) {
606  /*
607  * Using data that has been integrated in the driver before downsampling is preferred
608  * becasue it reduces aliasing errors. Correct the raw sensor data for scale factor errors
609  * and offsets due to temperature variation. It is assumed that any filtering of input
610  * data required is performed in the sensor driver, preferably before downsampling.
611  */
612 
613  // convert the delta velocities to an equivalent acceleration before application of corrections
614  float dt_inv = 1.e6f / accel_report.integral_dt;
615  accel_data = Vector3f(accel_report.x_integral * dt_inv,
616  accel_report.y_integral * dt_inv,
617  accel_report.z_integral * dt_inv);
618 
619  _last_sensor_data[uorb_index].accelerometer_integral_dt = accel_report.integral_dt;
620 
621  } else {
622  // using the value instead of the integral (the integral is the prefered choice)
623 
624  // Correct each sensor for temperature effects
625  // Filtering and/or downsampling of temperature should be performed in the driver layer
626  accel_data = Vector3f(accel_report.x, accel_report.y, accel_report.z);
627 
628  // handle the cse where this is our first output
629  if (_last_accel_timestamp[uorb_index] == 0) {
630  _last_accel_timestamp[uorb_index] = accel_report.timestamp - 1000;
631  }
632 
633  // approximate the delta time using the difference in accel data time stamps
635  (accel_report.timestamp - _last_accel_timestamp[uorb_index]);
636  }
637 
638  // handle temperature compensation
639  if (_temperature_compensation.apply_corrections_accel(uorb_index, accel_data, accel_report.temperature,
640  offsets[uorb_index], scales[uorb_index]) == 2) {
641  _corrections_changed = true;
642  }
643 
644  // rotate corrected measurements from sensor to body frame
645  accel_data = _board_rotation * accel_data;
646 
647  _last_sensor_data[uorb_index].accelerometer_m_s2[0] = accel_data(0);
648  _last_sensor_data[uorb_index].accelerometer_m_s2[1] = accel_data(1);
649  _last_sensor_data[uorb_index].accelerometer_m_s2[2] = accel_data(2);
650 
651  _last_accel_timestamp[uorb_index] = accel_report.timestamp;
652  _accel.voter.put(uorb_index, accel_report.timestamp, _last_sensor_data[uorb_index].accelerometer_m_s2,
653  accel_report.error_count, _accel.priority[uorb_index]);
654  }
655  }
656 
657  // find the best sensor
658  int best_index;
659  _accel.voter.get_best(hrt_absolute_time(), &best_index);
660 
661  // write the best sensor data to the output variables
662  if (best_index >= 0) {
664  memcpy(&raw.accelerometer_m_s2, &_last_sensor_data[best_index].accelerometer_m_s2, sizeof(raw.accelerometer_m_s2));
665 
666  if (best_index != _accel.last_best_vote) {
667  _accel.last_best_vote = (uint8_t)best_index;
668  _corrections.selected_accel_instance = (uint8_t)best_index;
669  _corrections_changed = true;
670  }
671 
672  if (_selection.accel_device_id != _accel_device_id[best_index]) {
673  _selection_changed = true;
675  }
676  }
677 }
678 
680 {
683 
684  for (int uorb_index = 0; uorb_index < _gyro.subscription_count; uorb_index++) {
685  bool gyro_updated;
686  orb_check(_gyro.subscription[uorb_index], &gyro_updated);
687 
688  if (gyro_updated) {
689  sensor_gyro_s gyro_report;
690 
691  int ret = orb_copy(ORB_ID(sensor_gyro), _gyro.subscription[uorb_index], &gyro_report);
692 
693  if (ret != PX4_OK || gyro_report.timestamp == 0) {
694  continue; //ignore invalid data
695  }
696 
697  if (!_gyro.enabled[uorb_index]) {
698  continue;
699  }
700 
701  // First publication with data
702  if (_gyro.priority[uorb_index] == 0) {
703  int32_t priority = 0;
704  orb_priority(_gyro.subscription[uorb_index], &priority);
705  _gyro.priority[uorb_index] = (uint8_t)priority;
706  }
707 
708  _gyro_device_id[uorb_index] = gyro_report.device_id;
709 
710  Vector3f gyro_rate;
711 
712  if (gyro_report.integral_dt != 0) {
713  /*
714  * Using data that has been integrated in the driver before downsampling is preferred
715  * becasue it reduces aliasing errors. Correct the raw sensor data for scale factor errors
716  * and offsets due to temperature variation. It is assumed that any filtering of input
717  * data required is performed in the sensor driver, preferably before downsampling.
718  */
719 
720  // convert the delta angles to an equivalent angular rate before application of corrections
721  float dt_inv = 1.e6f / gyro_report.integral_dt;
722  gyro_rate = Vector3f(gyro_report.x_integral * dt_inv,
723  gyro_report.y_integral * dt_inv,
724  gyro_report.z_integral * dt_inv);
725 
726  _last_sensor_data[uorb_index].gyro_integral_dt = gyro_report.integral_dt;
727 
728  } else {
729  //using the value instead of the integral (the integral is the prefered choice)
730 
731  // Correct each sensor for temperature effects
732  // Filtering and/or downsampling of temperature should be performed in the driver layer
733  gyro_rate = Vector3f(gyro_report.x, gyro_report.y, gyro_report.z);
734 
735  // handle the case where this is our first output
736  if (_last_sensor_data[uorb_index].timestamp == 0) {
737  _last_sensor_data[uorb_index].timestamp = gyro_report.timestamp - 1000;
738  }
739 
740  // approximate the delta time using the difference in gyro data time stamps
741  _last_sensor_data[uorb_index].gyro_integral_dt =
742  (gyro_report.timestamp - _last_sensor_data[uorb_index].timestamp);
743  }
744 
745  // handle temperature compensation
746  if (_temperature_compensation.apply_corrections_gyro(uorb_index, gyro_rate, gyro_report.temperature,
747  offsets[uorb_index], scales[uorb_index]) == 2) {
748  _corrections_changed = true;
749  }
750 
751  // rotate corrected measurements from sensor to body frame
752  gyro_rate = _board_rotation * gyro_rate;
753 
754  _last_sensor_data[uorb_index].gyro_rad[0] = gyro_rate(0);
755  _last_sensor_data[uorb_index].gyro_rad[1] = gyro_rate(1);
756  _last_sensor_data[uorb_index].gyro_rad[2] = gyro_rate(2);
757 
758  _last_sensor_data[uorb_index].timestamp = gyro_report.timestamp;
759  _gyro.voter.put(uorb_index, gyro_report.timestamp, _last_sensor_data[uorb_index].gyro_rad,
760  gyro_report.error_count, _gyro.priority[uorb_index]);
761  }
762  }
763 
764  // find the best sensor
765  int best_index;
766  _gyro.voter.get_best(hrt_absolute_time(), &best_index);
767 
768  // write data for the best sensor to output variables
769  if (best_index >= 0) {
770  raw.timestamp = _last_sensor_data[best_index].timestamp;
772  memcpy(&raw.gyro_rad, &_last_sensor_data[best_index].gyro_rad, sizeof(raw.gyro_rad));
773 
774  if (_gyro.last_best_vote != best_index) {
775  _gyro.last_best_vote = (uint8_t)best_index;
776  _corrections.selected_gyro_instance = (uint8_t)best_index;
777  _corrections_changed = true;
778  }
779 
780  if (_selection.gyro_device_id != _gyro_device_id[best_index]) {
781  _selection_changed = true;
783  }
784  }
785 }
786 
788 {
789  for (int uorb_index = 0; uorb_index < _mag.subscription_count; uorb_index++) {
790  bool mag_updated;
791  orb_check(_mag.subscription[uorb_index], &mag_updated);
792 
793  if (mag_updated) {
794  struct mag_report mag_report;
795 
796  int ret = orb_copy(ORB_ID(sensor_mag), _mag.subscription[uorb_index], &mag_report);
797 
798  if (ret != PX4_OK || mag_report.timestamp == 0) {
799  continue; //ignore invalid data
800  }
801 
802  if (!_mag.enabled[uorb_index]) {
803  continue;
804  }
805 
806  // First publication with data
807  if (_mag.priority[uorb_index] == 0) {
808  int32_t priority = 0;
809  orb_priority(_mag.subscription[uorb_index], &priority);
810  _mag.priority[uorb_index] = (uint8_t)priority;
811 
812  /* force a scale and offset update the first time we get data */
814 
815  if (!_mag.enabled[uorb_index]) {
816  /* in case the data on the mag topic comes after the initial parameterUpdate(), we would get here since the sensor
817  * is enabled by default. The latest parameterUpdate() call would set enabled to false and reset priority to zero
818  * for disabled sensors, and we shouldn't cal voter.put() in that case
819  */
820  continue;
821  }
822 
823  }
824 
825  Vector3f vect(mag_report.x, mag_report.y, mag_report.z);
826  vect = _mag_rotation[uorb_index] * vect;
827 
828  _last_magnetometer[uorb_index].timestamp = mag_report.timestamp;
829  _last_magnetometer[uorb_index].magnetometer_ga[0] = vect(0);
830  _last_magnetometer[uorb_index].magnetometer_ga[1] = vect(1);
831  _last_magnetometer[uorb_index].magnetometer_ga[2] = vect(2);
832 
833  _mag.voter.put(uorb_index, mag_report.timestamp, _last_magnetometer[uorb_index].magnetometer_ga, mag_report.error_count,
834  _mag.priority[uorb_index]);
835  }
836  }
837 
838  int best_index;
839  _mag.voter.get_best(hrt_absolute_time(), &best_index);
840 
841  if (best_index >= 0) {
842  magnetometer = _last_magnetometer[best_index];
843  _mag.last_best_vote = (uint8_t)best_index;
844 
845  if (_selection.mag_device_id != _mag_device_id[best_index]) {
846  _selection_changed = true;
848  }
849  }
850 }
851 
853 {
854  bool got_update = false;
857 
858  for (int uorb_index = 0; uorb_index < _baro.subscription_count; uorb_index++) {
859  bool baro_updated;
860  orb_check(_baro.subscription[uorb_index], &baro_updated);
861 
862  if (baro_updated) {
863  sensor_baro_s baro_report;
864 
865  int ret = orb_copy(ORB_ID(sensor_baro), _baro.subscription[uorb_index], &baro_report);
866 
867  if (ret != PX4_OK || baro_report.timestamp == 0) {
868  continue; //ignore invalid data
869  }
870 
871  // Convert from millibar to Pa
872  float corrected_pressure = 100.0f * baro_report.pressure;
873 
874  // handle temperature compensation
875  if (_temperature_compensation.apply_corrections_baro(uorb_index, corrected_pressure, baro_report.temperature,
876  offsets[uorb_index], scales[uorb_index]) == 2) {
877  _corrections_changed = true;
878  }
879 
880  // First publication with data
881  if (_baro.priority[uorb_index] == 0) {
882  int32_t priority = 0;
883  orb_priority(_baro.subscription[uorb_index], &priority);
884  _baro.priority[uorb_index] = (uint8_t)priority;
885  }
886 
887  _baro_device_id[uorb_index] = baro_report.device_id;
888 
889  got_update = true;
890 
891  float vect[3] = {baro_report.pressure, baro_report.temperature, 0.f};
892 
893  _last_airdata[uorb_index].timestamp = baro_report.timestamp;
894  _last_airdata[uorb_index].baro_temp_celcius = baro_report.temperature;
895  _last_airdata[uorb_index].baro_pressure_pa = corrected_pressure;
896 
897  _baro.voter.put(uorb_index, baro_report.timestamp, vect, baro_report.error_count, _baro.priority[uorb_index]);
898  }
899  }
900 
901  if (got_update) {
902  int best_index;
903  _baro.voter.get_best(hrt_absolute_time(), &best_index);
904 
905  if (best_index >= 0) {
906  airdata = _last_airdata[best_index];
907 
908  if (_baro.last_best_vote != best_index) {
909  _baro.last_best_vote = (uint8_t)best_index;
910  _corrections.selected_baro_instance = (uint8_t)best_index;
911  _corrections_changed = true;
912  }
913 
914  if (_selection.baro_device_id != _baro_device_id[best_index]) {
915  _selection_changed = true;
917  }
918 
919  // calculate altitude using the hypsometric equation
920 
921  static constexpr float T1 = 15.0f - CONSTANTS_ABSOLUTE_NULL_CELSIUS; /* temperature at base height in Kelvin */
922  static constexpr float a = -6.5f / 1000.0f; /* temperature gradient in degrees per metre */
923 
924  /* current pressure at MSL in kPa (QNH in hPa)*/
925  const float p1 = _parameters.baro_qnh * 0.1f;
926 
927  /* measured pressure in kPa */
928  const float p = airdata.baro_pressure_pa * 0.001f;
929 
930  /*
931  * Solve:
932  *
933  * / -(aR / g) \
934  * | (p / p1) . T1 | - T1
935  * \ /
936  * h = ------------------------------- + h1
937  * a
938  */
939  airdata.baro_alt_meter = (((powf((p / p1), (-(a * CONSTANTS_AIR_GAS_CONST) / CONSTANTS_ONE_G))) * T1) - T1) / a;
940 
941 
942  // calculate air density
943  // estimate air density assuming typical 20degC ambient temperature
944  // TODO: use air temperature if available (differential pressure sensors)
945  static constexpr float pressure_to_density = 1.0f / (CONSTANTS_AIR_GAS_CONST * (20.0f -
947  airdata.rho = pressure_to_density * airdata.baro_pressure_pa;
948  }
949  }
950 }
951 
952 bool VotedSensorsUpdate::checkFailover(SensorData &sensor, const char *sensor_name, const uint64_t type)
953 {
954  if (sensor.last_failover_count != sensor.voter.failover_count() && !_hil_enabled) {
955 
956  uint32_t flags = sensor.voter.failover_state();
957  int failover_index = sensor.voter.failover_index();
958 
959  if (flags == DataValidator::ERROR_FLAG_NO_ERROR) {
960  if (failover_index != -1) {
961  //we switched due to a non-critical reason. No need to panic.
962  PX4_INFO("%s sensor switch from #%i", sensor_name, failover_index);
963  }
964 
965  } else {
966  if (failover_index != -1) {
967  mavlink_log_emergency(&_mavlink_log_pub, "%s #%i fail: %s%s%s%s%s!",
968  sensor_name,
969  failover_index,
970  ((flags & DataValidator::ERROR_FLAG_NO_DATA) ? " OFF" : ""),
971  ((flags & DataValidator::ERROR_FLAG_STALE_DATA) ? " STALE" : ""),
972  ((flags & DataValidator::ERROR_FLAG_TIMEOUT) ? " TIMEOUT" : ""),
973  ((flags & DataValidator::ERROR_FLAG_HIGH_ERRCOUNT) ? " ERR CNT" : ""),
974  ((flags & DataValidator::ERROR_FLAG_HIGH_ERRDENSITY) ? " ERR DNST" : ""));
975 
976  // reduce priority of failed sensor to the minimum
977  sensor.priority[failover_index] = 1;
978 
979  PX4_ERR("Sensor %s #%i failed. Reconfiguring sensor priorities.", sensor_name, failover_index);
980 
981  int ctr_valid = 0;
982 
983  for (uint8_t i = 0; i < sensor.subscription_count; i++) {
984  if (sensor.priority[i] > 1) { ctr_valid++; }
985 
986  PX4_WARN("Remaining sensors after failover event %u: %s #%u priority: %u", failover_index, sensor_name, i,
987  sensor.priority[i]);
988  }
989 
990  if (ctr_valid < 2) {
991  if (ctr_valid == 0) {
992  // Zero valid sensors remain! Set even the primary sensor health to false
993  _info.subsystem_type = type;
994 
995  } else if (ctr_valid == 1) {
996  // One valid sensor remains, set secondary sensor health to false
997  if (type == subsystem_info_s::SUBSYSTEM_TYPE_GYRO) { _info.subsystem_type = subsystem_info_s::SUBSYSTEM_TYPE_GYRO2; }
998 
999  if (type == subsystem_info_s::SUBSYSTEM_TYPE_ACC) { _info.subsystem_type = subsystem_info_s::SUBSYSTEM_TYPE_ACC2; }
1000 
1001  if (type == subsystem_info_s::SUBSYSTEM_TYPE_MAG) { _info.subsystem_type = subsystem_info_s::SUBSYSTEM_TYPE_MAG2; }
1002  }
1003 
1005  _info.present = true;
1006  _info.enabled = true;
1007  _info.ok = false;
1008 
1010  }
1011  }
1012  }
1013 
1014  sensor.last_failover_count = sensor.voter.failover_count();
1015  return true;
1016  }
1017 
1018  return false;
1019 }
1020 
1021 void VotedSensorsUpdate::initSensorClass(const struct orb_metadata *meta, SensorData &sensor_data,
1022  uint8_t sensor_count_max)
1023 {
1024  int max_sensor_index = -1;
1025 
1026  for (unsigned i = 0; i < sensor_count_max; i++) {
1027  if (orb_exists(meta, i) != 0) {
1028  continue;
1029  }
1030 
1031  max_sensor_index = i;
1032 
1033  if (sensor_data.subscription[i] < 0) {
1034  sensor_data.subscription[i] = orb_subscribe_multi(meta, i);
1035 
1036  if (i > 0) {
1037  /* the first always exists, but for each further sensor, add a new validator */
1038  if (!sensor_data.voter.add_new_validator()) {
1039  PX4_ERR("failed to add validator for sensor %s %i", meta->o_name, i);
1040  }
1041  }
1042  }
1043  }
1044 
1045  // never decrease the sensor count, as we could end up with mismatching validators
1046  if (max_sensor_index + 1 > sensor_data.subscription_count) {
1047  sensor_data.subscription_count = max_sensor_index + 1;
1048  }
1049 }
1050 
1052 {
1053  PX4_INFO("gyro status:");
1054  _gyro.voter.print();
1055  PX4_INFO("accel status:");
1056  _accel.voter.print();
1057  PX4_INFO("mag status:");
1058  _mag.voter.print();
1059  PX4_INFO("baro status:");
1060  _baro.voter.print();
1061 
1063 }
1064 
1065 bool
1066 VotedSensorsUpdate::applyGyroCalibration(DevHandle &h, const struct gyro_calibration_s *gcal, const int device_id)
1067 {
1068 #if defined(__PX4_NUTTX)
1069 
1070  /* On most systems, we can just use the IOCTL call to set the calibration params. */
1071  return !h.ioctl(GYROIOCSSCALE, (long unsigned int)gcal);
1072 
1073 #else
1074  /* On QURT, the params are read directly in the respective wrappers. */
1075  return true;
1076 #endif
1077 }
1078 
1079 bool
1081 {
1082 #if defined(__PX4_NUTTX)
1083 
1084  /* On most systems, we can just use the IOCTL call to set the calibration params. */
1085  return !h.ioctl(ACCELIOCSSCALE, (long unsigned int)acal);
1086 
1087 #else
1088  /* On QURT, the params are read directly in the respective wrappers. */
1089  return true;
1090 #endif
1091 }
1092 
1093 bool
1094 VotedSensorsUpdate::applyMagCalibration(DevHandle &h, const struct mag_calibration_s *mcal, const int device_id)
1095 {
1096 #if defined(__PX4_NUTTX)
1097 
1098  if (!h.isValid()) {
1099  return false;
1100  }
1101 
1102  /* On most systems, we can just use the IOCTL call to set the calibration params. */
1103  return !h.ioctl(MAGIOCSSCALE, (long unsigned int)mcal);
1104 
1105 #else
1106  /* On QURT & POSIX, the params are read directly in the respective wrappers. */
1107  return true;
1108 #endif
1109 }
1110 
1112  vehicle_magnetometer_s &magnetometer)
1113 {
1114  accelPoll(raw);
1115  gyroPoll(raw);
1116  magPoll(magnetometer);
1117  baroPoll(airdata);
1118 
1119  // publish sensor corrections if necessary
1120  if (_corrections_changed) {
1122 
1124 
1125  _corrections_changed = false;
1126  }
1127 
1128  // publish sensor selection if changed
1129  if (_selection_changed) {
1131 
1133 
1134  _selection_changed = false;
1135  }
1136 }
1137 
1139 {
1140  checkFailover(_accel, "Accel", subsystem_info_s::SUBSYSTEM_TYPE_ACC);
1141  checkFailover(_gyro, "Gyro", subsystem_info_s::SUBSYSTEM_TYPE_GYRO);
1142  checkFailover(_mag, "Mag", subsystem_info_s::SUBSYSTEM_TYPE_MAG);
1143  checkFailover(_baro, "Baro", subsystem_info_s::SUBSYSTEM_TYPE_ABSPRESSURE);
1144 }
1145 
1147 {
1150  (int64_t)raw.timestamp);
1151  }
1152 }
1153 
1154 void
1156 {
1157  float accel_diff_sum_max_sq = 0.0f; // the maximum sum of axis differences squared
1158  unsigned check_index = 0; // the number of sensors the primary has been checked against
1159 
1160  // Check each sensor against the primary
1161  for (int sensor_index = 0; sensor_index < _accel.subscription_count; sensor_index++) {
1162 
1163  // check that the sensor we are checking against is not the same as the primary
1164  if ((_accel.priority[sensor_index] > 0) && (sensor_index != _accel.last_best_vote)) {
1165 
1166  float accel_diff_sum_sq = 0.0f; // sum of differences squared for a single sensor comparison agains the primary
1167 
1168  // calculate accel_diff_sum_sq for the specified sensor against the primary
1169  for (unsigned axis_index = 0; axis_index < 3; axis_index++) {
1170  _accel_diff[axis_index][check_index] = 0.95f * _accel_diff[axis_index][check_index] + 0.05f *
1172  _last_sensor_data[sensor_index].accelerometer_m_s2[axis_index]);
1173  accel_diff_sum_sq += _accel_diff[axis_index][check_index] * _accel_diff[axis_index][check_index];
1174 
1175  }
1176 
1177  // capture the largest sum value
1178  if (accel_diff_sum_sq > accel_diff_sum_max_sq) {
1179  accel_diff_sum_max_sq = accel_diff_sum_sq;
1180 
1181  }
1182 
1183  // increment the check index
1184  check_index++;
1185  }
1186 
1187  // check to see if the maximum number of checks has been reached and break
1188  if (check_index >= 2) {
1189  break;
1190 
1191  }
1192  }
1193 
1194  // skip check if less than 2 sensors
1195  if (check_index < 1) {
1196  preflt.accel_inconsistency_m_s_s = 0.0f;
1197 
1198  } else {
1199  // get the vector length of the largest difference and write to the combined sensor struct
1200  preflt.accel_inconsistency_m_s_s = sqrtf(accel_diff_sum_max_sq);
1201  }
1202 }
1203 
1205 {
1206  float gyro_diff_sum_max_sq = 0.0f; // the maximum sum of axis differences squared
1207  unsigned check_index = 0; // the number of sensors the primary has been checked against
1208 
1209  // Check each sensor against the primary
1210  for (int sensor_index = 0; sensor_index < _gyro.subscription_count; sensor_index++) {
1211 
1212  // check that the sensor we are checking against is not the same as the primary
1213  if ((_gyro.priority[sensor_index] > 0) && (sensor_index != _gyro.last_best_vote)) {
1214 
1215  float gyro_diff_sum_sq = 0.0f; // sum of differences squared for a single sensor comparison against the primary
1216 
1217  // calculate gyro_diff_sum_sq for the specified sensor against the primary
1218  for (unsigned axis_index = 0; axis_index < 3; axis_index++) {
1219  _gyro_diff[axis_index][check_index] = 0.95f * _gyro_diff[axis_index][check_index] + 0.05f *
1221  _last_sensor_data[sensor_index].gyro_rad[axis_index]);
1222  gyro_diff_sum_sq += _gyro_diff[axis_index][check_index] * _gyro_diff[axis_index][check_index];
1223 
1224  }
1225 
1226  // capture the largest sum value
1227  if (gyro_diff_sum_sq > gyro_diff_sum_max_sq) {
1228  gyro_diff_sum_max_sq = gyro_diff_sum_sq;
1229 
1230  }
1231 
1232  // increment the check index
1233  check_index++;
1234  }
1235 
1236  // check to see if the maximum number of checks has been reached and break
1237  if (check_index >= 2) {
1238  break;
1239 
1240  }
1241  }
1242 
1243  // skip check if less than 2 sensors
1244  if (check_index < 1) {
1245  preflt.gyro_inconsistency_rad_s = 0.0f;
1246 
1247  } else {
1248  // get the vector length of the largest difference and write to the combined sensor struct
1249  preflt.gyro_inconsistency_rad_s = sqrtf(gyro_diff_sum_max_sq);
1250  }
1251 }
1252 
1254 {
1255  Vector3f primary_mag(_last_magnetometer[_mag.last_best_vote].magnetometer_ga); // primary mag field vector
1256  float mag_angle_diff_max = 0.0f; // the maximum angle difference
1257  unsigned check_index = 0; // the number of sensors the primary has been checked against
1258 
1259  // Check each sensor against the primary
1260  for (int i = 0; i < _mag.subscription_count; i++) {
1261  // check that the sensor we are checking against is not the same as the primary
1262  if ((_mag.priority[i] > 0) && (i != _mag.last_best_vote)) {
1263  // calculate angle to 3D magnetic field vector of the primary sensor
1264  Vector3f current_mag(_last_magnetometer[i].magnetometer_ga);
1265  float angle_error = AxisAnglef(Quatf(current_mag, primary_mag)).angle();
1266 
1267  // complementary filter to not fail/pass on single outliers
1268  _mag_angle_diff[check_index] *= 0.95f;
1269  _mag_angle_diff[check_index] += 0.05f * angle_error;
1270 
1271  mag_angle_diff_max = math::max(mag_angle_diff_max, _mag_angle_diff[check_index]);
1272 
1273  // increment the check index
1274  check_index++;
1275  }
1276 
1277  // check to see if the maximum number of checks has been reached and break
1278  if (check_index >= 2) {
1279  break;
1280  }
1281  }
1282 
1283  // get the vector length of the largest difference and write to the combined sensor struct
1284  // will be zero if there is only one magnetometer and hence nothing to compare
1285  preflt.mag_inconsistency_angle = mag_angle_diff_max;
1286 }
uint32_t _baro_device_id[SENSOR_COUNT_MAX]
baro driver device id for each uorb instance
uint32_t integral_dt
Definition: sensor_accel.h:59
sensor_selection_s _selection
struct containing the sensor selection to be published to the uORB
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
Definition: uORB.cpp:90
static constexpr uint32_t ERROR_FLAG_NO_ERROR
Data validator error states.
static constexpr float CONSTANTS_AIR_GAS_CONST
Definition: geo.h:58
bool applyMagCalibration(DriverFramework::DevHandle &h, const struct mag_calibration_s *mcal, const int device_id)
Apply a mag calibration.
uint64_t timestamp
Definition: sensor_accel.h:53
static constexpr float CONSTANTS_ABSOLUTE_NULL_CELSIUS
Definition: geo.h:59
vehicle_magnetometer_s _last_magnetometer[SENSOR_COUNT_MAX]
latest sensor data from all sensors instances
void magPoll(vehicle_magnetometer_s &magnetometer)
Poll the magnetometer for updated data.
VotedSensorsUpdate(const Parameters &parameters, bool hil_enabled)
void sensorsPoll(sensor_combined_s &raw, vehicle_air_data_s &airdata, vehicle_magnetometer_s &magnetometer)
read new sensor data
constexpr uint8_t GYRO_COUNT_MAX
Definition: common.h:47
int set_sensor_id_accel(uint32_t device_id, int topic_instance)
void put(unsigned index, uint64_t timestamp, const float val[3], uint64_t error_count, int priority)
Put an item into the validator group.
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
gyro scaling factors; Vout = (Vin * Vscale) + Voffset
Definition: drv_gyro.h:54
Definition of geo / math functions to perform geodesic calculations.
void set_timeout(uint32_t timeout_interval_us)
Set the timeout value for the whole group.
uORB::Publication< sensor_correction_s > _sensor_correction_pub
handle to the sensor correction uORB topic
void setRelativeTimestamps(sensor_combined_s &raw)
set the relative timestamps of each sensor timestamp, based on the last sensorsPoll, so that the data can be published.
__EXPORT int param_set_no_notification(param_t param, const void *val)
Set the value of a parameter, but do not notify the system about the change.
Definition: parameters.cpp:820
sensor_correction_s _corrections
struct containing the sensor corrections to be published to the uORB
void baroPoll(vehicle_air_data_s &airdata)
Poll the barometer for updated data.
int orb_priority(int handle, int32_t *priority)
Definition: uORB.cpp:121
vehicle_air_data_s _last_airdata[SENSOR_COUNT_MAX]
latest sensor data from all sensors instances
__EXPORT int param_set(param_t param, const void *val)
Set the value of a parameter.
Definition: parameters.cpp:814
uint64_t error_count
Definition: sensor_gyro.h:54
bool publish(const T &data)
Publish the struct.
mag scaling factors; Vout = (Vin * Vscale) + Voffset
Definition: drv_mag.h:56
uint64_t error_count
Definition: sensor_baro.h:54
static constexpr uint32_t ERROR_FLAG_TIMEOUT
float x_integral
Definition: sensor_gyro.h:60
int failover_index()
Get the index of the failed sensor in the group.
float accelerometer_m_s2[3]
uint64_t subsystem_type
void initializeSensors()
This tries to find new sensor instances.
static const char * sensor_name
uint32_t device_id
Definition: sensor_baro.h:55
int orb_exists(const struct orb_metadata *meta, int instance)
Definition: uORB.cpp:105
void print()
Print the validator value.
uint32_t failover_state()
Get the error state of the failed sensor in the group.
static int32_t device_id[max_accel_sens]
Vector rotation library.
int init(sensor_combined_s &raw)
initialize subscriptions etc.
static constexpr float CONSTANTS_ONE_G
Definition: geo.h:51
void calcMagInconsistency(sensor_preflight_s &preflt)
Calculates the magnitude in Gauss of the largest difference between the primary and any other magneto...
accel scaling factors; Vout = Vscale * (Vin + Voffset)
Definition: drv_accel.h:54
const char * o_name
unique object name
Definition: uORB.h:51
static constexpr uint32_t ERROR_FLAG_STALE_DATA
uint32_t _gyro_device_id[SENSOR_COUNT_MAX]
gyro driver device id for each uorb instance
#define CAL_ERROR_APPLY_CAL_MSG
const bool _hil_enabled
is hardware-in-the-loop mode enabled?
float * get_best(uint64_t timestamp, int *index)
Get the best data triplet of the group.
float x_offset
Definition: drv_mag.h:57
#define ACCEL_BASE_DEVICE_PATH
Definition: drv_accel.h:49
float z_integral
Definition: sensor_gyro.h:62
float temperature
Definition: sensor_baro.h:57
sensor_combined_s _last_sensor_data[SENSOR_COUNT_MAX]
latest sensor data from all sensors instances
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
float pressure
Definition: sensor_baro.h:56
static constexpr uint32_t ERROR_FLAG_HIGH_ERRCOUNT
bool publish(const T &data)
Publish the struct.
Definition: Publication.hpp:68
#define MAGIOCSSCALE
set the mag scaling constants to the structure pointed to by (arg)
Definition: drv_mag.h:73
constexpr uint8_t ACCEL_COUNT_MAX
Definition: common.h:48
constexpr uint8_t MAG_COUNT_MAX
Definition: common.h:46
#define GYRO_BASE_DEVICE_PATH
Definition: drv_gyro.h:49
#define MAG_BASE_DEVICE_PATH
Definition: drv_mag.h:47
int parameters_update(bool hil_enabled=false)
(re)load the parameters.
bool _selection_changed
true when a sensor selection has changed and not been published
Rotation
Enum for board and external compass rotations.
Definition: rotation.h:51
void set_equal_value_threshold(uint32_t threshold)
Set the equal count threshold for the whole group.
int orb_unsubscribe(int handle)
Definition: uORB.cpp:85
DataValidator * add_new_validator()
Create a new Validator (with index equal to the number of currently existing validators) ...
uint8_t priority[SENSOR_COUNT_MAX]
sensor priority
float y_integral
Definition: sensor_gyro.h:61
float y_offset
Definition: drv_mag.h:59
Euler< float > Eulerf
Definition: Euler.hpp:156
float _gyro_diff[3][2]
filtered gyro differences between IMU uinits (rad/s)
int subscription[SENSOR_COUNT_MAX]
raw sensor data subscription
uint32_t _accel_device_id[SENSOR_COUNT_MAX]
accel driver device id for each uorb instance
uint64_t timestamp
Definition: sensor_gyro.h:53
uint32_t gyro_integral_dt
uint64_t error_count
Definition: sensor_accel.h:54
uint64_t _last_accel_timestamp[ACCEL_COUNT_MAX]
latest full timestamp
void initSensorClass(const orb_metadata *meta, SensorData &sensor_data, uint8_t sensor_count_max)
uint32_t device_id
Definition: sensor_gyro.h:55
float z_offset
Definition: drv_mag.h:61
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
Definition: common.h:43
Vector3< float > Vector3f
Definition: Vector3.hpp:136
#define ACCELIOCSSCALE
set the accel scaling constants to the structure pointed to by (arg)
Definition: drv_accel.h:73
static constexpr uint32_t ERROR_FLAG_NO_DATA
struct uart_esc::@18 _parameters
int set_sensor_id_gyro(uint32_t device_id, int topic_instance)
supply information which device_id matches a specific uORB topic_instance (needed if a system has mul...
Object metadata.
Definition: uORB.h:50
static constexpr uint32_t ERROR_FLAG_HIGH_ERRDENSITY
unsigned failover_count() const
Get the number of failover events.
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
void calcAccelInconsistency(sensor_preflight_s &preflt)
Calculates the magnitude in m/s/s of the largest difference between the primary and any other accel s...
float _mag_angle_diff[2]
filtered mag angle differences between sensor instances (Ga)
Quaternion< float > Quatf
Definition: Quaternion.hpp:544
TemperatureCompensation _temperature_compensation
sensor thermal compensation
matrix::Dcmf _mag_rotation[MAG_COUNT_MAX]
rotation matrix for the orientation that the external mag0 is mounted
void print_status()
output current configuration status to console
int orb_check(int handle, bool *updated)
Definition: uORB.cpp:95
int orb_subscribe_multi(const struct orb_metadata *meta, unsigned instance)
Definition: uORB.cpp:80
float temperature
Definition: sensor_gyro.h:63
bool applyAccelCalibration(DriverFramework::DevHandle &h, const struct accel_calibration_s *acal, const int device_id)
Apply a accel calibration.
uint32_t _mag_device_id[SENSOR_COUNT_MAX]
mag driver device id for each uorb instance
void parametersUpdate()
call this whenever parameters got updated.
uint32_t device_id
Definition: sensor_accel.h:55
float board_offset[3]
Definition: parameters.h:57
__EXPORT matrix::Dcmf get_rot_matrix(enum Rotation rot)
Get the rotation matrix.
Definition: rotation.cpp:45
#define GYROIOCSSCALE
set the gyro scaling constants to (arg)
Definition: drv_gyro.h:71
int apply_corrections_baro(int topic_instance, float &sensor_data, float temperature, float *offsets, float *scales)
AxisAngle< float > AxisAnglef
Definition: AxisAngle.hpp:160
matrix::Dcmf _board_rotation
rotation matrix for the orientation that the board is mounted
#define OK
Definition: uavcan_main.cpp:71
uORB::Publication< sensor_selection_s > _sensor_selection_pub
handle to the sensor selection uORB topic
void accelPoll(sensor_combined_s &raw)
Poll the accelerometer for updated data.
uORB::PublicationQueued< subsystem_info_s > _info_pub
int apply_corrections_accel(int topic_instance, matrix::Vector3f &sensor_data, float temperature, float *offsets, float *scales)
uint64_t timestamp
Definition: sensor_baro.h:53
int32_t board_rotation
Definition: parameters.h:55
int apply_corrections_gyro(int topic_instance, matrix::Vector3f &sensor_data, float temperature, float *offsets, float *scales)
Apply Thermal corrections to gyro (& other) sensor data.
int32_t accelerometer_timestamp_relative
int set_sensor_id_baro(uint32_t device_id, int topic_instance)
subsystem_info_s _info
subsystem info publication
#define MAG_ROT_VAL_INTERNAL
void deinit()
deinitialize the object (we cannot use the destructor because it is called on the wrong thread) ...
constexpr uint8_t BARO_COUNT_MAX
Definition: common.h:49
void checkFailover()
check if a failover event occured.
void gyroPoll(sensor_combined_s &raw)
Poll the gyro for updated data.
float _accel_diff[3][2]
filtered accel differences between IMU units (m/s/s)
uint32_t accelerometer_integral_dt
void calcGyroInconsistency(sensor_preflight_s &preflt)
Calculates the magnitude in rad/s of the largest difference between the primary and any other gyro se...
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint8_t last_best_vote
index of the latest best vote
uint32_t integral_dt
Definition: sensor_gyro.h:59
bool applyGyroCalibration(DriverFramework::DevHandle &h, const struct gyro_calibration_s *gcal, const int device_id)
Apply a gyro calibration.
#define mag_report
Definition: drv_mag.h:53