Skip to content

Plane: fixed guided VTOL command in terrain mode #28406

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

Merged
merged 3 commits into from
Mar 17, 2025
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
4 changes: 2 additions & 2 deletions ArduPlane/GCS_MAVLink_Plane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -759,7 +759,7 @@ bool GCS_MAVLINK_Plane::handle_guided_request(AP_Mission::Mission_Command &cmd)
void GCS_MAVLINK_Plane::handle_change_alt_request(AP_Mission::Mission_Command &cmd)
{
plane.next_WP_loc.alt = cmd.content.location.alt;
if (cmd.content.location.relative_alt) {
if (cmd.content.location.relative_alt && !cmd.content.location.terrain_alt) {
plane.next_WP_loc.alt += plane.home.alt;
}
plane.next_WP_loc.relative_alt = false;
Expand Down Expand Up @@ -874,7 +874,7 @@ MAV_RESULT GCS_MAVLINK_Plane::handle_command_int_do_reposition(const mavlink_com
#endif

// add home alt if needed
if (requested_position.relative_alt) {
if (requested_position.relative_alt && !requested_position.terrain_alt) {
requested_position.alt += plane.home.alt;
requested_position.relative_alt = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion ArduPlane/Plane.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -875,7 +875,7 @@ bool Plane::set_target_location(const Location &target_loc)
return false;
}
// add home alt if needed
if (loc.relative_alt) {
if (loc.relative_alt && !loc.terrain_alt) {
loc.alt += plane.home.alt;
loc.relative_alt = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion ArduPlane/mode_guided.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ void ModeGuided::navigate()
bool ModeGuided::handle_guided_request(Location target_loc)
{
// add home alt if needed
if (target_loc.relative_alt) {
if (target_loc.relative_alt && !target_loc.terrain_alt) {
target_loc.alt += plane.home.alt;
target_loc.relative_alt = 0;
}
Expand Down
118 changes: 108 additions & 10 deletions Tools/autotest/arduplane.py
Original file line number Diff line number Diff line change
Expand Up @@ -5859,39 +5859,61 @@ def RunMissionScript(self):

def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):
'''test handling of MAV_CMD_GUIDED_CHANGE_ALTITUDE'''
target_alt = 750
# this location is chosen to be fairly flat, but at a different terrain height to home
higher_ground = mavutil.location(-35.35465024, 149.13974996, target_alt, 0)
self.install_terrain_handlers_context()
self.start_subtest("set home relative altitude")
self.takeoff(30, relative=True)
self.change_mode('GUIDED')

# remember home
home_loc = self.home_position_as_mav_location()
height_diff = target_alt - home_loc.alt

# fly to higher ground
self.send_do_reposition(higher_ground, frame=mavutil.mavlink.MAV_FRAME_GLOBAL)
self.wait_location(
higher_ground,
accuracy=200,
timeout=600,
height_accuracy=10,
)

for alt in 50, 70:
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,
p7=alt,
p7=alt+height_diff,
frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
)
self.wait_altitude(alt-1, alt+1, timeout=30, relative=True)
self.wait_altitude(target_alt+alt-1, target_alt+alt+1, timeout=30, minimum_duration=10, relative=False)

# test for #24535
self.start_subtest("switch to loiter and resume guided maintains home relative altitude")
self.change_mode('LOITER')
self.delay_sim_time(5)
self.delay_sim_time(1)
self.change_mode('GUIDED')
self.wait_altitude(
alt-3, # NOTE: reuse of alt from above loop!
alt+3,
height_diff+alt-3, # NOTE: reuse of alt from above loop!
height_diff+alt+3,
minimum_duration=10,
timeout=30,
relative=True,
)
# test that this works if switching between RELATIVE (HOME) and GLOBAL(AMSL)
self.start_subtest("set global/AMSL altitude, switch to loiter and resume guided")
alt = 625
alt = target_alt+30
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,
p7=alt,
frame=mavutil.mavlink.MAV_FRAME_GLOBAL,
)
self.wait_altitude(alt-3, alt+3, timeout=30, relative=False)
self.wait_altitude(alt-3, alt+3, timeout=30, relative=False, minimum_duration=10)

# let it settle so LOITER captures a constant altitude
self.delay_sim_time(10)

# now switch to LOITER then back to GUIDED
self.change_mode('LOITER')
self.delay_sim_time(5)
self.change_mode('GUIDED')
Expand All @@ -5902,6 +5924,7 @@ def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):
timeout=30,
relative=False,
)

# test that this works if switching between RELATIVE (HOME) and terrain
self.start_subtest("set terrain altitude, switch to loiter and resume guided")
self.change_mode('GUIDED')
Expand All @@ -5912,15 +5935,32 @@ def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):
frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,
)
self.wait_altitude(
alt-5, # NOTE: reuse of alt from abovE
alt+5, # use a 5m buffer as the plane needs to go up and down a bit to maintain terrain distance
alt-10, # NOTE: reuse of alt from abovE
alt+10, # use a 10m buffer as the plane needs to go up and down a bit to maintain terrain distance
minimum_duration=10,
timeout=30,
relative=False,
altitude_source="TERRAIN_REPORT.current_height"
)

alt = 150
self.run_cmd_int(
mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,
p7=alt,
frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,
)
self.wait_altitude(
alt-10, # NOTE: reuse of alt from abovE
alt+10, # use a 10m buffer as the plane needs to go up and down a bit to maintain terrain distance
minimum_duration=10,
timeout=30,
relative=False,
altitude_source="TERRAIN_REPORT.current_height"
)
self.delay_sim_time(30)

self.change_mode('LOITER')
self.delay_sim_time(5)
self.delay_sim_time(1)
self.change_mode('GUIDED')
self.wait_altitude(
alt-5, # NOTE: reuse of alt from abovE
Expand All @@ -5931,6 +5971,64 @@ def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):
altitude_source="TERRAIN_REPORT.current_height"
)

