Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
gvf_parametric.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
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 <iostream>
28 #include <Eigen/Dense> // https://eigen.tuxfamily.org/dox/GettingStarted.html
29 
30 #include "gvf_parametric.h"
36 #include "../gvf_common.h"
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 #include "autopilot.h"
43 
44 // Control
45 uint32_t gvf_parametric_t0 = 0; // We need it for calculting the time lapse delta_T
46 uint32_t gvf_parametric_splines_ctr = 0; // We need it for Bézier curves splines Telemetry
48 
49 // Trajectory
51 
52 // Parameters array lenght
55 
56 // Error signals array lenght
58 
59 // Bézier
61 
62 #if PERIODIC_TELEMETRY
64 static void send_gvf_parametric(struct transport_tx *trans, struct link_device *dev)
65 {
67 
69  uint32_t delta_T = now - gvf_parametric_t0;
70 
72 
73  if (delta_T < 200) {
75  pprz_msg_send_GVF_PARAMETRIC(trans, dev, AC_ID, &traj_type, &gvf_parametric_control.s, &wb, gvf_parametric_plen,
77  }
78 }
79 
80 #if GVF_OCAML_GCS
81 static void send_circle_parametric(struct transport_tx *trans, struct link_device *dev)
82 {
84  uint32_t delta_T = now - gvf_parametric_t0;
85 
86  if (delta_T < 200)
88  pprz_msg_send_CIRCLE(trans, dev, AC_ID, &gvf_parametric_trajectory.p_parametric[0],
90  }
91 }
92 #endif // GVF_OCAML_GCS
93 
94 #endif // PERIODIC TELEMETRY
95 
96 #ifdef __cplusplus
97 }
98 #endif
99 
101 {
110 
111 #if PERIODIC_TELEMETRY
113 #if GVF_OCAML_GCS
114  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_CIRCLE, send_circle_parametric);
115 #endif // GVF_OCAML_GCS
116 #endif // PERIODIC_TELEMETRY
117 
118 }
119 
121 {
123 }
124 
125 void gvf_parametric_control_2D(float kx, float ky, float f1, float f2, float f1d, float f2d, float f1dd, float f2dd)
126 {
127 
128  uint32_t now = get_sys_time_msec();
130  gvf_parametric_t0 = now;
131 
132  if (gvf_parametric_control.delta_T > 300) { // We need at least two iterations for Delta_T
133  gvf_parametric_control.w = 0; // Reset w since we assume the algorithm starts
134  return;
135  }
136 
137  // Carrot position
138 #ifdef FIXEDWING_FIRMWARE
139  desired_x = f1;
140  desired_y = f2;
141 #endif
142 
143  float L = gvf_parametric_control.L;
145 
146  Eigen::Vector3f X;
147  Eigen::Matrix3f J;
148 
149  // Error signals phi_x and phi_y
150  struct EnuCoor_f *pos_enu = stateGetPositionEnu_f();
151  float x = pos_enu->x;
152  float y = pos_enu->y;
153 
154  float phi1 = L * (x - f1);
155  float phi2 = L * (y - f2);
156 
157  gvf_parametric_trajectory.phi_errors[0] = phi1; // Error signals for the telemetry
160 
161  // Chi
162  X(0) = L * beta * f1d - kx * phi1;
163  X(1) = L * beta * f2d - ky * phi2;
164  X(2) = L + beta * (kx * phi1 * f1d + ky * phi2 * f2d);
165  X *= L;
166 
167  // Jacobian
168  J.setZero();
169  J(0, 0) = -kx * L;
170  J(1, 1) = -ky * L;
171  J(2, 0) = (beta * L) * (beta * f1dd + kx * f1d);
172  J(2, 1) = (beta * L) * (beta * f2dd + ky * f2d);
173  J(2, 2) = beta * beta * (kx * (phi1 * f1dd - L * f1d * f1d) + ky * (phi2 * f2dd - L * f2d * f2d));
174  J *= L;
175 
176  // Guidance algorithm
178  float w_dot = (ground_speed * X(2)) / sqrtf(X(0) * X(0) + X(1) * X(1));
179 
180  Eigen::Vector3f xi_dot;
181  struct EnuCoor_f *vel_enu = stateGetSpeedEnu_f();
183 
184  xi_dot << vel_enu->x, vel_enu->y, w_dot;
185 
186  Eigen::Matrix3f G;
187  Eigen::Matrix3f Gp;
188  Eigen::Matrix<float, 2, 3> Fp;
189  Eigen::Vector2f h;
190  Eigen::Matrix<float, 1, 2> ht;
191 
192  G << 1, 0, 0,
193  0, 1, 0,
194  0, 0, 0;
195  Fp << 0, -1, 0,
196  1, 0, 0;
197  Gp << 0, -1, 0,
198  1, 0, 0,
199  0, 0, 0;
200 
201  h << sinf(course), cosf(course);
202  ht = h.transpose();
203 
204  Eigen::Matrix<float, 1, 3> Xt = X.transpose();
205  Eigen::Vector3f Xh = X / X.norm();
206  Eigen::Matrix<float, 1, 3> Xht = Xh.transpose();
207  Eigen::Matrix3f I;
208  I.setIdentity();
209 
210  float aux = ht * Fp * X;
211  float heading_rate = -1 / (Xt * G * X) * Xt * Gp * (I - Xh * Xht) * J * xi_dot - (gvf_parametric_control.k_psi * aux /
212  sqrtf(Xt * G * X));
213 
214  // From gvf_common.h TODO: implement d/dt of kppa and ori_err
215  gvf_c_omega.omega = heading_rate;
216  gvf_c_info.kappa = (f1d * f2dd - f1dd * f2d) / powf(f1d * f1d + f2d * f2d, 1.5);
217  gvf_c_info.ori_err = 1 - (Xh(0) * cosf(course) + Xh(1) * sinf(course));
218 
219  // Virtual coordinate update, even if the vehicle is not in autonomous mode, the parameter w will get "closer" to
220  // the vehicle. So it is not only okei but advisable to update it.
222 
224 }
225 
226 #ifdef FIXEDWING_FIRMWARE
227 void gvf_parametric_control_3D(float kx, float ky, float kz, float f1, float f2, float f3, float f1d, float f2d,
228  float f3d, float f1dd, float f2dd, float f3dd)
229 {
230  uint32_t now = get_sys_time_msec();
232  gvf_parametric_t0 = now;
233 
234  if (gvf_parametric_control.delta_T > 300) { // We need at least two iterations for Delta_T
235  gvf_parametric_control.w = 0; // Reset w since we assume the algorithm starts
236  return;
237  }
238 
239  // Carrot position
240  desired_x = f1;
241  desired_y = f2;
242 
243  float L = gvf_parametric_control.L;
245 
246  Eigen::Vector4f X;
247  Eigen::Matrix4f J;
248 
249  // Error signals phi_x phi_y and phi_z
250  struct EnuCoor_f *pos_enu = stateGetPositionEnu_f();
251  float x = pos_enu->x;
252  float y = pos_enu->y;
253  float z = pos_enu->z;
254 
255  float phi1 = L * (x - f1);
256  float phi2 = L * (y - f2);
257  float phi3 = L * (z - f3);
258 
259  gvf_parametric_trajectory.phi_errors[0] = phi1 / L; // Error signals in meters for the telemetry
263 
264 
265  // Chi
266  X(0) = -f1d * L * L * beta - kx * phi1;
267  X(1) = -f2d * L * L * beta - ky * phi2;
268  X(2) = -f3d * L * L * beta - kz * phi3;
269  X(3) = -L * L + beta * (kx * phi1 * f1d + ky * phi2 * f2d + kz * phi3 * f3d);
270  X *= L;
271 
272  // Jacobian
273  J.setZero();
274  J(0, 0) = -kx * L;
275  J(1, 1) = -ky * L;
276  J(2, 2) = -kz * L;
277  J(3, 0) = kx * f1d * beta * L;
278  J(3, 1) = ky * f2d * beta * L;
279  J(3, 2) = kz * f3d * beta * L;
280  J(0, 3) = -(beta * L) * (beta * L * f1dd - kx * f1d);
281  J(1, 3) = -(beta * L) * (beta * L * f2dd - ky * f2d);
282  J(2, 3) = -(beta * L) * (beta * L * f3dd - kz * f3d);
283  J(3, 3) = beta * beta * (kx * (phi1 * f1dd - L * f1d * f1d) + ky * (phi2 * f2dd - L * f2d * f2d)
284  + kz * (phi3 * f3dd - L * f3d * f3d));
285  J *= L;
286 
287  // Guidance algorithm
289  float w_dot = (ground_speed * X(3)) / sqrtf(X(0) * X(0) + X(1) * X(1));
290 
291  Eigen::Vector4f xi_dot;
292  struct EnuCoor_f *vel_enu = stateGetSpeedEnu_f();
294 
295  xi_dot << vel_enu->x, vel_enu->y, vel_enu->z, w_dot;
296 
297  Eigen::Matrix2f E;
298  Eigen::Matrix<float, 2, 4> F;
299  Eigen::Matrix<float, 2, 4> Fp;
300  Eigen::Matrix4f G;
301  Eigen::Matrix4f Gp;
302  Eigen::Matrix4f I;
303  Eigen::Vector2f h;
304  Eigen::Matrix<float, 1, 2> ht;
305 
306  h << sinf(course), cosf(course);
307  ht = h.transpose();
308  I.setIdentity();
309  F << 1.0, 0.0, 0.0, 0.0,
310  0.0, 1.0, 0.0, 0.0;
311  E << 0.0, -1.0,
312  1.0, 0.0;
313  G = F.transpose() * F;
314  Fp = E * F;
315  Gp = F.transpose() * E * F;
316 
317  Eigen::Matrix<float, 1, 4> Xt = X.transpose();
318  Eigen::Vector4f Xh = X / X.norm();
319  Eigen::Matrix<float, 1, 4> Xht = Xh.transpose();
320 
321  float aux = ht * Fp * X;
322 
323  float heading_rate = -1 / (Xt * G * X) * Xt * Gp * (I - Xh * Xht) * J * xi_dot - (gvf_parametric_control.k_psi * aux /
324  sqrtf(Xt * G * X));
325  float climbing_rate = (ground_speed * X(2)) / sqrtf(X(0) * X(0) + X(1) * X(1));
326 
327  // Virtual coordinate update, even if the vehicle is not in autonomous mode, the parameter w will get "closer" to
328  // the vehicle. So it is not only okei but advisable to update it.
330 
331  gvf_parametric_low_level_control_3D(heading_rate, climbing_rate);
332 }
333 #endif // FIXED_WING FIRMWARE
334 
336 // 2D TREFOIL KNOT
337 
338 bool gvf_parametric_2D_trefoil_XY(float xo, float yo, float w1, float w2, float ratio, float r, float alpha)
339 {
350 
351  float f1, f2, f1d, f2d, f1dd, f2dd;
352 
353  gvf_parametric_2d_trefoil_info(&f1, &f2, &f1d, &f2d, &f1dd, &f2dd);
355  f2dd);
356 
357  return true;
358 }
359 
360 bool gvf_parametric_2D_trefoil_wp(uint8_t wp, float w1, float w2, float ratio, float r, float alpha)
361 {
364  gvf_parametric_2D_trefoil_XY(WaypointX(wp), WaypointY(wp), w1, w2, ratio, r, alpha);
365  return true;
366 }
367 
368 // 2D CUBIC BEZIER CURVE
370 {
372  float fx, fy, fxd, fyd, fxdd, fydd;
373  gvf_parametric_2d_bezier_splines_info(gvf_bezier_2D, &fx, &fy, &fxd, &fyd, &fxdd, &fydd);
375  fydd);
376  return true;
377 }
378 
379 /* @param first_wp is the first waypoint of the Bézier Spline
380  * there should be 3*GVF_PARAMETRIC_2D_BEZIER_N_SEG+1 points
381  */
383 {
384  float x[3 * GVF_PARAMETRIC_2D_BEZIER_N_SEG + 1];
385  float y[3 * GVF_PARAMETRIC_2D_BEZIER_N_SEG + 1];
386  int k;
387  for (k = 0; k < 3 * GVF_PARAMETRIC_2D_BEZIER_N_SEG + 1; k++) {
388  x[k] = WaypointX(first_wp + k);
389  y[k] = WaypointY(first_wp + k);
390  }
392 
393  /* Send data piecewise. Some radio modules do not allow for a big data frame.*/
394 
395  // Send x points -> Indicate x with sign (+) in the first parameter
396  if (gvf_parametric_splines_ctr == 0) {
398  for (k = 0; k < 3 * GVF_PARAMETRIC_2D_BEZIER_N_SEG + 1; k++) {
400  }
401  }
402  // Send y points -> Indicate y with sign (-) in the first parameter
403  else if (gvf_parametric_splines_ctr == 1) {
405  for (k = 0; k < 3 * GVF_PARAMETRIC_2D_BEZIER_N_SEG + 1; k++) {
407  }
408  }
409  // send kx, ky, beta and anything else needed..
410  else {
415  }
416  gvf_parametric_plen = 16;
418 
419  // restart the spline
422  } else if (gvf_parametric_control.w < 0) {
424  }
426  return true;
427 }
428 
430 // 3D ELLIPSE
431 #ifdef FIXEDWING_FIRMWARE
432 bool gvf_parametric_3D_ellipse_XYZ(float xo, float yo, float r, float zl, float zh, float alpha)
433 {
434  horizontal_mode = HORIZONTAL_MODE_CIRCLE; // Circle for the 2D GCS
435 
436  // Safety first! If the asked altitude is low
437  if (zl > zh) {
438  zl = zh;
439  }
440  if (zl < 1 || zh < 1) {
441  zl = 10;
442  zh = 10;
443  }
444  if (r < 1) {
445  r = 60;
446  }
447 
457 
458  float f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd;
459 
460  gvf_parametric_3d_ellipse_info(&f1, &f2, &f3, &f1d, &f2d, &f3d, &f1dd, &f2dd, &f3dd);
462  gvf_parametric_3d_ellipse_par.kz, f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd);
463 
464  return true;
465 }
466 
467 bool gvf_parametric_3D_ellipse_wp(uint8_t wp, float r, float zl, float zh, float alpha)
468 {
471 
473  return true;
474 }
475 
476 bool gvf_parametric_3D_ellipse_wp_delta(uint8_t wp, float r, float alt_center, float delta, float alpha)
477 {
478  float zl = alt_center - delta;
479  float zh = alt_center + delta;
480 
482  return true;
483 }
484 
485 // 3D Lissajous
486 
487 bool gvf_parametric_3D_lissajous_XYZ(float xo, float yo, float zo, float cx, float cy, float cz, float wx, float wy,
488  float wz, float dx, float dy, float dz, float alpha)
489 {
490  // Safety first! If the asked altitude is low
491  if ((zo - cz) < 1) {
492  zo = 10;
493  cz = 0;
494  }
495 
512 
513  float f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd;
514 
515  gvf_parametric_3d_lissajous_info(&f1, &f2, &f3, &f1d, &f2d, &f3d, &f1dd, &f2dd, &f3dd);
517  gvf_parametric_3d_lissajous_par.kz, f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd);
518 
519  return true;
520 }
521 
522 bool gvf_parametric_3D_lissajous_wp_center(uint8_t wp, float zo, float cx, float cy, float cz, float wx, float wy,
523  float wz, float dx, float dy, float dz, float alpha)
524 {
527 
528  gvf_parametric_3D_lissajous_XYZ(waypoints[wp].x, waypoints[wp].y, zo, cx, cy, cz, wx, wy, wz, dx, dy, dz, alpha);
529  return true;
530 }
531 #endif // FIXEDWING_FIRMWARE
static void h(const real32_T x[7], const real32_T q[4], real32_T y[6])
static int16_t course[3]
Definition: airspeed_uADC.c:58
Core autopilot interface common to all firmwares.
uint32_t get_sys_time_msec(void)
Get the time in milliseconds since startup.
Definition: sys_time_arch.c:98
struct point waypoints[NB_WAYPOINT]
size == nb_waypoint, waypoint 0 is a dummy waypoint
Definition: common_nav.c:44
#define WaypointX(_wp)
Definition: common_nav.h:45
#define WaypointY(_wp)
Definition: common_nav.h:46
static float ground_speed
Definition: follow_me.c:76
#define E
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:848
static float stateGetHorizontalSpeedNorm_f(void)
Get norm of horizontal ground speed (float).
Definition: state.h:1076
static float stateGetHorizontalSpeedDir_f(void)
Get dir of horizontal ground speed (float).
Definition: state.h:1085
static struct EnuCoor_f * stateGetSpeedEnu_f(void)
Get ground speed in local ENU coordinates (float).
Definition: state.h:1058
gvf_common_omega gvf_c_omega
Definition: gvf_common.c:23
gvf_common_params gvf_c_info
Definition: gvf_common.c:24
gvf_parametric_con gvf_parametric_control
int gvf_parametric_elen
bool gvf_parametric_2D_bezier_wp(uint8_t first_wp)
uint32_t gvf_parametric_splines_ctr
bool gvf_parametric_2D_trefoil_XY(float xo, float yo, float w1, float w2, float ratio, float r, float alpha)
2D TRAJECTORIES
int gvf_parametric_plen_wps
static void send_gvf_parametric(struct transport_tx *trans, struct link_device *dev)
bool gvf_parametric_2D_bezier_XY(void)
bezier_t gvf_bezier_2D[GVF_PARAMETRIC_2D_BEZIER_N_SEG]
uint32_t gvf_parametric_t0
void gvf_parametric_init(void)
gvf_parametric_tra gvf_parametric_trajectory
void gvf_parametric_control_2D(float kx, float ky, float f1, float f2, float f1d, float f2d, float f1dd, float f2dd)
bool gvf_parametric_2D_trefoil_wp(uint8_t wp, float w1, float w2, float ratio, float r, float alpha)
int gvf_parametric_plen
void gvf_parametric_set_direction(int8_t s)
Guiding vector field algorithm for 2D and 3D parametric trajectories.
void gvf_parametric_control_3D(float, float, float, float, float, float, float, float, float, float, float, float)
@ LISSAJOUS_3D
@ BEZIER_2D
@ TREFOIL_2D
@ ELLIPSE_3D
#define GVF_PARAMETRIC_CONTROL_KCLIMB
#define GVF_PARAMETRIC_CONTROL_L
bool gvf_parametric_3D_ellipse_XYZ(float, float, float, float, float, float)
#define GVF_PARAMETRIC_CONTROL_BETA
#define GVF_PARAMETRIC_CONTROL_KROLL
bool gvf_parametric_3D_lissajous_XYZ(float, float, float, float, float, float, float, float, float, float, float, float, float)
#define GVF_PARAMETRIC_CONTROL_KPSI
bool gvf_parametric_3D_ellipse_wp_delta(uint8_t, float, float, float, float)
bool gvf_parametric_3D_lissajous_wp_center(uint8_t, float, float, float, float, float, float, float, float, float, float, float)
enum trajectories_parametric type
bool gvf_parametric_3D_ellipse_wp(uint8_t, float, float, float, float)
void gvf_parametric_2d_bezier_splines_info(bezier_t *bezier, float *f1, float *f2, float *f1d, float *f2d, float *f1dd, float *f2dd)
gvf_par_2d_bezier_par gvf_parametric_2d_bezier_par
void create_bezier_spline(bezier_t *bezier, float *px, float *py)
#define GVF_PARAMETRIC_2D_BEZIER_N_SEG
void gvf_parametric_2d_trefoil_info(float *f1, float *f2, float *f1d, float *f2d, float *f1dd, float *f2dd)
gvf_par_2d_tre_par gvf_parametric_2d_trefoil_par
Guiding vector field algorithm for 2D and 3D complex trajectories.
void gvf_parametric_3d_ellipse_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d, float *f1dd, float *f2dd, float *f3dd)
gvf_par_3d_ell_par gvf_parametric_3d_ellipse_par
Guiding vector field algorithm for 2D and 3D complex trajectories.
gvf_par_3d_lis_par gvf_parametric_3d_lissajous_par
void gvf_parametric_3d_lissajous_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d, float *f1dd, float *f2dd, float *f3dd)
Guiding vector field algorithm for 2D and 3D complex trajectories.
void gvf_parametric_low_level_control_3D(float heading_rate USED_IN_FIXEDWING_ONLY, float climbing_rate USED_IN_FIXEDWING_ONLY)
void gvf_parametric_low_level_control_2D(float heading_rate USED_IN_FIXEDWING_ONLY)
Firmware dependent file for the guiding vector field algorithm for 2D and 3D parametric trajectories.
static uint32_t s
float desired_x
Definition: nav.c:308
float desired_y
Definition: nav.c:308
uint8_t horizontal_mode
Definition: nav.c:70
#define HORIZONTAL_MODE_CIRCLE
Definition: nav.h:92
float y
in meters
float x
in meters
float z
in meters
vector in East North Up coordinates Units: meters
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
float alpha
Definition: textons.c:133
static float I
Definition: trilateration.c:35
static float J
Definition: trilateration.c:35
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
signed char int8_t
Typedef defining 8 bit char type.
Definition: vl53l1_types.h:103