Skip to content

Commit 718e5b5

Browse files
authored
sih: add fixed-wing support
1 parent 6060ec8 commit 718e5b5

File tree

9 files changed

+699
-28
lines changed

9 files changed

+699
-28
lines changed

ROMFS/px4fmu_common/init.d/airframes/1100_rc_quad_x_sih.hil

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,5 @@ param set-default CBRK_SUPPLY_CHK 894281
2626
# - without safety switch
2727
param set-default COM_PREARM_MODE 0
2828
param set-default CBRK_IO_SAFETY 22027
29+
30+
param set SIH_VEHICLE_TYPE 0
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#!/bin/sh
2+
#
3+
# @name SIH plane AERT
4+
#
5+
# @type Simulation
6+
# @class Plane
7+
#
8+
# @maintainer Romain Chiappinelli <[email protected]>
9+
#
10+
# @board px4_fmu-v2 exclude
11+
#
12+
13+
. ${R}etc/init.d/rc.fw_defaults
14+
15+
set MIXER AERT
16+
set PWM_OUT 1234
17+
18+
# set SYS_HITL to 2 to start the SIH and avoid sensors startup
19+
param set-default SYS_HITL 2
20+
21+
# disable some checks to allow to fly:
22+
# - with usb
23+
param set-default CBRK_USB_CHK 197848
24+
# - without real battery
25+
param set-default CBRK_SUPPLY_CHK 894281
26+
# - without safety switch
27+
param set-default COM_PREARM_MODE 0
28+
param set-default CBRK_IO_SAFETY 22027
29+
30+
param set-default BAT_N_CELLS 3
31+
32+
param set SIH_T_MAX 6.0
33+
param set SIH_MASS 0.3
34+
param set SIH_IXX 0.00402
35+
param set SIH_IYY 0.0144
36+
param set SIH_IZZ 0.0177
37+
param set SIH_IXZ 0.00046
38+
param set SIH_KDV 0.2
39+
40+
param set SIH_VEHICLE_TYPE 1 # sih as fixed wing

ROMFS/px4fmu_common/init.d/airframes/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ px4_add_romfs_files(
3939
1001_rc_quad_x.hil
4040
1002_standard_vtol.hil
4141
1100_rc_quad_x_sih.hil
42+
1101_rc_plane_sih.hil
4243

4344
# [2000, 2999] Standard planes"
4445
2100_standard_plane

Tools/jmavsim_run.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extra_args=
1010
baudrate=921600
1111
device=
1212
ip="127.0.0.1"
13-
while getopts ":b:d:p:qsr:f:i:lo" opt; do
13+
while getopts ":b:d:p:qsr:f:i:loa" opt; do
1414
case $opt in
1515
b)
1616
baudrate=$OPTARG
@@ -39,6 +39,9 @@ while getopts ":b:d:p:qsr:f:i:lo" opt; do
3939
o)
4040
extra_args="$extra_args -disponly"
4141
;;
42+
a)
43+
extra_args="$extra_args -fw" # aircraft
44+
;;
4245
\?)
4346
echo "Invalid option: -$OPTARG" >&2
4447
exit 1

src/modules/sih/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ px4_add_module(
3737
COMPILE_FLAGS
3838
${MAX_CUSTOM_OPT_LEVEL}
3939
SRCS
40+
aero.hpp
4041
sih.cpp
4142
sih.hpp
4243
DEPENDS

src/modules/sih/aero.hpp

Lines changed: 430 additions & 0 deletions
Large diffs are not rendered by default.

src/modules/sih/sih.cpp

Lines changed: 158 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
* Coriolis g Corporation - January 2019
4141
*/
4242

43+
#include "aero.hpp"
4344
#include "sih.hpp"
4445

4546
#include <px4_platform_common/getopt.h>
@@ -67,8 +68,10 @@ Sih::Sih() :
6768
const hrt_abstime task_start = hrt_absolute_time();
6869
_last_run = task_start;
6970
_gps_time = task_start;
71+
_airspeed_time = task_start;
7072
_gt_time = task_start;
7173
_dist_snsr_time = task_start;
74+
_vehicle = (VehicleType)constrain(_sih_vtype.get(), 0, 1);
7275
}
7376

7477
Sih::~Sih()
@@ -149,6 +152,11 @@ void Sih::Run()
149152
send_gps();
150153
}
151154

