Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
eff_scheduling_rotwing.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Dennis van Wijngaarden <D.C.vanWijngaarden@tudelft.nl>
3 *
4 * This file is part of paparazzi
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, see
18 * <http://www.gnu.org/licenses/>.
19 */
20
27
28#include "generated/airframe.h"
29#include "state.h"
30
34#include "autopilot.h"
35
37#include "modules/core/abi.h"
39
40#ifndef SERVO_ROTATION_MECH_IDX
41#error ctrl_eff_sched_rotwing requires a servo named ROTATION_MECH_IDX
42#endif
43
44#ifndef ROTWING_EFF_SCHED_IXX_BODY
45#error "NO ROTWING_EFF_SCHED_IXX_BODY defined"
46#endif
47
48#ifndef ROTWING_EFF_SCHED_IYY_BODY
49#error "NO ROTWING_EFF_SCHED_IYY_BODY defined"
50#endif
51
52#ifndef ROTWING_EFF_SCHED_IZZ
53#error "NO ROTWING_EFF_SCHED_IZZ defined"
54#endif
55
56#ifndef ROTWING_EFF_SCHED_IXX_WING
57#error "NO ROTWING_EFF_SCHED_IXX_WING defined"
58#endif
59
60#ifndef ROTWING_EFF_SCHED_IYY_WING
61#error "NO ROTWING_EFF_SCHED_IYY_WING defined"
62#endif
63
64#ifndef ROTWING_EFF_SCHED_M
65#error "NO ROTWING_EFF_SCHED_M defined"
66#endif
67
68#ifndef ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_PITCH
69#error "NO ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_PITCH defined"
70#endif
71
72#ifndef ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_ROLL
73#error "NO ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_ROLL defined"
74#endif
75
76#ifndef ROTWING_EFF_SCHED_HOVER_ROLL_PITCH_COEF
77#error "NO ROTWING_EFF_SCHED_HOVER_ROLL_PITCH_COEF defined"
78#endif
79
80#ifndef ROTWING_EFF_SCHED_HOVER_ROLL_ROLL_COEF
81#error "NO ROTWING_EFF_SCHED_HOVER_ROLL_ROLL_COEF defined"
82#endif
83
84#ifndef ROTWING_EFF_SCHED_K_ELEVATOR
85#error "NO ROTWING_EFF_SCHED_K_ELEVATOR defined"
86#endif
87
88#ifndef ROTWING_EFF_SCHED_K_RUDDER
89#error "NO ROTWING_EFF_SCHED_K_RUDDER defined"
90#endif
91
92#ifndef ROTWING_EFF_SCHED_K_AILERON
93#error "NO ROTWING_EFF_SCHED_K_AILERON defined"
94#endif
95
96#ifndef ROTWING_EFF_SCHED_K_FLAPERON
97#error "NO ROTWING_EFF_SCHED_K_FLAPERON defined"
98#endif
99
100#ifndef ROTWING_EFF_SCHED_K_PUSHER
101#error "NO ROTWING_EFF_SCHED_K_PUSHER defined"
102#endif
103
104#ifndef ROTWING_EFF_SCHED_K_ELEVATOR_DEFLECTION
105#error "NO ROTWING_EFF_SCHED_K_ELEVATOR_DEFLECTION defined"
106#endif
107
108#ifndef ROTWING_EFF_SCHED_D_RUDDER_D_PPRZ
109#error "NO ROTWING_EFF_SCHED_D_RUDDER_D_PPRZ defined"
110#endif
111
112#ifndef ROTWING_EFF_SCHED_K_RPM_PPRZ_PUSHER
113#error "NO ROTWING_EFF_SCHED_K_RPM_PPRZ_PUSHER defined"
114#endif
115
116#ifndef ROTWING_EFF_SCHED_K_LIFT_WING
117#error "NO ROTWING_EFF_SCHED_K_LIFT_WING defined"
118#endif
119
120#ifndef ROTWING_EFF_SCHED_K_LIFT_FUSELAGE
121#error "NO ROTWING_EFF_SCHED_K_LIFT_FUSELAGE defined"
122#endif
123
124#ifndef ROTWING_EFF_SCHED_K_LIFT_TAIL
125#error "NO ROTWING_EFF_SCHED_K_LIFT_TAIL defined"
126#endif
127
130 .Iyy_body = ROTWING_EFF_SCHED_IYY_BODY,
132 .Ixx_wing = ROTWING_EFF_SCHED_IXX_WING,
133 .Iyy_wing = ROTWING_EFF_SCHED_IYY_WING,
135 .DMdpprz_hover_pitch = ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_PITCH,
136 .DMdpprz_hover_roll = ROTWING_EFF_SCHED_DM_DPPRZ_HOVER_ROLL,
137 .hover_roll_pitch_coef = ROTWING_EFF_SCHED_HOVER_ROLL_PITCH_COEF,
138 .hover_roll_roll_coef = ROTWING_EFF_SCHED_HOVER_ROLL_ROLL_COEF,
139 .k_elevator = ROTWING_EFF_SCHED_K_ELEVATOR,
140 .k_rudder = ROTWING_EFF_SCHED_K_RUDDER,
141 .k_aileron = ROTWING_EFF_SCHED_K_AILERON,
142 .k_flaperon = ROTWING_EFF_SCHED_K_FLAPERON,
143 .k_pusher = ROTWING_EFF_SCHED_K_PUSHER,
144 .k_elevator_deflection = ROTWING_EFF_SCHED_K_ELEVATOR_DEFLECTION,
145 .d_rudder_d_pprz = ROTWING_EFF_SCHED_D_RUDDER_D_PPRZ,
146 .k_rpm_pprz_pusher = ROTWING_EFF_SCHED_K_RPM_PPRZ_PUSHER,
147 .k_lift_wing = ROTWING_EFF_SCHED_K_LIFT_WING,
148 .k_lift_fuselage = ROTWING_EFF_SCHED_K_LIFT_FUSELAGE,
149 .k_lift_tail = ROTWING_EFF_SCHED_K_LIFT_TAIL
150};
151
153
154// for negative values, still should be low_lim < up_lim
155inline float bound_or_zero(float value, float low_lim, float up_lim) {
156 float output = value;
157 if (low_lim > 0.f) {
158 if (value < low_lim) {
159 output = 0.f;
160 } else if (value > up_lim) {
161 output = up_lim;
162 }
163 } else {
164 if (value > up_lim) {
165 output = 0.f;
166 } else if (value < low_lim) {
167 output = low_lim;
168 }
169 }
170 return output;
171}
172
174float roll_eff_slider = 12.f;
175
177
179
181inline void eff_scheduling_rotwing_update_MMOI(void);
182inline void eff_scheduling_rotwing_update_cmd(void);
191
192inline float guidance_indi_get_liftd(float pitch UNUSED, float theta UNUSED);
194inline void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, float pitch_angle);
195
196
199#ifndef WING_ROTATION_CAN_ROTWING_ID
200#define WING_ROTATION_CAN_ROTWING_ID ABI_BROADCAST
201#endif
204
206{
207 for (int i=0; i<num_act; i++){
208 if (pos_msg[i].set.position && (pos_msg[i].idx == SERVO_ROTATION_MECH_IDX))
209 {
210 // Get wing rotation angle from sensor
211 eff_sched_var.wing_rotation_rad = 0.5 * M_PI - pos_msg[i].position;
212
213 // Bound wing rotation angle
215 }
216 }
217}
218
220{
221 // Initialize variables to quad values
224 eff_sched_var.wing_rotation_rad = 0; // ABI input
231
232 // Set moment derivative variables
233 float hover_thrust = 6000;
234 eff_sched_var.pitch_motor_dMdpprz = (eff_sched_p.DMdpprz_hover_pitch[0] + 2*hover_thrust * eff_sched_p.DMdpprz_hover_pitch[1]) / 10000.; // Dmdpprz hover pitch for hover thrust
235 eff_sched_var.roll_motor_dMdpprz = (eff_sched_p.DMdpprz_hover_roll[0] + 2*hover_thrust * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.; // Dmdpprz hover roll for hover thrust
236
241
244
245 // Get wing angle
247}
248
267
282
292
294{
295 // These indexes depend on the INDI sequence, not the actuator IDX
298 eff_sched_var.cmd_pusher_scaled = actuator_state_filt_vect[8] * 0.000853229; // Scaled with 8181 / 9600 / 1000
299 eff_sched_var.cmd_T_mean_scaled = (actuator_state_filt_vect[0] + actuator_state_filt_vect[1] + actuator_state_filt_vect[2] + actuator_state_filt_vect[3]) / 4. * 0.000853229; // Scaled with 8181 / 9600 / 1000
300}
301
309
311{
312 float cmd_quat[4];
313 float dM_dpprz[4];
314 // Quadratic thrust (and therefore moment) model of the hover propellers
315 for (uint8_t i = 0; i < 4; i++) {
317 Bound(cmd_quat[i], 2500, MAX_PPRZ);
318
319 if(i==0 || i==2) { // pitch motors
321 // Bound dM_dpprz to half and 2 times the hover effectiveness
323 } else { // roll motors
326 }
327 }
328
329 // Roll motor effectiveness
330 float dM_dpprz_right = dM_dpprz[1];
331 float dM_dpprz_left = dM_dpprz[3];;
332
335
337 if(autopilot.in_flight) {
340 }
342
344 Bound(roll_motor_q_eff, 0, 1);
345
346 // Update front pitch motor q effectiveness
347 g1g2[1][0] = dM_dpprz[0] / eff_sched_var.Iyy; // pitch effectiveness front motor
348
349 // Update back motor q effectiveness
350 g1g2[1][2] = - dM_dpprz[2] / eff_sched_var.Iyy; // pitch effectiveness back motor
351
352#ifdef RADIO_CONTROL_EFF_SWITCH
354 g1g2[0][1] = - roll_eff_slider / 1000.f;
355 } else {
357 }
358#else
359 g1g2[0][1] = roll_motor_p_eff_right; // roll effectiveness right motor (no airspeed compensation)
360#endif
361 // Update right motor p and q effectiveness
362 g1g2[1][1] = roll_motor_q_eff; // pitch effectiveness right motor
363
364 // Update left motor p and q effectiveness
365#ifdef RADIO_CONTROL_EFF_SWITCH
367 g1g2[0][3] = roll_eff_slider / 1000.f;
368 } else {
370 }
371#else
372 g1g2[0][3] = roll_motor_p_eff_left; // roll effectiveness left motor
373#endif
374 g1g2[1][3] = -roll_motor_q_eff; // pitch effectiveness left motor
375}
376
378{
380
384
385 // scale the effectiveness of the elevator down if it has a large deflection to encourage it to become flat quickly (pragmatic, not physically inpsired)
386 float elevator_ineffectiveness_scaling = (50-de)/40;
388
390
391 // Convert moment to effectiveness
393
394 Bound(eff_y_elev, 0.00001, 0.1);
395
396 g1g2[1][5] = eff_y_elev;
397}
398
400{
404
405 // Convert moment to effectiveness
406
408
409 // Convert moment to effectiveness
411
412 Bound(eff_z_rudder, 0.000001, 0.1);
413
414 g1g2[2][4] = eff_z_rudder;
415}
416
429
437
450
452
466
467// Override standard LIFT_D function
468float guidance_indi_get_liftd(float pitch UNUSED, float theta UNUSED) {
470}
471
473{
474 // Calculate the min and max increments
475 for (uint8_t i = 0; i < INDI_NUM_ACT; i++) {
478 wls_stab_p.u_pref[i] = act_pref[i];
479 if (i == 5) { // elevator
480 wls_stab_p.u_pref[i] = actuator_state_filt_vect[i]; // Set change in prefered state to 0 for elevator
481 wls_stab_p.u_min[i] = 0; // cmd 0 is lowest position for elevator
482 }
483 if (i == 7) { // flaperons
484 // If an offset is used, limit the max differential command to prevent unilateral saturation.
489 }
490 if (i==8) { // pusher
491 // dt (min to max) MAX_PPRZ / (dt * f) dt_min == 0.002
492 Bound(eff_sched_pusher_time, 0.002, 5.);
496
499 }
500 }
501}
502
503void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, float pitch_angle)
504{
505 // adjust weights
506 float fixed_wing_percentile = (rotwing_state_hover_motors_idling())? 1:0; // TODO: when hover props go below 40%, ...
508#define AIRSPEED_IMPORTANCE_IN_FORWARD_WEIGHT 16
509
511
512 // Increase importance of forward acceleration in forward flight
513 wls_guid_p.Wv[0] = Wv_original[0] * (1.0f + fixed_wing_percentile *
514 AIRSPEED_IMPORTANCE_IN_FORWARD_WEIGHT); // stall n low hover motor_off (weight 16x more important than vertical weight)
515
516 struct FloatEulers eulers_zxy;
518
522 Bound(du_min_thrust_z, -50., 0.);
525 Bound(du_max_thrust_z, 0., 50.);
526
530
532 float quad_pitch_limit_rad = RadOfDeg(5.0);
533
534 float airspeed = stateGetAirspeed_f();
535
536 float scheduled_pitch_angle = 0.f;
537 float pitch_angle_range = 3.;
539 Bound(meas_skew_angle, 0, 90); // Bound to prevent errors
542 wls_guid_p.Wu[1] = Wu_gih_original[1];
544 } else {
545 float pitch_progression = (airspeed - rotwing_state.fw_min_airspeed) / 2.f;
546 Bound(pitch_progression, 0.f, 1.f);
548 wls_guid_p.Wu[1] = Wu_gih_original[1] * (1.f - pitch_progression*0.99);
550 }
554 }
557
559
560 // Set lower limits
561 wls_guid_p.u_min[0] = -roll_limit_rad - roll_angle; //roll
562 wls_guid_p.u_min[1] = min_pitch_limit_rad - pitch_angle; // pitch
563
564 // Set upper limits limits
565 wls_guid_p.u_max[0] = roll_limit_rad - roll_angle; //roll
566 wls_guid_p.u_max[1] = max_pitch_limit_rad - pitch_angle; // pitch
567
569 wls_guid_p.u_min[2] = du_min_thrust_z;
570 wls_guid_p.u_max[2] = du_max_thrust_z;
571 } else {
572 wls_guid_p.u_min[2] = 0.;
573 wls_guid_p.u_max[2] = 0.;
574 }
575
577 wls_guid_p.u_min[3] = (-actuator_state_filt_vect[8] * g1g2[4][8]);
578 wls_guid_p.u_max[3] = 9.0; // Hacky value to prevent drone from pitching down in transition
579 } else {
580 wls_guid_p.u_min[3] = 0.;
581 wls_guid_p.u_max[3] = 0.;
582 }
583
584 // Set prefered states
585 wls_guid_p.u_pref[0] = 0; // prefered delta roll angle
586 wls_guid_p.u_pref[1] = -pitch_angle + pitch_pref_rad;// prefered delta pitch angle
587 wls_guid_p.u_pref[2] = wls_guid_p.u_max[2]; // Low thrust better for efficiency
588 wls_guid_p.u_pref[3] = body_v[0]; // solve the body acceleration
589}
Main include for ABI (AirBorneInterface).
Event structure to store callbacks in a linked list.
Definition abi_common.h:67
struct pprz_autopilot autopilot
Global autopilot structure.
Definition autopilot.c:49
Core autopilot interface common to all firmwares.
bool in_flight
in flight status
Definition autopilot.h:70
#define UNUSED(x)
void stabilization_indi_set_wls_settings(void)
Function that sets the u_min, u_max and u_pref if function not elsewhere defined.
void eff_scheduling_rotwing_update_flaperon_effectiveness(void)
void eff_scheduling_rotwing_update_rudder_effectiveness(void)
void eff_scheduling_rotwing_update_aileron_effectiveness(void)
float eff_scheduling_rotwing_lift_d
static const float Wu_gih_original[GUIDANCE_INDI_HYBRID_U]
struct rotwing_eff_sched_var_t eff_sched_var
void eff_scheduling_rotwing_update_MMOI(void)
#define WING_ROTATION_CAN_ROTWING_ID
ABI binding wing position data.
void eff_scheduling_rotwing_update_airspeed(void)
float roll_eff_slider
int32_t rw_flap_offset
void eff_scheduling_rotwing_update_cmd(void)
void eff_scheduling_rotwing_schedule_liftd(void)
float guidance_indi_get_liftd(float pitch UNUSED, float theta UNUSED)
#define AIRSPEED_IMPORTANCE_IN_FORWARD_WEIGHT
void eff_scheduling_rotwing_update_wing_angle(void)
struct rotwing_eff_sched_param_t eff_sched_p
void eff_scheduling_rotwing_update_hover_motor_effectiveness(void)
static abi_event wing_position_ev
void eff_scheduling_rotwing_init(void)
void eff_scheduling_rotwing_update_elevator_effectiveness(void)
float eff_sched_pusher_time
float bound_or_zero(float value, float low_lim, float up_lim)
void eff_scheduling_rotwing_update_pusher_effectiveness(void)
void eff_scheduling_rotwing_periodic(void)
static void wing_position_cb(uint8_t sender_id UNUSED, struct act_feedback_t *pos_msg, uint8_t num_act)
void guidance_indi_hybrid_set_wls_settings(float body_v[3], float roll_angle, float pitch_angle)
void float_eulers_of_quat_zxy(struct FloatEulers *e, struct FloatQuat *q)
euler rotation 'ZXY' This rotation order is useful if you need 90 deg pitch
euler angles
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition state.h:1294
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition state.h:1590
float guidance_indi_max_bank
float guidance_indi_pitch_pref_deg
struct FloatEulers eulers_zxy
state eulers in zxy order
A guidance mode based on Incremental Nonlinear Dynamic Inversion Come to ICRA2016 to learn more!
#define GUIDANCE_INDI_MAX_PITCH
#define GUIDANCE_INDI_MIN_PITCH
uint16_t foo
Definition main_demo5.c:58
Hardware independent API for actuators (servos, motor controllers).
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
#define MAX_PPRZ
Definition paparazzi.h:8
struct RadioControl radio_control
Generic interface for radio control modules.
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
bool rotwing_state_pusher_motor_running(void)
bool rotwing_state_hover_motors_running(void)
bool rotwing_state_hover_motors_idling(void)
Check if hover motors are idling (COMMAND_THRUST < ROTWING_QUAD_IDLE_MIN_THRUST) for ROTWING_QUAD_IDL...
struct rotwing_state_t rotwing_state
#define ROTWING_QUAD_PREF_PITCH
float meas_skew_angle_deg
#define ROTWING_SKEW_ANGLE_STEP
float act_pref[INDI_NUM_ACT]
bool act_is_servo[INDI_NUM_ACT]
struct WLS_t wls_stab_p
float g1g2[INDI_OUTPUTS][INDI_NUM_ACT]
float actuator_state_filt_vect[INDI_NUM_ACT]
API to get/set the generic vehicle states.
int int32_t
Typedef defining 32 bit int type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
float u_min[WLS_N_U_MAX]
Definition wls_alloc.h:75
float u_max[WLS_N_U_MAX]
Definition wls_alloc.h:76
float u_pref[WLS_N_U_MAX]
Definition wls_alloc.h:74