mirror of
https://github.com/paparazzi/paparazzi.git
synced 2026-05-30 03:27:33 +08:00
GVF Parametric (#2559)
Co-authored-by: Hector Garcia de Marina <hgdemarina@gmail.com>
This commit is contained in:
committed by
GitHub
parent
99c8d473aa
commit
f38be8110c
@@ -29,10 +29,12 @@
|
|||||||
|
|
||||||
<variables>
|
<variables>
|
||||||
<variable var="angle_ps" init="0" min="-180" max="179" step="1"/>
|
<variable var="angle_ps" init="0" min="-180" max="179" step="1"/>
|
||||||
|
<variable init="0" max="100" min="0" step="5" var="ell_delta"/>
|
||||||
</variables>
|
</variables>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module name="gvf_module"/>
|
<module name="gvf_module"/>
|
||||||
|
<module name="gvf_parametric"/>
|
||||||
</modules>
|
</modules>
|
||||||
|
|
||||||
<blocks>
|
<blocks>
|
||||||
@@ -78,6 +80,18 @@
|
|||||||
<call_once fun="gvf_nav_survey_polygon_setup(WP_S1, 4, angle_ps, 30, 30, 40, flight_altitude)"/>
|
<call_once fun="gvf_nav_survey_polygon_setup(WP_S1, 4, angle_ps, 30, 30, 40, flight_altitude)"/>
|
||||||
<call fun="gvf_nav_survey_polygon_run()"/>
|
<call fun="gvf_nav_survey_polygon_run()"/>
|
||||||
</block>
|
</block>
|
||||||
|
<block name="3D_ellipse">
|
||||||
|
<call fun="gvf_parametric_3D_ellipse_wp_delta(WP_ELLIPSE,gvf_parametric_3d_ellipse_par.r,flight_altitude-ground_alt,ell_delta,gvf_parametric_3d_ellipse_par.alpha)"/>
|
||||||
|
</block>
|
||||||
|
<block name="3D_lissajous">
|
||||||
|
<call fun="gvf_parametric_3D_lissajous_wp_center(WP_ELLIPSE,flight_altitude-ground_alt,gvf_parametric_3d_lissajous_par.cx, gvf_parametric_3d_lissajous_par.cy, gvf_parametric_3d_lissajous_par.cz, gvf_parametric_3d_lissajous_par.wx, gvf_parametric_3d_lissajous_par.wy, gvf_parametric_3d_lissajous_par.wz, gvf_parametric_3d_lissajous_par.dx, gvf_parametric_3d_lissajous_par.dy, gvf_parametric_3d_lissajous_par.dz, gvf_parametric_3d_lissajous_par.alpha)"/>
|
||||||
|
</block>
|
||||||
|
<block name="2D_trefoil">
|
||||||
|
<call_once fun="NavVerticalAutoThrottleMode(0.0)"/>
|
||||||
|
<call_once fun="NavVerticalAltitudeMode(flight_altitude, 0.0)"/>
|
||||||
|
<call fun="gvf_parametric_2D_trefoil_wp(WP_ELLIPSE,gvf_parametric_2d_trefoil_par.w1,gvf_parametric_2d_trefoil_par.w2,gvf_parametric_2d_trefoil_par.ratio,gvf_parametric_2d_trefoil_par.r, gvf_parametric_2d_trefoil_par.alpha)"/>
|
||||||
|
</block>
|
||||||
|
|
||||||
<block group="land" name="Land Right AF-TD" strip_button="Land right (wp AF-TD)" strip_icon="land-right.png">
|
<block group="land" name="Land Right AF-TD" strip_button="Land right (wp AF-TD)" strip_icon="land-right.png">
|
||||||
<set value="DEFAULT_CIRCLE_RADIUS" var="nav_radius"/>
|
<set value="DEFAULT_CIRCLE_RADIUS" var="nav_radius"/>
|
||||||
<deroute block="land"/>
|
<deroute block="land"/>
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
<!DOCTYPE module SYSTEM "module.dtd">
|
||||||
|
|
||||||
|
<module name="gvf_parametric" dir="guidance/gvf_parametric">
|
||||||
|
<doc>
|
||||||
|
<description>Guidance algorithm for tracking 2D and 3D smooth trajectories that are defined by a parametric equation.
|
||||||
|
|
||||||
|
For more details we refer to https://wiki.paparazziuav.org/wiki/Module/guidance_vector_field .
|
||||||
|
This algorithm needs the Eigen library, be sure you have it installed, e.g., git submodule update --init --recursive sw/ext/eigen
|
||||||
|
</description>
|
||||||
|
</doc>
|
||||||
|
|
||||||
|
<settings name="GVF_PARAMETRIC">
|
||||||
|
<dl_settings>
|
||||||
|
<dl_settings NAME="GVF_PARAMETRIC">
|
||||||
|
<dl_settings NAME="Control">
|
||||||
|
<dl_setting MAX="1" MIN="-1" STEP="2" VAR="gvf_parametric_control.s" shortname = "direction"/>
|
||||||
|
<dl_setting MAX="1.25" MIN="0.75" STEP="0.05" VAR="gvf_parametric_control.k_roll" shortname="k_roll" param="GVF_PARAMETRIC_CONTROL_KROLL"/>
|
||||||
|
<dl_setting MAX="1.25" MIN="0.75" STEP="0.05" VAR="gvf_parametric_control.k_climb" shortname="k_climb" param="GVF_PARAMETRIC_CONTROL_KCLIMB"/>
|
||||||
|
<dl_setting MAX="10" MIN="0.01" STEP="0.05" VAR="gvf_parametric_control.L" shortname="L" param="GVF_PARAMETRIC_CONTROL_L"/>
|
||||||
|
<dl_setting MAX="1" MIN="0.001" STEP="0.005" VAR="gvf_parametric_control.beta" shortname="beta" param="GVF_PARAMETRIC_CONTROL_BETA"/>
|
||||||
|
<dl_setting MAX="1.5" MIN="0.5" STEP="0.01" VAR="gvf_parametric_control.k_psi" shortname="k_psi" param="GVF_PARAMETRIC_CONTROL_KPSI"/>
|
||||||
|
</dl_settings>
|
||||||
|
<dl_settings NAME="2D_trefoil">
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_2d_trefoil_par.kx" shortname="2d_tre_kx" param="GVF_PARAMETRIC_2D_TREFOIL_KX"/>
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_2d_trefoil_par.ky" shortname="2d_tre_ky" param="GVF_PARAMETRIC_2D_TREFOIL_KY"/>
|
||||||
|
<dl_setting MAX="1" MIN="0.0" STEP="0.01" VAR="gvf_parametric_2d_trefoil_par.w1" shortname="2d_tre_w1" param="GVF_PARAMETRIC_2D_TREFOIL_W1"/>
|
||||||
|
<dl_setting MAX="1" MIN="0.0" STEP="0.01" VAR="gvf_parametric_2d_trefoil_par.w2" shortname="2d_tre_w2" param="GVF_PARAMETRIC_2D_TREFOIL_W2"/>
|
||||||
|
<dl_setting MAX="200" MIN="10" STEP="5" VAR="gvf_parametric_2d_trefoil_par.ratio" shortname="2d_tre_ratio" param="GVF_PARAMETRIC_2D_TREFOIL_RATIO"/>
|
||||||
|
<dl_setting MAX="200" MIN="10" STEP="5" VAR="gvf_parametric_2d_trefoil_par.r" shortname="2d_tre_r" param="GVF_PARAMETRIC_2D_TREFOIL_R"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180" STEP="1" VAR="gvf_parametric_2d_trefoil_par.alpha" shortname="2d_tre_alpha" param="GVF_PARAMETRIC_2D_TREFOIL_ALPHA"/>
|
||||||
|
</dl_settings>
|
||||||
|
<dl_settings NAME="3D_ellipse">
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_ellipse_par.kx" shortname="3d_ell_kx" param="GVF_PARAMETRIC_3D_ELLIPSE_KX"/>
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_ellipse_par.ky" shortname="3d_ell_ky" param="GVF_PARAMETRIC_3D_ELLIPSE_KY"/>
|
||||||
|
<dl_setting MAX="0.1" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_ellipse_par.kz" shortname="3d_ell_kz" param="GVF_PARAMETRIC_3D_ELLIPSE_KZ"/>
|
||||||
|
<dl_setting MAX="150" MIN="0.0" STEP="5" VAR="gvf_parametric_3d_ellipse_par.r" shortname="3d_ell_r" param="GVF_PARAMETRIC_3D_ELLIPSE_R"/>
|
||||||
|
<dl_setting MAX="150" MIN="10" STEP="5" VAR="gvf_parametric_3d_ellipse_par.zl" shortname="3d_ell_zl" param="GVF_PARAMETRIC_3D_ELLIPSE_ZL"/>
|
||||||
|
<dl_setting MAX="150" MIN="10" STEP="5" VAR="gvf_parametric_3d_ellipse_par.zh" shortname="3d_ell_zh" param="GVF_PARAMETRIC_3D_ELLIPSE_ZH"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180" STEP="1" VAR="gvf_parametric_3d_ellipse_par.alpha" shortname="3d_ell_alpha" param="GVF_PARAMETRIC_3D_ELLIPSE_ALPHA"/>
|
||||||
|
</dl_settings>
|
||||||
|
<dl_settings NAME="3D_lissajous">
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_lissajous_par.kx" shortname="3d_lis_kx" param="GVF_PARAMETRIC_3D_LISSAJOUS_KX"/>
|
||||||
|
<dl_setting MAX="0.01" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_lissajous_par.ky" shortname="3d_lis_ky" param="GVF_PARAMETRIC_3D_LISSAJOUS_KY"/>
|
||||||
|
<dl_setting MAX="0.1" MIN="0.0" STEP="0.0005" VAR="gvf_parametric_3d_lissajous_par.kz" shortname="3d_lis_kz" param="GVF_PARAMETRIC_3D_LISSAJOUS_KZ"/>
|
||||||
|
<dl_setting MAX="250" MIN="-250" STEP="5" VAR="gvf_parametric_3d_lissajous_par.cx" shortname="3d_lis_cx" param="GVF_PARAMETRIC_3D_LISSAJOUS_CX"/>
|
||||||
|
<dl_setting MAX="250" MIN="-250" STEP="5" VAR="gvf_parametric_3d_lissajous_par.cy" shortname="3d_lis_cy" param="GVF_PARAMETRIC_3D_LISSAJOUS_CY"/>
|
||||||
|
<dl_setting MAX="50" MIN="-50" STEP="5" VAR="gvf_parametric_3d_lissajous_par.cz" shortname="3d_lis_cz" param="GVF_PARAMETRIC_3D_LISSAJOUS_CZ"/>
|
||||||
|
<dl_setting MAX="10" MIN="-10.0" STEP="0.5" VAR="gvf_parametric_3d_lissajous_par.wx" shortname="3d_lis_wx" param="GVF_PARAMETRIC_3D_LISSAJOUS_WX"/>
|
||||||
|
<dl_setting MAX="10" MIN="-10" STEP="0.5" VAR="gvf_parametric_3d_lissajous_par.wy" shortname="3d_lis_wy" param="GVF_PARAMETRIC_3D_LISSAJOUS_WY"/>
|
||||||
|
<dl_setting MAX="10" MIN="-10" STEP="0.5" VAR="gvf_parametric_3d_lissajous_par.wz" shortname="3d_lis_wz" param="GVF_PARAMETRIC_3D_LISSAJOUS_WZ"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180.0" STEP="1" VAR="gvf_parametric_3d_lissajous_par.dx" shortname="3d_lis_dx" param="GVF_PARAMETRIC_3D_LISSAJOUS_DX"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180" STEP="1" VAR="gvf_parametric_3d_lissajous_par.dy" shortname="3d_lis_dy" param="GVF_PARAMETRIC_3D_LISSAJOUS_DY"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180" STEP="1" VAR="gvf_parametric_3d_lissajous_par.dz" shortname="3d_lis_dz" param="GVF_PARAMETRIC_3D_LISSAJOUS_DZ"/>
|
||||||
|
<dl_setting MAX="180" MIN="-180" STEP="1" VAR="gvf_parametric_3d_lissajous_par.alpha" shortname="3d_lis_alpha" param="GVF_PARAMETRIC_3D_LISSAJOUS_ALPHA"/>
|
||||||
|
</dl_settings>
|
||||||
|
</dl_settings>
|
||||||
|
</dl_settings>
|
||||||
|
</settings>
|
||||||
|
|
||||||
|
<header>
|
||||||
|
<file name="gvf_parametric.h"/>
|
||||||
|
<file name="gvf_parametric_low_level_control.h"/>
|
||||||
|
<file name="trajectories/gvf_parametric_3d_ellipse.h"/>
|
||||||
|
<file name="trajectories/gvf_parametric_3d_lissajous.h"/>
|
||||||
|
<file name="trajectories/gvf_parametric_2d_trefoil.h"/>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<init fun = "gvf_parametric_init()"/>
|
||||||
|
|
||||||
|
<makefile target="ap|nps" firmware="fixedwing">
|
||||||
|
<configure name="CXXSTANDARD" value="-std=c++14"/>
|
||||||
|
<flag name="CXXFLAGS" value="Wno-int-in-bool-context -Wno-deprecated-copy"/>
|
||||||
|
<include name="$(PAPARAZZI_SRC)/sw/ext/eigen"/>
|
||||||
|
<define name="EIGEN_NO_MALLOC"/>
|
||||||
|
<define name="EIGEN_NO_AUTOMATIC_RESIZING"/>
|
||||||
|
<file name="gvf_parametric.cpp"/>
|
||||||
|
<file name="gvf_parametric_low_level_control.c"/>
|
||||||
|
<file name="trajectories/gvf_parametric_3d_ellipse.c"/>
|
||||||
|
<file name="trajectories/gvf_parametric_3d_lissajous.c"/>
|
||||||
|
<file name="trajectories/gvf_parametric_2d_trefoil.c"/>
|
||||||
|
<flag name="LDFLAGS" value="lstdc++" />
|
||||||
|
</makefile>
|
||||||
|
|
||||||
|
<makefile target="ap" firmware="fixedwing">
|
||||||
|
<define name="EIGEN_NO_DEBUG"/>
|
||||||
|
</makefile>
|
||||||
|
</module>
|
||||||
@@ -32,6 +32,7 @@
|
|||||||
<message name="AIR_DATA" period="1.3"/>
|
<message name="AIR_DATA" period="1.3"/>
|
||||||
<message name="VECTORNAV_INFO" period="0.5"/>
|
<message name="VECTORNAV_INFO" period="0.5"/>
|
||||||
<message name="GVF" period="1"/>
|
<message name="GVF" period="1"/>
|
||||||
|
<message name="GVF_PARAMETRIC" period="1"/>
|
||||||
</mode>
|
</mode>
|
||||||
<mode name="minimal">
|
<mode name="minimal">
|
||||||
<message name="ALIVE" period="5"/>
|
<message name="ALIVE" period="5"/>
|
||||||
|
|||||||
@@ -40,6 +40,9 @@ gvf_con gvf_control;
|
|||||||
gvf_tra gvf_trajectory;
|
gvf_tra gvf_trajectory;
|
||||||
gvf_seg gvf_segment;
|
gvf_seg gvf_segment;
|
||||||
|
|
||||||
|
// Time variables to check if GVF is active
|
||||||
|
uint32_t gvf_t0 = 0;
|
||||||
|
|
||||||
#if PERIODIC_TELEMETRY
|
#if PERIODIC_TELEMETRY
|
||||||
#include "subsystems/datalink/telemetry.h"
|
#include "subsystems/datalink/telemetry.h"
|
||||||
static void send_gvf(struct transport_tx *trans, struct link_device *dev)
|
static void send_gvf(struct transport_tx *trans, struct link_device *dev)
|
||||||
@@ -65,27 +68,39 @@ static void send_gvf(struct transport_tx *trans, struct link_device *dev)
|
|||||||
|
|
||||||
uint8_t traj_type = (uint8_t)gvf_trajectory.type;
|
uint8_t traj_type = (uint8_t)gvf_trajectory.type;
|
||||||
|
|
||||||
pprz_msg_send_GVF(trans, dev, AC_ID, &gvf_control.error, &traj_type,
|
uint32_t now = get_sys_time_msec();
|
||||||
&gvf_control.s, &gvf_control.ke, plen, gvf_trajectory.p);
|
uint32_t delta_T = now - gvf_t0;
|
||||||
|
|
||||||
|
if (delta_T < 200)
|
||||||
|
pprz_msg_send_GVF(trans, dev, AC_ID, &gvf_control.error, &traj_type,
|
||||||
|
&gvf_control.s, &gvf_control.ke, plen, gvf_trajectory.p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_circle(struct transport_tx *trans, struct link_device *dev)
|
static void send_circle(struct transport_tx *trans, struct link_device *dev)
|
||||||
{
|
{
|
||||||
if (gvf_trajectory.type == ELLIPSE &&
|
uint32_t now = get_sys_time_msec();
|
||||||
(gvf_trajectory.p[2] == gvf_trajectory.p[3])) {
|
uint32_t delta_T = now - gvf_t0;
|
||||||
pprz_msg_send_CIRCLE(trans, dev, AC_ID,
|
|
||||||
&gvf_trajectory.p[0], &gvf_trajectory.p[1],
|
if (delta_T < 200)
|
||||||
&gvf_trajectory.p[2]);
|
if (gvf_trajectory.type == ELLIPSE &&
|
||||||
}
|
(gvf_trajectory.p[2] == gvf_trajectory.p[3])) {
|
||||||
|
pprz_msg_send_CIRCLE(trans, dev, AC_ID,
|
||||||
|
&gvf_trajectory.p[0], &gvf_trajectory.p[1],
|
||||||
|
&gvf_trajectory.p[2]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void send_segment(struct transport_tx *trans, struct link_device *dev)
|
static void send_segment(struct transport_tx *trans, struct link_device *dev)
|
||||||
{
|
{
|
||||||
if (gvf_trajectory.type == LINE && gvf_segment.seg == 1) {
|
uint32_t now = get_sys_time_msec();
|
||||||
pprz_msg_send_SEGMENT(trans, dev, AC_ID,
|
uint32_t delta_T = now - gvf_t0;
|
||||||
&gvf_segment.x1, &gvf_segment.y1,
|
|
||||||
&gvf_segment.x2, &gvf_segment.y2);
|
if (delta_T < 200)
|
||||||
}
|
if (gvf_trajectory.type == LINE && gvf_segment.seg == 1) {
|
||||||
|
pprz_msg_send_SEGMENT(trans, dev, AC_ID,
|
||||||
|
&gvf_segment.x1, &gvf_segment.y1,
|
||||||
|
&gvf_segment.x2, &gvf_segment.y2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -139,6 +154,8 @@ void gvf_init(void)
|
|||||||
void gvf_control_2D(float ke, float kn, float e,
|
void gvf_control_2D(float ke, float kn, float e,
|
||||||
struct gvf_grad *grad, struct gvf_Hess *hess)
|
struct gvf_grad *grad, struct gvf_Hess *hess)
|
||||||
{
|
{
|
||||||
|
gvf_t0 = get_sys_time_msec();
|
||||||
|
|
||||||
struct FloatEulers *att = stateGetNedToBodyEulers_f();
|
struct FloatEulers *att = stateGetNedToBodyEulers_f();
|
||||||
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
||||||
float course = stateGetHorizontalSpeedDir_f();
|
float course = stateGetHorizontalSpeedDir_f();
|
||||||
|
|||||||
@@ -32,8 +32,8 @@
|
|||||||
|
|
||||||
#include "std.h"
|
#include "std.h"
|
||||||
|
|
||||||
/** @typedef gvf_conf
|
/** @typedef gvf_con
|
||||||
* @brief Parameters for the GVF
|
* @brief Control parameters for the GVF
|
||||||
* @param ke Gain defining how agressive is the vector field
|
* @param ke Gain defining how agressive is the vector field
|
||||||
* @param kn Gain for making converge the vehile to the vector field
|
* @param kn Gain for making converge the vehile to the vector field
|
||||||
* @param error Error signal. It does not have any specific units. It depends on how the trajectory has been implemented. Check the specific wiki entry for each trajectory.
|
* @param error Error signal. It does not have any specific units. It depends on how the trajectory has been implemented. Check the specific wiki entry for each trajectory.
|
||||||
|
|||||||
@@ -0,0 +1,440 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/gvf_parametric.cpp
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <Eigen/Dense>
|
||||||
|
|
||||||
|
#include "gvf_parametric.h"
|
||||||
|
#include "gvf_parametric_low_level_control.h"
|
||||||
|
#include "./trajectories/gvf_parametric_3d_ellipse.h"
|
||||||
|
#include "./trajectories/gvf_parametric_3d_lissajous.h"
|
||||||
|
#include "./trajectories/gvf_parametric_2d_trefoil.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "autopilot.h"
|
||||||
|
|
||||||
|
// Control
|
||||||
|
uint32_t gvf_parametric_t0 = 0; // We need it for calculting the time lapse delta_T
|
||||||
|
gvf_parametric_con gvf_parametric_control;
|
||||||
|
|
||||||
|
// Trajectory
|
||||||
|
gvf_parametric_tra gvf_parametric_trajectory;
|
||||||
|
|
||||||
|
#if PERIODIC_TELEMETRY
|
||||||
|
#include "subsystems/datalink/telemetry.h"
|
||||||
|
static void send_gvf_parametric(struct transport_tx *trans, struct link_device *dev)
|
||||||
|
{
|
||||||
|
// Do not know whether is a good idea to do this check here or to include
|
||||||
|
// this plen in gvf_trajectory
|
||||||
|
int plen;
|
||||||
|
int elen;
|
||||||
|
|
||||||
|
switch (gvf_parametric_trajectory.type) {
|
||||||
|
case TREFOIL_2D:
|
||||||
|
plen = 7;
|
||||||
|
elen = 2;
|
||||||
|
break;
|
||||||
|
case ELLIPSE_3D:
|
||||||
|
plen = 6;
|
||||||
|
elen = 3;
|
||||||
|
break;
|
||||||
|
case LISSAJOUS_3D:
|
||||||
|
plen = 13;
|
||||||
|
elen = 3;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
plen = 1;
|
||||||
|
elen = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t traj_type = (uint8_t)gvf_parametric_trajectory.type;
|
||||||
|
|
||||||
|
uint32_t now = get_sys_time_msec();
|
||||||
|
uint32_t delta_T = now - gvf_parametric_t0;
|
||||||
|
|
||||||
|
float wb = gvf_parametric_control.w * gvf_parametric_control.beta;
|
||||||
|
|
||||||
|
if (delta_T < 200) {
|
||||||
|
pprz_msg_send_GVF_PARAMETRIC(trans, dev, AC_ID, &traj_type, &gvf_parametric_control.s, &wb, plen,
|
||||||
|
gvf_parametric_trajectory.p_parametric, elen, gvf_parametric_trajectory.phi_errors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void send_circle_parametric(struct transport_tx *trans, struct link_device *dev)
|
||||||
|
{
|
||||||
|
uint32_t now = get_sys_time_msec();
|
||||||
|
uint32_t delta_T = now - gvf_parametric_t0;
|
||||||
|
|
||||||
|
if (delta_T < 200)
|
||||||
|
if (gvf_parametric_trajectory.type == ELLIPSE_3D) {
|
||||||
|
pprz_msg_send_CIRCLE(trans, dev, AC_ID, &gvf_parametric_trajectory.p_parametric[0],
|
||||||
|
&gvf_parametric_trajectory.p_parametric[1], &gvf_parametric_trajectory.p_parametric[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // PERIODIC TELEMETRY
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gvf_parametric_init(void)
|
||||||
|
{
|
||||||
|
gvf_parametric_control.w = 0;
|
||||||
|
gvf_parametric_control.delta_T = 0;
|
||||||
|
gvf_parametric_control.s = 1;
|
||||||
|
gvf_parametric_control.k_roll = GVF_PARAMETRIC_CONTROL_KROLL;
|
||||||
|
gvf_parametric_control.k_climb = GVF_PARAMETRIC_CONTROL_KCLIMB;
|
||||||
|
gvf_parametric_control.k_psi = GVF_PARAMETRIC_CONTROL_KPSI;
|
||||||
|
gvf_parametric_control.L = GVF_PARAMETRIC_CONTROL_L;
|
||||||
|
gvf_parametric_control.beta = GVF_PARAMETRIC_CONTROL_BETA;
|
||||||
|
|
||||||
|
#if PERIODIC_TELEMETRY
|
||||||
|
register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_GVF_PARAMETRIC, send_gvf_parametric);
|
||||||
|
register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_CIRCLE, send_circle_parametric);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void gvf_parametric_set_direction(int8_t s)
|
||||||
|
{
|
||||||
|
gvf_parametric_control.s = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gvf_parametric_control_2D(float kx, float ky, float f1, float f2, float f1d, float f2d, float f1dd, float f2dd)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint32_t now = get_sys_time_msec();
|
||||||
|
gvf_parametric_control.delta_T = now - gvf_parametric_t0;
|
||||||
|
gvf_parametric_t0 = now;
|
||||||
|
|
||||||
|
if (gvf_parametric_control.delta_T > 300) { // We need at least two iterations for Delta_T
|
||||||
|
gvf_parametric_control.w = 0; // Reset w since we assume the algorithm starts
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float L = gvf_parametric_control.L;
|
||||||
|
float beta = gvf_parametric_control.beta * gvf_parametric_control.s;
|
||||||
|
|
||||||
|
Eigen::Vector3f X;
|
||||||
|
Eigen::Matrix3f J;
|
||||||
|
|
||||||
|
// Error signals phi_x and phi_y
|
||||||
|
struct EnuCoor_f *pos_enu = stateGetPositionEnu_f();
|
||||||
|
float x = pos_enu->x;
|
||||||
|
float y = pos_enu->y;
|
||||||
|
|
||||||
|
float phi1 = L * (x - f1);
|
||||||
|
float phi2 = L * (y - f2);
|
||||||
|
|
||||||
|
gvf_parametric_trajectory.phi_errors[0] = phi1; // Error signals for the telemetry
|
||||||
|
gvf_parametric_trajectory.phi_errors[1] = phi2;
|
||||||
|
|
||||||
|
// Chi
|
||||||
|
X(0) = L * beta * f1d - kx * phi1;
|
||||||
|
X(1) = L * beta * f2d - ky * phi2;
|
||||||
|
X(2) = L + beta * (kx * phi1 * f1d + ky * phi2 * f2d);
|
||||||
|
X *= L;
|
||||||
|
|
||||||
|
// Jacobian
|
||||||
|
J.setZero();
|
||||||
|
J(0, 0) = -kx * L;
|
||||||
|
J(1, 1) = -ky * L;
|
||||||
|
J(2, 0) = (beta * L) * (beta * f1dd + kx * f1d);
|
||||||
|
J(2, 1) = (beta * L) * (beta * f2dd + ky * f2d);
|
||||||
|
J(2, 2) = beta * beta * (kx * (phi1 * f1dd - L * f1d * f1d) + ky * (phi2 * f2dd - L * f2d * f2d));
|
||||||
|
J *= L;
|
||||||
|
|
||||||
|
// Guidance algorithm
|
||||||
|
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
||||||
|
float w_dot = (ground_speed * X(2)) / sqrtf(X(0) * X(0) + X(1) * X(1));
|
||||||
|
|
||||||
|
Eigen::Vector3f xi_dot;
|
||||||
|
struct EnuCoor_f *vel_enu = stateGetSpeedEnu_f();
|
||||||
|
float course = stateGetHorizontalSpeedDir_f();
|
||||||
|
|
||||||
|
xi_dot << vel_enu->x, vel_enu->y, w_dot;
|
||||||
|
|
||||||
|
Eigen::Matrix3f G;
|
||||||
|
Eigen::Matrix3f Gp;
|
||||||
|
Eigen::Matrix<float, 2, 3> Fp;
|
||||||
|
Eigen::Vector2f h;
|
||||||
|
Eigen::Matrix<float, 1, 2> ht;
|
||||||
|
|
||||||
|
G << 1, 0, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 0, 0;
|
||||||
|
Fp << 0, -1, 0,
|
||||||
|
1, 0, 0;
|
||||||
|
Gp << 0, -1, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
0, 0, 0;
|
||||||
|
|
||||||
|
h << sinf(course), cosf(course);
|
||||||
|
ht = h.transpose();
|
||||||
|
|
||||||
|
Eigen::Matrix<float, 1, 3> Xt = X.transpose();
|
||||||
|
Eigen::Vector3f Xh = X / X.norm();
|
||||||
|
Eigen::Matrix<float, 1, 3> Xht = Xh.transpose();
|
||||||
|
Eigen::Matrix3f I;
|
||||||
|
I.setIdentity();
|
||||||
|
|
||||||
|
float aux = ht * Fp * X;
|
||||||
|
float heading_rate = -1 / (Xt * G * X) * Xt * Gp * (I - Xh * Xht) * J * xi_dot - (gvf_parametric_control.k_psi * aux /
|
||||||
|
sqrtf(Xt * G * X));
|
||||||
|
|
||||||
|
// Virtual coordinate update, even if the vehicle is not in autonomous mode, the parameter w will get "closer" to
|
||||||
|
// the vehicle. So it is not only okei but advisable to update it.
|
||||||
|
gvf_parametric_control.w += w_dot * gvf_parametric_control.delta_T * 1e-3;
|
||||||
|
|
||||||
|
gvf_parametric_low_level_control_2D(heading_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gvf_parametric_control_3D(float kx, float ky, float kz, float f1, float f2, float f3, float f1d, float f2d,
|
||||||
|
float f3d, float f1dd, float f2dd, float f3dd)
|
||||||
|
{
|
||||||
|
uint32_t now = get_sys_time_msec();
|
||||||
|
gvf_parametric_control.delta_T = now - gvf_parametric_t0;
|
||||||
|
gvf_parametric_t0 = now;
|
||||||
|
|
||||||
|
if (gvf_parametric_control.delta_T > 300) { // We need at least two iterations for Delta_T
|
||||||
|
gvf_parametric_control.w = 0; // Reset w since we assume the algorithm starts
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
float L = gvf_parametric_control.L;
|
||||||
|
float beta = gvf_parametric_control.beta * gvf_parametric_control.s;
|
||||||
|
|
||||||
|
Eigen::Vector4f X;
|
||||||
|
Eigen::Matrix4f J;
|
||||||
|
|
||||||
|
// Error signals phi_x phi_y and phi_z
|
||||||
|
struct EnuCoor_f *pos_enu = stateGetPositionEnu_f();
|
||||||
|
float x = pos_enu->x;
|
||||||
|
float y = pos_enu->y;
|
||||||
|
float z = pos_enu->z;
|
||||||
|
|
||||||
|
float phi1 = L * (x - f1);
|
||||||
|
float phi2 = L * (y - f2);
|
||||||
|
float phi3 = L * (z - f3);
|
||||||
|
|
||||||
|
gvf_parametric_trajectory.phi_errors[0] = phi1 / L; // Error signals in meters for the telemetry
|
||||||
|
gvf_parametric_trajectory.phi_errors[1] = phi2 / L;
|
||||||
|
gvf_parametric_trajectory.phi_errors[2] = phi3 / L;
|
||||||
|
|
||||||
|
// Chi
|
||||||
|
X(0) = -f1d * L * L * beta - kx * phi1;
|
||||||
|
X(1) = -f2d * L * L * beta - ky * phi2;
|
||||||
|
X(2) = -f3d * L * L * beta - kz * phi3;
|
||||||
|
X(3) = -L * L + beta * (kx * phi1 * f1d + ky * phi2 * f2d + kz * phi3 * f3d);
|
||||||
|
X *= L;
|
||||||
|
|
||||||
|
// Jacobian
|
||||||
|
J.setZero();
|
||||||
|
J(0, 0) = -kx * L;
|
||||||
|
J(1, 1) = -ky * L;
|
||||||
|
J(2, 2) = -kz * L;
|
||||||
|
J(3, 0) = kx * f1d * beta * L;
|
||||||
|
J(3, 1) = ky * f2d * beta * L;
|
||||||
|
J(3, 2) = kz * f3d * beta * L;
|
||||||
|
J(0, 3) = -(beta * L) * (beta * L * f1dd - kx * f1d);
|
||||||
|
J(1, 3) = -(beta * L) * (beta * L * f2dd - ky * f2d);
|
||||||
|
J(2, 3) = -(beta * L) * (beta * L * f3dd - kz * f3d);
|
||||||
|
J(3, 3) = beta * beta * (kx * (phi1 * f1dd - L * f1d * f1d) + ky * (phi2 * f2dd - L * f2d * f2d)
|
||||||
|
+ kz * (phi3 * f3dd - L * f3d * f3d));
|
||||||
|
J *= L;
|
||||||
|
|
||||||
|
// Guidance algorithm
|
||||||
|
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
||||||
|
float w_dot = (ground_speed * X(3)) / sqrtf(X(0) * X(0) + X(1) * X(1));
|
||||||
|
|
||||||
|
Eigen::Vector4f xi_dot;
|
||||||
|
struct EnuCoor_f *vel_enu = stateGetSpeedEnu_f();
|
||||||
|
float course = stateGetHorizontalSpeedDir_f();
|
||||||
|
|
||||||
|
xi_dot << vel_enu->x, vel_enu->y, vel_enu->z, w_dot;
|
||||||
|
|
||||||
|
Eigen::Matrix2f E;
|
||||||
|
Eigen::Matrix<float, 2, 4> F;
|
||||||
|
Eigen::Matrix<float, 2, 4> Fp;
|
||||||
|
Eigen::Matrix4f G;
|
||||||
|
Eigen::Matrix4f Gp;
|
||||||
|
Eigen::Matrix4f I;
|
||||||
|
Eigen::Vector2f h;
|
||||||
|
Eigen::Matrix<float, 1, 2> ht;
|
||||||
|
|
||||||
|
h << sinf(course), cosf(course);
|
||||||
|
ht = h.transpose();
|
||||||
|
I.setIdentity();
|
||||||
|
F << 1.0, 0.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0, 0.0;
|
||||||
|
E << 0.0, -1.0,
|
||||||
|
1.0, 0.0;
|
||||||
|
G = F.transpose() * F;
|
||||||
|
Fp = E * F;
|
||||||
|
Gp = F.transpose() * E * F;
|
||||||
|
|
||||||
|
Eigen::Matrix<float, 1, 4> Xt = X.transpose();
|
||||||
|
Eigen::Vector4f Xh = X / X.norm();
|
||||||
|
Eigen::Matrix<float, 1, 4> Xht = Xh.transpose();
|
||||||
|
|
||||||
|
float aux = ht * Fp * X;
|
||||||
|
|
||||||
|
float heading_rate = -1 / (Xt * G * X) * Xt * Gp * (I - Xh * Xht) * J * xi_dot - (gvf_parametric_control.k_psi * aux /
|
||||||
|
sqrtf(Xt * G * X));
|
||||||
|
float climbing_rate = (ground_speed * X(2)) / sqrtf(X(0) * X(0) + X(1) * X(1));
|
||||||
|
|
||||||
|
// Virtual coordinate update, even if the vehicle is not in autonomous mode, the parameter w will get "closer" to
|
||||||
|
// the vehicle. So it is not only okei but advisable to update it.
|
||||||
|
gvf_parametric_control.w += w_dot * gvf_parametric_control.delta_T * 1e-3;
|
||||||
|
|
||||||
|
gvf_parametric_low_level_control_3D(heading_rate, climbing_rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 2D TRAJECTORIES **/
|
||||||
|
// 2D TREFOIL KNOT
|
||||||
|
|
||||||
|
bool gvf_parametric_2D_trefoil_XY(float xo, float yo, float w1, float w2, float ratio, float r, float alpha)
|
||||||
|
{
|
||||||
|
gvf_parametric_trajectory.type = TREFOIL_2D;
|
||||||
|
gvf_parametric_trajectory.p_parametric[0] = xo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[1] = yo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[2] = w1;
|
||||||
|
gvf_parametric_trajectory.p_parametric[3] = w2;
|
||||||
|
gvf_parametric_trajectory.p_parametric[4] = ratio;
|
||||||
|
gvf_parametric_trajectory.p_parametric[5] = r;
|
||||||
|
gvf_parametric_trajectory.p_parametric[6] = alpha;
|
||||||
|
|
||||||
|
float f1, f2, f1d, f2d, f1dd, f2dd;
|
||||||
|
|
||||||
|
gvf_parametric_2d_trefoil_info(&f1, &f2, &f1d, &f2d, &f1dd, &f2dd);
|
||||||
|
gvf_parametric_control_2D(gvf_parametric_2d_trefoil_par.kx, gvf_parametric_2d_trefoil_par.ky, f1, f2, f1d, f2d, f1dd,
|
||||||
|
f2dd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gvf_parametric_2D_trefoil_wp(uint8_t wp, float w1, float w2, float ratio, float r, float alpha)
|
||||||
|
{
|
||||||
|
gvf_parametric_2D_trefoil_XY(waypoints[wp].x, waypoints[wp].y, w1, w2, ratio, r, alpha);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 3D TRAJECTORIES **/
|
||||||
|
// 3D ELLIPSE
|
||||||
|
|
||||||
|
bool gvf_parametric_3D_ellipse_XYZ(float xo, float yo, float r, float zl, float zh, float alpha)
|
||||||
|
{
|
||||||
|
horizontal_mode = HORIZONTAL_MODE_CIRCLE; // Circle for the 2D GCS
|
||||||
|
|
||||||
|
// Safety first! If the asked altitude is low
|
||||||
|
if (zl > zh) {
|
||||||
|
zl = zh;
|
||||||
|
}
|
||||||
|
if (zl < 1 || zh < 1) {
|
||||||
|
zl = 10;
|
||||||
|
zh = 10;
|
||||||
|
}
|
||||||
|
if (r < 1) {
|
||||||
|
r = 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
gvf_parametric_trajectory.type = ELLIPSE_3D;
|
||||||
|
gvf_parametric_trajectory.p_parametric[0] = xo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[1] = yo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[2] = r;
|
||||||
|
gvf_parametric_trajectory.p_parametric[3] = zl;
|
||||||
|
gvf_parametric_trajectory.p_parametric[4] = zh;
|
||||||
|
gvf_parametric_trajectory.p_parametric[5] = alpha;
|
||||||
|
|
||||||
|
float f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd;
|
||||||
|
|
||||||
|
gvf_parametric_3d_ellipse_info(&f1, &f2, &f3, &f1d, &f2d, &f3d, &f1dd, &f2dd, &f3dd);
|
||||||
|
gvf_parametric_control_3D(gvf_parametric_3d_ellipse_par.kx, gvf_parametric_3d_ellipse_par.ky,
|
||||||
|
gvf_parametric_3d_ellipse_par.kz, f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gvf_parametric_3D_ellipse_wp(uint8_t wp, float r, float zl, float zh, float alpha)
|
||||||
|
{
|
||||||
|
gvf_parametric_3D_ellipse_XYZ(waypoints[wp].x, waypoints[wp].y, r, zl, zh, alpha);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gvf_parametric_3D_ellipse_wp_delta(uint8_t wp, float r, float alt_center, float delta, float alpha)
|
||||||
|
{
|
||||||
|
float zl = alt_center - delta;
|
||||||
|
float zh = alt_center + delta;
|
||||||
|
|
||||||
|
gvf_parametric_3D_ellipse_XYZ(waypoints[wp].x, waypoints[wp].y, r, zl, zh, alpha);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3D Lissajous
|
||||||
|
|
||||||
|
bool gvf_parametric_3D_lissajous_XYZ(float xo, float yo, float zo, float cx, float cy, float cz, float wx, float wy,
|
||||||
|
float wz, float dx, float dy, float dz, float alpha)
|
||||||
|
{
|
||||||
|
// Safety first! If the asked altitude is low
|
||||||
|
if ((zo - cz) < 1) {
|
||||||
|
zo = 10;
|
||||||
|
cz = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gvf_parametric_trajectory.type = LISSAJOUS_3D;
|
||||||
|
gvf_parametric_trajectory.p_parametric[0] = xo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[1] = yo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[2] = zo;
|
||||||
|
gvf_parametric_trajectory.p_parametric[3] = cx;
|
||||||
|
gvf_parametric_trajectory.p_parametric[4] = cy;
|
||||||
|
gvf_parametric_trajectory.p_parametric[5] = cz;
|
||||||
|
gvf_parametric_trajectory.p_parametric[6] = wx;
|
||||||
|
gvf_parametric_trajectory.p_parametric[7] = wy;
|
||||||
|
gvf_parametric_trajectory.p_parametric[8] = wz;
|
||||||
|
gvf_parametric_trajectory.p_parametric[9] = dx;
|
||||||
|
gvf_parametric_trajectory.p_parametric[10] = dy;
|
||||||
|
gvf_parametric_trajectory.p_parametric[11] = dz;
|
||||||
|
gvf_parametric_trajectory.p_parametric[12] = alpha;
|
||||||
|
|
||||||
|
float f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd;
|
||||||
|
|
||||||
|
gvf_parametric_3d_lissajous_info(&f1, &f2, &f3, &f1d, &f2d, &f3d, &f1dd, &f2dd, &f3dd);
|
||||||
|
gvf_parametric_control_3D(gvf_parametric_3d_lissajous_par.kx, gvf_parametric_3d_lissajous_par.ky,
|
||||||
|
gvf_parametric_3d_lissajous_par.kz, f1, f2, f3, f1d, f2d, f3d, f1dd, f2dd, f3dd);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gvf_parametric_3D_lissajous_wp_center(uint8_t wp, float zo, float cx, float cy, float cz, float wx, float wy,
|
||||||
|
float wz, float dx, float dy, float dz, float alpha)
|
||||||
|
{
|
||||||
|
gvf_parametric_3D_lissajous_XYZ(waypoints[wp].x, waypoints[wp].y, zo, cx, cy, cz, wx, wy, wz, dx, dy, dz, alpha);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/gvf_parametric.h
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D parametric trajectories.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GVF_PARAMETRIC_H
|
||||||
|
#define GVF_PARAMETRIC_H
|
||||||
|
|
||||||
|
#define GVF_PARAMETRIC_GRAVITY 9.806
|
||||||
|
|
||||||
|
/*! Default gain kroll for tuning the "coordinated turn" */
|
||||||
|
#ifndef GVF_PARAMETRIC_CONTROL_KROLL
|
||||||
|
#define GVF_PARAMETRIC_CONTROL_KROLL 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain kclimb for tuning the climbing setting point */
|
||||||
|
#ifndef GVF_PARAMETRIC_CONTROL_KCLIMB
|
||||||
|
#define GVF_PARAMETRIC_CONTROL_KCLIMB 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default scale for the error signals */
|
||||||
|
#ifndef GVF_PARAMETRIC_CONTROL_L
|
||||||
|
#define GVF_PARAMETRIC_CONTROL_L 0.1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default scale for w */
|
||||||
|
#ifndef GVF_PARAMETRIC_CONTROL_BETA
|
||||||
|
#define GVF_PARAMETRIC_CONTROL_BETA 0.01
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain kpsi for tuning the alignment of the vehicle with the vector field */
|
||||||
|
#ifndef GVF_PARAMETRIC_CONTROL_KPSI
|
||||||
|
#define GVF_PARAMETRIC_CONTROL_KPSI 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_ellipse.h"
|
||||||
|
#include "modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_lissajous.h"
|
||||||
|
#include "modules/guidance/gvf_parametric/trajectories/gvf_parametric_2d_trefoil.h"
|
||||||
|
|
||||||
|
/** @typedef gvf_parametric_con
|
||||||
|
* @brief Control parameters for the GVF_PARAMETRIC
|
||||||
|
* @param w Virtual coordinate from the parametrization of the trajectory
|
||||||
|
* @param delta_T Time between iterations needed for integrating w
|
||||||
|
* @param s Defines the direction to be tracked. It takes the values -1 or 1.
|
||||||
|
* @param k_roll Gain for tuning the coordinated turn.
|
||||||
|
* @param k_climb Gain for tuning the climbing setting point.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
float w;
|
||||||
|
float delta_T;
|
||||||
|
int8_t s;
|
||||||
|
float k_roll;
|
||||||
|
float k_climb;
|
||||||
|
float k_psi;
|
||||||
|
float L;
|
||||||
|
float beta;
|
||||||
|
} gvf_parametric_con;
|
||||||
|
|
||||||
|
extern gvf_parametric_con gvf_parametric_control;
|
||||||
|
|
||||||
|
// Parameters for the trajectories
|
||||||
|
enum trajectories_parametric {
|
||||||
|
TREFOIL_2D = 0,
|
||||||
|
ELLIPSE_3D = 1,
|
||||||
|
LISSAJOUS_3D = 2,
|
||||||
|
NONE_PARAMETRIC = 255,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
enum trajectories_parametric type;
|
||||||
|
float p_parametric[16];
|
||||||
|
float phi_errors[3];
|
||||||
|
} gvf_parametric_tra;
|
||||||
|
|
||||||
|
extern gvf_parametric_tra gvf_parametric_trajectory;
|
||||||
|
|
||||||
|
// Init function
|
||||||
|
extern void gvf_parametric_init(void);
|
||||||
|
|
||||||
|
// Control functions
|
||||||
|
extern void gvf_parametric_set_direction(int8_t s);
|
||||||
|
extern void gvf_parametric_control_2D(float, float, float, float, float, float, float, float);
|
||||||
|
extern void gvf_parametric_control_3D(float, float, float, float, float, float, float, float, float,
|
||||||
|
float, float, float);
|
||||||
|
|
||||||
|
// 2D Trefoil
|
||||||
|
extern bool gvf_parametric_2D_trefoil_XY(float, float, float, float, float, float, float);
|
||||||
|
extern bool gvf_parametric_2D_trefoil_wp(uint8_t, float, float, float, float, float);
|
||||||
|
|
||||||
|
// 3D Ellipse
|
||||||
|
extern bool gvf_parametric_3D_ellipse_XYZ(float, float, float, float, float, float);
|
||||||
|
extern bool gvf_parametric_3D_ellipse_wp(uint8_t, float, float, float, float);
|
||||||
|
extern bool gvf_parametric_3D_ellipse_wp_delta(uint8_t, float, float, float, float);
|
||||||
|
|
||||||
|
// 3D Lissajous
|
||||||
|
extern bool gvf_parametric_3D_lissajous_XYZ(float, float, float, float, float, float, float, float, float, float, float,
|
||||||
|
float, float);
|
||||||
|
extern bool gvf_parametric_3D_lissajous_wp_center(uint8_t, float, float, float, float, float, float, float, float,
|
||||||
|
float, float, float);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GVF_PARAMETRIC_H
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/gvf_parametric_low_level_control.c
|
||||||
|
*
|
||||||
|
* Firmware dependent file for the guiding vector field algorithm for 2D and 3D parametric trajectories.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "autopilot.h"
|
||||||
|
#include "gvf_parametric_low_level_control.h"
|
||||||
|
#include "gvf_parametric.h"
|
||||||
|
|
||||||
|
#if defined(FIXEDWING_FIRMWARE)
|
||||||
|
#include "firmwares/fixedwing/stabilization/stabilization_attitude.h"
|
||||||
|
#include "firmwares/fixedwing/guidance/guidance_v_n.h" // gvf_parametric is only compatible with the new pprz controller!
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void gvf_parametric_low_level_control_2D(float heading_rate)
|
||||||
|
{
|
||||||
|
#if defined(FIXEDWING_FIRMWARE)
|
||||||
|
if (autopilot_get_mode() == AP_MODE_AUTO2) {
|
||||||
|
// Lateral XY coordinates
|
||||||
|
lateral_mode = LATERAL_MODE_ROLL;
|
||||||
|
|
||||||
|
struct FloatEulers *att = stateGetNedToBodyEulers_f();
|
||||||
|
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
||||||
|
|
||||||
|
h_ctl_roll_setpoint =
|
||||||
|
-gvf_parametric_control.k_roll * atanf(heading_rate * ground_speed / GVF_PARAMETRIC_GRAVITY / cosf(att->theta));
|
||||||
|
BoundAbs(h_ctl_roll_setpoint, h_ctl_roll_max_setpoint); // Setting point for roll angle
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error gvf_parametric does not support your firmware yet
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void gvf_parametric_low_level_control_3D(float heading_rate, float climbing_rate)
|
||||||
|
{
|
||||||
|
#if defined(FIXEDWING_FIRMWARE)
|
||||||
|
if (autopilot_get_mode() == AP_MODE_AUTO2) {
|
||||||
|
// Vertical Z coordinate
|
||||||
|
v_ctl_mode = V_CTL_MODE_AUTO_CLIMB;
|
||||||
|
v_ctl_speed_mode = V_CTL_SPEED_THROTTLE;
|
||||||
|
|
||||||
|
v_ctl_climb_setpoint = gvf_parametric_control.k_climb * climbing_rate; // Setting point for vertical speed
|
||||||
|
|
||||||
|
// Lateral XY coordinates
|
||||||
|
lateral_mode = LATERAL_MODE_ROLL;
|
||||||
|
|
||||||
|
struct FloatEulers *att = stateGetNedToBodyEulers_f();
|
||||||
|
float ground_speed = stateGetHorizontalSpeedNorm_f();
|
||||||
|
|
||||||
|
h_ctl_roll_setpoint =
|
||||||
|
-gvf_parametric_control.k_roll * atanf(heading_rate * ground_speed / GVF_PARAMETRIC_GRAVITY / cosf(att->theta));
|
||||||
|
BoundAbs(h_ctl_roll_setpoint, h_ctl_roll_max_setpoint); // Setting point for roll angle
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error gvf_parametric does not support your firmware yet
|
||||||
|
#endif
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/gvf_parametric_low_level_control.h
|
||||||
|
*
|
||||||
|
* Firmware dependent file for the guiding vector field algorithm for 2D and 3D parametric trajectories.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GVF_PARAMETRIC_LOW_LEVEL_CONTROL_H
|
||||||
|
#define GVF_PARAMETRIC_LOW_LEVEL_CONTROL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Low level control functions
|
||||||
|
extern void gvf_parametric_low_level_control_2D(float);
|
||||||
|
extern void gvf_parametric_low_level_control_3D(float, float);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GVF_PARAMETRIC_LOW_LEVEL_CONTROL_H
|
||||||
|
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_2d_trefoil.c
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 2D trefoil know
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "subsystems/navigation/common_nav.h"
|
||||||
|
#include "modules/guidance/gvf_parametric/gvf_parametric.h"
|
||||||
|
#include "gvf_parametric_2d_trefoil.h"
|
||||||
|
|
||||||
|
/*! Default gain kx for the 2d trefoil knot trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_KX
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_KX 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain ky for the 2d trefoil knot trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_KY
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_KY 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default 1st frequency for the 2d trefoil trajectory*/
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_W1
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_W1 0.02
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default 2nd frequency for the 2d trefoil trajectory*/
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_W2
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_W2 0.03
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default ratio for the 2d trefoil trajectory*/
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_RATIO
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_RATIO 160
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default radius of the circles for the 2d trefoil trajectory*/
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_R
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_R 80
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default orientation for the 2d trefoil trajectory*/
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_ALPHA
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_ALPHA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gvf_par_2d_tre_par gvf_parametric_2d_trefoil_par = {GVF_PARAMETRIC_2D_TREFOIL_KX, GVF_PARAMETRIC_2D_TREFOIL_KY, GVF_PARAMETRIC_2D_TREFOIL_W1, GVF_PARAMETRIC_2D_TREFOIL_W2, GVF_PARAMETRIC_2D_TREFOIL_RATIO, GVF_PARAMETRIC_2D_TREFOIL_R, GVF_PARAMETRIC_2D_TREFOIL_ALPHA};
|
||||||
|
|
||||||
|
void gvf_parametric_2d_trefoil_info(float *f1, float *f2, float *f1d, float *f2d, float *f1dd, float *f2dd)
|
||||||
|
{
|
||||||
|
float xo = gvf_parametric_trajectory.p_parametric[0];
|
||||||
|
float yo = gvf_parametric_trajectory.p_parametric[1];
|
||||||
|
float w1 = gvf_parametric_trajectory.p_parametric[2];
|
||||||
|
float w2 = gvf_parametric_trajectory.p_parametric[3];
|
||||||
|
float ratio = gvf_parametric_trajectory.p_parametric[4];
|
||||||
|
float r = gvf_parametric_trajectory.p_parametric[5];
|
||||||
|
float alpha_rad = gvf_parametric_trajectory.p_parametric[6]*M_PI/180;
|
||||||
|
|
||||||
|
float w = gvf_parametric_control.w;
|
||||||
|
float wb = w * gvf_parametric_control.beta * gvf_parametric_control.s;
|
||||||
|
|
||||||
|
// Parametric equations of the trajectory and the partial derivatives w.r.t. 'w'
|
||||||
|
float nrf1 = cosf(wb*w1)*(r*cosf(wb*w2) + ratio);
|
||||||
|
float nrf2 = sinf(wb*w1)*(r*cosf(wb*w2) + ratio);
|
||||||
|
|
||||||
|
float nrf1d = -w1*sinf(wb*w1)*(r*cosf(wb*w2) + ratio) - cosf(wb*w1)*r*w2*sinf(wb*w2);
|
||||||
|
float nrf2d = w1*cosf(wb*w1)*(r*cosf(wb*w2) + ratio) - sinf(wb*w1)*r*w2*sinf(wb*w2);
|
||||||
|
|
||||||
|
float nrf1dd = -w1*w1*cosf(wb*w1)*(r*cosf(wb*w2) + ratio) + w1*sinf(wb*w1)*r*w2*sinf(wb*w2) + w1*sinf(wb*w1)*r*w2*sinf(wb*w2) - cosf(wb*w1)*r*w2*w2*cosf(wb*w2);
|
||||||
|
float nrf2dd = -w1*w1*sinf(wb*w1)*(r*cosf(wb*w2) + ratio) - w1*cosf(wb*w1)*r*w2*sinf(wb*w2) - w1*cosf(wb*w1)*r*w2*sinf(wb*w2) - sinf(wb*w1)*r*w2*w2*cosf(wb*w2);
|
||||||
|
|
||||||
|
*f1 = cosf(alpha_rad)*nrf1 - sinf(alpha_rad)*nrf2 + xo;
|
||||||
|
*f2 = sinf(alpha_rad)*nrf1 + cosf(alpha_rad)*nrf2 + yo;
|
||||||
|
|
||||||
|
*f1d = cosf(alpha_rad)*nrf1d - sinf(alpha_rad)*nrf2d;
|
||||||
|
*f2d = sinf(alpha_rad)*nrf1d + cosf(alpha_rad)*nrf2d;
|
||||||
|
|
||||||
|
*f1dd = cosf(alpha_rad)*nrf1dd - sinf(alpha_rad)*nrf2dd;
|
||||||
|
*f2dd = sinf(alpha_rad)*nrf1dd + cosf(alpha_rad)*nrf2dd;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_2d_trefoil.h
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 2D trefoil knot
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GVF_PARAMETRIC_2D_TREFOIL_H
|
||||||
|
#define GVF_PARAMETRIC_2D_TREFOIL_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @typedef gvf_2d_tre_par
|
||||||
|
* @brief Parameters for the GVF parametric 2D trefoil knot
|
||||||
|
* @param kx Gain defining how agressive is the vector field in x coordinate
|
||||||
|
* @param ky Gain defining how agressive is the vector field in y coordinate
|
||||||
|
* @param w1 1st frequency
|
||||||
|
* @param w2 2nd frequency
|
||||||
|
* @param off Off-phase
|
||||||
|
* @param r Radius of the "circles"
|
||||||
|
* @param alpha Orientation/rotation of the trajectory in the XY plane
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
float kx;
|
||||||
|
float ky;
|
||||||
|
float w1;
|
||||||
|
float w2;
|
||||||
|
float ratio;
|
||||||
|
float r;
|
||||||
|
float alpha;
|
||||||
|
} gvf_par_2d_tre_par;
|
||||||
|
|
||||||
|
extern gvf_par_2d_tre_par gvf_parametric_2d_trefoil_par;
|
||||||
|
|
||||||
|
extern void gvf_parametric_2d_trefoil_info(float *f1, float *f2, float *f1d, float *f2d, float *f1dd, float *f2dd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GVF_PARAMETRIC_2D_TREFOIL_H
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_ellipse.c
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 3D ellipse (intersection between a cylinder and a tilted plane)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "subsystems/navigation/common_nav.h"
|
||||||
|
#include "modules/guidance/gvf_parametric/gvf_parametric.h"
|
||||||
|
#include "gvf_parametric_3d_ellipse.h"
|
||||||
|
|
||||||
|
/*! Default gain kx for the 3d ellipse trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_KX
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_KX 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain ky for the 3d ellipse trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_KY
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_KY 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain kz for the 3d ellipse trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_KZ
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_KZ 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default radius of the cylinder */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_R
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_R 80
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default highest point for the ellipse trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_ZL
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_ZL 40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default highest point for the ellipse trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_ZH
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_ZH 40
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default orientation in degrees for the lowest point of the ellipse */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_ALPHA
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_ALPHA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gvf_par_3d_ell_par gvf_parametric_3d_ellipse_par = {GVF_PARAMETRIC_3D_ELLIPSE_KX,
|
||||||
|
GVF_PARAMETRIC_3D_ELLIPSE_KY, GVF_PARAMETRIC_3D_ELLIPSE_KZ, GVF_PARAMETRIC_3D_ELLIPSE_R, GVF_PARAMETRIC_3D_ELLIPSE_ZL, GVF_PARAMETRIC_3D_ELLIPSE_ZH, GVF_PARAMETRIC_3D_ELLIPSE_ALPHA
|
||||||
|
};
|
||||||
|
|
||||||
|
void gvf_parametric_3d_ellipse_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d,
|
||||||
|
float *f1dd, float *f2dd, float *f3dd)
|
||||||
|
{
|
||||||
|
float xo = gvf_parametric_trajectory.p_parametric[0];
|
||||||
|
float yo = gvf_parametric_trajectory.p_parametric[1];
|
||||||
|
float r = gvf_parametric_trajectory.p_parametric[2];
|
||||||
|
float zl = gvf_parametric_trajectory.p_parametric[3];
|
||||||
|
float zh = gvf_parametric_trajectory.p_parametric[4];
|
||||||
|
float alpha_rad = gvf_parametric_trajectory.p_parametric[5]*M_PI/180;
|
||||||
|
|
||||||
|
float w = gvf_parametric_control.w;
|
||||||
|
float wb = w * gvf_parametric_control.beta * gvf_parametric_control.s;
|
||||||
|
|
||||||
|
// Parametric equations of the trajectory and the partial derivatives w.r.t. 'w'
|
||||||
|
*f1 = r * cosf(wb) + xo;
|
||||||
|
*f2 = r * sinf(wb) + yo;
|
||||||
|
*f3 = 0.5 * (zh + zl + (zl - zh) * sinf(alpha_rad - wb));
|
||||||
|
|
||||||
|
*f1d = -r * sinf(wb);
|
||||||
|
*f2d = r * cosf(wb);
|
||||||
|
*f3d = -0.5 * (zl - zh) * cosf(alpha_rad - wb);
|
||||||
|
|
||||||
|
*f1dd = -r * cosf(wb);
|
||||||
|
*f2dd = -r * sinf(wb);
|
||||||
|
*f3dd = -0.5 * (zl - zh) * sinf(alpha_rad - wb);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_ellipse.h
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 3D ellipse (intersection between a cylinder and a tilted plane)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_ELLIPSE_H
|
||||||
|
#define GVF_PARAMETRIC_3D_ELLIPSE_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @typedef gvf_3d_ell_par
|
||||||
|
* @brief Parameters for the GVF parametric 3D ellipse
|
||||||
|
* @param kx Gain defining how agressive is the vector field in x coordinate
|
||||||
|
* @param ky Gain defining how agressive is the vector field in y coordinate
|
||||||
|
* @param kz Gain defining how agressive is the vector field in z coordinate
|
||||||
|
* @param r Radius of the cylinder in meters
|
||||||
|
* @param zl Altitude of the lowest point of the ellipse
|
||||||
|
* @param zh Altitude of the highest point of the ellipse
|
||||||
|
* @param alpha Heading of the lowest point zl in rads
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
float kx;
|
||||||
|
float ky;
|
||||||
|
float kz;
|
||||||
|
float r;
|
||||||
|
float zl;
|
||||||
|
float zh;
|
||||||
|
float alpha;
|
||||||
|
} gvf_par_3d_ell_par;
|
||||||
|
|
||||||
|
extern gvf_par_3d_ell_par gvf_parametric_3d_ellipse_par;
|
||||||
|
|
||||||
|
extern void gvf_parametric_3d_ellipse_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d,
|
||||||
|
float *f1dd, float *f2dd, float *f3dd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GVF_PARAMETRIC_3D_ELLIPSE_H
|
||||||
+143
@@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_lissajous.c
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 3D lissajous
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "subsystems/navigation/common_nav.h"
|
||||||
|
#include "modules/guidance/gvf_parametric/gvf_parametric.h"
|
||||||
|
#include "gvf_parametric_3d_lissajous.h"
|
||||||
|
|
||||||
|
/*! Default gain kx for the 3d lissajous trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_KX
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_KX 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain ky for the 3d lissajous trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_KY
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_KY 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default gain kz for the 3d lissajous trajectory */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_KZ
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_KZ 0.001
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default amplitude of the trajectory in the X plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_CX
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_CX 80
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default amplitude of the trajectory in the Y plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_CY
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_CY 80
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default amplitude of the trajectory in the Z plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_CZ
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_CZ 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default frequency of the trajectory in the X plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_WX
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_WX 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default frequency of the trajectory in the Y plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_WY
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_WY 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default frequency of the trajectory in the Z plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_WZ
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_WZ 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default offphase of the trajectory in the X plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_DX
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_DX 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default offphase of the trajectory in the Y plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_DY
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_DY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default offphase of the trajectory in the Z plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_DZ
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_DZ 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! Default orientation in degrees for the trajectory in the XY plane */
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_ALPHA
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_ALPHA 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
gvf_par_3d_lis_par gvf_parametric_3d_lissajous_par = {GVF_PARAMETRIC_3D_LISSAJOUS_KX, GVF_PARAMETRIC_3D_LISSAJOUS_KY, GVF_PARAMETRIC_3D_LISSAJOUS_KZ, GVF_PARAMETRIC_3D_LISSAJOUS_CX, GVF_PARAMETRIC_3D_LISSAJOUS_CY, GVF_PARAMETRIC_3D_LISSAJOUS_CZ, GVF_PARAMETRIC_3D_LISSAJOUS_WX, GVF_PARAMETRIC_3D_LISSAJOUS_WY, GVF_PARAMETRIC_3D_LISSAJOUS_WZ, GVF_PARAMETRIC_3D_LISSAJOUS_DX, GVF_PARAMETRIC_3D_LISSAJOUS_DY, GVF_PARAMETRIC_3D_LISSAJOUS_DZ, GVF_PARAMETRIC_3D_LISSAJOUS_ALPHA};
|
||||||
|
|
||||||
|
void gvf_parametric_3d_lissajous_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d,
|
||||||
|
float *f1dd, float *f2dd, float *f3dd)
|
||||||
|
{
|
||||||
|
float xo = gvf_parametric_trajectory.p_parametric[0];
|
||||||
|
float yo = gvf_parametric_trajectory.p_parametric[1];
|
||||||
|
float zo = gvf_parametric_trajectory.p_parametric[2];
|
||||||
|
float cx = gvf_parametric_trajectory.p_parametric[3];
|
||||||
|
float cy = gvf_parametric_trajectory.p_parametric[4];
|
||||||
|
float cz = gvf_parametric_trajectory.p_parametric[5];
|
||||||
|
float wx = gvf_parametric_trajectory.p_parametric[6];
|
||||||
|
float wy = gvf_parametric_trajectory.p_parametric[7];
|
||||||
|
float wz = gvf_parametric_trajectory.p_parametric[8];
|
||||||
|
float deltax_rad = gvf_parametric_trajectory.p_parametric[9]*M_PI/180;
|
||||||
|
float deltay_rad = gvf_parametric_trajectory.p_parametric[10]*M_PI/180;
|
||||||
|
float deltaz_rad = gvf_parametric_trajectory.p_parametric[11]*M_PI/180;
|
||||||
|
float alpha_rad = gvf_parametric_trajectory.p_parametric[12]*M_PI/180;
|
||||||
|
|
||||||
|
float w = gvf_parametric_control.w;
|
||||||
|
float wb = w * gvf_parametric_control.beta * gvf_parametric_control.s;
|
||||||
|
|
||||||
|
// Parametric equations of the trajectory and the partial derivatives w.r.t. 'w'
|
||||||
|
|
||||||
|
float nrf1 = cx*cosf(wx*wb + deltax_rad);
|
||||||
|
float nrf2 = cy*cosf(wy*wb + deltay_rad);
|
||||||
|
|
||||||
|
*f1 = cosf(alpha_rad)*nrf1 - sinf(alpha_rad)*nrf2 + xo;
|
||||||
|
*f2 = sinf(alpha_rad)*nrf1 + cosf(alpha_rad)*nrf2 + yo;
|
||||||
|
*f3 = cz*cosf(wz*wb + deltaz_rad) + zo;
|
||||||
|
|
||||||
|
float nrf1d = -wx*cx*sinf(wx*wb + deltax_rad);
|
||||||
|
float nrf2d = -wy*cy*sinf(wy*wb + deltay_rad);
|
||||||
|
|
||||||
|
*f1d = cosf(alpha_rad)*nrf1d - sinf(alpha_rad)*nrf2d;
|
||||||
|
*f2d = sinf(alpha_rad)*nrf1d + cosf(alpha_rad)*nrf2d;
|
||||||
|
*f3d = -wz*cz*sinf(wz*wb + deltaz_rad);
|
||||||
|
|
||||||
|
float nrf1dd = -wx*wx*cx*cosf(wx*wb + deltax_rad);
|
||||||
|
float nrf2dd = -wy*wy*cy*cosf(wy*wb + deltay_rad);
|
||||||
|
|
||||||
|
*f1dd = cosf(alpha_rad)*nrf1dd - sinf(alpha_rad)*nrf2dd;
|
||||||
|
*f2dd = sinf(alpha_rad)*nrf1dd + cosf(alpha_rad)*nrf2dd;
|
||||||
|
*f3dd = -wz*wz*cz*cosf(wz*wb + deltaz_rad);
|
||||||
|
}
|
||||||
|
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 Hector Garcia de Marina <hgarciad@ucm.es>
|
||||||
|
*
|
||||||
|
* This file is part of paparazzi.
|
||||||
|
*
|
||||||
|
* paparazzi is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* paparazzi is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with paparazzi; see the file COPYING. If not, see
|
||||||
|
* <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file modules/guidance/gvf_parametric/trajectories/gvf_parametric_3d_lissajous.h
|
||||||
|
*
|
||||||
|
* Guiding vector field algorithm for 2D and 3D complex trajectories.
|
||||||
|
*
|
||||||
|
* 3D lissajous figures
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GVF_PARAMETRIC_3D_LISSAJOUS_H
|
||||||
|
#define GVF_PARAMETRIC_3D_LISSAJOUS_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** @typedef gvf_3d_lis_par
|
||||||
|
* @brief Parameters for the GVF parametric 3D lissajous
|
||||||
|
* @param kx Gain defining how agressive is the vector field in x coordinate
|
||||||
|
* @param ky Gain defining how agressive is the vector field in y coordinate
|
||||||
|
* @param kz Gain defining how agressive is the vector field in z coordinate
|
||||||
|
* @param cx Amplitude of the trajectory in the X plane
|
||||||
|
* @param cy Amplitude of the trajectory in the Y plane
|
||||||
|
* @param cz Amplitude of the trajectory in the Z plane
|
||||||
|
* @param wx Frequency of the trajectory in the X plane
|
||||||
|
* @param wy Frequency of the trajectory in the Y plane
|
||||||
|
* @param wz Frequency of the trajectory in the Z plane
|
||||||
|
* @param dx Offphase of the trajectory in the X plane
|
||||||
|
* @param dy Offphase of the trajectory in the Y plane
|
||||||
|
* @param dz Offphase of the trajectory in the Z plane
|
||||||
|
* @param alpha Orientation/rotation of the trajectory in the XY plane
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
float kx;
|
||||||
|
float ky;
|
||||||
|
float kz;
|
||||||
|
float cx;
|
||||||
|
float cy;
|
||||||
|
float cz;
|
||||||
|
float wx;
|
||||||
|
float wy;
|
||||||
|
float wz;
|
||||||
|
float dx;
|
||||||
|
float dy;
|
||||||
|
float dz;
|
||||||
|
float alpha;
|
||||||
|
} gvf_par_3d_lis_par;
|
||||||
|
|
||||||
|
extern gvf_par_3d_lis_par gvf_parametric_3d_lissajous_par;
|
||||||
|
|
||||||
|
extern void gvf_parametric_3d_lissajous_info(float *f1, float *f2, float *f3, float *f1d, float *f2d, float *f3d,
|
||||||
|
float *f1dd, float *f2dd, float *f3dd);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // GVF_PARAMETRIC_3D_LISSAJOUS_H
|
||||||
@@ -0,0 +1,189 @@
|
|||||||
|
# Simulator for the gvf_parametric algorithm in Paparazzi (fixed-wing).
|
||||||
|
# Here you can check the demanded climbing and heading rates for your aircraft
|
||||||
|
# and the expected trajectories as well.
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from scipy import linalg as la
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import matplotlib
|
||||||
|
from mpl_toolkits.mplot3d import Axes3D
|
||||||
|
|
||||||
|
# Happy pdf for a happy submission without complains in paperplaza, arxiv, etc
|
||||||
|
font = {'size' : 20}
|
||||||
|
|
||||||
|
matplotlib.rc('font', **font)
|
||||||
|
|
||||||
|
matplotlib.rcParams['ps.useafm'] = True
|
||||||
|
matplotlib.rcParams['pdf.use14corefonts'] = True
|
||||||
|
matplotlib.rcParams['text.usetex'] = True
|
||||||
|
|
||||||
|
# Simulation parameters
|
||||||
|
tf = 500
|
||||||
|
dt = 5e-2
|
||||||
|
time = np.linspace(0, tf, tf/dt)
|
||||||
|
it = 1
|
||||||
|
|
||||||
|
# Data log
|
||||||
|
X_h = np.zeros((time.size, 4))
|
||||||
|
theta_h = np.zeros((time.size, 1))
|
||||||
|
e1_h = np.zeros((time.size, 1))
|
||||||
|
e2_h = np.zeros((time.size, 1))
|
||||||
|
e3_h = np.zeros((time.size, 1))
|
||||||
|
u_theta_h = np.zeros((time.size, 1))
|
||||||
|
u_z_h = np.zeros((time.size, 1))
|
||||||
|
u_w_h = np.zeros((time.size, 1))
|
||||||
|
|
||||||
|
# Initial conditions
|
||||||
|
X = np.array([[100], [-53], [40], [0]])
|
||||||
|
X_dot = np.array([[0], [0], [0], [0]])
|
||||||
|
theta = np.pi/4
|
||||||
|
|
||||||
|
X_h[0, :] = X.transpose()
|
||||||
|
theta_h[0] = theta
|
||||||
|
|
||||||
|
# Desired trajectory
|
||||||
|
xo = 0
|
||||||
|
yo = 0
|
||||||
|
zo = 100
|
||||||
|
cx = 150
|
||||||
|
cy = 150
|
||||||
|
cz = -10
|
||||||
|
deltax = 0
|
||||||
|
deltay = np.pi/2
|
||||||
|
deltaz = 0
|
||||||
|
wx = 1
|
||||||
|
wy = 1
|
||||||
|
wz = 1
|
||||||
|
|
||||||
|
alpha = np.pi/4
|
||||||
|
|
||||||
|
# Controller
|
||||||
|
L = 1e-1
|
||||||
|
beta = 1e-2
|
||||||
|
k1 = 1e-3
|
||||||
|
k2 = 1e-3
|
||||||
|
k3 = 1e-3
|
||||||
|
ktheta = 0.5
|
||||||
|
|
||||||
|
# Vehicle
|
||||||
|
s = 15
|
||||||
|
|
||||||
|
for t in time[:-1]:
|
||||||
|
|
||||||
|
x = X[0][0]
|
||||||
|
y = X[1][0]
|
||||||
|
z = X[2][0]
|
||||||
|
w = X[3][0]
|
||||||
|
|
||||||
|
wb = w*beta
|
||||||
|
|
||||||
|
#f
|
||||||
|
nrf1 = cx*np.cos(wx*wb + deltax)
|
||||||
|
nrf2 = cy*np.cos(wy*wb + deltay)
|
||||||
|
f3 = cz*np.cos(wz*wb + deltaz) + zo
|
||||||
|
|
||||||
|
nrf1d = -wx*cx*np.sin(wx*wb + deltax)
|
||||||
|
nrf2d = -wy*cy*np.sin(wy*wb + deltay)
|
||||||
|
f3d = -wz*cz*np.sin(wz*wb + deltaz)
|
||||||
|
|
||||||
|
nrf1dd = -wx*wx*cx*np.cos(wx*wb + deltax)
|
||||||
|
nrf2dd = -wy*wy*cy*np.cos(wy*wb + deltay)
|
||||||
|
f3dd = -wz*wz*cz*np.cos(wz*wb + deltaz)
|
||||||
|
|
||||||
|
f1 = np.cos(alpha)*nrf1 - np.sin(alpha)*nrf2 + xo
|
||||||
|
f2 = np.sin(alpha)*nrf1 + np.cos(alpha)*nrf2 + yo
|
||||||
|
|
||||||
|
f1d = np.cos(alpha)*nrf1d - np.sin(alpha)*nrf2d
|
||||||
|
f2d = np.sin(alpha)*nrf1d + np.cos(alpha)*nrf2d
|
||||||
|
|
||||||
|
f1dd = np.cos(alpha)*nrf1dd - np.sin(alpha)*nrf2dd
|
||||||
|
f2dd = np.sin(alpha)*nrf1dd + np.cos(alpha)*nrf2dd
|
||||||
|
|
||||||
|
#phi
|
||||||
|
phi1 = L*(x - f1)
|
||||||
|
phi2 = L*(y - f2)
|
||||||
|
phi3 = L*(z - f3)
|
||||||
|
|
||||||
|
#Chi, J
|
||||||
|
Chi = L*np.array([[-f1d*L*L*beta -k1*phi1],
|
||||||
|
[-f2d*L*L*beta -k2*phi2],
|
||||||
|
[-f3d*L*L*beta -k3*phi3],
|
||||||
|
[-L*L + beta*(k1*phi1*f1d + k2*phi2*f2d + k3*phi3*f3d)]])
|
||||||
|
|
||||||
|
j44 = beta*beta*(k1*(phi1*f1dd-L*f1d*f1d) + k2*(phi2*f2dd-L*f2d*f2d) + k3*(phi3*f3dd-L*f3d*f3d))
|
||||||
|
J = L*np.array([[-k1*L, 0, 0, -(beta*L)*(beta*L*f1dd-k1*f1d)],
|
||||||
|
[ 0, -k2*L, 0, -(beta*L)*(beta*L*f2dd-k2*f2d)],
|
||||||
|
[ 0, 0, -k3*L, -(beta*L)*(beta*L*f3dd-k3*f3d)],
|
||||||
|
[beta*L*k1*f1d, beta*L*k2*f2d, beta*L*k3*f3d, j44]])
|
||||||
|
|
||||||
|
#G, Fp, Gp
|
||||||
|
G = np.array([[1,0,0,0],
|
||||||
|
[0,1,0,0],
|
||||||
|
[0,0,0,0],
|
||||||
|
[0,0,0,0]])
|
||||||
|
|
||||||
|
Fp = np.array([[0, -1, 0, 0],
|
||||||
|
[1, 0, 0, 0]])
|
||||||
|
|
||||||
|
Gp = np.array([[0, -1, 0, 0],
|
||||||
|
[1, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0],
|
||||||
|
[0, 0, 0, 0]])
|
||||||
|
|
||||||
|
h = np.array([[np.cos(theta)],[np.sin(theta)]])
|
||||||
|
ht = h.transpose()
|
||||||
|
|
||||||
|
Chit = Chi.transpose()
|
||||||
|
Chinorm = np.sqrt(Chi.transpose().dot(Chi))[0][0]
|
||||||
|
Chih = Chi / Chinorm
|
||||||
|
|
||||||
|
u_theta = (-(1/(Chit.dot(G).dot(Chi))*Chit.dot(Gp).dot(np.eye(4) - Chih.dot(Chih.transpose())).dot(J).dot(X_dot)) - ktheta*ht.dot(Fp).dot(Chi) / np.sqrt(Chit.dot(G).dot(Chi)))[0][0]
|
||||||
|
|
||||||
|
u_zeta = Chi[2][0]*s / np.sqrt(Chi[0][0]*Chi[0][0] + Chi[1][0]*Chi[1][0])
|
||||||
|
u_w = Chi[3][0]*s / np.sqrt(Chi[0][0]*Chi[0][0] + Chi[1][0]*Chi[1][0])
|
||||||
|
|
||||||
|
# Euler integration
|
||||||
|
theta = theta + u_theta*dt
|
||||||
|
X_dot = np.array([[s*np.cos(theta)],[s*np.sin(theta)], [u_zeta], [u_w]])
|
||||||
|
X = X + X_dot*dt
|
||||||
|
|
||||||
|
|
||||||
|
# Log
|
||||||
|
X_h[it, :] = X.transpose()
|
||||||
|
theta_h[it] = theta
|
||||||
|
e1_h[it] = phi1
|
||||||
|
e2_h[it] = phi2
|
||||||
|
e3_h[it] = phi3
|
||||||
|
u_theta_h[it] = u_theta
|
||||||
|
u_z_h[it] = u_zeta
|
||||||
|
u_w_h[it] = u_w
|
||||||
|
|
||||||
|
it = it + 1
|
||||||
|
|
||||||
|
# Plots
|
||||||
|
|
||||||
|
fig3d = plt.figure()
|
||||||
|
ax3d = fig3d.gca(projection='3d')
|
||||||
|
ax3d.plot(X_h[:,0], X_h[:,1], X_h[:,2])
|
||||||
|
|
||||||
|
f, (axe1,axe2,axe3) = plt.subplots(3,1)
|
||||||
|
axe1.plot(time[1:], e1_h[1:])
|
||||||
|
axe2.plot(time[1:], e2_h[1:])
|
||||||
|
axe3.plot(time[1:], e3_h[1:])
|
||||||
|
axe3.set_xlabel("Time [s]")
|
||||||
|
axe1.set_xlabel("error X")
|
||||||
|
axe2.set_xlabel("error Y")
|
||||||
|
axe3.set_xlabel("error Z")
|
||||||
|
|
||||||
|
f, (axut,axuz,axuw) = plt.subplots(3,1)
|
||||||
|
axut.plot(time[1:], u_theta_h[1:])
|
||||||
|
axuz.plot(time[1:], u_z_h[1:])
|
||||||
|
axuw.plot(time[1:], u_w_h[1:])
|
||||||
|
axuw.set_xlabel("Time [s]")
|
||||||
|
axut.set_ylabel("Heading rate [rad/s]")
|
||||||
|
axuz.set_ylabel("Climbing rate [m/s]")
|
||||||
|
axuw.set_ylabel("Virual coord rate")
|
||||||
|
|
||||||
|
plt.show()
|
||||||
|
|
||||||
@@ -4,6 +4,7 @@ import time
|
|||||||
from scipy import linalg as la
|
from scipy import linalg as la
|
||||||
from matplotlib.path import Path
|
from matplotlib.path import Path
|
||||||
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas
|
||||||
|
from mpl_toolkits.mplot3d import Axes3D
|
||||||
import matplotlib.pyplot as pl
|
import matplotlib.pyplot as pl
|
||||||
import matplotlib.patches as patches
|
import matplotlib.patches as patches
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -33,12 +34,13 @@ class GVFFrame(wx.Frame):
|
|||||||
self.course = 0
|
self.course = 0
|
||||||
self.yaw = 0
|
self.yaw = 0
|
||||||
self.XY = np.array([0, 0])
|
self.XY = np.array([0, 0])
|
||||||
|
self.altitude = 0
|
||||||
|
self.ground_altitude = -1
|
||||||
|
|
||||||
# Desired trajectory
|
# Desired trajectory
|
||||||
self.timer_traj = 0 # We do not update the traj every time we receive a msg
|
|
||||||
self.timer_traj_lim = 7 # (7+1) * 0.25secs
|
|
||||||
self.s = 0
|
self.s = 0
|
||||||
self.ke = 0
|
self.ke = 0
|
||||||
|
self.gvf_error = 0
|
||||||
self.map_gvf = map2d(np.array([0, 0]), 150000)
|
self.map_gvf = map2d(np.array([0, 0]), 150000)
|
||||||
self.traj = None
|
self.traj = None
|
||||||
|
|
||||||
@@ -59,16 +61,18 @@ class GVFFrame(wx.Frame):
|
|||||||
if int(ac_id) == self.ac_id:
|
if int(ac_id) == self.ac_id:
|
||||||
if msg.name == 'GPS':
|
if msg.name == 'GPS':
|
||||||
self.course = int(msg.get_field(3))*np.pi/1800
|
self.course = int(msg.get_field(3))*np.pi/1800
|
||||||
|
self.altitude = float(msg.get_field(4))/1000
|
||||||
if msg.name == 'NAVIGATION':
|
if msg.name == 'NAVIGATION':
|
||||||
self.XY[0] = float(msg.get_field(2))
|
self.XY[0] = float(msg.get_field(2))
|
||||||
self.XY[1] = float(msg.get_field(3))
|
self.XY[1] = float(msg.get_field(3))
|
||||||
|
if msg.name == 'NAVIGATION_REF':
|
||||||
|
self.ground_altitude = float(msg.get_field(3))
|
||||||
if msg.name == 'ATTITUDE':
|
if msg.name == 'ATTITUDE':
|
||||||
self.yaw = float(msg.get_field(1))
|
self.yaw = float(msg.get_field(1))
|
||||||
if msg.name == 'GVF':
|
if msg.name == 'GVF':
|
||||||
self.gvf_error = float(msg.get_field(0))
|
self.gvf_error = float(msg.get_field(0))
|
||||||
# Straight line
|
# Straight line
|
||||||
if int(msg.get_field(1)) == 0 \
|
if int(msg.get_field(1)) == 0:
|
||||||
and self.timer_traj == self.timer_traj_lim:
|
|
||||||
self.s = int(msg.get_field(2))
|
self.s = int(msg.get_field(2))
|
||||||
self.ke = float(msg.get_field(3))
|
self.ke = float(msg.get_field(3))
|
||||||
param = [float(x) for x in msg.get_field(4)]
|
param = [float(x) for x in msg.get_field(4)]
|
||||||
@@ -81,8 +85,7 @@ class GVFFrame(wx.Frame):
|
|||||||
self.s, self.ke)
|
self.s, self.ke)
|
||||||
|
|
||||||
# Ellipse
|
# Ellipse
|
||||||
if int(msg.get_field(1)) == 1 \
|
elif int(msg.get_field(1)) == 1:
|
||||||
and self.timer_traj == self.timer_traj_lim:
|
|
||||||
self.s = int(msg.get_field(2))
|
self.s = int(msg.get_field(2))
|
||||||
self.ke = float(msg.get_field(3))
|
self.ke = float(msg.get_field(3))
|
||||||
param = [float(x) for x in msg.get_field(4)]
|
param = [float(x) for x in msg.get_field(4)]
|
||||||
@@ -96,8 +99,7 @@ class GVFFrame(wx.Frame):
|
|||||||
self.map_gvf.area, self.s, self.ke)
|
self.map_gvf.area, self.s, self.ke)
|
||||||
|
|
||||||
# Sin
|
# Sin
|
||||||
if int(msg.get_field(1)) == 2 \
|
elif int(msg.get_field(1)) == 2:
|
||||||
and self.timer_traj == self.timer_traj_lim:
|
|
||||||
self.s = int(msg.get_field(2))
|
self.s = int(msg.get_field(2))
|
||||||
self.ke = float(msg.get_field(3))
|
self.ke = float(msg.get_field(3))
|
||||||
param = [float(x) for x in msg.get_field(4)]
|
param = [float(x) for x in msg.get_field(4)]
|
||||||
@@ -112,34 +114,83 @@ class GVFFrame(wx.Frame):
|
|||||||
self.traj.vector_field(self.traj.XYoff, \
|
self.traj.vector_field(self.traj.XYoff, \
|
||||||
self.map_gvf.area, self.s, self.ke)
|
self.map_gvf.area, self.s, self.ke)
|
||||||
|
|
||||||
self.timer_traj = self.timer_traj + 1
|
if msg.name == 'GVF_PARAMETRIC':
|
||||||
if self.timer_traj > self.timer_traj_lim:
|
# Trefoil 2D
|
||||||
self.timer_traj = 0
|
if int(msg.get_field(0)) == 0:
|
||||||
|
self.s = int(msg.get_field(1))
|
||||||
|
self.wb = float(msg.get_field(2))
|
||||||
|
param = [float(x) for x in msg.get_field(3)]
|
||||||
|
xo = param[0]
|
||||||
|
yo = param[1]
|
||||||
|
w1 = param[2]
|
||||||
|
w2 = param[3]
|
||||||
|
ratio = param[4]
|
||||||
|
r = param[5]
|
||||||
|
alpha = param[6]
|
||||||
|
phi = [float(x) for x in msg.get_field(4)]
|
||||||
|
phi_x = phi[0]
|
||||||
|
phi_y = phi[1]
|
||||||
|
self.traj = traj_param_trefoil_2D(np.array([xo, yo]), w1, w2, ratio, r, alpha, self.wb)
|
||||||
|
|
||||||
def draw_gvf(self, XY, yaw, course):
|
# Ellipse 3D
|
||||||
|
elif int(msg.get_field(0)) == 1:
|
||||||
|
self.s = int(msg.get_field(1))
|
||||||
|
self.wb = float(msg.get_field(2))
|
||||||
|
param = [float(x) for x in msg.get_field(3)]
|
||||||
|
xo = param[0]
|
||||||
|
yo = param[1]
|
||||||
|
r = param[2]
|
||||||
|
zl = param[3]
|
||||||
|
zh = param[4]
|
||||||
|
alpha = param[5]
|
||||||
|
phi = [float(x) for x in msg.get_field(4)]
|
||||||
|
phi_x = phi[0]
|
||||||
|
phi_y = phi[1]
|
||||||
|
phi_z = phi[2]
|
||||||
|
self.traj = traj_param_ellipse_3D(np.array([xo,yo]), r, zl, zh, alpha, self.wb)
|
||||||
|
|
||||||
|
# Lissajous 3D
|
||||||
|
elif int(msg.get_field(0)) == 2:
|
||||||
|
self.s = int(msg.get_field(1))
|
||||||
|
self.wb = float(msg.get_field(2))
|
||||||
|
param = [float(x) for x in msg.get_field(3)]
|
||||||
|
xo = param[0]
|
||||||
|
yo = param[1]
|
||||||
|
zo = param[2]
|
||||||
|
cx = param[3]
|
||||||
|
cy = param[4]
|
||||||
|
cz = param[5]
|
||||||
|
wx = param[6]
|
||||||
|
wy = param[7]
|
||||||
|
wz = param[8]
|
||||||
|
dx = param[9]
|
||||||
|
dy = param[10]
|
||||||
|
dz = param[11]
|
||||||
|
alpha = param[12]
|
||||||
|
phi = [float(x) for x in msg.get_field(4)]
|
||||||
|
phi_x = phi[0]
|
||||||
|
phi_y = phi[1]
|
||||||
|
phi_z = phi[2]
|
||||||
|
self.traj = traj_param_lissajous_3D(np.array([xo,yo]), zo, cx, cy, cz, \
|
||||||
|
wx, wy, wz, dx, dy, dz, alpha, self.wb)
|
||||||
|
|
||||||
|
def draw_gvf(self, XY, yaw, course, altitude):
|
||||||
if self.traj is not None:
|
if self.traj is not None:
|
||||||
self.map_gvf.draw(XY, yaw, course, self.traj)
|
self.map_gvf.draw(XY, yaw, course, altitude, self.traj)
|
||||||
|
|
||||||
def OnClose(self, event):
|
def OnClose(self, event):
|
||||||
self.interface.shutdown()
|
self.interface.shutdown()
|
||||||
self.Destroy()
|
self.Destroy()
|
||||||
|
|
||||||
def OnRedrawTimer(self, event):
|
def OnRedrawTimer(self, event):
|
||||||
self.draw_gvf(self.XY, self.yaw, self.course)
|
self.draw_gvf(self.XY, self.yaw, self.course, self.altitude-self.ground_altitude)
|
||||||
self.canvas.draw()
|
self.canvas.draw()
|
||||||
|
|
||||||
class map2d:
|
class map2d:
|
||||||
def __init__(self, XYoff, area):
|
def __init__(self, XYoff, area):
|
||||||
self.XYoff = XYoff
|
self.XYoff = XYoff
|
||||||
self.area = area
|
self.area = area
|
||||||
self.fig, self.ax = pl.subplots()
|
self.fig = pl.figure()
|
||||||
self.ax.set_xlabel('South [m]')
|
|
||||||
self.ax.set_ylabel('West [m]')
|
|
||||||
self.ax.set_title('2D Map')
|
|
||||||
self.ax.annotate('HOME', xy = (0, 0))
|
|
||||||
self.ax.set_xlim(XYoff[0]-0.5*np.sqrt(area), XYoff[0]+0.5*np.sqrt(area))
|
|
||||||
self.ax.set_ylim(XYoff[1]-0.5*np.sqrt(area), XYoff[1]+0.5*np.sqrt(area))
|
|
||||||
self.ax.axis('equal')
|
|
||||||
|
|
||||||
def vehicle_patch(self, XY, yaw):
|
def vehicle_patch(self, XY, yaw):
|
||||||
Rot = np.array([[np.cos(yaw), np.sin(yaw)],[-np.sin(yaw), np.cos(yaw)]])
|
Rot = np.array([[np.cos(yaw), np.sin(yaw)],[-np.sin(yaw), np.cos(yaw)]])
|
||||||
@@ -167,42 +218,113 @@ class map2d:
|
|||||||
|
|
||||||
return patches.PathPatch(path, facecolor='red', lw=2)
|
return patches.PathPatch(path, facecolor='red', lw=2)
|
||||||
|
|
||||||
def draw(self, XY, yaw, course, traj):
|
def draw(self, XY, yaw, course, altitude, traj):
|
||||||
self.ax.clear()
|
self.fig.clf()
|
||||||
self.ax.plot(traj.traj_points[0, :], traj.traj_points[1, :])
|
if traj.dim == 2:
|
||||||
self.ax.quiver(traj.mapgrad_X, traj.mapgrad_Y, \
|
ax = self.fig.add_subplot(111)
|
||||||
traj.mapgrad_U, traj.mapgrad_V, color='Teal', \
|
ax.plot(traj.traj_points[0, :], traj.traj_points[1, :])
|
||||||
pivot='mid', width=0.002)
|
ax.quiver(traj.mapgrad_X, traj.mapgrad_Y, \
|
||||||
self.ax.add_patch(self.vehicle_patch(XY, yaw)) # In radians
|
traj.mapgrad_U, traj.mapgrad_V, color='Teal', \
|
||||||
apex = 45*np.pi/180 # 30 degrees apex angle
|
pivot='mid', width=0.002)
|
||||||
b = np.sqrt(2*(self.area/2000) / np.sin(apex))
|
ax.add_patch(self.vehicle_patch(XY, yaw)) # In radians
|
||||||
h = b*np.cos(apex/2)
|
apex = 45*np.pi/180 # 30 degrees apex angle
|
||||||
self.ax.arrow(XY[0], XY[1], \
|
b = np.sqrt(2*(self.area/2000) / np.sin(apex))
|
||||||
h*np.sin(course), h*np.cos(course),\
|
h = b*np.cos(apex/2)
|
||||||
head_width=5, head_length=10, fc='k', ec='k')
|
ax.arrow(XY[0], XY[1], \
|
||||||
self.ax.annotate('HOME', xy = (0, 0))
|
h*np.sin(course), h*np.cos(course),\
|
||||||
if isinstance(traj, traj_ellipse):
|
head_width=5, head_length=10, fc='k', ec='k')
|
||||||
self.ax.annotate('ELLIPSE', xy = (traj.XYoff[0], traj.XYoff[1]))
|
ax.annotate('HOME', xy = (0, 0))
|
||||||
self.ax.plot(0, 0, 'kx', ms=10, mew=2)
|
if isinstance(traj, traj_ellipse):
|
||||||
self.ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
ax.annotate('ELLIPSE', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
elif isinstance(traj, traj_sin):
|
ax.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
self.ax.annotate('SIN', xy = (traj.XYoff[0], traj.XYoff[1]))
|
ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
self.ax.plot(0, 0, 'kx', ms=10, mew=2)
|
elif isinstance(traj, traj_sin):
|
||||||
self.ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
ax.annotate('SIN', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
elif isinstance(traj, traj_line):
|
ax.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
self.ax.annotate('LINE', xy = (traj.XYoff[0], traj.XYoff[1]))
|
ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
self.ax.plot(0, 0, 'kx', ms=10, mew=2)
|
elif isinstance(traj, traj_line):
|
||||||
self.ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
ax.annotate('LINE', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
|
ax.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
|
ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
|
elif isinstance(traj, traj_param_trefoil_2D):
|
||||||
|
ax.annotate('TREFOIL', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
|
ax.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
|
ax.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
|
ax.plot(traj.wpoint[0], traj.wpoint[1], 'rx', ms=10, mew=2)
|
||||||
|
|
||||||
self.ax.set_xlabel('South [m]')
|
ax.set_xlabel('South [m]')
|
||||||
self.ax.set_ylabel('West [m]')
|
ax.set_ylabel('West [m]')
|
||||||
self.ax.set_title('2D Map')
|
ax.set_title('2D Map')
|
||||||
self.ax.set_xlim(self.XYoff[0]-0.5*np.sqrt(self.area), \
|
ax.set_xlim(self.XYoff[0]-0.5*np.sqrt(self.area), \
|
||||||
self.XYoff[0]+0.5*np.sqrt(self.area))
|
self.XYoff[0]+0.5*np.sqrt(self.area))
|
||||||
self.ax.set_ylim(self.XYoff[1]-0.5*np.sqrt(self.area), \
|
ax.set_ylim(self.XYoff[1]-0.5*np.sqrt(self.area), \
|
||||||
self.XYoff[1]+0.5*np.sqrt(self.area))
|
self.XYoff[1]+0.5*np.sqrt(self.area))
|
||||||
self.ax.axis('equal')
|
ax.axis('equal')
|
||||||
self.ax.grid()
|
ax.grid()
|
||||||
|
|
||||||
|
if traj.dim == 3:
|
||||||
|
a3d = self.fig.add_subplot(2,2,1, projection='3d')
|
||||||
|
axy = self.fig.add_subplot(2,2,2)
|
||||||
|
axz = self.fig.add_subplot(2,2,3)
|
||||||
|
ayz = self.fig.add_subplot(2,2,4)
|
||||||
|
|
||||||
|
a3d.set_title('3D Map')
|
||||||
|
axy.set_title('XY Map')
|
||||||
|
axz.set_title('XZ Map')
|
||||||
|
ayz.set_title('YZ Map')
|
||||||
|
|
||||||
|
# 3D
|
||||||
|
a3d.plot(traj.traj_points[0, :], traj.traj_points[1, :], traj.traj_points[2, :])
|
||||||
|
if altitude != -1:
|
||||||
|
a3d.plot([XY[0]], [XY[1]], [altitude], marker='o', markerfacecolor='r', markeredgecolor='r')
|
||||||
|
a3d.plot([traj.wpoint[0]], [traj.wpoint[1]], [traj.wpoint[2]], marker='x', markerfacecolor='r', markeredgecolor='r')
|
||||||
|
|
||||||
|
a3d.axis('equal')
|
||||||
|
if traj.deltaz < 0:
|
||||||
|
a3d.set_zlim(traj.zo+1.5*traj.deltaz, traj.zo-1.5*traj.deltaz)
|
||||||
|
else:
|
||||||
|
a3d.set_zlim(traj.zo-1.5*traj.deltaz, traj.zo+1.5*traj.deltaz)
|
||||||
|
|
||||||
|
# XY
|
||||||
|
axy.plot(traj.traj_points[0, :], traj.traj_points[1, :])
|
||||||
|
axy.add_patch(self.vehicle_patch(XY, yaw)) # In radians
|
||||||
|
apex = 45*np.pi/180 # 30 degrees apex angle
|
||||||
|
b = np.sqrt(2*(self.area/2000) / np.sin(apex))
|
||||||
|
h = b*np.cos(apex/2)
|
||||||
|
axy.arrow(XY[0], XY[1], \
|
||||||
|
h*np.sin(course), h*np.cos(course),\
|
||||||
|
head_width=5, head_length=10, fc='k', ec='k')
|
||||||
|
axy.annotate('HOME', xy = (0, 0))
|
||||||
|
axy.plot(traj.wpoint[0], traj.wpoint[1], 'rx', ms=10, mew=2)
|
||||||
|
if isinstance(traj, traj_param_ellipse_3D):
|
||||||
|
axy.annotate('ELLIPSE_3D', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
|
axy.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
|
axy.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
|
elif isinstance(traj, traj_param_lissajous_3D):
|
||||||
|
axy.annotate('LISSA_3D', xy = (traj.XYoff[0], traj.XYoff[1]))
|
||||||
|
axy.plot(0, 0, 'kx', ms=10, mew=2)
|
||||||
|
axy.plot(traj.XYoff[0], traj.XYoff[1], 'kx', ms=10, mew=2)
|
||||||
|
|
||||||
|
axy.axis('equal')
|
||||||
|
|
||||||
|
# XZ
|
||||||
|
axz.plot(traj.traj_points[0, :], traj.traj_points[2, :])
|
||||||
|
if altitude != -1:
|
||||||
|
axz.plot([XY[0]], [altitude], 'ro')
|
||||||
|
axz.plot(traj.wpoint[0], traj.wpoint[2], 'rx', ms=10, mew=2)
|
||||||
|
if traj.deltaz < 0:
|
||||||
|
axz.set_ylim(traj.zo+1.5*traj.deltaz, traj.zo-1.5*traj.deltaz)
|
||||||
|
else:
|
||||||
|
axz.set_ylim(traj.zo-1.5*traj.deltaz, traj.zo+1.5*traj.deltaz)
|
||||||
|
# YZ
|
||||||
|
ayz.plot(traj.traj_points[1, :], traj.traj_points[2, :])
|
||||||
|
if altitude != -1:
|
||||||
|
ayz.plot([XY[1]], [altitude], 'ro')
|
||||||
|
ayz.plot(traj.wpoint[1], traj.wpoint[2], 'rx', ms=10, mew=2)
|
||||||
|
if traj.deltaz < 0:
|
||||||
|
axz.set_ylim(traj.zo+1.5*traj.deltaz, traj.zo-1.5*traj.deltaz)
|
||||||
|
else:
|
||||||
|
ayz.set_ylim(traj.zo-1.5*traj.deltaz, traj.zo+1.5*traj.deltaz)
|
||||||
|
|
||||||
class traj_line:
|
class traj_line:
|
||||||
def float_range(self, start, end, step):
|
def float_range(self, start, end, step):
|
||||||
@@ -211,6 +333,7 @@ class traj_line:
|
|||||||
start += step
|
start += step
|
||||||
|
|
||||||
def __init__(self, Xminmax, a, b, alpha):
|
def __init__(self, Xminmax, a, b, alpha):
|
||||||
|
self.dim = 2
|
||||||
self.XYoff = np.array([a, b])
|
self.XYoff = np.array([a, b])
|
||||||
self.Xminmax = Xminmax
|
self.Xminmax = Xminmax
|
||||||
self.a, self.b, self.alpha = a, b, alpha
|
self.a, self.b, self.alpha = a, b, alpha
|
||||||
@@ -265,6 +388,7 @@ class traj_ellipse:
|
|||||||
start += step
|
start += step
|
||||||
|
|
||||||
def __init__(self, XYoff, rot, a, b):
|
def __init__(self, XYoff, rot, a, b):
|
||||||
|
self.dim = 2
|
||||||
self.XYoff = XYoff
|
self.XYoff = XYoff
|
||||||
self.a, self.b = a, b
|
self.a, self.b = a, b
|
||||||
self.rot = rot
|
self.rot = rot
|
||||||
@@ -324,6 +448,7 @@ class traj_sin:
|
|||||||
start += step
|
start += step
|
||||||
|
|
||||||
def __init__(self, Xminmax, a, b, alpha, w, off, A):
|
def __init__(self, Xminmax, a, b, alpha, w, off, A):
|
||||||
|
self.dim = 2
|
||||||
self.XYoff = np.array([a, b])
|
self.XYoff = np.array([a, b])
|
||||||
self.Xminmax = Xminmax
|
self.Xminmax = Xminmax
|
||||||
self.a, self.b, self.alpha, self.w, self.off, self.A = \
|
self.a, self.b, self.alpha, self.w, self.off, self.A = \
|
||||||
@@ -382,3 +507,125 @@ class traj_sin:
|
|||||||
|
|
||||||
self.mapgrad_U = self.mapgrad_U/norm
|
self.mapgrad_U = self.mapgrad_U/norm
|
||||||
self.mapgrad_V = self.mapgrad_V/norm
|
self.mapgrad_V = self.mapgrad_V/norm
|
||||||
|
|
||||||
|
class traj_param_trefoil_2D:
|
||||||
|
def float_range(self, start, end, step):
|
||||||
|
while start <= end:
|
||||||
|
yield start
|
||||||
|
start += step
|
||||||
|
|
||||||
|
def __init__(self, XYoff, w1, w2, ratio, r, alpha, wb):
|
||||||
|
self.dim = 2
|
||||||
|
self.XYoff, self.w1, self.w2, self.ratio, self.r, self.alpha, self.wb = XYoff, w1, w2, ratio, r, alpha, wb
|
||||||
|
self.mapgrad_X = []
|
||||||
|
self.mapgrad_Y = []
|
||||||
|
self.mapgrad_U = []
|
||||||
|
self.mapgrad_V = []
|
||||||
|
|
||||||
|
self.alpha = alpha*np.pi/180
|
||||||
|
|
||||||
|
self.wpoint = self.param_point(self.wb)
|
||||||
|
|
||||||
|
num_points = 1000
|
||||||
|
self.traj_points = np.zeros((2, num_points))
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
range_points = 1000.0
|
||||||
|
for t in self.float_range(0, range_points, range_points/num_points):
|
||||||
|
self.traj_points[:, i] = self.param_point(t)
|
||||||
|
i = i + 1
|
||||||
|
if i >= num_points:
|
||||||
|
break
|
||||||
|
|
||||||
|
def param_point(self, t):
|
||||||
|
xnr = np.cos(t*self.w1)*(self.r*np.cos(t*self.w2) + self.ratio)
|
||||||
|
ynr = np.sin(t*self.w1)*(self.r*np.cos(t*self.w2) + self.ratio)
|
||||||
|
|
||||||
|
x = np.cos(self.alpha)*xnr - np.sin(self.alpha)*ynr
|
||||||
|
y = np.sin(self.alpha)*xnr + np.cos(self.alpha)*ynr
|
||||||
|
|
||||||
|
return self.XYoff + np.array([x,y])
|
||||||
|
|
||||||
|
class traj_param_ellipse_3D:
|
||||||
|
def float_range(self, start, end, step):
|
||||||
|
while start <= end:
|
||||||
|
yield start
|
||||||
|
start += step
|
||||||
|
|
||||||
|
def __init__(self, XYoff, r, zl, zh, alpha, wb):
|
||||||
|
self.dim = 3
|
||||||
|
self.XYoff, self.r, self.zl, self.zh, self.alpha, self.wb = XYoff, r, zl, zh, alpha, wb
|
||||||
|
self.mapgrad_X = []
|
||||||
|
self.mapgrad_Y = []
|
||||||
|
self.mapgrad_U = []
|
||||||
|
self.mapgrad_V = []
|
||||||
|
|
||||||
|
self.deltaz = self.zh - self.zl # For the 3D plot
|
||||||
|
self.zo = self.zl + self.deltaz # For the 3D plot
|
||||||
|
self.alpha = self.alpha*np.pi/180
|
||||||
|
|
||||||
|
self.wpoint = self.param_point(self.wb)
|
||||||
|
|
||||||
|
num_points = 100
|
||||||
|
self.traj_points = np.zeros((3, num_points))
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
range_points = 2*np.pi + 0.1
|
||||||
|
for t in self.float_range(0, range_points, range_points/num_points):
|
||||||
|
self.traj_points[:, i] = self.param_point(t)
|
||||||
|
i = i + 1
|
||||||
|
if i >= num_points:
|
||||||
|
break
|
||||||
|
|
||||||
|
def param_point(self, t):
|
||||||
|
x = self.r * np.cos(t) + self.XYoff[0]
|
||||||
|
y = self.r * np.sin(t) + self.XYoff[1]
|
||||||
|
z = 0.5 * (self.zh + self.zl + (self.zl - self.zh) * np.sin(self.alpha - t))
|
||||||
|
|
||||||
|
return np.array([x,y,z])
|
||||||
|
|
||||||
|
class traj_param_lissajous_3D:
|
||||||
|
def float_range(self, start, end, step):
|
||||||
|
while start <= end:
|
||||||
|
yield start
|
||||||
|
start += step
|
||||||
|
|
||||||
|
def __init__(self, XYoff, zo, cx, cy, cz, wx, wy, wz, dx, dy, dz, alpha, wb):
|
||||||
|
self.dim = 3
|
||||||
|
self.XYoff, self.zo, self.cx, self.cy, self.cz, self.wx, self.wy, self.wz, self.dx, self.dy, self.dz, \
|
||||||
|
self.alpha, self.wb = XYoff, zo, cx, cy, cz, wx, wy, wz, dx, dy, dz, alpha, wb
|
||||||
|
self.mapgrad_X = []
|
||||||
|
self.mapgrad_Y = []
|
||||||
|
self.mapgrad_U = []
|
||||||
|
self.mapgrad_V = []
|
||||||
|
|
||||||
|
self.deltaz = self.cz # For the 3D plot
|
||||||
|
self.alpha = self.alpha*np.pi/180
|
||||||
|
self.dx = self.dx*np.pi/180
|
||||||
|
self.dy = self.dy*np.pi/180
|
||||||
|
self.dz = self.dz*np.pi/180
|
||||||
|
|
||||||
|
self.wpoint = self.param_point(self.wb)
|
||||||
|
|
||||||
|
smallest_w = min([self.wx, self.wy, self.wz])
|
||||||
|
|
||||||
|
num_points = 100
|
||||||
|
self.traj_points = np.zeros((3, num_points))
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
range_points = 3*np.pi / smallest_w
|
||||||
|
for t in self.float_range(0, range_points, range_points/num_points):
|
||||||
|
self.traj_points[:, i] = self.param_point(t)
|
||||||
|
i = i + 1
|
||||||
|
if i >= num_points:
|
||||||
|
break
|
||||||
|
|
||||||
|
def param_point(self, t):
|
||||||
|
xnr = self.cx*np.cos(self.wx*t + self.dx)
|
||||||
|
ynr = self.cy*np.cos(self.wy*t + self.dy)
|
||||||
|
z = self.cz*np.cos(self.wz*t + self.dz) + self.zo
|
||||||
|
|
||||||
|
x = np.cos(self.alpha)*xnr - np.sin(self.alpha)*ynr + self.XYoff[0]
|
||||||
|
y = np.sin(self.alpha)*xnr + np.cos(self.alpha)*ynr + self.XYoff[1]
|
||||||
|
|
||||||
|
return np.array([x,y,z])
|
||||||
|
|||||||
Reference in New Issue
Block a user