ekf2: move EKF out of ecl

This commit is contained in:
Daniel Agar
2021-07-15 10:38:24 -04:00
parent 883624d915
commit 2cf66a5d8f
216 changed files with 1369 additions and 2399 deletions
@@ -0,0 +1 @@
__pycache__/
@@ -0,0 +1,51 @@
############################################################################
#
# Copyright (c) 2019 ECL Development Team. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name ECL nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
set(SRCS
sensor_simulator.cpp
ekf_wrapper.cpp
ekf_logger.cpp
sensor.cpp
imu.cpp
mag.cpp
baro.cpp
gps.cpp
flow.cpp
range_finder.cpp
vio.cpp
airspeed.cpp
)
add_library(ecl_sensor_sim ${SRCS})
target_link_libraries(ecl_sensor_sim ecl_EKF)
@@ -0,0 +1,34 @@
#include "airspeed.h"
namespace sensor_simulator
{
namespace sensor
{
Airspeed::Airspeed(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Airspeed::~Airspeed()
{
}
void Airspeed::send(uint64_t time)
{
if (_true_airspeed_data > FLT_EPSILON && _indicated_airspeed_data > FLT_EPSILON) {
airspeedSample airspeed_sample;
airspeed_sample.time_us = time;
airspeed_sample.eas2tas = _true_airspeed_data / _indicated_airspeed_data;
airspeed_sample.true_airspeed = _true_airspeed_data;
_ekf->setAirspeedData(airspeed_sample);
}
}
void Airspeed::setData(float true_airspeed, float indicated_airspeed)
{
_true_airspeed_data = true_airspeed;
_indicated_airspeed_data = indicated_airspeed;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,66 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with airspeed data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_AIRSPEED_H
#define EKF_AIRSPEED_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Airspeed: public Sensor
{
public:
Airspeed(std::shared_ptr<Ekf> ekf);
~Airspeed();
void setData(float true_airspeed, float eas2tas);
private:
float _true_airspeed_data{0.0f};
float _indicated_airspeed_data{0.0f};
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_AIRSPEED_H
@@ -0,0 +1,27 @@
#include "baro.h"
namespace sensor_simulator
{
namespace sensor
{
Baro::Baro(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Baro::~Baro()
{
}
void Baro::send(uint64_t time)
{
_ekf->setBaroData(baroSample{time, _baro_data});
}
void Baro::setData(float baro)
{
_baro_data = baro;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,65 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with Mag data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_BARO_H
#define EKF_BARO_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Baro: public Sensor
{
public:
Baro(std::shared_ptr<Ekf> ekf);
~Baro();
void setData(float baro);
private:
float _baro_data{0.0f};
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_BARO_H
@@ -0,0 +1,141 @@
from pyulog import ULog
import pandas as pd
def getVioData(ulog: ULog) -> pd.DataFrame:
vehicle_visual_odometry = ulog.get_dataset("vehicle_visual_odometry").data
vio = pd.DataFrame({'timestamp': vehicle_visual_odometry['timestamp'],
'sensor' : 'vio',
'x': vehicle_visual_odometry["x"],
'y': vehicle_visual_odometry["y"],
'z': vehicle_visual_odometry["z"],
'qw': vehicle_visual_odometry["q[0]"],
'qx': vehicle_visual_odometry["q[1]"],
'qy': vehicle_visual_odometry["q[2]"],
'qz': vehicle_visual_odometry["q[3]"],
'vx': vehicle_visual_odometry["vx"],
'vy': vehicle_visual_odometry["vy"],
'vz': vehicle_visual_odometry["vz"]
})
return vio
def getOpticalFlowData(ulog: ULog) -> pd.DataFrame:
optical_flow = ulog.get_dataset("optical_flow").data
flow = pd.DataFrame({'timestamp': optical_flow['timestamp'],
'sensor' : 'flow',
'pixel_flow_x_integral': optical_flow["pixel_flow_x_integral"],
'pixel_flow_y_integral': optical_flow["pixel_flow_y_integral"],
'gyro_x_rate_integral': optical_flow["gyro_x_rate_integral"],
'gyro_y_rate_integral': optical_flow["gyro_y_rate_integral"],
'gyro_z_rate_integral': optical_flow["gyro_z_rate_integral"],
'quality': optical_flow["quality"]
})
return flow
def getAirspeedData(ulog: ULog) -> pd.DataFrame:
airspeed = ulog.get_dataset("airspeed").data
airspeed = pd.DataFrame({'timestamp': airspeed['timestamp'],
'sensor' : 'airspeed',
'true_as': airspeed["true_airspeed_m_s"],
'indicated_as': airspeed["indicated_airspeed_m_s"]
})
return airspeed
def getRangeFinderData(ulog: ULog) -> pd.DataFrame:
range = pd.DataFrame()
try:
range_0 = ulog.get_dataset("distance_sensor", 0).data
rng_0 = pd.DataFrame({'timestamp': range_0['timestamp'],
'sensor' : 'range',
'data': range_0["current_distance"],
'quality': range_0["signal_quality"]
})
range = pd.concat([range, rng_0], ignore_index=True, sort=False)
except:
pass
try:
range_1 = ulog.get_dataset("distance_sensor", 1).data
rng_1 = pd.DataFrame({'timestamp': range_1['timestamp'],
'sensor' : 'range',
'data': range_1["current_distance"],
'quality': range_1["signal_quality"]
})
range = pd.concat([range, rng_1], ignore_index=True, sort=False)
except:
pass
try:
range_2 = ulog.get_dataset("distance_sensor", 2).data
rng_2 = pd.DataFrame({'timestamp': range_2['timestamp'],
'sensor' : 'range',
'data': range_2["current_distance"],
'quality': range_2["signal_quality"]
})
range = pd.concat([range, rng_2], ignore_index=True, sort=False)
except:
pass
return range
def getGpsData(ulog: ULog) -> pd.DataFrame:
vehicle_gps_position = ulog.get_dataset("vehicle_gps_position").data
gps = pd.DataFrame({'timestamp': vehicle_gps_position['timestamp'],
'sensor' : 'gps',
'alt': vehicle_gps_position["alt"],
'lon': vehicle_gps_position["lon"],
'lat': vehicle_gps_position["lat"],
'vel_N': vehicle_gps_position["vel_n_m_s"],
'vel_E': vehicle_gps_position["vel_e_m_s"],
'vel_D': vehicle_gps_position["vel_d_m_s"],
})
return gps
def getBarometerData(ulog: ULog) -> pd.DataFrame:
vehicle_air_data = ulog.get_dataset("vehicle_air_data").data
baro = pd.DataFrame({'timestamp': vehicle_air_data['timestamp'],
'sensor' : 'baro',
'baro_alt_meter': vehicle_air_data["baro_alt_meter"]})
return baro
def getMagnetometerData(ulog: ULog) -> pd.DataFrame:
vehicle_magnetometer = ulog.get_dataset("vehicle_magnetometer").data
mag = pd.DataFrame({'timestamp': vehicle_magnetometer['timestamp'],
'sensor' : 'mag',
'magnetometer_ga[0]': vehicle_magnetometer["magnetometer_ga[0]"],
'magnetometer_ga[1]': vehicle_magnetometer["magnetometer_ga[1]"],
'magnetometer_ga[2]': vehicle_magnetometer["magnetometer_ga[2]"]})
return mag
def getImuData(ulog: ULog) -> pd.DataFrame:
sensor_combined = ulog.get_dataset("sensor_combined").data
imu = pd.DataFrame({'timestamp': sensor_combined['timestamp'],
'sensor' : 'imu',
'accel_m_s2[0]': sensor_combined["accelerometer_m_s2[0]"],
'accel_m_s2[1]': sensor_combined["accelerometer_m_s2[1]"],
'accel_m_s2[2]': sensor_combined["accelerometer_m_s2[2]"],
'gyro_rad[0]': sensor_combined["gyro_rad[0]"],
'gyro_rad[1]': sensor_combined["gyro_rad[1]"],
'gyro_rad[2]': sensor_combined["gyro_rad[2]"]})
return imu
def getVehicleLandingStatus(ulog: ULog) -> pd.DataFrame:
vehicle_land_detected = ulog.get_dataset("vehicle_land_detected").data
land = pd.DataFrame({'timestamp': vehicle_land_detected['timestamp'],
'sensor' : 'landed',
'landed': vehicle_land_detected["landed"]})
return land
@@ -0,0 +1,124 @@
from pyulog import ULog
import argparse
import pandas as pd
import csv
import convertULogToSensorData as util
path = "/home/kamil/Documents/QGroundControl/Logs/iris_vision.ulg"
output_path = "/home/kamil/Documents/QGroundControl/Logs/sensor_data_iris_vision.csv"
def get_arguments():
"""
parses the command line arguments
:return:
"""
parser = argparse.ArgumentParser(
description='Create a csv file with sensor data values in chronological order from a single'
'ulog file.')
parser.add_argument('input_file', metavar='file.ulg', help='ULog input file path')
parser.add_argument('output_file', metavar='file.ulg', help='csv output file path')
return parser.parse_args()
def main() -> None:
"""
main entry point
:return:
"""
args = get_arguments()
table = pd.DataFrame()
try:
ulog = ULog(args.input_file)
except:
print("Could not find ulog file")
exit(-1)
try:
imu = util.getImuData(ulog)
print("IMU data detected")
table = pd.concat([table, imu], ignore_index=True, sort=False)
except:
print("IMU data not detected")
try:
mag = util.getMagnetometerData(ulog)
print("Mag data detected")
table = pd.concat([table, mag], ignore_index=True, sort=False)
except:
print("Mag data not detected")
try:
baro = util.getBarometerData(ulog)
print("Baro data detected")
table = pd.concat([table, baro], ignore_index=True, sort=False)
except:
print("Baro data not detected")
try:
gps = util.getGpsData(ulog)
print("GPS data detected")
table = pd.concat([table, gps], ignore_index=True, sort=False)
except:
print("GPS data not detected")
try:
airspeed = util.getAirspeedData(ulog)
print("Airspeed data detected")
table = pd.concat([table, airspeed], ignore_index=True, sort=False)
except:
print("Airspeed data not detected")
try:
flow = util.getOpticalFlowData(ulog)
print("Flow data detected")
table = pd.concat([table, flow], ignore_index=True, sort=False)
except:
print("Flow data not detected")
try:
range = util.getRangeFinderData(ulog)
print("Range data detected")
table = pd.concat([table, range], ignore_index=True, sort=False)
except:
print("Range data not detected")
try:
vio = util.getVioData(ulog)
print("VIO data detected")
table = pd.concat([table, vio], ignore_index=True, sort=False)
except:
print("VIO data not detected")
try:
land = util.getVehicleLandingStatus(ulog)
print("Landing data detected")
table = pd.concat([table, land], ignore_index=True, sort=False)
except:
print("Landing data not detected")
table = table.sort_values('timestamp', axis=0, ascending=True)
table['timestamp'] = table['timestamp'] - table['timestamp'].iloc[0]
# remove the first 0.5 seconds of data to be robust against faulty initialized data
table = table[table.timestamp > 500000]
table.timestamp = table.timestamp - 500000
try:
table.to_csv(args.output_file, index=None, header=None)
# post processing remove empty cells from csv
result = []
with open(args.output_file, "r") as in_file:
reader = csv.reader(in_file)
result = [[item for item in row if item != ''] for row in reader]
with open(args.output_file, "w") as out_file:
csv_writer = csv.writer(out_file)
csv_writer.writerows(result)
except:
print("Could not write to specified output file")
if __name__ == '__main__':
main()
@@ -0,0 +1,73 @@
#include "ekf_logger.h"
EkfLogger::EkfLogger(std::shared_ptr<Ekf> ekf):
_ekf{ekf},
_ekf_wrapper(ekf)
{
}
EkfLogger::~EkfLogger() {}
void EkfLogger::setFilePath(std::string file_path)
{
_file_path = file_path;
}
void EkfLogger::writeStateToFile()
{
if (!_file_opened) {
_file.open(_file_path);
_file_opened = true;
_file << "Timestamp";
if (_state_logging_enabled) {
for (int i = 0; i < 24; i++) {
_file << ",state[" << i << "]";
}
}
if (_variance_logging_enabled) {
for (int i = 0; i < 24; i++) {
_file << ",variance[" << i << "]";
}
}
_file << std::endl;
}
if (_file) {
writeState();
} else {
std::cerr << "Can not write to output file" << std::endl;
system_exit(-1);
}
}
void EkfLogger::writeState()
{
if (_state_logging_enabled) {
uint64_t time = _ekf->get_imu_sample_delayed().time_us;
_file << time;
if (_state_logging_enabled) {
matrix::Vector<float, 24> state = _ekf->getStateAtFusionHorizonAsVector();
for (int i = 0; i < 24; i++) {
_file << "," << state(i);
}
}
if (_variance_logging_enabled) {
matrix::Vector<float, 24> variance = _ekf->covariances_diagonal();
for (int i = 0; i < 24; i++) {
_file << "," << variance(i);
}
}
_file << std::endl;
}
}
@@ -0,0 +1,76 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Class to write EKF state to file
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_EKF_LOGGER_H
#define EKF_EKF_LOGGER_H
#include "EKF/ekf.h"
#include "EKF/estimator_interface.h"
#include "ekf_wrapper.h"
#include <fstream>
#include <iostream>
class EkfLogger
{
public:
EkfLogger(std::shared_ptr<Ekf> ekf);
~EkfLogger();
void setFilePath(std::string file_path);
void enableStateLogging() { _state_logging_enabled = true; };
void disableStateLogging() { _state_logging_enabled = false; };
void enableVarianceLogging() { _variance_logging_enabled = true; };
void disableVarianceLogging() { _variance_logging_enabled = false; };
void writeStateToFile();
private:
std::shared_ptr<Ekf> _ekf;
EkfWrapper _ekf_wrapper;
std::string _file_path;
std::ofstream _file;
bool _file_opened {false};
bool _state_logging_enabled {true};
bool _variance_logging_enabled {true};
void writeState();
};
#endif // !EKF_EKF_LOGGER_H
@@ -0,0 +1,239 @@
#include "ekf_wrapper.h"
EkfWrapper::EkfWrapper(std::shared_ptr<Ekf> ekf):
_ekf{ekf}
{
_ekf_params = _ekf->getParamHandle();
}
EkfWrapper::~EkfWrapper()
{
}
void EkfWrapper::setBaroHeight()
{
_ekf_params->vdist_sensor_type = VDIST_SENSOR_BARO;
}
bool EkfWrapper::isIntendingBaroHeightFusion() const
{
return _ekf->control_status_flags().baro_hgt;
}
void EkfWrapper::setGpsHeight()
{
_ekf_params->vdist_sensor_type = VDIST_SENSOR_GPS;
}
bool EkfWrapper::isIntendingGpsHeightFusion() const
{
return _ekf->control_status_flags().gps_hgt;
}
void EkfWrapper::setRangeHeight()
{
_ekf_params->vdist_sensor_type = VDIST_SENSOR_RANGE;
}
bool EkfWrapper::isIntendingRangeHeightFusion() const
{
return _ekf->control_status_flags().rng_hgt;
}
void EkfWrapper::setVisionHeight()
{
_ekf_params->vdist_sensor_type = VDIST_SENSOR_EV;
}
bool EkfWrapper::isIntendingVisionHeightFusion() const
{
return _ekf->control_status_flags().ev_hgt;
}
void EkfWrapper::enableGpsFusion()
{
_ekf_params->fusion_mode |= MASK_USE_GPS;
}
void EkfWrapper::disableGpsFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_GPS;
}
bool EkfWrapper::isIntendingGpsFusion() const
{
return _ekf->control_status_flags().gps;
}
void EkfWrapper::enableGpsHeadingFusion()
{
_ekf_params->fusion_mode |= MASK_USE_GPSYAW;
}
void EkfWrapper::disableGpsHeadingFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_GPSYAW;
}
bool EkfWrapper::isIntendingGpsHeadingFusion() const
{
return _ekf->control_status_flags().gps_yaw;
}
void EkfWrapper::enableFlowFusion()
{
_ekf_params->fusion_mode |= MASK_USE_OF;
}
void EkfWrapper::disableFlowFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_OF;
}
bool EkfWrapper::isIntendingFlowFusion() const
{
return _ekf->control_status_flags().opt_flow;
}
void EkfWrapper::setFlowOffset(const Vector3f &offset)
{
_ekf_params->flow_pos_body = offset;
}
void EkfWrapper::enableExternalVisionPositionFusion()
{
_ekf_params->fusion_mode |= MASK_USE_EVPOS;
}
void EkfWrapper::disableExternalVisionPositionFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_EVPOS;
}
bool EkfWrapper::isIntendingExternalVisionPositionFusion() const
{
return _ekf->control_status_flags().ev_pos;
}
void EkfWrapper::enableExternalVisionVelocityFusion()
{
_ekf_params->fusion_mode |= MASK_USE_EVVEL;
}
void EkfWrapper::disableExternalVisionVelocityFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_EVVEL;
}
bool EkfWrapper::isIntendingExternalVisionVelocityFusion() const
{
return _ekf->control_status_flags().ev_vel;
}
void EkfWrapper::enableExternalVisionHeadingFusion()
{
_ekf_params->fusion_mode |= MASK_USE_EVYAW;
}
void EkfWrapper::disableExternalVisionHeadingFusion()
{
_ekf_params->fusion_mode &= ~MASK_USE_EVYAW;
}
bool EkfWrapper::isIntendingExternalVisionHeadingFusion() const
{
return _ekf->control_status_flags().ev_yaw;
}
void EkfWrapper::enableExternalVisionAlignment()
{
_ekf_params->fusion_mode |= MASK_ROTATE_EV;
}
void EkfWrapper::disableExternalVisionAlignment()
{
_ekf_params->fusion_mode &= ~MASK_ROTATE_EV;
}
bool EkfWrapper::isIntendingMagHeadingFusion() const
{
return _ekf->control_status_flags().mag_hdg;
}
bool EkfWrapper::isIntendingMag3DFusion() const
{
return _ekf->control_status_flags().mag_3D;
}
void EkfWrapper::setMagFuseTypeNone()
{
_ekf_params->mag_fusion_type = MAG_FUSE_TYPE_NONE;
}
bool EkfWrapper::isWindVelocityEstimated() const
{
return _ekf->control_status_flags().wind;
}
void EkfWrapper::enableTerrainRngFusion()
{
_ekf_params->terrain_fusion_mode |= TerrainFusionMask::TerrainFuseRangeFinder;
}
void EkfWrapper::disableTerrainRngFusion()
{
_ekf_params->terrain_fusion_mode &= ~TerrainFusionMask::TerrainFuseRangeFinder;
}
bool EkfWrapper::isIntendingTerrainRngFusion() const
{
terrain_fusion_status_u terrain_status;
terrain_status.value = _ekf->getTerrainEstimateSensorBitfield();
return terrain_status.flags.range_finder;
}
void EkfWrapper::enableTerrainFlowFusion()
{
_ekf_params->terrain_fusion_mode |= TerrainFusionMask::TerrainFuseOpticalFlow;
}
void EkfWrapper::disableTerrainFlowFusion()
{
_ekf_params->terrain_fusion_mode &= ~TerrainFusionMask::TerrainFuseOpticalFlow;
}
bool EkfWrapper::isIntendingTerrainFlowFusion() const
{
terrain_fusion_status_u terrain_status;
terrain_status.value = _ekf->getTerrainEstimateSensorBitfield();
return terrain_status.flags.flow;
}
Eulerf EkfWrapper::getEulerAngles() const
{
return Eulerf(_ekf->getQuaternion());
}
float EkfWrapper::getYawAngle() const
{
const Eulerf euler(_ekf->getQuaternion());
return euler(2);
}
matrix::Vector<float, 4> EkfWrapper::getQuaternionVariance() const
{
return matrix::Vector<float, 4>(_ekf->orientation_covariances().diag());
}
int EkfWrapper::getQuaternionResetCounter() const
{
float tmp[4];
uint8_t counter;
_ekf->get_quat_reset(tmp, &counter);
return static_cast<int>(counter);
}
matrix::Vector3f EkfWrapper::getDeltaVelBiasVariance() const
{
return _ekf->covariances_diagonal().slice<3, 1>(13, 0);
}
@@ -0,0 +1,120 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Wrapper class for Ekf object to set behavior or check status
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_EKF_WRAPPER_H
#define EKF_EKF_WRAPPER_H
#include <memory>
#include "EKF/ekf.h"
#include "EKF/estimator_interface.h"
class EkfWrapper
{
public:
EkfWrapper(std::shared_ptr<Ekf> ekf);
~EkfWrapper();
void setBaroHeight();
bool isIntendingBaroHeightFusion() const;
void setGpsHeight();
bool isIntendingGpsHeightFusion() const;
void setRangeHeight();
bool isIntendingRangeHeightFusion() const;
void setVisionHeight();
bool isIntendingVisionHeightFusion() const;
void enableGpsFusion();
void disableGpsFusion();
bool isIntendingGpsFusion() const;
void enableGpsHeadingFusion();
void disableGpsHeadingFusion();
bool isIntendingGpsHeadingFusion() const;
void enableFlowFusion();
void disableFlowFusion();
bool isIntendingFlowFusion() const;
void setFlowOffset(const matrix::Vector3f &offset);
void enableExternalVisionPositionFusion();
void disableExternalVisionPositionFusion();
bool isIntendingExternalVisionPositionFusion() const;
void enableExternalVisionVelocityFusion();
void disableExternalVisionVelocityFusion();
bool isIntendingExternalVisionVelocityFusion() const;
void enableExternalVisionHeadingFusion();
void disableExternalVisionHeadingFusion();
bool isIntendingExternalVisionHeadingFusion() const;
bool isIntendingMagHeadingFusion() const;
bool isIntendingMag3DFusion() const;
void setMagFuseTypeNone();
void enableExternalVisionAlignment();
void disableExternalVisionAlignment();
bool isWindVelocityEstimated() const;
void enableTerrainRngFusion();
void disableTerrainRngFusion();
bool isIntendingTerrainRngFusion() const;
void enableTerrainFlowFusion();
void disableTerrainFlowFusion();
bool isIntendingTerrainFlowFusion() const;
Eulerf getEulerAngles() const;
float getYawAngle() const;
matrix::Vector<float, 4> getQuaternionVariance() const;
int getQuaternionResetCounter() const;
matrix::Vector3f getDeltaVelBiasVariance() const;
private:
std::shared_ptr<Ekf> _ekf;
// Pointer to Ekf internal param struct
parameters *_ekf_params;
};
#endif // !EKF_EKF_WRAPPER_H
@@ -0,0 +1,39 @@
#include "flow.h"
namespace sensor_simulator
{
namespace sensor
{
Flow::Flow(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Flow::~Flow()
{
}
void Flow::send(uint64_t time)
{
_flow_data.time_us = time;
_ekf->setOpticalFlowData(_flow_data);
}
void Flow::setData(const flowSample &flow)
{
_flow_data = flow;
}
flowSample Flow::dataAtRest()
{
flowSample flow_at_rest;
flow_at_rest.dt = static_cast<float>(_update_period) * 1e-6f;
flow_at_rest.flow_xy_rad = Vector2f{0.0f, 0.0f};
flow_at_rest.gyro_xyz = Vector3f{0.0f, 0.0f, 0.0f};
flow_at_rest.quality = 255;
return flow_at_rest;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,66 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with optical flow data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_FLOW_H
#define EKF_FLOW_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Flow: public Sensor
{
public:
Flow(std::shared_ptr<Ekf> ekf);
~Flow();
void setData(const flowSample &flow);
flowSample dataAtRest();
private:
flowSample _flow_data;
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_FLOW_H
@@ -0,0 +1,134 @@
#include "gps.h"
namespace sensor_simulator
{
namespace sensor
{
Gps::Gps(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Gps::~Gps()
{
}
void Gps::send(const uint64_t time)
{
const float dt = static_cast<float>(time - _gps_data.time_usec) * 1e-6f;
_gps_data.time_usec = time;
if (fabsf(_gps_pos_rate(0)) > FLT_EPSILON || fabsf(_gps_pos_rate(1)) > FLT_EPSILON) {
stepHorizontalPositionByMeters(Vector2f(_gps_pos_rate) * dt);
}
if (fabsf(_gps_pos_rate(2)) > FLT_EPSILON) {
stepHeightByMeters(-_gps_pos_rate(2) * dt);
}
_ekf->setGpsData(_gps_data);
}
void Gps::setData(const gps_message &gps)
{
_gps_data = gps;
}
void Gps::setAltitude(const int32_t alt)
{
_gps_data.alt = alt;
}
void Gps::setLatitude(const int32_t lat)
{
_gps_data.lat = lat;
}
void Gps::setLongitude(const int32_t lon)
{
_gps_data.lon = lon;
}
void Gps::setVelocity(const Vector3f &vel)
{
_gps_data.vel_ned = vel;
}
void Gps::setYaw(const float yaw)
{
_gps_data.yaw = yaw;
}
void Gps::setYawOffset(const float yaw_offset)
{
_gps_data.yaw_offset = yaw_offset;
}
void Gps::setFixType(const int fix_type)
{
_gps_data.fix_type = fix_type;
}
void Gps::setNumberOfSatellites(const int num_satellites)
{
_gps_data.nsats = num_satellites;
}
void Gps::setPdop(const float pdop)
{
_gps_data.pdop = pdop;
}
void Gps::setPositionRateNED(const Vector3f &rate)
{
_gps_pos_rate = rate;
}
void Gps::stepHeightByMeters(const float hgt_change)
{
_gps_data.alt += hgt_change * 1e3f;
}
void Gps::stepHorizontalPositionByMeters(const Vector2f hpos_change)
{
float hposN_curr {0.f};
float hposE_curr {0.f};
double lat_new {0.0};
double lon_new {0.0};
map_projection_project(&_ekf->global_origin(), _gps_data.lat * 1e-7, _gps_data.lon * 1e-7, &hposN_curr, &hposE_curr);
Vector2f hpos_new = Vector2f{hposN_curr, hposE_curr} + hpos_change;
map_projection_reproject(&_ekf->global_origin(), hpos_new(0), hpos_new(1), &lat_new, &lon_new);
_gps_data.lon = static_cast<int32_t>(lon_new * 1e7);
_gps_data.lat = static_cast<int32_t>(lat_new * 1e7);
}
gps_message Gps::getDefaultGpsData()
{
gps_message gps_data{};
gps_data.time_usec = 0;
gps_data.lat = 473566094;
gps_data.lon = 85190237;
gps_data.alt = 422056;
gps_data.yaw = NAN;
gps_data.yaw_offset = 0.0f;
gps_data.fix_type = 3;
gps_data.eph = 0.5f;
gps_data.epv = 0.8f;
gps_data.sacc = 0.2f;
gps_data.vel_m_s = 0.0;
gps_data.vel_ned.setZero();
gps_data.vel_ned_valid = 1;
gps_data.nsats = 16;
gps_data.pdop = 0.0f;
return gps_data;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,79 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with Gps data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_GPS_H
#define EKF_GPS_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Gps: public Sensor
{
public:
Gps(std::shared_ptr<Ekf> ekf);
~Gps();
void setData(const gps_message &gps);
void stepHeightByMeters(const float hgt_change);
void stepHorizontalPositionByMeters(const Vector2f hpos_change);
void setPositionRateNED(const Vector3f &rate);
void setAltitude(const int32_t alt);
void setLatitude(const int32_t lat);
void setLongitude(const int32_t lon);
void setVelocity(const Vector3f &vel);
void setYaw(const float yaw);
void setYawOffset(const float yaw);
void setFixType(const int fix_type);
void setNumberOfSatellites(const int num_satellites);
void setPdop(const float pdop);
gps_message getDefaultGpsData();
private:
void send(uint64_t time) override;
gps_message _gps_data{};
Vector3f _gps_pos_rate{};
};
} // namespace sensor
} // namespace sensor_simulator
#endif // EKF_GPS_H
@@ -0,0 +1,46 @@
#include "imu.h"
namespace sensor_simulator
{
namespace sensor
{
Imu::Imu(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Imu::~Imu()
{
}
void Imu::send(uint64_t time)
{
const float dt = float((time - _time_last_data_sent) * 1.e-6f);
imuSample imu_sample{};
imu_sample.time_us = time;
imu_sample.delta_ang_dt = dt;
imu_sample.delta_ang = _gyro_data * imu_sample.delta_ang_dt;
imu_sample.delta_vel_dt = dt;
imu_sample.delta_vel = _accel_data * imu_sample.delta_vel_dt;
_ekf->setIMUData(imu_sample);
}
void Imu::setData(const Vector3f &accel, const Vector3f &gyro)
{
setAccelData(accel);
setGyroData(gyro);
}
void Imu::setAccelData(const Vector3f &accel)
{
_accel_data = accel;
}
void Imu::setGyroData(const Vector3f &gyro)
{
_gyro_data = gyro;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,68 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with Imu data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_IMU_H
#define EKF_IMU_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Imu: public Sensor
{
public:
Imu(std::shared_ptr<Ekf> ekf);
~Imu();
void setData(const Vector3f &accel, const Vector3f &gyro);
void setAccelData(const Vector3f &accel);
void setGyroData(const Vector3f &gyro);
private:
Vector3f _accel_data;
Vector3f _gyro_data;
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // EKF_IMU_H
@@ -0,0 +1,27 @@
#include "mag.h"
namespace sensor_simulator
{
namespace sensor
{
Mag::Mag(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Mag::~Mag()
{
}
void Mag::send(uint64_t time)
{
_ekf->setMagData(magSample{time, _mag_data});
}
void Mag::setData(const Vector3f &mag)
{
_mag_data = mag;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,65 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with Mag data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_MAG_H
#define EKF_MAG_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Mag: public Sensor
{
public:
Mag(std::shared_ptr<Ekf> ekf);
~Mag();
void setData(const Vector3f &mag);
private:
Vector3f _mag_data;
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_MAG_H
@@ -0,0 +1,36 @@
#include "range_finder.h"
namespace sensor_simulator
{
namespace sensor
{
RangeFinder::RangeFinder(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
RangeFinder::~RangeFinder()
{
}
void RangeFinder::send(uint64_t time)
{
_range_sample.time_us = time;
_ekf->setRangeData(_range_sample);
_ekf->set_rangefinder_limits(_min_distance, _max_distance);
}
void RangeFinder::setData(float range_data_meters, int8_t range_quality)
{
_range_sample.rng = range_data_meters;
_range_sample.quality = range_quality;
}
void RangeFinder::setLimits(float min_distance_m, float max_distance_m)
{
_min_distance = min_distance_m;
_max_distance = max_distance_m;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,67 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf with range finder data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_RANGE_FINDER_H
#define EKF_RANGE_FINDER_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class RangeFinder: public Sensor
{
public:
RangeFinder(std::shared_ptr<Ekf> ekf);
~RangeFinder();
void setData(float range_data, int8_t range_quality);
void setLimits(float min_distance_m, float max_distance_m);
private:
rangeSample _range_sample {};
float _min_distance {0.2f};
float _max_distance {20.0f};
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_RANGE_FINDER_H
@@ -0,0 +1,32 @@
#include "sensor.h"
namespace sensor_simulator
{
Sensor::Sensor(std::shared_ptr<Ekf> ekf): _ekf{ekf}
{
}
Sensor::~Sensor()
{
}
void Sensor::update(uint64_t time)
{
if (should_send(time)) {
send(time);
_time_last_data_sent = time;
}
}
bool Sensor::should_send(uint64_t time) const
{
return _is_running && is_time_to_send(time);
}
bool Sensor::is_time_to_send(uint64_t time) const
{
return (time >= _time_last_data_sent) && ((time - _time_last_data_sent) >= _update_period);
}
} // namespace sensor_simulator
@@ -0,0 +1,86 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Base class for defining the interface for simulaton of a sensor
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_SENSOR_H
#define EKF_SENSOR_H
#include "EKF/ekf.h"
#include <math.h>
#include <memory>
namespace sensor_simulator
{
class Sensor
{
public:
Sensor(std::shared_ptr<Ekf> ekf);
virtual ~Sensor();
void update(uint64_t time);
void setRateHz(uint32_t rate) { _update_period = uint32_t(1000000) / rate; }
bool isRunning() const { return _is_running; }
void start() { _is_running = true; }
void stop() { _is_running = false; }
bool should_send(uint64_t time) const;
protected:
std::shared_ptr<Ekf> _ekf;
// time in microseconds
uint32_t _update_period;
uint64_t _time_last_data_sent{0};
bool _is_running{false};
// Checks that the right amount time passed since last send data to fulfill rate
bool is_time_to_send(uint64_t time) const;
// call set*Data function of Ekf
virtual void send(uint64_t time) = 0;
};
} // namespace sensor_simulator
#endif // !EKF_SENSOR_H
@@ -0,0 +1,327 @@
#include "sensor_simulator.h"
SensorSimulator::SensorSimulator(std::shared_ptr<Ekf> ekf):
_airspeed(ekf),
_baro(ekf),
_flow(ekf),
_gps(ekf),
_imu(ekf),
_mag(ekf),
_rng(ekf),
_vio(ekf),
_ekf{ekf}
{
setSensorRateToDefault();
setSensorDataToDefault();
startBasicSensor();
}
SensorSimulator::~SensorSimulator()
{
}
void SensorSimulator::loadSensorDataFromFile(std::string file_name)
{
std::ifstream file(file_name);
std::string line;
while (!file.eof()) {
std::string timestamp;
std::string sensor_type;
std::string sensor_data;
sensor_info sensor_sample;
getline(file, timestamp, ',');
if (!timestamp.compare("")) { // empty line at end of file
break;
}
sensor_sample.timestamp = std::stoul(timestamp);
if (_replay_data.size() > 0) {
sensor_info last_sample = _replay_data.back();
if (sensor_sample.timestamp < last_sample.timestamp) {
std::cout << "Timestamps not sorted ascendingly" << std::endl;
system_exit(-1);
}
}
getline(file, sensor_type, ',');
if (!sensor_type.compare("imu")) {
sensor_sample.sensor_type = sensor_info::IMU;
} else if (!sensor_type.compare("mag")) {
sensor_sample.sensor_type = sensor_info::MAG;
} else if (!sensor_type.compare("baro")) {
sensor_sample.sensor_type = sensor_info::BARO;
} else if (!sensor_type.compare("gps")) {
sensor_sample.sensor_type = sensor_info::GPS;
} else if (!sensor_type.compare("airspeed")) {
sensor_sample.sensor_type = sensor_info::AIRSPEED;
} else if (!sensor_type.compare("range")) {
sensor_sample.sensor_type = sensor_info::RANGE;
} else if (!sensor_type.compare("flow")) {
sensor_sample.sensor_type = sensor_info::FLOW;
} else if (!sensor_type.compare("vio")) {
sensor_sample.sensor_type = sensor_info::VISION;
} else if (!sensor_type.compare("landed")) {
sensor_sample.sensor_type = sensor_info::LANDING_STATUS;
} else {
std::cout << "Sensor type in file unknown" << std::endl;
system_exit(-1);
}
getline(file, sensor_data);
std::stringstream ss(sensor_data);
int8_t i = 0;
while (ss.good()) {
if (i >= 10) {
std::cout << "sensor data bigger than expected" << std::endl;
system_exit(-1);
}
std::string value_string;
getline(ss, value_string, ',');
if (!value_string.compare("")) {
continue;
}
sensor_sample.sensor_data[i] = std::stod(value_string);
i++;
}
_replay_data.emplace_back(sensor_sample);
}
file.close();
_has_replay_data = true;
}
void SensorSimulator::setSensorRateToDefault()
{
_imu.setRateHz(200);
_mag.setRateHz(80);
_baro.setRateHz(80);
_gps.setRateHz(5);
_flow.setRateHz(50);
_rng.setRateHz(30);
_vio.setRateHz(30);
_airspeed.setRateHz(100);
}
void SensorSimulator::setSensorDataToDefault()
{
_airspeed.setData(0.0f, 0.0f);
_baro.setData(122.2f);
_flow.setData(_flow.dataAtRest());
_gps.setData(_gps.getDefaultGpsData());
_imu.setData(Vector3f{0.0f, 0.0f, -CONSTANTS_ONE_G}, Vector3f{0.0f, 0.0f, 0.0f});
_mag.setData(Vector3f{0.2f, 0.0f, 0.4f});
_rng.setData(0.2f, 100);
_vio.setData(_vio.dataAtRest());
}
void SensorSimulator::startBasicSensor()
{
_baro.start();
_imu.start();
_mag.start();
}
void SensorSimulator::runSeconds(float duration_seconds)
{
runMicroseconds(uint32_t(duration_seconds * 1e6f));
}
void SensorSimulator::runMicroseconds(uint32_t duration)
{
// simulate in 1000us steps
const uint64_t start_time = _time;
for (; _time < start_time + (uint64_t)duration; _time += 1000) {
bool update_imu = _imu.should_send(_time);
updateSensors();
if (update_imu) {
// Update at IMU rate
_ekf->update();
}
}
}
void SensorSimulator::updateSensors()
{
_imu.update(_time);
_mag.update(_time);
_baro.update(_time);
_gps.update(_time);
_flow.update(_time);
_rng.update(_time);
_vio.update(_time);
_airspeed.update(_time);
}
void SensorSimulator::runReplaySeconds(float duration_seconds)
{
runReplayMicroseconds(uint32_t(duration_seconds * 1e6f));
}
void SensorSimulator::runReplayMicroseconds(uint32_t duration)
{
if (!_has_replay_data) {
std::cout << "Can not run replay without replay data" << std::endl;
system_exit(-1);
}
// simulate in 1000us steps
const uint64_t start_time = _time;
for (; _time < start_time + duration; _time += 1000) {
setSensorDataFromReplayData();
bool update_imu = _imu.should_send(_time);
updateSensors();
if (update_imu) {
_ekf->update();
}
}
}
void SensorSimulator::setSensorDataFromReplayData()
{
if (_replay_data.size() > 0) {
sensor_info sample = _replay_data[_current_replay_data_index];
while (sample.timestamp < _time) {
setSingleReplaySample(sample);
if (_current_replay_data_index < _replay_data.size()) {
_current_replay_data_index ++;
} else {
break;
}
sample = _replay_data[_current_replay_data_index];
}
} else {
std::cerr << "Loaded replay data empty. Likely could not load replay data" << std::endl;
system_exit(-1);
}
}
void SensorSimulator::setSingleReplaySample(const sensor_info &sample)
{
if (sample.sensor_type == sensor_info::IMU) {
Vector3f accel{(float) sample.sensor_data[0],
(float) sample.sensor_data[1],
(float) sample.sensor_data[2]};
Vector3f gyro{(float) sample.sensor_data[3],
(float) sample.sensor_data[4],
(float) sample.sensor_data[5]};
_imu.setData(accel, gyro);
} else if (sample.sensor_type == sensor_info::MAG) {
Vector3f mag{(float) sample.sensor_data[0],
(float) sample.sensor_data[1],
(float) sample.sensor_data[2]};
_mag.setData(mag);
} else if (sample.sensor_type == sensor_info::BARO) {
_baro.setData((float) sample.sensor_data[0]);
} else if (sample.sensor_type == sensor_info::GPS) {
_gps.setAltitude((int32_t) sample.sensor_data[0]);
_gps.setLatitude((int32_t) sample.sensor_data[1]);
_gps.setLongitude((int32_t) sample.sensor_data[2]);
_gps.setVelocity(Vector3f((float) sample.sensor_data[3],
(float) sample.sensor_data[4],
(float) sample.sensor_data[5]));
} else if (sample.sensor_type == sensor_info::AIRSPEED) {
_airspeed.setData((float) sample.sensor_data[0], (float) sample.sensor_data[1]);
} else if (sample.sensor_type == sensor_info::RANGE) {
_rng.setData((float) sample.sensor_data[0], (float) sample.sensor_data[1]);
} else if (sample.sensor_type == sensor_info::FLOW) {
flowSample flow_sample;
flow_sample.flow_xy_rad = Vector2f(sample.sensor_data[0],
sample.sensor_data[1]);
flow_sample.gyro_xyz = Vector3f(sample.sensor_data[2],
sample.sensor_data[3],
sample.sensor_data[4]);
flow_sample.quality = sample.sensor_data[5];
_flow.setData(flow_sample);
} else if (sample.sensor_type == sensor_info::VISION) {
// sensor not yet implemented
// extVisionSample vision_sample;
// vision_sample.pos;
// vision_sample.quat;
// vision_sample.vel;
// _vio.setData((float) sample.sensor_data[0], (float) sample.sensor_data[1]);
} else if (sample.sensor_type == sensor_info::LANDING_STATUS) {
bool landed = fabsf(sample.sensor_data[0]) <= 0.f;
_ekf->set_in_air_status(!landed);
} else {
printf("Unknown sensor type, can not set replay sample");
system_exit(-1);
}
}
void SensorSimulator::setGpsLatitude(const double latitude)
{
int32_t lat = static_cast<int32_t>(latitude * 1e7);
_gps.setLatitude(lat);
}
void SensorSimulator::setGpsLongitude(const double longitude)
{
int32_t lon = static_cast<int32_t>(longitude * 1e7);
_gps.setLongitude(lon);
}
void SensorSimulator::setGpsAltitude(const float altitude)
{
int32_t alt = static_cast<int32_t>(altitude * 1e3f);
_gps.setAltitude(alt);
}
void SensorSimulator::setImuBias(Vector3f accel_bias, Vector3f gyro_bias)
{
_imu.setData(Vector3f{0.0f, 0.0f, -CONSTANTS_ONE_G} + accel_bias,
Vector3f{0.0f, 0.0f, 0.0f} + gyro_bias);
}
void SensorSimulator::simulateOrientation(Quatf orientation)
{
const Vector3f world_sensed_gravity = {0.0f, 0.0f, -CONSTANTS_ONE_G};
const Vector3f world_mag_field = Vector3f{0.2f, 0.0f, 0.4f};
const Dcmf R_bodyToWorld(orientation);
const Vector3f sensed_gravity_body = R_bodyToWorld.transpose() * world_sensed_gravity;
const Vector3f body_mag_field = R_bodyToWorld.transpose() * world_mag_field;
_imu.setData(sensed_gravity_body, Vector3f{0.0f, 0.0f, 0.0f});
_mag.setData(body_mag_field);
}
@@ -0,0 +1,143 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* This class is providing methods to feed the ECL EKF with measurement.
* It takes a pointer to the Ekf object and will manipulate the object
* by call set*Data functions.
* It simulates the time to allow for sensor data being set at certain rate
* and also calls the update method of the EKF
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_SENSOR_SIMULATOR_H
#define EKF_SENSOR_SIMULATOR_H
#include <memory>
#include <fstream>
#include <iostream>
#include <sstream>
#include <vector>
#include <array>
#include "imu.h"
#include "mag.h"
#include "baro.h"
#include "gps.h"
#include "flow.h"
#include "range_finder.h"
#include "vio.h"
#include "airspeed.h"
#include "EKF/ekf.h"
using namespace sensor_simulator::sensor;
struct sensor_info {
uint64_t timestamp {};
enum measurement_t {IMU, MAG, BARO, GPS, AIRSPEED, RANGE, FLOW, VISION, LANDING_STATUS} sensor_type = IMU;
std::array<double, 10> sensor_data {};
};
class SensorSimulator
{
public:
SensorSimulator(std::shared_ptr<Ekf> ekf);
~SensorSimulator();
uint64_t getTime() const { return _time; };
void runSeconds(float duration_seconds);
void runMicroseconds(uint32_t duration);
void runReplaySeconds(float duration_seconds);
void runReplayMicroseconds(uint32_t duration);
void startBaro() { _baro.start(); }
void stopBaro() { _baro.stop(); }
void startGps() { _gps.start(); }
void stopGps() { _gps.stop(); }
void startFlow() { _flow.start(); }
void stopFlow() { _flow.stop(); }
void startRangeFinder() { _rng.start(); }
void stopRangeFinder() { _rng.stop(); }
void startExternalVision() { _vio.start(); }
void stopExternalVision() { _vio.stop(); }
void startAirspeedSensor() { _airspeed.start(); }
void stopAirspeedSensor() { _airspeed.stop(); }
void setGpsLatitude(const double latitude);
void setGpsLongitude(const double longitude);
void setGpsAltitude(const float altitude);
void setImuBias(Vector3f accel_bias, Vector3f gyro_bias);
void simulateOrientation(Quatf orientation);
void loadSensorDataFromFile(std::string filename);
Airspeed _airspeed;
Baro _baro;
Flow _flow;
Gps _gps;
Imu _imu;
Mag _mag;
RangeFinder _rng;
Vio _vio;
protected:
private:
void setSensorDataToDefault();
void setSensorDataFromReplayData();
void setSensorRateToDefault();
void setSingleReplaySample(const sensor_info &sample);
void startBasicSensor();
void updateSensors();
std::shared_ptr<Ekf> _ekf {nullptr};
std::vector<sensor_info> _replay_data {};
bool _has_replay_data {false};
uint64_t _current_replay_data_index {0};
uint64_t _time {0}; // microseconds
};
#endif // !EKF_SENSOR_SIMULATOR_H
@@ -0,0 +1,86 @@
#include "vio.h"
namespace sensor_simulator
{
namespace sensor
{
Vio::Vio(std::shared_ptr<Ekf> ekf): Sensor(ekf)
{
}
Vio::~Vio()
{
}
void Vio::send(uint64_t time)
{
_vio_data.time_us = time;
_ekf->setExtVisionData(_vio_data);
}
void Vio::setData(const extVisionSample &vio_data)
{
_vio_data = vio_data;
}
void Vio::setVelocityVariance(const Vector3f &velVar)
{
setVelocityCovariance(matrix::diag(velVar));
}
void Vio::setVelocityCovariance(const Matrix3f &velCov)
{
_vio_data.velCov = velCov;
}
void Vio::setPositionVariance(const Vector3f &posVar)
{
_vio_data.posVar = posVar;
}
void Vio::setAngularVariance(float angVar)
{
_vio_data.angVar = angVar;
}
void Vio::setVelocity(const Vector3f &vel)
{
_vio_data.vel = vel;
}
void Vio::setPosition(const Vector3f &pos)
{
_vio_data.pos = pos;
}
void Vio::setOrientation(const Quatf &quat)
{
_vio_data.quat = quat;
}
void Vio::setVelocityFrameToBody()
{
_vio_data.vel_frame = velocity_frame_t::BODY_FRAME_FRD;
}
void Vio::setVelocityFrameToLocal()
{
_vio_data.vel_frame = velocity_frame_t::LOCAL_FRAME_FRD;
}
extVisionSample Vio::dataAtRest()
{
extVisionSample vio_data;
vio_data.pos = Vector3f{0.0f, 0.0f, 0.0f};;
vio_data.vel = Vector3f{0.0f, 0.0f, 0.0f};;
vio_data.quat = Quatf{1.0f, 0.0f, 0.0f, 0.0f};
vio_data.posVar = Vector3f{0.1f, 0.1f, 0.1f};
vio_data.velCov = matrix::eye<float, 3>() * 0.1f;
vio_data.angVar = 0.05f;
vio_data.vel_frame = velocity_frame_t::LOCAL_FRAME_FRD;
return vio_data;
}
} // namespace sensor
} // namespace sensor_simulator
@@ -0,0 +1,76 @@
/****************************************************************************
*
* Copyright (c) 2019 ECL Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/**
* Feeds Ekf external vision data
* @author Kamil Ritz <ka.ritz@hotmail.com>
*/
#ifndef EKF_VIO_H
#define EKF_VIO_H
#include "sensor.h"
namespace sensor_simulator
{
namespace sensor
{
class Vio: public Sensor
{
public:
Vio(std::shared_ptr<Ekf> ekf);
~Vio();
void setData(const extVisionSample &vio_data);
void setVelocityVariance(const Vector3f &velVar);
void setVelocityCovariance(const Matrix3f &velCov);
void setPositionVariance(const Vector3f &posVar);
void setAngularVariance(float angVar);
void setVelocity(const Vector3f &vel);
void setPosition(const Vector3f &pos);
void setOrientation(const Quatf &quat);
void setVelocityFrameToLocal();
void setVelocityFrameToBody();
extVisionSample dataAtRest();
private:
extVisionSample _vio_data;
void send(uint64_t time) override;
};
} // namespace sensor
} // namespace sensor_simulator
#endif // !EKF_VIO_H