2015-08-11 03:28:43 -03:00
|
|
|
#include <AP_HAL/AP_HAL.h>
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-04 03:15:12 -03:00
|
|
|
#if CONFIG_HAL_BOARD == HAL_BOARD_SITL
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-08-11 03:28:43 -03:00
|
|
|
#include "AP_HAL_SITL.h"
|
2015-05-04 03:15:12 -03:00
|
|
|
#include "AP_HAL_SITL_Namespace.h"
|
|
|
|
#include "HAL_SITL_Class.h"
|
2012-12-14 21:54:26 -04:00
|
|
|
#include "UARTDriver.h"
|
|
|
|
#include "Scheduler.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
2012-12-18 03:12:05 -04:00
|
|
|
#include <sys/select.h>
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-08-11 03:28:43 -03:00
|
|
|
#include <AP_Param/AP_Param.h>
|
2016-01-01 02:09:07 -04:00
|
|
|
#include <SITL/SIM_JSBSim.h>
|
2016-01-03 17:22:02 -04:00
|
|
|
#include <AP_HAL/utility/Socket.h>
|
2015-03-21 11:27:25 -03:00
|
|
|
|
2012-12-14 21:54:26 -04:00
|
|
|
extern const AP_HAL::HAL& hal;
|
|
|
|
|
2015-05-04 03:15:12 -03:00
|
|
|
using namespace HALSITL;
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-04 18:08:42 -03:00
|
|
|
void SITL_State::_set_param_default(const char *parm)
|
2014-04-10 23:28:32 -03:00
|
|
|
{
|
2015-05-04 18:08:42 -03:00
|
|
|
char *pdup = strdup(parm);
|
|
|
|
char *p = strchr(pdup, '=');
|
2016-10-30 02:24:21 -03:00
|
|
|
if (p == nullptr) {
|
2014-04-10 23:28:32 -03:00
|
|
|
printf("Please specify parameter as NAME=VALUE");
|
|
|
|
exit(1);
|
|
|
|
}
|
2016-10-30 02:24:21 -03:00
|
|
|
float value = strtof(p+1, nullptr);
|
2014-04-10 23:28:32 -03:00
|
|
|
*p = 0;
|
|
|
|
enum ap_var_type var_type;
|
2015-10-01 22:15:21 -03:00
|
|
|
AP_Param *vp = AP_Param::find(pdup, &var_type);
|
2016-10-30 02:24:21 -03:00
|
|
|
if (vp == nullptr) {
|
2015-10-01 22:15:21 -03:00
|
|
|
printf("Unknown parameter %s\n", pdup);
|
2015-05-04 21:59:07 -03:00
|
|
|
exit(1);
|
2014-04-10 23:28:32 -03:00
|
|
|
}
|
|
|
|
if (var_type == AP_PARAM_FLOAT) {
|
|
|
|
((AP_Float *)vp)->set_and_save(value);
|
|
|
|
} else if (var_type == AP_PARAM_INT32) {
|
|
|
|
((AP_Int32 *)vp)->set_and_save(value);
|
|
|
|
} else if (var_type == AP_PARAM_INT16) {
|
|
|
|
((AP_Int16 *)vp)->set_and_save(value);
|
|
|
|
} else if (var_type == AP_PARAM_INT8) {
|
|
|
|
((AP_Int8 *)vp)->set_and_save(value);
|
|
|
|
} else {
|
2015-10-01 22:15:21 -03:00
|
|
|
printf("Unable to set parameter %s\n", pdup);
|
2014-04-10 23:28:32 -03:00
|
|
|
exit(1);
|
|
|
|
}
|
2015-10-01 22:15:21 -03:00
|
|
|
printf("Set parameter %s to %f\n", pdup, value);
|
2015-05-04 18:08:42 -03:00
|
|
|
free(pdup);
|
2014-04-10 23:28:32 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-12-14 21:54:26 -04:00
|
|
|
/*
|
|
|
|
setup for SITL handling
|
|
|
|
*/
|
2015-11-18 21:22:47 -04:00
|
|
|
void SITL_State::_sitl_setup(const char *home_str)
|
2012-12-14 21:54:26 -04:00
|
|
|
{
|
2016-06-20 22:00:36 -03:00
|
|
|
_home_str = home_str;
|
|
|
|
|
2018-03-02 00:28:15 -04:00
|
|
|
#if !defined(__CYGWIN__) && !defined(__CYGWIN64__)
|
2015-05-04 21:59:07 -03:00
|
|
|
_parent_pid = getppid();
|
2012-12-14 21:54:26 -04:00
|
|
|
#endif
|
|
|
|
|
2014-08-09 08:23:19 -03:00
|
|
|
#ifndef HIL_MODE
|
2015-05-04 21:59:07 -03:00
|
|
|
_setup_fdm();
|
2014-08-09 08:23:19 -03:00
|
|
|
#endif
|
2015-05-04 21:59:07 -03:00
|
|
|
fprintf(stdout, "Starting SITL input\n");
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-04 21:59:07 -03:00
|
|
|
// find the barometer object if it exists
|
2018-06-15 17:03:18 -03:00
|
|
|
_sitl = AP::sitl();
|
2019-02-10 14:29:43 -04:00
|
|
|
_barometer = AP_Baro::get_singleton();
|
|
|
|
_ins = AP_InertialSensor::get_singleton();
|
2018-06-15 17:03:18 -03:00
|
|
|
_compass = Compass::get_singleton();
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2016-10-30 02:24:21 -03:00
|
|
|
if (_sitl != nullptr) {
|
2012-12-14 21:54:26 -04:00
|
|
|
// setup some initial values
|
2014-08-09 08:23:19 -03:00
|
|
|
#ifndef HIL_MODE
|
2017-05-11 10:38:32 -03:00
|
|
|
_update_airspeed(0);
|
2017-05-28 01:09:58 -03:00
|
|
|
_update_gps(0, 0, 0, 0, 0, 0, 0, false);
|
2017-01-09 05:16:13 -04:00
|
|
|
_update_rangefinder(0);
|
2014-08-09 08:23:19 -03:00
|
|
|
#endif
|
2015-05-24 23:11:16 -03:00
|
|
|
if (enable_gimbal) {
|
2016-02-26 01:15:00 -04:00
|
|
|
gimbal = new SITL::Gimbal(_sitl->state);
|
2015-05-24 23:11:16 -03:00
|
|
|
}
|
2016-01-01 02:09:07 -04:00
|
|
|
|
2019-10-08 01:14:45 -03:00
|
|
|
sitl_model->set_buzzer(&_sitl->buzzer_sim);
|
2018-07-31 09:32:43 -03:00
|
|
|
sitl_model->set_sprayer(&_sitl->sprayer_sim);
|
|
|
|
sitl_model->set_gripper_servo(&_sitl->gripper_sim);
|
|
|
|
sitl_model->set_gripper_epm(&_sitl->gripper_epm_sim);
|
2019-01-08 21:40:22 -04:00
|
|
|
sitl_model->set_parachute(&_sitl->parachute_sim);
|
2019-02-28 22:24:15 -04:00
|
|
|
sitl_model->set_precland(&_sitl->precland_sim);
|
2020-10-20 19:41:31 -03:00
|
|
|
_sitl->i2c_sim.init();
|
2020-08-03 00:24:26 -03:00
|
|
|
sitl_model->set_i2c(&_sitl->i2c_sim);
|
2018-07-31 09:32:43 -03:00
|
|
|
|
2016-09-21 14:02:15 -03:00
|
|
|
if (_use_fg_view) {
|
2018-06-16 22:39:41 -03:00
|
|
|
fg_socket.connect(_fg_address, _fg_view_port);
|
2016-09-21 14:02:15 -03:00
|
|
|
}
|
|
|
|
|
2016-11-21 09:39:13 -04:00
|
|
|
fprintf(stdout, "Using Irlock at port : %d\n", _irlock_port);
|
2016-11-17 14:05:04 -04:00
|
|
|
_sitl->irlock_port = _irlock_port;
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
2015-03-21 11:27:25 -03:00
|
|
|
|
|
|
|
if (_synthetic_clock_mode) {
|
|
|
|
// start with non-zero clock
|
2015-04-30 04:15:40 -03:00
|
|
|
hal.scheduler->stop_clock(1);
|
2015-03-21 11:27:25 -03:00
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-08-09 08:23:19 -03:00
|
|
|
#ifndef HIL_MODE
|
2012-12-14 21:54:26 -04:00
|
|
|
/*
|
|
|
|
setup a SITL FDM listening UDP port
|
|
|
|
*/
|
|
|
|
void SITL_State::_setup_fdm(void)
|
|
|
|
{
|
2018-12-19 06:44:34 -04:00
|
|
|
if (!_sitl_rc_in.reuseaddress()) {
|
|
|
|
fprintf(stderr, "SITL: socket reuseaddress failed on RC in port: %d - %s\n", _rcin_port, strerror(errno));
|
2018-06-08 01:12:58 -03:00
|
|
|
fprintf(stderr, "Aborting launch...\n");
|
2015-05-04 21:59:07 -03:00
|
|
|
exit(1);
|
|
|
|
}
|
2018-12-19 06:44:34 -04:00
|
|
|
if (!_sitl_rc_in.bind("0.0.0.0", _rcin_port)) {
|
|
|
|
fprintf(stderr, "SITL: socket bind failed on RC in port : %d - %s\n", _rcin_port, strerror(errno));
|
2018-12-13 22:37:20 -04:00
|
|
|
fprintf(stderr, "Aborting launch...\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!_sitl_rc_in.set_blocking(false)) {
|
|
|
|
fprintf(stderr, "SITL: socket set_blocking(false) failed on RC in port: %d - %s\n", _rcin_port, strerror(errno));
|
|
|
|
fprintf(stderr, "Aborting launch...\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (!_sitl_rc_in.set_cloexec()) {
|
|
|
|
fprintf(stderr, "SITL: socket set_cloexec() failed on RC in port: %d - %s\n", _rcin_port, strerror(errno));
|
|
|
|
fprintf(stderr, "Aborting launch...\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
2014-08-09 08:23:19 -03:00
|
|
|
#endif
|
2012-12-14 21:54:26 -04:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
2015-05-02 08:41:13 -03:00
|
|
|
step the FDM by one time step
|
2012-12-14 21:54:26 -04:00
|
|
|
*/
|
2015-05-02 08:41:13 -03:00
|
|
|
void SITL_State::_fdm_input_step(void)
|
2012-12-14 21:54:26 -04:00
|
|
|
{
|
2015-05-02 08:41:13 -03:00
|
|
|
static uint32_t last_pwm_input = 0;
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-11-22 22:21:33 -04:00
|
|
|
_fdm_input_local();
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-02 08:41:13 -03:00
|
|
|
/* make sure we die if our parent dies */
|
|
|
|
if (kill(_parent_pid, 0) != 0) {
|
|
|
|
exit(1);
|
|
|
|
}
|
2015-05-04 21:59:07 -03:00
|
|
|
|
2016-10-30 02:24:21 -03:00
|
|
|
if (_scheduler->interrupts_are_blocked() || _sitl == nullptr) {
|
2015-05-02 08:41:13 -03:00
|
|
|
return;
|
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-02 08:41:13 -03:00
|
|
|
// simulate RC input at 50Hz
|
2018-07-31 07:24:18 -03:00
|
|
|
if (AP_HAL::millis() - last_pwm_input >= 20 && _sitl->rc_fail != SITL::SITL::SITL_RCFail_NoPulses) {
|
2015-11-19 23:11:17 -04:00
|
|
|
last_pwm_input = AP_HAL::millis();
|
2015-05-02 08:41:13 -03:00
|
|
|
new_rc_input = true;
|
|
|
|
}
|
2015-03-21 11:27:25 -03:00
|
|
|
|
2015-05-02 08:41:13 -03:00
|
|
|
_scheduler->sitl_begin_atomic();
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2016-10-30 02:24:21 -03:00
|
|
|
if (_update_count == 0 && _sitl != nullptr) {
|
2017-05-28 01:09:58 -03:00
|
|
|
_update_gps(0, 0, 0, 0, 0, 0, 0, false);
|
2015-03-21 11:27:25 -03:00
|
|
|
_scheduler->timer_event();
|
|
|
|
_scheduler->sitl_end_atomic();
|
2015-05-02 08:41:13 -03:00
|
|
|
return;
|
|
|
|
}
|
2015-03-21 11:27:25 -03:00
|
|
|
|
2016-10-30 02:24:21 -03:00
|
|
|
if (_sitl != nullptr) {
|
2015-05-02 08:41:13 -03:00
|
|
|
_update_gps(_sitl->state.latitude, _sitl->state.longitude,
|
|
|
|
_sitl->state.altitude,
|
|
|
|
_sitl->state.speedN, _sitl->state.speedE, _sitl->state.speedD,
|
2020-07-07 20:53:01 -03:00
|
|
|
_sitl->state.yawDeg, true);
|
2017-05-11 10:38:32 -03:00
|
|
|
_update_airspeed(_sitl->state.airspeed);
|
2017-01-09 05:16:13 -04:00
|
|
|
_update_rangefinder(_sitl->state.range);
|
2016-06-20 22:00:36 -03:00
|
|
|
|
|
|
|
if (_sitl->adsb_plane_count >= 0 &&
|
|
|
|
adsb == nullptr) {
|
2019-10-24 13:11:10 -03:00
|
|
|
adsb = new SITL::ADSB(_sitl->state, sitl_model->get_home());
|
2016-06-20 22:00:36 -03:00
|
|
|
} else if (_sitl->adsb_plane_count == -1 &&
|
|
|
|
adsb != nullptr) {
|
|
|
|
delete adsb;
|
|
|
|
adsb = nullptr;
|
|
|
|
}
|
2015-05-02 08:41:13 -03:00
|
|
|
}
|
2015-05-04 21:59:07 -03:00
|
|
|
|
|
|
|
// trigger all APM timers.
|
2015-05-02 08:41:13 -03:00
|
|
|
_scheduler->timer_event();
|
|
|
|
_scheduler->sitl_end_atomic();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void SITL_State::wait_clock(uint64_t wait_time_usec)
|
|
|
|
{
|
2015-11-19 23:11:17 -04:00
|
|
|
while (AP_HAL::micros64() < wait_time_usec) {
|
2019-09-02 03:00:16 -03:00
|
|
|
if (hal.scheduler->in_main_thread() ||
|
|
|
|
Scheduler::from(hal.scheduler)->semaphore_wait_hack_required()) {
|
2018-07-06 23:42:00 -03:00
|
|
|
_fdm_input_step();
|
|
|
|
} else {
|
|
|
|
usleep(1000);
|
|
|
|
}
|
2015-03-21 11:27:25 -03:00
|
|
|
}
|
2020-04-02 21:50:25 -03:00
|
|
|
// check the outbound TCP queue size. If it is too long then
|
|
|
|
// MAVProxy/pymavlink take too long to process packets and it ends
|
|
|
|
// up seeing traffic well into our past and hits time-out
|
|
|
|
// conditions.
|
|
|
|
if (sitl_model->get_speedup() > 1) {
|
|
|
|
while (true) {
|
|
|
|
const int queue_length = ((HALSITL::UARTDriver*)hal.uartA)->get_system_outqueue_length();
|
|
|
|
// ::fprintf(stderr, "queue_length=%d\n", (signed)queue_length);
|
|
|
|
if (queue_length < 1024) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
usleep(1000);
|
|
|
|
}
|
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
|
|
|
|
2017-08-10 07:23:11 -03:00
|
|
|
#define streq(a, b) (!strcmp(a, b))
|
|
|
|
int SITL_State::sim_fd(const char *name, const char *arg)
|
|
|
|
{
|
2018-03-07 21:25:34 -04:00
|
|
|
if (streq(name, "vicon")) {
|
|
|
|
if (vicon != nullptr) {
|
|
|
|
AP_HAL::panic("Only one vicon system at a time");
|
|
|
|
}
|
|
|
|
vicon = new SITL::Vicon();
|
|
|
|
return vicon->fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "benewake_tf02")) {
|
|
|
|
if (benewake_tf02 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one benewake_tf02 at a time");
|
|
|
|
}
|
|
|
|
benewake_tf02 = new SITL::RF_Benewake_TF02();
|
|
|
|
return benewake_tf02->fd();
|
|
|
|
} else if (streq(name, "benewake_tf03")) {
|
|
|
|
if (benewake_tf03 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one benewake_tf03 at a time");
|
|
|
|
}
|
|
|
|
benewake_tf03 = new SITL::RF_Benewake_TF03();
|
|
|
|
return benewake_tf03->fd();
|
|
|
|
} else if (streq(name, "benewake_tfmini")) {
|
|
|
|
if (benewake_tfmini != nullptr) {
|
|
|
|
AP_HAL::panic("Only one benewake_tfmini at a time");
|
|
|
|
}
|
|
|
|
benewake_tfmini = new SITL::RF_Benewake_TFmini();
|
|
|
|
return benewake_tfmini->fd();
|
|
|
|
} else if (streq(name, "lightwareserial")) {
|
|
|
|
if (lightwareserial != nullptr) {
|
|
|
|
AP_HAL::panic("Only one lightwareserial at a time");
|
|
|
|
}
|
|
|
|
lightwareserial = new SITL::RF_LightWareSerial();
|
|
|
|
return lightwareserial->fd();
|
2020-06-30 08:10:28 -03:00
|
|
|
} else if (streq(name, "lightwareserial-binary")) {
|
|
|
|
if (lightwareserial_binary != nullptr) {
|
|
|
|
AP_HAL::panic("Only one lightwareserial-binary at a time");
|
|
|
|
}
|
|
|
|
lightwareserial_binary = new SITL::RF_LightWareSerialBinary();
|
|
|
|
return lightwareserial_binary->fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "lanbao")) {
|
|
|
|
if (lanbao != nullptr) {
|
|
|
|
AP_HAL::panic("Only one lanbao at a time");
|
|
|
|
}
|
|
|
|
lanbao = new SITL::RF_Lanbao();
|
|
|
|
return lanbao->fd();
|
|
|
|
} else if (streq(name, "blping")) {
|
|
|
|
if (blping != nullptr) {
|
|
|
|
AP_HAL::panic("Only one blping at a time");
|
|
|
|
}
|
|
|
|
blping = new SITL::RF_BLping();
|
|
|
|
return blping->fd();
|
|
|
|
} else if (streq(name, "leddarone")) {
|
|
|
|
if (leddarone != nullptr) {
|
|
|
|
AP_HAL::panic("Only one leddarone at a time");
|
|
|
|
}
|
|
|
|
leddarone = new SITL::RF_LeddarOne();
|
|
|
|
return leddarone->fd();
|
|
|
|
} else if (streq(name, "ulanding_v0")) {
|
|
|
|
if (ulanding_v0 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one ulanding_v0 at a time");
|
|
|
|
}
|
|
|
|
ulanding_v0 = new SITL::RF_uLanding_v0();
|
|
|
|
return ulanding_v0->fd();
|
|
|
|
} else if (streq(name, "ulanding_v1")) {
|
|
|
|
if (ulanding_v1 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one ulanding_v1 at a time");
|
|
|
|
}
|
|
|
|
ulanding_v1 = new SITL::RF_uLanding_v1();
|
|
|
|
return ulanding_v1->fd();
|
|
|
|
} else if (streq(name, "maxsonarseriallv")) {
|
|
|
|
if (maxsonarseriallv != nullptr) {
|
|
|
|
AP_HAL::panic("Only one maxsonarseriallv at a time");
|
|
|
|
}
|
|
|
|
maxsonarseriallv = new SITL::RF_MaxsonarSerialLV();
|
|
|
|
return maxsonarseriallv->fd();
|
|
|
|
} else if (streq(name, "wasp")) {
|
|
|
|
if (wasp != nullptr) {
|
|
|
|
AP_HAL::panic("Only one wasp at a time");
|
|
|
|
}
|
|
|
|
wasp = new SITL::RF_Wasp();
|
|
|
|
return wasp->fd();
|
|
|
|
} else if (streq(name, "nmea")) {
|
|
|
|
if (nmea != nullptr) {
|
|
|
|
AP_HAL::panic("Only one nmea at a time");
|
|
|
|
}
|
|
|
|
nmea = new SITL::RF_NMEA();
|
|
|
|
return nmea->fd();
|
2019-12-16 22:21:13 -04:00
|
|
|
|
2020-04-21 00:29:11 -03:00
|
|
|
} else if (streq(name, "rf_mavlink")) {
|
|
|
|
if (wasp != nullptr) {
|
|
|
|
AP_HAL::panic("Only one rf_mavlink at a time");
|
|
|
|
}
|
|
|
|
rf_mavlink = new SITL::RF_MAVLink();
|
|
|
|
return rf_mavlink->fd();
|
|
|
|
|
2019-12-16 22:21:13 -04:00
|
|
|
} else if (streq(name, "frsky-d")) {
|
|
|
|
if (frsky_d != nullptr) {
|
|
|
|
AP_HAL::panic("Only one frsky_d at a time");
|
|
|
|
}
|
|
|
|
frsky_d = new SITL::Frsky_D();
|
|
|
|
return frsky_d->fd();
|
|
|
|
// } else if (streq(name, "frsky-SPort")) {
|
|
|
|
// if (frsky_sport != nullptr) {
|
|
|
|
// AP_HAL::panic("Only one frsky_sport at a time");
|
|
|
|
// }
|
|
|
|
// frsky_sport = new SITL::Frsky_SPort();
|
|
|
|
// return frsky_sport->fd();
|
|
|
|
|
|
|
|
// } else if (streq(name, "frsky-SPortPassthrough")) {
|
|
|
|
// if (frsky_sport_passthrough != nullptr) {
|
|
|
|
// AP_HAL::panic("Only one frsky_sport passthrough at a time");
|
|
|
|
// }
|
|
|
|
// frsky_sport = new SITL::Frsky_SPortPassthrough();
|
|
|
|
// return frsky_sportpassthrough->fd();
|
2020-06-04 14:59:30 -03:00
|
|
|
} else if (streq(name, "crsf")) {
|
|
|
|
if (crsf != nullptr) {
|
|
|
|
AP_HAL::panic("Only one crsf at a time");
|
|
|
|
}
|
|
|
|
crsf = new SITL::CRSF();
|
|
|
|
return crsf->fd();
|
2019-11-20 22:11:42 -04:00
|
|
|
} else if (streq(name, "rplidara2")) {
|
|
|
|
if (rplidara2 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one rplidara2 at a time");
|
|
|
|
}
|
|
|
|
rplidara2 = new SITL::PS_RPLidarA2();
|
|
|
|
return rplidara2->fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "richenpower")) {
|
|
|
|
sitl_model->set_richenpower(&_sitl->richenpower_sim);
|
|
|
|
return _sitl->richenpower_sim.fd();
|
2020-06-14 20:36:08 -03:00
|
|
|
} else if (streq(name, "gyus42v2")) {
|
|
|
|
if (gyus42v2 != nullptr) {
|
|
|
|
AP_HAL::panic("Only one gyus42v2 at a time");
|
|
|
|
}
|
|
|
|
gyus42v2 = new SITL::RF_GYUS42v2();
|
|
|
|
return gyus42v2->fd();
|
2018-03-07 21:25:34 -04:00
|
|
|
}
|
2019-10-28 23:52:19 -03:00
|
|
|
|
|
|
|
AP_HAL::panic("unknown simulated device: %s", name);
|
|
|
|
}
|
|
|
|
int SITL_State::sim_fd_write(const char *name)
|
|
|
|
{
|
|
|
|
if (streq(name, "vicon")) {
|
|
|
|
if (vicon == nullptr) {
|
|
|
|
AP_HAL::panic("No vicon created");
|
|
|
|
}
|
|
|
|
return vicon->write_fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "benewake_tf02")) {
|
|
|
|
if (benewake_tf02 == nullptr) {
|
|
|
|
AP_HAL::panic("No benewake_tf02 created");
|
|
|
|
}
|
|
|
|
return benewake_tf02->write_fd();
|
|
|
|
} else if (streq(name, "benewake_tf03")) {
|
|
|
|
if (benewake_tf03 == nullptr) {
|
|
|
|
AP_HAL::panic("No benewake_tf03 created");
|
|
|
|
}
|
|
|
|
return benewake_tf03->write_fd();
|
|
|
|
} else if (streq(name, "benewake_tfmini")) {
|
|
|
|
if (benewake_tfmini == nullptr) {
|
|
|
|
AP_HAL::panic("No benewake_tfmini created");
|
|
|
|
}
|
|
|
|
return benewake_tfmini->write_fd();
|
|
|
|
} else if (streq(name, "lightwareserial")) {
|
|
|
|
if (lightwareserial == nullptr) {
|
|
|
|
AP_HAL::panic("No lightwareserial created");
|
|
|
|
}
|
|
|
|
return lightwareserial->write_fd();
|
2020-06-30 08:10:28 -03:00
|
|
|
} else if (streq(name, "lightwareserial-binary")) {
|
|
|
|
if (lightwareserial_binary == nullptr) {
|
|
|
|
AP_HAL::panic("No lightwareserial_binary created");
|
|
|
|
}
|
|
|
|
return lightwareserial_binary->write_fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "lanbao")) {
|
|
|
|
if (lanbao == nullptr) {
|
|
|
|
AP_HAL::panic("No lanbao created");
|
|
|
|
}
|
|
|
|
return lanbao->write_fd();
|
|
|
|
} else if (streq(name, "blping")) {
|
|
|
|
if (blping == nullptr) {
|
|
|
|
AP_HAL::panic("No blping created");
|
|
|
|
}
|
|
|
|
return blping->write_fd();
|
|
|
|
} else if (streq(name, "leddarone")) {
|
|
|
|
if (leddarone == nullptr) {
|
|
|
|
AP_HAL::panic("No leddarone created");
|
|
|
|
}
|
|
|
|
return leddarone->write_fd();
|
|
|
|
} else if (streq(name, "ulanding_v0")) {
|
|
|
|
if (ulanding_v0 == nullptr) {
|
|
|
|
AP_HAL::panic("No ulanding_v0 created");
|
|
|
|
}
|
|
|
|
return ulanding_v0->write_fd();
|
|
|
|
} else if (streq(name, "ulanding_v1")) {
|
|
|
|
if (ulanding_v1 == nullptr) {
|
|
|
|
AP_HAL::panic("No ulanding_v1 created");
|
|
|
|
}
|
|
|
|
return ulanding_v1->write_fd();
|
|
|
|
} else if (streq(name, "maxsonarseriallv")) {
|
|
|
|
if (maxsonarseriallv == nullptr) {
|
|
|
|
AP_HAL::panic("No maxsonarseriallv created");
|
|
|
|
}
|
|
|
|
return maxsonarseriallv->write_fd();
|
|
|
|
} else if (streq(name, "wasp")) {
|
|
|
|
if (wasp == nullptr) {
|
|
|
|
AP_HAL::panic("No wasp created");
|
|
|
|
}
|
|
|
|
return wasp->write_fd();
|
|
|
|
} else if (streq(name, "nmea")) {
|
|
|
|
if (nmea == nullptr) {
|
|
|
|
AP_HAL::panic("No nmea created");
|
|
|
|
}
|
|
|
|
return nmea->write_fd();
|
2020-04-21 00:29:11 -03:00
|
|
|
} else if (streq(name, "rf_mavlink")) {
|
|
|
|
if (rf_mavlink == nullptr) {
|
|
|
|
AP_HAL::panic("No rf_mavlink created");
|
|
|
|
}
|
|
|
|
return rf_mavlink->write_fd();
|
2019-12-16 22:21:13 -04:00
|
|
|
} else if (streq(name, "frsky-d")) {
|
|
|
|
if (frsky_d == nullptr) {
|
|
|
|
AP_HAL::panic("No frsky-d created");
|
|
|
|
}
|
|
|
|
return frsky_d->write_fd();
|
2020-06-04 14:59:30 -03:00
|
|
|
} else if (streq(name, "crsf")) {
|
|
|
|
if (crsf == nullptr) {
|
|
|
|
AP_HAL::panic("No crsf created");
|
|
|
|
}
|
|
|
|
return crsf->write_fd();
|
2019-11-20 22:11:42 -04:00
|
|
|
} else if (streq(name, "rplidara2")) {
|
|
|
|
if (rplidara2 == nullptr) {
|
|
|
|
AP_HAL::panic("No rplidara2 created");
|
|
|
|
}
|
|
|
|
return rplidara2->write_fd();
|
2019-10-28 23:53:01 -03:00
|
|
|
} else if (streq(name, "richenpower")) {
|
|
|
|
return _sitl->richenpower_sim.write_fd();
|
2020-06-14 20:36:08 -03:00
|
|
|
} else if (streq(name, "gyus42v2")) {
|
|
|
|
if (gyus42v2 == nullptr) {
|
|
|
|
AP_HAL::panic("No gyus42v2 created");
|
|
|
|
}
|
|
|
|
return gyus42v2->write_fd();
|
2019-10-28 23:52:19 -03:00
|
|
|
}
|
2017-08-10 07:23:11 -03:00
|
|
|
AP_HAL::panic("unknown simulated device: %s", name);
|
|
|
|
}
|
|
|
|
|
2014-08-09 08:23:19 -03:00
|
|
|
#ifndef HIL_MODE
|
2012-12-14 21:54:26 -04:00
|
|
|
/*
|
2016-09-21 14:15:00 -03:00
|
|
|
check for a SITL RC input packet
|
2012-12-14 21:54:26 -04:00
|
|
|
*/
|
2016-09-21 14:15:00 -03:00
|
|
|
void SITL_State::_check_rc_input(void)
|
2012-12-14 21:54:26 -04:00
|
|
|
{
|
2018-05-30 07:18:40 -03:00
|
|
|
uint32_t count = 0;
|
|
|
|
while (_read_rc_sitl_input()) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 100) {
|
|
|
|
::fprintf(stderr, "Read %u rc inputs\n", count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SITL_State::_read_rc_sitl_input()
|
|
|
|
{
|
2015-05-04 21:59:07 -03:00
|
|
|
struct pwm_packet {
|
2016-01-03 17:22:02 -04:00
|
|
|
uint16_t pwm[16];
|
2015-11-22 22:21:33 -04:00
|
|
|
} pwm_pkt;
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2018-05-30 07:18:40 -03:00
|
|
|
const ssize_t size = _sitl_rc_in.recv(&pwm_pkt, sizeof(pwm_pkt), 0);
|
2015-11-22 22:21:33 -04:00
|
|
|
switch (size) {
|
2018-05-30 07:18:40 -03:00
|
|
|
case -1:
|
|
|
|
return false;
|
2016-01-03 17:22:02 -04:00
|
|
|
case 8*2:
|
|
|
|
case 16*2: {
|
2015-05-04 21:59:07 -03:00
|
|
|
// a packet giving the receiver PWM inputs
|
2018-07-31 07:24:18 -03:00
|
|
|
for (uint8_t i=0; i<size/2; i++) {
|
2016-01-04 09:21:54 -04:00
|
|
|
// setup the pwm input for the RC channel inputs
|
2016-05-03 23:50:02 -03:00
|
|
|
if (i < _sitl->state.rcin_chan_count) {
|
|
|
|
// we're using rc from simulator
|
|
|
|
continue;
|
|
|
|
}
|
2018-07-31 07:24:18 -03:00
|
|
|
uint16_t pwm = pwm_pkt.pwm[i];
|
|
|
|
if (pwm != 0) {
|
|
|
|
if (_sitl->rc_fail == SITL::SITL::SITL_RCFail_Throttle950) {
|
|
|
|
if (i == 2) {
|
|
|
|
// set throttle (assumed to be on channel 3...)
|
|
|
|
pwm = 950;
|
|
|
|
} else {
|
|
|
|
// centre all other inputs
|
|
|
|
pwm = 1500;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pwm_input[i] = pwm;
|
2015-05-04 21:59:07 -03:00
|
|
|
}
|
|
|
|
}
|
2018-05-30 07:18:40 -03:00
|
|
|
return true;
|
2015-05-04 21:59:07 -03:00
|
|
|
}
|
2018-05-30 07:18:40 -03:00
|
|
|
default:
|
2019-10-28 03:05:28 -03:00
|
|
|
fprintf(stderr, "Malformed SITL RC input (%ld)", (long)size);
|
2015-05-04 21:59:07 -03:00
|
|
|
}
|
2018-05-30 07:18:40 -03:00
|
|
|
return false;
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
2015-05-02 07:27:33 -03:00
|
|
|
|
2016-01-01 02:09:07 -04:00
|
|
|
/*
|
|
|
|
output current state to flightgear
|
|
|
|
*/
|
|
|
|
void SITL_State::_output_to_flightgear(void)
|
|
|
|
{
|
|
|
|
SITL::FGNetFDM fdm {};
|
|
|
|
const SITL::sitl_fdm &sfdm = _sitl->state;
|
|
|
|
|
|
|
|
fdm.version = 0x18;
|
|
|
|
fdm.padding = 0;
|
2018-10-10 16:03:11 -03:00
|
|
|
fdm.longitude = DEG_TO_RAD_DOUBLE*sfdm.longitude;
|
|
|
|
fdm.latitude = DEG_TO_RAD_DOUBLE*sfdm.latitude;
|
2016-01-01 02:09:07 -04:00
|
|
|
fdm.altitude = sfdm.altitude;
|
|
|
|
fdm.agl = sfdm.altitude;
|
|
|
|
fdm.phi = radians(sfdm.rollDeg);
|
|
|
|
fdm.theta = radians(sfdm.pitchDeg);
|
|
|
|
fdm.psi = radians(sfdm.yawDeg);
|
2016-01-03 20:09:27 -04:00
|
|
|
if (_vehicle == ArduCopter) {
|
|
|
|
fdm.num_engines = 4;
|
|
|
|
for (uint8_t i=0; i<4; i++) {
|
|
|
|
fdm.rpm[i] = constrain_float((pwm_output[i]-1000), 0, 1000);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fdm.num_engines = 4;
|
|
|
|
fdm.rpm[0] = constrain_float((pwm_output[2]-1000)*3, 0, 3000);
|
|
|
|
// for quadplane
|
|
|
|
fdm.rpm[1] = constrain_float((pwm_output[5]-1000)*12, 0, 12000);
|
|
|
|
fdm.rpm[2] = constrain_float((pwm_output[6]-1000)*12, 0, 12000);
|
|
|
|
fdm.rpm[3] = constrain_float((pwm_output[7]-1000)*12, 0, 12000);
|
|
|
|
}
|
2016-01-01 02:09:07 -04:00
|
|
|
fdm.ByteSwap();
|
|
|
|
|
|
|
|
fg_socket.send(&fdm, sizeof(fdm));
|
|
|
|
}
|
2015-05-02 07:27:33 -03:00
|
|
|
|
|
|
|
/*
|
|
|
|
get FDM input from a local model
|
|
|
|
*/
|
|
|
|
void SITL_State::_fdm_input_local(void)
|
|
|
|
{
|
2018-07-31 09:32:43 -03:00
|
|
|
struct sitl_input input;
|
2015-05-02 07:27:33 -03:00
|
|
|
|
2015-05-02 08:54:19 -03:00
|
|
|
// check for direct RC input
|
2016-09-21 14:15:00 -03:00
|
|
|
_check_rc_input();
|
2015-05-02 08:54:19 -03:00
|
|
|
|
|
|
|
// construct servos structure for FDM
|
2015-05-02 07:27:33 -03:00
|
|
|
_simulator_servos(input);
|
2015-05-02 08:54:19 -03:00
|
|
|
|
|
|
|
// update the model
|
2019-08-15 03:52:50 -03:00
|
|
|
sitl_model->update_model(input);
|
2015-05-02 08:54:19 -03:00
|
|
|
|
|
|
|
// get FDM output from the model
|
2016-03-25 07:35:16 -03:00
|
|
|
if (_sitl) {
|
|
|
|
sitl_model->fill_fdm(_sitl->state);
|
|
|
|
_sitl->update_rate_hz = sitl_model->get_rate_hz();
|
2016-05-03 23:50:02 -03:00
|
|
|
|
2018-07-31 07:24:18 -03:00
|
|
|
if (_sitl->rc_fail == SITL::SITL::SITL_RCFail_None) {
|
2016-06-04 16:54:46 -03:00
|
|
|
for (uint8_t i=0; i< _sitl->state.rcin_chan_count; i++) {
|
|
|
|
pwm_input[i] = 1000 + _sitl->state.rcin[i]*1000;
|
|
|
|
}
|
2016-05-03 23:50:02 -03:00
|
|
|
}
|
2016-03-25 07:35:16 -03:00
|
|
|
}
|
2015-05-02 08:54:19 -03:00
|
|
|
|
2016-10-30 02:24:21 -03:00
|
|
|
if (gimbal != nullptr) {
|
2015-05-24 23:11:16 -03:00
|
|
|
gimbal->update();
|
|
|
|
}
|
2016-10-30 02:24:21 -03:00
|
|
|
if (adsb != nullptr) {
|
2015-11-18 21:22:47 -04:00
|
|
|
adsb->update();
|
|
|
|
}
|
2018-03-07 21:25:34 -04:00
|
|
|
if (vicon != nullptr) {
|
|
|
|
Quaternion attitude;
|
|
|
|
sitl_model->get_attitude(attitude);
|
|
|
|
vicon->update(sitl_model->get_location(),
|
|
|
|
sitl_model->get_position(),
|
2020-05-14 23:14:22 -03:00
|
|
|
sitl_model->get_velocity_ef(),
|
2018-03-07 21:25:34 -04:00
|
|
|
attitude);
|
|
|
|
}
|
2019-10-28 23:53:01 -03:00
|
|
|
if (benewake_tf02 != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
benewake_tf02->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (benewake_tf03 != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
benewake_tf03->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (benewake_tfmini != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
benewake_tfmini->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (lightwareserial != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
lightwareserial->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
2020-06-30 08:10:28 -03:00
|
|
|
if (lightwareserial_binary != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
lightwareserial_binary->update(sitl_model->rangefinder_range());
|
2020-06-30 08:10:28 -03:00
|
|
|
}
|
2019-10-28 23:53:01 -03:00
|
|
|
if (lanbao != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
lanbao->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (blping != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
blping->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (leddarone != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
leddarone->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (ulanding_v0 != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
ulanding_v0->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (ulanding_v1 != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
ulanding_v1->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (maxsonarseriallv != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
maxsonarseriallv->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (wasp != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
wasp->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
|
|
|
if (nmea != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
nmea->update(sitl_model->rangefinder_range());
|
2019-10-28 23:53:01 -03:00
|
|
|
}
|
2020-04-21 00:29:11 -03:00
|
|
|
if (rf_mavlink != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
rf_mavlink->update(sitl_model->rangefinder_range());
|
2020-04-21 00:29:11 -03:00
|
|
|
}
|
2020-06-14 20:36:08 -03:00
|
|
|
if (gyus42v2 != nullptr) {
|
2020-08-04 00:47:23 -03:00
|
|
|
gyus42v2->update(sitl_model->rangefinder_range());
|
2020-06-14 20:36:08 -03:00
|
|
|
}
|
2015-05-24 23:11:16 -03:00
|
|
|
|
2019-12-16 22:21:13 -04:00
|
|
|
if (frsky_d != nullptr) {
|
|
|
|
frsky_d->update();
|
|
|
|
}
|
|
|
|
// if (frsky_sport != nullptr) {
|
|
|
|
// frsky_sport->update();
|
|
|
|
// }
|
|
|
|
// if (frsky_sportpassthrough != nullptr) {
|
|
|
|
// frsky_sportpassthrough->update();
|
|
|
|
// }
|
2020-06-04 14:59:30 -03:00
|
|
|
|
|
|
|
if (crsf != nullptr) {
|
|
|
|
crsf->update();
|
|
|
|
}
|
|
|
|
|
2019-11-20 22:11:42 -04:00
|
|
|
if (rplidara2 != nullptr) {
|
|
|
|
rplidara2->update(sitl_model->get_location());
|
|
|
|
}
|
2019-12-16 22:21:13 -04:00
|
|
|
|
2019-11-10 07:18:32 -04:00
|
|
|
if (_sitl) {
|
|
|
|
_sitl->efi_ms.update();
|
|
|
|
}
|
|
|
|
|
2016-09-21 14:02:15 -03:00
|
|
|
if (_sitl && _use_fg_view) {
|
2016-03-25 07:35:16 -03:00
|
|
|
_output_to_flightgear();
|
|
|
|
}
|
2016-01-01 02:09:07 -04:00
|
|
|
|
2015-05-02 08:54:19 -03:00
|
|
|
// update simulation time
|
2016-03-25 07:35:16 -03:00
|
|
|
if (_sitl) {
|
|
|
|
hal.scheduler->stop_clock(_sitl->state.timestamp_us);
|
|
|
|
} else {
|
|
|
|
hal.scheduler->stop_clock(AP_HAL::micros64()+100);
|
|
|
|
}
|
2015-05-02 08:54:19 -03:00
|
|
|
|
2016-11-19 02:21:54 -04:00
|
|
|
set_height_agl();
|
|
|
|
|
2015-05-02 07:27:33 -03:00
|
|
|
_synthetic_clock_mode = true;
|
|
|
|
_update_count++;
|
|
|
|
}
|
2014-08-09 08:23:19 -03:00
|
|
|
#endif
|
2012-12-14 21:54:26 -04:00
|
|
|
|
|
|
|
/*
|
2015-05-02 07:27:33 -03:00
|
|
|
create sitl_input structure for sending to FDM
|
2012-12-14 21:54:26 -04:00
|
|
|
*/
|
2018-07-31 09:32:43 -03:00
|
|
|
void SITL_State::_simulator_servos(struct sitl_input &input)
|
2012-12-14 21:54:26 -04:00
|
|
|
{
|
2015-05-02 07:27:33 -03:00
|
|
|
static uint32_t last_update_usec;
|
|
|
|
|
2015-05-04 21:59:07 -03:00
|
|
|
/* this maps the registers used for PWM outputs. The RC
|
|
|
|
* driver updates these whenever it wants the channel output
|
|
|
|
* to change */
|
|
|
|
uint8_t i;
|
|
|
|
|
2017-08-07 09:05:52 -03:00
|
|
|
if (last_update_usec == 0 || !output_ready) {
|
2015-06-29 19:55:02 -03:00
|
|
|
for (i=0; i<SITL_NUM_CHANNELS; i++) {
|
2015-05-04 21:59:07 -03:00
|
|
|
pwm_output[i] = 1000;
|
|
|
|
}
|
|
|
|
if (_vehicle == ArduPlane) {
|
|
|
|
pwm_output[0] = pwm_output[1] = pwm_output[3] = 1500;
|
|
|
|
}
|
2020-03-26 21:51:15 -03:00
|
|
|
if (_vehicle == Rover) {
|
2015-05-04 21:59:07 -03:00
|
|
|
pwm_output[0] = pwm_output[1] = pwm_output[2] = pwm_output[3] = 1500;
|
|
|
|
}
|
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2015-05-04 21:59:07 -03:00
|
|
|
// output at chosen framerate
|
2015-11-19 23:11:17 -04:00
|
|
|
uint32_t now = AP_HAL::micros();
|
2015-05-04 21:59:07 -03:00
|
|
|
last_update_usec = now;
|
2013-09-15 20:16:52 -03:00
|
|
|
|
2015-05-22 22:04:13 -03:00
|
|
|
float altitude = _barometer?_barometer->get_altitude():0;
|
2016-07-15 22:36:59 -03:00
|
|
|
float wind_speed = 0;
|
|
|
|
float wind_direction = 0;
|
2018-01-30 12:37:18 -04:00
|
|
|
float wind_dir_z = 0;
|
2018-04-30 12:26:15 -03:00
|
|
|
|
|
|
|
// give 5 seconds to calibrate airspeed sensor at 0 wind speed
|
|
|
|
if (wind_start_delay_micros == 0) {
|
|
|
|
wind_start_delay_micros = now;
|
|
|
|
} else if (_sitl && (now - wind_start_delay_micros) > 5000000 ) {
|
2016-07-15 22:36:59 -03:00
|
|
|
// The EKF does not like step inputs so this LPF keeps it happy.
|
2018-01-30 12:37:18 -04:00
|
|
|
wind_speed = _sitl->wind_speed_active = (0.95f*_sitl->wind_speed_active) + (0.05f*_sitl->wind_speed);
|
2016-07-15 22:36:59 -03:00
|
|
|
wind_direction = _sitl->wind_direction_active = (0.95f*_sitl->wind_direction_active) + (0.05f*_sitl->wind_direction);
|
2018-01-30 12:37:18 -04:00
|
|
|
wind_dir_z = _sitl->wind_dir_z_active = (0.95f*_sitl->wind_dir_z_active) + (0.05f*_sitl->wind_dir_z);
|
2018-04-30 12:26:15 -03:00
|
|
|
|
|
|
|
// pass wind into simulators using different wind types via param SIM_WIND_T*.
|
|
|
|
switch (_sitl->wind_type) {
|
|
|
|
case SITL::SITL::WIND_TYPE_SQRT:
|
|
|
|
if (altitude < _sitl->wind_type_alt) {
|
|
|
|
wind_speed *= sqrtf(MAX(altitude / _sitl->wind_type_alt, 0));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SITL::SITL::WIND_TYPE_COEF:
|
|
|
|
wind_speed += (altitude - _sitl->wind_type_alt) * _sitl->wind_type_coef;
|
|
|
|
break;
|
2016-07-15 22:36:59 -03:00
|
|
|
|
2018-04-30 12:26:15 -03:00
|
|
|
case SITL::SITL::WIND_TYPE_NO_LIMIT:
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// never allow negative wind velocity
|
|
|
|
wind_speed = MAX(wind_speed, 0);
|
|
|
|
}
|
2016-07-15 22:36:59 -03:00
|
|
|
|
2015-05-22 22:04:13 -03:00
|
|
|
input.wind.speed = wind_speed;
|
2016-07-15 22:36:59 -03:00
|
|
|
input.wind.direction = wind_direction;
|
2016-03-25 07:35:16 -03:00
|
|
|
input.wind.turbulence = _sitl?_sitl->wind_turbulance:0;
|
2018-01-30 12:37:18 -04:00
|
|
|
input.wind.dir_z = wind_dir_z;
|
2015-05-22 22:04:13 -03:00
|
|
|
|
2015-06-29 19:55:02 -03:00
|
|
|
for (i=0; i<SITL_NUM_CHANNELS; i++) {
|
2015-05-04 21:59:07 -03:00
|
|
|
if (pwm_output[i] == 0xFFFF) {
|
|
|
|
input.servos[i] = 0;
|
|
|
|
} else {
|
|
|
|
input.servos[i] = pwm_output[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-26 00:17:12 -03:00
|
|
|
float engine_mul = _sitl?_sitl->engine_mul.get():1;
|
2017-03-20 17:41:09 -03:00
|
|
|
uint8_t engine_fail = _sitl?_sitl->engine_fail.get():0;
|
2019-12-24 17:19:05 -04:00
|
|
|
float throttle = 0.0f;
|
2016-03-25 07:35:16 -03:00
|
|
|
|
2017-04-07 22:50:28 -03:00
|
|
|
if (engine_fail >= ARRAY_SIZE(input.servos)) {
|
2017-03-20 17:41:09 -03:00
|
|
|
engine_fail = 0;
|
|
|
|
}
|
2017-04-07 22:50:28 -03:00
|
|
|
// apply engine multiplier to motor defined by the SIM_ENGINE_FAIL parameter
|
2020-03-26 21:51:15 -03:00
|
|
|
if (_vehicle != Rover) {
|
2017-03-05 09:20:20 -04:00
|
|
|
input.servos[engine_fail] = ((input.servos[engine_fail]-1000) * engine_mul) + 1000;
|
|
|
|
} else {
|
|
|
|
input.servos[engine_fail] = static_cast<uint16_t>(((input.servos[engine_fail] - 1500) * engine_mul) + 1500);
|
|
|
|
}
|
2019-12-24 17:19:05 -04:00
|
|
|
|
2015-05-04 21:59:07 -03:00
|
|
|
if (_vehicle == ArduPlane) {
|
2020-01-16 15:00:58 -04:00
|
|
|
float forward_throttle = constrain_float((input.servos[2] - 1000) / 1000.0f, 0.0f, 1.0f);
|
|
|
|
// do a little quadplane dance
|
|
|
|
float hover_throttle = 0.0f;
|
|
|
|
uint8_t running_motors = 0;
|
|
|
|
for (i=0; i < sitl_model->get_num_motors() - 1; i++) {
|
|
|
|
float motor_throttle = constrain_float((input.servos[sitl_model->get_motors_offset() + i] - 1000) / 1000.0f, 0.0f, 1.0f);
|
|
|
|
// update motor_on flag
|
|
|
|
if (!is_zero(motor_throttle)) {
|
|
|
|
hover_throttle += motor_throttle;
|
|
|
|
running_motors++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (running_motors > 0) {
|
|
|
|
hover_throttle /= running_motors;
|
|
|
|
}
|
|
|
|
if (!is_zero(forward_throttle)) {
|
|
|
|
throttle = forward_throttle;
|
|
|
|
} else {
|
|
|
|
throttle = hover_throttle;
|
|
|
|
}
|
2020-03-26 21:51:15 -03:00
|
|
|
} else if (_vehicle == Rover) {
|
2017-03-05 09:20:20 -04:00
|
|
|
input.servos[2] = static_cast<uint16_t>(constrain_int16(input.servos[2], 1000, 2000));
|
|
|
|
input.servos[0] = static_cast<uint16_t>(constrain_int16(input.servos[0], 1000, 2000));
|
2019-12-24 17:19:05 -04:00
|
|
|
throttle = fabsf((input.servos[2] - 1500) / 500.0f);
|
2015-05-04 21:59:07 -03:00
|
|
|
} else {
|
2013-05-19 02:29:08 -03:00
|
|
|
// run checks on each motor
|
2019-12-24 17:19:05 -04:00
|
|
|
uint8_t running_motors = 0;
|
2020-01-16 15:00:58 -04:00
|
|
|
for (i=0; i < sitl_model->get_num_motors(); i++) {
|
2019-12-24 17:19:05 -04:00
|
|
|
float motor_throttle = constrain_float((input.servos[i] - 1000) / 1000.0f, 0.0f, 1.0f);
|
2013-05-19 02:29:08 -03:00
|
|
|
// update motor_on flag
|
2019-12-24 17:19:05 -04:00
|
|
|
if (!is_zero(motor_throttle)) {
|
|
|
|
throttle += motor_throttle;
|
|
|
|
running_motors++;
|
2015-05-04 21:59:07 -03:00
|
|
|
}
|
|
|
|
}
|
2019-12-24 17:19:05 -04:00
|
|
|
if (running_motors > 0) {
|
|
|
|
throttle /= running_motors;
|
|
|
|
}
|
2015-05-04 21:59:07 -03:00
|
|
|
}
|
2016-03-25 07:35:16 -03:00
|
|
|
if (_sitl) {
|
2019-12-24 17:19:05 -04:00
|
|
|
_sitl->throttle = throttle;
|
2016-03-25 07:35:16 -03:00
|
|
|
}
|
2012-12-14 21:54:26 -04:00
|
|
|
|
2016-03-25 07:35:16 -03:00
|
|
|
float voltage = 0;
|
|
|
|
_current = 0;
|
2015-11-22 22:31:29 -04:00
|
|
|
|
2016-03-25 07:35:16 -03:00
|
|
|
if (_sitl != nullptr) {
|
|
|
|
if (_sitl->state.battery_voltage <= 0) {
|
2017-10-27 14:24:53 -03:00
|
|
|
if (_vehicle == ArduSub) {
|
|
|
|
voltage = _sitl->batt_voltage;
|
|
|
|
for (i = 0; i < 6; i++) {
|
|
|
|
float pwm = input.servos[i];
|
|
|
|
//printf("i: %d, pwm: %.2f\n", i, pwm);
|
|
|
|
float fraction = fabsf((pwm - 1500) / 500.0f);
|
|
|
|
|
|
|
|
voltage -= fraction * 0.5f;
|
|
|
|
|
|
|
|
float draw = fraction * 15;
|
|
|
|
_current += draw;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// simulate simple battery setup
|
|
|
|
// lose 0.7V at full throttle
|
2019-12-24 17:19:05 -04:00
|
|
|
voltage = _sitl->batt_voltage - 0.7f * throttle;
|
2017-10-27 14:24:53 -03:00
|
|
|
|
|
|
|
// assume 50A at full throttle
|
2019-12-24 17:19:05 -04:00
|
|
|
_current = 50.0f * throttle;
|
2017-10-27 14:24:53 -03:00
|
|
|
}
|
2016-03-25 07:35:16 -03:00
|
|
|
} else {
|
|
|
|
// FDM provides voltage and current
|
|
|
|
voltage = _sitl->state.battery_voltage;
|
|
|
|
_current = _sitl->state.battery_current;
|
|
|
|
}
|
2015-11-22 22:31:29 -04:00
|
|
|
}
|
2015-05-02 07:27:33 -03:00
|
|
|
|
2013-09-30 02:34:47 -03:00
|
|
|
// assume 3DR power brick
|
2015-04-24 00:47:07 -03:00
|
|
|
voltage_pin_value = ((voltage / 10.1f) / 5.0f) * 1024;
|
|
|
|
current_pin_value = ((_current / 17.0f) / 5.0f) * 1024;
|
2018-03-07 22:11:05 -04:00
|
|
|
// fake battery2 as just a 25% gain on the first one
|
|
|
|
voltage2_pin_value = ((voltage * 0.25f / 10.1f) / 5.0f) * 1024;
|
|
|
|
current2_pin_value = ((_current * 0.25f / 17.0f) / 5.0f) * 1024;
|
2015-05-02 07:27:33 -03:00
|
|
|
}
|
|
|
|
|
2012-12-14 21:54:26 -04:00
|
|
|
void SITL_State::init(int argc, char * const argv[])
|
|
|
|
{
|
2019-09-15 03:46:13 -03:00
|
|
|
pwm_input[0] = pwm_input[1] = pwm_input[3] = 1500;
|
|
|
|
pwm_input[4] = pwm_input[7] = 1800;
|
|
|
|
pwm_input[2] = pwm_input[5] = pwm_input[6] = 1000;
|
2012-12-17 23:56:21 -04:00
|
|
|
|
2016-01-10 02:23:32 -04:00
|
|
|
_scheduler = Scheduler::from(hal.scheduler);
|
2015-05-04 21:59:07 -03:00
|
|
|
_parse_command_line(argc, argv);
|
2012-12-14 21:54:26 -04:00
|
|
|
}
|
|
|
|
|
2015-01-03 06:47:54 -04:00
|
|
|
/*
|
2016-11-19 02:21:54 -04:00
|
|
|
set height above the ground in meters
|
2015-01-03 06:47:54 -04:00
|
|
|
*/
|
2016-11-19 02:21:54 -04:00
|
|
|
void SITL_State::set_height_agl(void)
|
2015-01-03 06:47:54 -04:00
|
|
|
{
|
2015-05-04 21:59:07 -03:00
|
|
|
static float home_alt = -1;
|
2015-01-03 06:47:54 -04:00
|
|
|
|
2018-11-04 01:31:04 -04:00
|
|
|
if (!_sitl) {
|
|
|
|
// in example program
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-14 23:35:38 -03:00
|
|
|
if (is_equal(home_alt, -1.0f) && _sitl->state.altitude > 0) {
|
2015-01-03 06:47:54 -04:00
|
|
|
// remember home altitude as first non-zero altitude
|
2015-05-04 21:59:07 -03:00
|
|
|
home_alt = _sitl->state.altitude;
|
2015-01-03 06:47:54 -04:00
|
|
|
}
|
|
|
|
|
2016-06-03 15:07:36 -03:00
|
|
|
#if AP_TERRAIN_AVAILABLE
|
2020-07-20 22:56:10 -03:00
|
|
|
if (_sitl != nullptr &&
|
2018-03-31 02:11:31 -03:00
|
|
|
_sitl->terrain_enable) {
|
2015-01-03 06:47:54 -04:00
|
|
|
// get height above terrain from AP_Terrain. This assumes
|
|
|
|
// AP_Terrain is working
|
|
|
|
float terrain_height_amsl;
|
|
|
|
struct Location location;
|
|
|
|
location.lat = _sitl->state.latitude*1.0e7;
|
|
|
|
location.lng = _sitl->state.longitude*1.0e7;
|
|
|
|
|
2020-07-20 22:56:10 -03:00
|
|
|
AP_Terrain *_terrain = AP_Terrain::get_singleton();
|
|
|
|
if (_terrain != nullptr &&
|
|
|
|
_terrain->height_amsl(location, terrain_height_amsl, false)) {
|
2016-11-19 02:21:54 -04:00
|
|
|
_sitl->height_agl = _sitl->state.altitude - terrain_height_amsl;
|
|
|
|
return;
|
2015-01-03 06:47:54 -04:00
|
|
|
}
|
|
|
|
}
|
2016-06-03 15:07:36 -03:00
|
|
|
#endif
|
2015-01-03 06:47:54 -04:00
|
|
|
|
2018-03-31 02:11:31 -03:00
|
|
|
if (_sitl != nullptr) {
|
|
|
|
// fall back to flat earth model
|
|
|
|
_sitl->height_agl = _sitl->state.altitude - home_alt;
|
|
|
|
}
|
2015-01-03 06:47:54 -04:00
|
|
|
}
|
|
|
|
|
2012-12-14 21:54:26 -04:00
|
|
|
#endif
|