PX4 Firmware
PX4 Autopilot Software http://px4.io
mission.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (c) 2013-2018 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 navigator_mission.cpp
35  *
36  * Helper class to access missions
37  *
38  * @author Julian Oes <julian@oes.ch>
39  * @author Thomas Gubler <thomasgubler@gmail.com>
40  * @author Anton Babushkin <anton.babushkin@me.com>
41  * @author Ban Siesta <bansiesta@gmail.com>
42  * @author Simon Wilks <simon@uaventure.com>
43  * @author Andreas Antener <andreas@uaventure.com>
44  * @author Sander Smeets <sander@droneslab.com>
45  * @author Lorenz Meier <lorenz@px4.io>
46  */
47 
48 #include "mission.h"
49 #include "navigator.h"
50 
51 #include <string.h>
52 #include <drivers/drv_hrt.h>
53 #include <dataman/dataman.h>
54 #include <systemlib/mavlink_log.h>
55 #include <systemlib/err.h>
56 #include <lib/ecl/geo/geo.h>
57 #include <navigator/navigation.h>
58 #include <uORB/uORB.h>
59 #include <uORB/topics/mission.h>
61 
63  MissionBlock(navigator),
64  ModuleParams(navigator)
65 {
66 }
67 
68 void
70 {
71  /* We need to reset the mission cruising speed, otherwise the
72  * mission velocity which might have been set using mission items
73  * is used for missions such as RTL. */
75 
76  /* Without home a mission can't be valid yet anyway, let's wait. */
78  return;
79  }
80 
81  if (_inited) {
82  if (_mission_sub.updated()) {
84 
85  if (_mission_type == MISSION_TYPE_NONE && _mission.count > 0) {
86  _mission_type = MISSION_TYPE_MISSION;
87  }
88  }
89 
90  /* reset the current mission if needed */
91  if (need_to_reset_mission(false)) {
95  }
96 
97  } else {
98 
99  /* load missions from storage */
100  mission_s mission_state = {};
101 
103 
104  /* read current state */
105  int read_res = dm_read(DM_KEY_MISSION_STATE, 0, &mission_state, sizeof(mission_s));
106 
108 
109  if (read_res == sizeof(mission_s)) {
110  _mission.dataman_id = mission_state.dataman_id;
111  _mission.count = mission_state.count;
112  _current_mission_index = mission_state.current_seq;
113 
114  // find and store landing start marker (if available)
116  }
117 
118  /* On init let's check the mission, maybe there is already one available. */
119  check_mission_valid(false);
120 
121  _inited = true;
122  }
123 
124  /* require takeoff after non-loiter or landing */
126  _need_takeoff = true;
127  }
128 
129  /* reset so current mission item gets restarted if mission was paused */
130  _work_item_type = WORK_ITEM_TYPE_DEFAULT;
131 
132  /* reset so MISSION_ITEM_REACHED isn't published */
134 }
135 
136 void
138 {
139  // Disable camera trigger
140  vehicle_command_s cmd = {};
141  cmd.command = vehicle_command_s::VEHICLE_CMD_DO_TRIGGER_CONTROL;
142  // Pause trigger
143  cmd.param1 = -1.0f;
144  cmd.param3 = 1.0f;
146 }
147 
148 void
150 {
152  // do not set the closest mission item in the normal mission mode
153  if (_mission_execution_mode != mission_result_s::MISSION_EXECUTION_MODE_NORMAL) {
155  }
156 
158  }
159 
160  // we already reset the mission items
161  _execution_mode_changed = false;
162 
164 
165  // unpause triggering if it was paused
166  vehicle_command_s cmd = {};
167  cmd.command = vehicle_command_s::VEHICLE_CMD_DO_TRIGGER_CONTROL;
168  // unpause trigger
169  cmd.param1 = -1.0f;
170  cmd.param3 = 0.0f;
172 }
173 
174 void
176 {
177  if (_work_item_type == WORK_ITEM_TYPE_PRECISION_LAND) {
178  // switch out of precision land once landed
181  _work_item_type = WORK_ITEM_TYPE_DEFAULT;
182 
183  } else {
185  }
186  }
187 
188  check_mission_valid(false);
189 
190  /* check if anything has changed */
191  bool mission_sub_updated = _mission_sub.updated();
192 
193  if (mission_sub_updated) {
195  update_mission();
196  }
197 
198  /* reset the current mission if needed */
199  if (need_to_reset_mission(true)) {
202  update_mission();
204  mission_sub_updated = true;
205  }
206 
207  _mission_changed = false;
208 
209  /* reset mission items if needed */
210  if (mission_sub_updated || _mission_waypoints_changed || _execution_mode_changed) {
212  // do not set the closest mission item in the normal mission mode
213  if (_mission_execution_mode != mission_result_s::MISSION_EXECUTION_MODE_NORMAL) {
215  }
216 
218  }
219 
220  _execution_mode_changed = false;
222  }
223 
224  /* lets check if we reached the current mission item */
225  if (_mission_type != MISSION_TYPE_NONE && is_mission_item_reached()) {
226  /* If we just completed a takeoff which was inserted before the right waypoint,
227  there is no need to report that we reached it because we didn't. */
228  if (_work_item_type != WORK_ITEM_TYPE_TAKEOFF) {
230  }
231 
233  /* switch to next waypoint if 'autocontinue' flag set */
234  advance_mission();
236  }
237 
238  } else if (_mission_type != MISSION_TYPE_NONE && _param_mis_altmode.get() == MISSION_ALTMODE_FOH) {
239 
241 
242  } else {
243  /* if waypoint position reached allow loiter on the setpoint */
246  }
247  }
248 
249  /* check if a cruise speed change has been commanded */
250  if (_mission_type != MISSION_TYPE_NONE) {
252  }
253 
254  /* see if we need to update the current yaw heading */
255  if (!_param_mis_mnt_yaw_ctl.get()
256  && (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING)
257  && (_navigator->get_vroi().mode != vehicle_roi_s::ROI_NONE)
263  || _work_item_type == WORK_ITEM_TYPE_ALIGN)) {
264  // Mount control is disabled If the vehicle is in ROI-mode, the vehicle
265  // needs to rotate such that ROI is in the field of view.
266  // ROI only makes sense for multicopters.
268  }
269 
270  // TODO: Add vtol heading update method if required.
271  // Question: Why does vtol ever have to update heading?
272 
273  /* check if landing needs to be aborted */
275  && (_navigator->abort_landing())) {
276 
278  }
279 }
280 
281 bool
283 {
285  (index != _current_mission_index) && (index < _mission.count)) {
286 
287  _current_mission_index = index;
288 
289  // a mission index is set manually which has the higher priority than the closest mission item
290  // as it is set by the user
292 
293  // update mission items if already in active mission
295  // prevent following "previous - current" line
300  }
301 
302  return true;
303  }
304 
305  return false;
306 }
307 
308 void
310 {
312 }
313 
314 void
316 {
317  if (_mission_execution_mode != mode) {
320 
321 
322  switch (_mission_execution_mode) {
323  case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
324  case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD:
325  if (mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
326  // command a transition if in vtol mc mode
327  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING &&
330 
331  set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW);
332 
334  pos_sp_triplet->previous = pos_sp_triplet->current;
338  }
339 
340  if (_mission_type == MISSION_TYPE_NONE && _mission.count > 0) {
341  _mission_type = MISSION_TYPE_MISSION;
342  }
343 
346 
347  } else if (_current_mission_index > 0) {
349  }
350 
351  _work_item_type = WORK_ITEM_TYPE_DEFAULT;
352  }
353 
354  break;
355 
356  case mission_result_s::MISSION_EXECUTION_MODE_REVERSE:
357  if ((mode == mission_result_s::MISSION_EXECUTION_MODE_NORMAL) ||
358  (mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD)) {
359  // handle switch from reverse to forward mission
360  if (_current_mission_index < 0) {
362 
363  } else if (_current_mission_index < _mission.count - 1) {
365  }
366 
367  _work_item_type = WORK_ITEM_TYPE_DEFAULT;
368  }
369 
370  break;
371 
372  }
373 
375  }
376 }
377 
378 bool
380 {
381  /* return true if a MAV_CMD_DO_LAND_START, NAV_CMD_VTOL_LAND or NAV_CMD_LAND is found and internally save the index
382  * return false if not found
383  */
384 
385  const dm_item_t dm_current = (dm_item_t)_mission.dataman_id;
386  struct mission_item_s missionitem = {};
387  struct mission_item_s missionitem_prev = {}; //to store mission item before currently checked on, needed to get pos of wp before NAV_CMD_DO_LAND_START
388 
389  for (size_t i = 1; i < _mission.count; i++) {
390  const ssize_t len = sizeof(missionitem);
391  missionitem_prev = missionitem; // store the last mission item before reading a new one
392 
393  if (dm_read(dm_current, i, &missionitem, len) != len) {
394  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
395  PX4_ERR("dataman read failure");
396  break;
397  }
398 
399  // first check for DO_LAND_START marker
400  if ((missionitem.nav_cmd == NAV_CMD_DO_LAND_START) && (missionitem_prev.nav_cmd == NAV_CMD_WAYPOINT)) {
401 
402  _land_start_available = true;
403  _land_start_index = i;
404  // the DO_LAND_START marker contains no position sp, so take them from the previous mission item
405  _landing_lat = missionitem_prev.lat;
406  _landing_lon = missionitem_prev.lon;
407  _landing_alt = missionitem_prev.altitude;
408  return true;
409 
410  // if no DO_LAND_START marker available, also check for VTOL_LAND or normal LAND
411 
412  } else if (((missionitem.nav_cmd == NAV_CMD_VTOL_LAND) && _navigator->get_vstatus()->is_vtol) ||
413  (missionitem.nav_cmd == NAV_CMD_LAND)) {
414 
415  _land_start_available = true;
416  _land_start_index = i;
417  _landing_lat = missionitem.lat;
418  _landing_lon = missionitem.lon;
419  _landing_alt = missionitem.altitude;
420  return true;
421  }
422  }
423 
424  _land_start_available = false;
425  return false;
426 }
427 
428 bool
430 {
431  // if not currently landing, jump to do_land_start
432  if (_land_start_available) {
433  if (landing()) {
434  return true;
435 
436  } else {
438  return landing();
439  }
440  }
441 
442  return false;
443 }
444 
445 bool
447 {
448  // vehicle is currently landing if
449  // mission valid, still flying, and in the landing portion of mission
450 
451  const bool mission_valid = _navigator->get_mission_result()->valid;
452  const bool on_landing_stage = _land_start_available && (_current_mission_index >= get_land_start_index());
453 
454  return mission_valid && on_landing_stage;
455 }
456 
457 void
459 {
460 
461  bool failed = true;
462 
463  /* Reset vehicle_roi
464  * Missions that do not explicitly configure ROI would not override
465  * an existing ROI setting from previous missions */
467 
468  const mission_s old_mission = _mission;
469 
470  if (_mission_sub.copy(&_mission)) {
471  /* determine current index */
472  if (_mission.current_seq >= 0 && _mission.current_seq < (int)_mission.count) {
474 
475  } else {
476  /* if less items available, reset to first item */
477  if (_current_mission_index >= (int)_mission.count) {
479 
480  } else if (_current_mission_index < 0) {
481  /* if not initialized, set it to 0 */
483  }
484 
485  /* otherwise, just leave it */
486  }
487 
488  check_mission_valid(true);
489 
490  failed = !_navigator->get_mission_result()->valid;
491 
492  if (!failed) {
493  /* reset mission failure if we have an updated valid mission */
495 
496  /* reset sequence info as well */
499 
500  /* reset work item if new mission has been accepted */
501  _work_item_type = WORK_ITEM_TYPE_DEFAULT;
502  _mission_changed = true;
503  }
504 
505  /* check if the mission waypoints changed while the vehicle is in air
506  * TODO add a flag to mission_s which actually tracks if the position of the waypoint changed */
507  if (((_mission.count != old_mission.count) ||
508  (_mission.dataman_id != old_mission.dataman_id)) &&
511  }
512 
513  } else {
514  PX4_ERR("mission update failed");
515  }
516 
517  if (failed) {
518  _mission.count = 0;
519  _mission.current_seq = 0;
521 
522  PX4_ERR("mission check failed");
523  }
524 
525  // find and store landing start marker (if available)
527 
529 }
530 
531 
532 void
534 {
535  /* do not advance mission item if we're processing sub mission work items */
536  if (_work_item_type != WORK_ITEM_TYPE_DEFAULT) {
537  return;
538  }
539 
540  switch (_mission_type) {
542  switch (_mission_execution_mode) {
543  case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
544  case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
546  break;
547  }
548 
549  case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
550  // find next position item in reverse order
551  dm_item_t dm_current = (dm_item_t)(_mission.dataman_id);
552 
553  for (int32_t i = _current_mission_index - 1; i >= 0; i--) {
554  struct mission_item_s missionitem = {};
555  const ssize_t len = sizeof(missionitem);
556 
557  if (dm_read(dm_current, i, &missionitem, len) != len) {
558  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
559  PX4_ERR("dataman read failure");
560  break;
561  }
562 
563  if (item_contains_position(missionitem)) {
565  return;
566  }
567  }
568 
569  // finished flying back the mission
571  break;
572  }
573 
574  default:
576  }
577 
578  break;
579 
580  case MISSION_TYPE_NONE:
581  default:
582  break;
583  }
584 }
585 
586 void
588 {
589  /* reset the altitude foh (first order hold) logic, if altitude foh is enabled (param) a new foh element starts now */
590  _min_current_sp_distance_xy = FLT_MAX;
591 
592  /* the home dist check provides user feedback, so we initialize it to this */
593  bool user_feedback_done = false;
594 
595  /* mission item that comes after current if available */
596  struct mission_item_s mission_item_next_position;
597  bool has_next_position_item = false;
598 
599  work_item_type new_work_item_type = WORK_ITEM_TYPE_DEFAULT;
600 
601  if (prepare_mission_items(&_mission_item, &mission_item_next_position, &has_next_position_item)) {
602  /* if mission type changed, notify */
603  if (_mission_type != MISSION_TYPE_MISSION) {
605  _mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Executing Reverse Mission" :
606  "Executing Mission");
607  user_feedback_done = true;
608  }
609 
610  _mission_type = MISSION_TYPE_MISSION;
611 
612  } else {
613  /* no mission available or mission finished, switch to loiter */
614  if (_mission_type != MISSION_TYPE_NONE) {
615 
618  _mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Reverse Mission finished, landed" :
619  "Mission finished, landed.");
620 
621  } else {
622  /* https://en.wikipedia.org/wiki/Loiter_(aeronautics) */
624  _mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Reverse Mission finished, loitering" :
625  "Mission finished, loitering.");
626 
627  /* use last setpoint for loiter */
629  }
630 
631  user_feedback_done = true;
632  }
633 
634  _mission_type = MISSION_TYPE_NONE;
635 
636  /* set loiter mission item and ensure that there is a minimum clearance from home */
638 
639  /* update position setpoint triplet */
641  pos_sp_triplet->previous.valid = false;
643  mission_item_to_position_setpoint(_mission_item, &pos_sp_triplet->current);
644  pos_sp_triplet->next.valid = false;
645 
646  /* reuse setpoint for LOITER only if it's not IDLE */
647  _navigator->set_can_loiter_at_sp(pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_LOITER);
648 
649  // set mission finished
652 
653  if (!user_feedback_done) {
654  /* only tell users that we got no mission if there has not been any
655  * better, more specific feedback yet
656  * https://en.wikipedia.org/wiki/Loiter_(aeronautics)
657  */
658 
660  /* landed, refusing to take off without a mission */
661  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "No valid mission available, refusing takeoff.");
662 
663  } else {
664  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "No valid mission available, loitering.");
665  }
666 
667  user_feedback_done = true;
668  }
669 
671  return;
672  }
673 
674  /*********************************** handle mission item *********************************************/
675 
676  /* handle mission items depending on the mode */
677 
678  const position_setpoint_s current_setpoint_copy = _navigator->get_position_setpoint_triplet()->current;
679 
681  switch (_mission_execution_mode) {
682  case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
683  case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
684  /* force vtol land */
687  }
688 
690 
691  // allow weather vane in mission
692  pos_sp_triplet->current.allow_weather_vane = true;
693 
694  /* do takeoff before going to setpoint if needed and not already in takeoff */
695  /* in fixed-wing this whole block will be ignored and a takeoff item is always propagated */
696  if (do_need_vertical_takeoff() &&
697  _work_item_type == WORK_ITEM_TYPE_DEFAULT &&
698  new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
699 
700  new_work_item_type = WORK_ITEM_TYPE_TAKEOFF;
701 
702  /* use current mission item as next position item */
703  mission_item_next_position = _mission_item;
704  mission_item_next_position.nav_cmd = NAV_CMD_WAYPOINT;
705  has_next_position_item = true;
706 
707  float takeoff_alt = calculate_takeoff_altitude(&_mission_item);
708 
709  mavlink_log_info(_navigator->get_mavlink_log_pub(), "Takeoff to %.1f meters above home.",
710  (double)(takeoff_alt - _navigator->get_home_position()->alt));
711 
715  /* hold heading for takeoff items */
717  _mission_item.altitude = takeoff_alt;
720  _mission_item.time_inside = 0.0f;
721 
723  && _work_item_type == WORK_ITEM_TYPE_DEFAULT
724  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT
725  && _navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
726 
727  /* if there is no need to do a takeoff but we have a takeoff item, treat is as waypoint */
729  /* ignore yaw here, otherwise it might yaw before heading_sp_update takes over */
730  _mission_item.yaw = NAN;
731  /* since _mission_item.time_inside and and _mission_item.pitch_min build a union, we need to set time_inside to zero
732  * since in NAV_CMD_TAKEOFF mode there is currently no time_inside.
733  * Note also that resetting time_inside to zero will cause pitch_min to be zero as well.
734  */
735  _mission_item.time_inside = 0.0f;
736 
738  && _work_item_type == WORK_ITEM_TYPE_DEFAULT
739  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
740 
741  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
742  /* haven't transitioned yet, trigger vtol takeoff logic below */
743  _work_item_type = WORK_ITEM_TYPE_TAKEOFF;
744 
745  } else {
746  /* already in fixed-wing, go to waypoint */
748  }
749 
750  /* ignore yaw here, otherwise it might yaw before heading_sp_update takes over */
751  _mission_item.yaw = NAN;
752  }
753 
754  /* if we just did a normal takeoff navigate to the actual waypoint now */
756  _work_item_type == WORK_ITEM_TYPE_TAKEOFF &&
757  new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
758 
760  /* ignore yaw here, otherwise it might yaw before heading_sp_update takes over */
761  _mission_item.yaw = NAN;
762  /* since _mission_item.time_inside and and _mission_item.pitch_min build a union, we need to set time_inside to zero
763  * since in NAV_CMD_TAKEOFF mode there is currently no time_inside.
764  */
765  _mission_item.time_inside = 0.0f;
766  }
767 
768  /* if we just did a VTOL takeoff, prepare transition */
770  _work_item_type == WORK_ITEM_TYPE_TAKEOFF &&
771  new_work_item_type == WORK_ITEM_TYPE_DEFAULT &&
772  _navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING &&
774 
775  /* disable weathervane before front transition for allowing yaw to align */
776  pos_sp_triplet->current.allow_weather_vane = false;
777 
778  /* set yaw setpoint to heading of VTOL_TAKEOFF wp against current position */
782 
784 
785  new_work_item_type = WORK_ITEM_TYPE_ALIGN;
786 
787  /* set position setpoint to current while aligning */
790  }
791 
792  /* heading is aligned now, prepare transition */
794  _work_item_type == WORK_ITEM_TYPE_ALIGN &&
795  _navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING &&
797 
798  /* check if the vtol_takeoff waypoint is on top of us */
799  if (do_need_move_to_takeoff()) {
800  new_work_item_type = WORK_ITEM_TYPE_TRANSITON_AFTER_TAKEOFF;
801  }
802 
803  set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW);
804 
805  /* set position setpoint to target during the transition */
806  // TODO: if has_next_position_item and use_next set next, or if use_heading set generated
808  }
809 
810  /* takeoff completed and transitioned, move to takeoff wp as fixed wing */
812  && _work_item_type == WORK_ITEM_TYPE_TRANSITON_AFTER_TAKEOFF
813  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
814 
815  new_work_item_type = WORK_ITEM_TYPE_DEFAULT;
818  _mission_item.time_inside = 0.0f;
819  }
820 
821  /* move to land wp as fixed wing */
823  && _work_item_type == WORK_ITEM_TYPE_DEFAULT
824  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT
826 
827  new_work_item_type = WORK_ITEM_TYPE_MOVE_TO_LAND;
828 
829  /* use current mission item as next position item */
830  mission_item_next_position = _mission_item;
831  has_next_position_item = true;
832 
834 
835  if (pos_sp_triplet->current.valid && pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_POSITION) {
836  altitude = pos_sp_triplet->current.alt;
837  }
838 
843  _mission_item.time_inside = 0.0f;
845  }
846 
847  /* transition to MC */
849  && _work_item_type == WORK_ITEM_TYPE_MOVE_TO_LAND
850  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT
853 
854  set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC);
855 
857  }
858 
859  /* move to landing waypoint before descent if necessary */
860  if (do_need_move_to_land() &&
861  (_work_item_type == WORK_ITEM_TYPE_DEFAULT ||
862  _work_item_type == WORK_ITEM_TYPE_MOVE_TO_LAND_AFTER_TRANSITION) &&
863  new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
864 
865  new_work_item_type = WORK_ITEM_TYPE_MOVE_TO_LAND;
866 
867  /* use current mission item as next position item */
868  mission_item_next_position = _mission_item;
869  has_next_position_item = true;
870 
871  /*
872  * Ignoring waypoint altitude:
873  * Set altitude to the same as we have now to prevent descending too fast into
874  * the ground. Actual landing will descend anyway until it touches down.
875  * XXX: We might want to change that at some point if it is clear to the user
876  * what the altitude means on this waypoint type.
877  */
879 
880  if (pos_sp_triplet->current.valid
881  && pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_POSITION) {
882  altitude = pos_sp_triplet->current.alt;
883  }
884 
889  _mission_item.time_inside = 0.0f;
890 
891  } else if (_mission_item.nav_cmd == NAV_CMD_LAND && _work_item_type == WORK_ITEM_TYPE_DEFAULT) {
893  new_work_item_type = WORK_ITEM_TYPE_PRECISION_LAND;
894 
895  if (_mission_item.land_precision == 1) {
897 
898  } else { //_mission_item.land_precision == 2
900  }
901 
903 
904  }
905  }
906 
907  /* we just moved to the landing waypoint, now descend */
908  if (_work_item_type == WORK_ITEM_TYPE_MOVE_TO_LAND &&
909  new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
910 
912  new_work_item_type = WORK_ITEM_TYPE_PRECISION_LAND;
913 
914  if (_mission_item.land_precision == 1) {
916 
917  } else { //_mission_item.land_precision == 2
919  }
920 
922 
923  }
924 
925  }
926 
927  /* ignore yaw for landing items */
928  /* XXX: if specified heading for landing is desired we could add another step before the descent
929  * that aligns the vehicle first */
931  _mission_item.yaw = NAN;
932  }
933 
934 
935  // for fast forward convert certain types to simple waypoint
936  // XXX: add other types which should be ignored in fast forward
937  if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD &&
942  _mission_item.time_inside = 0.0f;
943  }
944 
945  break;
946  }
947 
948  case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
950  // convert mission item to a simple waypoint
953  _mission_item.time_inside = 0.0f;
954 
955  } else {
956  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "MissionReverse: Got a non-position mission item, ignoring it");
957  }
958 
959  break;
960  }
961  }
962 
963  } else {
964  /* handle non-position mission items such as commands */
965  switch (_mission_execution_mode) {
966  case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
967  case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
969 
970  /* turn towards next waypoint before MC to FW transition */
972  && _work_item_type == WORK_ITEM_TYPE_DEFAULT
973  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT
974  && _navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING
976  && has_next_position_item) {
977 
978  /* disable weathervane before front transition for allowing yaw to align */
979  pos_sp_triplet->current.allow_weather_vane = false;
980 
981  new_work_item_type = WORK_ITEM_TYPE_ALIGN;
982 
983  set_align_mission_item(&_mission_item, &mission_item_next_position);
984 
985  /* set position setpoint to target during the transition */
987  mission_item_to_position_setpoint(mission_item_next_position, &pos_sp_triplet->current);
988  }
989 
990  /* yaw is aligned now */
991  if (_work_item_type == WORK_ITEM_TYPE_ALIGN &&
992  new_work_item_type == WORK_ITEM_TYPE_DEFAULT) {
993 
994  new_work_item_type = WORK_ITEM_TYPE_DEFAULT;
995 
996  /* set position setpoint to target during the transition */
997  pos_sp_triplet->previous = pos_sp_triplet->current;
998  generate_waypoint_from_heading(&pos_sp_triplet->current, pos_sp_triplet->current.yaw);
999  }
1000 
1001  /* don't advance mission after FW to MC command */
1003  && _work_item_type == WORK_ITEM_TYPE_DEFAULT
1004  && new_work_item_type == WORK_ITEM_TYPE_DEFAULT
1007  && pos_sp_triplet->current.valid) {
1008 
1009  new_work_item_type = WORK_ITEM_TYPE_CMD_BEFORE_MOVE;
1010  }
1011 
1012  /* after FW to MC transition finish moving to the waypoint */
1013  if (_work_item_type == WORK_ITEM_TYPE_CMD_BEFORE_MOVE &&
1014  new_work_item_type == WORK_ITEM_TYPE_DEFAULT
1015  && pos_sp_triplet->current.valid) {
1016 
1017  new_work_item_type = WORK_ITEM_TYPE_DEFAULT;
1018 
1020  copy_position_if_valid(&_mission_item, &pos_sp_triplet->current);
1021  _mission_item.autocontinue = true;
1022  _mission_item.time_inside = 0.0f;
1023  }
1024 
1025  // ignore certain commands in mission fast forward
1026  if ((_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD) &&
1028  _mission_item.autocontinue = true;
1029  _mission_item.time_inside = 0.0f;
1030  }
1031 
1032  break;
1033  }
1034 
1035  case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
1036  // nothing to do, all commands are ignored
1037  break;
1038  }
1039  }
1040  }
1041 
1042  /*********************************** set setpoints and check next *********************************************/
1043 
1045 
1046  /* set current position setpoint from mission item (is protected against non-position items) */
1047  if (new_work_item_type != WORK_ITEM_TYPE_PRECISION_LAND) {
1050  }
1051 
1052  /* only set the previous position item if the current one really changed */
1053  if ((_work_item_type != WORK_ITEM_TYPE_MOVE_TO_LAND) &&
1054  !position_setpoint_equal(&pos_sp_triplet->current, &current_setpoint_copy)) {
1055  pos_sp_triplet->previous = current_setpoint_copy;
1056  }
1057 
1058  /* issue command if ready (will do nothing for position mission items) */
1060 
1061  /* set current work item type */
1062  _work_item_type = new_work_item_type;
1063 
1064  /* require takeoff after landing or idle */
1065  if (pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_LAND
1066  || pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_IDLE) {
1067 
1068  _need_takeoff = true;
1069  }
1070 
1073 
1074  if (_mission_type == MISSION_TYPE_MISSION) {
1076  }
1077 
1079  /* try to process next mission item */
1080  if (has_next_position_item) {
1081  /* got next mission item, update setpoint triplet */
1082  mission_apply_limitation(mission_item_next_position);
1083  mission_item_to_position_setpoint(mission_item_next_position, &pos_sp_triplet->next);
1084 
1085  } else {
1086  /* next mission item is not available */
1087  pos_sp_triplet->next.valid = false;
1088  }
1089 
1090  } else {
1091  /* vehicle will be paused on current waypoint, don't set next item */
1092  pos_sp_triplet->next.valid = false;
1093  }
1094 
1095  /* Save the distance between the current sp and the previous one */
1096  if (pos_sp_triplet->current.valid && pos_sp_triplet->previous.valid) {
1097 
1099  pos_sp_triplet->current.lat, pos_sp_triplet->current.lon,
1100  pos_sp_triplet->previous.lat, pos_sp_triplet->previous.lon);
1101  }
1102 
1104 }
1105 
1106 bool
1108 {
1109  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
1110 
1111  float takeoff_alt = calculate_takeoff_altitude(&_mission_item);
1112 
1114  /* force takeoff if landed (additional protection) */
1115  _need_takeoff = true;
1116 
1117  } else if (_navigator->get_global_position()->alt > takeoff_alt - _navigator->get_altitude_acceptance_radius()) {
1118  /* if in-air and already above takeoff height, don't do takeoff */
1119  _need_takeoff = false;
1120 
1124  /* if in-air but below takeoff height and we have a takeoff item */
1125  _need_takeoff = true;
1126  }
1127 
1128  /* check if current mission item is one that requires takeoff before */
1129  if (_need_takeoff && (
1135 
1136  _need_takeoff = false;
1137  return true;
1138  }
1139  }
1140 
1141  return false;
1142 }
1143 
1144 bool
1146 {
1147  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING
1149 
1152 
1153  return d_current > _navigator->get_acceptance_radius();
1154  }
1155 
1156  return false;
1157 }
1158 
1159 bool
1161 {
1162  if (_navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING
1164 
1167 
1168  return d_current > _navigator->get_acceptance_radius();
1169  }
1170 
1171  return false;
1172 }
1173 
1174 void
1176 {
1177  if (setpoint->valid && setpoint->type == position_setpoint_s::SETPOINT_TYPE_POSITION) {
1178  mission_item->lat = setpoint->lat;
1179  mission_item->lon = setpoint->lon;
1180  mission_item->altitude = setpoint->alt;
1181 
1182  } else {
1183  mission_item->lat = _navigator->get_global_position()->lat;
1184  mission_item->lon = _navigator->get_global_position()->lon;
1185  mission_item->altitude = _navigator->get_global_position()->alt;
1186  }
1187 
1188  mission_item->altitude_is_relative = false;
1189 }
1190 
1191 void
1192 Mission::set_align_mission_item(struct mission_item_s *mission_item, struct mission_item_s *mission_item_next)
1193 {
1194  mission_item->nav_cmd = NAV_CMD_WAYPOINT;
1196  mission_item->altitude_is_relative = false;
1197  mission_item->autocontinue = true;
1198  mission_item->time_inside = 0.0f;
1199  mission_item->yaw = get_bearing_to_next_waypoint(
1201  mission_item_next->lat, mission_item_next->lon);
1202  mission_item->force_heading = true;
1203 }
1204 
1205 float
1207 {
1208  /* calculate takeoff altitude */
1209  float takeoff_alt = get_absolute_altitude_for_item(*mission_item);
1210 
1211  /* takeoff to at least MIS_TAKEOFF_ALT above home/ground, even if first waypoint is lower */
1213  takeoff_alt = fmaxf(takeoff_alt, _navigator->get_global_position()->alt + _navigator->get_takeoff_min_alt());
1214 
1215  } else {
1216  takeoff_alt = fmaxf(takeoff_alt, _navigator->get_home_position()->alt + _navigator->get_takeoff_min_alt());
1217  }
1218 
1219  return takeoff_alt;
1220 }
1221 
1222 void
1224 {
1225  struct position_setpoint_triplet_s *pos_sp_triplet =
1227 
1228  // Only update if current triplet is valid
1229  if (pos_sp_triplet->current.valid) {
1230 
1231  double point_from_latlon[2] = { _navigator->get_global_position()->lat,
1233  };
1234  double point_to_latlon[2] = { _navigator->get_global_position()->lat,
1236  };
1237  float yaw_offset = 0.0f;
1238 
1239  // Depending on ROI-mode, update heading
1240  switch (_navigator->get_vroi().mode) {
1241  case vehicle_roi_s::ROI_LOCATION: {
1242  // ROI is a fixed location. Vehicle needs to point towards that location
1243  point_to_latlon[0] = _navigator->get_vroi().lat;
1244  point_to_latlon[1] = _navigator->get_vroi().lon;
1245  // No yaw offset required
1246  yaw_offset = 0.0f;
1247  break;
1248  }
1249 
1250  case vehicle_roi_s::ROI_WPNEXT: {
1251  // ROI is current waypoint. Vehcile needs to point towards current waypoint
1252  point_to_latlon[0] = pos_sp_triplet->current.lat;
1253  point_to_latlon[1] = pos_sp_triplet->current.lon;
1254  // Add the gimbal's yaw offset
1255  yaw_offset = _navigator->get_vroi().yaw_offset;
1256  break;
1257  }
1258 
1259  case vehicle_roi_s::ROI_NONE:
1260  case vehicle_roi_s::ROI_WPINDEX:
1261  case vehicle_roi_s::ROI_TARGET:
1262  case vehicle_roi_s::ROI_ENUM_END:
1263  default: {
1264  }
1265  }
1266 
1267  // Get desired heading and update it.
1268  // However, only update if distance to desired heading is
1269  // larger than acceptance radius to prevent excessive yawing
1270  float d_current = get_distance_to_next_waypoint(point_from_latlon[0],
1271  point_from_latlon[1], point_to_latlon[0], point_to_latlon[1]);
1272 
1273  if (d_current > _navigator->get_acceptance_radius()) {
1274  float yaw = matrix::wrap_pi(
1275  get_bearing_to_next_waypoint(point_from_latlon[0],
1276  point_from_latlon[1], point_to_latlon[0],
1277  point_to_latlon[1]) + yaw_offset);
1278 
1279  _mission_item.yaw = yaw;
1280  pos_sp_triplet->current.yaw = _mission_item.yaw;
1281  pos_sp_triplet->current.yaw_valid = true;
1282  }
1283 
1284  // we set yaw directly so we can run this in parallel to the FOH update
1286  }
1287 }
1288 
1289 void
1291 {
1293 
1294  /* Don't change setpoint if last and current waypoint are not valid
1295  * or if the previous altitude isn't from a position or loiter setpoint or
1296  * if rotary wing since that is handled in the mc_pos_control
1297  */
1298 
1299 
1300  if (!pos_sp_triplet->previous.valid || !pos_sp_triplet->current.valid || !PX4_ISFINITE(pos_sp_triplet->previous.alt)
1301  || !(pos_sp_triplet->previous.type == position_setpoint_s::SETPOINT_TYPE_POSITION ||
1302  pos_sp_triplet->previous.type == position_setpoint_s::SETPOINT_TYPE_LOITER) ||
1303  _navigator->get_vstatus()->vehicle_type == vehicle_status_s::VEHICLE_TYPE_ROTARY_WING) {
1304 
1305  return;
1306  }
1307 
1308  // Calculate acceptance radius, i.e. the radius within which we do not perform a first order hold anymore
1310 
1311  if (pos_sp_triplet->current.type == position_setpoint_s::SETPOINT_TYPE_LOITER) {
1312  acc_rad = _navigator->get_acceptance_radius(fabsf(_mission_item.loiter_radius) * 1.2f);
1313  }
1314 
1315  /* Do not try to find a solution if the last waypoint is inside the acceptance radius of the current one */
1316  if (_distance_current_previous - acc_rad < FLT_EPSILON) {
1317  return;
1318  }
1319 
1320  /* Don't do FOH for non-missions, landing and takeoff waypoints, the ground may be near
1321  * and the FW controller has a custom landing logic
1322  *
1323  * NAV_CMD_LOITER_TO_ALT doesn't change altitude until reaching desired lat/lon
1324  * */
1329  || !_navigator->is_planned_mission()) {
1330 
1331  return;
1332  }
1333 
1334  /* Calculate distance to current waypoint */
1337 
1338  /* Save distance to waypoint if it is the smallest ever achieved, however make sure that
1339  * _min_current_sp_distance_xy is never larger than the distance between the current and the previous wp */
1340  _min_current_sp_distance_xy = math::min(math::min(d_current, _min_current_sp_distance_xy),
1342 
1343  /* if the minimal distance is smaller then the acceptance radius, we should be at waypoint alt
1344  * navigator will soon switch to the next waypoint item (if there is one) as soon as we reach this altitude */
1345  if (_min_current_sp_distance_xy < acc_rad) {
1347 
1348  } else {
1349  /* update the altitude sp of the 'current' item in the sp triplet, but do not update the altitude sp
1350  * of the mission item as it is used to check if the mission item is reached
1351  * The setpoint is set linearly and such that the system reaches the current altitude at the acceptance
1352  * radius around the current waypoint
1353  **/
1354  float delta_alt = (get_absolute_altitude_for_item(_mission_item) - pos_sp_triplet->previous.alt);
1355  float grad = -delta_alt / (_distance_current_previous - acc_rad);
1356  float a = pos_sp_triplet->previous.alt - grad * _distance_current_previous;
1357  pos_sp_triplet->current.alt = a + grad * _min_current_sp_distance_xy;
1358  }
1359 
1360  // we set altitude directly so we can run this in parallel to the heading update
1362 }
1363 
1364 void
1366 {
1368 
1369  const float cruising_speed = _navigator->get_cruising_speed();
1370 
1371  /* Don't change setpoint if the current waypoint is not valid */
1372  if (!pos_sp_triplet->current.valid ||
1373  fabsf(pos_sp_triplet->current.cruising_speed - cruising_speed) < FLT_EPSILON) {
1374  return;
1375  }
1376 
1377  pos_sp_triplet->current.cruising_speed = cruising_speed;
1378 
1380 }
1381 
1382 void
1384 {
1385  // Abort FW landing
1386  // first climb out then loiter over intended landing location
1387 
1389  return;
1390  }
1391 
1392  // loiter at the larger of MIS_LTRMIN_ALT above the landing point
1393  // or 2 * FW_CLMBOUT_DIFF above the current altitude
1394  const float alt_landing = get_absolute_altitude_for_item(_mission_item);
1395  const float alt_sp = math::max(alt_landing + _navigator->get_loiter_min_alt(),
1396  _navigator->get_global_position()->alt + 20.0f);
1397 
1398  // turn current landing waypoint into an indefinite loiter
1401  _mission_item.altitude = alt_sp;
1404  _mission_item.autocontinue = false;
1406 
1410 
1411  mavlink_and_console_log_info(_navigator->get_mavlink_log_pub(), "Holding at %d m above landing.",
1412  (int)(alt_sp - alt_landing));
1413 
1414  // reset mission index to start of landing
1415  if (_land_start_available) {
1417 
1418  } else {
1419  // move mission index back (landing approach point)
1421  }
1422 
1423  // send reposition cmd to get out of mission
1424  vehicle_command_s vcmd = {};
1425 
1426  vcmd.command = vehicle_command_s::VEHICLE_CMD_DO_REPOSITION;
1427  vcmd.param1 = -1;
1428  vcmd.param2 = 1;
1429  vcmd.param5 = _mission_item.lat;
1430  vcmd.param6 = _mission_item.lon;
1431  vcmd.param7 = alt_sp;
1432 
1434 }
1435 
1436 bool
1438  mission_item_s *next_position_mission_item, bool *has_next_position_item)
1439 {
1440  *has_next_position_item = false;
1441  bool first_res = false;
1442  int offset = 1;
1443 
1444  if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
1445  offset = -1;
1446  }
1447 
1448  if (read_mission_item(0, mission_item)) {
1449 
1450  first_res = true;
1451 
1452  /* trying to find next position mission item */
1453  while (read_mission_item(offset, next_position_mission_item)) {
1454 
1455  if (item_contains_position(*next_position_mission_item)) {
1456  *has_next_position_item = true;
1457  break;
1458  }
1459 
1460  if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
1461  offset--;
1462 
1463  } else {
1464  offset++;
1465 
1466  }
1467  }
1468  }
1469 
1470  return first_res;
1471 }
1472 
1473 bool
1474 Mission::read_mission_item(int offset, struct mission_item_s *mission_item)
1475 {
1476  /* select mission */
1477  const int current_index = _current_mission_index;
1478  int index_to_read = current_index + offset;
1479 
1480  int *mission_index_ptr = (offset == 0) ? &_current_mission_index : &index_to_read;
1481  const dm_item_t dm_item = (dm_item_t)_mission.dataman_id;
1482 
1483  /* do not work on empty missions */
1484  if (_mission.count == 0) {
1485  return false;
1486  }
1487 
1488  /* Repeat this several times in case there are several DO JUMPS that we need to follow along, however, after
1489  * 10 iterations we have to assume that the DO JUMPS are probably cycling and give up. */
1490  for (int i = 0; i < 10; i++) {
1491  if (*mission_index_ptr < 0 || *mission_index_ptr >= (int)_mission.count) {
1492  /* mission item index out of bounds - if they are equal, we just reached the end */
1493  if ((*mission_index_ptr != (int)_mission.count) && (*mission_index_ptr != -1)) {
1494  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission item index out of bound, index: %d, max: %d.",
1495  *mission_index_ptr, _mission.count);
1496  }
1497 
1498  return false;
1499  }
1500 
1501  const ssize_t len = sizeof(struct mission_item_s);
1502 
1503  /* read mission item to temp storage first to not overwrite current mission item if data damaged */
1504  struct mission_item_s mission_item_tmp;
1505 
1506  /* read mission item from datamanager */
1507  if (dm_read(dm_item, *mission_index_ptr, &mission_item_tmp, len) != len) {
1508  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
1509  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Waypoint could not be read.");
1510  return false;
1511  }
1512 
1513  /* check for DO_JUMP item, and whether it hasn't not already been repeated enough times */
1514  if (mission_item_tmp.nav_cmd == NAV_CMD_DO_JUMP) {
1515  const bool execute_jumps = _mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_NORMAL;
1516 
1517  /* do DO_JUMP as many times as requested if not in reverse mode */
1518  if ((mission_item_tmp.do_jump_current_count < mission_item_tmp.do_jump_repeat_count) && execute_jumps) {
1519 
1520  /* only raise the repeat count if this is for the current mission item
1521  * but not for the read ahead mission item */
1522  if (offset == 0) {
1523  (mission_item_tmp.do_jump_current_count)++;
1524 
1525  /* save repeat count */
1526  if (dm_write(dm_item, *mission_index_ptr, DM_PERSIST_POWER_ON_RESET, &mission_item_tmp, len) != len) {
1527  /* not supposed to happen unless the datamanager can't access the dataman */
1528  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "DO JUMP waypoint could not be written.");
1529  return false;
1530  }
1531 
1532  report_do_jump_mission_changed(*mission_index_ptr, mission_item_tmp.do_jump_repeat_count);
1533  }
1534 
1535  /* set new mission item index and repeat
1536  * we don't have to validate here, if it's invalid, we should realize this later .*/
1537  *mission_index_ptr = mission_item_tmp.do_jump_mission_index;
1538 
1539  } else {
1540  if (offset == 0 && execute_jumps) {
1541  mavlink_log_info(_navigator->get_mavlink_log_pub(), "DO JUMP repetitions completed.");
1542  }
1543 
1544  /* no more DO_JUMPS, therefore just try to continue with next mission item */
1545  if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
1546  (*mission_index_ptr)--;
1547 
1548  } else {
1549  (*mission_index_ptr)++;
1550  }
1551  }
1552 
1553  } else {
1554  /* if it's not a DO_JUMP, then we were successful */
1555  memcpy(mission_item, &mission_item_tmp, sizeof(struct mission_item_s));
1556  return true;
1557  }
1558  }
1559 
1560  /* we have given up, we don't want to cycle forever */
1561  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "DO JUMP is cycling, giving up.");
1562  return false;
1563 }
1564 
1565 void
1567 {
1568  mission_s mission_state = {};
1569 
1570  /* lock MISSION_STATE item */
1571  int dm_lock_ret = dm_lock(DM_KEY_MISSION_STATE);
1572 
1573  if (dm_lock_ret != 0) {
1574  PX4_ERR("DM_KEY_MISSION_STATE lock failed");
1575  }
1576 
1577  /* read current state */
1578  int read_res = dm_read(DM_KEY_MISSION_STATE, 0, &mission_state, sizeof(mission_s));
1579 
1580  if (read_res == sizeof(mission_s)) {
1581  /* data read successfully, check dataman ID and items count */
1582  if (mission_state.dataman_id == _mission.dataman_id && mission_state.count == _mission.count) {
1583  /* navigator may modify only sequence, write modified state only if it changed */
1584  if (mission_state.current_seq != _current_mission_index) {
1585  mission_state.current_seq = _current_mission_index;
1586  mission_state.timestamp = hrt_absolute_time();
1587 
1589  sizeof(mission_s)) != sizeof(mission_s)) {
1590 
1591  PX4_ERR("Can't save mission state");
1592  }
1593  }
1594  }
1595 
1596  } else {
1597  /* invalid data, this must not happen and indicates error in mission publisher */
1598  mission_state.timestamp = hrt_absolute_time();
1599  mission_state.dataman_id = _mission.dataman_id;
1600  mission_state.count = _mission.count;
1601  mission_state.current_seq = _current_mission_index;
1602 
1603  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Invalid mission state.");
1604 
1605  /* write modified state only if changed */
1607  sizeof(mission_s)) != sizeof(mission_s)) {
1608 
1609  PX4_ERR("Can't save mission state");
1610  }
1611  }
1612 
1613  /* unlock MISSION_STATE item */
1614  if (dm_lock_ret == 0) {
1616  }
1617 }
1618 
1619 void
1620 Mission::report_do_jump_mission_changed(int index, int do_jumps_remaining)
1621 {
1622  /* inform about the change */
1625  _navigator->get_mission_result()->item_do_jump_remaining = do_jumps_remaining;
1626 
1628 }
1629 
1630 void
1632 {
1635 
1637 }
1638 
1639 void
1641 {
1644 
1646 
1648 }
1649 
1650 void
1652 {
1653  if ((!_home_inited && _navigator->home_position_valid()) || force) {
1654 
1655  MissionFeasibilityChecker _missionFeasibilityChecker(_navigator);
1656 
1658  _missionFeasibilityChecker.checkMissionFeasible(_mission,
1659  _param_mis_dist_1wp.get(),
1660  _param_mis_dist_wps.get(),
1662 
1667 
1668  // find and store landing start marker (if available)
1670  }
1671 }
1672 
1673 void
1675 {
1677 
1678  if (dm_read(DM_KEY_MISSION_STATE, 0, &mission, sizeof(mission_s)) == sizeof(mission_s)) {
1680  /* set current item to 0 */
1681  mission.current_seq = 0;
1682 
1683  /* reset jump counters */
1684  if (mission.count > 0) {
1685  const dm_item_t dm_current = (dm_item_t)mission.dataman_id;
1686 
1687  for (unsigned index = 0; index < mission.count; index++) {
1688  struct mission_item_s item;
1689  const ssize_t len = sizeof(struct mission_item_s);
1690 
1691  if (dm_read(dm_current, index, &item, len) != len) {
1692  PX4_WARN("could not read mission item during reset");
1693  break;
1694  }
1695 
1696  if (item.nav_cmd == NAV_CMD_DO_JUMP) {
1697  item.do_jump_current_count = 0;
1698 
1699  if (dm_write(dm_current, index, DM_PERSIST_POWER_ON_RESET, &item, len) != len) {
1700  PX4_WARN("could not save mission item during reset");
1701  break;
1702  }
1703  }
1704  }
1705  }
1706 
1707  } else {
1708  mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Could not read mission.");
1709 
1710  /* initialize mission state in dataman */
1711  mission.timestamp = hrt_absolute_time();
1713  mission.count = 0;
1714  mission.current_seq = 0;
1715  }
1716 
1718  }
1719 
1721 }
1722 
1723 bool
1725 {
1726  /* reset mission state when disarmed */
1727  if (_navigator->get_vstatus()->arming_state != vehicle_status_s::ARMING_STATE_ARMED && _need_mission_reset) {
1728  _need_mission_reset = false;
1729  return true;
1730 
1731  } else if (_navigator->get_vstatus()->arming_state == vehicle_status_s::ARMING_STATE_ARMED && active) {
1732  /* mission is running, need reset after disarm */
1733  _need_mission_reset = true;
1734  }
1735 
1736  return false;
1737 }
1738 
1739 void
1741 {
1744  yaw, 1000000.0f,
1745  &(setpoint->lat), &(setpoint->lon));
1746  setpoint->type = position_setpoint_s::SETPOINT_TYPE_POSITION;
1747  setpoint->yaw = yaw;
1748 }
1749 
1750 int32_t
1752 {
1753  int32_t min_dist_index(0);
1754  float min_dist(FLT_MAX), dist_xy(FLT_MAX), dist_z(FLT_MAX);
1755 
1756  dm_item_t dm_current = (dm_item_t)(_mission.dataman_id);
1757 
1758  for (size_t i = 0; i < _mission.count; i++) {
1759  struct mission_item_s missionitem = {};
1760  const ssize_t len = sizeof(missionitem);
1761 
1762  if (dm_read(dm_current, i, &missionitem, len) != len) {
1763  /* not supposed to happen unless the datamanager can't access the SD card, etc. */
1764  PX4_ERR("dataman read failure");
1765  break;
1766  }
1767 
1768  if (item_contains_position(missionitem)) {
1769  // do not consider land waypoints for a fw
1770  if (!((missionitem.nav_cmd == NAV_CMD_LAND) &&
1772  (!_navigator->get_vstatus()->is_vtol))) {
1773  float dist = get_distance_to_point_global_wgs84(missionitem.lat, missionitem.lon,
1774  get_absolute_altitude_for_item(missionitem),
1778  &dist_xy, &dist_z);
1779 
1780  if (dist < min_dist) {
1781  min_dist = dist;
1782  min_dist_index = i;
1783  }
1784  }
1785  }
1786  }
1787 
1788  // for mission reverse also consider the home position
1789  if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
1797  &dist_xy, &dist_z);
1798 
1799  if (dist < min_dist) {
1800  min_dist = dist;
1801  min_dist_index = -1;
1802  }
1803  }
1804 
1805  return min_dist_index;
1806 }
1807 
1809 {
1810  return ((p1->valid == p2->valid) &&
1811  (p1->type == p2->type) &&
1812  (fabsf(p1->x - p2->x) < FLT_EPSILON) &&
1813  (fabsf(p1->y - p2->y) < FLT_EPSILON) &&
1814  (fabsf(p1->z - p2->z) < FLT_EPSILON) &&
1815  (p1->position_valid == p2->position_valid) &&
1816  (fabsf(p1->vx - p2->vx) < FLT_EPSILON) &&
1817  (fabsf(p1->vy - p2->vy) < FLT_EPSILON) &&
1818  (fabsf(p1->vz - p2->vz) < FLT_EPSILON) &&
1819  (p1->velocity_valid == p2->velocity_valid) &&
1820  (p1->velocity_frame == p2->velocity_frame) &&
1821  (p1->alt_valid == p2->alt_valid) &&
1822  (fabs(p1->lat - p2->lat) < DBL_EPSILON) &&
1823  (fabs(p1->lon - p2->lon) < DBL_EPSILON) &&
1824  (fabsf(p1->alt - p2->alt) < FLT_EPSILON) &&
1825  ((fabsf(p1->yaw - p2->yaw) < FLT_EPSILON) || (!PX4_ISFINITE(p1->yaw) && !PX4_ISFINITE(p2->yaw))) &&
1826  (p1->yaw_valid == p2->yaw_valid) &&
1827  (fabsf(p1->yawspeed - p2->yawspeed) < FLT_EPSILON) &&
1828  (p1->yawspeed_valid == p2->yawspeed_valid) &&
1829  (fabsf(p1->loiter_radius - p2->loiter_radius) < FLT_EPSILON) &&
1830  (p1->loiter_direction == p2->loiter_direction) &&
1831  (fabsf(p1->pitch_min - p2->pitch_min) < FLT_EPSILON) &&
1832  (fabsf(p1->a_x - p2->a_x) < FLT_EPSILON) &&
1833  (fabsf(p1->a_y - p2->a_y) < FLT_EPSILON) &&
1834  (fabsf(p1->a_z - p2->a_z) < FLT_EPSILON) &&
1835  (p1->acceleration_valid == p2->acceleration_valid) &&
1837  (fabsf(p1->acceptance_radius - p2->acceptance_radius) < FLT_EPSILON) &&
1838  (fabsf(p1->cruising_speed - p2->cruising_speed) < FLT_EPSILON) &&
1839  (fabsf(p1->cruising_throttle - p2->cruising_throttle) < FLT_EPSILON));
1840 
1841 }
bool land_start()
Definition: mission.cpp:429
#define VEHICLE_TYPE_FIXED_WING
bool home_position_valid()
Definition: navigator.h:166
Global position setpoint in WGS84 coordinates.
Definition: navigation.h:145
int32_t index_closest_mission_item() const
Return the index of the closest mission item to the current global position.
Definition: mission.cpp:1751
float get_distance_to_point_global_wgs84(double lat_now, double lon_now, float alt_now, double lat_next, double lon_next, float alt_next, float *dist_xy, float *dist_z)
Definition: geo.cpp:523
enum Mission::@122 MISSION_TYPE_NONE
void copy_position_if_valid(struct mission_item_s *mission_item, struct position_setpoint_s *setpoint)
Copies position from setpoint if valid, otherwise copies current position.
Definition: mission.cpp:1175
align for next waypoint
Definition: mission.h:283
void advance_mission()
Move on to next mission item or switch to loiter.
Definition: mission.cpp:533
void generate_waypoint_from_heading(struct position_setpoint_s *setpoint, float yaw)
Project current location with heading to far away location and fill setpoint.
Definition: mission.cpp:1740
void on_inactive() override
This function is called while the mode is inactive.
Definition: mission.cpp:69
float get_acceptance_radius()
Get the acceptance radius.
API for the uORB lightweight object broker.
Definition of geo / math functions to perform geodesic calculations.
uint8_t _mission_execution_mode
the current mode of how the mission is executed,look at mission_result.msg for the definition ...
Definition: mission.h:290
float altitude
altitude in meters (AMSL)
Definition: navigation.h:160
bool is_planned_mission() const
Definition: navigator.h:268
Mission(Navigator *navigator)
Definition: mission.cpp:62
uint16_t autocontinue
true if next waypoint should follow after this one
Definition: navigation.h:177
bool checkMissionFeasible(const mission_s &mission, float max_distance_to_1st_waypoint, float max_distance_between_waypoints, bool land_start_req)
float acceptance_radius
default radius in which the mission is accepted as reached in meters
Definition: navigation.h:155
float get_loiter_min_alt() const
Definition: navigator.h:285
__EXPORT int dm_lock(dm_item_t item)
Lock all items of a type.
Definition: dataman.cpp:1157
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
void increment_mission_instance_count()
Definition: navigator.h:263
void set_loiter_item(struct mission_item_s *item, float min_clearance=-1.0f)
Set a loiter mission item, if possible reuse the position setpoint, otherwise take the current positi...
struct position_setpoint_s next
bool _mission_waypoints_changed
Definition: mission.h:271
bool abort_landing()
uint64_t timestamp
Definition: mission.h:53
float _landing_alt
Definition: mission.h:259
enum Mission::work_item_type WORK_ITEM_TYPE_DEFAULT
current type of work to do (sub mission item)
bool _waypoint_position_reached
struct home_position_s * get_home_position()
Getters.
Definition: navigator.h:151
void altitude_sp_foh_update()
Updates the altitude sp to follow a foh.
Definition: mission.cpp:1290
dm_item_t
Types of items that the data manager can store.
Definition: dataman.h:50
uint16_t vtol_back_transition
part of the vtol back transition sequence
Definition: navigation.h:177
takeoff before moving to waypoint
Definition: mission.h:281
uint8_t dataman_id
Definition: mission.h:56
void set_current_mission_item()
Set the current mission item.
Definition: mission.cpp:1640
DEFINE_PARAMETERS((ParamFloat< px4::params::MIS_DIST_1WP >) _param_mis_dist_1wp,(ParamFloat< px4::params::MIS_DIST_WPS >) _param_mis_dist_wps,(ParamInt< px4::params::MIS_ALTMODE >) _param_mis_altmode,(ParamInt< px4::params::MIS_MNT_YAW_CTL >) _param_mis_mnt_yaw_ctl) uORB mission_s _mission
< mission subscription
Definition: mission.h:250
uint16_t origin
how the mission item was generated
Definition: navigation.h:177
float get_absolute_altitude_for_item(const mission_item_s &mission_item) const
struct position_setpoint_s previous
void on_inactivation() override
This function is called one time when mode becomes inactive.
Definition: mission.cpp:137
int32_t _current_mission_index
Definition: mission.h:252
bool need_to_reset_mission(bool active)
Returns true if we need to reset the mission.
Definition: mission.cpp:1724
uint16_t do_jump_repeat_count
how many times do jump needs to be done
Definition: navigation.h:168
struct vehicle_land_detected_s * get_land_detected()
Definition: navigator.h:157
float _distance_current_previous
distance from previous to current sp in pos_sp_triplet, only use if current and previous are valid ...
Definition: mission.h:276
uint16_t item_do_jump_remaining
void report_do_jump_mission_changed(int index, int do_jumps_remaining)
Inform about a changed mission item after a DO_JUMP.
Definition: mission.cpp:1620
void check_mission_valid(bool force)
Check whether a mission is ready to go.
Definition: mission.cpp:1651
#define FLT_EPSILON
bool get_can_loiter_at_sp()
Definition: navigator.h:170
High-resolution timer with callouts and timekeeping.
bool _mission_changed
Definition: mission.h:272
bool do_need_move_to_takeoff()
Returns true if we need to move to waypoint location after vtol takeoff.
Definition: mission.cpp:1160
double lon
longitude in degrees
Definition: navigation.h:147
void do_abort_landing()
Abort landing.
Definition: mission.cpp:1383
Navigator * _navigator
bool mission_landing_required()
Definition: navigator.h:278
bool _need_takeoff
if true, then takeoff must be performed before going to the first waypoint (if needed) ...
Definition: mission.h:261
bool _home_inited
Definition: mission.h:269
const vehicle_roi_s & get_vroi()
Definition: navigator.h:162
void reset_cruising_speed()
Reset cruising speed to default values.
uint16_t _land_start_index
index of DO_LAND_START, INVALID_DO_LAND_START if no planned landing
Definition: mission.h:256
struct position_setpoint_s current
move to land waypoint before descent
Definition: mission.h:282
uint16_t get_land_start_index() const
Definition: mission.h:89
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
void reset_triplets()
Set triplets to invalid.
struct vehicle_global_position_s * get_global_position()
Definition: navigator.h:156
uint16_t seq_current
void waypoint_from_heading_and_distance(double lat_start, double lon_start, float bearing, float dist, double *lat_target, double *lon_target)
Creates a waypoint from given waypoint, distance and bearing see http://www.movable-type.co.uk/scripts/latlong.html.
Definition: geo.cpp:303
float get_cruising_speed()
Get the cruising speed.
bool set_current_mission_index(uint16_t index)
Definition: mission.cpp:282
mission_item_s _mission_item
void on_active() override
This function is called while the mode is active.
Definition: precland.cpp:107
uint16_t nav_cmd
navigation command
Definition: navigation.h:165
void reset_mission(struct mission_s &mission)
Reset mission.
Definition: mission.cpp:1674
void on_activation() override
This function is called one time when mode becomes active, pos_sp_triplet must be initialized here...
Definition: mission.cpp:149
uint16_t do_jump_current_count
count how many times the jump has been done
Definition: navigation.h:171
void mission_apply_limitation(mission_item_s &item)
General function used to adjust the mission item based on vehicle specific limitations.
void cruising_speed_sp_update()
Update the cruising speed setpoint.
Definition: mission.cpp:1365
DATAMANAGER driver.
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
float get_bearing_to_next_waypoint(double lat_now, double lon_now, double lat_next, double lon_next)
Returns the bearing to the next waypoint in radians.
Definition: geo.cpp:320
bool _execution_mode_changed
Definition: mission.h:291
void reset_mission_item_reached()
Reset all reached flags.
uint8_t execution_mode
void heading_sp_update()
Updates the heading of the vehicle.
Definition: mission.cpp:1223
void set_closest_item_as_current()
Definition: mission.cpp:309
void set_execution_mode(const uint8_t mode)
Set a new mission mode and handle the switching between the different modes.
Definition: mission.cpp:315
float time_inside
time that the MAV should stay inside the radius before advancing in seconds
Definition: navigation.h:151
PrecLand * get_precland()
allow others, e.g.
Definition: navigator.h:160
bool _land_start_available
Definition: mission.h:255
uint8_t mode
Definition: vehicle_roi.h:66
__EXPORT void dm_unlock(dm_item_t item)
Unlock a data Item.
Definition: dataman.cpp:1202
bool position_setpoint_equal(const position_setpoint_s *p1, const position_setpoint_s *p2) const
Definition: mission.cpp:1808
void update_mission()
Update mission topic.
Definition: mission.cpp:458
uint16_t land_precision
Defines if landing should be precise: 0 = normal landing, 1 = opportunistic precision landing...
Definition: navigation.h:173
constexpr _Tp min(_Tp a, _Tp b)
Definition: Limits.hpp:54
void reset_vroi()
Definition: navigator.h:163
Type wrap_pi(Type x)
Wrap value in range [-π, π)
bool find_mission_land_start()
Find and store the index of the landing sequence (DO_LAND_START)
Definition: mission.cpp:379
bool do_need_move_to_land()
Returns true if we need to move to waypoint location before starting descent.
Definition: mission.cpp:1145
float get_time_inside(const mission_item_s &item) const
struct position_setpoint_triplet_s * get_position_setpoint_triplet()
Definition: navigator.h:153
void on_activation() override
This function is called one time when mode becomes active, pos_sp_triplet must be initialized here...
Definition: precland.cpp:73
uint16_t item_changed_index
void issue_command(const mission_item_s &item)
struct mission_result_s * get_mission_result()
Definition: navigator.h:152
int16_t do_jump_mission_index
index where the do jump will go to
Definition: navigation.h:167
constexpr _Tp max(_Tp a, _Tp b)
Definition: Limits.hpp:60
void save_mission_state()
Save current mission state to dataman.
Definition: mission.cpp:1566
bool mission_item_to_position_setpoint(const mission_item_s &item, position_setpoint_s *sp)
Convert a mission item to a position setpoint.
bool is_mission_item_reached()
Check if mission item has been reached.
bool read_mission_item(int offset, struct mission_item_s *mission_item)
Read current (offset == 0) or a specific (offset > 0) mission item from the dataman and watch out for...
Definition: mission.cpp:1474
int32_t current_seq
Definition: mission.h:54
bool prepare_mission_items(mission_item_s *mission_item, mission_item_s *next_position_mission_item, bool *has_next_position_item)
Read the current and the next mission item.
Definition: mission.cpp:1437
float yaw_offset
Definition: vehicle_roi.h:65
bool do_need_vertical_takeoff()
Returns true if we need to do a takeoff at the current state.
Definition: mission.cpp:1107
void publish_vehicle_cmd(vehicle_command_s *vcmd)
float calculate_takeoff_altitude(struct mission_item_s *mission_item)
Calculate takeoff height for mission item considering ground clearance.
Definition: mission.cpp:1206
float get_loiter_radius()
Definition: navigator.h:171
static bool item_contains_position(const mission_item_s &item)
void set_mission_item_reached()
Set a mission item as reached.
Definition: mission.cpp:1631
__EXPORT ssize_t dm_write(dm_item_t item, unsigned index, dm_persitence_t persistence, const void *buf, size_t count)
Write to the data manager file.
Definition: dataman.cpp:1072
bool _inited
Definition: mission.h:268
void on_active() override
This function is called while the mode is active.
Definition: mission.cpp:175
orb_advert_t * get_mavlink_log_pub()
Definition: navigator.h:261
struct vehicle_status_s * get_vstatus()
Definition: navigator.h:159
bool landing()
Definition: mission.cpp:446
void set_mission_result_updated()
Definition: navigator.h:146
work_item_type
Definition: mission.h:279
float get_takeoff_min_alt() const
Definition: navigator.h:286
double _landing_lon
Definition: mission.h:258
uint16_t force_heading
heading needs to be reached
Definition: navigation.h:177
mode
Definition: vtol_type.h:76
float yaw
in radians NED -PI..+PI, NAN means don&#39;t change yaw
Definition: navigation.h:157
float loiter_radius
loiter radius in meters, 0 for a VTOL to hover, negative for counter-clockwise
Definition: navigation.h:156
bool _need_mission_reset
Definition: mission.h:270
void set_can_loiter_at_sp(bool can_loiter)
Setters.
Definition: navigator.h:144
void set_position_setpoint_triplet_updated()
Definition: navigator.h:145
float get_altitude_acceptance_radius()
Get the altitude acceptance radius.
virtual void on_inactivation()
This function is called one time when mode becomes inactive.
void set_align_mission_item(struct mission_item_s *mission_item, struct mission_item_s *mission_item_next)
Create mission item to align towards next waypoint.
Definition: mission.cpp:1192
void set_mode(PrecLandMode mode)
Definition: precland.h:76
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
double _landing_lat
Definition: mission.h:257
float _min_current_sp_distance_xy
< true if the mission changed since the mission mode was active
Definition: mission.h:274
uint16_t altitude_is_relative
true if altitude is relative from start point
Definition: navigation.h:177
void set_mission_items()
Set new mission items.
Definition: mission.cpp:587
void set_cruising_speed(float speed=-1.0f)
Set the cruising speed.
void set_vtol_transition_item(struct mission_item_s *item, const uint8_t new_mode)
Set vtol transition item.
double lat
latitude in degrees
Definition: navigation.h:146