autotest: reimplement wait_location with new object-based approach

the existing wait_and_maintain method is problematic when it comes to waiting on different value types.
This commit is contained in:
Peter Barker 2024-02-29 11:54:39 +11:00 committed by Peter Barker
parent 1509a8ea8d
commit 3ca6e29ad1
4 changed files with 194 additions and 89 deletions

View File

@ -7090,22 +7090,23 @@ class AutoTestCopter(vehicle_test_suite.TestSuite):
def check_avoidance_corners(self):
self.takeoff(10, mode="LOITER")
here = self.mav.location()
self.set_rc(2, 1400)
west_loc = mavutil.location(-35.363007,
149.164911,
0,
here.alt,
0)
self.wait_location(west_loc, accuracy=6)
north_loc = mavutil.location(-35.362908,
149.165051,
0,
here.alt,
0)
self.reach_heading_manual(0)
self.wait_location(north_loc, accuracy=6, timeout=200)
self.reach_heading_manual(90)
east_loc = mavutil.location(-35.363013,
149.165194,
0,
here.alt,
0)
self.wait_location(east_loc, accuracy=6)
self.reach_heading_manual(225)
@ -7556,18 +7557,19 @@ class AutoTestCopter(vehicle_test_suite.TestSuite):
self.takeoff(10, mode="LOITER")
self.set_rc(2, 1400)
west_loc = mavutil.location(-35.362919, 149.165055, 0, 0)
here = self.mav.location()
west_loc = mavutil.location(-35.362919, 149.165055, here.alt, 0)
self.wait_location(west_loc, accuracy=1)
self.reach_heading_manual(0)
north_loc = mavutil.location(-35.362881, 149.165103, 0, 0)
north_loc = mavutil.location(-35.362881, 149.165103, here.alt, 0)
self.wait_location(north_loc, accuracy=1)
self.set_rc(2, 1500)
self.set_rc(1, 1600)
east_loc = mavutil.location(-35.362986, 149.165227, 0, 0)
east_loc = mavutil.location(-35.362986, 149.165227, here.alt, 0)
self.wait_location(east_loc, accuracy=1)
self.set_rc(1, 1500)
self.set_rc(2, 1600)
south_loc = mavutil.location(-35.363025, 149.165182, 0, 0)
south_loc = mavutil.location(-35.363025, 149.165182, here.alt, 0)
self.wait_location(south_loc, accuracy=1)
self.set_rc(2, 1500)
self.do_RTL()

View File