155+
if (_vehicle == VehicleType::FW && _now - _airspeed_time >= 50_ms) {
156+
_airspeed_time = _now;
157+
send_airspeed();
158+
}
159+
152160
// distance sensor published at 50 Hz
153161
if (_now - _dist_snsr_time >= 20_ms
154162
&& fabs(_distance_snsr_override) < 10000) {
@@ -254,24 +262,53 @@ void Sih::read_motors()
254262
{
255263
actuator_outputs_s actuators_out;
256264

265+
float pwm_middle = 0.5f * (PWM_DEFAULT_MIN + PWM_DEFAULT_MAX);
266+
257267
if (_actuator_out_sub.update(&actuators_out)) {
258268
for (int i = 0; i < NB_MOTORS; i++) { // saturate the motor signals
259-
float u_sp = constrain((actuators_out.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN), 0.0f, 1.0f);
260-
_u[i] = _u[i] + _dt / _T_TAU * (u_sp - _u[i]); // first order transfer function with time constant tau
269+
if (_vehicle == VehicleType::FW && i < 3) { // control surfaces in range [-1,1]
270+
_u[i] = constrain(2.0f * (actuators_out.output[i] - pwm_middle) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN), -1.0f, 1.0f);
271+
272+
} else { // throttle signals in range [0,1]
273+
float u_sp = constrain((actuators_out.output[i] - PWM_DEFAULT_MIN) / (PWM_DEFAULT_MAX - PWM_DEFAULT_MIN), 0.0f, 1.0f);
274+
_u[i] = _u[i] + _dt / _T_TAU * (u_sp - _u[i]); // first order transfer function with time constant tau
275+
}
261276
}
262277
}
263278
}
264279

265280
// generate the motors thrust and torque in the body frame
266281
void Sih::generate_force_and_torques()
267282
{
268-
_T_B = Vector3f(0.0f, 0.0f, -_T_MAX * (+_u[0] + _u[1] + _u[2] + _u[3]));
269-
_Mt_B = Vector3f(_L_ROLL * _T_MAX * (-_u[0] + _u[1] + _u[2] - _u[3]),
270-
_L_PITCH * _T_MAX * (+_u[0] - _u[1] + _u[2] - _u[3]),
271-
_Q_MAX * (+_u[0] + _u[1] - _u[2] - _u[3]));
283+
if (_vehicle == VehicleType::MC) {
284+
_T_B = Vector3f(0.0f, 0.0f, -_T_MAX * (+_u[0] + _u[1] + _u[2] + _u[3]));
285+
_Mt_B = Vector3f(_L_ROLL * _T_MAX * (-_u[0] + _u[1] + _u[2] - _u[3]),
286+
_L_PITCH * _T_MAX * (+_u[0] - _u[1] + _u[2] - _u[3]),
287+
_Q_MAX * (+_u[0] + _u[1] - _u[2] - _u[3]));
288+
_Fa_I = -_KDV * _v_I; // first order drag to slow down the aircraft
289+
_Ma_B = -_KDW * _w_B; // first order angular damper
290+
291+
} else if (_vehicle == VehicleType::FW) {
292+
_T_B = Vector3f(_T_MAX * _u[3], 0.0f, 0.0f); // forward thruster
293+
// _Mt_B = Vector3f(_Q_MAX*_u[3], 0.0f,0.0f); // thruster torque
294+
_Mt_B = Vector3f();
295+
generate_aerodynamics();
296+
}
297+
298+
}
272299

273-
_Fa_I = -_KDV * _v_I; // first order drag to slow down the aircraft
274-
_Ma_B = -_KDW * _w_B; // first order angular damper
300+
void Sih::generate_aerodynamics()
301+
{
302+
_v_B = _C_IB.transpose() * _v_I; // velocity in body frame [m/s]
303+
float altitude = _H0 - _p_I(2);
304+
_wing_l.update_aero(_v_B, _w_B, altitude, _u[0]*FLAP_MAX);
305+
_wing_r.update_aero(_v_B, _w_B, altitude, -_u[0]*FLAP_MAX);
306+
_tailplane.update_aero(_v_B, _w_B, altitude, _u[1]*FLAP_MAX, _T_MAX * _u[3]);
307+
_fin.update_aero(_v_B, _w_B, altitude, _u[2]*FLAP_MAX, _T_MAX * _u[3]);
308+
_Fa_I = _C_IB * (_wing_l.get_Fa() + _wing_r.get_Fa() + _tailplane.get_Fa() + _fin.get_Fa()) - _KDV *
309+
_v_I; // sum of aerodynamic forces
310+
// _Ma_B = wing_l.Ma + wing_r.Ma + tailplane.Ma + fin.Ma + flap_moments() -_KDW * _w_B; // aerodynamic moments
311+
_Ma_B = _wing_l.get_Ma() + _wing_r.get_Ma() + _tailplane.get_Ma() + _fin.get_Ma() - _KDW * _w_B; // aerodynamic moments
275312
}
276313

