Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Copter: support DO_RETURN_PATH_START in AUTO RTL mode #26383

Merged
merged 5 commits into from
Apr 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions ArduCopter/GCS_Mavlink.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -836,6 +836,12 @@ MAV_RESULT GCS_MAVLINK_Copter::handle_command_int_packet(const mavlink_command_i
return MAV_RESULT_ACCEPTED;

#if MODE_AUTO_ENABLED == ENABLED
case MAV_CMD_DO_RETURN_PATH_START:
if (copter.mode_auto.return_path_start_auto_RTL(ModeReason::GCS_COMMAND)) {
return MAV_RESULT_ACCEPTED;
}
return MAV_RESULT_FAILED;

case MAV_CMD_DO_LAND_START:
if (copter.mode_auto.jump_to_landing_sequence_auto_RTL(ModeReason::GCS_COMMAND)) {
return MAV_RESULT_ACCEPTED;
Expand Down
3 changes: 2 additions & 1 deletion ArduCopter/mode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ bool Copter::set_mode(Mode::Number mode, ModeReason reason)
#if MODE_AUTO_ENABLED == ENABLED
if (mode == Mode::Number::AUTO_RTL) {
// Special case for AUTO RTL, not a true mode, just AUTO in disguise
return mode_auto.jump_to_landing_sequence_auto_RTL(reason);
// Attempt to join return path, fallback to do-land-start
return mode_auto.return_path_or_jump_to_landing_sequence_auto_RTL(reason);
}
#endif

Expand Down
9 changes: 9 additions & 0 deletions ArduCopter/mode.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,12 @@ class ModeAuto : public Mode {
// Go straight to landing sequence via DO_LAND_START, if succeeds pretend to be Auto RTL mode
bool jump_to_landing_sequence_auto_RTL(ModeReason reason);

// Join mission after DO_RETURN_PATH_START waypoint, if succeeds pretend to be Auto RTL mode
bool return_path_start_auto_RTL(ModeReason reason);

// Try join return path else do land start
bool return_path_or_jump_to_landing_sequence_auto_RTL(ModeReason reason);

// lua accessors for nav script time support
bool nav_script_time(uint16_t &id, uint8_t &cmd, float &arg1, float &arg2, int16_t &arg3, int16_t &arg4);
void nav_script_time_done(uint16_t id);
Expand Down Expand Up @@ -589,6 +595,9 @@ class ModeAuto : public Mode {
AllowWeatherVaning = (1 << 7U),
};

// Enter auto rtl pseudo mode
bool enter_auto_rtl(ModeReason reason);

bool start_command(const AP_Mission::Mission_Command& cmd);
bool verify_command(const AP_Mission::Mission_Command& cmd);
void exit_mission();
Expand Down
86 changes: 67 additions & 19 deletions ArduCopter/mode_auto.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,8 @@ void ModeAuto::run()
}

// only pretend to be in auto RTL so long as mission still thinks its in a landing sequence or the mission has completed
if (auto_RTL && (!(mission.get_in_landing_sequence_flag() || mission.state() == AP_Mission::mission_state::MISSION_COMPLETE))) {
const bool auto_rtl_active = mission.get_in_landing_sequence_flag() || mission.get_in_return_path_flag() || mission.state() == AP_Mission::mission_state::MISSION_COMPLETE;
if (auto_RTL && !auto_rtl_active) {
auto_RTL = false;
// log exit from Auto RTL
#if HAL_LOGGING_ENABLED
Expand Down Expand Up @@ -216,30 +217,75 @@ bool ModeAuto::allows_weathervaning() const
// Go straight to landing sequence via DO_LAND_START, if succeeds pretend to be Auto RTL mode
bool ModeAuto::jump_to_landing_sequence_auto_RTL(ModeReason reason)
{
if (mission.jump_to_landing_sequence(get_stopping_point())) {
mission.set_force_resume(true);
// if not already in auto switch to auto
if ((copter.flightmode == &copter.mode_auto) || set_mode(Mode::Number::AUTO, reason)) {
auto_RTL = true;
if (!mission.jump_to_landing_sequence(get_stopping_point())) {
LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(Number::AUTO_RTL));
// make sad noise
if (copter.ap.initialised) {
AP_Notify::events.user_mode_change_failed = 1;
}
gcs().send_text(MAV_SEVERITY_WARNING, "Mode change to AUTO RTL failed: No landing sequence found");
rmackay9 marked this conversation as resolved.
Show resolved Hide resolved
return false;
}

return enter_auto_rtl(reason);
}

// Join mission after DO_RETURN_PATH_START waypoint, if succeeds pretend to be Auto RTL mode
bool ModeAuto::return_path_start_auto_RTL(ModeReason reason)
{
if (!mission.jump_to_closest_mission_leg(get_stopping_point())) {
LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(Number::AUTO_RTL));
// make sad noise
if (copter.ap.initialised) {
AP_Notify::events.user_mode_change_failed = 1;
}
gcs().send_text(MAV_SEVERITY_WARNING, "Mode change to AUTO RTL failed: No return path found");
return false;
}

return enter_auto_rtl(reason);
}

// Try join return path else do land start
bool ModeAuto::return_path_or_jump_to_landing_sequence_auto_RTL(ModeReason reason)
{
const Location stopping_point = get_stopping_point();
if (!mission.jump_to_closest_mission_leg(stopping_point) && !mission.jump_to_landing_sequence(stopping_point)) {
LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(Number::AUTO_RTL));
// make sad noise
if (copter.ap.initialised) {
AP_Notify::events.user_mode_change_failed = 1;
}
gcs().send_text(MAV_SEVERITY_WARNING, "Mode change to AUTO RTL failed: No return path or landing sequence found");
return false;
}

return enter_auto_rtl(reason);
}

// Enter auto rtl pseudo mode
bool ModeAuto::enter_auto_rtl(ModeReason reason)
{
mission.set_force_resume(true);

// if not already in auto switch to auto
if ((copter.flightmode == this) || set_mode(Mode::Number::AUTO, reason)) {
auto_RTL = true;
#if HAL_LOGGING_ENABLED
// log entry into AUTO RTL
copter.logger.Write_Mode((uint8_t)copter.flightmode->mode_number(), reason);
// log entry into AUTO RTL
copter.logger.Write_Mode((uint8_t)copter.flightmode->mode_number(), reason);
#endif

// make happy noise
if (copter.ap.initialised) {
AP_Notify::events.user_mode_change = 1;
}
return true;
// make happy noise
if (copter.ap.initialised) {
AP_Notify::events.user_mode_change = 1;
}
// mode change failed, revert force resume flag
mission.set_force_resume(false);

gcs().send_text(MAV_SEVERITY_WARNING, "Mode change to AUTO RTL failed");
} else {
gcs().send_text(MAV_SEVERITY_WARNING, "Mode change to AUTO RTL failed: No landing sequence found");
return true;
}

// mode change failed, revert force resume flag
mission.set_force_resume(false);

LOGGER_WRITE_ERROR(LogErrorSubsystem::FLIGHT_MODE, LogErrorCode(Number::AUTO_RTL));
// make sad noise
if (copter.ap.initialised) {
Expand Down Expand Up @@ -758,6 +804,7 @@ bool ModeAuto::start_command(const AP_Mission::Mission_Command& cmd)
break;
#endif

case MAV_CMD_DO_RETURN_PATH_START:
case MAV_CMD_DO_LAND_START:
break;

Expand Down Expand Up @@ -964,6 +1011,7 @@ bool ModeAuto::verify_command(const AP_Mission::Mission_Command& cmd)
case MAV_CMD_DO_GUIDED_LIMITS:
case MAV_CMD_DO_FENCE_ENABLE:
case MAV_CMD_DO_WINCH:
case MAV_CMD_DO_RETURN_PATH_START:
case MAV_CMD_DO_LAND_START:
cmd_complete = true;
break;
Expand Down
116 changes: 116 additions & 0 deletions Tools/autotest/arducopter.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from vehicle_test_suite import Test
from vehicle_test_suite import MAV_POS_TARGET_TYPE_MASK
from vehicle_test_suite import WaitAndMaintainArmed
from vehicle_test_suite import WaitModeTimeout

from pymavlink.rotmat import Vector3

Expand Down Expand Up @@ -10909,6 +10910,120 @@ def GuidedModeThrust(self):
self.wait_altitude(0.5, 100, relative=True, timeout=10)
self.do_RTL()

def AutoRTL(self):
'''Test Auto RTL mode using do land start and return path start mission items'''
alt = 50
guided_loc = self.home_relative_loc_ne(1000, 0)
guided_loc.alt += alt

# Arm, take off and fly to guided location
self.takeoff(mode='GUIDED')
self.fly_guided_move_to(guided_loc, timeout=240)

# Try auto RTL mode, should fail with no mission
try:
self.change_mode('AUTO_RTL', timeout=10)
raise NotAchievedException("Should not change mode with no mission")
except WaitModeTimeout:
pass
except Exception as e:
raise e

# pymavlink does not understand the new return path command yet, at some point it will
cmd_return_path_start = 188 # mavutil.mavlink.MAV_CMD_DO_RETURN_PATH_START

# Do land start and do return path should both fail as commands too
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_LAND_START, want_result=mavutil.mavlink.MAV_RESULT_FAILED)
self.run_cmd(cmd_return_path_start, want_result=mavutil.mavlink.MAV_RESULT_FAILED)

# Load mission with do land start
self.upload_simple_relhome_mission([
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 1000, 0, alt), # 1
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 750, 0, alt), # 2
self.create_MISSION_ITEM_INT(mavutil.mavlink.MAV_CMD_DO_LAND_START), # 3
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 500, 0, alt), # 4
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 250, 0, alt), # 5
])

