mirror of https://github.com/ArduPilot/ardupilot
autotest: handle terrain requests internally to autotest
We will cache all required SRTM data within the autotest branch
This commit is contained in:
parent
1166beea81
commit
00d3af6fc5
|
@ -36,6 +36,7 @@
|
||||||
*.vbrain
|
*.vbrain
|
||||||
*.vrx
|
*.vrx
|
||||||
*.zip
|
*.zip
|
||||||
|
!Tools/autotest/tilecache/**/*.zip
|
||||||
*~
|
*~
|
||||||
.*.swo
|
.*.swo
|
||||||
.*.swp
|
.*.swp
|
||||||
|
|
|
@ -488,9 +488,8 @@ class AutoTestCopter(AutoTest):
|
||||||
|
|
||||||
self.change_mode('LOITER')
|
self.change_mode('LOITER')
|
||||||
|
|
||||||
mavproxy = self.start_mavproxy()
|
self.install_terrain_handlers_context()
|
||||||
self.wait_ready_to_arm(timeout=120*60) # terrain takes time
|
self.wait_ready_to_arm()
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
self.arm_vehicle()
|
self.arm_vehicle()
|
||||||
|
|
||||||
|
@ -3225,10 +3224,7 @@ class AutoTestCopter(AutoTest):
|
||||||
ex = None
|
ex = None
|
||||||
self.context_push()
|
self.context_push()
|
||||||
|
|
||||||
# we must start mavproxy here as otherwise we can't get the
|
self.install_terrain_handlers_context()
|
||||||
# terrain database tiles - this leads to random failures in
|
|
||||||
# CI!
|
|
||||||
mavproxy = self.start_mavproxy()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.set_analog_rangefinder_parameters()
|
self.set_analog_rangefinder_parameters()
|
||||||
|
@ -3278,8 +3274,6 @@ class AutoTestCopter(AutoTest):
|
||||||
self.disarm_vehicle(force=True)
|
self.disarm_vehicle(force=True)
|
||||||
ex = e
|
ex = e
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
self.context_pop()
|
self.context_pop()
|
||||||
self.reboot_sitl()
|
self.reboot_sitl()
|
||||||
if ex is not None:
|
if ex is not None:
|
||||||
|
@ -5779,10 +5773,7 @@ class AutoTestCopter(AutoTest):
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# we must start mavproxy here as otherwise we can't get the
|
self.install_terrain_handlers_context()
|
||||||
# terrain database tiles - this leads to random failures in
|
|
||||||
# CI!
|
|
||||||
mavproxy = self.start_mavproxy()
|
|
||||||
|
|
||||||
self.set_parameter("FS_GCS_ENABLE", 0)
|
self.set_parameter("FS_GCS_ENABLE", 0)
|
||||||
self.change_mode('GUIDED')
|
self.change_mode('GUIDED')
|
||||||
|
@ -5843,8 +5834,6 @@ class AutoTestCopter(AutoTest):
|
||||||
|
|
||||||
self.wait_disarmed()
|
self.wait_disarmed()
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
def PrecisionLoiterCompanion(self):
|
def PrecisionLoiterCompanion(self):
|
||||||
"""Use Companion PrecLand backend precision messages to loiter."""
|
"""Use Companion PrecLand backend precision messages to loiter."""
|
||||||
|
|
||||||
|
|
|
@ -2565,11 +2565,11 @@ function'''
|
||||||
|
|
||||||
def TerrainMission(self):
|
def TerrainMission(self):
|
||||||
|
|
||||||
mavproxy = self.start_mavproxy()
|
self.install_terrain_handlers_context()
|
||||||
|
|
||||||
num_wp = self.load_mission("ap-terrain.txt")
|
num_wp = self.load_mission("ap-terrain.txt")
|
||||||
|
|
||||||
self.wait_ready_to_arm(timeout=120*60) # time to get terrain
|
self.wait_ready_to_arm()
|
||||||
self.arm_vehicle()
|
self.arm_vehicle()
|
||||||
|
|
||||||
global max_alt
|
global max_alt
|
||||||
|
@ -2586,8 +2586,6 @@ function'''
|
||||||
|
|
||||||
self.fly_mission_waypoints(num_wp-1, mission_timeout=600)
|
self.fly_mission_waypoints(num_wp-1, mission_timeout=600)
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
if max_alt < 200:
|
if max_alt < 200:
|
||||||
raise NotAchievedException("Did not follow terrain")
|
raise NotAchievedException("Did not follow terrain")
|
||||||
|
|
||||||
|
@ -2595,7 +2593,7 @@ function'''
|
||||||
'''test AP_Terrain'''
|
'''test AP_Terrain'''
|
||||||
self.reboot_sitl() # we know the terrain height at CMAC
|
self.reboot_sitl() # we know the terrain height at CMAC
|
||||||
|
|
||||||
mavproxy = self.start_mavproxy()
|
self.install_terrain_handlers_context()
|
||||||
|
|
||||||
self.wait_ready_to_arm()
|
self.wait_ready_to_arm()
|
||||||
loc = self.mav.location()
|
loc = self.mav.location()
|
||||||
|
@ -2636,8 +2634,6 @@ function'''
|
||||||
raise NotAchievedException("Expected terrain height=%f got=%f" %
|
raise NotAchievedException("Expected terrain height=%f got=%f" %
|
||||||
(expected_terrain_height, report.terrain_height))
|
(expected_terrain_height, report.terrain_height))
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
def test_loiter_terrain(self):
|
def test_loiter_terrain(self):
|
||||||
default_rad = self.get_parameter("WP_LOITER_RAD")
|
default_rad = self.get_parameter("WP_LOITER_RAD")
|
||||||
self.set_parameters({
|
self.set_parameters({
|
||||||
|
|
|
@ -30,6 +30,7 @@ import threading
|
||||||
import enum
|
import enum
|
||||||
|
|
||||||
from MAVProxy.modules.lib import mp_util
|
from MAVProxy.modules.lib import mp_util
|
||||||
|
from MAVProxy.modules.lib import mp_elevation
|
||||||
|
|
||||||
from pymavlink import mavparm
|
from pymavlink import mavparm
|
||||||
from pymavlink import mavwp, mavutil, DFReader
|
from pymavlink import mavwp, mavutil, DFReader
|
||||||
|
@ -1542,6 +1543,17 @@ class AutoTest(ABC):
|
||||||
self.last_sim_time_cached = 0
|
self.last_sim_time_cached = 0
|
||||||
self.last_sim_time_cached_wallclock = 0
|
self.last_sim_time_cached_wallclock = 0
|
||||||
|
|
||||||
|
# to autopilot we do not want to go to the internet for tiles,
|
||||||
|
# usually. Set this to False to gather tiles from internet in
|
||||||
|
# the cae there are new tiles required, then add them to the
|
||||||
|
# repo and set this back to false:
|
||||||
|
self.terrain_in_offline_mode = True
|
||||||
|
self.elevationmodel = mp_elevation.ElevationModel(
|
||||||
|
cachedir=util.reltopdir("Tools/autotest/tilecache/srtm"),
|
||||||
|
offline=self.terrain_in_offline_mode
|
||||||
|
)
|
||||||
|
self.terrain_data_messages_sent = 0 # count of messages back
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
if self.rc_thread is not None:
|
if self.rc_thread is not None:
|
||||||
self.progress("Joining RC thread in __del__")
|
self.progress("Joining RC thread in __del__")
|
||||||
|
@ -7029,6 +7041,8 @@ Also, ignores heartbeats not from our target system'''
|
||||||
self.progress(fmt % ("**--tests_total_time--**", tests_total_time))
|
self.progress(fmt % ("**--tests_total_time--**", tests_total_time))
|
||||||
self.progress("mavproxy_start was called %u times" %
|
self.progress("mavproxy_start was called %u times" %
|
||||||
(self.start_mavproxy_count,))
|
(self.start_mavproxy_count,))
|
||||||
|
self.progress("Supplied terrain data to autopilot in %u messages" %
|
||||||
|
(self.terrain_data_messages_sent,))
|
||||||
|
|
||||||
def send_statustext(self, text):
|
def send_statustext(self, text):
|
||||||
if sys.version_info.major >= 3 and not isinstance(text, bytes):
|
if sys.version_info.major >= 3 and not isinstance(text, bytes):
|
||||||
|
@ -9510,6 +9524,61 @@ Also, ignores heartbeats not from our target system'''
|
||||||
self.context_pop()
|
self.context_pop()
|
||||||
self.reboot_sitl()
|
self.reboot_sitl()
|
||||||
|
|
||||||
|
def install_terrain_handlers_context(self):
|
||||||
|
'''install a message handler into the current context which will
|
||||||
|
listen for an fulfill terrain requests from ArduPilot. Will
|
||||||
|
die if the data is not available - but
|
||||||
|
self.terrain_in_offline_mode can be set to true in the
|
||||||
|
constructor to change this behaviour
|
||||||
|
'''
|
||||||
|
|
||||||
|
def check_terrain_requests(mav, m):
|
||||||
|
if m.get_type() != 'TERRAIN_REQUEST':
|
||||||
|
return
|
||||||
|
self.progress("Processing TERRAIN_REQUEST (%s)" %
|
||||||
|
self.dump_message_verbose(m))
|
||||||
|
# swiped from mav_terrain.py
|
||||||
|
for bit in range(56):
|
||||||
|
if m.mask & (1 << bit) == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
lat = m.lat * 1.0e-7
|
||||||
|
lon = m.lon * 1.0e-7
|
||||||
|
bit_spacing = m.grid_spacing * 4
|
||||||
|
(lat, lon) = mp_util.gps_offset(lat, lon,
|
||||||
|
east=bit_spacing * (bit % 8),
|
||||||
|
north=bit_spacing * (bit // 8))
|
||||||
|
data = []
|
||||||
|
for i in range(4*4):
|
||||||
|
y = i % 4
|
||||||
|
x = i // 4
|
||||||
|
(lat2, lon2) = mp_util.gps_offset(lat, lon,
|
||||||
|
east=m.grid_spacing * y,
|
||||||
|
north=m.grid_spacing * x)
|
||||||
|
# if we are in online mode then we'll try to fetch
|
||||||
|
# from the internet into the cache dir:
|
||||||
|
for i in range(120):
|
||||||
|
alt = self.elevationmodel.GetElevation(lat2, lon2)
|
||||||
|
if alt is not None:
|
||||||
|
break
|
||||||
|
if self.terrain_in_offline_mode:
|
||||||
|
break
|
||||||
|
self.progress("No elevation data for (%f %f); retry" %
|
||||||
|
(lat2, lon2))
|
||||||
|
time.sleep(1)
|
||||||
|
if alt is None:
|
||||||
|
# no data - we can't send the packet
|
||||||
|
raise ValueError("No elevation data for (%f %f)" % (lat2, lon2))
|
||||||
|
data.append(int(alt))
|
||||||
|
self.terrain_data_messages_sent += 1
|
||||||
|
self.mav.mav.terrain_data_send(m.lat,
|
||||||
|
m.lon,
|
||||||
|
m.grid_spacing,
|
||||||
|
bit,
|
||||||
|
data)
|
||||||
|
|
||||||
|
self.install_message_hook_context(check_terrain_requests)
|
||||||
|
|
||||||
def test_set_position_global_int(self, timeout=100):
|
def test_set_position_global_int(self, timeout=100):
|
||||||
"""Test set position message in guided mode."""
|
"""Test set position message in guided mode."""
|
||||||
# Disable heading and yaw test on rover type
|
# Disable heading and yaw test on rover type
|
||||||
|
@ -9523,10 +9592,7 @@ Also, ignores heartbeats not from our target system'''
|
||||||
test_heading = True
|
test_heading = True
|
||||||
test_yaw_rate = True
|
test_yaw_rate = True
|
||||||
|
|
||||||
# we must start mavproxy here as otherwise we can't get the
|
self.install_terrain_handlers_context()
|
||||||
# terrain database tiles - this leads to random failures in
|
|
||||||
# CI!
|
|
||||||
mavproxy = self.start_mavproxy()
|
|
||||||
|
|
||||||
self.set_parameter("FS_GCS_ENABLE", 0)
|
self.set_parameter("FS_GCS_ENABLE", 0)
|
||||||
self.change_mode("GUIDED")
|
self.change_mode("GUIDED")
|
||||||
|
@ -9732,8 +9798,6 @@ Also, ignores heartbeats not from our target system'''
|
||||||
called_function=lambda plop, empty: send_yaw_rate(
|
called_function=lambda plop, empty: send_yaw_rate(
|
||||||
target_rate, None), minimum_duration=5)
|
target_rate, None), minimum_duration=5)
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
self.progress("Getting back to home and disarm")
|
self.progress("Getting back to home and disarm")
|
||||||
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
|
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
|
||||||
self.disarm_vehicle()
|
self.disarm_vehicle()
|
||||||
|
@ -9750,10 +9814,7 @@ Also, ignores heartbeats not from our target system'''
|
||||||
test_heading = True
|
test_heading = True
|
||||||
test_yaw_rate = True
|
test_yaw_rate = True
|
||||||
|
|
||||||
# we must start mavproxy here as otherwise we can't get the
|
self.install_terrain_handlers_context()
|
||||||
# terrain database tiles - this leads to random failures in
|
|
||||||
# CI!
|
|
||||||
mavproxy = self.start_mavproxy()
|
|
||||||
|
|
||||||
self.set_parameter("FS_GCS_ENABLE", 0)
|
self.set_parameter("FS_GCS_ENABLE", 0)
|
||||||
self.change_mode("GUIDED")
|
self.change_mode("GUIDED")
|
||||||
|
@ -10099,8 +10160,6 @@ Also, ignores heartbeats not from our target system'''
|
||||||
minimum_duration=2
|
minimum_duration=2
|
||||||
)
|
)
|
||||||
|
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
self.progress("Getting back to home and disarm")
|
self.progress("Getting back to home and disarm")
|
||||||
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
|
self.do_RTL(distance_min=0, distance_max=wp_accuracy)
|
||||||
self.disarm_vehicle()
|
self.disarm_vehicle()
|
||||||
|
|
|
@ -556,7 +556,7 @@ def start_MAVProxy_SITL(atype,
|
||||||
aircraft = 'test.%s' % atype
|
aircraft = 'test.%s' % atype
|
||||||
cmd.extend(['--aircraft', aircraft])
|
cmd.extend(['--aircraft', aircraft])
|
||||||
cmd.extend(options)
|
cmd.extend(options)
|
||||||
cmd.extend(['--default-modules', 'misc,terrain,wp,rally,fence,param,arm,mode,rc,cmdlong,output'])
|
cmd.extend(['--default-modules', 'misc,wp,rally,fence,param,arm,mode,rc,cmdlong,output'])
|
||||||
|
|
||||||
print("PYTHONPATH: %s" % str(env['PYTHONPATH']))
|
print("PYTHONPATH: %s" % str(env['PYTHONPATH']))
|
||||||
print("Running: %s" % cmd_as_shell(cmd))
|
print("Running: %s" % cmd_as_shell(cmd))
|
||||||
|
|
|
@ -290,12 +290,8 @@ class AutoTestQuadPlane(AutoTest):
|
||||||
self.load_fence(fence)
|
self.load_fence(fence)
|
||||||
if self.mavproxy is not None:
|
if self.mavproxy is not None:
|
||||||
self.mavproxy.send('wp list\n')
|
self.mavproxy.send('wp list\n')
|
||||||
# terrain can take a *long* time to load:
|
self.install_terrain_handlers_context()
|
||||||
timeout = 120
|
self.wait_ready_to_arm()
|
||||||
if include_terrain_timeout:
|
|
||||||
timeout *= 1000 # yes, *that* long
|
|
||||||
mavproxy = self.start_mavproxy()
|
|
||||||
self.wait_ready_to_arm(timeout=timeout)
|
|
||||||
self.arm_vehicle()
|
self.arm_vehicle()
|
||||||
self.change_mode('AUTO')
|
self.change_mode('AUTO')
|
||||||
self.wait_waypoint(1, 19, max_dist=60, timeout=1200)
|
self.wait_waypoint(1, 19, max_dist=60, timeout=1200)
|
||||||
|
@ -303,13 +299,12 @@ class AutoTestQuadPlane(AutoTest):
|
||||||
self.wait_disarmed(timeout=120) # give quadplane a long time to land
|
self.wait_disarmed(timeout=120) # give quadplane a long time to land
|
||||||
# wait for blood sample here
|
# wait for blood sample here
|
||||||
self.set_current_waypoint(20)
|
self.set_current_waypoint(20)
|
||||||
self.wait_ready_to_arm(timeout=timeout)
|
self.wait_ready_to_arm()
|
||||||
self.arm_vehicle()
|
self.arm_vehicle()
|
||||||
self.wait_waypoint(20, 34, max_dist=60, timeout=1200)
|
self.wait_waypoint(20, 34, max_dist=60, timeout=1200)
|
||||||
|
|
||||||
self.wait_disarmed(timeout=120) # give quadplane a long time to land
|
self.wait_disarmed(timeout=120) # give quadplane a long time to land
|
||||||
self.progress("Mission OK")
|
self.progress("Mission OK")
|
||||||
self.stop_mavproxy(mavproxy)
|
|
||||||
|
|
||||||
def enum_state_name(self, enum_name, state, pretrim=None):
|
def enum_state_name(self, enum_name, state, pretrim=None):
|
||||||
e = mavutil.mavlink.enums[enum_name]
|
e = mavutil.mavlink.enums[enum_name]
|
||||||
|
|
Loading…
Reference in New Issue