Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
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 
32 
33 #include "autopilot.h"
34 
36 #include "modules/core/abi.h"
38 #include "generated/radio.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 
129  .Ixx_body = ROTWING_EFF_SCHED_IXX_BODY,
130  .Iyy_body = ROTWING_EFF_SCHED_IYY_BODY,
131  .Izz = ROTWING_EFF_SCHED_IZZ,
132  .Ixx_wing = ROTWING_EFF_SCHED_IXX_WING,
133  .Iyy_wing = ROTWING_EFF_SCHED_IYY_WING,
134  .m = ROTWING_EFF_SCHED_M,
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
155 inline 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 
173 float eff_sched_pusher_time = 0.002;
174 float roll_eff_slider = 12.f;
175 
177 
179 inline void eff_scheduling_rotwing_update_MMOI(void);
180 inline void eff_scheduling_rotwing_update_cmd(void);
188 inline void eff_scheduling_rotwing_schedule_liftd(void);
189 
190 inline float guidance_indi_get_liftd(float pitch UNUSED, float theta UNUSED);
192 
193 
196 #ifndef WING_ROTATION_CAN_ROTWING_ID
197 #define WING_ROTATION_CAN_ROTWING_ID ABI_BROADCAST
198 #endif
199 PRINT_CONFIG_VAR(WING_ROTATION_CAN_ROTWING_ID)
201 
202 static void wing_position_cb(uint8_t sender_id UNUSED, struct act_feedback_t *pos_msg, uint8_t num_act)
203 {
204  for (int i=0; i<num_act; i++){
205  if (pos_msg[i].set.position && (pos_msg[i].idx == SERVO_ROTATION_MECH_IDX))
206  {
207  // Get wing rotation angle from sensor
208  eff_sched_var.wing_rotation_rad = 0.5 * M_PI - pos_msg[i].position;
209 
210  // Bound wing rotation angle
211  Bound(eff_sched_var.wing_rotation_rad, 0, 0.5 * M_PI);
212  }
213  }
214 }
215 
217 {
218  // Initialize variables to quad values
221  eff_sched_var.wing_rotation_rad = 0; // ABI input
223  eff_sched_var.cosr = 1;
224  eff_sched_var.sinr = 0;
225  eff_sched_var.cosr2 = 1;
226  eff_sched_var.sinr2 = 0;
227  eff_sched_var.sinr3 = 0;
228 
229  // Set moment derivative variables
230  float hover_thrust = 6000;
231  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
232  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
233 
238 
241 
242  // Get wing angle
244 }
245 
247 {
248  // your periodic code here.
249  // freq = 10.0 Hz
254 
255  // Update the effectiveness values
263 }
264 
266 {
267  // Calculate sin and cosines of rotation
269 
272 
275 
277 
278 }
279 
281 {
284 
285  // Bound inertia
286  Bound(eff_sched_var.Ixx, 0.01, 100.);
287  Bound(eff_sched_var.Iyy, 0.01, 100.);
288 }
289 
291 {
292  // These indexes depend on the INDI sequence, not the actuator IDX
295  eff_sched_var.cmd_pusher_scaled = actuator_state_filt_vect[8] * 0.000853229; // Scaled with 8181 / 9600 / 1000
296  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
297 }
298 
300 {
302  Bound(eff_sched_var.airspeed, 0. , 30.);
304  Bound(eff_sched_var.airspeed2, 0. , 900.);
305 }
306 
308 {
309  float cmd_quat[4];
310  float dM_dpprz[4];
311  // Quadratic thrust (and therefore moment) model of the hover propellers
312  for (uint8_t i = 0; i < 4; i++) {
313  cmd_quat[i] = actuator_state_filt_vect[i];
314  Bound(cmd_quat[i], 2500, MAX_PPRZ);
315 
316  if(i==0 || i==2) { // pitch motors
317  dM_dpprz[i] = (eff_sched_p.DMdpprz_hover_pitch[0] + 2*cmd_quat[i] * eff_sched_p.DMdpprz_hover_pitch[1]) / 10000.;
318  // Bound dM_dpprz to half and 2 times the hover effectiveness
319  Bound(dM_dpprz[i], eff_sched_var.pitch_motor_dMdpprz * 0.5, eff_sched_var.pitch_motor_dMdpprz * 2.0);
320  } else { // roll motors
321  dM_dpprz[i] = (eff_sched_p.DMdpprz_hover_roll[0] + 2*cmd_quat[i] * eff_sched_p.DMdpprz_hover_roll[1]) / 10000.;
322  Bound(dM_dpprz[i], eff_sched_var.roll_motor_dMdpprz * 0.5, eff_sched_var.roll_motor_dMdpprz * 2.0);
323  }
324  }
325 
326  // Roll motor effectiveness
327  float dM_dpprz_right = dM_dpprz[1];
328  float dM_dpprz_left = dM_dpprz[3];;
329 
331  roll_motor_p_eff_right = bound_or_zero(roll_motor_p_eff_right, -1.f, -0.00001f);
332 
334  if(autopilot.in_flight) {
335  float roll_motor_airspeed_compensation = eff_sched_p.hover_roll_roll_coef[1] * eff_sched_var.airspeed * eff_sched_var.cosr / eff_sched_var.Ixx;
336  roll_motor_p_eff_left += roll_motor_airspeed_compensation;
337  }
338  roll_motor_p_eff_left = bound_or_zero(roll_motor_p_eff_left, 0.00001f, 1.f);
339 
341  Bound(roll_motor_q_eff, 0, 1);
342 
343  // Update front pitch motor q effectiveness
344  g1g2[1][0] = dM_dpprz[0] / eff_sched_var.Iyy; // pitch effectiveness front motor
345 
346  // Update back motor q effectiveness
347  g1g2[1][2] = - dM_dpprz[2] / eff_sched_var.Iyy; // pitch effectiveness back motor
348 
349 #ifdef RADIO_CONTROL_EFF_SWITCH
350  if (radio_control.values[RADIO_CONTROL_EFF_SWITCH] > 1750) {
351  g1g2[0][1] = - roll_eff_slider / 1000.f;
352  } else {
353  g1g2[0][1] = roll_motor_p_eff_right;
354  }
355 #else
356  g1g2[0][1] = roll_motor_p_eff_right; // roll effectiveness right motor (no airspeed compensation)
357 #endif
358  // Update right motor p and q effectiveness
359  g1g2[1][1] = roll_motor_q_eff; // pitch effectiveness right motor
360 
361  // Update left motor p and q effectiveness
362 #ifdef RADIO_CONTROL_EFF_SWITCH
363  if (radio_control.values[RADIO_CONTROL_EFF_SWITCH] > 1750) {
364  g1g2[0][3] = roll_eff_slider / 1000.f;
365  } else {
366  g1g2[0][3] = roll_motor_p_eff_left;
367  }
368 #else
369  g1g2[0][3] = roll_motor_p_eff_left; // roll effectiveness left motor
370 #endif
371  g1g2[1][3] = -roll_motor_q_eff; // pitch effectiveness left motor
372 }
373 
375 {
377 
378  float dMyde = (eff_sched_p.k_elevator[0] * de * eff_sched_var.airspeed2 +
381 
382  // scale the effectiveness of the elevator down if it has a large deflection to encourage it to become flat quickly (pragmatic, not physically inpsired)
383  float elevator_ineffectiveness_scaling = (50-de)/40;
384  Bound(elevator_ineffectiveness_scaling, 0.5, 1.0);
385 
386  float dMydpprz = dMyde * eff_sched_p.k_elevator_deflection[1];
387 
388  // Convert moment to effectiveness
389  float eff_y_elev = dMydpprz / eff_sched_var.Iyy;
390 
391  Bound(eff_y_elev, 0.00001, 0.1);
392 
393  g1g2[1][5] = eff_y_elev;
394 }
395 
397 {
401 
402  // Convert moment to effectiveness
403 
404  float dMzdpprz = dMzdr * eff_sched_p.d_rudder_d_pprz;
405 
406  // Convert moment to effectiveness
407  float eff_z_rudder = dMzdpprz / eff_sched_p.Izz;
408 
409  Bound(eff_z_rudder, 0.000001, 0.1);
410 
411  g1g2[2][4] = eff_z_rudder;
412 }
413 
415 {
416  float dMxdpprz = (eff_sched_p.k_aileron * eff_sched_var.airspeed2 * eff_sched_var.sinr3) / 1000000.;
417  float eff_x_aileron = dMxdpprz / eff_sched_var.Ixx;
418  Bound(eff_x_aileron, 0, 0.005)
419  g1g2[0][6] = eff_x_aileron;
420 
421  float dMydpprz = 4.0*(eff_sched_p.k_aileron * eff_sched_var.airspeed2 * eff_sched_var.sinr2 * eff_sched_var.cosr) / 1000000.;
422  float eff_y_aileron = dMydpprz / eff_sched_var.Iyy;
423  eff_y_aileron = bound_or_zero(eff_y_aileron, 0.00003f, 0.005f);
424  g1g2[1][6] = eff_y_aileron;
425 }
426 
428 {
429  float dMxdpprz = (eff_sched_p.k_flaperon * eff_sched_var.airspeed2 * eff_sched_var.sinr3) / 1000000.;
430  float eff_x_flap_aileron = dMxdpprz / eff_sched_var.Ixx;
431  Bound(eff_x_flap_aileron, 0, 0.005)
432  g1g2[0][7] = eff_x_flap_aileron;
433 }
434 
436 {
438 
439  float dFxdrpmP = eff_sched_p.k_pusher[0]*rpmP + eff_sched_p.k_pusher[1] * eff_sched_var.airspeed;
441 
442  float eff_pusher = (dFxdrpmP * drpmPdpprz / eff_sched_p.m) / 10000.;
443 
444  Bound(eff_pusher, 0.00030, 0.0015);
445  g1g2[4][8] = eff_pusher;
446 }
447 
449 
451 {
453  float lift_d_fuselage = eff_sched_p.k_lift_fuselage * eff_sched_var.airspeed2 / eff_sched_p.m;
455 
456  float lift_d = lift_d_wing + lift_d_fuselage + lift_d_tail;
458  lift_d = 0.0;
459  }
460  Bound(lift_d, -130., 0.);
462 }
463 
464 // Override standard LIFT_D function
465 float guidance_indi_get_liftd(float pitch UNUSED, float theta UNUSED) {
467 }
468 
470 {
471  // Calculate the min and max increments
472  for (uint8_t i = 0; i < INDI_NUM_ACT; i++) {
475  wls_stab_p.u_pref[i] = act_pref[i];
476  if (i == 5) { // elevator
477  wls_stab_p.u_pref[i] = actuator_state_filt_vect[i]; // Set change in prefered state to 0 for elevator
478  wls_stab_p.u_min[i] = 0; // cmd 0 is lowest position for elevator
479  }
480  if (i == 7) { // flaperons
481  // If an offset is used, limit the max differential command to prevent unilateral saturation.
482  int32_t flap_saturation_limit = MAX_PPRZ - abs(rw_flap_offset);
483  BoundAbs(flap_saturation_limit, MAX_PPRZ);
484  wls_stab_p.u_min[i] = -flap_saturation_limit;
485  wls_stab_p.u_max[i] = flap_saturation_limit;
486  }
487  if (i==8) { // pusher
488  // dt (min to max) MAX_PPRZ / (dt * f) dt_min == 0.002
489  Bound(eff_sched_pusher_time, 0.002, 5.);
490  float max_increment = MAX_PPRZ / (eff_sched_pusher_time * 500);
491  wls_stab_p.u_min[i] = actuators_pprz[i] - max_increment;
492  wls_stab_p.u_max[i] = actuators_pprz[i] + max_increment;
493 
494  Bound(wls_stab_p.u_min[i], 0, MAX_PPRZ);
495  Bound(wls_stab_p.u_max[i], 0, MAX_PPRZ);
496  }
497  }
498 }
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
uint8_t last_wp UNUSED
if(GpsFixValid() &&e_identification_started)
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
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)
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)
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition: state.h:1407
Hardware independent API for actuators (servos, motor controllers).
#define MAX_PPRZ
Definition: paparazzi.h:8
struct RadioControl radio_control
Definition: radio_control.c:33
Generic interface for radio control modules.
pprz_t values[RADIO_CONTROL_NB_CHANNEL]
Definition: radio_control.h:67
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.
Definition: vl53l1_types.h:83
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
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