ardupilot/libraries/AP_NavEKF3/AP_NavEKF3_Buffer.h

189 lines
5.6 KiB
C
Raw Normal View History

AP_NavEKF3: added EKF3 for EKF experimentation AP_NavEKF3: Implement same maths as PX4/ecl EKF Replace attitude vector states with quaternions Remove gyro scale factor states Add XY accel delta velocity bias estimation Initial tuning Add GPS body frame offset compensation AP_NavEKF3: Fix bugs and consolidate aiding switch logic Switching in and out of aiding modes was being performed in more than one place and was using two variables. The reversion out of GPS mode due to prolonged loss of GPS was not working. This consolidates the logic and ensures that PV_AidingMode is only changed by the setAidingMode function. AP_NavEKF3: prevent multiple fusion mode changes per filter update AP_NavEKF3: Update tuning defaults AP_NavEKF3: Fix bug causing switching in and out of aiding If the GPS receiver was disconnected and no data received, then then the gpsGoodToAlign check did not get a chance to run and becasue it was previously true the EKF would switch back into aiding. This prevents this by ensuring that gpsGoodToAlign defaults to false when the check is not being performed. An additional check has also been dded to ensure that there is GPS data to fuse before we declare ready to use GPS. AP_NavEKF3: Fix bug preventing planes recovering from bad magnetometers This bug created a race condition whereby if the EKF had to reset the yaw to the GPS ground course to recover from a bad magnetometer, the new heading could be over-written by the bad magnetic heading when the plane reached the height for the scheduled reset. AP_NavEKF3: Improve switch-over to backup magnetometer When switching over to a back up magnetometer, ensure that the earth field estimate are reset. Otherwise mag earth field estimates due to the previous failed mag could cause data from the new mag to be rejected. AP_NavEKF3: enable automatic use of range finder height AP_NavEKF3: Fix bug in handling of invalid range data AP_NavEKF3: Fix height drift on ground using range finder without GPSAP_NavEKF3: AP_NavEKF3: Handle yaw jumps due to core switches AP_NavEKF3: Enable simultaneous GPS and optical flow use AP_NavEKF3: fix console status reporting AP_NavEKF3: send messages to mavlink instead of console This allows the GCS to better handle the display of messages to the user. AP_NavEKF3: replace deprecated function call AP_NavEKF3: Compensate for sensor body frame offsets AP_NavEKF3: Fix bug in median filter code AP_NavEKF3: save some memory in the position offsets in EKF3 We don't need to copy that vector3f for every sample. A uint8_t does the job AP_NavEKF3: Add fusion of range beacon data AP_NavEKF3: Bring up to date with EKF2 AP_NavEKF3: Misc range beacon updates AP_NavEKF3: Add mising accessors AP_NavEKF3: remove duplicate include AP_NavEKF3: Prevent NaN's when accessing range beacon debug data AP_NavEKF3: Update range beacon naming AP_NavEKF3: updates AP_NavEKF3: miscellaneous changes AP_NavEKF3: misc updates AP_NavEKF3: misc range beacons updates AP_NavEKF3: add missing rover default param
2016-07-14 02:08:43 -03:00
// EKF Buffer models
// this buffer model is to be used for observation buffers,
// the data is pushed into buffer like any standard ring buffer
// return is based on the sample time provided
template <typename element_type>
class obs_ring_buffer_t
{
public:
struct element_t{
element_type element;
} *buffer;
// initialise buffer, returns false when allocation has failed
bool init(uint32_t size)
{
buffer = new element_t[size];
if(buffer == nullptr)
{
return false;
}
memset(buffer,0,size*sizeof(element_t));
_size = size;
_head = 0;
_tail = 0;
_new_data = false;
return true;
}
/*
* Searches through a ring buffer and return the newest data that is older than the
* time specified by sample_time_ms
* Zeros old data so it cannot not be used again
* Returns false if no data can be found that is less than 100msec old
*/
bool recall(element_type &element,uint32_t sample_time)
{
if(!_new_data) {
return false;
}
bool success = false;
uint8_t tail = _tail, bestIndex;
if(_head == tail) {
if (buffer[tail].element.time_ms != 0 && buffer[tail].element.time_ms <= sample_time) {
// if head is equal to tail just check if the data is unused and within time horizon window
if (((sample_time - buffer[tail].element.time_ms) < 100)) {
bestIndex = tail;
success = true;
_new_data = false;
}
}
} else {
while(_head != tail) {
// find a measurement older than the fusion time horizon that we haven't checked before
if (buffer[tail].element.time_ms != 0 && buffer[tail].element.time_ms <= sample_time) {
// Find the most recent non-stale measurement that meets the time horizon criteria
if (((sample_time - buffer[tail].element.time_ms) < 100)) {
bestIndex = tail;
success = true;
}
} else if(buffer[tail].element.time_ms > sample_time){
break;
}
tail = (tail+1)%_size;
}
}
if (success) {
element = buffer[bestIndex].element;
_tail = (bestIndex+1)%_size;
//make time zero to stop using it again,
//resolves corner case of reusing the element when head == tail
buffer[bestIndex].element.time_ms = 0;
return true;
} else {
return false;
}
}
/*
* Writes data and timestamp to a Ring buffer and advances indices that
* define the location of the newest and oldest data
*/
inline void push(element_type element)
{
// Advance head to next available index
_head = (_head+1)%_size;
// New data is written at the head
buffer[_head].element = element;
_new_data = true;
}
// writes the same data to all elements in the ring buffer
inline void reset_history(element_type element, uint32_t sample_time) {
for (uint8_t index=0; index<_size; index++) {
buffer[index].element = element;
}
}
// zeroes all data in the ring buffer
inline void reset() {
_head = 0;
_tail = 0;
_new_data = false;
memset(buffer,0,_size*sizeof(element_t));
}
private:
uint8_t _size,_head,_tail,_new_data;
};
// Following buffer model is for IMU data,
// it achieves a distance of sample size
// between youngest and oldest
template <typename element_type>
class imu_ring_buffer_t
{
public:
struct element_t{
element_type element;
} *buffer;
// initialise buffer, returns false when allocation has failed
bool init(uint32_t size)
{
buffer = new element_t[size];
if(buffer == nullptr)
{
return false;
}
memset(buffer,0,size*sizeof(element_t));
_size = size;
_youngest = 0;
_oldest = 0;
return true;
}
/*
* Writes data to a Ring buffer and advances indices that
* define the location of the newest and oldest data
*/
inline void push_youngest_element(element_type element)
{
// push youngest to the buffer
_youngest = (_youngest+1)%_size;
buffer[_youngest].element = element;
// set oldest data index
_oldest = (_youngest+1)%_size;
}
// retrieve the oldest data from the ring buffer tail
inline element_type pop_oldest_element() {
element_type ret = buffer[_oldest].element;
return ret;
}
// writes the same data to all elements in the ring buffer
inline void reset_history(element_type element) {
for (uint8_t index=0; index<_size; index++) {
buffer[index].element = element;
}
}
// zeroes all data in the ring buffer
inline void reset() {
_youngest = 0;
_oldest = 0;
memset(buffer,0,_size*sizeof(element_t));
}
// retrieves data from the ring buffer at a specified index
inline element_type& operator[](uint32_t index) {
return buffer[index].element;
}
// returns the index for the ring buffer oldest data
inline uint8_t get_oldest_index(){
return _oldest;
}
// returns the index for the ring buffer youngest data
inline uint8_t get_youngest_index(){
return _youngest;
}
private:
uint8_t _size,_oldest,_youngest;
};