Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
eff_scheduling_rotwing_nB.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;//1.0e-6;
75static float flt_cut_ap = 2.0e-6;//2.0e-5; //2.0e-3
76static float flt_cut = 1.0e-6;//1.0e-5; //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);
248 RW.att.sphi = sinf(RW.att.phi);
249 RW.att.cphi = cosf(RW.att.phi);
252 RW.att.spsi = sinf(RW.att.psi);
253 RW.att.cpsi = cosf(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 // Calc motor and control effectiveness
274
275 float sigma1 = I_inv[y][y]*RW.skew.sinr - I_inv[x][y]*RW.skew.cosr;
276 float sigma2 = I_inv[x][x]*RW.skew.cosr - I_inv[x][y]*RW.skew.sinr;
277 // Motor Front
283 // Motor Right
289 // Motor Back
291 G1_RW[RW_ap][COMMAND_MOTOR_BACK] = -(RW.mB.dFdu * RW.mB.l) * I_inv[x][y];
292 G1_RW[RW_aq][COMMAND_MOTOR_BACK] = -(RW.mB.dFdu * RW.mB.l) * I_inv[y][y];
295 // Motor Left
301
302 // Aileron
303 float Mx_a = RW.ail.dFdu * RW.as2 * RW.ail.l * RW.skew.sinr3;
304 float My_a = RW.ail.dFdu * RW.as2 * RW.ail.l * (RW.skew.cosr-RW.skew.cosr3);
305 G1_RW[RW_ap][COMMAND_AILERONS] = Mx_a * I_inv[x][x] + My_a * I_inv[x][y];
306 G1_RW[RW_aq][COMMAND_AILERONS] = Mx_a * I_inv[x][y] + My_a * I_inv[y][y];
307 // Lift and thrust
309 Bound(RW.wing.dLdtheta, 0.0, 1300.0);
311 Bound(RW.wing.L, 0.0, 350.0);
312 RW.P = 0;//actuator_state_1l[COMMAND_MOTOR_PUSHER] * RW.mP.dFdu;
313}
314
324
325
332void sum_EFF_MAT_RW(void) {
333
334 // Thrust and Pusher force estimation
335 float L = RW.wing.L / RW.m; // Lift specific force
336 float dLdtheta = RW.wing.dLdtheta / RW.m; // Lift specific force derivative with pitch
337 float T = RW.T / RW.m; // Thrust specific force. Minus gravity is a guesstimate.
338 float P = RW.P / RW.m; // Pusher specific force
339 float T_L = T + L * RW.att.ctheta; // Thrust and Lift term
340 float P_L = P + L * RW.att.stheta; // Pusher and Lift term
341 // Kept for consistency with eff_scheduling_rotwing_V2, not used by the nB effectiveness
342 (void)dLdtheta;
343 (void)T_L;
344 (void)P_L;
345 int i = 0;
346 int j = 0;
347
348 for (i = 0; i < EFF_MAT_COLS_NB; i++) {
349 switch (i) {
350 case (COMMAND_MOTOR_FRONT):
351 case (COMMAND_MOTOR_BACK):
352 case (COMMAND_MOTOR_RIGHT):
353 case (COMMAND_MOTOR_LEFT):
356 EFF_MAT_RW[RW_aD][i] = (RW.att.cphi * RW.att.ctheta ) * G1_RW[RW_aZ][i];
357 EFF_MAT_RW[RW_ap][i] = (G1_RW[RW_ap][i]) ;
358 EFF_MAT_RW[RW_aq][i] = (G1_RW[RW_aq][i]) ;
359 EFF_MAT_RW[RW_ar][i] = (G1_RW[RW_ar][i] + G2_RW[i]) ;
360 break;
361 case (COMMAND_AILERONS):
362 EFF_MAT_RW[RW_aN][i] = 0.0;
363 EFF_MAT_RW[RW_aE][i] = 0.0;
364 EFF_MAT_RW[RW_aD][i] = 0.0;
365 EFF_MAT_RW[RW_ap][i] = G1_RW[RW_ap][i];
366 EFF_MAT_RW[RW_aq][i] = G1_RW[RW_aq][i];
367 EFF_MAT_RW[RW_ar][i] = G1_RW[RW_ar][i];
368 break;
369 case (COMMAND_ROLL):
370 EFF_MAT_RW[RW_aN][i] = (-RW.att.cphi * RW.att.ctheta * RW.att.spsi * T);
371 EFF_MAT_RW[RW_aE][i] = ( RW.att.cphi * RW.att.ctheta * RW.att.cpsi * T);
372 EFF_MAT_RW[RW_aD][i] = ( RW.att.sphi * RW.att.ctheta * T);
373 EFF_MAT_RW[RW_ap][i] = 0.0;
374 EFF_MAT_RW[RW_aq][i] = 0.0;
375 EFF_MAT_RW[RW_ar][i] = 0.0;
376 break;
377 case (COMMAND_PITCH):
378 EFF_MAT_RW[RW_aN][i] = (-(RW.att.ctheta * RW.att.cpsi - RW.att.sphi * RW.att.stheta * RW.att.spsi) * T);
379 EFF_MAT_RW[RW_aE][i] = (-(RW.att.ctheta * RW.att.spsi + RW.att.sphi * RW.att.stheta * RW.att.cpsi) * T);
380 EFF_MAT_RW[RW_aD][i] = ( RW.att.stheta * RW.att.cphi * T) ;
381 EFF_MAT_RW[RW_ap][i] = 0.0;
382 EFF_MAT_RW[RW_aq][i] = 0.0;
383 EFF_MAT_RW[RW_ar][i] = 0.0;
384 break;
385 default:
386 break;
387 }
388 }
389 for (i = 0; i < EFF_MAT_ROWS_NB; i++) {
390 for(j = 0; j < EFF_MAT_COLS_NB; j++) {
391 float abs = fabs(EFF_MAT_RW[i][j]);
392 switch (i) {
393 case (RW_aN):
394 case (RW_aE):
395 case (RW_aD):
396 if (abs < flt_cut_a) {
397 EFF_MAT_RW[i][j] = 0.0;
398 }
399 break;
400 case (RW_aq):
401 case (RW_ar):
402 if (abs < flt_cut) {
403 EFF_MAT_RW[i][j] = 0.0;
404 }
405 break;
406 case (RW_ap):
407 if (abs < flt_cut_ap) {
408 EFF_MAT_RW[i][j] = 0.0;
409 }
410 break;
411 }
412 }
413 }
414 if(manual_roll){
415 //EFF_MAT_RW[RW_ap][1] = -0.012149;
416 //EFF_MAT_RW[RW_ap][3] = 0.012149;
417 //EFF_MAT_RW[RW_ap][1] = -roll_eff/1000.0;
418 //EFF_MAT_RW[RW_ap][3] = roll_eff/1000.0;
419 EFF_MAT_RW[RW_ap][0] = 0.0006;
420 EFF_MAT_RW[RW_ap][2] = -0.0006;
421 }
422 if(manual_pitch){
423 EFF_MAT_RW[RW_aq][0] = 0.001708;
424 EFF_MAT_RW[RW_aq][2] = -0.001708;
425 }
426 if(manual_yaw){
427 EFF_MAT_RW[RW_ar][0] = -0.000421;
428 EFF_MAT_RW[RW_ar][1] = 0.000421;
429 EFF_MAT_RW[RW_ar][2] = -0.000421;
430 EFF_MAT_RW[RW_ar][3] = 0.000421;
431 //G2_RW[0] = -2.1e-5;
432 //G2_RW[1] = 2.1e-5;
433 //G2_RW[2] = -2.1e-5;
434 //G2_RW[3] = 2.1e-5;
435 }
436}
437
439{
440 // Calculate sin and cosines of rotation
442 RW.skew.rad = skew_filt.o[0];
443 RW.skew.deg = RW.skew.rad / M_PI * 180.;
452#ifdef INS_EXT_VISION_ROTATION
453 // Define an INS external pose quaternion rotation from the wing rotation angle
454 struct FloatEulers rot_e = {0, 0, RW.skew.rad};
456#endif
457
458}
459static float sim_time = 0.0f;
461{
463 RW.as = body_rates->r*0.5; //stateGetAirspeed_f(); FIXME
464 float sgn_as = copysignf(1.0,RW.as);
465 BoundAbs(RW.as,30.);
466 RW.as2 = sgn_as * RW.as * RW.as;
467 BoundAbs(RW.as2, 900.);
468 if(airspeed_fake_on) {
469 //float freq = 0.5;
470 //float amp = 3.0;
471 sim_time += 0.002f;
472 RW.as = airspeed_fake ;//+ amp * sinf(2.0 * M_PI * freq * time);
473 RW.as2 = RW.as * RW.as;
474 } else {
475 sim_time = 0.0f;
476 }
477}
478
480{
481 if (RW.as > ELE_MIN_AS){
484 } else {
486 }
487}
488
489float calc_thrust_curve(float k1, float k2, float k3, float u){
490 return k1*u*u + k2*u + k3;
491}
492
493float calc_thrust_curve_d(float k1, float k2, float u){
494 float out= 2.0*k1*u + k2;
495 Bound(out, 1.0e-3, 1.0e-2);
496 return out;
497}
498
500 switch(thrust_curve){
501 case(0):
502 // Curve calculated at the Current Motor State
507 break;
508 case(1):
509 // Curve statically calculated at 50% throttle
514 break;
515 case(2):
516 // Manual thrust for tuning
521 break;
522 }
523 // T = k1*u^2 + k2*u + k3-----|k1 | k2 | k3 | u
524 //float T_mF = calc_thrust_curve(ROTWING_EFF_SCHED_MF_k1, ROTWING_EFF_SCHED_MF_k2, ROTWING_EFF_SCHED_MF_k3, actuator_state_1l[COMMAND_MOTOR_FRONT]);
525 //float T_mR = calc_thrust_curve(ROTWING_EFF_SCHED_MR_k1, ROTWING_EFF_SCHED_MR_k2, ROTWING_EFF_SCHED_MR_k3, actuator_state_1l[COMMAND_MOTOR_RIGHT]);
526 //float T_mB = calc_thrust_curve(ROTWING_EFF_SCHED_MB_k1, ROTWING_EFF_SCHED_MB_k2, ROTWING_EFF_SCHED_MB_k3, actuator_state_1l[COMMAND_MOTOR_BACK]);
527 //float T_mL = calc_thrust_curve(ROTWING_EFF_SCHED_ML_k1, ROTWING_EFF_SCHED_ML_k2, ROTWING_EFF_SCHED_ML_k3, actuator_state_1l[COMMAND_MOTOR_LEFT]);
528 RW.T = RW.m*9.81/(RW.att.cphi * RW.att.ctheta);//T_mF + T_mR + T_mB + T_mL;
529 Bound(RW.T, 30.0, 180.0);
530}
531
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 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
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
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
static float sim_time
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
#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_eulers_of_quat_zxy(struct FloatEulers *e, const struct FloatQuat *q)
euler rotation 'ZXY' This rotation order is useful if you need 90 deg pitch
void float_quat_of_eulers(struct FloatQuat *q, const struct FloatEulers *e)
quat of euler roation 'ZYX'
euler angles
angular rates
static struct FloatQuat * stateGetNedToBodyQuat_f(void)
Get vehicle body attitude quaternion (float).
Definition state.h:1302
static struct FloatRates * stateGetBodyRates_f(void)
Get vehicle body angular rate (float).
Definition state.h:1381
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.