Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
eff_scheduling_rotwing_V2.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 Tomaso De Ponti <T.M.L.DePonti@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#include "generated/airframe.h"
28#include "state.h"
30#include "modules/core/abi.h"
33
34#define FORCE_ONELOOP
35#ifdef FORCE_ONELOOP
38#else
40#endif
41
42#ifndef ROTWING_EFF_SCHED_IXX_BODY
43#error "NO ROTWING_EFF_SCHED_IXX_BODY defined"
44#endif
45
46#ifndef ROTWING_EFF_SCHED_IYY_BODY
47#error "NO ROTWING_EFF_SCHED_IYY_BODY defined"
48#endif
49
50#ifndef ROTWING_EFF_SCHED_IZZ
51#error "NO ROTWING_EFF_SCHED_IZZ defined"
52#endif
53
54#ifndef ROTWING_EFF_SCHED_IXX_WING
55#error "NO ROTWING_EFF_SCHED_IXX_WING defined"
56#endif
57
58#ifndef ROTWING_EFF_SCHED_IYY_WING
59#error "NO ROTWING_EFF_SCHED_IYY_WING defined"
60#endif
61
62#ifndef ROTWING_EFF_SCHED_M
63#error "NO ROTWING_EFF_SCHED_M defined"
64#endif
65
66bool manual_roll = false;
67bool manual_pitch = false;
68bool manual_yaw = false;
69/* Effectiveness Matrix definition */
70float G2_RW[EFF_MAT_COLS_NB] = {0};//ROTWING_EFF_SCHED_G2; //scaled by RW_G_SCALE
71float G1_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB] = {0};//{ROTWING_EFF_SCHED_G1_ZERO, ROTWING_EFF_SCHED_G1_ZERO, ROTWING_EFF_SCHED_G1_THRUST, ROTWING_EFF_SCHED_G1_ROLL, ROTWING_EFF_SCHED_G1_PITCH, ROTWING_EFF_SCHED_G1_YAW}; //scaled by RW_G_SCALE
73float I_inv[3][3] = {0};
74static float flt_cut_a = 1.0e-6;
75static float flt_cut_ap = 2.0e-3;
76static float flt_cut = 1.0e-4;
77
83/* Temp variables*/
84int G2_on = 0;
85bool airspeed_fake_on = false;
86float airspeed_fake = 0.0;
87float ele_eff = 19.36; // (0.88*22.0);
88float roll_eff = 8.9;//15.402;//3.835;//3.835;5.5
89float yaw_eff = 0.237; // 1.3171*0.390=0.514 or 0.659 and 0.812 (pitch - roll)
90float ele_min = 0.0;
91/* Define Forces and Moments tructs for each actuator*/
92struct RW_Model RW;
93
94int thrust_curve = 1.0;
95float temp_mQ_k = 1.37; //Manual Value For Tuning2
98void ele_pref_sched(void);
99void update_attitude(void);
100void sum_EFF_MAT_RW(void);
101void init_RW_Model(void);
102void calc_G1_G2_RW(void);
103float calc_thrust_curve(float k1, float k2, float k3, float u);
104float calc_thrust_curve_d(float k1, float k2, float u);
105void calc_all_thrust_curve(void);
106void init_all_thrust_curve(void);
107
110#ifndef WING_ROTATION_CAN_ROTWING_ID
111#define WING_ROTATION_CAN_ROTWING_ID ABI_BROADCAST
112#endif
115
116float skew_meas = 0.0;
118{
119 for (int i=0; i<num_act; i++){
120 if (pos_msg[i].set.position && (pos_msg[i].idx == SERVO_ROTATION_MECH_IDX))
121 {
122 skew_meas = 0.5 * M_PI - pos_msg[i].position;
123 Bound(skew_meas, 0, 0.5 * M_PI);
124 }
125 }
126}
127
128#include "generated/modules.h"
143
145{
146 // Inertia and mass
147 RW.I.b_xx = ROTWING_EFF_SCHED_IXX_BODY; // [kgm²]
148 RW.I.b_yy = ROTWING_EFF_SCHED_IYY_BODY; // [kgm²]
149 RW.I.w_xx = ROTWING_EFF_SCHED_IXX_WING; // [kgm²]
150 RW.I.w_yy = ROTWING_EFF_SCHED_IYY_WING; // [kgm²]
151 RW.I.xx = (RW.I.b_xx + RW.I.w_xx); // [kgm²]
152 RW.I.yy = RW.I.b_yy + RW.I.w_yy; // [kgm²]
153 RW.I.zz = ROTWING_EFF_SCHED_IZZ; // [kgm²]
154 RW.m = ROTWING_EFF_SCHED_M; // [kg]
155
156 // Init the thrust curves
158 // Motor Front
162 printf("RW.mF.dFdu: %f\n", RW.mF.dFdu);
164
165 // Motor Right
170
171 // Motor Back
176
177 // Motor Left
182
183 // Motor Pusher
188
189 // Elevator
190 RW.ele.dFdu = ele_eff / (RW_G_SCALE * RW_G_SCALE); // [N / pprz] old value: 24.81 29.70
191 RW.ele.dMdu = 0; // [Nm / pprz]
192 RW.ele.dMdud = 0; // [Nm / pprz]
193 RW.ele.l = 0.85; // [m]
194 RW.ele_pref = 0;
195 // Rudder
196 RW.rud.dFdu = 1.2015 / (RW_G_SCALE * RW_G_SCALE); // [N / pprz]
197 RW.rud.dMdu = 0; // [Nm / pprz]
198 RW.rud.dMdud = 0; // [Nm / pprz]
199 RW.rud.l = 0.88; // [m]
200 // Aileron
201 RW.ail.dFdu = 7.678 / (RW_G_SCALE * RW_G_SCALE); // [N / pprz] (1.88 * 4.084)
202 RW.ail.dMdu = 0; // [Nm / pprz]
203 RW.ail.dMdud = 0; // [Nm / pprz]
204 RW.ail.l = 0.68; // [m]
205 // Flaperon
206 RW.flp.dFdu = 10.825 / (RW_G_SCALE * RW_G_SCALE); // [N / pprz] (1.88 * 5.758)
207 RW.flp.dMdu = 0; // [Nm / pprz]
208 RW.flp.dMdud = 0; // [Nm / pprz]
209 RW.flp.l = 0.36; // [m]
210 // Lift: k0 the v²+ k1 the sin² v² + k2 sin² v²
211 RW.wing.k0 = 0.336 + 0.0507 + 0.102;
212 RW.wing.k1 = 0.616;
213 RW.wing.k2 = 0.121;
214 // Initialize attitude
215 RW.att.phi = 0.0;
216 RW.att.theta = 0.0;
217 RW.att.psi = 0.0;
218 RW.att.sphi = 0.0;
219 RW.att.cphi = 0.0;
220 RW.att.stheta = 0.0;
221 RW.att.ctheta = 0.0;
222 RW.att.spsi = 0.0;
223 RW.att.cpsi = 0.0;
224 // Initialize skew variables to quad values
225 RW.skew.rad = 0.0; // ABI input
226 RW.skew.deg = 0.0;
227 RW.skew.cosr = 1.0;
228 RW.skew.sinr = 0.0;
229 RW.skew.cosr2 = 1.0;
230 RW.skew.sinr2 = 0.0;
231 RW.skew.sinr3 = 0.0;
232 // Initialize airspeed
233 RW.as = 0.0;
234 RW.as2 = 0.0;
235}
236
237/*Update the attitude*/
239{
244 RW.att.phi = phi_filt.o[0];//eulers_zxy_RW_EFF.phi;
245 RW.att.theta = theta_filt.o[0];//eulers_zxy_RW_EFF.theta;
246 RW.att.psi = psi_filt.o[0];//eulers_zxy_RW_EFF.psi;
247 //printf("Attitude filt: %f %f %f\n", RW.att.phi, RW.att.theta, RW.att.psi);
254}
255/* Function to precalculate once some constant effectiveness values to improve efficiency*/
257{
258 // Inertia
259 int x = 0;
260 int y = 1;
261 int z = 2;
263 I_inv[x][x] = (RW.I.w_yy*RW.skew.cosr2 + RW.I.w_xx*RW.skew.sinr2 + RW.I.b_yy)/(sigma);
264 I_inv[x][y] = (RW.skew.cosr*RW.skew.sinr*(RW.I.w_xx - RW.I.w_yy))/sigma;
265 I_inv[x][z] = 0.0;
266 I_inv[y][x] = I_inv[x][y];
267 I_inv[y][y] = (RW.I.w_xx*RW.skew.cosr2 + RW.I.w_yy*RW.skew.sinr2 + RW.I.b_xx)/sigma;
268 I_inv[y][z] = 0.0;
269 I_inv[z][x] = 0.0;
270 I_inv[z][y] = 0.0;
271 I_inv[z][z] = 1/RW.I.zz;
272 //printf("I_inv_x: %f %f %f\n", I_inv[x][x], I_inv[x][y], I_inv[x][z]);
273 //printf("I_inv_y: %f %f %f\n", I_inv[y][x], I_inv[y][y], I_inv[y][z]);
274 //printf("I_inv_z: %f %f %f\n", I_inv[z][x], I_inv[z][y], I_inv[z][z]);
275 //printf("Control - I: %f %f %f\n", 1.0/I_inv[x][x], 1.0/I_inv[y][y], 1.0/I_inv[z][z]);
276 // Calc motor and control effectiveness
278
279 float sigma1 = I_inv[y][y]*RW.skew.sinr - I_inv[x][y]*RW.skew.cosr;
280 float sigma2 = I_inv[x][x]*RW.skew.cosr - I_inv[x][y]*RW.skew.sinr;
281 // Motor Front
287 // Motor Right
293 // Motor Back
295 G1_RW[RW_ap][COMMAND_MOTOR_BACK] = -(RW.mB.dFdu * RW.mB.l) * I_inv[x][y];
296 G1_RW[RW_aq][COMMAND_MOTOR_BACK] = -(RW.mB.dFdu * RW.mB.l) * I_inv[y][y];
299 // Motor Left
305 // Motor Pusher
307 // Elevator
309 G1_RW[RW_ap][COMMAND_ELEVATOR] = (RW.ele.dFdu * RW.as2 * RW.ele.l) * I_inv[x][y];
310 G1_RW[RW_aq][COMMAND_ELEVATOR] = (RW.ele.dFdu * RW.as2 * RW.ele.l) * I_inv[y][y];
311 // Rudder
312 G1_RW[RW_ar][COMMAND_RUDDER] = (RW.rud.dFdu * RW.as2 * RW.rud.l) * I_inv[z][z];
313 // Aileron
314 float Mx_a = RW.ail.dFdu * RW.as2 * RW.ail.l * RW.skew.sinr3;
315 float My_a = RW.ail.dFdu * RW.as2 * RW.ail.l * (RW.skew.cosr-RW.skew.cosr3);
316 G1_RW[RW_ap][COMMAND_AILERONS] = Mx_a * I_inv[x][x] + My_a * I_inv[x][y];
317 G1_RW[RW_aq][COMMAND_AILERONS] = Mx_a * I_inv[x][y] + My_a * I_inv[y][y];
318 // Flaperon
319 float Mx_f = RW.flp.dFdu * RW.as2 * RW.flp.l * RW.skew.sinr3;
320 float My_f = RW.flp.dFdu * RW.as2 * RW.flp.l * (RW.skew.cosr-RW.skew.cosr3);
321 G1_RW[RW_ap][COMMAND_FLAPS] = Mx_f * I_inv[x][x] + My_f * I_inv[x][y];
322 G1_RW[RW_aq][COMMAND_FLAPS] = Mx_f * I_inv[x][y] + My_f * I_inv[y][y];
323 // Lift and thrust
325 Bound(RW.wing.dLdtheta, 0.0, 1300.0);
327 Bound(RW.wing.L, 0.0, 350.0);
329}
330
340
341
348void sum_EFF_MAT_RW(void) {
349
350 // Thrust and Pusher force estimation
351 float L = RW.wing.L / RW.m; // Lift specific force
352 float dLdtheta = RW.wing.dLdtheta / RW.m; // Lift specific force derivative with pitch
353 float T = RW.T / RW.m; // Thrust specific force. Minus gravity is a guesstimate.
354 float P = RW.P / RW.m; // Pusher specific force
355 float T_L = T + L * RW.att.ctheta; // Thrust and Lift term
356 float P_L = P + L * RW.att.stheta; // Pusher and Lift term
357 int i = 0;
358 int j = 0;
359
360 for (i = 0; i < EFF_MAT_COLS_NB; i++) {
361 switch (i) {
362 case (COMMAND_MOTOR_FRONT):
363 case (COMMAND_MOTOR_BACK):
364 case (COMMAND_MOTOR_RIGHT):
365 case (COMMAND_MOTOR_LEFT):
368 EFF_MAT_RW[RW_aD][i] = (RW.att.cphi * RW.att.ctheta ) * G1_RW[RW_aZ][i];
369 EFF_MAT_RW[RW_ap][i] = (G1_RW[RW_ap][i]) ;
370 EFF_MAT_RW[RW_aq][i] = (G1_RW[RW_aq][i]) ;
371 EFF_MAT_RW[RW_ar][i] = (G1_RW[RW_ar][i] + G2_RW[i]) ;
372 break;
373 case (COMMAND_MOTOR_PUSHER):
376 EFF_MAT_RW[RW_aD][i] = (- RW.att.cphi * RW.att.stheta ) * G1_RW[RW_aX][i];
377 EFF_MAT_RW[RW_ap][i] = 0.0;
378 EFF_MAT_RW[RW_aq][i] = 0.0;
379 EFF_MAT_RW[RW_ar][i] = 0.0;
380 break;
381 case (COMMAND_ELEVATOR):
382 case (COMMAND_RUDDER):
383 case (COMMAND_AILERONS):
384 case (COMMAND_FLAPS):
385 EFF_MAT_RW[RW_aN][i] = 0.0;
386 EFF_MAT_RW[RW_aE][i] = 0.0;
387 EFF_MAT_RW[RW_aD][i] = 0.0;
388 EFF_MAT_RW[RW_ap][i] = G1_RW[RW_ap][i];
389 EFF_MAT_RW[RW_aq][i] = G1_RW[RW_aq][i];
390 EFF_MAT_RW[RW_ar][i] = G1_RW[RW_ar][i];
391 break;
392 case (COMMAND_ROLL):
396 EFF_MAT_RW[RW_ap][i] = 0.0;
397 EFF_MAT_RW[RW_aq][i] = 0.0;
398 EFF_MAT_RW[RW_ar][i] = 0.0;
399 break;
400 case (COMMAND_PITCH):
401 EFF_MAT_RW[RW_aN][i] = (-(RW.att.ctheta * RW.att.cpsi - RW.att.sphi * RW.att.stheta * RW.att.spsi) * T - (RW.att.cpsi * RW.att.stheta + RW.att.ctheta * RW.att.sphi * RW.att.spsi) * P - RW.att.sphi * RW.att.spsi * dLdtheta);
402 EFF_MAT_RW[RW_aE][i] = (-(RW.att.ctheta * RW.att.spsi + RW.att.sphi * RW.att.stheta * RW.att.cpsi) * T - (RW.att.spsi * RW.att.stheta - RW.att.cpsi * RW.att.ctheta * RW.att.sphi) * P + RW.att.sphi * RW.att.cpsi * dLdtheta);
403 EFF_MAT_RW[RW_aD][i] = ( RW.att.stheta * RW.att.cphi * T - RW.att.cphi * RW.att.ctheta * P - RW.att.cphi * dLdtheta) ;
404 EFF_MAT_RW[RW_ap][i] = 0.0;
405 EFF_MAT_RW[RW_aq][i] = 0.0;
406 EFF_MAT_RW[RW_ar][i] = 0.0;
407 break;
408 default:
409 break;
410 }
411 }
412 for (i = 0; i < EFF_MAT_ROWS_NB; i++) {
413 for(j = 0; j < EFF_MAT_COLS_NB; j++) {
414 float abs = fabs(EFF_MAT_RW[i][j]);
415 switch (i) {
416 case (RW_aN):
417 case (RW_aE):
418 case (RW_aD):
419 if (abs < flt_cut_a) {
420 EFF_MAT_RW[i][j] = 0.0;
421 }
422 break;
423 case (RW_aq):
424 case (RW_ar):
425 if (abs < flt_cut) {
426 EFF_MAT_RW[i][j] = 0.0;
427 }
428 break;
429 case (RW_ap):
430 if (abs < flt_cut_ap) {
431 EFF_MAT_RW[i][j] = 0.0;
432 }
433 break;
434 }
435 }
436 }
437 if(manual_roll){
438 //EFF_MAT_RW[RW_ap][1] = -0.012149;
439 //EFF_MAT_RW[RW_ap][3] = 0.012149;
440 //EFF_MAT_RW[RW_ap][1] = -roll_eff/1000.0;
441 //EFF_MAT_RW[RW_ap][3] = roll_eff/1000.0;
442 EFF_MAT_RW[RW_ap][0] = 0.0006;
443 EFF_MAT_RW[RW_ap][2] = -0.0006;
444 }
445 if(manual_pitch){
446 EFF_MAT_RW[RW_aq][0] = 0.001708;
447 EFF_MAT_RW[RW_aq][2] = -0.001708;
448 }
449 if(manual_yaw){
450 EFF_MAT_RW[RW_ar][0] = -0.000421;
451 EFF_MAT_RW[RW_ar][1] = 0.000421;
452 EFF_MAT_RW[RW_ar][2] = -0.000421;
453 EFF_MAT_RW[RW_ar][3] = 0.000421;
454 G2_RW[0] = -2.1e-5;
455 G2_RW[1] = 2.1e-5;
456 G2_RW[2] = -2.1e-5;
457 G2_RW[3] = 2.1e-5;
458 }
459}
460
462{
463 // Calculate sin and cosines of rotation
465 RW.skew.rad = skew_filt.o[0];
466 RW.skew.deg = RW.skew.rad / M_PI * 180.;
475#ifdef INS_EXT_VISION_ROTATION
476 // Define an INS external pose quaternion rotation from the wing rotation angle
477 struct FloatEulers rot_e = {0, 0, RW.skew.rad};
479#endif
480
481}
483{
485 Bound(RW.as, 0. , 30.);
486 RW.as2 = RW.as * RW.as;
487 Bound(RW.as2, 0. , 900.);
488 if(airspeed_fake_on) {
490 RW.as2 = RW.as * RW.as;
491 }
492}
493
495{
496 if (RW.as > ELE_MIN_AS){
499 } else {
501 }
502}
503
504float calc_thrust_curve(float k1, float k2, float k3, float u){
505 return k1*u*u + k2*u + k3;
506}
507
508float calc_thrust_curve_d(float k1, float k2, float u){
509 float out= 2.0*k1*u + k2;
510 Bound(out, 1.0e-3, 1.0e-2);
511 return out;
512}
513
515 switch(thrust_curve){
516 case(0):
517 // Curve calculated at the Current Motor State
522 break;
523 case(1):
524 // Curve statically calculated at 50% throttle
529 break;
530 case(2):
531 // Manual thrust for tuning
536 break;
537 }
538 // T = k1*u^2 + k2*u + k3-----|k1 | k2 | k3 | u
543 RW.T = RW.m*9.81;//T_mF + T_mR + T_mB + T_mL;
544 Bound(RW.T, 30.0, 180.0);
545}
546
Main include for ABI (AirBorneInterface).
Event structure to store callbacks in a linked list.
Definition abi_common.h:68
#define UNUSED(x)
#define RW_G_SCALE
#define RW_aN
#define RW_aE
#define RW_aZ
#define RW_aX
#define EFF_MAT_COLS_NB
#define RW_ap
#define RW_ar
#define COMMAND_PITCH
#define COMMAND_ROLL
#define EFF_MAT_ROWS_NB
#define RW_aq
#define RW_aD
void update_attitude(void)
float G2_RW[EFF_MAT_COLS_NB]
void calc_G1_G2_RW(void)
float G1_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
float I_inv[3][3]
float airspeed_fake
struct FloatEulers eulers_zxy_RW_EFF
static float flt_cut_ap
struct RW_Model RW
bool manual_pitch
float calc_thrust_curve_d(float k1, float k2, float u)
static Butterworth2LowPass psi_filt
void calc_all_thrust_curve(void)
#define WING_ROTATION_CAN_ROTWING_ID
ABI binding wing position data.
float actuator_state_filt_vect[EFF_MAT_COLS_NB]
void eff_scheduling_rotwing_update_airspeed(void)
float EFF_MAT_RW[EFF_MAT_ROWS_NB][EFF_MAT_COLS_NB]
static Butterworth2LowPass skew_filt
void ele_pref_sched(void)
void eff_scheduling_rotwing_update_wing_angle(void)
float calc_thrust_curve(float k1, float k2, float k3, float u)
static abi_event wing_position_ev
void eff_scheduling_rotwing_init(void)
static Butterworth2LowPass theta_filt
void sum_EFF_MAT_RW(void)
Function that sums g1 and g2 to obtain the g1_g2 matrix.
static float flt_cut_a
bool airspeed_fake_on
void init_RW_Model(void)
static float flt_cut
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)
float temp_mQ_k
void init_all_thrust_curve(void)
static Butterworth2LowPass phi_filt
struct wing_model wing
struct F_M_Body ele
struct F_M_Body mP
struct F_M_Body mL
struct F_M_Body mR
struct F_M_Body mF
struct RW_attitude att
struct F_M_Body rud
struct RW_skew skew
struct F_M_Body flp
struct F_M_Body mB
struct F_M_Body ail
#define ELE_MAX_AS
#define ELE_MIN_AS
#define ZERO_ELE_PPRZ
float phi
in radians
float theta
in radians
float psi
in radians
void float_quat_of_eulers(struct FloatQuat *q, const struct FloatEulers *e)
quat of euler roation 'ZYX'
euler angles
static struct FloatEulers * stateGetNedToBodyEulersZxy_f(void)
Get vehicle body attitude ZXY euler angles (float).
Definition state.h:1320
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition state.h:1604
Integrated Navigation System interface.
Simple first order low pass filter with bilinear transform.
float o[2]
output history
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, const float tau, const float sample_time, const float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, const float value)
Update second order Butterworth low pass filter state with a new value.
Second order low pass filter structure.
uint16_t foo
Definition main_demo5.c:58
Hardware independent API for actuators (servos, motor controllers).
float actuator_state_1l[ANDI_NUM_ACT_TOT]
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
API to get/set the generic vehicle states.
static float P[3][3]
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.