Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
nav_rotorcraft_hybrid.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Gautier Hattenberger <gautier.hattenberger@enac.fr>
3  *
4  * This file is part of paparazzi
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
28 #include "math/pprz_isa.h"
29 #include "generated/flight_plan.h"
30 
31 // if NAV_HYBRID_MAX_BANK is not defined, set it to 30 degrees.
32 #ifndef NAV_HYBRID_MAX_BANK
33 float nav_hybrid_max_bank = 0.52f;
34 #else
35 float nav_hybrid_max_bank = NAV_HYBRID_MAX_BANK;
36 #endif
37 
38 // Max ground speed that will be commanded
39 #ifndef NAV_HYBRID_MAX_AIRSPEED
40 #define NAV_HYBRID_MAX_AIRSPEED 15.0f
41 #endif
42 
43 #ifndef NAV_HYBRID_SPEED_MARGIN
44 #define NAV_HYBRID_SPEED_MARGIN 10.0f
45 #endif
46 
47 #define NAV_MAX_SPEED (NAV_HYBRID_MAX_AIRSPEED + NAV_HYBRID_SPEED_MARGIN)
49 
50 #ifndef NAV_HYBRID_GOTO_MAX_SPEED
51 #define NAV_HYBRID_GOTO_MAX_SPEED NAV_MAX_SPEED
52 #endif
53 
55 
56 #ifndef NAV_HYBRID_MAX_DECELERATION
57 #define NAV_HYBRID_MAX_DECELERATION 1.0
58 #endif
59 
61 
62 #ifdef NAV_HYBRID_LINE_GAIN
63 float nav_hybrid_line_gain = NAV_HYBRID_LINE_GAIN;
64 #else
65 float nav_hybrid_line_gain = 1.0f;
66 #endif
67 
68 #ifndef NAV_HYBRID_NAV_LINE_DIST
69 #define NAV_HYBRID_NAV_LINE_DIST 50.f
70 #endif
71 
72 #ifndef NAV_HYBRID_NAV_CIRCLE_DIST
73 #define NAV_HYBRID_NAV_CIRCLE_DIST 40.f
74 #endif
75 
76 #ifdef NAV_HYBRID_POS_GAIN
77 float nav_hybrid_pos_gain = NAV_HYBRID_POS_GAIN;
78 #else
79 float nav_hybrid_pos_gain = 1.0f;
80 #endif
81 
82 #ifndef GUIDANCE_INDI_HYBRID
83 bool force_forward = 0.0f;
84 #endif
85 
86 #ifndef NAV_HYBRID_GOTO_MODE
87 #define NAV_HYBRID_GOTO_MODE NAV_SETPOINT_MODE_SPEED
88 #endif
89 
93 static void nav_hybrid_goto(struct EnuCoor_f *wp)
94 {
97  VECT2_COPY(nav.target, *wp);
98 
99  // Calculate position error
100  struct FloatVect2 pos_error;
101  struct EnuCoor_f *pos = stateGetPositionEnu_f();
102  VECT2_DIFF(pos_error, nav.target, *pos);
103 
104  struct FloatVect2 speed_sp;
106 
107  // Bound the setpoint velocity vector
108  float max_h_speed = nav_max_speed;
109  if (!force_forward) {
110  // If not in force_forward, compute speed based on decceleration and nav_goto_max_speed
111  // Calculate distance to waypoint
112  float dist_to_wp = float_vect2_norm(&pos_error);
113  // Calculate max speed when decelerating at MAX capacity a_max
114  // distance travelled d = 1/2 a_max t^2
115  // The time in which it does this is: T = V / a_max
116  // The maximum speed at which to fly to still allow arriving with zero
117  // speed at the waypoint given maximum deceleration is: V = sqrt(2 * a_max * d)
118  float max_speed_decel2 = fabsf(2.f * dist_to_wp * nav_max_deceleration_sp); // dist_to_wp can only be positive, but just in case
119  float max_speed_decel = sqrtf(max_speed_decel2);
120  // Bound the setpoint velocity vector
121  max_h_speed = Min(nav_goto_max_speed, max_speed_decel); // use hover max speed
122  }
123  float_vect2_bound_in_2d(&speed_sp, max_h_speed);
124 
128 }
129 
130 static void nav_hybrid_route(struct EnuCoor_f *wp_start, struct EnuCoor_f *wp_end)
131 {
132  struct FloatVect2 wp_diff, pos_diff;
133  VECT2_DIFF(wp_diff, *wp_end, *wp_start);
135 
136  // Calculate magnitude of the desired speed vector based on distance to waypoint
137  float dist_to_target = float_vect2_norm(&pos_diff);
138  float desired_speed;
139  if (force_forward) {
140  desired_speed = nav_max_speed;
141  } else {
142  desired_speed = dist_to_target * nav_hybrid_pos_gain;
143  Bound(desired_speed, 0.0f, nav_max_speed);
144  }
145 
146  // Calculate length of line segment
147  float length_line = Max(float_vect2_norm(&wp_diff), 0.01f);
148  // Normal vector to the line, with length of the line
149  struct FloatVect2 normalv;
150  VECT2_ASSIGN(normalv, -wp_diff.y, wp_diff.x);
151  // Length of normal vector is the same as of the line segment
152  float length_normalv = length_line; // >= 0.01
153  // Distance along the normal vector
154  float dist_to_line = (pos_diff.x * normalv.x + pos_diff.y * normalv.y) / length_normalv;
155  // Normal vector scaled to be the distance to the line
156  struct FloatVect2 v_to_line, v_along_line;
157  v_to_line.x = dist_to_line * normalv.x / length_normalv * nav_hybrid_line_gain;
158  v_to_line.y = dist_to_line * normalv.y / length_normalv * nav_hybrid_line_gain;
159  // The distance that needs to be traveled along the line
160  v_along_line.x = wp_diff.x / length_line * NAV_HYBRID_NAV_LINE_DIST;
161  v_along_line.y = wp_diff.y / length_line * NAV_HYBRID_NAV_LINE_DIST;
162  // Calculate the desired direction to converge to the line
163  struct FloatVect2 direction;
164  VECT2_SMUL(direction, v_along_line, (1.f / (1.f + fabsf(dist_to_line) * 0.05f)));
165  VECT2_ADD(direction, v_to_line);
166  float length_direction = Max(float_vect2_norm(&direction), 0.01f);
167  // Scale to have the desired speed
168  VECT2_SMUL(nav.speed, direction, desired_speed / length_direction);
169  // final target position, should be on the line, for display
171 
172  nav_rotorcraft_base.goto_wp.from = *wp_start;
173  nav_rotorcraft_base.goto_wp.to = *wp_end;
177 }
178 
179 static bool nav_hybrid_approaching(struct EnuCoor_f *wp, struct EnuCoor_f *from, float approaching_time)
180 {
181  float dist_to_point;
182  struct FloatVect2 diff;
183  struct EnuCoor_f *pos = stateGetPositionEnu_f();
184 
185  /* if an approaching_time is given, estimate diff after approching_time secs */
186  if (approaching_time > 0.f) {
187  struct FloatVect2 estimated_pos;
188  struct FloatVect2 estimated_progress;
189  struct EnuCoor_f *speed = stateGetSpeedEnu_f();
190  VECT2_SMUL(estimated_progress, *speed, approaching_time);
191  VECT2_SUM(estimated_pos, *pos, estimated_progress);
192  VECT2_DIFF(diff, *wp, estimated_pos);
193  }
194  /* else use current position */
195  else {
196  VECT2_DIFF(diff, *wp, *pos);
197  }
198  /* compute distance of estimated/current pos to target wp
199  */
200  dist_to_point = float_vect2_norm(&diff);
201 
202  /* return TRUE if we have arrived */
203  if (dist_to_point < ARRIVED_AT_WAYPOINT) {
204  return true;
205  }
206 
207  /* if coming from a valid waypoint */
208  if (from != NULL) {
209  /* return TRUE if normal line at the end of the segment is crossed */
210  struct FloatVect2 from_diff;
211  VECT2_DIFF(from_diff, *wp, *from);
212  return (diff.x * from_diff.x + diff.y * from_diff.y < 0.f);
213  }
214 
215  return false;
216 }
217 
218 static void nav_hybrid_circle(struct EnuCoor_f *wp_center, float radius)
219 {
220  struct FloatVect2 pos_diff;
221  float desired_speed;
222 
223  VECT2_DIFF(pos_diff, *stateGetPositionEnu_f(), *wp_center);
224  // direction of rotation
225  float sign_radius = radius > 0.f ? 1.f : -1.f;
226  // absolute radius
227  float abs_radius = fabsf(radius);
228 
229  if (abs_radius > 0.1f) {
230  // store last qdr
231  float last_qdr = nav_rotorcraft_base.circle.qdr;
232  // compute qdr
234  // increment circle radians
235  float trigo_diff = nav_rotorcraft_base.circle.qdr - last_qdr;
236  NormRadAngle(trigo_diff);
237  nav_rotorcraft_base.circle.radians += trigo_diff;
238  // progress angle
239  float progress_angle = NAV_HYBRID_NAV_CIRCLE_DIST / abs_radius;
240  Bound(progress_angle, M_PI / 16.f, M_PI / 4.f);
241  float alpha = nav_rotorcraft_base.circle.qdr - sign_radius * progress_angle;
242  // final target position, should be on the circle, for display
243  nav.target.x = wp_center->x + cosf(alpha) * abs_radius;
244  nav.target.y = wp_center->y + sinf(alpha) * abs_radius;
245  }
246  else {
247  // radius is too small, direct to center
248  VECT2_COPY(nav.target, *wp_center);
249  }
250  // compute desired speed
251  if (force_forward) {
252  desired_speed = nav_max_speed;
253  } else {
254  float radius_diff = fabsf(float_vect2_norm(&pos_diff) - abs_radius);
255  if (radius_diff > NAV_HYBRID_NAV_CIRCLE_DIST) {
256  // far from circle, speed proportional to diff
257  desired_speed = radius_diff * nav_hybrid_pos_gain;
258  } else {
259  // close to circle, speed function of radius for a feasible turn
260  // 0.8 * MAX_BANK gives some margins for the turns
261  desired_speed = sqrtf(PPRZ_ISA_GRAVITY * abs_radius * tanf(0.8f * nav_hybrid_max_bank));
262  }
263  Bound(desired_speed, 0.0f, nav_max_speed);
264  }
265  // compute speed vector from target position
266  struct FloatVect2 speed_unit;
267  VECT2_DIFF(speed_unit, nav.target, *stateGetPositionEnu_f());
268  float_vect2_normalize(&speed_unit);
269  VECT2_SMUL(nav.speed, speed_unit, desired_speed);
270 
271  nav_rotorcraft_base.circle.center = *wp_center;
275 }
276 
284 {
288 
289  // register nav functions
292 }
293 
294 
#define Min(x, y)
Definition: esc_dshot.c:109
void float_vect2_bound_in_2d(struct FloatVect2 *vect2, float bound)
static float float_vect2_norm(struct FloatVect2 *v)
static void float_vect2_normalize(struct FloatVect2 *v)
normalize 2D vector in place
#define VECT2_ADD(_a, _b)
Definition: pprz_algebra.h:74
#define VECT2_SMUL(_vo, _vi, _s)
Definition: pprz_algebra.h:98
#define VECT2_DIFF(_c, _a, _b)
Definition: pprz_algebra.h:92
#define VECT2_COPY(_a, _b)
Definition: pprz_algebra.h:68
#define VECT2_SUM(_c, _a, _b)
Definition: pprz_algebra.h:86
#define VECT2_ASSIGN(_a, _x, _y)
Definition: pprz_algebra.h:62
#define PPRZ_ISA_GRAVITY
earth-surface gravitational acceleration in m/s^2
Definition: pprz_isa.h:56
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:719
static struct EnuCoor_f * stateGetSpeedEnu_f(void)
Get ground speed in local ENU coordinates (float).
Definition: state.h:917
struct FloatVect3 speed_sp
Definition: guidance_indi.c:73
float leg_progress
progress over leg
Definition: nav_base.h:39
struct EnuCoor_f center
center WP position
Definition: nav_base.h:46
struct NavGoto_t goto_wp
Definition: nav_base.h:63
float leg_length
leg length
Definition: nav_base.h:40
struct EnuCoor_f to
end WP position
Definition: nav_base.h:37
float dist2_to_wp
squared distance to next waypoint
Definition: nav_base.h:38
struct NavCircle_t circle
Definition: nav_base.h:64
struct EnuCoor_f from
start WP position
Definition: nav_base.h:36
float radians
incremental angular distance
Definition: nav_base.h:49
float radius
radius in meters
Definition: nav_base.h:47
float qdr
qdr in radians
Definition: nav_base.h:48
struct NavBase_t nav_rotorcraft_base
Basic Nav struct.
float nav_max_deceleration_sp
bool force_forward
forward flight for hybrid nav
static void nav_hybrid_circle(struct EnuCoor_f *wp_center, float radius)
#define NAV_HYBRID_GOTO_MODE
static void nav_hybrid_goto(struct EnuCoor_f *wp)
Implement basic nav function for the hybrid case.
#define NAV_HYBRID_NAV_LINE_DIST
#define NAV_HYBRID_NAV_CIRCLE_DIST
static void nav_hybrid_route(struct EnuCoor_f *wp_start, struct EnuCoor_f *wp_end)
float nav_max_speed
float nav_hybrid_max_bank
#define NAV_HYBRID_GOTO_MAX_SPEED
float nav_hybrid_line_gain
float nav_hybrid_pos_gain
static bool nav_hybrid_approaching(struct EnuCoor_f *wp, struct EnuCoor_f *from, float approaching_time)
float nav_goto_max_speed
void nav_rotorcraft_hybrid_init(void)
Init and register nav functions.
#define NAV_HYBRID_MAX_DECELERATION
#define NAV_MAX_SPEED
Specific navigation functions for hybrid aircraft.
struct FloatVect2 pos_diff
uint8_t direction
float y
in meters
float x
in meters
vector in East North Up coordinates Units: meters
Paparazzi atmospheric pressure conversion utilities.
struct RotorcraftNavigation nav
Definition: navigation.c:51
void nav_register_circle(navigation_circle nav_circle)
Definition: navigation.c:397
void nav_register_goto_wp(navigation_goto nav_goto, navigation_route nav_route, navigation_approaching nav_approaching)
Registering functions.
Definition: navigation.c:390
float get_dist2_to_point(struct EnuCoor_f *p)
Returns squared horizontal distance to given point.
Definition: navigation.c:306
Rotorcraft navigation functions.
struct EnuCoor_f speed
speed setpoint (in m/s)
Definition: navigation.h:128
#define NAV_HORIZONTAL_MODE_WAYPOINT
Nav modes these modes correspond to the flight plan instructions used to set the high level navigatio...
Definition: navigation.h:85
#define NAV_HORIZONTAL_MODE_CIRCLE
Definition: navigation.h:87
#define NAV_HORIZONTAL_MODE_ROUTE
Definition: navigation.h:86
#define NAV_SETPOINT_MODE_SPEED
Definition: navigation.h:101
#define DEFAULT_CIRCLE_RADIUS
default nav_circle_radius in meters
Definition: navigation.h:42
struct EnuCoor_f target
final target position (in meters)
Definition: navigation.h:126
#define ARRIVED_AT_WAYPOINT
minimum horizontal distance to waypoint to mark as arrived
Definition: navigation.h:55
float alpha
Definition: textons.c:133