Files
PX4-Autopilot/src/modules/simulation/simulator_sih/sih.hpp
2026-07-17 10:51:42 -05:00

359 lines
17 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/****************************************************************************
*
* Copyright (c) 2019-2026 PX4 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.
*
****************************************************************************/
/**
* @file sih.hpp
* Simulator in Hardware
*
* @author Romain Chiappinelli <romain.chiap@gmail.com>
*
* Coriolis g Corporation - January 2019
*/
/** The sensor signals reconstruction and noise levels are from [1]. The aerodynamic model is from [2].
* The quaternion integration are from [3]. The tailsitter model is from [4]. The propeller models are from [5]
* [1] Bulka E, and Nahon M, "Autonomous fixed-wing aerobatics: from theory to flight."
* In 2018 IEEE International Conference on Robotics and Automation (ICRA), pp. 6573-6580. IEEE, 2018.
* [2] Khan W, supervised by Nahon M, "Dynamics modeling of agile fixed-wing unmanned aerial vehicles."
* McGill University (Canada), PhD thesis, 2016.
* [3] Sveier A, Sjøberg AM, Egeland O. "Applied RungeKuttaMunthe-Kaas Integration for the Quaternion Kinematics."
* Journal of Guidance, Control, and Dynamics. 2019 Dec;42(12):2747-54.
* [4] Chiappinelli R, supervised by Nahon M, "Modeling and control of a flying wing tailsitter unmanned aerial vehicle."
* McGill University (Canada), Masters Thesis, 2018.
* [5] J.B. Brandt, R.W. Deters, G.K. Ananda, O.D. Dantsker, and M.S. Selig 2026, UIUC Propeller Database,
* Vols 1-4, University of Illinois at Urbana-Champaign, Department of Aerospace Engineering, retrieved from https://m-selig.ae.illinois.edu/props/propDB.html.
*/
#pragma once
#include <px4_platform_common/module.h>
#include <px4_platform_common/module_params.h>
#include <px4_platform_common/posix.h>
#include <matrix/matrix/math.hpp> // matrix, vectors, dcm, quaterions
#include <conversion/rotation.h> // math::radians,
#include <lib/atmosphere/atmosphere.h> // to get the physical constants
#include <drivers/drv_hrt.h> // to get the real time
#include <lib/drivers/accelerometer/PX4Accelerometer.hpp>
#include <lib/drivers/gyroscope/PX4Gyroscope.hpp>
#include <lib/drivers/rangefinder/PX4Rangefinder.hpp>
#include <lib/geo/geo.h>
#include <lib/lat_lon_alt/lat_lon_alt.hpp>
#include <lib/perf/perf_counter.h>
#include <uORB/Publication.hpp>
#include <uORB/Subscription.hpp>
#include <uORB/SubscriptionInterval.hpp>
#include <uORB/topics/airspeed.h>
#include <uORB/topics/actuator_outputs.h>
#include <lib/failure_injection/FailureInjection.hpp>
#include <uORB/topics/distance_sensor.h>
#include <uORB/topics/failure_injection.h>
#include <uORB/topics/esc_status.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/vehicle_angular_velocity.h>
#include <uORB/topics/vehicle_attitude.h>
#include <uORB/topics/vehicle_global_position.h>
#include <uORB/topics/vehicle_local_position.h>
#include <uORB/topics/ranging_beacon.h>
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
#include <sys/time.h>
#endif
using namespace time_literals;
class Sih : public ModuleBase, public ModuleParams
{
public:
static Descriptor desc;
Sih();
virtual ~Sih();
/** @see ModuleBase */
static int task_spawn(int argc, char *argv[]);
/** @see ModuleBase */
static int run_trampoline(int argc, char *argv[]);
/** @see ModuleBase */
static Sih *instantiate(int argc, char *argv[]);
/** @see ModuleBase */
static int custom_command(int argc, char *argv[]);
/** @see ModuleBase::print_status() */
int print_status() override;
/** @see ModuleBase */
static int print_usage(const char *reason = nullptr);
/** @see ModuleBase::run() */
void run() override;
static float generate_wgn(); // generate white Gaussian noise sample
// generate white Gaussian noise sample as a 3D vector with specified std
static matrix::Vector3f noiseGauss3f(float stdx, float stdy, float stdz);
private:
void parameters_updated();
void updateFailureConfig();
// simulated sensors
PX4Accelerometer _px4_accel{1310988}; // 1310988: DRV_IMU_DEVTYPE_SIM, BUS: 1, ADDR: 1, TYPE: SIMULATION
PX4Gyroscope _px4_gyro{1310988}; // 1310988: DRV_IMU_DEVTYPE_SIM, BUS: 1, ADDR: 1, TYPE: SIMULATION
PX4Rangefinder _px4_rangefinder{10092548}; // 10092548: DRV_DIST_DEVTYPE_SIM, BUS: 0, ADDR: 0, TYPE: SIMULATION
uORB::Publication<airspeed_s> _airspeed_pub{ORB_ID(airspeed)};
uORB::Publication<ranging_beacon_s> _ranging_beacon_pub{ORB_ID(ranging_beacon)};
uORB::Publication<esc_status_s> _esc_status_pub{ORB_ID(esc_status)};
// groundtruth
uORB::Publication<vehicle_angular_velocity_s> _angular_velocity_ground_truth_pub{ORB_ID(vehicle_angular_velocity_groundtruth)};
uORB::Publication<vehicle_attitude_s> _attitude_ground_truth_pub{ORB_ID(vehicle_attitude_groundtruth)};
uORB::Publication<vehicle_local_position_s> _local_position_ground_truth_pub{ORB_ID(vehicle_local_position_groundtruth)};
uORB::Publication<vehicle_global_position_s> _global_position_ground_truth_pub{ORB_ID(vehicle_global_position_groundtruth)};
uORB::SubscriptionInterval _parameter_update_sub{ORB_ID(parameter_update), 1_s};
uORB::Subscription _actuator_out_sub{ORB_ID(actuator_outputs_sim)};
failure_injection::Config _failure_config;
bool _airspeed_blocked{false};
bool _distance_sensor_blocked{false};
bool _accel_blocked{false};
bool _gyro_blocked{false};
// hard constants
static constexpr uint16_t NUM_ACTUATORS_MAX = 9;
static constexpr uint16_t NUM_DYN_THRUSTER = 2; // number of dynamic thruster model with advance ratio
// Ranging beacon simulation constants
static constexpr uint8_t NUM_RANGING_BEACONS = 4;
bool _beacons_configured{false};
struct RangingBeaconConfig {
double lat_deg;
double lon_deg;
float alt_m;
};
struct RangingBeaconOffset {
float north_m;
float east_m;
float alt_offset_m;
};
// NED offsets from SIH_LOC_LAT0/LON0/H0, resolved once in init_variables()
static constexpr RangingBeaconOffset RANGING_BEACON_OFFSETS[NUM_RANGING_BEACONS] = {
{ 5000.f, 0.f, 30.f}, // ~5 km North
{ 0.f, 10000.f, 0.f}, // ~10 km East
{-20000.f, -15000.f, 110.f}, // ~20 km South-West
{ 35000.f, 45000.f, 310.f} // ~50 km North-East
};
RangingBeaconConfig _ranging_beacons[NUM_RANGING_BEACONS] {};
static constexpr float T1_C = 15.0f; // ground temperature in Celsius
static constexpr float T1_K = T1_C - atmosphere::kAbsoluteNullCelsius; // ground temperature in Kelvin
static constexpr float TEMP_GRADIENT = -6.5f / 1000.0f; // temperature gradient in degrees per metre
// Aerodynamic coefficients
static constexpr float RHO = 1.225f; // air density at sea level [kg/m^3]
static constexpr float SPAN = 0.86f; // wing span [m]
static constexpr float MAC = 0.21f; // wing mean aerodynamic chord [m]
static constexpr float RP = 0.1f; // radius of the propeller [m]
static constexpr float FLAP_MAX = M_PI_F / 12.0f; // 15 deg, maximum control surface deflection
// read the motor signals outputted from the mixer
void read_motors(const float dt);
void publish_esc_status();
uint8_t num_motors() const;
// generate the motors thrust and torque in the body frame
void generate_force_and_torques(const float dt);
// apply the equations of motion of a rigid body and integrate one step
void equations_of_motion(const float dt);
// reconstruct the noisy sensor signals
void reconstruct_sensors_signals(const hrt_abstime &time_now_us);
void send_airspeed(const hrt_abstime &time_now_us);
void send_dist_snsr(const hrt_abstime &time_now_us);
void send_ranging_beacon(const hrt_abstime &time_now_us);
void publish_ground_truth(const hrt_abstime &time_now_us);
void generate_fw_aerodynamics(const float roll_cmd, const float pitch_cmd, const float yaw_cmd, const float thrust_for_prowash);
void generate_ts_aerodynamics();
void generate_rover_ackermann_dynamics(const float throttle_cmd, const float steering_cmd, const float dt);
void sensor_step();
void ecefToNed();
#if defined(ENABLE_LOCKSTEP_SCHEDULER)
void lockstep_loop();
uint64_t _current_simulation_time_us{0};
float _achieved_speedup{0.f};
#endif
void realtime_loop();
px4_sem_t _data_semaphore;
hrt_call _timer_call{};
perf_counter_t _loop_perf{perf_alloc(PC_ELAPSED, MODULE_NAME": cycle")};
perf_counter_t _loop_interval_perf{perf_alloc(PC_INTERVAL, MODULE_NAME": cycle interval")};
hrt_abstime _last_run{0};
hrt_abstime _last_actuator_output_time{0};
hrt_abstime _airspeed_time{0};
hrt_abstime _dist_snsr_time{0};
hrt_abstime _ranging_beacon_time{0};
uint8_t _ranging_beacon_idx{0};
bool _grounded{true}; // whether the vehicle is on the ground
// Quantities in body frame (FRD)
matrix::Vector3f _T_B{}; // thrust force [N]
matrix::Vector3f _Mt_B{}; // thruster moments [Nm]
matrix::Vector3f _Ma_B{}; // aerodynamic moments [Nm]
matrix::Vector3f _w_B{}; // body rates in body frame [rad/s]
matrix::Vector3f _v_B{}; // body frame velocity [m/s]
// Quantities in local navigation frame (NED, body-fixed)
matrix::Vector3f _v_N{}; // velocity [m/s]
matrix::Vector3f _v_N_dot{}; // time derivative of velocity [m/s^2]
matrix::Vector3f _v_wind_N{}; // wind velocity [m/s]
matrix::Vector3f _v_apparent_N{}; // vehicle velocity relative to the air [m/s]
// Quantities in Earth-centered-Earth-fixed coordinates
matrix::Vector3f _Fa_E{}; // aerodynamic force [N]
matrix::Vector3d _p_E{}; // position [m]
matrix::Vector3f _v_E{}; // velocity [m/s]
matrix::Vector3f _v_E_dot{}; // time derivative of velocity [m/s^2]
matrix::Vector3f _specific_force_E{}; // acceleration except gravity (for IMU) [m/s^2]
// Frame conversion
matrix::Quatf _q_E{}; // Attitude quaternion (rotation from body to ECEF frame)
matrix::Quatf _q{}; // Attitude quaternion (rotation from body to local navigation frame)
matrix::Dcmf _R_N2E; // Rotation matrix from local navigation to ECEF frame
LatLonAlt _lla{};
matrix::Vector3f _lpos{}; // position in a local tangent-plane frame [m]
float _u[NUM_ACTUATORS_MAX] {}; // thruster signals
float _T[NUM_DYN_THRUSTER] {}; // thruster forces (N)
float _Q[NUM_DYN_THRUSTER] {}; // thruster torque (Nm)
Thruster _thruster[NUM_DYN_THRUSTER] {}; // thruster objects
enum class VehicleType {Quadcopter, FixedWing, TailsitterVTOL, StandardVTOL, Hexacopter, RoverAckermann, First = Quadcopter, Last = RoverAckermann}; // numbering dependent on parameter SIH_VEHICLE_TYPE
VehicleType _vehicle = VehicleType::Quadcopter;
// aerodynamic segments for the fixedwing
AeroSeg _wing_l = AeroSeg(SPAN / 2.0f, MAC, -4.0f, matrix::Vector3f(0.0f, -SPAN / 4.0f, 0.0f), 3.0f,
SPAN / MAC, MAC / 3.0f);
AeroSeg _wing_r = AeroSeg(SPAN / 2.0f, MAC, -4.0f, matrix::Vector3f(0.0f, SPAN / 4.0f, 0.0f), -3.0f,
SPAN / MAC, MAC / 3.0f);
AeroSeg _tailplane = AeroSeg(0.3f, 0.1f, 0.0f, matrix::Vector3f(-0.4f, 0.0f, 0.0f), 0.0f, -1.0f, 0.05f, RP);
AeroSeg _fin = AeroSeg(0.25, 0.18, 0.0f, matrix::Vector3f(-0.45f, 0.0f, -0.1f), -90.0f, -1.0f, 0.12f, RP);
AeroSeg _fuselage = AeroSeg(0.2, 0.8, 0.0f, matrix::Vector3f(0.0f, 0.0f, 0.0f), -90.0f);
// aerodynamic segments for the tailsitter
static constexpr const int NB_TS_SEG = 11;
static constexpr const float TS_AR = 3.13f;
static constexpr const float TS_CM = 0.115f; // longitudinal position of the CM from trailing edge
static constexpr const float TS_RP = 0.0625f; // propeller radius [m]
static constexpr const float TS_DEF_MAX = math::radians(39.0f); // max deflection
matrix::Dcmf _R_S2B = matrix::Dcmf(matrix::Eulerf(0.0f, math::radians(90.0f), 0.0f)); // segment to body 90 deg pitch
AeroSeg _ts[NB_TS_SEG] = {
AeroSeg(0.0225f, 0.110f, 0.0f, matrix::Vector3f(0.083f - TS_CM, -0.239f, 0.0f), 0.0f, TS_AR),
AeroSeg(0.0383f, 0.125f, 0.0f, matrix::Vector3f(0.094f - TS_CM, -0.208f, 0.0f), 0.0f, TS_AR, 0.063f),
// AeroSeg(0.0884f, 0.148f, 0.0f, matrix::Vector3f(0.111f-TS_CM, -0.143f, 0.0f), 0.0f, TS_AR, 0.063f, TS_RP),
AeroSeg(0.0884f, 0.085f, 0.0f, matrix::Vector3f(0.158f - TS_CM, -0.143f, 0.0f), 0.0f, TS_AR),
AeroSeg(0.0884f, 0.063f, 0.0f, matrix::Vector3f(0.047f - TS_CM, -0.143f, 0.0f), 0.0f, TS_AR, 0.063f, TS_RP),
AeroSeg(0.0633f, 0.176f, 0.0f, matrix::Vector3f(0.132f - TS_CM, -0.068f, 0.0f), 0.0f, TS_AR, 0.063f),
AeroSeg(0.0750f, 0.231f, 0.0f, matrix::Vector3f(0.173f - TS_CM, 0.000f, 0.0f), 0.0f, TS_AR),
AeroSeg(0.0633f, 0.176f, 0.0f, matrix::Vector3f(0.132f - TS_CM, 0.068f, 0.0f), 0.0f, TS_AR, 0.063f),
// AeroSeg(0.0884f, 0.148f, 0.0f, matrix::Vector3f(0.111f-TS_CM, 0.143f, 0.0f), 0.0f, TS_AR, 0.063f, TS_RP),
AeroSeg(0.0884f, 0.085f, 0.0f, matrix::Vector3f(0.158f - TS_CM, 0.143f, 0.0f), 0.0f, TS_AR),
AeroSeg(0.0884f, 0.063f, 0.0f, matrix::Vector3f(0.047f - TS_CM, 0.143f, 0.0f), 0.0f, TS_AR, 0.063f, TS_RP),
AeroSeg(0.0383f, 0.125f, 0.0f, matrix::Vector3f(0.094f - TS_CM, 0.208f, 0.0f), 0.0f, TS_AR, 0.063f),
AeroSeg(0.0225f, 0.110f, 0.0f, matrix::Vector3f(0.083f - TS_CM, 0.239f, 0.0f), 0.0f, TS_AR)
};
// parameters
MapProjection _lpos_ref{};
float _lpos_ref_alt;
float _MASS, _T_MAX, _Q_MAX, _L_ROLL, _L_PITCH, _KDV, _KDW, _T_TAU, _F_T_MAX, _F_Q_MAX;
matrix::Matrix3f _I; // vehicle inertia matrix
matrix::Matrix3f _Im1; // inverse of the inertia matrix
float _distance_snsr_min, _distance_snsr_max, _distance_snsr_override;
esc_status_s _esc_status{};
// parameters defined in sih_params.c
DEFINE_PARAMETERS(
(ParamInt<px4::params::IMU_GYRO_RATEMAX>) _imu_gyro_ratemax,
(ParamInt<px4::params::IMU_INTEG_RATE>) _imu_integration_rate,
(ParamFloat<px4::params::SIH_MASS>) _sih_mass,
(ParamFloat<px4::params::SIH_IXX>) _sih_ixx,
(ParamFloat<px4::params::SIH_IYY>) _sih_iyy,
(ParamFloat<px4::params::SIH_IZZ>) _sih_izz,
(ParamFloat<px4::params::SIH_IXY>) _sih_ixy,
(ParamFloat<px4::params::SIH_IXZ>) _sih_ixz,
(ParamFloat<px4::params::SIH_IYZ>) _sih_iyz,
(ParamFloat<px4::params::SIH_T_MAX>) _sih_t_max,
(ParamFloat<px4::params::SIH_Q_MAX>) _sih_q_max,
(ParamFloat<px4::params::SIH_L_ROLL>) _sih_l_roll,
(ParamFloat<px4::params::SIH_L_PITCH>) _sih_l_pitch,
(ParamFloat<px4::params::SIH_KDV>) _sih_kdv,
(ParamFloat<px4::params::SIH_KDW>) _sih_kdw,
(ParamFloat<px4::params::SIH_LOC_LAT0>) _sih_lat0,
(ParamFloat<px4::params::SIH_LOC_LON0>) _sih_lon0,
(ParamFloat<px4::params::SIH_LOC_H0>) _sih_h0,
(ParamFloat<px4::params::SIH_DISTSNSR_MIN>) _sih_distance_snsr_min,
(ParamFloat<px4::params::SIH_DISTSNSR_MAX>) _sih_distance_snsr_max,
(ParamFloat<px4::params::SIH_DISTSNSR_OVR>) _sih_distance_snsr_override,
(ParamFloat<px4::params::SIH_T_TAU>) _sih_thrust_tau,
// forward propeller
(ParamFloat<px4::params::SIH_F_T_MAX>) _sih_f_thrust_max,
(ParamFloat<px4::params::SIH_F_Q_MAX>) _sih_f_torque_max,
(ParamFloat<px4::params::SIH_F_CT0>) _sih_f_ct0,
(ParamFloat<px4::params::SIH_F_CT1>) _sih_f_ct1,
(ParamFloat<px4::params::SIH_F_CT2>) _sih_f_ct2,
(ParamFloat<px4::params::SIH_F_CP0>) _sih_f_cp0,
(ParamFloat<px4::params::SIH_F_CP1>) _sih_f_cp1,
(ParamFloat<px4::params::SIH_F_CP2>) _sih_f_cp2,
(ParamFloat<px4::params::SIH_F_DIA_INCH>) _sih_forward_diameter_inch,
(ParamFloat<px4::params::SIH_F_RPM_MAX>) _sih_forward_rpm_max,
(ParamInt<px4::params::BAT1_SOURCE>) _bat1_source,
(ParamInt<px4::params::SIH_VEHICLE_TYPE>) _sih_vtype,
(ParamFloat<px4::params::SIH_WIND_N>) _sih_wind_n,
(ParamFloat<px4::params::SIH_WIND_E>) _sih_wind_e,
(ParamFloat<px4::params::SIH_RNGBC_NOISE>) _sih_ranging_beacon_noise
)
};