mirror of https://github.com/ArduPilot/ardupilot
168 lines
5.4 KiB
C++
168 lines
5.4 KiB
C++
/*
|
|
SITL handling
|
|
|
|
This emulates the ADS7844 ADC
|
|
|
|
Andrew Tridgell November 2011
|
|
*/
|
|
|
|
#include <AP_HAL/AP_HAL.h>
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
|
|
|
#include "AP_HAL_SITL.h"
|
|
#include "AP_HAL_SITL_Namespace.h"
|
|
#include "HAL_SITL_Class.h"
|
|
|
|
#include <AP_Math/AP_Math.h>
|
|
#include <AP_Compass/AP_Compass.h>
|
|
#include <AP_Declination/AP_Declination.h>
|
|
#include <AP_RangeFinder/AP_RangeFinder.h>
|
|
#include <SITL/SITL.h>
|
|
#include "Scheduler.h"
|
|
#include <AP_Math/AP_Math.h>
|
|
#include <AP_ADC/AP_ADC.h>
|
|
#include "SITL_State.h"
|
|
#include <fenv.h>
|
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
using namespace HALSITL;
|
|
|
|
/*
|
|
convert airspeed in m/s to an airspeed sensor value
|
|
*/
|
|
uint16_t SITL_State::_airspeed_sensor(float airspeed)
|
|
{
|
|
const float airspeed_ratio = 1.9936f;
|
|
const float airspeed_offset = 2013;
|
|
float airspeed_pressure, airspeed_raw;
|
|
|
|
airspeed_pressure = (airspeed*airspeed) / airspeed_ratio;
|
|
airspeed_raw = airspeed_pressure + airspeed_offset;
|
|
if (airspeed_raw/4 > 0xFFFF) {
|
|
return 0xFFFF;
|
|
}
|
|
// add delay
|
|
uint32_t now = AP_HAL::millis();
|
|
uint32_t best_time_delta_wind = 200; // initialise large time representing buffer entry closest to current time - delay.
|
|
uint8_t best_index_wind = 0; // initialise number representing the index of the entry in buffer closest to delay.
|
|
|
|
// storing data from sensor to buffer
|
|
if (now - last_store_time_wind >= 10) { // store data every 10 ms.
|
|
last_store_time_wind = now;
|
|
if (store_index_wind > wind_buffer_length-1) { // reset buffer index if index greater than size of buffer
|
|
store_index_wind = 0;
|
|
}
|
|
buffer_wind[store_index_wind].data = airspeed_raw; // add data to current index
|
|
buffer_wind[store_index_wind].time = last_store_time_wind; // add time to current index
|
|
store_index_wind = store_index_wind + 1; // increment index
|
|
}
|
|
|
|
// return delayed measurement
|
|
delayed_time_wind = now - _sitl->wind_delay; // get time corresponding to delay
|
|
// find data corresponding to delayed time in buffer
|
|
for (uint8_t i=0; i<=wind_buffer_length-1; i++) {
|
|
// find difference between delayed time and time stamp in buffer
|
|
time_delta_wind = abs(
|
|
(int32_t)(delayed_time_wind - buffer_wind[i].time));
|
|
// if this difference is smaller than last delta, store this time
|
|
if (time_delta_wind < best_time_delta_wind) {
|
|
best_index_wind = i;
|
|
best_time_delta_wind = time_delta_wind;
|
|
}
|
|
}
|
|
if (best_time_delta_wind < 200) { // only output stored state if < 200 msec retrieval error
|
|
airspeed_raw = buffer_wind[best_index_wind].data;
|
|
}
|
|
|
|
return airspeed_raw/4;
|
|
}
|
|
|
|
|
|
/*
|
|
emulate an analog rangefinder
|
|
*/
|
|
uint16_t SITL_State::_ground_sonar(void)
|
|
{
|
|
float altitude = height_agl();
|
|
|
|
// sensor position offset in body frame
|
|
Vector3f relPosSensorBF = _sitl->rngfnd_pos_offset;
|
|
|
|
// adjust altitude for position of the sensor on the vehicle if position offset is non-zero
|
|
if (!relPosSensorBF.is_zero()) {
|
|
// get a rotation matrix following DCM conventions (body to earth)
|
|
Matrix3f rotmat;
|
|
rotmat.from_euler(radians(_sitl->state.rollDeg),
|
|
radians(_sitl->state.pitchDeg),
|
|
radians(_sitl->state.yawDeg));
|
|
// rotate the offset into earth frame
|
|
Vector3f relPosSensorEF = rotmat * relPosSensorBF;
|
|
// correct the altitude at the sensor
|
|
altitude -= relPosSensorEF.z;
|
|
}
|
|
|
|
float voltage = 5.0f;
|
|
if (fabsf(_sitl->state.rollDeg) < 90 &&
|
|
fabsf(_sitl->state.pitchDeg) < 90) {
|
|
// adjust for apparent altitude with roll
|
|
altitude /= cosf(radians(_sitl->state.rollDeg)) * cosf(radians(_sitl->state.pitchDeg));
|
|
|
|
altitude += _sitl->sonar_noise * _rand_float();
|
|
|
|
// Altitude in in m, scaler in meters/volt
|
|
voltage = altitude / _sitl->sonar_scale;
|
|
voltage = constrain_float(voltage, 0, 5.0f);
|
|
|
|
if (_sitl->sonar_glitch >= (_rand_float() + 1.0f)/2.0f) {
|
|
voltage = 5.0f;
|
|
}
|
|
}
|
|
|
|
return 1023*(voltage / 5.0f);
|
|
}
|
|
|
|
/*
|
|
setup the INS input channels with new input
|
|
|
|
Note that this uses roll, pitch and yaw only as inputs. The
|
|
simulator rollrates are instantaneous, whereas we need to use
|
|
average rates to cope with slow update rates.
|
|
|
|
inputs are in degrees
|
|
|
|
phi - roll
|
|
theta - pitch
|
|
psi - true heading
|
|
alpha - angle of attack
|
|
beta - side slip
|
|
phidot - roll rate
|
|
thetadot - pitch rate
|
|
psidot - yaw rate
|
|
v_north - north velocity in local/body frame
|
|
v_east - east velocity in local/body frame
|
|
v_down - down velocity in local/body frame
|
|
A_X_pilot - X accel in body frame
|
|
A_Y_pilot - Y accel in body frame
|
|
A_Z_pilot - Z accel in body frame
|
|
|
|
Note: doubles on high prec. stuff are preserved until the last moment
|
|
|
|
*/
|
|
void SITL_State::_update_ins(float roll, float pitch, float yaw, // Relative to earth
|
|
double rollRate, double pitchRate,double yawRate, // Local to plane
|
|
double xAccel, double yAccel, double zAccel, // Local to plane
|
|
float airspeed, float altitude)
|
|
{
|
|
if (_ins == nullptr) {
|
|
// no inertial sensor in this sketch
|
|
return;
|
|
}
|
|
|
|
sonar_pin_value = _ground_sonar();
|
|
float airspeed_simulated = (fabsf(_sitl->arspd_fail) > 1.0e-6f) ? _sitl->arspd_fail : airspeed;
|
|
airspeed_pin_value = _airspeed_sensor(airspeed_simulated + (_sitl->arspd_noise * _rand_float()));
|
|
}
|
|
|
|
#endif
|