mirror of https://github.com/ArduPilot/ardupilot
Tools: autotest: tests for new fence code
Tools: autotest: move clear_mission up, use it before running each test Also have it understand MAV_MISSION_TYPE_ALL Tools: autotest: add tests for polyfence Tools: autotest: add tests for multiple inclusion polyfences Tools: autotest: ensure we can't arm inside a circle exclusion zone Tools: autotest: add test for arming outside an inclusion zone Tools: autotest: add tests for upload timeout Tools: autotest: add tests for not arming due to polygon zones Tools: autotest: add test for fence point reboot survivability Tools: autotest: add test for moving fence point Tools: autotest: add some tests via MAVProxy Tools: autotest: add test for avoiding polygonal exclusion zones Tools: autotest: add test for object avoidance Currently disabled as it doesn't pass where it seemingly should. Tools: autotest: skip MAVProxy tests on older MAVProxy versions Tools: autotest: adjust fence loading for lack of string back from MAVProxy Tools: autotest: create a do_RTL function Tools: autotest: cope with loading QGC-style fence files Tools: autotest: add test for object-avoidance in guided mode Tools: autotest: add OA test for auto mode Tools: autotest: add test for bendy ruler in guided mode Tools: autotest: adjust for new MAVProxy fence module not emitting old strings Tools: autotest: add tests for prearming due to bad parameter values
This commit is contained in:
parent
179db476bf
commit
0a23de087c
File diff suppressed because it is too large
Load Diff
|
@ -644,6 +644,43 @@ class AutoTestCopter(AutoTest):
|
||||||
self.fly_fence_avoid_test_radius_check(avoid_behave=1, timeout=timeout)
|
self.fly_fence_avoid_test_radius_check(avoid_behave=1, timeout=timeout)
|
||||||
self.fly_fence_avoid_test_radius_check(avoid_behave=0, timeout=timeout)
|
self.fly_fence_avoid_test_radius_check(avoid_behave=0, timeout=timeout)
|
||||||
|
|
||||||
|
def assert_prearm_failure(self, expected_statustext, timeout=5, ignore_prearm_failures=[]):
|
||||||
|
seen_statustext = False
|
||||||
|
seen_command_ack = False
|
||||||
|
|
||||||
|
self.drain_mav()
|
||||||
|
tstart = self.get_sim_time_cached()
|
||||||
|
arm_last_send = 0
|
||||||
|
while True:
|
||||||
|
if seen_command_ack and seen_statustext:
|
||||||
|
break
|
||||||
|
now = self.get_sim_time_cached()
|
||||||
|
if now - tstart > timeout:
|
||||||
|
raise NotAchievedException("Did not see failure-to-arm messages (statustext=%s command_ack=%s" % (seen_statustext, seen_command_ack))
|
||||||
|
if now - arm_last_send > 1:
|
||||||
|
arm_last_send = now
|
||||||
|
self.send_mavlink_arm_command()
|
||||||
|
m = self.mav.recv_match(blocking=True, timeout=1)
|
||||||
|
if m is None:
|
||||||
|
continue
|
||||||
|
if m.get_type() == "STATUSTEXT":
|
||||||
|
if expected_statustext in m.text:
|
||||||
|
self.progress("Got: %s" % str(m))
|
||||||
|
seen_statustext = True
|
||||||
|
elif "PreArm" in m.text and m.text[8:] not in ignore_prearm_failures:
|
||||||
|
self.progress("Got: %s" % str(m))
|
||||||
|
raise NotAchievedException("Unexpected prearm failure (%s)" % m.text)
|
||||||
|
|
||||||
|
if m.get_type() == "COMMAND_ACK":
|
||||||
|
print("Got: %s" % str(m))
|
||||||
|
if m.command == mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM:
|
||||||
|
if m.result != 4:
|
||||||
|
raise NotAchievedException("command-ack says we didn't fail to arm")
|
||||||
|
self.progress("Got: %s" % str(m))
|
||||||
|
seen_command_ack = True
|
||||||
|
if self.mav.motors_armed():
|
||||||
|
raise NotAchievedException("Armed when we shouldn't have")
|
||||||
|
|
||||||
# fly_fence_test - fly east until you hit the horizontal circular fence
|
# fly_fence_test - fly east until you hit the horizontal circular fence
|
||||||
def fly_fence_test(self, timeout=180):
|
def fly_fence_test(self, timeout=180):
|
||||||
# enable fence, disable avoidance
|
# enable fence, disable avoidance
|
||||||
|
@ -662,43 +699,29 @@ class AutoTestCopter(AutoTest):
|
||||||
self.start_subtest("ensure we can't arm if ouside fence")
|
self.start_subtest("ensure we can't arm if ouside fence")
|
||||||
self.load_fence_using_mavproxy("fence-in-middle-of-nowhere.txt")
|
self.load_fence_using_mavproxy("fence-in-middle-of-nowhere.txt")
|
||||||
self.delay_sim_time(5) # let fence check run so it loads-from-eeprom
|
self.delay_sim_time(5) # let fence check run so it loads-from-eeprom
|
||||||
seen_statustext = False
|
self.assert_prearm_failure("vehicle outside fence")
|
||||||
seen_command_ack = False
|
|
||||||
|
|
||||||
tstart = self.get_sim_time_cached()
|
|
||||||
while True:
|
|
||||||
self.send_mavlink_arm_command()
|
|
||||||
if seen_command_ack and seen_statustext:
|
|
||||||
break
|
|
||||||
if self.get_sim_time_cached() - tstart > 5:
|
|
||||||
raise NotAchievedException("Did not see failure-to-arm messages (statustext=%s command_ack=%s" % (seen_statustext, seen_command_ack))
|
|
||||||
m = self.mav.recv_match(blocking=True, timeout=1)
|
|
||||||
if m is None:
|
|
||||||
continue
|
|
||||||
if m.get_type() == "STATUSTEXT":
|
|
||||||
if "vehicle outside fence" in m.text:
|
|
||||||
self.progress("Got: %s" % str(m))
|
|
||||||
seen_statustext = True
|
|
||||||
elif "PreArm" in m.text:
|
|
||||||
self.progress("Got: %s" % str(m))
|
|
||||||
raise NotAchievedException("Unexpected prearm failure (%s)" % m.text)
|
|
||||||
|
|
||||||
if m.get_type() == "COMMAND_ACK":
|
|
||||||
print("Got: %s" % str(m))
|
|
||||||
if m.command == mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM:
|
|
||||||
if m.result != 4:
|
|
||||||
raise NotAchievedException("command-ack says we didn't fail to arm")
|
|
||||||
self.progress("Got: %s" % str(m))
|
|
||||||
seen_command_ack = True
|
|
||||||
if self.mav.motors_armed():
|
|
||||||
raise NotAchievedException("Armed when we shouldn't have")
|
|
||||||
|
|
||||||
self.progress("Failed to arm outside fence (good!)")
|
self.progress("Failed to arm outside fence (good!)")
|
||||||
|
self.clear_fence()
|
||||||
|
self.delay_sim_time(5) # let fence breach clear
|
||||||
self.drain_mav()
|
self.drain_mav()
|
||||||
self.mavproxy.send('fence clear\n')
|
self.end_subtest("ensure we can't arm if ouside fence")
|
||||||
self.delay_sim_time(2)
|
|
||||||
self.mavproxy.send('fence list\n')
|
self.start_subtest("ensure we can't arm with bad radius")
|
||||||
self.mavproxy.expect("No geo-fence points")
|
self.context_push()
|
||||||
|
self.set_parameter("FENCE_RADIUS", -1)
|
||||||
|
self.assert_prearm_failure("Invalid FENCE_RADIUS value")
|
||||||
|
self.context_pop()
|
||||||
|
self.progress("Failed to arm with bad radius")
|
||||||
|
self.drain_mav()
|
||||||
|
self.end_subtest("ensure we can't arm with bad radius")
|
||||||
|
|
||||||
|
self.start_subtest("ensure we can't arm with bad alt")
|
||||||
|
self.context_push()
|
||||||
|
self.set_parameter("FENCE_ALT_MAX", -1)
|
||||||
|
self.assert_prearm_failure("Invalid FENCE_ALT_MAX value")
|
||||||
|
self.context_pop()
|
||||||
|
self.progress("Failed to arm with bad altitude")
|
||||||
|
self.end_subtest("ensure we can't arm with bad radius")
|
||||||
|
|
||||||
self.start_subtest("Check breach-fence behaviour")
|
self.start_subtest("Check breach-fence behaviour")
|
||||||
self.set_parameter("FENCE_TYPE", 2)
|
self.set_parameter("FENCE_TYPE", 2)
|
||||||
|
|
|
@ -15,6 +15,8 @@ import operator
|
||||||
from MAVProxy.modules.lib import mp_util
|
from MAVProxy.modules.lib import mp_util
|
||||||
|
|
||||||
from pymavlink import mavwp, mavutil, DFReader
|
from pymavlink import mavwp, mavutil, DFReader
|
||||||
|
from pymavlink import mavextra
|
||||||
|
|
||||||
from pysim import util, vehicleinfo
|
from pysim import util, vehicleinfo
|
||||||
|
|
||||||
# a list of pexpect objects to read while waiting for
|
# a list of pexpect objects to read while waiting for
|
||||||
|
@ -222,6 +224,25 @@ class AutoTest(ABC):
|
||||||
HOME.alt,
|
HOME.alt,
|
||||||
HOME.heading)
|
HOME.heading)
|
||||||
|
|
||||||
|
def mavproxy_version(self):
|
||||||
|
'''return the current version of mavproxy as a tuple e.g. (1,8,8)'''
|
||||||
|
return util.MAVProxy_version()
|
||||||
|
|
||||||
|
def mavproxy_version_gt(self, major, minor, point):
|
||||||
|
if os.getenv("AUTOTEST_FORCE_MAVPROXY_VERSION", None) is not None:
|
||||||
|
return True
|
||||||
|
(got_major, got_minor, got_point) = self.mavproxy_version()
|
||||||
|
print("Got: %s.%s.%s" % (got_major, got_minor, got_point))
|
||||||
|
if got_major > major:
|
||||||
|
return True
|
||||||
|
elif got_major < major:
|
||||||
|
return False
|
||||||
|
if got_minor > minor:
|
||||||
|
return True
|
||||||
|
elif got_minor < minor:
|
||||||
|
return False
|
||||||
|
return got_point > point
|
||||||
|
|
||||||
def open_mavproxy_logfile(self):
|
def open_mavproxy_logfile(self):
|
||||||
return MAVProxyLogFile()
|
return MAVProxyLogFile()
|
||||||
|
|
||||||
|
@ -299,12 +320,29 @@ class AutoTest(ABC):
|
||||||
def count_lines_in_filepath(self, filepath):
|
def count_lines_in_filepath(self, filepath):
|
||||||
return len([i for i in open(filepath)])
|
return len([i for i in open(filepath)])
|
||||||
|
|
||||||
|
def count_expected_fence_lines_in_filepath(self, filepath):
|
||||||
|
count = 0
|
||||||
|
is_qgc = False
|
||||||
|
for i in open(filepath):
|
||||||
|
i = re.sub("#.*", "", i) # trim comments
|
||||||
|
if i.isspace():
|
||||||
|
# skip empty lines
|
||||||
|
continue
|
||||||
|
if re.match("QGC", i):
|
||||||
|
# skip QGC header line
|
||||||
|
is_qgc = True
|
||||||
|
continue
|
||||||
|
count += 1
|
||||||
|
if is_qgc:
|
||||||
|
count += 2 # file doesn't include return point + closing point
|
||||||
|
return count
|
||||||
|
|
||||||
def load_fence_using_mavproxy(self, filename):
|
def load_fence_using_mavproxy(self, filename):
|
||||||
self.set_parameter("FENCE_TOTAL", 0)
|
self.set_parameter("FENCE_TOTAL", 0)
|
||||||
filepath = os.path.join(self.mission_directory(), filename)
|
filepath = os.path.join(self.mission_directory(), filename)
|
||||||
count = self.count_lines_in_filepath(filepath)
|
count = self.count_expected_fence_lines_in_filepath(filepath)
|
||||||
self.mavproxy.send('fence load %s\n' % filepath)
|
self.mavproxy.send('fence load %s\n' % filepath)
|
||||||
self.mavproxy.expect("Loaded %u geo-fence" % count)
|
# self.mavproxy.expect("Loaded %u (geo-)?fence" % count)
|
||||||
tstart = self.get_sim_time_cached()
|
tstart = self.get_sim_time_cached()
|
||||||
while True:
|
while True:
|
||||||
t2 = self.get_sim_time_cached()
|
t2 = self.get_sim_time_cached()
|
||||||
|
@ -686,6 +724,97 @@ class AutoTest(ABC):
|
||||||
raise ValueError("count %u not handled" % count)
|
raise ValueError("count %u not handled" % count)
|
||||||
self.progress("Files same")
|
self.progress("Files same")
|
||||||
|
|
||||||
|
def assert_rally_files_same(self, file1, file2):
|
||||||
|
self.progress("Comparing (%s) and (%s)" % (file1, file2, ))
|
||||||
|
f1 = open(file1)
|
||||||
|
f2 = open(file2)
|
||||||
|
lines_f1 = f1.readlines()
|
||||||
|
lines_f2 = f2.readlines()
|
||||||
|
self.assert_rally_content_same(lines_f1, lines_f2)
|
||||||
|
|
||||||
|
def assert_rally_filepath_content(self, file1, content):
|
||||||
|
f1 = open(file1)
|
||||||
|
lines_f1 = f1.readlines()
|
||||||
|
lines_content = content.split("\n")
|
||||||
|
print("lines content: %s" % str(lines_content))
|
||||||
|
self.assert_rally_content_same(lines_f1, lines_content)
|
||||||
|
|
||||||
|
def assert_rally_content_same(self, f1, f2):
|
||||||
|
'''check each line in f1 matches one-to-one with f2'''
|
||||||
|
for l1, l2 in zip(f1, f2):
|
||||||
|
print("l1: %s" % l1)
|
||||||
|
print("l2: %s" % l2)
|
||||||
|
l1 = l1.rstrip("\n")
|
||||||
|
l2 = l2.rstrip("\n")
|
||||||
|
l1 = l1.rstrip("\r")
|
||||||
|
l2 = l2.rstrip("\r")
|
||||||
|
if l1 == l2:
|
||||||
|
# e.g. the first "QGC WPL 110" line
|
||||||
|
continue
|
||||||
|
if re.match(r"0\s", l1):
|
||||||
|
# home changes...
|
||||||
|
continue
|
||||||
|
l1 = l1.rstrip()
|
||||||
|
l2 = l2.rstrip()
|
||||||
|
print("al1: %s" % str(l1))
|
||||||
|
print("al2: %s" % str(l2))
|
||||||
|
fields1 = re.split(r"\s+", l1)
|
||||||
|
fields2 = re.split(r"\s+", l2)
|
||||||
|
# line = int(fields1[0])
|
||||||
|
t = int(fields1[3]) # mission item type
|
||||||
|
for (count, (i1, i2)) in enumerate(zip(fields1, fields2)):
|
||||||
|
# if count == 2: # frame
|
||||||
|
# if t in [mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,
|
||||||
|
# mavutil.mavlink.MAV_CMD_CONDITION_YAW,
|
||||||
|
# mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH,
|
||||||
|
# mavutil.mavlink.MAV_CMD_NAV_LOITER_TIME,
|
||||||
|
# mavutil.mavlink.MAV_CMD_DO_JUMP,
|
||||||
|
# mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONTROL,
|
||||||
|
# ]:
|
||||||
|
# # ardupilot doesn't remember frame on these commands
|
||||||
|
# if int(i1) == 3:
|
||||||
|
# i1 = 0
|
||||||
|
# if int(i2) == 3:
|
||||||
|
# i2 = 0
|
||||||
|
# if count == 6: # param 3
|
||||||
|
# if t in [mavutil.mavlink.MAV_CMD_NAV_LOITER_TIME]:
|
||||||
|
# # ardupilot canonicalises this to -1 for ccw or 1 for cw.
|
||||||
|
# if float(i1) == 0:
|
||||||
|
# i1 = 1.0
|
||||||
|
# if float(i2) == 0:
|
||||||
|
# i2 = 1.0
|
||||||
|
# if count == 7: # param 4
|
||||||
|
# if t == mavutil.mavlink.MAV_CMD_NAV_LAND:
|
||||||
|
# # ardupilot canonicalises "0" to "1" param 4 (yaw)
|
||||||
|
# if int(float(i1)) == 0:
|
||||||
|
# i1 = 1
|
||||||
|
# if int(float(i2)) == 0:
|
||||||
|
# i2 = 1
|
||||||
|
if 0 <= count <= 3 or 11 <= count <= 11:
|
||||||
|
if int(i1) != int(i2):
|
||||||
|
raise ValueError("Rally points different: (%s vs %s) (%d vs %d) (count=%u)" %
|
||||||
|
(l1, l2, int(i1), int(i2), count)) # NOCI
|
||||||
|
continue
|
||||||
|
if 4 <= count <= 10:
|
||||||
|
f_i1 = float(i1)
|
||||||
|
f_i2 = float(i2)
|
||||||
|
delta = abs(f_i1 - f_i2)
|
||||||
|
max_allowed_delta = 0.000009
|
||||||
|
if delta > max_allowed_delta:
|
||||||
|
raise ValueError(
|
||||||
|
("Rally has different (float) content: " +
|
||||||
|
"(%s vs %s) " +
|
||||||
|
"(%f vs %f) " +
|
||||||
|
"(%.10f) " +
|
||||||
|
"(count=%u)") %
|
||||||
|
(l1, l2,
|
||||||
|
f_i1, f_i2,
|
||||||
|
delta,
|
||||||
|
count)) # NOCI
|
||||||
|
continue
|
||||||
|
raise ValueError("count %u not handled" % count)
|
||||||
|
self.progress("Rally content same")
|
||||||
|
|
||||||
def load_rally(self, filename):
|
def load_rally(self, filename):
|
||||||
"""Load rally points from a file to flight controller."""
|
"""Load rally points from a file to flight controller."""
|
||||||
self.progress("Loading rally points (%s)" % filename)
|
self.progress("Loading rally points (%s)" % filename)
|
||||||
|
@ -938,6 +1067,7 @@ class AutoTest(ABC):
|
||||||
def arm_vehicle(self, timeout=20):
|
def arm_vehicle(self, timeout=20):
|
||||||
"""Arm vehicle with mavlink arm message."""
|
"""Arm vehicle with mavlink arm message."""
|
||||||
self.progress("Arm motors with MAVLink cmd")
|
self.progress("Arm motors with MAVLink cmd")
|
||||||
|
self.drain_mav()
|
||||||
tstart = self.get_sim_time()
|
tstart = self.get_sim_time()
|
||||||
self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
|
self.run_cmd(mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,
|
||||||
1, # ARM
|
1, # ARM
|
||||||
|
@ -2192,11 +2322,20 @@ class AutoTest(ABC):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if m.get_type() == 'MISSION_ACK':
|
if m.get_type() == 'MISSION_ACK':
|
||||||
raise NotAchievedException("Received unexpected mission ack %s" % str(m))
|
if (m.target_system == 255 and
|
||||||
|
m.target_component == 0 and
|
||||||
|
m.type == 1 and
|
||||||
|
m.mission_type == 0):
|
||||||
|
# this is just MAVProxy trying to screw us up
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise NotAchievedException("Received unexpected mission ack %s" % str(m))
|
||||||
|
|
||||||
self.progress("Handling request for item %u" % m.seq)
|
self.progress("Handling request for item %u/%u" % (m.seq, len(items)-1))
|
||||||
|
self.progress("Item (%s)" % str(items[m.seq]))
|
||||||
if m.seq in sent:
|
if m.seq in sent:
|
||||||
raise NotAchievedException("received duplicate request for item %u" % m.seq)
|
self.progress("received duplicate request for item %u" % m.seq)
|
||||||
|
continue
|
||||||
|
|
||||||
if m.seq not in remaining_to_send:
|
if m.seq not in remaining_to_send:
|
||||||
raise NotAchievedException("received request for unknown item %u" % m.seq)
|
raise NotAchievedException("received request for unknown item %u" % m.seq)
|
||||||
|
@ -2211,10 +2350,9 @@ class AutoTest(ABC):
|
||||||
if items[m.seq].target_component != target_component:
|
if items[m.seq].target_component != target_component:
|
||||||
raise NotAchievedException("supplied item not of correct target component")
|
raise NotAchievedException("supplied item not of correct target component")
|
||||||
if items[m.seq].seq != m.seq:
|
if items[m.seq].seq != m.seq:
|
||||||
raise NotAchievedException("requested item has incorrect sequence number")
|
raise NotAchievedException("supplied item has incorrect sequence number (%u vs %u)" % (items[m.seq].seq, m.seq))
|
||||||
|
|
||||||
items[m.seq].pack(self.mav.mav)
|
items[m.seq].pack(self.mav.mav)
|
||||||
self.progress("Sending (%s)" % str(items[m.seq]))
|
|
||||||
self.mav.mav.send(items[m.seq])
|
self.mav.mav.send(items[m.seq])
|
||||||
remaining_to_send.discard(m.seq)
|
remaining_to_send.discard(m.seq)
|
||||||
sent.add(m.seq)
|
sent.add(m.seq)
|
||||||
|
@ -2230,22 +2368,34 @@ class AutoTest(ABC):
|
||||||
(mavutil.mavlink.enums["MAV_MISSION_RESULT"][m.type].name),)
|
(mavutil.mavlink.enums["MAV_MISSION_RESULT"][m.type].name),)
|
||||||
self.progress("Upload of all %u items succeeded" % len(items))
|
self.progress("Upload of all %u items succeeded" % len(items))
|
||||||
|
|
||||||
def download_using_mission_protocol(self, mission_type):
|
def download_using_mission_protocol(self, mission_type, verbose=False, timeout=10):
|
||||||
'''mavlink2 required'''
|
'''mavlink2 required'''
|
||||||
target_system = 1
|
target_system = 1
|
||||||
target_component = 1
|
target_component = 1
|
||||||
|
self.drain_mav_unparsed()
|
||||||
|
self.progress("Sending mission_request_list")
|
||||||
self.mav.mav.mission_request_list_send(target_system,
|
self.mav.mav.mission_request_list_send(target_system,
|
||||||
target_component,
|
target_component,
|
||||||
mission_type)
|
mission_type)
|
||||||
|
|
||||||
|
tstart = self.get_sim_time_cached()
|
||||||
while True:
|
while True:
|
||||||
m = self.mav.recv_match(type='MISSION_COUNT',
|
if self.get_sim_time_cached() - tstart > timeout:
|
||||||
blocking=True,
|
raise NotAchievedException("Did not get MISSION_COUNT packet")
|
||||||
timeout=5)
|
m = self.mav.recv_match(blocking=True, timeout=0.1)
|
||||||
self.progress(str(m))
|
if verbose:
|
||||||
|
self.progress(str(m))
|
||||||
|
if m.get_type() == 'MISSION_ACK':
|
||||||
|
if m.target_system == 255 and m.target_component == 0:
|
||||||
|
# this was for MAVProxy
|
||||||
|
continue
|
||||||
|
self.progress("Mission ACK: %s" % str(m))
|
||||||
|
raise NotAchievedException("Received MISSION_ACK while waiting for MISSION_COUNT")
|
||||||
|
if m.get_type() != 'MISSION_COUNT':
|
||||||
|
continue
|
||||||
if m is None:
|
if m is None:
|
||||||
raise NotAchievedException("Did not get MISSION_COUNT response")
|
raise NotAchievedException("Did not get MISSION_COUNT response")
|
||||||
if m.target_component != 250:
|
if m.target_component != 250: # FIXME: constant?!
|
||||||
continue
|
continue
|
||||||
if m.mission_type != mission_type:
|
if m.mission_type != mission_type:
|
||||||
raise NotAchievedException("Mission count response of incorrect type")
|
raise NotAchievedException("Mission count response of incorrect type")
|
||||||
|
@ -2324,6 +2474,17 @@ class AutoTest(ABC):
|
||||||
m = self.poll_home_position()
|
m = self.poll_home_position()
|
||||||
return mavutil.location(m.latitude*1.0e-7, m.longitude*1.0e-7, m.altitude*1.0e-3, 0)
|
return mavutil.location(m.latitude*1.0e-7, m.longitude*1.0e-7, m.altitude*1.0e-3, 0)
|
||||||
|
|
||||||
|
def offset_location_ne(self, location, metres_north, metres_east):
|
||||||
|
'''return a new location offset from passed-in location'''
|
||||||
|
(target_lat, target_lng) = mavextra.gps_offset(location.lat,
|
||||||
|
location.lng,
|
||||||
|
metres_east,
|
||||||
|
metres_north)
|
||||||
|
return mavutil.location(target_lat,
|
||||||
|
target_lng,
|
||||||
|
location.alt,
|
||||||
|
location.heading)
|
||||||
|
|
||||||
def monitor_groundspeed(self, want, tolerance=0.5, timeout=5):
|
def monitor_groundspeed(self, want, tolerance=0.5, timeout=5):
|
||||||
tstart = self.get_sim_time()
|
tstart = self.get_sim_time()
|
||||||
while True:
|
while True:
|
||||||
|
@ -2897,8 +3058,47 @@ class AutoTest(ABC):
|
||||||
if m is None:
|
if m is None:
|
||||||
raise NotAchievedException("Requested CAMERA_FEEDBACK did not arrive")
|
raise NotAchievedException("Requested CAMERA_FEEDBACK did not arrive")
|
||||||
|
|
||||||
def clear_fence_using_mavproxy(self):
|
def clear_mission(self, mission_type, target_system=1, target_component=1):
|
||||||
|
'''clear mision_type from autopilot. Note that this does NOT actually
|
||||||
|
send a MISSION_CLEAR_ALL message
|
||||||
|
'''
|
||||||
|
if mission_type == mavutil.mavlink.MAV_MISSION_TYPE_ALL:
|
||||||
|
# recurse
|
||||||
|
if not self.is_tracker() and not self.is_plane():
|
||||||
|
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
|
||||||
|
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
|
||||||
|
if not self.is_sub() and not self.is_tracker():
|
||||||
|
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.mav.mav.mission_count_send(target_system,
|
||||||
|
target_component,
|
||||||
|
0,
|
||||||
|
mission_type)
|
||||||
|
m = self.mav.recv_match(type='MISSION_ACK',
|
||||||
|
blocking=True,
|
||||||
|
timeout=5)
|
||||||
|
if m is None:
|
||||||
|
raise NotAchievedException("Expected ACK for clearing mission")
|
||||||
|
if m.target_system != self.mav.mav.srcSystem:
|
||||||
|
raise NotAchievedException("ACK not targetted at correct system want=%u got=%u" %
|
||||||
|
(self.mav.mav.srcSystem, m.target_system))
|
||||||
|
if m.target_component != self.mav.mav.srcComponent:
|
||||||
|
raise NotAchievedException("ACK not targetted at correct component want=%u got=%u" %
|
||||||
|
(self.mav.mav.srcComponent, m.target_component))
|
||||||
|
if m.type != mavutil.mavlink.MAV_MISSION_ACCEPTED:
|
||||||
|
raise NotAchievedException("Expected MAV_MISSION_ACCEPTED got %s" %
|
||||||
|
(mavutil.mavlink.enums["MAV_MISSION_RESULT"][m.type].name,))
|
||||||
|
|
||||||
|
def clear_fence_using_mavproxy(self, timeout=10):
|
||||||
self.mavproxy.send("fence clear\n")
|
self.mavproxy.send("fence clear\n")
|
||||||
|
tstart = self.get_sim_time_cached()
|
||||||
|
while True:
|
||||||
|
now = self.get_sim_time_cached()
|
||||||
|
if now - tstart > timeout:
|
||||||
|
raise AutoTestTimeoutException("FENCE_TOTAL did not go to zero")
|
||||||
|
if self.get_parameter("FENCE_TOTAL") == 0:
|
||||||
|
break
|
||||||
|
|
||||||
def clear_fence(self):
|
def clear_fence(self):
|
||||||
self.clear_fence_using_mavproxy()
|
self.clear_fence_using_mavproxy()
|
||||||
|
@ -3070,6 +3270,63 @@ class AutoTest(ABC):
|
||||||
'''return mode vehicle should start in with default RC inputs set'''
|
'''return mode vehicle should start in with default RC inputs set'''
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def upload_fences_from_locations(self,
|
||||||
|
vertex_type,
|
||||||
|
list_of_list_of_locs,
|
||||||
|
target_system=1,
|
||||||
|
target_component=1):
|
||||||
|
seq = 0
|
||||||
|
items = []
|
||||||
|
for locs in list_of_list_of_locs:
|
||||||
|
if type(locs) == dict:
|
||||||
|
# circular fence
|
||||||
|
if vertex_type == mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION:
|
||||||
|
v = mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION
|
||||||
|
else:
|
||||||
|
v = mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION
|
||||||
|
item = self.mav.mav.mission_item_int_encode(
|
||||||
|
target_system,
|
||||||
|
target_component,
|
||||||
|
seq, # seq
|
||||||
|
mavutil.mavlink.MAV_FRAME_GLOBAL,
|
||||||
|
v,
|
||||||
|
0, # current
|
||||||
|
0, # autocontinue
|
||||||
|
locs["radius"], # p1
|
||||||
|
0, # p2
|
||||||
|
0, # p3
|
||||||
|
0, # p4
|
||||||
|
int(locs["loc"].lat *1e7), # latitude
|
||||||
|
int(locs["loc"].lng *1e7), # longitude
|
||||||
|
33.0000, # altitude
|
||||||
|
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
|
||||||
|
seq += 1
|
||||||
|
items.append(item)
|
||||||
|
continue
|
||||||
|
count = len(locs)
|
||||||
|
for loc in locs:
|
||||||
|
item = self.mav.mav.mission_item_int_encode(
|
||||||
|
target_system,
|
||||||
|
target_component,
|
||||||
|
seq, # seq
|
||||||
|
mavutil.mavlink.MAV_FRAME_GLOBAL,
|
||||||
|
vertex_type,
|
||||||
|
0, # current
|
||||||
|
0, # autocontinue
|
||||||
|
count, # p1
|
||||||
|
0, # p2
|
||||||
|
0, # p3
|
||||||
|
0, # p4
|
||||||
|
int(loc.lat *1e7), # latitude
|
||||||
|
int(loc.lng *1e7), # longitude
|
||||||
|
33.0000, # altitude
|
||||||
|
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
|
||||||
|
seq += 1
|
||||||
|
items.append(item)
|
||||||
|
|
||||||
|
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
|
||||||
|
items)
|
||||||
|
|
||||||
def wait_for_initial_mode(self):
|
def wait_for_initial_mode(self):
|
||||||
'''wait until we get a heartbeat with an expected initial mode (the
|
'''wait until we get a heartbeat with an expected initial mode (the
|
||||||
one specified in the vehicle constructor)'''
|
one specified in the vehicle constructor)'''
|
||||||
|
@ -3094,6 +3351,19 @@ switch value'''
|
||||||
self.progress("---------- %s ----------" % description)
|
self.progress("---------- %s ----------" % description)
|
||||||
self.progress("-")
|
self.progress("-")
|
||||||
|
|
||||||
|
def start_subsubtest(self, description):
|
||||||
|
self.progress(".")
|
||||||
|
self.progress(".......... %s .........." % description)
|
||||||
|
self.progress(".")
|
||||||
|
|
||||||
|
def end_subtest(self, description):
|
||||||
|
'''TODO: sanity checks?'''
|
||||||
|
pass
|
||||||
|
|
||||||
|
def end_subsubtest(self, description):
|
||||||
|
'''TODO: sanity checks?'''
|
||||||
|
pass
|
||||||
|
|
||||||
def test_skipped(self, test, reason):
|
def test_skipped(self, test, reason):
|
||||||
(name, desc, func) = test
|
(name, desc, func) = test
|
||||||
self.progress("##### %s is skipped: %s" % (name, reason))
|
self.progress("##### %s is skipped: %s" % (name, reason))
|
||||||
|
@ -3142,6 +3412,8 @@ switch value'''
|
||||||
self.progress("Setting up RC parameters")
|
self.progress("Setting up RC parameters")
|
||||||
self.set_rc_default()
|
self.set_rc_default()
|
||||||
self.wait_for_mode_switch_poll()
|
self.wait_for_mode_switch_poll()
|
||||||
|
if not self.is_tracker(): # FIXME - more to the point, fix Tracker's mission handling
|
||||||
|
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_ALL)
|
||||||
|
|
||||||
for test in tests:
|
for test in tests:
|
||||||
(name, desc, func) = test
|
(name, desc, func) = test
|
||||||
|
|
|
@ -353,12 +353,26 @@ def start_SITL(binary,
|
||||||
return child
|
return child
|
||||||
|
|
||||||
|
|
||||||
|
def mavproxy_cmd():
|
||||||
|
'''return path to which mavproxy to use'''
|
||||||
|
return os.getenv('MAVPROXY_CMD', 'mavproxy.py')
|
||||||
|
|
||||||
|
def MAVProxy_version():
|
||||||
|
'''return the current version of mavproxy as a tuple e.g. (1,8,8)'''
|
||||||
|
command = "%s --version" % mavproxy_cmd()
|
||||||
|
output = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).communicate()[0]
|
||||||
|
output = output.decode('ascii')
|
||||||
|
match = re.search("MAVProxy Version: ([0-9]+)[.]([0-9]+)[.]([0-9]+)", output)
|
||||||
|
if match is None:
|
||||||
|
raise ValueError("Unable to determine MAVProxy version from (%s)" % output)
|
||||||
|
return (int(match.group(1)), int(match.group(2)), int(match.group(3)))
|
||||||
|
|
||||||
def start_MAVProxy_SITL(atype, aircraft=None, setup=False, master='tcp:127.0.0.1:5760',
|
def start_MAVProxy_SITL(atype, aircraft=None, setup=False, master='tcp:127.0.0.1:5760',
|
||||||
options=[], logfile=sys.stdout):
|
options=[], logfile=sys.stdout):
|
||||||
"""Launch mavproxy connected to a SITL instance."""
|
"""Launch mavproxy connected to a SITL instance."""
|
||||||
import pexpect
|
import pexpect
|
||||||
global close_list
|
global close_list
|
||||||
MAVPROXY = os.getenv('MAVPROXY_CMD', 'mavproxy.py')
|
MAVPROXY = mavproxy_cmd()
|
||||||
cmd = MAVPROXY + ' --master=%s --out=127.0.0.1:14550' % master
|
cmd = MAVPROXY + ' --master=%s --out=127.0.0.1:14550' % master
|
||||||
if setup:
|
if setup:
|
||||||
cmd += ' --setup'
|
cmd += ' --setup'
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
QGC WPL 110
|
||||||
|
0 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.071766 -105.230202 0.000000 0
|
||||||
|
1 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.071014 -105.230247 0.000000 0
|
||||||
|
2 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.071014 -105.228821 0.000000 0
|
||||||
|
3 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.071609 -105.228867 0.000000 0
|
||||||
|
4 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.071602 -105.228172 0.000000 0
|
||||||
|
5 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.070858 -105.227982 0.000000 0
|
||||||
|
6 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.070789 -105.226219 0.000000 0
|
||||||
|
7 0 0 5001 8.000000 0.000000 0.000000 0.000000 40.072453 -105.226379 0.000000 0
|
||||||
|
8 0 0 5004 20.000000 0.000000 0.000000 0.000000 40.071609 -105.228172 0.000000 0
|
||||||
|
9 0 0 5004 20.000000 0.000000 0.000000 0.000000 40.071625 -105.227982 0.000000 0
|
|
@ -0,0 +1,4 @@
|
||||||
|
QGC WPL 110
|
||||||
|
0 0 0 16 0.000000 0.000000 0.000000 0.000000 40.071377 -105.229790 0.000000 1
|
||||||
|
1 0 3 16 0.000000 0.000000 0.000000 0.000000 40.071260 -105.227000 100.000000 1
|
||||||
|
2 0 0 20 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
|
|
@ -0,0 +1,25 @@
|
||||||
|
QGC WPL 110
|
||||||
|
0 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071613 -105.230118 0.000000 0
|
||||||
|
1 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071644 -105.229393 0.000000 0
|
||||||
|
2 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071106 -105.229393 0.000000 0
|
||||||
|
3 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071747 -105.228668 0.000000 0
|
||||||
|
4 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072220 -105.228775 0.000000 0
|
||||||
|
5 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072357 -105.229729 0.000000 0
|
||||||
|
6 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072777 -105.229988 0.000000 0
|
||||||
|
7 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.073181 -105.228897 0.000000 0
|
||||||
|
8 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072914 -105.228073 0.000000 0
|
||||||
|
9 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.073387 -105.228180 0.000000 0
|
||||||
|
10 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.073635 -105.229431 0.000000 0
|
||||||
|
11 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.073967 -105.229301 0.000000 0
|
||||||
|
12 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.073891 -105.227478 0.000000 0
|
||||||
|
13 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072697 -105.227440 0.000000 0
|
||||||
|
14 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.072430 -105.227898 0.000000 0
|
||||||
|
15 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071880 -105.227196 0.000000 0
|
||||||
|
16 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.071407 -105.227730 0.000000 0
|
||||||
|
17 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.070194 -105.227249 0.000000 0
|
||||||
|
18 0 0 5001 19.000000 0.000000 0.000000 0.000000 40.070175 -105.230110 0.000000 0
|
||||||
|
19 0 0 5002 4.000000 0.000000 0.000000 0.000000 40.071922 -105.228676 0.000000 0
|
||||||
|
20 0 0 5002 4.000000 0.000000 0.000000 0.000000 40.071712 -105.228172 0.000000 0
|
||||||
|
21 0 0 5002 4.000000 0.000000 0.000000 0.000000 40.071560 -105.228676 0.000000 0
|
||||||
|
22 0 0 5002 4.000000 0.000000 0.000000 0.000000 40.071739 -105.228920 0.000000 0
|
||||||
|
23 0 0 5004 20.000000 0.000000 0.000000 0.000000 40.072430 -105.228004 0.000000 0
|
|
@ -0,0 +1,4 @@
|
||||||
|
QGC WPL 110
|
||||||
|
0 0 0 16 0.000000 0.000000 0.000000 0.000000 40.071377 -105.229790 0.000000 1
|
||||||
|
1 0 3 16 0.000000 0.000000 0.000000 0.000000 40.073799 -105.229156 100.000000 1
|
||||||
|
2 0 0 20 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 1
|
Loading…
Reference in New Issue