/**************************************************************************** * * Copyright (c) 2013-2019 PX4 Development Team. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * 3. Neither the name PX4 nor the names of its contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************/ /** * @file mission_feasibility_checker.cpp * Provides checks if mission is feasible given the navigation capabilities * * @author Lorenz Meier * @author Thomas Gubler * @author Sander Smeets * @author Nuno Marques */ #include "mission_feasibility_checker.h" #include "mission_block.h" #include "navigator.h" #include #include #include #include #include #include bool MissionFeasibilityChecker::checkMissionFeasible(const mission_s &mission) { // Reset warning flag _navigator->get_mission_result()->warning = false; // first check if we have a valid position const bool home_valid = _navigator->home_global_position_valid(); const bool home_alt_valid = _navigator->home_alt_valid(); // trivial case: A mission with length zero cannot be valid if ((int)mission.count <= 0) { return false; } if (!home_alt_valid) { mavlink_log_info(_navigator->get_mavlink_log_pub(), "Not yet ready for mission, no position lock.\t"); events::send(events::ID("navigator_mis_no_pos_lock"), events::Log::Info, "Not yet ready for mission, no position lock"); return false; } bool failed = false; for (size_t i = 0; i < mission.count; i++) { struct mission_item_s missionitem = {}; bool success = _dataman_client.readSync((dm_item_t)mission.mission_dataman_id, i, reinterpret_cast(&missionitem), sizeof(mission_item_s)); if (!success) { _navigator->get_mission_result()->warning = true; /* not supposed to happen unless the datamanager can't access the SD card, etc. */ return false; } if (!_feasibility_checker.processNextItem(missionitem, i, mission.count)) { failed = true; break; } } failed |= _feasibility_checker.someCheckFailed(); failed |= !checkMissionAgainstGeofence(mission, _navigator->get_home_position()->alt, home_valid); _navigator->get_mission_result()->warning = failed; return !failed; } bool MissionFeasibilityChecker::checkMissionAgainstGeofence(const mission_s &mission, float home_alt, bool home_valid) { if (_navigator->get_geofence().isHomeRequired() && !home_valid) { mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence requires valid home position\t"); events::send(events::ID("navigator_mis_geofence_no_home"), {events::Log::Error, events::LogInternal::Info}, "Geofence requires a valid home position"); return false; } /* Check if all mission items are inside the geofence (if we have a valid geofence) */ if (_navigator->get_geofence().valid()) { for (size_t i = 0; i < mission.count; i++) { struct mission_item_s missionitem = {}; bool success = _dataman_client.readSync((dm_item_t)mission.mission_dataman_id, i, reinterpret_cast(&missionitem), sizeof(mission_item_s)); if (!success) { /* not supposed to happen unless the datamanager can't access the SD card, etc. */ return false; } if (missionitem.altitude_is_relative && !home_valid) { mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence requires valid home position\t"); events::send(events::ID("navigator_mis_geofence_no_home2"), {events::Log::Error, events::LogInternal::Info}, "Geofence requires a valid home position"); return false; } // Geofence function checks against home altitude amsl missionitem.altitude = missionitem.altitude_is_relative ? missionitem.altitude + home_alt : missionitem.altitude; if (MissionBlock::item_contains_position(missionitem) && !_navigator->get_geofence().checkPointAgainstAllGeofences( missionitem.lat, missionitem.lon, missionitem.altitude)) { mavlink_log_critical(_navigator->get_mavlink_log_pub(), "Geofence violation for waypoint %zu\t", i + 1); events::send(events::ID("navigator_mis_geofence_violation"), {events::Log::Error, events::LogInternal::Info}, "Geofence violation for waypoint {1}", i + 1); return false; } } } return true; }