@ -175,10 +175,11 @@ class AutoTestPlane(vehicle_test_suite.TestSuite):
def fly_RTL(self):
"""Fly to home."""
self.progress("Flying home in RTL")
target_loc = self.homeloc
target_loc.alt += 100
self.change_mode('RTL')
self.wait_location(self.homeloc,
self.wait_location(target_loc,
accuracy=120,
target_altitude=self.homeloc.alt+100,
height_accuracy=20,
timeout=180)
self.progress("RTL Complete")
@ -1877,8 +1878,8 @@ class AutoTestPlane(vehicle_test_suite.TestSuite):
self.wait_ready_to_arm()
self.homeloc = self.mav.location()
guided_loc = mavutil.location(-35.39723762, 149.07284612, 99.0, 0)
rally_loc = mavutil.location(-35.3654952000, 149.1558698000, 100, 0)
guided_loc = mavutil.location(-35.39723762, 149.07284612, self.homeloc.alt+99.0, 0)
rally_loc = mavutil.location(-35.3654952000, 149.1558698000, self.homeloc.alt+100, 0)
terrain_wait_path(self.homeloc, rally_loc, 10)
@ -1898,19 +1899,23 @@ class AutoTestPlane(vehicle_test_suite.TestSuite):
self.change_mode("GUIDED")
self.do_reposition(guided_loc, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT)
self.progress("Flying to guided location")
self.wait_location(guided_loc,
self.wait_location(
guided_loc,
accuracy=200,
target_altitude=None,
timeout=600)
timeout=600,
height_accuracy=10,
)
self.progress("Reached guided location")
self.set_parameter("RALLY_LIMIT_KM", 50)
self.change_mode("RTL")
self.progress("Flying to rally point")
self.wait_location(rally_loc,
self.wait_location(
rally_loc,
accuracy=200,
target_altitude=None,
timeout=600)
timeout=600,
height_accuracy=10,
)
self.progress("Reached rally point with TERRAIN_FOLLOW")
# Fly back to guided location
@ -1933,17 +1938,21 @@ class AutoTestPlane(vehicle_test_suite.TestSuite):
self.check_rally_upload_download(rally_item)
# Once back at guided location re-trigger RTL
self.wait_location(guided_loc,
self.wait_location(
guided_loc,
accuracy=200,
target_altitude=None,
timeout=600)
timeout=600,
height_accuracy=10,
)
self.change_mode("RTL")
self.progress("Flying to rally point")
self.wait_location(rally_loc,
self.wait_location(
rally_loc,
accuracy=200,
target_altitude=None,
timeout=600)
timeout=600,
height_accuracy=10,
)
self.progress("Reached rally point with terrain alt frame")
self.context_pop()

View File

@ -1369,7 +1369,7 @@ Brakes have negligible effect (with=%0.2fm without=%0.2fm delta=%0.2fm)
# location copied in from rover-test-rally.txt:
loc = mavutil.location(40.071553,
-105.229401,
0,
1583,
0)
self.wait_location(loc, accuracy=accuracy, minimum_duration=10, timeout=45)

View File

@ -342,6 +342,117 @@ class Telem(object):
self.update_read()
class WaitAndMaintain(object):
def __init__(self,
test_suite,
minimum_duration=None,
progress_print_interval=1,
timeout=30,
):
self.test_suite = test_suite
self.minimum_duration = minimum_duration
self.achieving_duration_start = None
self.timeout = timeout
self.last_progress_print = 0
self.progress_print_interval = progress_print_interval
def run(self):
self.announce_test_start()
tstart = self.test_suite.get_sim_time_cached()
while True:
now = self.test_suite.get_sim_time_cached()
current_value = self.get_current_value()
if now - self.last_progress_print > self.progress_print_interval:
self.print_progress(now, current_value)
self.last_progress_print = now
# check for timeout
if now - tstart > self.timeout:
raise self.timeoutexception()
# handle the case where we are are achieving our value:
if self.validate_value(current_value):
if self.achieving_duration_start is None:
self.achieving_duration_start = now
if (self.minimum_duration is None or
now - self.achieving_duration_start > self.minimum_duration):
self.announce_success()
return True
continue
# handle the case where we are not achieving our value:
self.achieving_duration_start = None
def progress(self, text):
self.test_suite.progress(text)
def announce_test_start(self):
self.progress(self.announce_start_text())
def announce_success(self):
self.progress(self.success_text())
def print_progress(self, now, value):
text = self.progress_text(value)
if self.achieving_duration_start is not None:
delta = now - self.achieving_duration_start
text += f" (maintain={delta:.1f}/{self.minimum_duration})"
self.progress(text)
class WaitAndMaintainLocation(WaitAndMaintain):
def __init__(self, test_suite, target, accuracy=5, height_accuracy=1, **kwargs):
super(WaitAndMaintainLocation, self).__init__(test_suite, **kwargs)
self.target = target
self.height_accuracy = height_accuracy
self.accuracy = accuracy
def announce_start_text(self):
t = self.target
if self.height_accuracy is not None:
return ("Waiting for distance to Location (%.4f, %.4f, %.2f) (h_err<%f, v_err<%.2f " %
(t.lat, t.lng, t.alt*0.01, self.accuracy, self.height_accuracy))
return ("Waiting for distance to Location (%.4f, %.4f) (h_err<%f" %
(t.lat, t.lng, self.accuracy))
def get_target_value(self):
return self.loc
def get_current_value(self):
return self.test_suite.mav.location()
def horizontal_error(self, value):
return self.test_suite.get_distance(value, self.target)
def vertical_error(self, value):
return math.fabs(value.alt*0.01 - self.target.alt*0.01)
def validate_value(self, value):
if self.horizontal_error(value) > self.accuracy:
return False
if self.height_accuracy is None:
return True
if self.vertical_error(value) > self.height_accuracy:
return False
return True
def success_text(self):
return "Reached location"
def timeoutexception(self):
return AutoTestTimeoutException("Failed to attain location")
def progress_text(self, current_value):
if self.height_accuracy is not None:
return (f"Want=({self.target.lat:.7f},{self.target.lng:.7f},{self.target.alt:.2f}) Got=({current_value.lat:.7f},{current_value.lng:.7f},{current_value.alt:.2f}) dist={self.horizontal_error(current_value):.2f} vdist={self.vertical_error(current_value):.2f}") # noqa
return (f"Want=({self.target.lat},{self.target.lng}) distance={self.horizontal_error(current_value)}")
class MSP_Generic(Telem):
def __init__(self, destination_address):
super(MSP_Generic, self).__init__(destination_address)
@ -7490,38 +7601,9 @@ class TestSuite(ABC):
0, # "land dir"
0) # flags
def wait_location(self,
loc,
accuracy=5.0,
timeout=30,
target_altitude=None,
height_accuracy=-1,
**kwargs):
"""Wait for arrival at a location."""
def get_distance_to_loc():
return self.get_distance(self.mav.location(), loc)
def validator(value2, empty=None):
if value2 <= accuracy:
if target_altitude is not None:
height_delta = math.fabs(self.mav.location().alt - target_altitude)
if height_accuracy != -1 and height_delta > height_accuracy:
return False
return True
else:
return False
debug_text = "Distance to Location (%.4f, %.4f) " % (loc.lat, loc.lng)
if target_altitude is not None:
debug_text += ",at altitude %.1f height_accuracy=%.1f, d" % (target_altitude, height_accuracy)
self.wait_and_maintain(
value_name=debug_text,
target=0,
current_value_getter=lambda: get_distance_to_loc(),
accuracy=accuracy,
validator=lambda value2, target2: validator(value2, None),
timeout=timeout,
**kwargs
)
def wait_location(self, loc, **kwargs):
waiter = WaitAndMaintainLocation(self, loc, **kwargs)
waiter.run()
def assert_current_waypoint(self, wpnum):
seq = self.mav.waypoint_current()
@ -10774,7 +10856,7 @@ Also, ignores heartbeats not from our target system'''
# Disable heading and yaw test on rover type
if self.is_rover():
test_alt = False
test_alt = True
test_heading = False
test_yaw_rate = False
else:
@ -10835,6 +10917,16 @@ Also, ignores heartbeats not from our target system'''
0, # yawrate
)
def testpos(self, targetpos : mavutil.location, test_alt : bool, frame_name : str, frame):
send_target_position(targetpos.lat, targetpos.lng, to_alt_frame(targetpos.alt, frame_name), frame)
self.wait_location(
targetpos,
accuracy=wp_accuracy,
timeout=timeout,
height_accuracy=(2 if test_alt else None),
minimum_duration=2,
)
for frame in MAV_FRAMES_TO_TEST:
frame_name = mavutil.mavlink.enums["MAV_FRAME"][frame].name
self.start_subtest("Testing Set Position in %s" % frame_name)
@ -10842,37 +10934,25 @@ Also, ignores heartbeats not from our target system'''
targetpos.lat += 0.0001
if test_alt:
targetpos.alt += 5
send_target_position(targetpos.lat, targetpos.lng, to_alt_frame(targetpos.alt, frame_name), frame)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
testpos(self, targetpos, test_alt, frame_name, frame)
self.start_subtest("Changing Longitude")
targetpos.lng += 0.0001
if test_alt:
targetpos.alt -= 5
send_target_position(targetpos.lat, targetpos.lng, to_alt_frame(targetpos.alt, frame_name), frame)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
testpos(self, targetpos, test_alt, frame_name, frame)
self.start_subtest("Revert Latitude")
targetpos.lat -= 0.0001
if test_alt:
targetpos.alt += 5
send_target_position(targetpos.lat, targetpos.lng, to_alt_frame(targetpos.alt, frame_name), frame)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
testpos(self, targetpos, test_alt, frame_name, frame)
self.start_subtest("Revert Longitude")
targetpos.lng -= 0.0001
if test_alt:
targetpos.alt -= 5
send_target_position(targetpos.lat, targetpos.lng, to_alt_frame(targetpos.alt, frame_name), frame)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
testpos(self, targetpos, test_alt, frame_name, frame)
if test_heading:
self.start_subtest("Testing Yaw targetting in %s" % frame_name)
@ -10900,9 +10980,13 @@ Also, ignores heartbeats not from our target system'''
math.radians(42), # yaw
0, # yawrate
)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
self.wait_location(
targetpos,
accuracy=wp_accuracy,
timeout=timeout,
height_accuracy=(2 if test_alt else None),
minimum_duration=2,
)
self.wait_heading(42, minimum_duration=5, timeout=timeout)
self.start_subtest("Revert Latitude and Heading")
@ -10929,9 +11013,13 @@ Also, ignores heartbeats not from our target system'''
math.radians(0), # yaw
0, # yawrate
)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2, minimum_duration=2)
self.wait_location(
targetpos,
accuracy=wp_accuracy,
timeout=timeout,
height_accuracy=(2 if test_alt else None),
minimum_duration=2,
)
self.wait_heading(0, minimum_duration=5, timeout=timeout)
if test_yaw_rate:
@ -10967,9 +11055,12 @@ Also, ignores heartbeats not from our target system'''
self.wait_yaw_speed(target_rate, timeout=timeout,
called_function=lambda plop, empty: send_yaw_rate(
target_rate, None), minimum_duration=5)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2)
self.wait_location(
targetpos,
accuracy=wp_accuracy,
timeout=timeout,
height_accuracy=(2 if test_alt else None),
)
self.start_subtest("Revert Latitude and invert Yaw rate")
target_rate = -1.0
@ -10979,9 +11070,12 @@ Also, ignores heartbeats not from our target system'''
self.wait_yaw_speed(target_rate, timeout=timeout,
called_function=lambda plop, empty: send_yaw_rate(
target_rate, None), minimum_duration=5)
self.wait_location(targetpos, accuracy=wp_accuracy, timeout=timeout,
target_altitude=(targetpos.alt if test_alt else None),
height_accuracy=2)
self.wait_location(
targetpos,
accuracy=wp_accuracy,
timeout=timeout,
height_accuracy=(2 if test_alt else None),
)
self.start_subtest("Changing Yaw rate to zero")
target_rate = 0.0
self.wait_yaw_speed(target_rate, timeout=timeout,