diff --git a/libraries/AP_Compass/AP_Compass.h b/libraries/AP_Compass/AP_Compass.h index ebc458f0713f52ab4abe6e120cc6975d3b9d41c6..83112a359eb353593de69071138c00278c904f05 100644 --- a/libraries/AP_Compass/AP_Compass.h +++ b/libraries/AP_Compass/AP_Compass.h @@ -6,3 +6,4 @@ #include "AP_Compass_HMC5843.h" #include "AP_Compass_HIL.h" #include "AP_Compass_PX4.h" +#include "AP_Compass_VRBRAIN.h" diff --git a/libraries/AP_Compass/AP_Compass_VRBRAIN.cpp b/libraries/AP_Compass/AP_Compass_VRBRAIN.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de3a809ac73fde2e8aba3cf8675bc272357f10c7 --- /dev/null +++ b/libraries/AP_Compass/AP_Compass_VRBRAIN.cpp @@ -0,0 +1,155 @@ +/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- +/* + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * AP_Compass_VRBRAIN.cpp - Arduino Library for VRBRAIN magnetometer + * + */ + + +#include <AP_HAL.h> + +#if CONFIG_HAL_BOARD == HAL_BOARD_VRBRAIN +#include "AP_Compass_VRBRAIN.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include <drivers/drv_mag.h> +#include <drivers/drv_hrt.h> +#include <stdio.h> +#include <errno.h> + +extern const AP_HAL::HAL& hal; + + +// Public Methods ////////////////////////////////////////////////////////////// + +bool AP_Compass_VRBRAIN::init(void) +{ + _mag_fd[0] = open(MAG_DEVICE_PATH, O_RDONLY); + if (_mag_fd[0] < 0) { + hal.console->printf("Unable to open " MAG_DEVICE_PATH "\n"); + return false; + } + + _mag_fd[1] = open(MAG_DEVICE_PATH "1", O_RDONLY); + if (_mag_fd[1] >= 0) { + _num_instances = 2; + } else { + _num_instances = 1; + } + + for (uint8_t i=0; i<_num_instances; i++) { + // average over up to 20 samples + if (ioctl(_mag_fd[i], SENSORIOCSQUEUEDEPTH, 20) != 0) { + hal.console->printf("Failed to setup compass queue\n"); + return false; + } + + // remember if the compass is external + _is_external[i] = (ioctl(_mag_fd[i], MAGIOCGEXTERNAL, 0) > 0); + if (_is_external[i]) { + hal.console->printf("Using external compass[%u]\n", (unsigned)i); + } + _count[0] = 0; + _sum[i].zero(); + _healthy[i] = false; + } + + // give the driver a chance to run, and gather one sample + hal.scheduler->delay(40); + accumulate(); + if (_count[0] == 0) { + hal.console->printf("Failed initial compass accumulate\n"); + } + return true; +} + +bool AP_Compass_VRBRAIN::read(void) +{ + // try to accumulate one more sample, so we have the latest data + accumulate(); + + // consider the compass healthy if we got a reading in the last 0.2s + for (uint8_t i=0; i<_num_instances; i++) { + _healthy[i] = (hrt_absolute_time() - _last_timestamp[i] < 200000); + } + + for (uint8_t i=0; i<_num_instances; i++) { + _sum[i] /= _count[i]; + _sum[i] *= 1000; + + // apply default board orientation for this compass type. This is + // a noop on most boards + _sum[i].rotate(MAG_BOARD_ORIENTATION); + + // override any user setting of COMPASS_EXTERNAL + _external.set(_is_external[0]); + + if (_is_external[i]) { + // add user selectable orientation + _sum[i].rotate((enum Rotation)_orientation.get()); + } else { + // add in board orientation from AHRS + _sum[i].rotate(_board_orientation); + } + + _sum[i] += _offset[i].get(); + + // apply motor compensation + if (_motor_comp_type != AP_COMPASS_MOT_COMP_DISABLED && _thr_or_curr != 0.0f) { + _motor_offset[i] = _motor_compensation[i].get() * _thr_or_curr; + _sum[i] += _motor_offset[i]; + } else { + _motor_offset[i].zero(); + } + + _field[i] = _sum[i]; + + _sum[i].zero(); + _count[i] = 0; + } + + last_update = _last_timestamp[0]; + + return _healthy[0]; +} + +void AP_Compass_VRBRAIN::accumulate(void) +{ + struct mag_report mag_report; + for (uint8_t i=0; i<_num_instances; i++) { + while (::read(_mag_fd[i], &mag_report, sizeof(mag_report)) == sizeof(mag_report) && + mag_report.timestamp != _last_timestamp[i]) { + _sum[i] += Vector3f(mag_report.x, mag_report.y, mag_report.z); + _count[i]++; + _last_timestamp[i] = mag_report.timestamp; + } + } +} + +uint8_t AP_Compass_VRBRAIN::_get_primary(void) const +{ + for (uint8_t i=0; i<_num_instances; i++) { + if (_healthy[i]) return i; + } + return 0; +} + +#endif // CONFIG_HAL_BOARD diff --git a/libraries/AP_Compass/AP_Compass_VRBRAIN.h b/libraries/AP_Compass/AP_Compass_VRBRAIN.h new file mode 100644 index 0000000000000000000000000000000000000000..0a560f926c7d929e06a3de489624635ced294876 --- /dev/null +++ b/libraries/AP_Compass/AP_Compass_VRBRAIN.h @@ -0,0 +1,33 @@ +/// -*- tab-width: 4; Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- + +#ifndef AP_Compass_VRBRAIN_H +#define AP_Compass_VRBRAIN_H + +#include "Compass.h" + +class AP_Compass_VRBRAIN : public Compass +{ +public: + AP_Compass_VRBRAIN() : Compass() { + product_id = AP_COMPASS_TYPE_VRBRAIN; + _num_instances = 0; + } + bool init(void); + bool read(void); + void accumulate(void); + + // return the number of compass instances + uint8_t get_count(void) const { return _num_instances; } + +private: + uint8_t _get_primary(void) const; + uint8_t _num_instances; + int _mag_fd[COMPASS_MAX_INSTANCES]; + Vector3f _sum[COMPASS_MAX_INSTANCES]; + uint32_t _count[COMPASS_MAX_INSTANCES]; + uint64_t _last_timestamp[COMPASS_MAX_INSTANCES]; + bool _is_external[COMPASS_MAX_INSTANCES]; +}; + +#endif // AP_Compass_VRBRAIN_H + diff --git a/libraries/AP_Compass/Compass.h b/libraries/AP_Compass/Compass.h index 418368456b7ba1e23bb2d9f53e448a65cdd41172..7efe596c4edd14fbc183e8c59020d42c82c438ad 100644 --- a/libraries/AP_Compass/Compass.h +++ b/libraries/AP_Compass/Compass.h @@ -14,6 +14,7 @@ #define AP_COMPASS_TYPE_HMC5843 0x02 #define AP_COMPASS_TYPE_HMC5883L 0x03 #define AP_COMPASS_TYPE_PX4 0x04 +#define AP_COMPASS_TYPE_VRBRAIN 0x05 // motor compensation types (for use with motor_comp_enabled) #define AP_COMPASS_MOT_COMP_DISABLED 0x00 @@ -33,6 +34,8 @@ # define MAG_BOARD_ORIENTATION ROTATION_NONE #elif CONFIG_HAL_BOARD == HAL_BOARD_LINUX # define MAG_BOARD_ORIENTATION ROTATION_YAW_90 +#elif CONFIG_HAL_BOARD == HAL_BOARD_VRBRAIN +# define MAG_BOARD_ORIENTATION ROTATION_NONE #else # error "You must define a default compass orientation for this board" #endif