277314
// apply the equations of motion of a rigid body and integrate one step
@@ -282,40 +319,79 @@ void Sih::equations_of_motion()
282319
// Equations of motion of a rigid body
283320
_p_I_dot = _v_I; // position differential
284321
_v_I_dot = (_W_I + _Fa_I + _C_IB * _T_B) / _MASS; // conservation of linear momentum
285-
_q_dot = _q.derivative1(_w_B); // attitude differential
322+
// _q_dot = _q.derivative1(_w_B); // attitude differential
323+
_dq = expq(0.5f * _dt * _w_B);
286324
_w_B_dot = _Im1 * (_Mt_B + _Ma_B - _w_B.cross(_I * _w_B)); // conservation of angular momentum
287325

288326
// fake ground, avoid free fall
289327
if (_p_I(2) > 0.0f && (_v_I_dot(2) > 0.0f || _v_I(2) > 0.0f)) {
290-
if (!_grounded) { // if we just hit the floor
291-
// for the accelerometer, compute the acceleration that will stop the vehicle in one time step
292-
_v_I_dot = -_v_I / _dt;
293-
294-
} else {
295-
_v_I_dot.setZero();
328+
if (_vehicle == VehicleType::MC) {
329+
if (!_grounded) { // if we just hit the floor
330+
// for the accelerometer, compute the acceleration that will stop the vehicle in one time step
331+
_v_I_dot = -_v_I / _dt;
332+
333+
} else {
334+
_v_I_dot.setZero();
335+
}
336+
337+
_v_I.setZero();
338+
_w_B.setZero();
339+
_grounded = true;
340+
341+
} else if (_vehicle == VehicleType::FW) {
342+
if (!_grounded) { // if we just hit the floor
343+
// for the accelerometer, compute the acceleration that will stop the vehicle in one time step
344+
_v_I_dot(2) = -_v_I(2) / _dt;
345+
346+
} else {
347+
// we only allow negative acceleration in order to takeoff
348+
_v_I_dot(2) = fminf(_v_I_dot(2), 0.0f);
349+
}
350+
351+
// integration: Euler forward
352+
_p_I = _p_I + _p_I_dot * _dt;
353+
_v_I = _v_I + _v_I_dot * _dt;
354+
Eulerf RPY = Eulerf(_q);
355+
RPY(0) = 0.0f; // no roll
356+
RPY(1) = radians(0.0f); // pitch slightly up to get some lift
357+
_q = Quatf(RPY);
358+
_w_B.setZero();
359+
_grounded = true;
296360
}
297361

298-
_v_I.setZero();
299-
_w_B.setZero();
300-
_grounded = true;
301-
302362
} else {
303363
// integration: Euler forward
304364
_p_I = _p_I + _p_I_dot * _dt;
305365
_v_I = _v_I + _v_I_dot * _dt;
306-
_q = _q + _q_dot * _dt; // as given in attitude_estimator_q_main.cpp
366+
_q = _q * _dq; // as given in attitude_estimator_q_main.cpp
307367
_q.normalize();
308-
_w_B = _w_B + _w_B_dot * _dt;
368+
// integration Runge-Kutta 4
369+
// rk4_update(_p_I, _v_I, _q, _w_B);
370+
_w_B = constrain(_w_B + _w_B_dot * _dt, -6.0f * M_PI_F, 6.0f * M_PI_F);
309371
_grounded = false;
310372
}
311373
}
312374

