Paparazzi UAS  v5.8.2_stable-0-g6260b7c
Paparazzi is a free software Unmanned Aircraft System.
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
navigation.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008-2009 Antoine Drouin <poinix@gmail.com>
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, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
29 #define NAV_C
30 
32 
33 #include "pprz_debug.h"
34 #include "subsystems/gps.h" // needed by auto_nav from the flight plan
35 #include "subsystems/ins.h"
36 #include "state.h"
37 
39 #include "generated/modules.h"
40 #include "generated/flight_plan.h"
41 
42 /* for default GUIDANCE_H_USE_REF */
44 
45 #include "math/pprz_algebra_int.h"
46 
48 #include "messages.h"
49 #include "mcu_periph/uart.h"
50 
53 
55 
57 
59 #ifndef FAILSAFE_MODE_DISTANCE
60 #define FAILSAFE_MODE_DISTANCE (1.5*MAX_DIST_FROM_HOME)
61 #endif
62 
63 const float max_dist_from_home = MAX_DIST_FROM_HOME;
64 const float max_dist2_from_home = MAX_DIST_FROM_HOME * MAX_DIST_FROM_HOME;
68 
69 bool_t exception_flag[10] = {0}; //exception flags that can be used in the flight plan
70 
72 
74 struct EnuCoor_i nav_segment_start, nav_segment_end;
77 
80 
82 
85 float nav_radius;
87 
89 #ifndef DEFAULT_CIRCLE_RADIUS
90 #define DEFAULT_CIRCLE_RADIUS 5.
91 #endif
92 
93 #ifndef NAV_CLIMB_VSPEED
94 #define NAV_CLIMB_VSPEED 0.5
95 #endif
96 
97 #ifndef NAV_DESCEND_VSPEED
98 #define NAV_DESCEND_VSPEED -0.8
99 #endif
100 
105 
106 static inline void nav_set_altitude(void);
107 
108 #define CLOSE_TO_WAYPOINT (15 << 8)
109 #define CARROT_DIST (12 << 8)
110 
112 #ifndef ARRIVED_AT_WAYPOINT
113 #define ARRIVED_AT_WAYPOINT 3.0
114 #endif
115 
116 #if PERIODIC_TELEMETRY
118 
119 void set_exception_flag(uint8_t flag_num) {
120  exception_flag[flag_num] = 1;
121 }
122 
123 static void send_nav_status(struct transport_tx *trans, struct link_device *dev)
124 {
125  float dist_home = sqrtf(dist2_to_home);
126  float dist_wp = sqrtf(dist2_to_wp);
127  pprz_msg_send_ROTORCRAFT_NAV_STATUS(trans, dev, AC_ID,
129  &dist_home, &dist_wp,
130  &nav_block, &nav_stage,
131  &horizontal_mode);
133  float sx = POS_FLOAT_OF_BFP(nav_segment_start.x);
134  float sy = POS_FLOAT_OF_BFP(nav_segment_start.y);
135  float ex = POS_FLOAT_OF_BFP(nav_segment_end.x);
136  float ey = POS_FLOAT_OF_BFP(nav_segment_end.y);
137  pprz_msg_send_SEGMENT(trans, dev, AC_ID, &sx, &sy, &ex, &ey);
138  } else if (horizontal_mode == HORIZONTAL_MODE_CIRCLE) {
142  pprz_msg_send_CIRCLE(trans, dev, AC_ID, &cx, &cy, &r);
143  }
144 }
145 
146 static void send_wp_moved(struct transport_tx *trans, struct link_device *dev)
147 {
148  static uint8_t i;
149  i++;
150  if (i >= nb_waypoint) { i = 0; }
151  pprz_msg_send_WP_MOVED_ENU(trans, dev, AC_ID,
152  &i,
153  &(waypoints[i].enu_i.x),
154  &(waypoints[i].enu_i.y),
155  &(waypoints[i].enu_i.z));
156 }
157 #endif
158 
159 void nav_init(void)
160 {
161  waypoints_init();
162 
163  nav_block = 0;
164  nav_stage = 0;
165  nav_altitude = POS_BFP_OF_REAL(SECURITY_HEIGHT);
167  flight_altitude = SECURITY_ALT;
168  VECT3_COPY(navigation_target, waypoints[WP_HOME].enu_i);
169  VECT3_COPY(navigation_carrot, waypoints[WP_HOME].enu_i);
170 
173 
174  nav_roll = 0;
175  nav_pitch = 0;
176  nav_heading = 0;
180  nav_throttle = 0;
181  nav_climb = 0;
182  nav_leg_progress = 0;
183  nav_leg_length = 1;
184 
186  dist2_to_home = 0;
187  dist2_to_wp = 0;
188 
189 #if PERIODIC_TELEMETRY
190  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_ROTORCRAFT_NAV_STATUS, send_nav_status);
191  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_WP_MOVED, send_wp_moved);
192 #endif
193 }
194 
195 static inline void UNUSED nav_advance_carrot(void)
196 {
197  struct EnuCoor_i *pos = stateGetPositionEnu_i();
198  /* compute a vector to the waypoint */
199  struct Int32Vect2 path_to_waypoint;
200  VECT2_DIFF(path_to_waypoint, navigation_target, *pos);
201 
202  /* saturate it */
203  VECT2_STRIM(path_to_waypoint, -(1 << 15), (1 << 15));
204 
205  int32_t dist_to_waypoint = int32_vect2_norm(&path_to_waypoint);
206 
207  if (dist_to_waypoint < CLOSE_TO_WAYPOINT) {
209  } else {
210  struct Int32Vect2 path_to_carrot;
211  VECT2_SMUL(path_to_carrot, path_to_waypoint, CARROT_DIST);
212  VECT2_SDIV(path_to_carrot, path_to_carrot, dist_to_waypoint);
213  VECT2_SUM(navigation_carrot, path_to_carrot, *pos);
214  }
215 }
216 
217 void nav_run(void)
218 {
219 
220 #if GUIDANCE_H_USE_REF
221  // if GUIDANCE_H_USE_REF, CARROT_DIST is not used
223 #else
225 #endif
226 
228 }
229 
230 void nav_circle(struct EnuCoor_i *wp_center, int32_t radius)
231 {
232  if (radius == 0) {
233  VECT2_COPY(navigation_target, *wp_center);
234  dist2_to_wp = get_dist2_to_point(wp_center);
235  } else {
236  struct Int32Vect2 pos_diff;
237  VECT2_DIFF(pos_diff, *stateGetPositionEnu_i(), *wp_center);
238  // go back to half metric precision or values are too large
239  //INT32_VECT2_RSHIFT(pos_diff,pos_diff,INT32_POS_FRAC/2);
240  // store last qdr
241  int32_t last_qdr = nav_circle_qdr;
242  // compute qdr
243  nav_circle_qdr = int32_atan2(pos_diff.y, pos_diff.x);
244  // increment circle radians
245  if (nav_circle_radians != 0) {
246  int32_t angle_diff = nav_circle_qdr - last_qdr;
247  INT32_ANGLE_NORMALIZE(angle_diff);
248  nav_circle_radians += angle_diff;
249  } else {
250  // Smallest angle to increment at next step
251  nav_circle_radians = 1;
252  }
253 
254  // direction of rotation
255  int8_t sign_radius = radius > 0 ? 1 : -1;
256  // absolute radius
257  int32_t abs_radius = abs(radius);
258  // carrot_angle
259  int32_t carrot_angle = ((CARROT_DIST << INT32_ANGLE_FRAC) / abs_radius);
260  Bound(carrot_angle, (INT32_ANGLE_PI / 16), INT32_ANGLE_PI_4);
261  carrot_angle = nav_circle_qdr - sign_radius * carrot_angle;
262  int32_t s_carrot, c_carrot;
263  PPRZ_ITRIG_SIN(s_carrot, carrot_angle);
264  PPRZ_ITRIG_COS(c_carrot, carrot_angle);
265  // compute setpoint
266  VECT2_ASSIGN(pos_diff, abs_radius * c_carrot, abs_radius * s_carrot);
267  INT32_VECT2_RSHIFT(pos_diff, pos_diff, INT32_TRIG_FRAC);
268  VECT2_SUM(navigation_target, *wp_center, pos_diff);
269  }
270  nav_circle_center = *wp_center;
273 }
274 
275 
276 void nav_route(struct EnuCoor_i *wp_start, struct EnuCoor_i *wp_end)
277 {
278  struct Int32Vect2 wp_diff, pos_diff, wp_diff_prec;
279  VECT2_DIFF(wp_diff, *wp_end, *wp_start);
280  VECT2_DIFF(pos_diff, *stateGetPositionEnu_i(), *wp_start);
281  // go back to metric precision or values are too large
282  VECT2_COPY(wp_diff_prec, wp_diff);
283  INT32_VECT2_RSHIFT(wp_diff, wp_diff, INT32_POS_FRAC);
284  INT32_VECT2_RSHIFT(pos_diff, pos_diff, INT32_POS_FRAC);
285  uint32_t leg_length2 = Max((wp_diff.x * wp_diff.x + wp_diff.y * wp_diff.y), 1);
286  nav_leg_length = int32_sqrt(leg_length2);
287  nav_leg_progress = (pos_diff.x * wp_diff.x + pos_diff.y * wp_diff.y) / nav_leg_length;
288  int32_t progress = Max((CARROT_DIST >> INT32_POS_FRAC), 0);
289  nav_leg_progress += progress;
290  int32_t prog_2 = nav_leg_length;
291  Bound(nav_leg_progress, 0, prog_2);
292  struct Int32Vect2 progress_pos;
293  VECT2_SMUL(progress_pos, wp_diff_prec, ((float)nav_leg_progress) / nav_leg_length);
294  VECT2_SUM(navigation_target, *wp_start, progress_pos);
295 
296  nav_segment_start = *wp_start;
297  nav_segment_end = *wp_end;
299 
301 }
302 
303 bool_t nav_approaching_from(struct EnuCoor_i *wp, struct EnuCoor_i *from, int16_t approaching_time)
304 {
305  int32_t dist_to_point;
306  struct Int32Vect2 diff;
307  struct EnuCoor_i *pos = stateGetPositionEnu_i();
308 
309  /* if an approaching_time is given, estimate diff after approching_time secs */
310  if (approaching_time > 0) {
311  struct Int32Vect2 estimated_pos;
312  struct Int32Vect2 estimated_progress;
313  struct EnuCoor_i *speed = stateGetSpeedEnu_i();
314  VECT2_SMUL(estimated_progress, *speed, approaching_time);
315  INT32_VECT2_RSHIFT(estimated_progress, estimated_progress, (INT32_SPEED_FRAC - INT32_POS_FRAC));
316  VECT2_SUM(estimated_pos, *pos, estimated_progress);
317  VECT2_DIFF(diff, *wp, estimated_pos);
318  }
319  /* else use current position */
320  else {
321  VECT2_DIFF(diff, *wp, *pos);
322  }
323  /* compute distance of estimated/current pos to target wp
324  * distance with half metric precision (6.25 cm)
325  */
326  INT32_VECT2_RSHIFT(diff, diff, INT32_POS_FRAC / 2);
327  dist_to_point = int32_vect2_norm(&diff);
328 
329  /* return TRUE if we have arrived */
330  if (dist_to_point < BFP_OF_REAL(ARRIVED_AT_WAYPOINT, INT32_POS_FRAC / 2)) {
331  return TRUE;
332  }
333 
334  /* if coming from a valid waypoint */
335  if (from != NULL) {
336  /* return TRUE if normal line at the end of the segment is crossed */
337  struct Int32Vect2 from_diff;
338  VECT2_DIFF(from_diff, *wp, *from);
339  INT32_VECT2_RSHIFT(from_diff, from_diff, INT32_POS_FRAC / 2);
340  return (diff.x * from_diff.x + diff.y * from_diff.y < 0);
341  }
342 
343  return FALSE;
344 }
345 
346 bool_t nav_check_wp_time(struct EnuCoor_i *wp, uint16_t stay_time)
347 {
348  uint16_t time_at_wp;
349  uint32_t dist_to_point;
350  static uint16_t wp_entry_time = 0;
351  static bool_t wp_reached = FALSE;
352  static struct EnuCoor_i wp_last = { 0, 0, 0 };
353  struct Int32Vect2 diff;
354 
355  if ((wp_last.x != wp->x) || (wp_last.y != wp->y)) {
356  wp_reached = FALSE;
357  wp_last = *wp;
358  }
359  VECT2_DIFF(diff, *wp, *stateGetPositionEnu_i());
360  INT32_VECT2_RSHIFT(diff, diff, INT32_POS_FRAC / 2);
361  dist_to_point = int32_vect2_norm(&diff);
362  if (dist_to_point < BFP_OF_REAL(ARRIVED_AT_WAYPOINT, INT32_POS_FRAC / 2)) {
363  if (!wp_reached) {
364  wp_reached = TRUE;
365  wp_entry_time = autopilot_flight_time;
366  time_at_wp = 0;
367  } else {
368  time_at_wp = autopilot_flight_time - wp_entry_time;
369  }
370  } else {
371  time_at_wp = 0;
372  wp_reached = FALSE;
373  }
374  if (time_at_wp > stay_time) {
375  INT_VECT3_ZERO(wp_last);
376  return TRUE;
377  }
378  return FALSE;
379 }
380 
381 static inline void nav_set_altitude(void)
382 {
383  static int32_t last_nav_alt = 0;
384  if (abs(nav_altitude - last_nav_alt) > (POS_BFP_OF_REAL(0.2))) {
386  last_nav_alt = nav_altitude;
387  }
388 }
389 
390 
393 {
395  /* update local ENU coordinates of global waypoints */
397  return 0;
398 }
399 
400 unit_t nav_reset_alt(void)
401 {
404  return 0;
405 }
406 
407 void nav_init_stage(void)
408 {
410  stage_time = 0;
411  nav_circle_radians = 0;
413 }
414 
415 #include <stdio.h>
417 {
418  RunOnceEvery(NAV_FREQ, { stage_time++; block_time++; });
419 
421 
422  dist2_to_wp = 0;
423 
424  /* from flight_plan.h */
425  auto_nav();
426 
427  /* run carrot loop */
428  nav_run();
429 }
430 
431 void navigation_update_wp_from_speed(uint8_t wp, struct Int16Vect3 speed_sp, int16_t heading_rate_sp)
432 {
433  // MY_ASSERT(wp < nb_waypoint); FIXME
434  int32_t s_heading, c_heading;
435  PPRZ_ITRIG_SIN(s_heading, nav_heading);
436  PPRZ_ITRIG_COS(c_heading, nav_heading);
437  // FIXME : scale POS to SPEED
438  struct Int32Vect3 delta_pos;
439  VECT3_SDIV(delta_pos, speed_sp, NAV_FREQ); /* fixme :make sure the division is really a >> */
440  INT32_VECT3_RSHIFT(delta_pos, delta_pos, (INT32_SPEED_FRAC - INT32_POS_FRAC));
441  waypoints[wp].enu_i.x += (s_heading * delta_pos.x + c_heading * delta_pos.y) >> INT32_TRIG_FRAC;
442  waypoints[wp].enu_i.y += (c_heading * delta_pos.x - s_heading * delta_pos.y) >> INT32_TRIG_FRAC;
443  waypoints[wp].enu_i.z += delta_pos.z;
444  int32_t delta_heading = heading_rate_sp / NAV_FREQ;
445  delta_heading = delta_heading >> (INT32_SPEED_FRAC - INT32_POS_FRAC);
446  nav_heading += delta_heading;
447 
448  INT32_COURSE_NORMALIZE(nav_heading);
449  RunOnceEvery(10, DOWNLINK_SEND_WP_MOVED_ENU(DefaultChannel, DefaultDevice, &wp,
450  &(waypoints[wp].enu_i.x),
451  &(waypoints[wp].enu_i.y),
452  &(waypoints[wp].enu_i.z)));
453 }
454 
455 bool_t nav_detect_ground(void)
456 {
457  if (!autopilot_ground_detected) { return FALSE; }
459  return TRUE;
460 }
461 
462 bool_t nav_is_in_flight(void)
463 {
464  return autopilot_in_flight;
465 }
466 
468 void nav_home(void)
469 {
471  VECT3_COPY(navigation_target, waypoints[WP_HOME].enu_i);
472 
474  nav_altitude = waypoints[WP_HOME].enu_i.z;
476 
478 
479  /* run carrot loop */
480  nav_run();
481 }
482 
485 {
486  struct EnuCoor_f *pos = stateGetPositionEnu_f();
487  struct FloatVect2 pos_diff;
488  pos_diff.x = POS_FLOAT_OF_BFP(p->x) - pos->x;
489  pos_diff.y = POS_FLOAT_OF_BFP(p->y) - pos->y;
490  return pos_diff.x * pos_diff.x + pos_diff.y * pos_diff.y;
491 }
492 
495 {
496  return get_dist2_to_point(&waypoints[wp_id].enu_i);
497 }
498 
503 {
506 }
507 
509 bool_t nav_set_heading_rad(float rad)
510 {
513  return FALSE;
514 }
515 
517 bool_t nav_set_heading_deg(float deg)
518 {
519  return nav_set_heading_rad(RadOfDeg(deg));
520 }
521 
523 bool_t nav_set_heading_towards(float x, float y)
524 {
525  struct FloatVect2 target = {x, y};
526  struct FloatVect2 pos_diff;
527  VECT2_DIFF(pos_diff, target, *stateGetPositionEnu_f());
528  // don't change heading if closer than 0.5m to target
529  if (VECT2_NORM2(pos_diff) > 0.25) {
530  float heading_f = atan2f(pos_diff.x, pos_diff.y);
531  nav_heading = ANGLE_BFP_OF_REAL(heading_f);
532  }
533  // return false so it can be called from the flightplan
534  // meaning it will continue to the next stage
535  return FALSE;
536 }
537 
540 {
542 }
543 
546 {
548  return FALSE;
549 }
int32_t psi
in rad with INT32_ANGLE_FRAC
uint16_t block_time
unsigned short uint16_t
Definition: types.h:16
void ins_reset_local_origin(void)
Reset the geographic reference to the current GPS fix.
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
float x
Definition: common_nav.h:40
int32_t y
North.
Generic transmission transport header.
Definition: transport.h:89
int32_t x
East.
#define INT32_SPEED_FRAC
bool_t autopilot_ground_detected
Definition: autopilot.c:78
Periodic telemetry system header (includes downlink utility and generated code).
uint16_t autopilot_flight_time
flight time in seconds.
Definition: autopilot.c:48
#define VECT2_SUM(_c, _a, _b)
Definition: pprz_algebra.h:85
#define INT32_ANGLE_FRAC
#define VECT2_STRIM(_v, _min, _max)
Definition: pprz_algebra.h:109
vector in East North Up coordinates Units: meters
#define POS_BFP_OF_REAL(_af)
#define VECT3_COPY(_a, _b)
Definition: pprz_algebra.h:139
static float radius
Definition: chemotaxis.c:15
#define VECT2_COPY(_a, _b)
Definition: pprz_algebra.h:67
#define VECT2_DIFF(_c, _a, _b)
Definition: pprz_algebra.h:91
uint8_t nav_block
Integrated Navigation System interface.
#define INT32_VECT3_RSHIFT(_o, _i, _r)
Autopilot modes.
#define VECT2_ASSIGN(_a, _x, _y)
Definition: pprz_algebra.h:61
static uint32_t int32_vect2_norm(struct Int32Vect2 *v)
return norm of 2D vector
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:702
#define FALSE
Definition: std.h:5
#define BFP_OF_REAL(_vr, _frac)
#define PPRZ_ITRIG_SIN(_s, _a)
#define TRUE
Definition: std.h:4
float y
Definition: common_nav.h:41
#define Max(x, y)
#define WaypointX(_wp)
Definition: common_nav.h:45
float x
in meters
Device independent GPS code (interface)
bool_t autopilot_in_flight
Definition: autopilot.c:68
#define INT32_ANGLE_NORMALIZE(_a)
unsigned long uint32_t
Definition: types.h:18
signed short int16_t
Definition: types.h:17
#define VECT3_SDIV(_vo, _vi, _s)
Definition: pprz_algebra.h:195
uint32_t int32_sqrt(uint32_t in)
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
#define VECT2_NORM2(_v)
Definition: pprz_algebra.h:117
#define INT32_POS_FRAC
uint16_t stage_time
In s.
#define WaypointY(_wp)
Definition: common_nav.h:46
#define VECT2_SMUL(_vo, _vi, _s)
Definition: pprz_algebra.h:97
const uint8_t nb_waypoint
Definition: common_nav.c:37
signed long int32_t
Definition: types.h:19
#define ANGLE_BFP_OF_REAL(_af)
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:69
uint8_t nav_stage
#define INT32_TRIG_FRAC
#define VECT2_SDIV(_vo, _vi, _s)
Definition: pprz_algebra.h:103
#define INT_VECT3_ZERO(_v)
#define INT32_ANGLE_PI_4
vector in East North Up coordinates
unsigned char uint8_t
Definition: types.h:14
API to get/set the generic vehicle states.
static struct EnuCoor_i * stateGetSpeedEnu_i(void)
Get ground speed in local ENU coordinates (int).
Definition: state.h:849
struct point waypoints[NB_WAYPOINT]
size == nb_waypoint, waypoint 0 is a dummy waypoint
Definition: common_nav.c:38
#define INT32_COURSE_NORMALIZE(_a)
Horizontal guidance for rotorcrafts.
#define INT32_ANGLE_PI
static float p[2][2]
#define POS_FLOAT_OF_BFP(_ai)
static struct EnuCoor_i * stateGetPositionEnu_i(void)
Get position in local ENU coordinates (int).
Definition: state.h:657
#define INT32_VECT2_RSHIFT(_o, _i, _r)
signed char int8_t
Definition: types.h:15
void waypoints_localize_all(void)
update local ENU coordinates of global waypoints
Definition: waypoints.c:265
static struct Int32Eulers * stateGetNedToBodyEulers_i(void)
Get vehicle body attitude euler angles (int).
Definition: state.h:1096
float y
in meters
void ins_reset_altitude_ref(void)
INS altitude reference reset.
void waypoints_init(void)
initialize global and local waypoints
Definition: waypoints.c:35
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:46
#define PPRZ_ITRIG_COS(_c, _a)
int32_t int32_atan2(int32_t y, int32_t x)
Paparazzi fixed point algebra.