PX4 Firmware
PX4 Autopilot Software http://px4.io
mission_feasibility_checker.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2019 PX4 Development Team. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * 3. Neither the name PX4 nor the names of its contributors may be
16  * used to endorse or promote products derived from this software
17  * without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
26  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
27  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  *
32  ****************************************************************************/
33 /**
34  * @file mission_feasibility_checker.cpp
35  * Provides checks if mission is feasible given the navigation capabilities
36  *
37  * @author Lorenz Meier <lm@inf.ethz.ch>
38  * @author Thomas Gubler <thomasgubler@student.ethz.ch>
39  * @author Sander Smeets <sander@droneslab.com>
40  * @author Nuno Marques <nuno.marques@dronesolutions.io>
41  */
42 
44 
45 #include "mission_block.h"
46 #include "navigator.h"
47 
48 #include <drivers/drv_pwm_output.h>
49 #include <lib/ecl/geo/geo.h>
50 #include <lib/mathlib/mathlib.h>
52 #include <systemlib/mavlink_log.h>
53 #include <uORB/Subscription.hpp>
55 
56 bool
58  float max_distance_to_1st_waypoint, float max_distance_between_waypoints,
59  bool land_start_req)
60 {
61  bool failed = false;
62  bool warned = false;
63 
64  // first check if we have a valid position
65  const bool home_valid = _navigator->home_position_valid();
66  const bool home_alt_valid = _navigator->home_alt_valid();
67 
68  if (!home_alt_valid) {
69  failed = true;
70  warned = true;
71  mavlink_log_info(_navigator->get_mavlink_log_pub(), "Not yet ready for mission, no position lock.");
72 
73  } else {
74  failed = failed || !checkDistanceToFirstWaypoint(mission, max_distance_to_1st_waypoint);
75  }
76 
77  const float home_alt = _navigator->get_home_position()->alt;
78 
79  // check if all mission item commands are supported
80  failed = failed || !checkMissionItemValidity(mission);
81  failed = failed || !checkDistancesBetweenWaypoints(mission, max_distance_between_waypoints);
82  failed = failed || !checkGeofence(mission, home_alt, home_valid);
83  failed = failed || !checkHomePositionAltitude(mission, home_alt, home_alt_valid, warned);
84 
85  // VTOL always respects rotary wing feasibility
86  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING
88  failed = failed || !checkRotarywing(mission, home_alt);
89 
90  } else {
91  failed = failed || !checkFixedwing(mission, home_alt, land_start_req);
92  }
93 
94  return !failed;
95 }
96 
97 bool
99 {
100  /*
101  * Perform check and issue feedback to the user
102  * Mission is only marked as feasible if takeoff check passes
103  */
104  return checkTakeoff(mission, home_alt);
105 }
106 
107 bool
108 MissionFeasibilityChecker::checkFixedwing(const mission_s &mission, float home_alt, bool land_start_req)
109 {
110  /* Perform checks and issue feedback to the user for all checks */
111  bool resTakeoff = checkTakeoff(mission, home_alt);
112  bool resLanding = checkFixedWingLanding(mission, land_start_req);
113 
114  /* Mission is only marked as feasible if all checks return true */
115  return (resTakeoff && resLanding);
116 }
117 
118 bool
119 MissionFeasibilityChecker::checkGeofence(const mission_s &mission, float home_alt, bool home_valid)
120 {
121  if (_navigator->get_geofence().isHomeRequired() && !home_valid) {
122  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence requires valid home position");
123  return false;
124  }
125 
126  /* Check if all mission items are inside the geofence (if we have a valid geofence) */
127  if (_navigator->get_geofence().valid()) {
128  for (size_t i = 0; i < mission.count; i++) {
129  struct mission_item_s missionitem = {};
130  const ssize_t len = sizeof(missionitem);
131 
132  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
133  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
134  return false;
135  }
136 
137  if (missionitem.altitude_is_relative && !home_valid) {
138  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence requires valid home position");
139  return false;
140  }
141 
142  // Geofence function checks against home altitude amsl
143  missionitem.altitude = missionitem.altitude_is_relative ? missionitem.altitude + home_alt : missionitem.altitude;
144 
145  if (MissionBlock::item_contains_position(missionitem) && !_navigator->get_geofence().check(missionitem)) {
146 
147  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence violation for waypoint %zu", i + 1);
148  return false;
149  }
150  }
151  }
152 
153  return true;
154 }
155 
156 bool
157 MissionFeasibilityChecker::checkHomePositionAltitude(const mission_s &mission, float home_alt, bool home_alt_valid,
158  bool throw_error)
159 {
160  /* Check if all waypoints are above the home altitude */
161  for (size_t i = 0; i < mission.count; i++) {
162  struct mission_item_s missionitem = {};
163  const ssize_t len = sizeof(struct mission_item_s);
164 
165  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
167  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
168  return false;
169  }
170 
171  /* reject relative alt without home set */
172  if (missionitem.altitude_is_relative && !home_alt_valid && MissionBlock::item_contains_position(missionitem)) {
173 
175 
176  if (throw_error) {
177  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: No home pos, WP %zu uses rel alt", i + 1);
178  return false;
179 
180  } else {
181  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Warning: No home pos, WP %zu uses rel alt", i + 1);
182  return true;
183  }
184  }
185 
186  /* calculate the global waypoint altitude */
187  float wp_alt = (missionitem.altitude_is_relative) ? missionitem.altitude + home_alt : missionitem.altitude;
188 
189  if ((home_alt > wp_alt) && MissionBlock::item_contains_position(missionitem)) {
190 
192 
193  if (throw_error) {
194  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: Waypoint %zu below home", i + 1);
195  return false;
196 
197  } else {
198  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Warning: Waypoint %zu below home", i + 1);
199  return true;
200  }
201  }
202  }
203 
204  return true;
205 }
206 
207 bool
209 {
210  // do not allow mission if we find unsupported item
211  for (size_t i = 0; i < mission.count; i++) {
212  struct mission_item_s missionitem;
213  const ssize_t len = sizeof(struct mission_item_s);
214 
215  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
216  // not supposed to happen unless the datamanager can't access the SD card, etc.
217  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: Cannot access SD card");
218  return false;
219  }
220 
221  // check if we find unsupported items and reject mission if so
222  if (missionitem.nav_cmd != NAV_CMD_IDLE &&
223  missionitem.nav_cmd != NAV_CMD_WAYPOINT &&
224  missionitem.nav_cmd != NAV_CMD_LOITER_UNLIMITED &&
225  missionitem.nav_cmd != NAV_CMD_LOITER_TIME_LIMIT &&
226  missionitem.nav_cmd != NAV_CMD_RETURN_TO_LAUNCH &&
227  missionitem.nav_cmd != NAV_CMD_LAND &&
228  missionitem.nav_cmd != NAV_CMD_TAKEOFF &&
229  missionitem.nav_cmd != NAV_CMD_LOITER_TO_ALT &&
230  missionitem.nav_cmd != NAV_CMD_VTOL_TAKEOFF &&
231  missionitem.nav_cmd != NAV_CMD_VTOL_LAND &&
232  missionitem.nav_cmd != NAV_CMD_DELAY &&
233  missionitem.nav_cmd != NAV_CMD_DO_JUMP &&
234  missionitem.nav_cmd != NAV_CMD_DO_CHANGE_SPEED &&
235  missionitem.nav_cmd != NAV_CMD_DO_SET_HOME &&
236  missionitem.nav_cmd != NAV_CMD_DO_SET_SERVO &&
237  missionitem.nav_cmd != NAV_CMD_DO_LAND_START &&
238  missionitem.nav_cmd != NAV_CMD_DO_TRIGGER_CONTROL &&
239  missionitem.nav_cmd != NAV_CMD_DO_DIGICAM_CONTROL &&
240  missionitem.nav_cmd != NAV_CMD_IMAGE_START_CAPTURE &&
241  missionitem.nav_cmd != NAV_CMD_IMAGE_STOP_CAPTURE &&
242  missionitem.nav_cmd != NAV_CMD_VIDEO_START_CAPTURE &&
243  missionitem.nav_cmd != NAV_CMD_VIDEO_STOP_CAPTURE &&
244  missionitem.nav_cmd != NAV_CMD_DO_MOUNT_CONFIGURE &&
245  missionitem.nav_cmd != NAV_CMD_DO_MOUNT_CONTROL &&
246  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI &&
247  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_LOCATION &&
248  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_WPNEXT_OFFSET &&
249  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_NONE &&
250  missionitem.nav_cmd != NAV_CMD_DO_SET_CAM_TRIGG_DIST &&
252  missionitem.nav_cmd != NAV_CMD_SET_CAMERA_MODE &&
253  missionitem.nav_cmd != NAV_CMD_DO_VTOL_TRANSITION) {
254 
255  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: item %i: unsupported cmd: %d", (int)(i + 1),
256  (int)missionitem.nav_cmd);
257  return false;
258  }
259 
260  /* Check non navigation item */
261  if (missionitem.nav_cmd == NAV_CMD_DO_SET_SERVO) {
262 
263  /* check actuator number */
264  if (missionitem.params[0] < 0 || missionitem.params[0] > 5) {
265  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Actuator number %d is out of bounds 0..5",
266  (int)missionitem.params[0]);
267  return false;
268  }
269 
270  /* check actuator value */
271  if (missionitem.params[1] < -PWM_DEFAULT_MAX || missionitem.params[1] > PWM_DEFAULT_MAX) {
273  "Actuator value %d is out of bounds -PWM_DEFAULT_MAX..PWM_DEFAULT_MAX", (int)missionitem.params[1]);
274  return false;
275  }
276  }
277 
278  // check if the mission starts with a land command while the vehicle is landed
279  if ((i == 0) && missionitem.nav_cmd == NAV_CMD_LAND && _navigator->get_land_detected()->landed) {
280 
281  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: starts with landing");
282  return false;
283  }
284  }
285 
286  return true;
287 }
288 
289 bool
290 MissionFeasibilityChecker::checkTakeoff(const mission_s &mission, float home_alt)
291 {
292  bool has_takeoff = false;
293  bool takeoff_first = false;
294  int takeoff_index = -1;
295 
296  for (size_t i = 0; i < mission.count; i++) {
297  struct mission_item_s missionitem = {};
298  const ssize_t len = sizeof(struct mission_item_s);
299 
300  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
301  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
302  return false;
303  }
304 
305  // look for a takeoff waypoint
306  if (missionitem.nav_cmd == NAV_CMD_TAKEOFF) {
307  // make sure that the altitude of the waypoint is at least one meter larger than the acceptance radius
308  // this makes sure that the takeoff waypoint is not reached before we are at least one meter in the air
309 
310  float takeoff_alt = missionitem.altitude_is_relative
311  ? missionitem.altitude
312  : missionitem.altitude - home_alt;
313 
314  // check if we should use default acceptance radius
316 
317  if (missionitem.acceptance_radius > NAV_EPSILON_POSITION) {
318  acceptance_radius = missionitem.acceptance_radius;
319  }
320 
321  if (takeoff_alt - 1.0f < acceptance_radius) {
322  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: Takeoff altitude too low!");
323  return false;
324  }
325 
326  // tell that mission has a takeoff waypoint
327  has_takeoff = true;
328 
329  // tell that a takeoff waypoint is the first "waypoint"
330  // mission item
331  if (i == 0) {
332  takeoff_first = true;
333 
334  } else if (takeoff_index == -1) {
335  // stores the index of the first takeoff waypoint
336  takeoff_index = i;
337  }
338  }
339  }
340 
341  if (takeoff_index != -1) {
342  // checks if all the mission items before the first takeoff waypoint
343  // are not waypoints or position-related items;
344  // this means that, before a takeoff waypoint, one can set
345  // one of the bellow mission items
346  for (size_t i = 0; i < (size_t)takeoff_index; i++) {
347  struct mission_item_s missionitem = {};
348  const ssize_t len = sizeof(struct mission_item_s);
349 
350  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
351  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
352  return false;
353  }
354 
355  takeoff_first = !(missionitem.nav_cmd != NAV_CMD_IDLE &&
356  missionitem.nav_cmd != NAV_CMD_DELAY &&
357  missionitem.nav_cmd != NAV_CMD_DO_JUMP &&
358  missionitem.nav_cmd != NAV_CMD_DO_CHANGE_SPEED &&
359  missionitem.nav_cmd != NAV_CMD_DO_SET_HOME &&
360  missionitem.nav_cmd != NAV_CMD_DO_SET_SERVO &&
361  missionitem.nav_cmd != NAV_CMD_DO_LAND_START &&
362  missionitem.nav_cmd != NAV_CMD_DO_TRIGGER_CONTROL &&
363  missionitem.nav_cmd != NAV_CMD_DO_DIGICAM_CONTROL &&
364  missionitem.nav_cmd != NAV_CMD_IMAGE_START_CAPTURE &&
365  missionitem.nav_cmd != NAV_CMD_IMAGE_STOP_CAPTURE &&
366  missionitem.nav_cmd != NAV_CMD_VIDEO_START_CAPTURE &&
367  missionitem.nav_cmd != NAV_CMD_VIDEO_STOP_CAPTURE &&
368  missionitem.nav_cmd != NAV_CMD_DO_MOUNT_CONFIGURE &&
369  missionitem.nav_cmd != NAV_CMD_DO_MOUNT_CONTROL &&
370  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI &&
371  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_LOCATION &&
372  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_WPNEXT_OFFSET &&
373  missionitem.nav_cmd != NAV_CMD_DO_SET_ROI_NONE &&
374  missionitem.nav_cmd != NAV_CMD_DO_SET_CAM_TRIGG_DIST &&
375  missionitem.nav_cmd != NAV_CMD_DO_SET_CAM_TRIGG_INTERVAL &&
376  missionitem.nav_cmd != NAV_CMD_SET_CAMERA_MODE &&
377  missionitem.nav_cmd != NAV_CMD_DO_VTOL_TRANSITION);
378  }
379  }
380 
382  // check for a takeoff waypoint, after the above conditions have been met
383  // MIS_TAKEOFF_REQ param has to be set and the vehicle has to be landed - one can load a mission
384  // while the vehicle is flying and it does not require a takeoff waypoint
385  if (!has_takeoff) {
386  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: takeoff waypoint required.");
387  return false;
388 
389  } else if (!takeoff_first) {
390  // check if the takeoff waypoint is the first waypoint item on the mission
391  // i.e, an item with position/attitude change modification
392  // if it is not, the mission should be rejected
393  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: takeoff not first waypoint item");
394  return false;
395  }
396  }
397 
398  // all checks have passed
399  return true;
400 }
401 
402 bool
404 {
405  /* Go through all mission items and search for a landing waypoint
406  * if landing waypoint is found: the previous waypoint is checked to be at a feasible distance and altitude given the landing slope */
407 
408  bool landing_valid = false;
409 
410  bool land_start_found = false;
411  size_t do_land_start_index = 0;
412  size_t landing_approach_index = 0;
413 
414  for (size_t i = 0; i < mission.count; i++) {
415  struct mission_item_s missionitem;
416  const ssize_t len = sizeof(missionitem);
417 
418  if (dm_read((dm_item_t)mission.dataman_id, i, &missionitem, len) != len) {
419  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
420  return false;
421  }
422 
423  // if DO_LAND_START found then require valid landing AFTER
424  if (missionitem.nav_cmd == NAV_CMD_DO_LAND_START) {
425  if (land_start_found) {
426  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: more than one land start.");
427  return false;
428 
429  } else {
430  land_start_found = true;
431  do_land_start_index = i;
432  }
433  }
434 
435  if (missionitem.nav_cmd == NAV_CMD_LAND) {
436  mission_item_s missionitem_previous {};
437 
438  if (i > 0) {
439  landing_approach_index = i - 1;
440 
441  if (dm_read((dm_item_t)mission.dataman_id, landing_approach_index, &missionitem_previous, len) != len) {
442  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
443  return false;
444  }
445 
446  if (MissionBlock::item_contains_position(missionitem_previous)) {
447 
448  uORB::SubscriptionData<position_controller_landing_status_s> landing_status{ORB_ID(position_controller_landing_status)};
449 
450  const bool landing_status_valid = (landing_status.get().timestamp > 0);
451  const float wp_distance = get_distance_to_next_waypoint(missionitem_previous.lat, missionitem_previous.lon,
452  missionitem.lat, missionitem.lon);
453 
454  if (landing_status_valid && (wp_distance > landing_status.get().flare_length)) {
455  /* Last wp is before flare region */
456 
457  const float delta_altitude = missionitem.altitude - missionitem_previous.altitude;
458 
459  if (delta_altitude < 0) {
460 
461  const float horizontal_slope_displacement = landing_status.get().horizontal_slope_displacement;
462  const float slope_angle_rad = landing_status.get().slope_angle_rad;
463  const float slope_alt_req = Landingslope::getLandingSlopeAbsoluteAltitude(wp_distance, missionitem.altitude,
464  horizontal_slope_displacement, slope_angle_rad);
465 
466  if (missionitem_previous.altitude > slope_alt_req + 1.0f) {
467  /* Landing waypoint is above altitude of slope at the given waypoint distance (with small tolerance for floating point discrepancies) */
468  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: adjust landing approach.");
469 
470  const float wp_distance_req = Landingslope::getLandingSlopeWPDistance(missionitem_previous.altitude,
471  missionitem.altitude, horizontal_slope_displacement, slope_angle_rad);
472 
473  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Move down %d m or move further away by %d m.",
474  (int)ceilf(slope_alt_req - missionitem_previous.altitude),
475  (int)ceilf(wp_distance_req - wp_distance));
476 
477  return false;
478  }
479 
480  } else {
481  /* Landing waypoint is above last waypoint */
482  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: landing above last waypoint.");
483  return false;
484  }
485 
486  } else {
487  /* Last wp is in flare region */
488  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: waypoint within landing flare.");
489  return false;
490  }
491 
492  landing_valid = true;
493 
494  } else {
495  // mission item before land doesn't have a position
496  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: need landing approach.");
497  return false;
498  }
499 
500  } else {
501  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: starts with land waypoint.");
502  return false;
503  }
504  }
505  }
506 
507  if (land_start_req && !land_start_found) {
508  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: landing pattern required.");
509  return false;
510  }
511 
512  if (land_start_found && (!landing_valid || (do_land_start_index > landing_approach_index))) {
513  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission rejected: invalid land start.");
514  return false;
515  }
516 
517  /* No landing waypoints or no waypoints */
518  return true;
519 }
520 
521 bool
523 {
524  if (max_distance <= 0.0f) {
525  /* param not set, check is ok */
526  return true;
527  }
528 
529  /* find first waypoint (with lat/lon) item in datamanager */
530  for (size_t i = 0; i < mission.count; i++) {
531 
532  struct mission_item_s mission_item {};
533 
534  if (!(dm_read((dm_item_t)mission.dataman_id, i, &mission_item, sizeof(mission_item_s)) == sizeof(mission_item_s))) {
535  /* error reading, mission is invalid */
536  mavlink_log_info(_navigator->get_mavlink_log_pub(), "Error reading offboard mission.");
537  return false;
538  }
539 
540  /* check only items with valid lat/lon */
541  if (!MissionBlock::item_contains_position(mission_item)) {
542  continue;
543  }
544 
545  /* check distance from current position to item */
546  float dist_to_1wp = get_distance_to_next_waypoint(
547  mission_item.lat, mission_item.lon,
549 
550  if (dist_to_1wp < max_distance) {
551 
552  return true;
553 
554  } else {
555  /* item is too far from home */
557  "First waypoint too far away: %d meters, %d max.",
558  (int)dist_to_1wp, (int)max_distance);
559 
561  return false;
562  }
563  }
564 
565  /* no waypoints found in mission, then we will not fly far away */
566  return true;
567 }
568 
569 bool
571 {
572  if (max_distance <= 0.0f) {
573  /* param not set, check is ok */
574  return true;
575  }
576 
577  double last_lat = (double)NAN;
578  double last_lon = (double)NAN;
579 
580  /* Go through all waypoints */
581  for (size_t i = 0; i < mission.count; i++) {
582 
583  struct mission_item_s mission_item {};
584 
585  if (!(dm_read((dm_item_t)mission.dataman_id, i, &mission_item, sizeof(mission_item_s)) == sizeof(mission_item_s))) {
586  /* error reading, mission is invalid */
587  mavlink_log_info(_navigator->get_mavlink_log_pub(), "Error reading offboard mission.");
588  return false;
589  }
590 
591  /* check only items with valid lat/lon */
592  if (!MissionBlock::item_contains_position(mission_item)) {
593  continue;
594  }
595 
596  /* Compare it to last waypoint if already available. */
597  if (PX4_ISFINITE(last_lat) && PX4_ISFINITE(last_lon)) {
598 
599  /* check distance from current position to item */
600  const float dist_between_waypoints = get_distance_to_next_waypoint(
601  mission_item.lat, mission_item.lon,
602  last_lat, last_lon);
603 
604  if (dist_between_waypoints > max_distance) {
605  /* item is too far from home */
607  "Distance between waypoints too far: %d meters, %d max.",
608  (int)dist_between_waypoints, (int)max_distance);
609 
611  return false;
612  }
613  }
614 
615  last_lat = mission_item.lat;
616  last_lon = mission_item.lon;
617  }
618 
619  /* We ran through all waypoints and have not found any distances between waypoints that are too far. */
620  return true;
621 }
#define PWM_DEFAULT_MAX
Default maximum PWM in us.
bool home_position_valid()
Definition: navigator.h:166
Global position setpoint in WGS84 coordinates.
Definition: navigation.h:145
bool checkDistancesBetweenWaypoints(const mission_s &mission, float max_distance)
static float getLandingSlopeAbsoluteAltitude(float wp_landing_distance, float wp_landing_altitude, float horizontal_slope_displacement, float landing_slope_angle_rad)
Definition of geo / math functions to perform geodesic calculations.
float altitude
altitude in meters (AMSL)
Definition: navigation.h:160
float acceptance_radius
default radius in which the mission is accepted as reached in meters
Definition: navigation.h:155
bool checkMissionFeasible(const mission_s &mission, float max_distance_to_1st_waypoint, float max_distance_between_waypoints, bool land_start_req)
bool valid()
Definition: geofence.cpp:430
float get_distance_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next)
Returns the distance to the next waypoint in meters.
Definition: geo.cpp:270
Helper class to use mission items.
struct home_position_s * get_home_position()
Getters.
Definition: navigator.h:151
bool checkFixedwing(const mission_s &mission, float home_alt, bool land_start_req)
dm_item_t
Types of items that the data manager can store.
Definition: dataman.h:50
uint8_t dataman_id
Definition: mission.h:56
struct vehicle_land_detected_s * get_land_detected()
Definition: navigator.h:157
Provides checks if mission is feasible given the navigation capabilities.
bool checkRotarywing(const mission_s &mission, float home_alt)
double lon
longitude in degrees
Definition: navigation.h:147
bool get_takeoff_required() const
Definition: navigator.h:287
bool checkTakeoff(const mission_s &mission, float home_alt)
Geofence & get_geofence()
Definition: navigator.h:168
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
uint16_t count
Definition: mission.h:55
__EXPORT ssize_t dm_read(dm_item_t item, unsigned index, void *buf, size_t count)
Retrieve from the data manager file.
Definition: dataman.cpp:1104
bool checkFixedWingLanding(const mission_s &mission, bool land_start_req)
uint16_t nav_cmd
navigation command
Definition: navigation.h:165
bool check(const vehicle_global_position_s &global_position, const vehicle_gps_position_s &gps_position, const home_position_s home_pos, bool home_position_set)
Return whether the system obeys the geofence.
Definition: geofence.cpp:190
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
Definition: integration.cpp:8
bool checkGeofence(const mission_s &mission, float home_alt, bool home_valid)
static float getLandingSlopeWPDistance(float slope_altitude, float wp_landing_altitude, float horizontal_slope_displacement, float landing_slope_angle_rad)
bool home_alt_valid()
Definition: navigator.h:165
float params[7]
array to store mission command values for MAV_FRAME_MISSION
Definition: navigation.h:162
bool checkHomePositionAltitude(const mission_s &mission, float home_alt, bool home_alt_valid, bool throw_error)
struct mission_result_s * get_mission_result()
Definition: navigator.h:152
bool checkMissionItemValidity(const mission_s &mission)
static bool item_contains_position(const mission_item_s &item)
float get_default_acceptance_radius()
Returns the default acceptance radius defined by the parameter.
orb_advert_t * get_mavlink_log_pub()
Definition: navigator.h:261
struct vehicle_status_s * get_vstatus()
Definition: navigator.h:159
bool isHomeRequired()
Definition: geofence.cpp:569
bool checkDistanceToFirstWaypoint(const mission_s &mission, float max_distance)
uint16_t altitude_is_relative
true if altitude is relative from start point
Definition: navigation.h:177
double lat
latitude in degrees
Definition: navigation.h:146