375+
// Sih::States Sih::eom_f(States x) // equations of motion f: x'=f(x)
376+
// {
377+
// States x_dot{}; // dx/dt
378+
379+
// Dcmf C_IB = matrix::Dcm<float>(x.q); // body to inertial transformation
380+
// // Equations of motion of a rigid body
381+
// x_dot.p_I = x.v_I; // position differential
382+
// x_dot.v_I = (_W_I + _Fa_I + C_IB * _T_B) / _MASS; // conservation of linear momentum
383+
// x_dot.q = x.q.derivative1(x.w_B); // attitude differential
384+
// x_dot.w_B = _Im1 * (_Mt_B + _Ma_B - x.w_B.cross(_I * x.w_B)); // conservation of angular momentum
385+
386+
// return x_dot;
387+
// }
388+
313389
// reconstruct the noisy sensor signals
314390
void Sih::reconstruct_sensors_signals()
315391
{
316-
// The sensor signals reconstruction and noise levels are from
317-
// Bulka, Eitan, and Meyer Nahon. "Autonomous fixed-wing aerobatics: from theory to flight."
318-
// In 2018 IEEE International Conference on Robotics and Automation (ICRA), pp. 6573-6580. IEEE, 2018.
392+
// The sensor signals reconstruction and noise levels are from [1]
393+
// [1] Bulka, Eitan, and Meyer Nahon. "Autonomous fixed-wing aerobatics: from theory to flight."
394+
// In 2018 IEEE International Conference on Robotics and Automation (ICRA), pp. 6573-6580. IEEE, 2018.
319395

320396
// IMU
321397
_acc = _C_IB.transpose() * (_v_I_dot - Vector3f(0.0f, 0.0f, CONSTANTS_ONE_G)) + noiseGauss3f(0.5f, 1.7f, 1.4f);
@@ -376,6 +452,17 @@ void Sih::send_gps()
376452
_sensor_gps_pub.publish(_sensor_gps);
377453
}
378454

455+
void Sih::send_airspeed()
456+
{
457+
airspeed_s airspeed{};
458+
airspeed.timestamp = _now;
459+
airspeed.true_airspeed_m_s = fmaxf(0.1f, _v_B(0) + generate_wgn() * 0.2f);
460+
airspeed.indicated_airspeed_m_s = airspeed.true_airspeed_m_s * sqrtf(_wing_l.get_rho() / RHO);
461+
airspeed.air_temperature_celsius = _baro_temp_c;
462+
airspeed.confidence = 0.7f;
463+
_airspeed_pub.publish(airspeed);
464+
}
465+
379466
void Sih::send_dist_snsr()
380467
{
381468
_distance_snsr.timestamp = _now;
@@ -430,6 +517,22 @@ void Sih::publish_sih()
430517
_gpos_gt_pub.publish(_gpos_gt);
431518
}
432519

520+
// quaternion exponential as defined in [3]
521+
Quatf Sih::expq(const matrix::Vector3f &u)
522+
{
523+
float u_norm = u.norm();
524+
Vector3f v;
525+
526+
if (u_norm < 1.0e-6f) { // error will be smaller than 1e-18
527+
v = (1.0f - u_norm * u_norm / 6.0f) * u; // first taylor serie term of sin(x)/x
528+
529+
} else {
530+
v = sinf(u_norm) / u_norm * u;
531+
}
532+
533+
return Quatf(cosf(u_norm), v(0), v(1), v(2));
534+
}
535+
433536
float Sih::generate_wgn() // generate white Gaussian noise sample with std=1
434537
{
435538
// algorithm 1:
@@ -465,6 +568,37 @@ Vector3f Sih::noiseGauss3f(float stdx, float stdy, float stdz)
465568
return Vector3f(generate_wgn() * stdx, generate_wgn() * stdy, generate_wgn() * stdz);
466569
}
467570

571+
int Sih::print_status()
572+
{
573+
if (_vehicle == VehicleType::MC) {
574+
PX4_INFO("Running MC");
575+
576+
} else {
577+
PX4_INFO("Running FW");
578+
}
579+
580+
PX4_INFO("vehicle landed: %d", _grounded);
581+
PX4_INFO("dt [us]: %d", (int)(_dt * 1e6f));
582+
PX4_INFO("inertial position NED (m)");
583+
_p_I.print();
584+
PX4_INFO("inertial velocity NED (m/s)");
585+
_v_I.print();
586+
PX4_INFO("attitude roll-pitch-yaw (deg)");
587+
(Eulerf(_q) * 180.0f / M_PI_F).print();
588+
PX4_INFO("angular acceleration roll-pitch-yaw (deg/s)");
589+
(_w_B * 180.0f / M_PI_F).print();
590+
PX4_INFO("actuator signals");
591+
Vector<float, 8> u = Vector<float, 8>(_u);
592+
u.transpose().print();
593+
PX4_INFO("Aerodynamic forces NED inertial (N)");
594+
_Fa_I.print();
595+
PX4_INFO("Aerodynamic moments body frame (Nm)");
596+
_Ma_B.print();
597+
PX4_INFO("v_I.z: %f", (double)_v_I(2));
598+
PX4_INFO("v_I_dot.z: %f", (double)_v_I_dot(2));
599+
return 0;
600+
}
601+
468602
int Sih::task_spawn(int argc, char *argv[])
469603
{
470604
Sih *instance = new Sih();

0 commit comments

Comments
 (0)