# Return path should still fail
self.run_cmd(cmd_return_path_start, want_result=mavutil.mavlink.MAV_RESULT_FAILED)

# Do land start should jump to the waypoint following the item
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_LAND_START, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
self.drain_mav()
self.assert_current_waypoint(4)

# Back to guided location
self.change_mode('GUIDED')
self.fly_guided_move_to(guided_loc)

# mode change to Auto RTL should do the same
self.change_mode('AUTO_RTL')
self.drain_mav()
self.assert_current_waypoint(4)

# Back to guided location
self.change_mode('GUIDED')
self.fly_guided_move_to(guided_loc)

# Add a return path item
self.upload_simple_relhome_mission([
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 1250, 0, alt), # 1
self.create_MISSION_ITEM_INT(cmd_return_path_start), # 2
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 900, 0, alt), # 3
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 750, 0, alt), # 4
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 550, 0, alt), # 5
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 500, 0, alt), # 6
self.create_MISSION_ITEM_INT(mavutil.mavlink.MAV_CMD_DO_LAND_START), # 7
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 250, 0, alt), # 8
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, -250, 0, alt), # 9
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, -500, 0, alt), # 10
])

# Return path should now work
self.run_cmd(cmd_return_path_start, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
self.drain_mav()
self.assert_current_waypoint(3)

# Back to guided location
self.change_mode('GUIDED')
self.fly_guided_move_to(guided_loc)

# mode change to Auto RTL should join the return path
self.change_mode('AUTO_RTL')
self.drain_mav()
self.assert_current_waypoint(3)

# do land start should still work
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_LAND_START, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
self.drain_mav()
self.assert_current_waypoint(8)

# Move a bit closer in guided
return_path_test = self.home_relative_loc_ne(600, 0)
return_path_test.alt += alt
self.change_mode('GUIDED')
self.fly_guided_move_to(return_path_test, timeout=100)

# check the mission is joined further along
self.run_cmd(cmd_return_path_start, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
self.drain_mav()
self.assert_current_waypoint(5)

# fly over home
home = self.home_relative_loc_ne(0, 0)
home.alt += alt
self.change_mode('GUIDED')
self.fly_guided_move_to(home, timeout=140)

# Should never join return path after do land start
self.run_cmd(cmd_return_path_start, want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED)
self.drain_mav()
self.assert_current_waypoint(6)

# Done
self.land_and_disarm()

def tests2b(self): # this block currently around 9.5mins here
'''return list of all tests'''
ret = ([
Expand Down Expand Up @@ -10990,6 +11105,7 @@ def tests2b(self): # this block currently around 9.5mins here
self.LoiterToGuidedHomeVSOrigin,
self.GuidedModeThrust,
self.CompassMot,
self.AutoRTL,
])
return ret

Expand Down
13 changes: 13 additions & 0 deletions libraries/AP_Common/Location.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,19 @@ Vector3d Location::get_distance_NED_double(const Location &loc2) const
(alt - loc2.alt) * 0.01);
}

// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2 considering alt frame, if altitude cannot be resolved down distance is 0
Vector3f Location::get_distance_NED_alt_frame(const Location &loc2) const
{
int32_t alt1, alt2 = 0;
if (!get_alt_cm(AltFrame::ABSOLUTE, alt1) || !loc2.get_alt_cm(AltFrame::ABSOLUTE, alt2)) {
// one or both of the altitudes are invalid, don't do alt distance calc
alt1 = 0, alt2 = 0;
}
return Vector3f((loc2.lat - lat) * LOCATION_SCALING_FACTOR,
diff_longitude(loc2.lng,lng) * LOCATION_SCALING_FACTOR * longitude_scale((loc2.lat+lat)/2),
(alt1 - alt2) * 0.01);
}

Vector2d Location::get_distance_NE_double(const Location &loc2) const
{
return Vector2d((loc2.lat - lat) * double(LOCATION_SCALING_FACTOR),
Expand Down
3 changes: 3 additions & 0 deletions libraries/AP_Common/Location.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class Location
Vector3f get_distance_NED(const Location &loc2) const;
Vector3d get_distance_NED_double(const Location &loc2) const;

// return the distance in meters in North/East/Down plane as a N/E/D vector to loc2 considering alt frame, if altitude cannot be resolved down distance is 0
Vector3f get_distance_NED_alt_frame(const Location &loc2) const;

// return the distance in meters in North/East plane as a N/E vector to loc2
Vector2f get_distance_NE(const Location &loc2) const;
Vector2d get_distance_NE_double(const Location &loc2) const;
Expand Down
Loading
Loading