self.start_subtest("test flyto with relative alt")
dest = copy.copy(higher_ground)
dest.alt = higher_ground.alt + 100 - home_loc.alt
self.progress("dest.alt=%.1f" % dest.alt)
self.send_do_reposition(dest, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT)
self.wait_location(
dest,
accuracy=200,
timeout=600,
height_accuracy=10,
)
self.wait_altitude(
dest.alt-5,
dest.alt+5,
minimum_duration=10,
timeout=30,
relative=True
)

self.start_subtest("test flyto with absolute alt")
dest = copy.copy(higher_ground)
dest.alt = higher_ground.alt + 60
self.progress("dest.alt=%.1f" % dest.alt)
self.send_do_reposition(dest, frame=mavutil.mavlink.MAV_FRAME_GLOBAL)
self.wait_location(
dest,
accuracy=200,
timeout=600,
height_accuracy=10,
)
self.wait_altitude(
dest.alt-5,
dest.alt+5,
minimum_duration=10,
timeout=30,
relative=False
)

self.start_subtest("test flyto with terrain alt")
dest = copy.copy(higher_ground)
dest.alt = 130
self.progress("dest.alt=%.1f" % dest.alt)
self.send_do_reposition(dest, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT)
self.wait_location(
dest,
accuracy=200,
timeout=600,
height_accuracy=10,
)
self.wait_altitude(
dest.alt-10,
dest.alt+10,
minimum_duration=10,
timeout=30,
relative=False,
altitude_source="TERRAIN_REPORT.current_height"
)

self.delay_sim_time(5)
self.fly_home_land_and_disarm()

Expand Down
39 changes: 39 additions & 0 deletions Tools/autotest/quadplane.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import os
import numpy
import math
import copy

from pymavlink import mavutil
from pymavlink.rotmat import Vector3
Expand Down Expand Up @@ -2163,6 +2164,43 @@ def WindEstimateConsistency(self):
self.progress("Wind estimates correlated")
break

def DoRepositionTerrain(self):
'''test handling of DO_REPOSITION with terrain alt'''
# this location is chosen to be fairly flat, but at a different terrain height to home
self.install_terrain_handlers_context()
self.start_subtest("test reposition with terrain alt")
self.wait_ready_to_arm()

dest = copy.copy(SITL_START_LOCATION)
dest.alt = 45

self.set_parameters({
'Q_GUIDED_MODE': 1,
})

self.takeoff(30, mode='GUIDED')

# fly to higher ground
self.send_do_reposition(dest, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT)
self.wait_location(
dest,
accuracy=200,
timeout=600,
height_accuracy=10,
)
self.delay_sim_time(20)

self.wait_altitude(
dest.alt-10, # NOTE: reuse of alt from abovE
dest.alt+10, # use a 10m buffer as the plane needs to go up and down a bit to maintain terrain distance
minimum_duration=10,
timeout=30,
relative=False,
altitude_source="TERRAIN_REPORT.current_height"
)
self.change_mode("QLAND")
self.mav.motors_disarmed_wait()

def tests(self):
'''return list of all tests'''

Expand Down Expand Up @@ -2215,5 +2253,6 @@ def tests(self):
self.RTL_AUTOLAND_1, # as in fly-home then go to landing sequence
self.RTL_AUTOLAND_1_FROM_GUIDED, # as in fly-home then go to landing sequence
self.AHRSFlyForwardFlag,
self.DoRepositionTerrain,
])
return ret
Loading