Navigator Mission RTL (#8749)

* Add return to land to mission

This method uses the planned mission for rtl. If a landing sequence
is present it will continue the mission and land. If not it will
fly back the mission and loiter/land at the home position.
This commit is contained in:
Florian Achermann
2018-05-27 18:07:06 +02:00
committed by Daniel Agar
parent fdfa764913
commit 84578748f4
11 changed files with 793 additions and 348 deletions

View File

@@ -8,6 +8,7 @@ set(config_module_list
# #
#drivers/barometer #drivers/barometer
drivers/differential_pressure drivers/differential_pressure
#drivers/distance_sensor
#drivers/magnetometer #drivers/magnetometer
#drivers/telemetry #drivers/telemetry
@@ -47,7 +48,7 @@ set(config_module_list
# distance sensors # distance sensors
drivers/distance_sensor/ll40ls drivers/distance_sensor/ll40ls
drivers/distance_sensor/mb12xx #drivers/distance_sensor/mb12xx
drivers/distance_sensor/sf0x drivers/distance_sensor/sf0x
drivers/distance_sensor/sf1xx drivers/distance_sensor/sf1xx
drivers/distance_sensor/srf02 drivers/distance_sensor/srf02

View File

@@ -1,3 +1,7 @@
uint8 MISSION_EXECUTION_MODE_NORMAL = 0 # Execute the mission according to the planned items
uint8 MISSION_EXECUTION_MODE_REVERSE = 1 # Execute the mission in reverse order, ignoring commands and converting all waypoints to normal ones
uint8 MISSION_EXECUTION_MODE_FAST_FORWARD = 2 # Execute the mission as fast as possible, for example converting loiter waypoints to normal ones
uint32 instance_count # Instance count of this mission. Increments monotonically whenever the mission is modified uint32 instance_count # Instance count of this mission. Increments monotonically whenever the mission is modified
int32 seq_reached # Sequence of the mission item which has been reached, default -1 int32 seq_reached # Sequence of the mission item which has been reached, default -1
@@ -15,3 +19,5 @@ bool flight_termination # true if the navigator demands a flight termination fr
bool item_do_jump_changed # true if the number of do jumps remaining has changed bool item_do_jump_changed # true if the number of do jumps remaining has changed
uint16 item_changed_index # indicate which item has changed uint16 item_changed_index # indicate which item has changed
uint16 item_do_jump_remaining # set to the number of do jumps remaining for that item uint16 item_do_jump_remaining # set to the number of do jumps remaining for that item
uint8 execution_mode # indicates the mode in which the mission is executed

View File

@@ -48,6 +48,7 @@
#include "mission.h" #include "mission.h"
#include "navigator.h" #include "navigator.h"
#include <string.h>
#include <drivers/drv_hrt.h> #include <drivers/drv_hrt.h>
#include <dataman/dataman.h> #include <dataman/dataman.h>
#include <systemlib/mavlink_log.h> #include <systemlib/mavlink_log.h>
@@ -84,6 +85,10 @@ Mission::on_inactive()
if (offboard_updated) { if (offboard_updated) {
update_offboard_mission(); update_offboard_mission();
if (_mission_type == MISSION_TYPE_NONE && _offboard_mission.count > 0) {
_mission_type = MISSION_TYPE_OFFBOARD;
}
} }
/* reset the current offboard mission if needed */ /* reset the current offboard mission if needed */
@@ -147,6 +152,14 @@ Mission::on_inactivation()
void void
Mission::on_activation() Mission::on_activation()
{ {
if (_mission_waypoints_changed) {
_current_offboard_mission_index = index_closest_mission_item();
_mission_waypoints_changed = false;
}
// we already reset the mission items
_execution_mode_changed = false;
set_mission_items(); set_mission_items();
// unpause triggering if it was paused // unpause triggering if it was paused
@@ -179,8 +192,16 @@ Mission::on_active()
offboard_updated = true; offboard_updated = true;
} }
_mission_changed = false;
/* reset mission items if needed */ /* reset mission items if needed */
if (offboard_updated) { if (offboard_updated || _mission_waypoints_changed || _execution_mode_changed) {
if (_mission_waypoints_changed) {
_current_offboard_mission_index = index_closest_mission_item();
_mission_waypoints_changed = false;
}
_execution_mode_changed = false;
set_mission_items(); set_mission_items();
} }
@@ -251,6 +272,10 @@ Mission::set_current_offboard_mission_index(uint16_t index)
_current_offboard_mission_index = index; _current_offboard_mission_index = index;
// a mission offboard index is set manually which has the higher priority than the closest mission item
// as it is set by the user
_mission_waypoints_changed = false;
// update mission items if already in active mission // update mission items if already in active mission
if (_navigator->is_planned_mission()) { if (_navigator->is_planned_mission()) {
// prevent following "previous - current" line // prevent following "previous - current" line
@@ -266,6 +291,76 @@ Mission::set_current_offboard_mission_index(uint16_t index)
return false; return false;
} }
void
Mission::set_closest_item_as_current()
{
_current_offboard_mission_index = index_closest_mission_item();
}
void
Mission::set_execution_mode(const uint8_t mode)
{
if (_mission_execution_mode != mode) {
_execution_mode_changed = true;
_navigator->get_mission_result()->execution_mode = mode;
switch (_mission_execution_mode) {
case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD:
if (mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
// command a transition if in vtol mc mode
if (_navigator->get_vstatus()->is_rotary_wing &&
_navigator->get_vstatus()->is_vtol &&
!_navigator->get_land_detected()->landed) {
set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW);
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
pos_sp_triplet->previous = pos_sp_triplet->current;
generate_waypoint_from_heading(&pos_sp_triplet->current, _mission_item.yaw);
_navigator->set_position_setpoint_triplet_updated();
issue_command(_mission_item);
}
if (_mission_type == MISSION_TYPE_NONE && _offboard_mission.count > 0) {
_mission_type = MISSION_TYPE_OFFBOARD;
}
if (_current_offboard_mission_index > _offboard_mission.count - 1) {
_current_offboard_mission_index = _offboard_mission.count - 1;
} else if (_current_offboard_mission_index > 0) {
--_current_offboard_mission_index;
}
_work_item_type = WORK_ITEM_TYPE_DEFAULT;
}
break;
case mission_result_s::MISSION_EXECUTION_MODE_REVERSE:
if ((mode == mission_result_s::MISSION_EXECUTION_MODE_NORMAL) ||
(mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD)) {
// handle switch from reverse to forward mission
if (_current_offboard_mission_index < 0) {
_current_offboard_mission_index = 0;
} else if (_current_offboard_mission_index < _offboard_mission.count - 1) {
++_current_offboard_mission_index;
}
_work_item_type = WORK_ITEM_TYPE_DEFAULT;
}
break;
}
_mission_execution_mode = mode;
}
}
bool bool
Mission::find_offboard_land_start() Mission::find_offboard_land_start()
{ {
@@ -287,7 +382,9 @@ Mission::find_offboard_land_start()
break; break;
} }
if (missionitem.nav_cmd == NAV_CMD_DO_LAND_START) { if ((missionitem.nav_cmd == NAV_CMD_DO_LAND_START) ||
((missionitem.nav_cmd == NAV_CMD_VTOL_LAND) && _navigator->get_vstatus()->is_vtol) ||
(missionitem.nav_cmd == NAV_CMD_LAND)) {
_land_start_available = true; _land_start_available = true;
_land_start_index = i; _land_start_index = i;
return true; return true;
@@ -330,11 +427,14 @@ Mission::landing()
void void
Mission::update_offboard_mission() Mission::update_offboard_mission()
{ {
bool failed = true; bool failed = true;
/* reset triplets */ /* reset triplets */
_navigator->reset_triplets(); _navigator->reset_triplets();
struct mission_s old_offboard_mission = _offboard_mission;
if (orb_copy(ORB_ID(mission), _navigator->get_offboard_mission_sub(), &_offboard_mission) == OK) { if (orb_copy(ORB_ID(mission), _navigator->get_offboard_mission_sub(), &_offboard_mission) == OK) {
/* determine current index */ /* determine current index */
if (_offboard_mission.current_seq >= 0 && _offboard_mission.current_seq < (int)_offboard_mission.count) { if (_offboard_mission.current_seq >= 0 && _offboard_mission.current_seq < (int)_offboard_mission.count) {
@@ -367,6 +467,15 @@ Mission::update_offboard_mission()
/* reset work item if new mission has been accepted */ /* reset work item if new mission has been accepted */
_work_item_type = WORK_ITEM_TYPE_DEFAULT; _work_item_type = WORK_ITEM_TYPE_DEFAULT;
_mission_changed = true;
}
/* check if the mission waypoints changed while the vehicle is in air
* TODO add a flag to mission_s which actually tracks if the position of the waypoint changed */
if (((_offboard_mission.count != old_offboard_mission.count) ||
(_offboard_mission.dataman_id != old_offboard_mission.dataman_id)) &&
!_navigator->get_land_detected()->landed) {
_mission_waypoints_changed = true;
} }
} else { } else {
@@ -398,8 +507,43 @@ Mission::advance_mission()
switch (_mission_type) { switch (_mission_type) {
case MISSION_TYPE_OFFBOARD: case MISSION_TYPE_OFFBOARD:
switch (_mission_execution_mode) {
case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
_current_offboard_mission_index++; _current_offboard_mission_index++;
break; break;
}
case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
// find next position item in reverse order
dm_item_t dm_current = (dm_item_t)(_offboard_mission.dataman_id);
for (int32_t i = _current_offboard_mission_index - 1; i >= 0; i--) {
struct mission_item_s missionitem = {};
const ssize_t len = sizeof(missionitem);
if (dm_read(dm_current, i, &missionitem, len) != len) {
/* not supposed to happen unless the datamanager can't access the SD card, etc. */
PX4_ERR("dataman read failure");
break;
}
if (item_contains_position(missionitem)) {
_current_offboard_mission_index = i;
return;
}
}
// finished flying back the mission
_current_offboard_mission_index = -1;
break;
}
default:
_current_offboard_mission_index++;
}
break;
case MISSION_TYPE_NONE: case MISSION_TYPE_NONE:
default: default:
@@ -407,17 +551,6 @@ Mission::advance_mission()
} }
} }
float
Mission::get_absolute_altitude_for_item(struct mission_item_s &mission_item)
{
if (mission_item.altitude_is_relative) {
return mission_item.altitude + _navigator->get_home_position()->alt;
} else {
return mission_item.altitude;
}
}
void void
Mission::set_mission_items() Mission::set_mission_items()
{ {
@@ -436,7 +569,9 @@ Mission::set_mission_items()
if (prepare_mission_items(&_mission_item, &mission_item_next_position, &has_next_position_item)) { if (prepare_mission_items(&_mission_item, &mission_item_next_position, &has_next_position_item)) {
/* if mission type changed, notify */ /* if mission type changed, notify */
if (_mission_type != MISSION_TYPE_OFFBOARD) { if (_mission_type != MISSION_TYPE_OFFBOARD) {
mavlink_log_info(_navigator->get_mavlink_log_pub(), "Executing mission."); mavlink_log_info(_navigator->get_mavlink_log_pub(),
_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Executing Reverse Mission" :
"Executing Mission");
user_feedback_done = true; user_feedback_done = true;
} }
@@ -447,11 +582,15 @@ Mission::set_mission_items()
if (_mission_type != MISSION_TYPE_NONE) { if (_mission_type != MISSION_TYPE_NONE) {
if (_navigator->get_land_detected()->landed) { if (_navigator->get_land_detected()->landed) {
mavlink_log_info(_navigator->get_mavlink_log_pub(), "Mission finished, landed."); mavlink_log_info(_navigator->get_mavlink_log_pub(),
_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Reverse Mission finished, landed" :
"Mission finished, landed.");
} else { } else {
/* https://en.wikipedia.org/wiki/Loiter_(aeronautics) */ /* https://en.wikipedia.org/wiki/Loiter_(aeronautics) */
mavlink_log_info(_navigator->get_mavlink_log_pub(), "Mission finished, loitering."); mavlink_log_info(_navigator->get_mavlink_log_pub(),
_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE ? "Reverse Mission finished, loitering" :
"Mission finished, loitering.");
/* use last setpoint for loiter */ /* use last setpoint for loiter */
_navigator->set_can_loiter_at_sp(true); _navigator->set_can_loiter_at_sp(true);
@@ -502,9 +641,14 @@ Mission::set_mission_items()
/*********************************** handle mission item *********************************************/ /*********************************** handle mission item *********************************************/
/* handle position mission items */ /* handle mission items depending on the mode */
if (item_contains_position(_mission_item)) {
const position_setpoint_s current_setpoint_copy = _navigator->get_position_setpoint_triplet()->current;
if (item_contains_position(_mission_item)) {
switch (_mission_execution_mode) {
case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
/* force vtol land */ /* force vtol land */
if (_navigator->force_vtol() && _mission_item.nav_cmd == NAV_CMD_LAND) { if (_navigator->force_vtol() && _mission_item.nav_cmd == NAV_CMD_LAND) {
_mission_item.nav_cmd = NAV_CMD_VTOL_LAND; _mission_item.nav_cmd = NAV_CMD_VTOL_LAND;
@@ -512,11 +656,6 @@ Mission::set_mission_items()
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet(); position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
/* we have a new position item so set previous position setpoint to current */
if (_work_item_type != WORK_ITEM_TYPE_MOVE_TO_LAND) {
pos_sp_triplet->previous = pos_sp_triplet->current;
}
/* do takeoff before going to setpoint if needed and not already in takeoff */ /* do takeoff before going to setpoint if needed and not already in takeoff */
/* in fixed-wing this whole block will be ignored and a takeoff item is always propagated */ /* in fixed-wing this whole block will be ignored and a takeoff item is always propagated */
if (do_need_vertical_takeoff() && if (do_need_vertical_takeoff() &&
@@ -603,9 +742,7 @@ Mission::set_mission_items()
new_work_item_type = WORK_ITEM_TYPE_TRANSITON_AFTER_TAKEOFF; new_work_item_type = WORK_ITEM_TYPE_TRANSITON_AFTER_TAKEOFF;
} }
_mission_item.nav_cmd = NAV_CMD_DO_VTOL_TRANSITION; set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW);
_mission_item.params[0] = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_FW;
_mission_item.yaw = _navigator->get_global_position()->yaw;
/* set position setpoint to target during the transition */ /* set position setpoint to target during the transition */
// TODO: if has_next_position_item and use_next set next, or if use_heading set generated // TODO: if has_next_position_item and use_next set next, or if use_heading set generated
@@ -656,9 +793,8 @@ Mission::set_mission_items()
&& !_navigator->get_vstatus()->is_rotary_wing && !_navigator->get_vstatus()->is_rotary_wing
&& !_navigator->get_land_detected()->landed) { && !_navigator->get_land_detected()->landed) {
_mission_item.nav_cmd = NAV_CMD_DO_VTOL_TRANSITION; set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC);
_mission_item.params[0] = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC;
_mission_item.autocontinue = true;
new_work_item_type = WORK_ITEM_TYPE_MOVE_TO_LAND_AFTER_TRANSITION; new_work_item_type = WORK_ITEM_TYPE_MOVE_TO_LAND_AFTER_TRANSITION;
} }
@@ -737,9 +873,41 @@ Mission::set_mission_items()
_mission_item.yaw = NAN; _mission_item.yaw = NAN;
} }
// for fast forward convert certain types to simple waypoint
// XXX: add other types which should be ignored in fast forward
if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD &&
((_mission_item.nav_cmd == NAV_CMD_LOITER_UNLIMITED) ||
(_mission_item.nav_cmd == NAV_CMD_LOITER_TIME_LIMIT))) {
_mission_item.nav_cmd = NAV_CMD_WAYPOINT;
_mission_item.autocontinue = true;
_mission_item.time_inside = 0.0f;
}
break;
}
case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
if (item_contains_position(_mission_item)) {
// convert mission item to a simple waypoint
_mission_item.nav_cmd = NAV_CMD_WAYPOINT;
_mission_item.autocontinue = true;
_mission_item.time_inside = 0.0f;
} else {
mavlink_log_critical(_navigator->get_mavlink_log_pub(), "MissionReverse: Got a non-position mission item, ignoring it");
}
break;
}
}
} else { } else {
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
/* handle non-position mission items such as commands */ /* handle non-position mission items such as commands */
switch (_mission_execution_mode) {
case mission_result_s::MISSION_EXECUTION_MODE_NORMAL:
case mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD: {
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
/* turn towards next waypoint before MC to FW transition */ /* turn towards next waypoint before MC to FW transition */
if (_mission_item.nav_cmd == NAV_CMD_DO_VTOL_TRANSITION if (_mission_item.nav_cmd == NAV_CMD_DO_VTOL_TRANSITION
@@ -788,9 +956,25 @@ Mission::set_mission_items()
new_work_item_type = WORK_ITEM_TYPE_DEFAULT; new_work_item_type = WORK_ITEM_TYPE_DEFAULT;
_mission_item.nav_cmd = NAV_CMD_WAYPOINT; _mission_item.nav_cmd = NAV_CMD_WAYPOINT;
copy_positon_if_valid(&_mission_item, &pos_sp_triplet->current); copy_position_if_valid(&_mission_item, &pos_sp_triplet->current);
_mission_item.autocontinue = true; _mission_item.autocontinue = true;
_mission_item.time_inside = 0; _mission_item.time_inside = 0.0f;
}
// ignore certain commands in mission fast forward
if ((_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD) &&
(_mission_item.nav_cmd == NAV_CMD_DELAY)) {
_mission_item.autocontinue = true;
_mission_item.time_inside = 0.0f;
}
break;
}
case mission_result_s::MISSION_EXECUTION_MODE_REVERSE: {
// nothing to do, all commands are ignored
break;
}
} }
} }
@@ -804,6 +988,12 @@ Mission::set_mission_items()
mission_item_to_position_setpoint(_mission_item, &pos_sp_triplet->current); mission_item_to_position_setpoint(_mission_item, &pos_sp_triplet->current);
} }
/* only set the previous position item if the current one really changed */
if ((_work_item_type != WORK_ITEM_TYPE_MOVE_TO_LAND) &&
!position_setpoint_equal(&pos_sp_triplet->current, &current_setpoint_copy)) {
pos_sp_triplet->previous = current_setpoint_copy;
}
/* issue command if ready (will do nothing for position mission items) */ /* issue command if ready (will do nothing for position mission items) */
issue_command(_mission_item); issue_command(_mission_item);
@@ -828,7 +1018,7 @@ Mission::set_mission_items()
/* try to process next mission item */ /* try to process next mission item */
if (has_next_position_item) { if (has_next_position_item) {
/* got next mission item, update setpoint triplet */ /* got next mission item, update setpoint triplet */
mission_apply_limitation(_mission_item); mission_apply_limitation(mission_item_next_position);
mission_item_to_position_setpoint(mission_item_next_position, &pos_sp_triplet->next); mission_item_to_position_setpoint(mission_item_next_position, &pos_sp_triplet->next);
} else { } else {
@@ -920,7 +1110,7 @@ Mission::do_need_move_to_takeoff()
} }
void void
Mission::copy_positon_if_valid(struct mission_item_s *mission_item, struct position_setpoint_s *setpoint) Mission::copy_position_if_valid(struct mission_item_s *mission_item, struct position_setpoint_s *setpoint)
{ {
if (setpoint->valid && setpoint->type == position_setpoint_s::SETPOINT_TYPE_POSITION) { if (setpoint->valid && setpoint->type == position_setpoint_s::SETPOINT_TYPE_POSITION) {
mission_item->lat = setpoint->lat; mission_item->lat = setpoint->lat;
@@ -940,7 +1130,7 @@ void
Mission::set_align_mission_item(struct mission_item_s *mission_item, struct mission_item_s *mission_item_next) Mission::set_align_mission_item(struct mission_item_s *mission_item, struct mission_item_s *mission_item_next)
{ {
mission_item->nav_cmd = NAV_CMD_WAYPOINT; mission_item->nav_cmd = NAV_CMD_WAYPOINT;
copy_positon_if_valid(mission_item, &(_navigator->get_position_setpoint_triplet()->current)); copy_position_if_valid(mission_item, &(_navigator->get_position_setpoint_triplet()->current));
mission_item->altitude_is_relative = false; mission_item->altitude_is_relative = false;
mission_item->autocontinue = true; mission_item->autocontinue = true;
mission_item->time_inside = 0.0f; mission_item->time_inside = 0.0f;
@@ -1220,12 +1410,17 @@ Mission::do_abort_landing()
} }
bool bool
Mission::prepare_mission_items(mission_item_s *mission_item, mission_item_s *next_position_mission_item, Mission::prepare_mission_items(mission_item_s *mission_item,
bool *has_next_position_item) mission_item_s *next_position_mission_item, bool *has_next_position_item)
{ {
*has_next_position_item = false;
bool first_res = false; bool first_res = false;
int offset = 1; int offset = 1;
if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
offset = -1;
}
if (read_mission_item(0, mission_item)) { if (read_mission_item(0, mission_item)) {
first_res = true; first_res = true;
@@ -1238,7 +1433,13 @@ Mission::prepare_mission_items(mission_item_s *mission_item, mission_item_s *nex
break; break;
} }
if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
offset--;
} else {
offset++; offset++;
}
} }
} }
@@ -1249,27 +1450,25 @@ bool
Mission::read_mission_item(int offset, struct mission_item_s *mission_item) Mission::read_mission_item(int offset, struct mission_item_s *mission_item)
{ {
/* select offboard mission */ /* select offboard mission */
struct mission_s *mission = &_offboard_mission; const int current_index = _current_offboard_mission_index;
int current_index = _current_offboard_mission_index;
int index_to_read = current_index + offset; int index_to_read = current_index + offset;
int *mission_index_ptr = (offset == 0) ? &_current_offboard_mission_index : &index_to_read; int *mission_index_ptr = (offset == 0) ? &_current_offboard_mission_index : &index_to_read;
const dm_item_t dm_item = (dm_item_t)_offboard_mission.dataman_id; const dm_item_t dm_item = (dm_item_t)_offboard_mission.dataman_id;
/* do not work on empty missions */ /* do not work on empty missions */
if (mission->count == 0) { if (_offboard_mission.count == 0) {
return false; return false;
} }
/* Repeat this several times in case there are several DO JUMPS that we need to follow along, however, after /* Repeat this several times in case there are several DO JUMPS that we need to follow along, however, after
* 10 iterations we have to assume that the DO JUMPS are probably cycling and give up. */ * 10 iterations we have to assume that the DO JUMPS are probably cycling and give up. */
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
if (*mission_index_ptr < 0 || *mission_index_ptr >= (int)_offboard_mission.count) {
if (*mission_index_ptr < 0 || *mission_index_ptr >= (int)mission->count) {
/* mission item index out of bounds - if they are equal, we just reached the end */ /* mission item index out of bounds - if they are equal, we just reached the end */
if (*mission_index_ptr != (int)mission->count) { if ((*mission_index_ptr != (int)_offboard_mission.count) && (*mission_index_ptr != -1)) {
mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission item index out of bound, index: %d, max: %d.", mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Mission item index out of bound, index: %d, max: %d.",
*mission_index_ptr, mission->count); *mission_index_ptr, _offboard_mission.count);
} }
return false; return false;
@@ -1289,9 +1488,10 @@ Mission::read_mission_item(int offset, struct mission_item_s *mission_item)
/* check for DO_JUMP item, and whether it hasn't not already been repeated enough times */ /* check for DO_JUMP item, and whether it hasn't not already been repeated enough times */
if (mission_item_tmp.nav_cmd == NAV_CMD_DO_JUMP) { if (mission_item_tmp.nav_cmd == NAV_CMD_DO_JUMP) {
const bool execute_jumps = _mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_NORMAL;
/* do DO_JUMP as many times as requested */ /* do DO_JUMP as many times as requested if not in reverse mode */
if (mission_item_tmp.do_jump_current_count < mission_item_tmp.do_jump_repeat_count) { if ((mission_item_tmp.do_jump_current_count < mission_item_tmp.do_jump_repeat_count) && execute_jumps) {
/* only raise the repeat count if this is for the current mission item /* only raise the repeat count if this is for the current mission item
* but not for the read ahead mission item */ * but not for the read ahead mission item */
@@ -1313,13 +1513,18 @@ Mission::read_mission_item(int offset, struct mission_item_s *mission_item)
*mission_index_ptr = mission_item_tmp.do_jump_mission_index; *mission_index_ptr = mission_item_tmp.do_jump_mission_index;
} else { } else {
if (offset == 0) { if (offset == 0 && execute_jumps) {
mavlink_log_info(_navigator->get_mavlink_log_pub(), "DO JUMP repetitions completed."); mavlink_log_info(_navigator->get_mavlink_log_pub(), "DO JUMP repetitions completed.");
} }
/* no more DO_JUMPS, therefore just try to continue with next mission item */ /* no more DO_JUMPS, therefore just try to continue with next mission item */
if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
(*mission_index_ptr)--;
} else {
(*mission_index_ptr)++; (*mission_index_ptr)++;
} }
}
} else { } else {
/* if it's not a DO_JUMP, then we were successful */ /* if it's not a DO_JUMP, then we were successful */
@@ -1516,3 +1721,96 @@ Mission::generate_waypoint_from_heading(struct position_setpoint_s *setpoint, fl
setpoint->type = position_setpoint_s::SETPOINT_TYPE_POSITION; setpoint->type = position_setpoint_s::SETPOINT_TYPE_POSITION;
setpoint->yaw = yaw; setpoint->yaw = yaw;
} }
int32_t
Mission::index_closest_mission_item() const
{
int32_t min_dist_index(0);
float min_dist(FLT_MAX), dist_xy(FLT_MAX), dist_z(FLT_MAX);
dm_item_t dm_current = (dm_item_t)(_offboard_mission.dataman_id);
for (size_t i = 0; i < _offboard_mission.count; i++) {
struct mission_item_s missionitem = {};
const ssize_t len = sizeof(missionitem);
if (dm_read(dm_current, i, &missionitem, len) != len) {
/* not supposed to happen unless the datamanager can't access the SD card, etc. */
PX4_ERR("dataman read failure");
break;
}
if (item_contains_position(missionitem)) {
// do not consider land waypoints for a fw
if (!((missionitem.nav_cmd == NAV_CMD_LAND) &&
(!_navigator->get_vstatus()->is_rotary_wing) &&
(!_navigator->get_vstatus()->is_vtol))) {
float dist = get_distance_to_point_global_wgs84(missionitem.lat, missionitem.lon,
get_absolute_altitude_for_item(missionitem),
_navigator->get_global_position()->lat,
_navigator->get_global_position()->lon,
_navigator->get_global_position()->alt,
&dist_xy, &dist_z);
if (dist < min_dist) {
min_dist = dist;
min_dist_index = i;
}
}
}
}
// for mission reverse also consider the home position
if (_mission_execution_mode == mission_result_s::MISSION_EXECUTION_MODE_REVERSE) {
float dist = get_distance_to_point_global_wgs84(
_navigator->get_home_position()->lat,
_navigator->get_home_position()->lon,
_navigator->get_home_position()->alt,
_navigator->get_global_position()->lat,
_navigator->get_global_position()->lon,
_navigator->get_global_position()->alt,
&dist_xy, &dist_z);
if (dist < min_dist) {
min_dist = dist;
min_dist_index = -1;
}
}
return min_dist_index;
}
bool Mission::position_setpoint_equal(const position_setpoint_s *p1, const position_setpoint_s *p2) const
{
return ((p1->valid == p2->valid) &&
(p1->type == p2->type) &&
(fabsf(p1->x - p2->x) < FLT_EPSILON) &&
(fabsf(p1->y - p2->y) < FLT_EPSILON) &&
(fabsf(p1->z - p2->z) < FLT_EPSILON) &&
(p1->position_valid == p2->position_valid) &&
(fabsf(p1->vx - p2->vx) < FLT_EPSILON) &&
(fabsf(p1->vy - p2->vy) < FLT_EPSILON) &&
(fabsf(p1->vz - p2->vz) < FLT_EPSILON) &&
(p1->velocity_valid == p2->velocity_valid) &&
(p1->velocity_frame == p2->velocity_frame) &&
(p1->alt_valid == p2->alt_valid) &&
(fabs(p1->lat - p2->lat) < DBL_EPSILON) &&
(fabs(p1->lon - p2->lon) < DBL_EPSILON) &&
(fabsf(p1->alt - p2->alt) < FLT_EPSILON) &&
((fabsf(p1->yaw - p2->yaw) < FLT_EPSILON) || (!PX4_ISFINITE(p1->yaw) && !PX4_ISFINITE(p2->yaw))) &&
(p1->yaw_valid == p2->yaw_valid) &&
(fabsf(p1->yawspeed - p2->yawspeed) < FLT_EPSILON) &&
(p1->yawspeed_valid == p2->yawspeed_valid) &&
(fabsf(p1->loiter_radius - p2->loiter_radius) < FLT_EPSILON) &&
(p1->loiter_direction == p2->loiter_direction) &&
(fabsf(p1->pitch_min - p2->pitch_min) < FLT_EPSILON) &&
(fabsf(p1->a_x - p2->a_x) < FLT_EPSILON) &&
(fabsf(p1->a_y - p2->a_y) < FLT_EPSILON) &&
(fabsf(p1->a_z - p2->a_z) < FLT_EPSILON) &&
(p1->acceleration_valid == p2->acceleration_valid) &&
(p1->acceleration_is_force == p2->acceleration_is_force) &&
(fabsf(p1->acceptance_radius - p2->acceptance_radius) < FLT_EPSILON) &&
(fabsf(p1->cruising_speed - p2->cruising_speed) < FLT_EPSILON) &&
(fabsf(p1->cruising_throttle - p2->cruising_throttle) < FLT_EPSILON));
}

View File

@@ -94,7 +94,19 @@ public:
bool landing(); bool landing();
uint16_t get_land_start_index() const { return _land_start_index; } uint16_t get_land_start_index() const { return _land_start_index; }
bool get_land_start_available() const { return _land_start_available; }
bool get_mission_finished() const { return _mission_type == MISSION_TYPE_NONE; }
bool get_mission_changed() const { return _mission_changed ; }
bool get_mission_waypoints_changed() const { return _mission_waypoints_changed ; }
void set_closest_item_as_current();
/**
* Set a new mission mode and handle the switching between the different modes
*
* For a list of the different modes refer to mission_result.msg
*/
void set_execution_mode(const uint8_t mode);
private: private:
/** /**
@@ -130,7 +142,7 @@ private:
/** /**
* Copies position from setpoint if valid, otherwise copies current position * Copies position from setpoint if valid, otherwise copies current position
*/ */
void copy_positon_if_valid(struct mission_item_s *mission_item, struct position_setpoint_s *setpoint); void copy_position_if_valid(struct mission_item_s *mission_item, struct position_setpoint_s *setpoint);
/** /**
* Create mission item to align towards next waypoint * Create mission item to align towards next waypoint
@@ -162,16 +174,14 @@ private:
*/ */
void do_abort_landing(); void do_abort_landing();
float get_absolute_altitude_for_item(struct mission_item_s &mission_item);
/** /**
* Read the current and the next mission item. The next mission item read is the * Read the current and the next mission item. The next mission item read is the
* next mission item that contains a position. * next mission item that contains a position.
* *
* @return true if current mission item available * @return true if current mission item available
*/ */
bool prepare_mission_items(mission_item_s *mission_item, mission_item_s *next_position_mission_item, bool prepare_mission_items(mission_item_s *mission_item,
bool *has_next_position_item); mission_item_s *next_position_mission_item, bool *has_next_position_item);
/** /**
* Read current (offset == 0) or a specific (offset > 0) mission item * Read current (offset == 0) or a specific (offset > 0) mission item
@@ -179,7 +189,7 @@ private:
* *
* @return true if successful * @return true if successful
*/ */
bool read_mission_item(int offset, mission_item_s *mission_item); bool read_mission_item(int offset, struct mission_item_s *mission_item);
/** /**
* Save current offboard mission state to dataman * Save current offboard mission state to dataman
@@ -206,7 +216,6 @@ private:
*/ */
void check_mission_valid(bool force); void check_mission_valid(bool force);
/** /**
* Reset offboard mission * Reset offboard mission
*/ */
@@ -227,6 +236,13 @@ private:
*/ */
bool find_offboard_land_start(); bool find_offboard_land_start();
/**
* Return the index of the closest offboard mission item to the current global position.
*/
int32_t index_closest_mission_item() const;
bool position_setpoint_equal(const position_setpoint_s *p1, const position_setpoint_s *p2) const;
DEFINE_PARAMETERS( DEFINE_PARAMETERS(
(ParamFloat<px4::params::MIS_DIST_1WP>) _param_dist_1wp, (ParamFloat<px4::params::MIS_DIST_1WP>) _param_dist_1wp,
(ParamFloat<px4::params::MIS_DIST_WPS>) _param_dist_between_wps, (ParamFloat<px4::params::MIS_DIST_WPS>) _param_dist_between_wps,
@@ -253,6 +269,8 @@ private:
bool _inited{false}; bool _inited{false};
bool _home_inited{false}; bool _home_inited{false};
bool _need_mission_reset{false}; bool _need_mission_reset{false};
bool _mission_waypoints_changed{false};
bool _mission_changed{false}; /** < true if the mission changed since the mission mode was active */
float _min_current_sp_distance_xy{FLT_MAX}; /**< minimum distance which was achieved to the current waypoint */ float _min_current_sp_distance_xy{FLT_MAX}; /**< minimum distance which was achieved to the current waypoint */
@@ -269,4 +287,7 @@ private:
WORK_ITEM_TYPE_MOVE_TO_LAND_AFTER_TRANSITION, WORK_ITEM_TYPE_MOVE_TO_LAND_AFTER_TRANSITION,
WORK_ITEM_TYPE_PRECISION_LAND WORK_ITEM_TYPE_PRECISION_LAND
} _work_item_type{WORK_ITEM_TYPE_DEFAULT}; /**< current type of work to do (sub mission item) */ } _work_item_type{WORK_ITEM_TYPE_DEFAULT}; /**< current type of work to do (sub mission item) */
uint8_t _mission_execution_mode{mission_result_s::MISSION_EXECUTION_MODE_NORMAL}; /**< the current mode of how the mission is executed,look at mission_result.msg for the definition */
bool _execution_mode_changed{false};
}; };

View File

@@ -677,6 +677,15 @@ MissionBlock::set_idle_item(struct mission_item_s *item)
item->origin = ORIGIN_ONBOARD; item->origin = ORIGIN_ONBOARD;
} }
void
MissionBlock::set_vtol_transition_item(struct mission_item_s *item, const uint8_t new_mode)
{
item->nav_cmd = NAV_CMD_DO_VTOL_TRANSITION;
item->params[0] = (float) new_mode;
item->yaw = _navigator->get_global_position()->yaw;
item->autocontinue = true;
}
void void
MissionBlock::mission_apply_limitation(mission_item_s &item) MissionBlock::mission_apply_limitation(mission_item_s &item)
{ {
@@ -705,3 +714,14 @@ MissionBlock::mission_apply_limitation(mission_item_s &item)
* Add other limitations here * Add other limitations here
*/ */
} }
float
MissionBlock::get_absolute_altitude_for_item(struct mission_item_s &mission_item) const
{
if (mission_item.altitude_is_relative) {
return mission_item.altitude + _navigator->get_home_position()->alt;
} else {
return mission_item.altitude;
}
}

View File

@@ -107,6 +107,11 @@ protected:
*/ */
void set_idle_item(struct mission_item_s *item); void set_idle_item(struct mission_item_s *item);
/**
* Set vtol transition item
*/
void set_vtol_transition_item(struct mission_item_s *item, const uint8_t new_mode);
/** /**
* General function used to adjust the mission item based on vehicle specific limitations * General function used to adjust the mission item based on vehicle specific limitations
*/ */
@@ -116,6 +121,8 @@ protected:
float get_time_inside(const struct mission_item_s &item); float get_time_inside(const struct mission_item_s &item);
float get_absolute_altitude_for_item(struct mission_item_s &mission_item) const;
mission_item_s _mission_item{}; mission_item_s _mission_item{};
bool _waypoint_position_reached{false}; bool _waypoint_position_reached{false};

View File

@@ -250,9 +250,12 @@ public:
bool is_planned_mission() const { return _navigation_mode == &_mission; } bool is_planned_mission() const { return _navigation_mode == &_mission; }
bool on_mission_landing() { return _mission.landing(); } bool on_mission_landing() { return _mission.landing(); }
bool start_mission_landing() { return _mission.land_start(); } bool start_mission_landing() { return _mission.land_start(); }
bool mission_start_land_available() { return _mission.get_land_start_available(); }
// RTL // RTL
bool mission_landing_required() { return _rtl.mission_landing_required(); } bool mission_landing_required() { return _rtl.rtl_type() == RTL::RTL_LAND; }
int rtl_type() { return _rtl.rtl_type(); }
bool in_rtl_state() const { return _vstatus.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_RTL; }
bool abort_landing(); bool abort_landing();
@@ -268,7 +271,6 @@ public:
bool force_vtol(); bool force_vtol();
private: private:
int _fw_pos_ctrl_status_sub{-1}; /**< notification of vehicle capabilities updates */ int _fw_pos_ctrl_status_sub{-1}; /**< notification of vehicle capabilities updates */
int _global_pos_sub{-1}; /**< global position subscription */ int _global_pos_sub{-1}; /**< global position subscription */
int _gps_pos_sub{-1}; /**< gps position subscription */ int _gps_pos_sub{-1}; /**< gps position subscription */
@@ -298,7 +300,7 @@ private:
vehicle_land_detected_s _land_detected{}; /**< vehicle land_detected */ vehicle_land_detected_s _land_detected{}; /**< vehicle land_detected */
vehicle_local_position_s _local_pos{}; /**< local vehicle position */ vehicle_local_position_s _local_pos{}; /**< local vehicle position */
vehicle_status_s _vstatus{}; /**< vehicle status */ vehicle_status_s _vstatus{}; /**< vehicle status */
uint8_t _previous_nav_state{}; /**< nav_state of the previous iteration*/
// Publications // Publications
geofence_result_s _geofence_result{}; geofence_result_s _geofence_result{};
position_setpoint_triplet_s _pos_sp_triplet{}; /**< triplet of position setpoints */ position_setpoint_triplet_s _pos_sp_triplet{}; /**< triplet of position setpoints */

View File

@@ -111,7 +111,6 @@ Navigator::Navigator() :
_navigation_mode_array[8] = &_land; _navigation_mode_array[8] = &_land;
_navigation_mode_array[9] = &_precland; _navigation_mode_array[9] = &_precland;
_navigation_mode_array[10] = &_follow_target; _navigation_mode_array[10] = &_follow_target;
} }
void void
@@ -559,7 +558,10 @@ Navigator::run()
switch (_vstatus.nav_state) { switch (_vstatus.nav_state) {
case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION: case vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION:
_pos_sp_triplet_published_invalid_once = false; _pos_sp_triplet_published_invalid_once = false;
_mission.set_execution_mode(mission_result_s::MISSION_EXECUTION_MODE_NORMAL);
navigation_mode_new = &_mission; navigation_mode_new = &_mission;
break; break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER: case vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER:
@@ -572,11 +574,20 @@ Navigator::run()
navigation_mode_new = &_rcLoss; navigation_mode_new = &_rcLoss;
break; break;
case vehicle_status_s::NAVIGATION_STATE_AUTO_RTL: case vehicle_status_s::NAVIGATION_STATE_AUTO_RTL: {
_pos_sp_triplet_published_invalid_once = false; _pos_sp_triplet_published_invalid_once = false;
// if RTL is set to use a mission landing and mission has a planned landing, then use MISSION const bool rtl_activated = _previous_nav_state != vehicle_status_s::NAVIGATION_STATE_AUTO_RTL;
if (mission_landing_required() && on_mission_landing()) {
switch (rtl_type()) {
case RTL::RTL_LAND:
if (rtl_activated) {
mavlink_and_console_log_info(get_mavlink_log_pub(), "RTL LAND activated");
}
// if RTL is set to use a mission landing and mission has a planned landing, then use MISSION to fly there directly
if (on_mission_landing() && !get_land_detected()->landed) {
_mission.set_execution_mode(mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD);
navigation_mode_new = &_mission; navigation_mode_new = &_mission;
} else { } else {
@@ -585,6 +596,75 @@ Navigator::run()
break; break;
case RTL::RTL_MISSION:
if (_mission.get_land_start_available() && !get_land_detected()->landed) {
// the mission contains a landing spot
_mission.set_execution_mode(mission_result_s::MISSION_EXECUTION_MODE_FAST_FORWARD);
if (_navigation_mode != &_mission) {
if (_navigation_mode == nullptr) {
// switching from an manual mode, go to landing if not already landing
if (!on_mission_landing()) {
start_mission_landing();
}
} else {
// switching from an auto mode, continue the mission from the closest item
_mission.set_closest_item_as_current();
}
}
if (rtl_activated) {
mavlink_and_console_log_info(get_mavlink_log_pub(), "RTL Mission activated, continue mission");
}
navigation_mode_new = &_mission;
} else {
// fly the mission in reverse if switching from a non-manual mode
_mission.set_execution_mode(mission_result_s::MISSION_EXECUTION_MODE_REVERSE);
if ((_navigation_mode != nullptr && (_navigation_mode != &_rtl || _mission.get_mission_changed())) &&
(! _mission.get_mission_finished()) &&
(!get_land_detected()->landed)) {
// determine the closest mission item if switching from a non-mission mode, and we are either not already
// mission mode or the mission waypoints changed.
// The seconds condition is required so that when no mission was uploaded and one is available the closest
// mission item is determined and also that if the user changes the active mission index while rtl is active
// always that waypoint is tracked first.
if ((_navigation_mode != &_mission) && (rtl_activated || _mission.get_mission_waypoints_changed())) {
_mission.set_closest_item_as_current();
}
if (rtl_activated) {
mavlink_and_console_log_info(get_mavlink_log_pub(), "RTL Mission activated, fly mission in reverse");
}
navigation_mode_new = &_mission;
} else {
if (rtl_activated) {
mavlink_and_console_log_info(get_mavlink_log_pub(), "RTL Mission activated, fly to home");
}
navigation_mode_new = &_rtl;
}
}
break;
default:
if (rtl_activated) {
mavlink_and_console_log_info(get_mavlink_log_pub(), "RTL HOME activated");
}
navigation_mode_new = &_rtl;
break;
}
break;
}
case vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF: case vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF:
_pos_sp_triplet_published_invalid_once = false; _pos_sp_triplet_published_invalid_once = false;
navigation_mode_new = &_takeoff; navigation_mode_new = &_takeoff;
@@ -640,6 +720,9 @@ Navigator::run()
break; break;
} }
// update the vehicle status
_previous_nav_state = _vstatus.nav_state;
/* we have a new navigation mode: reset triplet */ /* we have a new navigation mode: reset triplet */
if (_navigation_mode != navigation_mode_new) { if (_navigation_mode != navigation_mode_new) {
// We don't reset the triplet if we just did an auto-takeoff and are now // We don't reset the triplet if we just did an auto-takeoff and are now

View File

@@ -63,11 +63,10 @@ RTL::on_inactive()
_rtl_state = RTL_STATE_NONE; _rtl_state = RTL_STATE_NONE;
} }
bool int
RTL::mission_landing_required() RTL::rtl_type() const
{ {
// returns true if navigator should use planned mission landing return _param_rtl_type.get();
return (_param_rtl_land_type.get() == 1);
} }
void void
@@ -77,9 +76,8 @@ RTL::on_activation()
// for safety reasons don't go into RTL if landed // for safety reasons don't go into RTL if landed
_rtl_state = RTL_STATE_LANDED; _rtl_state = RTL_STATE_LANDED;
} else if (mission_landing_required() && _navigator->on_mission_landing()) { } else if ((rtl_type() == RTL_LAND) && _navigator->on_mission_landing()) {
// RTL straight to RETURN state, but mission will takeover for landing // RTL straight to RETURN state, but mission will takeover for landing
_rtl_state = RTL_STATE_RETURN;
} else if ((_navigator->get_global_position()->alt < _navigator->get_home_position()->alt + _param_return_alt.get()) } else if ((_navigator->get_global_position()->alt < _navigator->get_home_position()->alt + _param_return_alt.get())
|| _rtl_alt_min) { || _rtl_alt_min) {
@@ -117,7 +115,7 @@ RTL::set_rtl_item()
// RTL_TYPE: mission landing // RTL_TYPE: mission landing
// landing using planned mission landing, fly to DO_LAND_START instead of returning HOME // landing using planned mission landing, fly to DO_LAND_START instead of returning HOME
// do nothing, let navigator takeover with mission landing // do nothing, let navigator takeover with mission landing
if (mission_landing_required()) { if (rtl_type() == RTL_LAND) {
if (_rtl_state > RTL_STATE_CLIMB) { if (_rtl_state > RTL_STATE_CLIMB) {
if (_navigator->start_mission_landing()) { if (_navigator->start_mission_landing()) {
mavlink_and_console_log_info(_navigator->get_mavlink_log_pub(), "RTL: using mission landing"); mavlink_and_console_log_info(_navigator->get_mavlink_log_pub(), "RTL: using mission landing");
@@ -137,24 +135,27 @@ RTL::set_rtl_item()
position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet(); position_setpoint_triplet_s *pos_sp_triplet = _navigator->get_position_setpoint_triplet();
switch (_rtl_state) {
case RTL_STATE_CLIMB: {
// check if we are pretty close to home already // check if we are pretty close to home already
const float home_dist = get_distance_to_next_waypoint(home.lat, home.lon, gpos.lat, gpos.lon); const float home_dist = get_distance_to_next_waypoint(home.lat, home.lon, gpos.lat, gpos.lon);
// if we are close to home we do not climb as high, otherwise we climb to return alt // compute the return altitude
float climb_alt = home.alt + _param_return_alt.get(); float return_alt = max(home.alt + _param_return_alt.get(), gpos.alt);
// we are close to home, limit climb to min // we are close to home, limit climb to min
if (home_dist < _param_rtl_min_dist.get()) { if (home_dist < _param_rtl_min_dist.get()) {
climb_alt = home.alt + _param_descend_alt.get(); return_alt = home.alt + _param_descend_alt.get();
} }
// compute the loiter altitude
const float loiter_altitude = min(home.alt + _param_descend_alt.get(), gpos.alt);
switch (_rtl_state) {
case RTL_STATE_CLIMB: {
_mission_item.nav_cmd = NAV_CMD_WAYPOINT; _mission_item.nav_cmd = NAV_CMD_WAYPOINT;
_mission_item.lat = gpos.lat; _mission_item.lat = gpos.lat;
_mission_item.lon = gpos.lon; _mission_item.lon = gpos.lon;
_mission_item.altitude = climb_alt; _mission_item.altitude = return_alt;
_mission_item.altitude_is_relative = false; _mission_item.altitude_is_relative = false;
_mission_item.yaw = NAN; _mission_item.yaw = NAN;
_mission_item.acceptance_radius = _navigator->get_acceptance_radius(); _mission_item.acceptance_radius = _navigator->get_acceptance_radius();
@@ -163,7 +164,7 @@ RTL::set_rtl_item()
_mission_item.origin = ORIGIN_ONBOARD; _mission_item.origin = ORIGIN_ONBOARD;
mavlink_and_console_log_info(_navigator->get_mavlink_log_pub(), "RTL: climb to %d m (%d m above home)", mavlink_and_console_log_info(_navigator->get_mavlink_log_pub(), "RTL: climb to %d m (%d m above home)",
(int)ceilf(climb_alt), (int)ceilf(climb_alt - _navigator->get_home_position()->alt)); (int)ceilf(return_alt), (int)ceilf(return_alt - _navigator->get_home_position()->alt));
break; break;
} }
@@ -173,13 +174,11 @@ RTL::set_rtl_item()
_mission_item.nav_cmd = NAV_CMD_WAYPOINT; _mission_item.nav_cmd = NAV_CMD_WAYPOINT;
_mission_item.lat = home.lat; _mission_item.lat = home.lat;
_mission_item.lon = home.lon; _mission_item.lon = home.lon;
_mission_item.altitude = gpos.alt; _mission_item.altitude = return_alt;
_mission_item.altitude_is_relative = false; _mission_item.altitude_is_relative = false;
// use home yaw if close to home // use home yaw if close to home
/* check if we are pretty close to home already */ /* check if we are pretty close to home already */
const float home_dist = get_distance_to_next_waypoint(home.lat, home.lon, gpos.lat, gpos.lon);
if (home_dist < _param_rtl_min_dist.get()) { if (home_dist < _param_rtl_min_dist.get()) {
_mission_item.yaw = home.yaw; _mission_item.yaw = home.yaw;
@@ -200,8 +199,7 @@ RTL::set_rtl_item()
} }
case RTL_STATE_TRANSITION_TO_MC: { case RTL_STATE_TRANSITION_TO_MC: {
_mission_item.nav_cmd = NAV_CMD_DO_VTOL_TRANSITION; set_vtol_transition_item(&_mission_item, vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC);
_mission_item.params[0] = vtol_vehicle_status_s::VEHICLE_VTOL_STATE_MC;
break; break;
} }
@@ -209,7 +207,7 @@ RTL::set_rtl_item()
_mission_item.nav_cmd = NAV_CMD_WAYPOINT; _mission_item.nav_cmd = NAV_CMD_WAYPOINT;
_mission_item.lat = home.lat; _mission_item.lat = home.lat;
_mission_item.lon = home.lon; _mission_item.lon = home.lon;
_mission_item.altitude = min(home.alt + _param_descend_alt.get(), gpos.alt); _mission_item.altitude = loiter_altitude;
_mission_item.altitude_is_relative = false; _mission_item.altitude_is_relative = false;
// except for vtol which might be still off here and should point towards this location // except for vtol which might be still off here and should point towards this location
@@ -241,7 +239,7 @@ RTL::set_rtl_item()
// don't change altitude // don't change altitude
_mission_item.lat = home.lat; _mission_item.lat = home.lat;
_mission_item.lon = home.lon; _mission_item.lon = home.lon;
_mission_item.altitude = gpos.alt; _mission_item.altitude = loiter_altitude;
_mission_item.altitude_is_relative = false; _mission_item.altitude_is_relative = false;
_mission_item.yaw = home.yaw; _mission_item.yaw = home.yaw;
_mission_item.loiter_radius = _navigator->get_loiter_radius(); _mission_item.loiter_radius = _navigator->get_loiter_radius();

View File

@@ -50,7 +50,14 @@ class Navigator;
class RTL : public MissionBlock, public ModuleParams class RTL : public MissionBlock, public ModuleParams
{ {
public: public:
enum RTLType {
RTL_HOME = 0,
RTL_LAND,
RTL_MISSION,
};
RTL(Navigator *navigator); RTL(Navigator *navigator);
~RTL() = default; ~RTL() = default;
void on_inactive() override; void on_inactive() override;
@@ -59,7 +66,7 @@ public:
void set_return_alt_min(bool min); void set_return_alt_min(bool min);
bool mission_landing_required(); int rtl_type() const;
private: private:
/** /**
@@ -90,6 +97,6 @@ private:
(ParamFloat<px4::params::RTL_DESCEND_ALT>) _param_descend_alt, (ParamFloat<px4::params::RTL_DESCEND_ALT>) _param_descend_alt,
(ParamFloat<px4::params::RTL_LAND_DELAY>) _param_land_delay, (ParamFloat<px4::params::RTL_LAND_DELAY>) _param_land_delay,
(ParamFloat<px4::params::RTL_MIN_DIST>) _param_rtl_min_dist, (ParamFloat<px4::params::RTL_MIN_DIST>) _param_rtl_min_dist,
(ParamInt<px4::params::RTL_LAND_TYPE>) _param_rtl_land_type (ParamInt<px4::params::RTL_TYPE>) _param_rtl_type
) )
}; };

View File

@@ -105,12 +105,14 @@ PARAM_DEFINE_FLOAT(RTL_LAND_DELAY, -1.0f);
PARAM_DEFINE_FLOAT(RTL_MIN_DIST, 5.0f); PARAM_DEFINE_FLOAT(RTL_MIN_DIST, 5.0f);
/** /**
* RTL land location * Return type
* *
* Land at the home location or planned mission landing * Fly straight to the home location or planned mission landing and land there or
* use the planned mission to get to those points.
* *
* @value 0 Home Position * @value 0 Return home via direct path
* @value 1 Planned Landing (Mission) * @value 1 Return to a planned mission landing, if available, via direct path, else return to home via direct path
* @value 2 Return to a planned mission landing, if available, using the mission path, else return to home via the reverse mission path
* @group Return To Land * @group Return To Land
*/ */
PARAM_DEFINE_INT32(RTL_LAND_TYPE, 0); PARAM_DEFINE_INT32(RTL_TYPE, 0);