Files
PX4-Autopilot/src/modules/navigator/mission_feasibility_checker.cpp
T
KonradRudinandSilvan Fuhrer 3478765c31 Navigator: MissionFeasibilityCheck: Rework 1st waypoint check (#23568)
* FeasibilityChecker: only warn when first waypoint is too far, but still accept mission as valid

* feasiblityChecker: make distance to first waypoint check against home position instead of current position, so it is more constant during a flight

* Apply suggestions from code review

Co-authored-by: Silvan Fuhrer <silvan@auterion.com>

* feasibilityCheckerTest: update tests to not fail for first waypoint check

* feasibilityChecker: make comment for 1stwaypointcheck event

* Feasibility check unit test: fix comment

Signed-off-by: Silvan Fuhrer <silvan@auterion.com>

---------

Signed-off-by: Silvan Fuhrer <silvan@auterion.com>
Co-authored-by: Silvan Fuhrer <silvan@auterion.com>
2024-08-21 09:08:36 +02:00

155 lines
5.8 KiB
C++

/****************************************************************************
*
* 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 <lm@inf.ethz.ch>
* @author Thomas Gubler <thomasgubler@student.ethz.ch>
* @author Sander Smeets <sander@droneslab.com>
* @author Nuno Marques <nuno.marques@dronesolutions.io>
*/
#include "mission_feasibility_checker.h"
#include "mission_block.h"
#include "navigator.h"
#include <drivers/drv_pwm_output.h>
#include <lib/geo/geo.h>
#include <lib/mathlib/mathlib.h>
#include <systemlib/mavlink_log.h>
#include <uORB/Subscription.hpp>
#include <px4_platform_common/events.h>
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<uint8_t *>(&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<uint8_t *>(&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<int16_t>(events::ID("navigator_mis_geofence_violation"), {events::Log::Error, events::LogInternal::Info},
"Geofence violation for waypoint {1}",
i + 1);
return false;
}
}
}
return true;
}