Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
approach_moving_target.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2021 Ewoud Smeur <e.j.j.smeur@tudelft.nl>
3  *
4  * This file is part of paparazzi
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
26 #include "generated/airframe.h"
27 
28 #include "approach_moving_target.h"
29 
30 #include "generated/modules.h"
31 #include "modules/core/abi.h"
33 
34 
35 // Filter value in Hz
36 #ifndef APPROACH_MOVING_TARGET_CUTOFF_FREQ_FILTERS_HZ
37 #define APPROACH_MOVING_TARGET_CUTOFF_FREQ_FILTERS_HZ 0.5
38 #endif
39 
40 // Approach slope angle in degrees
41 #ifndef APPROACH_MOVING_TARGET_SLOPE
42 #define APPROACH_MOVING_TARGET_SLOPE 35.0
43 #endif
44 
45 // Approach initial distance in meters
46 #ifndef APPROACH_MOVING_TARGET_DISTANCE
47 #define APPROACH_MOVING_TARGET_DISTANCE 60.0
48 #endif
49 
50 // Approach speed in meters per second along the slope
51 #ifndef APPROACH_MOVING_TARGET_SPEED
52 #define APPROACH_MOVING_TARGET_SPEED -1.0
53 #endif
54 
55 // Gains
56 #ifndef APPROACH_MOVING_TARGET_ERR_SLOWDOWN_GAIN
57 #define APPROACH_MOVING_TARGET_ERR_SLOWDOWN_GAIN 0.25
58 #endif
59 
60 #ifndef APPROACH_MOVING_TARGET_POS_GAIN
61 #define APPROACH_MOVING_TARGET_POS_GAIN 0.3
62 #endif
63 
64 #ifndef APPROACH_MOVING_TARGET_SPEED_GAIN
65 #define APPROACH_MOVING_TARGET_SPEED_GAIN 1.0
66 #endif
67 
68 #ifndef APPROACH_MOVING_TARGET_RELVEL_GAIN
69 #define APPROACH_MOVING_TARGET_RELVEL_GAIN 1.0
70 #endif
71 
75 
76 #define DEBUG_AMT TRUE
77 #include <stdio.h>
78 
79 struct Amt amt = {
82  .psi_ref = 180.0,
83  .slope_ref = APPROACH_MOVING_TARGET_SLOPE,
84  .err_slowdown_gain = APPROACH_MOVING_TARGET_ERR_SLOWDOWN_GAIN,
88  .cutoff_freq_filters_hz = APPROACH_MOVING_TARGET_CUTOFF_FREQ_FILTERS_HZ,
89  .enabled_time = 0,
90  .wp_id = 0,
91 };
92 
93 struct AmtTelem {
94  struct FloatVect3 des_pos;
95  struct FloatVect3 des_vel;
96 };
97 
98 struct AmtTelem amt_telem;
100 
101 struct FloatVect3 nav_get_speed_sp_from_diagonal(struct EnuCoor_i target, float pos_gain, float rope_heading);
102 void update_waypoint(uint8_t wp_id, struct FloatVect3 *target_ned);
103 
104 #if PERIODIC_TELEMETRY
106 static void send_approach_moving_target(struct transport_tx *trans, struct link_device *dev)
107 {
108  pprz_msg_send_APPROACH_MOVING_TARGET(trans, dev, AC_ID,
115  &amt.distance);
116 }
117 #endif
118 
120 {
122 #if PERIODIC_TELEMETRY
123  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_APPROACH_MOVING_TARGET, send_approach_moving_target);
124 #endif
125 }
126 
128 {
129  amt.cutoff_freq_filters_hz = filter_freq;
130  // tau = 1/(2*pi*Fc)
131  float tau = 1.0 / (2.0 * M_PI * amt.cutoff_freq_filters_hz);
132  float sample_time = 1.0 / FOLLOW_DIAGONAL_APPROACH_FREQ;
133  for (uint8_t i = 0; i < 3; i++) {
134  init_butterworth_2_low_pass(&target_pos_filt[i], tau, sample_time, 0.0);
135  init_butterworth_2_low_pass(&target_vel_filt[i], tau, sample_time, 0.0);
136  }
137  init_butterworth_2_low_pass(&target_heading_filt, tau, sample_time, 0.0);
138 
139 }
140 
141 // Update a waypoint such that you can see on the GCS where the drone wants to go
142 void update_waypoint(uint8_t wp_id, struct FloatVect3 *target_ned)
143 {
144 
145  // Update the waypoint
146  struct EnuCoor_f target_enu;
147  ENU_OF_TO_NED(target_enu, *target_ned);
148  waypoint_set_enu(wp_id, &target_enu);
149 
150  // Send waypoint update every half second
151  RunOnceEvery(100 / 2, {
152  // Send to the GCS that the waypoint has been moved
153  DOWNLINK_SEND_WP_MOVED_ENU(DefaultChannel, DefaultDevice, &wp_id,
154  &waypoints[wp_id].enu_i.x,
155  &waypoints[wp_id].enu_i.y,
156  &waypoints[wp_id].enu_i.z);
157  });
158 }
159 
160 // Function to enable from flight plan (call repeatedly!)
162 {
164  amt.wp_id = wp_id;
165 }
166 
172 {
173 
174  // Check if the flight plan recently called the enable function
176  return;
177  }
178 
179  // Get the target position, velocity and heading
180  struct NedCoor_f target_pos, target_vel = {0};
181  float target_heading;
182  if (!target_get_pos(&target_pos, &target_heading)) {
183  // TODO: What to do? Same can be checked for the velocity
184  return;
185  }
186  if (target_heading > 360.f) {
187  // TODO: We got an invalid heading and need to do something with it
188  return;
189  }
190  target_get_vel(&target_vel);
191 
192  // filter target values
196 
200 
201  // just filtering the heading will go wrong if it wraps, instead do:
202  // take the diff with current heading_filtered, wrap that, add to current, insert in filter and wrap again?
203  // example: target_heading - target_heading_filt (170 - -170 = 340), -> -20 -> -190 -> into filter -> wrap
204  float heading_diff = RadOfDeg(target_heading) - target_heading_filt.o[0];
205  FLOAT_ANGLE_NORMALIZE(heading_diff);
206  float target_heading_input = target_heading_filt.o[0] + heading_diff;
207  update_butterworth_2_low_pass(&target_heading_filt, target_heading_input);
208  float target_heading_filt_wrapped = target_heading_filt.o[0];
209  FLOAT_ANGLE_NORMALIZE(target_heading_filt_wrapped);
210 
211  target_pos.x = target_pos_filt[0].o[0];
212  target_pos.y = target_pos_filt[1].o[0];
213  target_pos.z = target_pos_filt[2].o[0];
214 
215  target_vel.x = target_vel_filt[0].o[0];
216  target_vel.y = target_vel_filt[1].o[0];
217  target_vel.z = target_vel_filt[2].o[0];
218 
219  VECT3_SMUL(target_vel, target_vel, amt.speed_gain);
220 
221  // Reference model
222  float gamma_ref = RadOfDeg(amt.slope_ref);
223  float psi_ref = target_heading_filt_wrapped + RadOfDeg(amt.psi_ref);
224 
225  amt.rel_unit_vec.x = cosf(gamma_ref) * cosf(psi_ref);
226  amt.rel_unit_vec.y = cosf(gamma_ref) * sinf(psi_ref);
227  amt.rel_unit_vec.z = -sinf(gamma_ref);
228 
229  // desired position = rel_pos + target_pos
230  struct FloatVect3 ref_relpos;
231  VECT3_SMUL(ref_relpos, amt.rel_unit_vec, amt.distance);
232 
233  // ATTENTION, target_pos is already relative now!
234  struct FloatVect3 des_pos;
235  VECT3_SUM(des_pos, ref_relpos, target_pos);
236 
237  struct FloatVect3 ref_relvel;
239 
240  // error controller
241  struct FloatVect3 pos_err;
242  struct FloatVect3 ec_vel;
243  struct NedCoor_f *drone_pos = stateGetPositionNed_f();
244  // ATTENTION, target_pos is already relative now!
245  // VECT3_DIFF(pos_err, des_pos, *drone_pos);
246  VECT3_COPY(pos_err, des_pos);
247  VECT3_SMUL(ec_vel, pos_err, amt.pos_gain);
248 
249  // desired velocity = rel_vel + target_vel + error_controller(using NED position)
250  struct FloatVect3 des_vel = {
251  ref_relvel.x + target_vel.x + ec_vel.x,
252  ref_relvel.y + target_vel.y + ec_vel.y,
253  ref_relvel.z + target_vel.z + ec_vel.z,
254  };
255 
256  float_vect3_bound_in_3d(&des_vel, 10.0);
257 
258  // Bound vertical speed setpoint
259  if (stateGetAirspeed_f() > 13.0) {
260  Bound(des_vel.z, -4.0, 5.0);
261  } else {
262  Bound(des_vel.z, -nav.climb_vspeed, -nav.descend_vspeed);
263  }
264 
265  AbiSendMsgVEL_SP(VEL_SP_FCR_ID, &des_vel);
266 
267  /* limit the speed such that the vertical component is small enough
268  * and doesn't outrun the vehicle
269  */
270  float min_speed;
271  float sin_gamma_ref = sinf(gamma_ref);
272  if (sin_gamma_ref > 0.05) {
273  min_speed = (nav.descend_vspeed + 0.1) / sin_gamma_ref;
274  } else {
275  min_speed = -5.0; // prevent dividing by zero
276  }
277 
278  // The upper bound is not very important
279  Bound(amt.speed, min_speed, 4.0);
280 
281  // Reduce approach speed if the error is large
282  float norm_pos_err_sq = VECT3_NORM2(pos_err);
283  float int_speed = amt.speed / (norm_pos_err_sq * amt.err_slowdown_gain + 1.0);
284 
285  // integrate speed to get the distance
286  float dt = FOLLOW_DIAGONAL_APPROACH_PERIOD;
287  amt.distance += int_speed * dt;
288 
289  // For display purposes
290  struct FloatVect3 disp_pos_target;
291  VECT3_SUM(disp_pos_target, des_pos, *drone_pos);
292  update_waypoint(amt.wp_id, &disp_pos_target);
293 
294  // Debug target pos:
295  VECT3_DIFF(amt_telem.des_pos, *drone_pos, target_pos);
296 
297  // Update values for telemetry
298  VECT3_COPY(amt_telem.des_pos, des_pos);
299  VECT3_COPY(amt_telem.des_vel, des_vel);
300 }
Main include for ABI (AirBorneInterface).
#define VEL_SP_FCR_ID
#define APPROACH_MOVING_TARGET_CUTOFF_FREQ_FILTERS_HZ
#define APPROACH_MOVING_TARGET_POS_GAIN
void follow_diagonal_approach(void)
Generates a velocity reference from a diagonal approach path.
struct FloatVect3 nav_get_speed_sp_from_diagonal(struct EnuCoor_i target, float pos_gain, float rope_heading)
struct AmtTelem amt_telem
Butterworth2LowPass target_pos_filt[3]
Butterworth2LowPass target_heading_filt
#define APPROACH_MOVING_TARGET_RELVEL_GAIN
#define APPROACH_MOVING_TARGET_SPEED
struct Amt amt
#define APPROACH_MOVING_TARGET_SLOPE
void approach_moving_target_set_low_pass_freq(float filter_freq)
struct FloatVect3 des_vel
bool approach_moving_target_enabled
Butterworth2LowPass target_vel_filt[3]
struct FloatVect3 des_pos
static void send_approach_moving_target(struct transport_tx *trans, struct link_device *dev)
#define APPROACH_MOVING_TARGET_DISTANCE
void approach_moving_target_init(void)
void update_waypoint(uint8_t wp_id, struct FloatVect3 *target_ned)
#define APPROACH_MOVING_TARGET_SPEED_GAIN
void approach_moving_target_enable(uint8_t wp_id)
#define APPROACH_MOVING_TARGET_ERR_SLOWDOWN_GAIN
float speed_gain
int32_t enabled_time
float err_slowdown_gain
uint8_t wp_id
float relvel_gain
float cutoff_freq_filters_hz
struct FloatVect3 rel_unit_vec
uint32_t get_sys_time_msec(void)
Get the time in milliseconds since startup.
Definition: sys_time_arch.c:98
struct point waypoints[NB_WAYPOINT]
size == nb_waypoint, waypoint 0 is a dummy waypoint
Definition: common_nav.c:44
float y
Definition: common_nav.h:41
float x
Definition: common_nav.h:40
#define FLOAT_ANGLE_NORMALIZE(_a)
void float_vect3_bound_in_3d(struct FloatVect3 *vect3, float bound)
#define VECT3_SUM(_c, _a, _b)
Definition: pprz_algebra.h:161
#define VECT3_NORM2(_v)
Definition: pprz_algebra.h:252
#define VECT3_SMUL(_vo, _vi, _s)
Definition: pprz_algebra.h:189
#define VECT3_COPY(_a, _b)
Definition: pprz_algebra.h:140
#define VECT3_DIFF(_c, _a, _b)
Definition: pprz_algebra.h:182
#define ENU_OF_TO_NED(_po, _pi)
Definition: pprz_geodetic.h:41
vector in East North Up coordinates
static struct NedCoor_f * stateGetPositionNed_f(void)
Get position in local NED coordinates (float).
Definition: state.h:839
static float stateGetAirspeed_f(void)
Get airspeed (float).
Definition: state.h:1590
Simple first order low pass filter with bilinear transform.
float o[2]
output history
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
Second order low pass filter structure.
void waypoint_set_enu(uint8_t wp_id, struct EnuCoor_f *enu)
Set local ENU waypoint coordinates.
Definition: waypoints.c:177
#define NAVIGATION_FREQUENCY
Default fixedwing navigation frequency.
Definition: nav.h:49
float z
in meters
float x
in meters
float y
in meters
vector in East North Up coordinates Units: meters
vector in North East Down coordinates Units: meters
struct RotorcraftNavigation nav
Definition: navigation.c:51
float descend_vspeed
descend speed setting, mostly used in flight plans
Definition: navigation.h:147
float climb_vspeed
climb speed setting, mostly used in flight plans
Definition: navigation.h:146
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
bool target_get_pos(struct NedCoor_f *pos, float *heading)
Get the current target position (NED) and heading.
Definition: target_pos.c:143
struct target_t target
Definition: target_pos.c:65
bool target_get_vel(struct NedCoor_f *vel)
Get the current target velocity (NED)
Definition: target_pos.c:192
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98