Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/master/Tools/autotest/arduplane.py
Views: 1798
'''1Fly ArduPlane in SITL23AP_FLAKE8_CLEAN4'''56from __future__ import print_function7import copy8import math9import os10import signal1112from pymavlink import quaternion13from pymavlink import mavutil1415from pymavlink.rotmat import Vector31617import vehicle_test_suite1819from vehicle_test_suite import AutoTestTimeoutException20from vehicle_test_suite import NotAchievedException21from vehicle_test_suite import OldpymavlinkException22from vehicle_test_suite import PreconditionFailedException23from vehicle_test_suite import Test24from vehicle_test_suite import WaitModeTimeout2526from pysim import vehicleinfo27from pysim import util2829import operator3031# get location of scripts32testdir = os.path.dirname(os.path.realpath(__file__))33SITL_START_LOCATION = mavutil.location(-35.362938, 149.165085, 585, 354)34WIND = "0,180,0.2" # speed,direction,variance353637class AutoTestPlane(vehicle_test_suite.TestSuite):38@staticmethod39def get_not_armable_mode_list():40return []4142@staticmethod43def get_not_disarmed_settable_modes_list():44return ["FOLLOW"]4546@staticmethod47def get_no_position_not_settable_modes_list():48return []4950@staticmethod51def get_position_armable_modes_list():52return ["GUIDED", "AUTO"]5354@staticmethod55def get_normal_armable_modes_list():56return ["MANUAL", "STABILIZE", "ACRO"]5758def log_name(self):59return "ArduPlane"6061def default_speedup(self):62return 1006364def test_filepath(self):65return os.path.realpath(__file__)6667def sitl_start_location(self):68return SITL_START_LOCATION6970def defaults_filepath(self):71return os.path.join(testdir, 'default_params/plane-jsbsim.parm')7273def set_current_test_name(self, name):74self.current_test_name_directory = "ArduPlane_Tests/" + name + "/"7576def default_frame(self):77return "plane-elevrev"7879def apply_defaultfile_parameters(self):80# plane passes in a defaults_filepath in place of applying81# parameters afterwards.82pass8384def is_plane(self):85return True8687def get_stick_arming_channel(self):88return int(self.get_parameter("RCMAP_YAW"))8990def get_disarm_delay(self):91return int(self.get_parameter("LAND_DISARMDELAY"))9293def set_autodisarm_delay(self, delay):94self.set_parameter("LAND_DISARMDELAY", delay)9596def takeoff(self, alt=150, alt_max=None, relative=True, mode=None, timeout=None):97"""Takeoff to altitude."""9899if mode == "TAKEOFF":100return self.takeoff_in_TAKEOFF(alt=alt, relative=relative, timeout=timeout)101102return self.takeoff_in_FBWA(alt=alt, alt_max=alt_max, relative=relative, timeout=timeout)103104def takeoff_in_TAKEOFF(self, alt=150, relative=True, mode=None, alt_epsilon=2, timeout=None):105if relative is not True:106raise ValueError("Only relative alt supported ATM")107self.change_mode("TAKEOFF")108self.context_push()109self.set_parameter('TKOFF_ALT', alt)110self.wait_ready_to_arm()111self.arm_vehicle()112self.wait_altitude(alt-alt_epsilon, alt+alt_epsilon, relative=True, timeout=timeout)113self.context_pop()114115def takeoff_in_FBWA(self, alt=150, alt_max=None, relative=True, mode=None, timeout=30):116if alt_max is None:117alt_max = alt + 30118119self.change_mode("FBWA")120121self.wait_ready_to_arm()122self.arm_vehicle()123124# some rudder to counteract the prop torque125self.set_rc(4, 1700)126127# some up elevator to keep the tail down128self.set_rc(2, 1200)129130# get it moving a bit first131self.set_rc(3, 1300)132self.wait_groundspeed(6, 100)133134# a bit faster again, straighten rudder135self.set_rc_from_map({1363: 1600,1374: 1500,138})139self.wait_groundspeed(12, 100)140141# hit the gas harder now, and give it some more elevator142self.set_rc_from_map({1432: 1100,1443: 2000,145})146147# gain a bit of altitude148self.wait_altitude(alt, alt_max, timeout=timeout, relative=relative)149150# level off151self.set_rc(2, 1500)152153self.progress("TAKEOFF COMPLETE")154155def fly_left_circuit(self):156"""Fly a left circuit, 200m on a side."""157self.change_mode('FBWA')158self.set_rc(3, 2000)159self.wait_level_flight()160161self.progress("Flying left circuit")162# do 4 turns163for i in range(0, 4):164# hard left165self.progress("Starting turn %u" % i)166self.set_rc(1, 1000)167self.wait_heading(270 - (90*i), accuracy=10)168self.set_rc(1, 1500)169self.progress("Starting leg %u" % i)170self.wait_distance(100, accuracy=20)171self.progress("Circuit complete")172173def fly_RTL(self):174"""Fly to home."""175self.progress("Flying home in RTL")176target_loc = self.home_position_as_mav_location()177target_loc.alt += 100178self.change_mode('RTL')179self.wait_location(target_loc,180accuracy=120,181height_accuracy=20,182timeout=180)183self.progress("RTL Complete")184185def NeedEKFToArm(self):186"""Ensure the EKF must be healthy for the vehicle to arm."""187self.progress("Ensuring we need EKF to be healthy to arm")188self.set_parameter("SIM_GPS1_ENABLE", 0)189self.context_collect("STATUSTEXT")190tstart = self.get_sim_time()191success = False192for run_cmd in self.run_cmd, self.run_cmd_int:193while not success:194if self.get_sim_time_cached() - tstart > 60:195raise NotAchievedException("Did not get correct failure reason")196run_cmd(mavutil.mavlink.MAV_CMD_RUN_PREARM_CHECKS)197try:198self.wait_statustext(".*AHRS: not using configured AHRS type.*", timeout=1, check_context=True, regex=True)199success = True200continue201except AutoTestTimeoutException:202pass203204self.set_parameter("SIM_GPS1_ENABLE", 1)205self.wait_ready_to_arm()206207def fly_LOITER(self, num_circles=4):208"""Loiter where we are."""209self.progress("Testing LOITER for %u turns" % num_circles)210self.change_mode('LOITER')211212m = self.mav.recv_match(type='VFR_HUD', blocking=True)213initial_alt = m.alt214self.progress("Initial altitude %u\n" % initial_alt)215216while num_circles > 0:217self.wait_heading(0, accuracy=10, timeout=60)218self.wait_heading(180, accuracy=10, timeout=60)219num_circles -= 1220self.progress("Loiter %u circles left" % num_circles)221222m = self.mav.recv_match(type='VFR_HUD', blocking=True)223final_alt = m.alt224self.progress("Final altitude %u initial %u\n" %225(final_alt, initial_alt))226227self.change_mode('FBWA')228229if abs(final_alt - initial_alt) > 20:230raise NotAchievedException("Failed to maintain altitude")231232self.progress("Completed Loiter OK")233234def fly_CIRCLE(self, num_circles=1):235"""Circle where we are."""236self.progress("Testing CIRCLE for %u turns" % num_circles)237self.change_mode('CIRCLE')238239m = self.mav.recv_match(type='VFR_HUD', blocking=True)240initial_alt = m.alt241self.progress("Initial altitude %u\n" % initial_alt)242243while num_circles > 0:244self.wait_heading(0, accuracy=10, timeout=60)245self.wait_heading(180, accuracy=10, timeout=60)246num_circles -= 1247self.progress("CIRCLE %u circles left" % num_circles)248249m = self.mav.recv_match(type='VFR_HUD', blocking=True)250final_alt = m.alt251self.progress("Final altitude %u initial %u\n" %252(final_alt, initial_alt))253254self.change_mode('FBWA')255256if abs(final_alt - initial_alt) > 20:257raise NotAchievedException("Failed to maintain altitude")258259self.progress("Completed CIRCLE OK")260261def wait_level_flight(self, accuracy=5, timeout=30):262"""Wait for level flight."""263tstart = self.get_sim_time()264self.progress("Waiting for level flight")265self.set_rc(1, 1500)266self.set_rc(2, 1500)267self.set_rc(4, 1500)268while self.get_sim_time_cached() < tstart + timeout:269m = self.mav.recv_match(type='ATTITUDE', blocking=True)270roll = math.degrees(m.roll)271pitch = math.degrees(m.pitch)272self.progress("Roll=%.1f Pitch=%.1f" % (roll, pitch))273if math.fabs(roll) <= accuracy and math.fabs(pitch) <= accuracy:274self.progress("Attained level flight")275return276raise NotAchievedException("Failed to attain level flight")277278def change_altitude(self, altitude, accuracy=30, relative=False):279"""Get to a given altitude."""280if relative:281altitude += self.home_position_as_mav_location().alt282self.change_mode('FBWA')283alt_error = self.mav.messages['VFR_HUD'].alt - altitude284if alt_error > 0:285self.set_rc(2, 2000)286else:287self.set_rc(2, 1000)288self.wait_altitude(altitude-accuracy/2, altitude+accuracy/2)289self.set_rc(2, 1500)290self.progress("Reached target altitude at %u" %291self.mav.messages['VFR_HUD'].alt)292return self.wait_level_flight()293294def axial_left_roll(self, count=1):295"""Fly a left axial roll."""296# full throttle!297self.set_rc(3, 2000)298self.change_altitude(300, relative=True)299300# fly the roll in manual301self.change_mode('MANUAL')302303while count > 0:304self.progress("Starting roll")305self.set_rc(1, 1000)306try:307self.wait_roll(-150, accuracy=90)308self.wait_roll(150, accuracy=90)309self.wait_roll(0, accuracy=90)310except Exception as e:311self.set_rc(1, 1500)312raise e313count -= 1314315# back to FBWA316self.set_rc(1, 1500)317self.change_mode('FBWA')318self.set_rc(3, 1700)319return self.wait_level_flight()320321def inside_loop(self, count=1):322"""Fly a inside loop."""323# full throttle!324self.set_rc(3, 2000)325self.change_altitude(300, relative=True)326# fly the loop in manual327self.change_mode('MANUAL')328329while count > 0:330self.progress("Starting loop")331self.set_rc(2, 1000)332self.wait_pitch(-60, accuracy=20)333self.wait_pitch(0, accuracy=20)334count -= 1335336# back to FBWA337self.set_rc(2, 1500)338self.change_mode('FBWA')339self.set_rc(3, 1700)340return self.wait_level_flight()341342def set_attitude_target(self, tolerance=10):343"""Test setting of attitude target in guided mode."""344self.change_mode("GUIDED")345346steps = [{"name": "roll-over", "roll": 60, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000001},347{"name": "roll-back", "roll": 0, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000001},348{"name": "pitch-up+throttle", "roll": 0, "pitch": 20, "yaw": 0, "throttle": 1, "type_mask": 0b11000010},349{"name": "pitch-back", "roll": 0, "pitch": 0, "yaw": 0, "throttle": 0, "type_mask": 0b10000010}]350351state_wait = "wait"352state_hold = "hold"353try:354for step in steps:355step_start = self.get_sim_time_cached()356state = state_wait357state_start = self.get_sim_time_cached()358while True:359m = self.mav.recv_match(type='ATTITUDE',360blocking=True,361timeout=0.1)362now = self.get_sim_time_cached()363if now - step_start > 30:364raise AutoTestTimeoutException("Manuevers not completed")365if m is None:366continue367368angle_error = 0369if (step["type_mask"] & 0b00000001) or (step["type_mask"] == 0b10000000):370angle_error += abs(math.degrees(m.roll) - step["roll"])371372if (step["type_mask"] & 0b00000010) or (step["type_mask"] == 0b10000000):373angle_error += abs(math.degrees(m.pitch) - step["pitch"])374375if (step["type_mask"] & 0b00000100) or (step["type_mask"] == 0b10000000):376# Strictly we should angle wrap, by plane doesn't support yaw correctly anyway so its not tested here377angle_error += abs(math.degrees(m.yaw) - step["yaw"])378379# Note were not checking throttle, however the SITL plane needs full throttle to meet the380# target pitch attitude, Pitch test will fail without throttle override381382if state == state_wait:383# Reduced tolerance for initial trigger384if angle_error < (tolerance * 0.25):385state = state_hold386state_start = now387388# Allow 10 seconds to reach attitude389if (now - state_start) > 10:390raise NotAchievedException(step["name"] + ": Failed to get to set attitude")391392elif state == state_hold:393# Give 2 seconds to stabilize394if (now - state_start) > 2 and not (angle_error < tolerance):395raise NotAchievedException(step["name"] + ": Failed to hold set attitude")396397# Hold for 10 seconds398if (now - state_start) > 12:399# move onto next step400self.progress("%s Done" % (step["name"]))401break402403self.progress("%s %s error: %f" % (step["name"], state, angle_error))404405time_boot_millis = 0 # FIXME406target_system = 1 # FIXME407target_component = 1 # FIXME408type_mask = step["type_mask"] ^ 0xFF # FIXME409# attitude in radians:410q = quaternion.Quaternion([math.radians(step["roll"]),411math.radians(step["pitch"]),412math.radians(step["yaw"])])413self.mav.mav.set_attitude_target_send(time_boot_millis,414target_system,415target_component,416type_mask,417q,4180, # roll rate, not used in AP4190, # pitch rate, not used in AP4200, # yaw rate, not used in AP421step["throttle"])422except Exception as e:423self.change_mode('FBWA')424self.set_rc(3, 1700)425raise e426427# back to FBWA428self.change_mode('FBWA')429self.set_rc(3, 1700)430self.wait_level_flight()431432def test_stabilize(self, count=1):433"""Fly stabilize mode."""434# full throttle!435self.set_rc(3, 2000)436self.set_rc(2, 1300)437self.change_altitude(300, relative=True)438self.set_rc(2, 1500)439440self.change_mode('STABILIZE')441442while count > 0:443self.progress("Starting roll")444self.set_rc(1, 2000)445self.wait_roll(-150, accuracy=90)446self.wait_roll(150, accuracy=90)447self.wait_roll(0, accuracy=90)448count -= 1449450self.set_rc(1, 1500)451self.wait_roll(0, accuracy=5)452453# back to FBWA454self.change_mode('FBWA')455self.set_rc(3, 1700)456return self.wait_level_flight()457458def test_acro(self, count=1):459"""Fly ACRO mode."""460# full throttle!461self.set_rc(3, 2000)462self.set_rc(2, 1300)463self.change_altitude(300, relative=True)464self.set_rc(2, 1500)465466self.change_mode('ACRO')467468while count > 0:469self.progress("Starting roll")470self.set_rc(1, 1000)471self.wait_roll(-150, accuracy=90)472self.wait_roll(150, accuracy=90)473self.wait_roll(0, accuracy=90)474count -= 1475self.set_rc(1, 1500)476477# back to FBWA478self.change_mode('FBWA')479480self.wait_level_flight()481482self.change_mode('ACRO')483484count = 2485while count > 0:486self.progress("Starting loop")487self.set_rc(2, 1000)488self.wait_pitch(-60, accuracy=20)489self.wait_pitch(0, accuracy=20)490count -= 1491492self.set_rc(2, 1500)493494# back to FBWA495self.change_mode('FBWA')496self.set_rc(3, 1700)497return self.wait_level_flight()498499def test_FBWB(self, mode='FBWB'):500"""Fly FBWB or CRUISE mode."""501self.change_mode(mode)502self.set_rc(3, 1700)503self.set_rc(2, 1500)504505# lock in the altitude by asking for an altitude change then releasing506self.set_rc(2, 1000)507self.wait_distance(50, accuracy=20)508self.set_rc(2, 1500)509self.wait_distance(50, accuracy=20)510511m = self.mav.recv_match(type='VFR_HUD', blocking=True)512initial_alt = m.alt513self.progress("Initial altitude %u\n" % initial_alt)514515self.progress("Flying right circuit")516# do 4 turns517for i in range(0, 4):518# hard left519self.progress("Starting turn %u" % i)520self.set_rc(1, 1800)521try:522self.wait_heading(0 + (90*i), accuracy=20, timeout=60)523except Exception as e:524self.set_rc(1, 1500)525raise e526self.set_rc(1, 1500)527self.progress("Starting leg %u" % i)528self.wait_distance(100, accuracy=20)529self.progress("Circuit complete")530531self.progress("Flying rudder left circuit")532# do 4 turns533for i in range(0, 4):534# hard left535self.progress("Starting turn %u" % i)536self.set_rc(4, 1900)537try:538self.wait_heading(360 - (90*i), accuracy=20, timeout=60)539except Exception as e:540self.set_rc(4, 1500)541raise e542self.set_rc(4, 1500)543self.progress("Starting leg %u" % i)544self.wait_distance(100, accuracy=20)545self.progress("Circuit complete")546547m = self.mav.recv_match(type='VFR_HUD', blocking=True)548final_alt = m.alt549self.progress("Final altitude %u initial %u\n" %550(final_alt, initial_alt))551552# back to FBWA553self.change_mode('FBWA')554555if abs(final_alt - initial_alt) > 20:556raise NotAchievedException("Failed to maintain altitude")557558return self.wait_level_flight()559560def fly_mission(self, filename, mission_timeout=60.0, strict=True, quadplane=False):561"""Fly a mission from a file."""562self.progress("Flying mission %s" % filename)563num_wp = self.load_mission(filename, strict=strict)-1564self.fly_mission_waypoints(num_wp, mission_timeout=mission_timeout, quadplane=quadplane)565566def fly_mission_waypoints(self, num_wp, mission_timeout=60.0, quadplane=False):567self.set_current_waypoint(0, check_afterwards=False)568self.context_push()569self.context_collect('STATUSTEXT')570self.change_mode('AUTO')571self.wait_waypoint(1, num_wp, max_dist=60, timeout=mission_timeout)572self.wait_groundspeed(0, 0.5, timeout=mission_timeout)573if quadplane:574self.wait_statustext("Throttle disarmed", timeout=200, check_context=True)575else:576self.wait_statustext("Auto disarmed", timeout=60, check_context=True)577self.context_pop()578self.progress("Mission OK")579580def DO_REPOSITION(self):581'''Test mavlink DO_REPOSITION command'''582self.progress("Takeoff")583self.takeoff(alt=50)584self.set_rc(3, 1500)585self.progress("Entering guided and flying somewhere constant")586self.change_mode("GUIDED")587loc = self.mav.location()588self.location_offset_ne(loc, 500, 500)589590new_alt = 100591self.run_cmd_int(592mavutil.mavlink.MAV_CMD_DO_REPOSITION,593p5=int(loc.lat * 1e7),594p6=int(loc.lng * 1e7),595p7=new_alt, # alt596frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,597)598self.wait_altitude(new_alt-10, new_alt, timeout=30, relative=True)599600self.install_terrain_handlers_context()601602self.location_offset_ne(loc, 500, 500)603terrain_height_wanted = 150604self.run_cmd_int(605mavutil.mavlink.MAV_CMD_DO_REPOSITION,6060,6070,6080,6090,610int(loc.lat*1e7),611int(loc.lng*1e7),612terrain_height_wanted, # alt613frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,614)615616# move to specific terrain-relative altitude and hold for <n> seconds617tstart = self.get_sim_time_cached()618achieve_start = None619tr = None620while True:621if self.get_sim_time_cached() - tstart > 120:622raise NotAchievedException("Did not move to correct terrain alt")623624m = self.mav.recv_match(type='TERRAIN_REPORT',625blocking=True,626timeout=1)627tr = m628terrain_height_achieved = m.current_height629self.progress("terrain_alt=%f want=%f" %630(terrain_height_achieved, terrain_height_wanted))631if m is None:632continue633if abs(terrain_height_wanted - terrain_height_achieved) > 5:634if achieve_start is not None:635self.progress("Achieve stop")636achieve_start = None637elif achieve_start is None:638self.progress("Achieve start")639achieve_start = self.get_sim_time_cached()640if achieve_start is not None:641if self.get_sim_time_cached() - achieve_start > 10:642break643m = self.mav.recv_match(type='GLOBAL_POSITION_INT',644blocking=True,645timeout=1)646self.progress("TR: %s" % tr)647self.progress("GPI: %s" % m)648min_delta = 4649delta = abs(m.relative_alt/1000.0 - tr.current_height)650if abs(delta < min_delta):651raise NotAchievedException("Expected altitude delta (want=%f got=%f)" %652(min_delta, delta))653654self.fly_home_land_and_disarm(timeout=180)655656def ExternalPositionEstimate(self):657'''Test mavlink EXTERNAL_POSITION_ESTIMATE command'''658if not hasattr(mavutil.mavlink, 'MAV_CMD_EXTERNAL_POSITION_ESTIMATE'):659raise OldpymavlinkException("pymavlink too old; upgrade pymavlink to get MAV_CMD_EXTERNAL_POSITION_ESTIMATE") # noqa660self.change_mode("TAKEOFF")661self.wait_ready_to_arm()662self.arm_vehicle()663self.wait_altitude(48, 52, relative=True)664665loc = self.mav.location()666self.location_offset_ne(loc, 2000, 2000)667668# setting external position fail while we have GPS lock669self.progress("set new position with GPS")670self.run_cmd_int(671mavutil.mavlink.MAV_CMD_EXTERNAL_POSITION_ESTIMATE,672p1=self.get_sim_time()-1, # transmit time673p2=0.5, # processing delay674p3=50, # accuracy675p5=int(loc.lat * 1e7),676p6=int(loc.lng * 1e7),677p7=float("NaN"), # alt678frame=mavutil.mavlink.MAV_FRAME_GLOBAL,679want_result=mavutil.mavlink.MAV_RESULT_FAILED,680)681682self.progress("disable the GPS")683self.run_auxfunc(68465,6852,686want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED687)688689# fly for a bit to get into non-aiding state690self.progress("waiting 20 seconds")691tstart = self.get_sim_time()692while self.get_sim_time() < tstart + 20:693self.wait_heartbeat()694695self.progress("getting base position")696gpi = self.mav.recv_match(697type='GLOBAL_POSITION_INT',698blocking=True,699timeout=5700)701loc = mavutil.location(gpi.lat*1e-7, gpi.lon*1e-7, 0, 0)702703self.progress("set new position with no GPS")704self.run_cmd_int(705mavutil.mavlink.MAV_CMD_EXTERNAL_POSITION_ESTIMATE,706p1=self.get_sim_time()-1, # transmit time707p2=0.5, # processing delay708p3=50, # accuracy709p5=gpi.lat+1,710p6=gpi.lon+1,711p7=float("NaN"), # alt712frame=mavutil.mavlink.MAV_FRAME_GLOBAL,713want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED714)715716self.progress("waiting 3 seconds")717tstart = self.get_sim_time()718while self.get_sim_time() < tstart + 3:719self.wait_heartbeat()720721gpi2 = self.mav.recv_match(722type='GLOBAL_POSITION_INT',723blocking=True,724timeout=5725)726loc2 = mavutil.location(gpi2.lat*1e-7, gpi2.lon*1e-7, 0, 0)727dist = self.get_distance(loc, loc2)728729self.progress("dist is %.1f" % dist)730if dist > 200:731raise NotAchievedException("Position error dist=%.1f" % dist)732733self.progress("re-enable the GPS")734self.run_auxfunc(73565,7360,737want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED738)739740self.progress("flying home")741self.fly_home_land_and_disarm()742743def DeepStall(self):744'''Test DeepStall Landing'''745# self.fly_deepstall_absolute()746self.fly_deepstall_relative()747748def fly_deepstall_absolute(self):749self.start_subtest("DeepStall Relative Absolute")750deepstall_elevator_pwm = 1661751self.set_parameters({752"LAND_TYPE": 1,753"LAND_DS_ELEV_PWM": deepstall_elevator_pwm,754"RTL_AUTOLAND": 1,755})756self.load_mission("plane-deepstall-mission.txt")757self.change_mode("AUTO")758self.wait_ready_to_arm()759self.arm_vehicle()760self.progress("Waiting for deepstall messages")761762# note that the following two don't necessarily happen in this763# order, but at very high speedups we may miss the elevator764# PWM if we first look for the text (due to the get_sim_time()765# in wait_servo_channel_value)766767self.context_collect('STATUSTEXT')768769# assume elevator is on channel 2:770self.wait_servo_channel_value(2, deepstall_elevator_pwm, timeout=240)771772self.wait_text("Deepstall: Entry: ", check_context=True)773774self.disarm_wait(timeout=120)775776self.progress("Flying home")777self.set_current_waypoint(0, check_afterwards=False)778self.takeoff(10)779self.set_parameter("LAND_TYPE", 0)780self.fly_home_land_and_disarm()781782def fly_deepstall_relative(self):783self.start_subtest("DeepStall Relative")784deepstall_elevator_pwm = 1661785self.set_parameters({786"LAND_TYPE": 1,787"LAND_DS_ELEV_PWM": deepstall_elevator_pwm,788"RTL_AUTOLAND": 1,789})790self.load_mission("plane-deepstall-relative-mission.txt")791self.change_mode("AUTO")792self.wait_ready_to_arm()793self.arm_vehicle()794self.wait_current_waypoint(4)795796# assume elevator is on channel 2:797self.wait_servo_channel_value(2, deepstall_elevator_pwm, timeout=240)798799self.progress("Waiting for stage DEEPSTALL_STAGE_LAND")800self.assert_receive_message(801'DEEPSTALL',802condition='DEEPSTALL.stage==6',803timeout=240,804)805self.progress("Reached stage DEEPSTALL_STAGE_LAND")806807self.disarm_wait(timeout=120)808self.set_current_waypoint(0, check_afterwards=False)809810self.progress("Flying home")811self.set_current_waypoint(0, check_afterwards=False)812self.takeoff(100)813self.set_parameter("LAND_TYPE", 0)814self.fly_home_land_and_disarm(timeout=240)815816def SmartBattery(self):817'''Test smart battery logging etc'''818self.set_parameters({819"BATT_MONITOR": 16, # Maxell battery monitor820})821822# Must reboot sitl after setting montior type for SMBus parameters to be set due to dynamic group823self.reboot_sitl()824self.set_parameters({825"BATT_I2C_BUS": 2, # specified in SIM_I2C.cpp826"BATT_I2C_ADDR": 11, # specified in SIM_I2C.cpp827})828self.reboot_sitl()829830self.wait_ready_to_arm()831m = self.assert_receive_message('BATTERY_STATUS', timeout=10)832if m.voltages_ext[0] == 65536:833raise NotAchievedException("Flag value rather than voltage")834if abs(m.voltages_ext[0] - 1000) > 300:835raise NotAchievedException("Did not get good ext voltage (got=%f)" %836(m.voltages_ext[0],))837self.arm_vehicle()838self.delay_sim_time(5)839self.disarm_vehicle()840if not self.current_onboard_log_contains_message("BCL2"):841raise NotAchievedException("Expected BCL2 message")842843def context_push_do_change_speed(self):844# the following lines ensure we revert these parameter values845# - DO_CHANGE_AIRSPEED is a permanent vehicle change!846self.context_push()847self.set_parameters({848"AIRSPEED_CRUISE": self.get_parameter("AIRSPEED_CRUISE"),849"MIN_GROUNDSPEED": self.get_parameter("MIN_GROUNDSPEED"),850"TRIM_THROTTLE": self.get_parameter("TRIM_THROTTLE"),851})852853def DO_CHANGE_SPEED(self):854'''Test DO_CHANGE_SPEED command/item'''855self.set_parameters({856"RTL_AUTOLAND": 1,857})858859self.context_push_do_change_speed()860self.DO_CHANGE_SPEED_mavlink_long()861self.context_pop()862863self.set_current_waypoint(1)864self.zero_throttle()865866self.context_push_do_change_speed()867self.DO_CHANGE_SPEED_mavlink_int()868self.context_pop()869870self.context_push_do_change_speed()871self.DO_CHANGE_SPEED_mission()872self.context_pop()873874def DO_CHANGE_SPEED_mission(self):875'''test DO_CHANGE_SPEED as a mission item'''876self.start_subtest("DO_CHANGE_SPEED_mission")877self.load_mission("mission.txt")878self.set_current_waypoint(1)879880self.progress("Takeoff")881self.set_rc(3, 1000)882self.takeoff(alt=10)883self.set_rc(3, 1500)884885self.start_subtest("Check initial speed")886887self.change_mode('AUTO')888889checks = [890(1, self.get_parameter("AIRSPEED_CRUISE")),891(3, 10),892(5, 20),893(7, 15),894]895896for (current_waypoint, want_airspeed) in checks:897self.wait_current_waypoint(current_waypoint, timeout=150)898self.wait_airspeed(want_airspeed-1, want_airspeed+1, minimum_duration=5, timeout=120)899900self.fly_home_land_and_disarm()901902def DO_CHANGE_SPEED_mavlink_int(self):903self.DO_CHANGE_SPEED_mavlink(self.run_cmd_int)904905def DO_CHANGE_SPEED_mavlink_long(self):906self.DO_CHANGE_SPEED_mavlink(self.run_cmd)907908def DO_CHANGE_SPEED_mavlink(self, run_cmd_method):909'''test DO_CHANGE_SPEED as a mavlink command'''910self.progress("Takeoff")911self.takeoff(alt=100, mode="TAKEOFF", timeout=120)912self.set_rc(3, 1500)913# ensure we know what the airspeed is:914self.progress("Entering guided and flying somewhere constant")915self.change_mode("GUIDED")916self.run_cmd_int(917mavutil.mavlink.MAV_CMD_DO_REPOSITION,918p5=12345, # lat* 1e7919p6=12345, # lon* 1e7920p7=100, # alt921frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,922)923self.delay_sim_time(10)924self.progress("Ensuring initial speed is known and relatively constant")925initial_speed = 22.0926timeout = 15927self.wait_airspeed(initial_speed-1, initial_speed+1, minimum_duration=5, timeout=timeout)928929self.start_subtest("Setting groundspeed")930for new_target_groundspeed in initial_speed + 5, initial_speed + 2:931run_cmd_method(932mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,933p1=1, # groundspeed934p2=new_target_groundspeed,935p3=-1, # throttle / no change936p4=0, # absolute values937)938self.wait_groundspeed(new_target_groundspeed-2, new_target_groundspeed+2, timeout=80, minimum_duration=5)939self.progress("Adding some wind, ensuring groundspeed holds")940self.set_parameter("SIM_WIND_SPD", 5)941self.delay_sim_time(5)942self.wait_groundspeed(new_target_groundspeed-2, new_target_groundspeed+2, timeout=40, minimum_duration=5)943self.set_parameter("SIM_WIND_SPD", 0)944945# clear target groundspeed946run_cmd_method(947mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,948p1=1, # groundspeed949p2=0,950p3=-1, # throttle / no change951p4=0, # absolute values952)953954self.start_subtest("Setting airspeed")955for new_target_airspeed in initial_speed - 5, initial_speed + 5:956run_cmd_method(957mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,958p1=0, # airspeed959p2=new_target_airspeed,960p3=-1, # throttle / no change961p4=0, # absolute values962)963self.wait_airspeed(new_target_airspeed-2, new_target_airspeed+2, minimum_duration=5)964965self.context_push()966self.progress("Adding some wind, hoping groundspeed increases/decreases")967self.set_parameters({968"SIM_WIND_SPD": 7,969"SIM_WIND_DIR": 270,970})971self.delay_sim_time(5)972timeout = 10973tstart = self.get_sim_time()974while True:975if self.get_sim_time_cached() - tstart > timeout:976raise NotAchievedException("Did not achieve groundspeed delta")977m = self.mav.recv_match(type='VFR_HUD', blocking=True)978delta = abs(m.airspeed - m.groundspeed)979want_delta = 5980self.progress("groundspeed and airspeed should be different (have=%f want=%f)" % (delta, want_delta))981if delta > want_delta:982break983self.context_pop()984985# cancel minimum groundspeed:986run_cmd_method(987mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,988p1=0, # groundspeed989p2=-2, # return to default990p3=0, # throttle / no change991p4=0, # absolute values992)993# cancel airspeed:994run_cmd_method(995mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,996p1=1, # airspeed997p2=-2, # return to default998p3=0, # throttle / no change999p4=0, # absolute values1000)10011002self.start_subtest("Setting throttle")1003self.set_parameter('ARSPD_USE', 0) # setting throttle only effective without airspeed1004for (set_throttle, expected_throttle) in (97, 79), (60, 51), (95, 77):1005run_cmd_method(1006mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,1007p1=3, # throttle1008p2=0,1009p3=set_throttle, # throttle / no change1010p4=0, # absolute values1011)1012self.wait_message_field_values('VFR_HUD', {1013"throttle": expected_throttle,1014}, minimum_duration=5, epsilon=2)10151016self.fly_home_land_and_disarm(timeout=240)10171018def fly_home_land_and_disarm(self, timeout=120):1019filename = "flaps.txt"1020self.progress("Using %s to fly home" % filename)1021self.load_generic_mission(filename)1022self.change_mode("AUTO")1023# don't set current waypoint to 8 unless we're distant from it1024# or we arrive instantly and never see it as our current1025# waypoint:1026self.wait_distance_to_waypoint(8, 100, 10000000)1027self.set_current_waypoint(8)1028# TODO: reflect on file to find this magic waypoint number?1029# self.wait_waypoint(7, num_wp-1, timeout=500) # we1030# tend to miss the final waypoint by a fair bit, and1031# this is probably too noisy anyway?1032self.wait_disarmed(timeout=timeout)10331034def TestFlaps(self):1035"""Test flaps functionality."""1036filename = "flaps.txt"1037flaps_ch = 51038flaps_ch_min = 10001039flaps_ch_trim = 15001040flaps_ch_max = 200010411042servo_ch = 51043servo_ch_min = 12001044servo_ch_trim = 13001045servo_ch_max = 180010461047self.set_parameters({1048"SERVO%u_FUNCTION" % servo_ch: 3, # flapsauto1049"RC%u_OPTION" % flaps_ch: 208, # Flaps RCx_OPTION1050"LAND_FLAP_PERCNT": 50,1051"LOG_DISARMED": 1,1052"RTL_AUTOLAND": 1,10531054"RC%u_MIN" % flaps_ch: flaps_ch_min,1055"RC%u_MAX" % flaps_ch: flaps_ch_max,1056"RC%u_TRIM" % flaps_ch: flaps_ch_trim,10571058"SERVO%u_MIN" % servo_ch: servo_ch_min,1059"SERVO%u_MAX" % servo_ch: servo_ch_max,1060"SERVO%u_TRIM" % servo_ch: servo_ch_trim,1061})10621063self.progress("check flaps are not deployed")1064self.set_rc(flaps_ch, flaps_ch_min)1065self.wait_servo_channel_value(servo_ch, servo_ch_min, timeout=3)1066self.progress("deploy the flaps")1067self.set_rc(flaps_ch, flaps_ch_max)1068tstart = self.get_sim_time()1069self.wait_servo_channel_value(servo_ch, servo_ch_max)1070tstop = self.get_sim_time_cached()1071delta_time = tstop - tstart1072delta_time_min = 0.51073delta_time_max = 1.51074if delta_time < delta_time_min or delta_time > delta_time_max:1075raise NotAchievedException((1076"Flaps Slew not working (%f seconds)" % (delta_time,)))1077self.progress("undeploy flaps")1078self.set_rc(flaps_ch, flaps_ch_min)1079self.wait_servo_channel_value(servo_ch, servo_ch_min)10801081self.progress("Flying mission %s" % filename)1082self.load_mission(filename)1083self.change_mode('AUTO')1084self.wait_ready_to_arm()1085self.arm_vehicle()1086# flaps should deploy for landing (RC input value used for position?!)1087self.wait_servo_channel_value(servo_ch, flaps_ch_trim, timeout=300)1088# flaps should undeploy at the end1089self.wait_servo_channel_value(servo_ch, servo_ch_min, timeout=30)10901091self.progress("Flaps OK")10921093def TestRCRelay(self):1094'''Test Relay RC Channel Option'''1095self.set_parameters({1096"RELAY1_FUNCTION": 1, # Enable relay as a standard relay pin1097"RC12_OPTION": 28 # Relay On/Off1098})1099self.set_rc(12, 1000)1100self.reboot_sitl() # needed for RC12_OPTION and RELAY1_FUNCTION to take effect11011102off = self.get_parameter("SIM_PIN_MASK")1103if off:1104raise PreconditionFailedException("SIM_MASK_PIN off")11051106# allow time for the RC library to register initial value:1107self.delay_sim_time(1)11081109self.set_rc(12, 2000)1110self.wait_heartbeat()1111self.wait_heartbeat()11121113on = self.get_parameter("SIM_PIN_MASK")1114if not on:1115raise NotAchievedException("SIM_PIN_MASK doesn't reflect ON")1116self.set_rc(12, 1000)1117self.wait_heartbeat()1118self.wait_heartbeat()1119off = self.get_parameter("SIM_PIN_MASK")1120if off:1121raise NotAchievedException("SIM_PIN_MASK doesn't reflect OFF")11221123def TestRCCamera(self):1124'''Test RC Option - Camera Trigger'''1125self.set_parameter("RC12_OPTION", 9) # CameraTrigger1126self.set_parameter("CAM1_TYPE", 1) # Camera with servo trigger1127self.reboot_sitl() # needed for RC12_OPTION to take effect11281129x = self.mav.messages.get("CAMERA_FEEDBACK", None)1130if x is not None:1131raise PreconditionFailedException("Receiving CAMERA_FEEDBACK?!")1132self.set_rc(12, 2000)1133tstart = self.get_sim_time()1134while self.get_sim_time_cached() - tstart < 10:1135x = self.mav.messages.get("CAMERA_FEEDBACK", None)1136if x is not None:1137break1138self.wait_heartbeat()1139self.set_rc(12, 1000)1140if x is None:1141raise NotAchievedException("No CAMERA_FEEDBACK message received")11421143self.wait_ready_to_arm()11441145original_alt = self.get_altitude()11461147takeoff_alt = 301148self.takeoff(takeoff_alt)1149self.set_rc(12, 2000)1150self.delay_sim_time(1)1151self.set_rc(12, 1000)1152x = self.mav.messages.get("CAMERA_FEEDBACK", None)1153if abs(x.alt_rel - takeoff_alt) > 10:1154raise NotAchievedException("Bad relalt (want=%f vs got=%f)" % (takeoff_alt, x.alt_rel))1155if abs(x.alt_msl - (original_alt+30)) > 10:1156raise NotAchievedException("Bad absalt (want=%f vs got=%f)" % (original_alt+30, x.alt_msl))1157self.fly_home_land_and_disarm()11581159def ThrottleFailsafe(self):1160'''Fly throttle failsafe'''1161self.change_mode('MANUAL')1162m = self.mav.recv_match(type='SYS_STATUS', blocking=True)1163receiver_bit = mavutil.mavlink.MAV_SYS_STATUS_SENSOR_RC_RECEIVER1164self.progress("Testing receiver enabled")1165if (not (m.onboard_control_sensors_enabled & receiver_bit)):1166raise PreconditionFailedException()1167self.progress("Testing receiver present")1168if (not (m.onboard_control_sensors_present & receiver_bit)):1169raise PreconditionFailedException()1170self.progress("Testing receiver health")1171if (not (m.onboard_control_sensors_health & receiver_bit)):1172raise PreconditionFailedException()11731174self.progress("Ensure we know original throttle value")1175self.wait_rc_channel_value(3, 1000)11761177self.set_parameter("THR_FS_VALUE", 960)1178self.progress("Failing receiver (throttle-to-950)")1179self.context_collect("HEARTBEAT")1180self.set_parameter("SIM_RC_FAIL", 2) # throttle-to-9501181self.wait_mode('RTL') # long failsafe1182if (self.get_mode_from_mode_mapping("CIRCLE") not in1183[x.custom_mode for x in self.context_stop_collecting("HEARTBEAT")]):1184raise NotAchievedException("Did not go via circle mode")1185self.progress("Ensure we've had our throttle squashed to 950")1186self.wait_rc_channel_value(3, 950)1187self.do_timesync_roundtrip()1188m = self.assert_receive_message('SYS_STATUS')1189self.progress("Got (%s)" % str(m))1190self.progress("Testing receiver enabled")1191if (not (m.onboard_control_sensors_enabled & receiver_bit)):1192raise NotAchievedException("Receiver not enabled")1193self.progress("Testing receiver present")1194if (not (m.onboard_control_sensors_present & receiver_bit)):1195raise NotAchievedException("Receiver not present")1196# skip this until RC is fixed1197# self.progress("Testing receiver health")1198# if (m.onboard_control_sensors_health & receiver_bit):1199# raise NotAchievedException("Sensor healthy when it shouldn't be")1200self.set_parameter("SIM_RC_FAIL", 0)1201# have to allow time for RC to be fetched from SITL1202self.delay_sim_time(0.5)1203self.do_timesync_roundtrip()1204m = self.assert_receive_message('SYS_STATUS')1205self.progress("Testing receiver enabled")1206if (not (m.onboard_control_sensors_enabled & receiver_bit)):1207raise NotAchievedException("Receiver not enabled")1208self.progress("Testing receiver present")1209if (not (m.onboard_control_sensors_present & receiver_bit)):1210raise NotAchievedException("Receiver not present")1211self.progress("Testing receiver health")1212if (not (m.onboard_control_sensors_health & receiver_bit)):1213raise NotAchievedException("Receiver not healthy2")1214self.change_mode('MANUAL')12151216self.progress("Failing receiver (no-pulses)")1217self.context_collect("HEARTBEAT")1218self.set_parameter("SIM_RC_FAIL", 1) # no-pulses1219self.wait_mode('RTL') # long failsafe1220if (self.get_mode_from_mode_mapping("CIRCLE") not in1221[x.custom_mode for x in self.context_stop_collecting("HEARTBEAT")]):1222raise NotAchievedException("Did not go via circle mode")1223self.do_timesync_roundtrip()1224m = self.assert_receive_message('SYS_STATUS')1225self.progress("Got (%s)" % str(m))1226self.progress("Testing receiver enabled")1227if (not (m.onboard_control_sensors_enabled & receiver_bit)):1228raise NotAchievedException("Receiver not enabled")1229self.progress("Testing receiver present")1230if (not (m.onboard_control_sensors_present & receiver_bit)):1231raise NotAchievedException("Receiver not present")1232self.progress("Testing receiver health")1233if (m.onboard_control_sensors_health & receiver_bit):1234raise NotAchievedException("Sensor healthy when it shouldn't be")1235self.progress("Making RC work again")1236self.set_parameter("SIM_RC_FAIL", 0)1237# have to allow time for RC to be fetched from SITL1238self.progress("Giving receiver time to recover")1239self.delay_sim_time(0.5)1240self.do_timesync_roundtrip()1241m = self.assert_receive_message('SYS_STATUS')1242self.progress("Testing receiver enabled")1243if (not (m.onboard_control_sensors_enabled & receiver_bit)):1244raise NotAchievedException("Receiver not enabled")1245self.progress("Testing receiver present")1246if (not (m.onboard_control_sensors_present & receiver_bit)):1247raise NotAchievedException("Receiver not present")1248self.progress("Testing receiver health")1249if (not (m.onboard_control_sensors_health & receiver_bit)):1250raise NotAchievedException("Receiver not healthy")1251self.change_mode('MANUAL')12521253self.progress("Ensure long failsafe can trigger when short failsafe disabled")1254self.context_push()1255self.context_collect("STATUSTEXT")1256self.set_parameters({1257"FS_SHORT_ACTN": 3, # 3 means disabled1258"SIM_RC_FAIL": 1,1259})1260self.wait_statustext("Long failsafe on", check_context=True)1261self.wait_mode("RTL")1262# self.context_clear_collection("STATUSTEXT")1263self.set_parameter("SIM_RC_FAIL", 0)1264self.wait_text("Long Failsafe Cleared", check_context=True)1265self.change_mode("MANUAL")12661267self.progress("Trying again with THR_FS_VALUE")1268self.set_parameters({1269"THR_FS_VALUE": 960,1270"SIM_RC_FAIL": 2,1271})1272self.wait_statustext("Long Failsafe on", check_context=True)1273self.wait_mode("RTL")1274self.context_pop()12751276self.start_subtest("Not use RC throttle input when THR_FAILSAFE==2")1277self.takeoff(100)1278self.set_rc(3, 1800)1279self.set_rc(1, 2000)1280self.wait_attitude(desroll=45, timeout=1)1281self.context_push()1282self.set_parameters({1283"THR_FAILSAFE": 2,1284"SIM_RC_FAIL": 1, # no pulses1285})1286self.delay_sim_time(1)1287self.wait_attitude(desroll=0, timeout=5)1288self.assert_servo_channel_value(3, self.get_parameter("RC3_MIN"))1289self.set_parameters({1290"SIM_RC_FAIL": 0, # fix receiver1291})1292self.zero_throttle()1293self.disarm_vehicle(force=True)1294self.context_pop()1295self.reboot_sitl()12961297def ThrottleFailsafeFence(self):1298'''Fly fence survives throttle failsafe'''1299fence_bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE13001301self.progress("Checking fence is not present before being configured")1302m = self.mav.recv_match(type='SYS_STATUS', blocking=True)1303self.progress("Got (%s)" % str(m))1304if (m.onboard_control_sensors_enabled & fence_bit):1305raise NotAchievedException("Fence enabled before being configured")13061307self.change_mode('MANUAL')1308self.wait_ready_to_arm()13091310self.load_fence("CMAC-fence.txt")13111312self.set_parameter("RC7_OPTION", 11) # AC_Fence uses Aux switch functionality1313self.set_parameter("FENCE_ACTION", 4) # Fence action Brake1314self.set_rc_from_map({13153: 1000,13167: 2000,1317}) # Turn fence on with aux function13181319m = self.mav.recv_match(type='FENCE_STATUS', blocking=True, timeout=2)1320self.progress("Got (%s)" % str(m))1321if m is None:1322raise NotAchievedException("Got FENCE_STATUS unexpectedly")13231324self.progress("Checking fence is initially OK")1325self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE,1326present=True,1327enabled=True,1328healthy=True,1329verbose=True,1330timeout=30)13311332self.set_parameter("THR_FS_VALUE", 960)1333self.progress("Failing receiver (throttle-to-950)")1334self.set_parameter("SIM_RC_FAIL", 2) # throttle-to-9501335self.wait_mode("CIRCLE")1336self.delay_sim_time(1) # give1337self.do_timesync_roundtrip()13381339self.progress("Checking fence is OK after receiver failure (bind-values)")1340fence_bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE1341m = self.assert_receive_message('SYS_STATUS')1342if (not (m.onboard_control_sensors_enabled & fence_bit)):1343raise NotAchievedException("Fence not enabled after RC fail")1344self.do_fence_disable() # Ensure the fence is disabled after test13451346def GCSFailsafe(self):1347'''Ensure Long-Failsafe works on GCS loss'''1348self.start_subtest("Test Failsafe: RTL")1349self.load_sample_mission()1350self.set_parameters({1351"FS_GCS_ENABL": 1,1352"FS_LONG_ACTN": 1,1353"RTL_AUTOLAND": 1,1354"SYSID_MYGCS": self.mav.source_system,1355})1356self.takeoff()1357self.change_mode('LOITER')1358self.progress("Disconnecting GCS")1359self.set_heartbeat_rate(0)1360self.wait_mode("RTL", timeout=10)1361self.set_heartbeat_rate(self.speedup)1362self.end_subtest("Completed RTL Failsafe test")13631364self.start_subtest("Test Failsafe: FBWA Glide")1365self.set_parameters({1366"FS_LONG_ACTN": 2,1367})1368self.change_mode('AUTO')1369self.progress("Disconnecting GCS")1370self.set_heartbeat_rate(0)1371self.wait_mode("FBWA", timeout=10)1372self.set_heartbeat_rate(self.speedup)1373self.end_subtest("Completed FBWA Failsafe test")13741375self.start_subtest("Test Failsafe: Deploy Parachute")1376self.load_mission("plane-parachute-mission.txt")1377self.set_current_waypoint(1)1378self.set_parameters({1379"CHUTE_ENABLED": 1,1380"CHUTE_TYPE": 10,1381"SERVO9_FUNCTION": 27,1382"SIM_PARA_ENABLE": 1,1383"SIM_PARA_PIN": 9,1384"FS_LONG_ACTN": 3,1385})1386self.change_mode("AUTO")1387self.progress("Disconnecting GCS")1388self.set_heartbeat_rate(0)1389self.wait_statustext("BANG", timeout=60)1390self.set_heartbeat_rate(self.speedup)1391self.disarm_vehicle(force=True)1392self.reboot_sitl()1393self.end_subtest("Completed Parachute Failsafe test")13941395def TestGripperMission(self):1396'''Test Gripper mission items'''1397self.set_parameter("RTL_AUTOLAND", 1)1398self.load_mission("plane-gripper-mission.txt")1399self.set_current_waypoint(1)1400self.change_mode('AUTO')1401self.wait_ready_to_arm()1402self.arm_vehicle()1403self.wait_statustext("Gripper Grabbed", timeout=60)1404self.wait_statustext("Gripper Released", timeout=60)1405self.wait_statustext("Auto disarmed", timeout=60)14061407def assert_fence_sys_status(self, present, enabled, health):1408self.delay_sim_time(1)1409self.do_timesync_roundtrip()1410m = self.assert_receive_message('SYS_STATUS', timeout=1)1411tests = [1412("present", present, m.onboard_control_sensors_present),1413("enabled", enabled, m.onboard_control_sensors_enabled),1414("health", health, m.onboard_control_sensors_health),1415]1416bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE1417for test in tests:1418(name, want, field) = test1419got = (field & bit) != 01420if want != got:1421raise NotAchievedException("fence status incorrect; %s want=%u got=%u" %1422(name, want, got))14231424def wait_circling_point_with_radius(self, loc, want_radius, epsilon=5.0, min_circle_time=5, timeout=120):1425on_radius_start_heading = None1426average_radius = 0.01427circle_time_start = 01428done_time = False1429done_angle = False1430tstart = self.get_sim_time()1431while True:1432if self.get_sim_time() - tstart > timeout:1433raise AutoTestTimeoutException("Did not get onto circle")1434here = self.mav.location()1435got_radius = self.get_distance(loc, here)1436average_radius = 0.95*average_radius + 0.05*got_radius1437on_radius = abs(got_radius - want_radius) < epsilon1438m = self.mav.recv_match(type='VFR_HUD', blocking=True)1439heading = m.heading1440on_string = "off"1441got_angle = ""1442if on_radius_start_heading is not None:1443got_angle = "%0.2f" % abs(on_radius_start_heading - heading) # FIXME1444on_string = "on"14451446want_angle = 180 # we don't actually get this (angle-substraction issue. But we get enough...1447self.progress("wait-circling: got-r=%0.2f want-r=%f avg-r=%f %s want-a=%0.1f got-a=%s" %1448(got_radius, want_radius, average_radius, on_string, want_angle, got_angle))1449if on_radius:1450if on_radius_start_heading is None:1451on_radius_start_heading = heading1452average_radius = got_radius1453circle_time_start = self.get_sim_time()1454continue1455if abs(on_radius_start_heading - heading) > want_angle: # FIXME1456done_angle = True1457if self.get_sim_time() - circle_time_start > min_circle_time:1458done_time = True1459if done_time and done_angle:1460return1461continue1462if on_radius_start_heading is not None:1463average_radius = 0.01464on_radius_start_heading = None1465circle_time_start = 014661467def MODE_SWITCH_RESET(self):1468'''test the MODE_SWITCH_RESET auxiliary function'''1469self.set_parameters({1470"RC9_OPTION": 96,1471})14721473self.progress("Using RC to change modes")1474self.set_rc(8, 1500)1475self.wait_mode('FBWA')14761477self.progress("Killing RC to engage RC failsafe")1478self.set_parameter('SIM_RC_FAIL', 1)1479self.wait_mode('RTL')14801481self.progress("Reinstating RC")1482self.set_parameter('SIM_RC_FAIL', 0)14831484self.progress("Ensuring we don't automatically revert mode")1485self.delay_sim_time(2)1486self.assert_mode_is('RTL')14871488self.progress("Ensuring MODE_SWITCH_RESET switch resets to pre-failsafe mode")1489self.set_rc(9, 2000)1490self.wait_mode('FBWA')14911492def FenceStatic(self):1493'''Test Basic Fence Functionality'''1494self.progress("Checking for bizarre healthy-when-not-present-or-enabled")1495self.set_parameter("FENCE_TYPE", 4) # Start by only setting polygon fences, otherwise fence will report present1496self.assert_fence_sys_status(False, False, True)1497self.load_fence("CMAC-fence.txt")1498m = self.mav.recv_match(type='FENCE_STATUS', blocking=True, timeout=2)1499if m is not None:1500raise NotAchievedException("Got FENCE_STATUS unexpectedly")1501self.set_parameter("FENCE_ACTION", 0) # report only1502self.assert_fence_sys_status(True, False, True)1503self.set_parameter("FENCE_ACTION", 1) # RTL1504self.assert_fence_sys_status(True, False, True)1505self.do_fence_enable()1506self.assert_fence_sys_status(True, True, True)1507m = self.assert_receive_message('FENCE_STATUS', timeout=2)1508if m.breach_status:1509raise NotAchievedException("Breached fence unexpectedly (%u)" %1510(m.breach_status))1511self.do_fence_disable()1512self.assert_fence_sys_status(True, False, True)1513self.set_parameter("FENCE_ACTION", 1)1514self.assert_fence_sys_status(True, False, True)1515self.set_parameter("FENCE_ACTION", 0)1516self.assert_fence_sys_status(True, False, True)1517self.clear_fence()1518if self.get_parameter("FENCE_TOTAL") != 0:1519raise NotAchievedException("Expected zero points remaining")1520self.assert_fence_sys_status(False, False, True)1521self.progress("Trying to enable fence with no points")1522self.do_fence_enable(want_result=mavutil.mavlink.MAV_RESULT_FAILED)15231524# test a rather unfortunate behaviour:1525self.progress("Killing a live fence with fence-clear")1526self.load_fence("CMAC-fence.txt")1527self.set_parameter("FENCE_ACTION", 1) # AC_FENCE_ACTION_RTL_AND_LAND == 1. mavutil.mavlink.FENCE_ACTION_RTL == 41528self.do_fence_enable()1529self.assert_fence_sys_status(True, True, True)1530self.clear_fence()1531self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE, False, False, True)1532if self.get_parameter("FENCE_TOTAL") != 0:1533raise NotAchievedException("Expected zero points remaining")1534self.assert_fence_sys_status(False, False, True)1535self.do_fence_disable()15361537# ensure that a fence is present if it is tin can, min alt or max alt1538self.progress("Test other fence types (tin-can, min alt, max alt")1539self.set_parameter("FENCE_TYPE", 1) # max alt1540self.assert_fence_sys_status(True, False, True)1541self.set_parameter("FENCE_TYPE", 8) # min alt1542self.assert_fence_sys_status(True, False, True)1543self.set_parameter("FENCE_TYPE", 2) # tin can1544self.assert_fence_sys_status(True, False, True)15451546# Test cannot arm if outside of fence and fence is enabled1547self.progress("Test Arming while vehicle below FENCE_ALT_MIN")1548default_fence_alt_min = self.get_parameter("FENCE_ALT_MIN")1549self.set_parameter("FENCE_ALT_MIN", 50)1550self.set_parameter("FENCE_TYPE", 8) # Enables minimum altitude breaches1551self.do_fence_enable()1552self.delay_sim_time(2) # Allow breach to propagate1553self.assert_fence_enabled()15541555self.try_arm(False, "Vehicle breaching Min Alt fence")1556self.do_fence_disable()1557self.set_parameter("FENCE_ALT_MIN", default_fence_alt_min)15581559# Test arming outside inclusion zone1560self.progress("Test arming while Vehicle breaching of inclusion zone")1561self.set_parameter("FENCE_TYPE", 4) # Enables polygon fence types1562self.upload_fences_from_locations([(1563mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [1564mavutil.location(1.000, 1.000, 0, 0),1565mavutil.location(1.000, 1.001, 0, 0),1566mavutil.location(1.001, 1.001, 0, 0),1567mavutil.location(1.001, 1.000, 0, 0)1568]1569)])1570self.delay_sim_time(10) # let fence check run so it loads-from-eeprom1571self.do_fence_enable()1572self.assert_fence_enabled()1573self.delay_sim_time(2) # Allow breach to propagate1574self.try_arm(False, "Vehicle breaching Polygon fence")1575self.do_fence_disable()1576self.clear_fence()15771578self.progress("Test arming while vehicle inside exclusion zone")1579self.set_parameter("FENCE_TYPE", 4) # Enables polygon fence types1580home_loc = self.mav.location()1581locs = [1582mavutil.location(home_loc.lat - 0.001, home_loc.lng - 0.001, 0, 0),1583mavutil.location(home_loc.lat - 0.001, home_loc.lng + 0.001, 0, 0),1584mavutil.location(home_loc.lat + 0.001, home_loc.lng + 0.001, 0, 0),1585mavutil.location(home_loc.lat + 0.001, home_loc.lng - 0.001, 0, 0),1586]1587self.upload_fences_from_locations([1588(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, locs),1589])1590self.delay_sim_time(10) # let fence check run so it loads-from-eeprom1591self.do_fence_enable()1592self.assert_fence_enabled()1593self.delay_sim_time(2) # Allow breach to propagate1594self.try_arm(False, "Vehicle breaching Polygon fence")1595self.do_fence_disable()15961597def test_fence_breach_circle_at(self, loc, disable_on_breach=False):1598self.load_fence("CMAC-fence.txt")1599want_radius = 1001600# when ArduPlane is fixed, remove this fudge factor1601REALLY_BAD_FUDGE_FACTOR = 1.161602expected_radius = REALLY_BAD_FUDGE_FACTOR * want_radius1603self.set_parameters({1604"RTL_RADIUS": want_radius,1605"NAVL1_LIM_BANK": 60,1606"FENCE_ACTION": 1, # AC_FENCE_ACTION_RTL_AND_LAND == 1. mavutil.mavlink.FENCE_ACTION_RTL == 41607})16081609self.wait_ready_to_arm() # need an origin to load fence16101611self.do_fence_enable()1612self.assert_fence_sys_status(True, True, True)16131614self.takeoff(alt=45, alt_max=300)16151616tstart = self.get_sim_time()1617while True:1618if self.get_sim_time() - tstart > 30:1619raise NotAchievedException("Did not breach fence")1620m = self.assert_receive_message('FENCE_STATUS', timeout=2)1621if m.breach_status == 0:1622continue16231624# we've breached; check our state;1625if m.breach_type != mavutil.mavlink.FENCE_BREACH_BOUNDARY:1626raise NotAchievedException("Unexpected breach type %u" %1627(m.breach_type,))1628if m.breach_count == 0:1629raise NotAchievedException("Unexpected breach count %u" %1630(m.breach_count,))1631self.assert_fence_sys_status(True, True, False)1632break16331634self.wait_circling_point_with_radius(loc, expected_radius)1635self.do_fence_disable()1636self.disarm_vehicle(force=True)1637self.reboot_sitl()16381639def FenceRTL(self):1640'''Test Fence RTL'''1641self.progress("Testing FENCE_ACTION_RTL no rally point")1642# have to disable the fence once we've breached or we breach1643# it as part of the loiter-at-home!1644self.test_fence_breach_circle_at(self.home_position_as_mav_location())16451646def FenceRTLRally(self):1647'''Test Fence RTL Rally'''1648self.progress("Testing FENCE_ACTION_RTL with rally point")16491650self.wait_ready_to_arm()1651loc = self.home_relative_loc_ne(50, -50)1652self.upload_rally_points_from_locations([loc])1653self.test_fence_breach_circle_at(loc)16541655def FenceRetRally(self):1656""" Tests the FENCE_RET_RALLY flag, either returning to fence return point,1657or rally point """1658target_system = 11659target_component = 11660self.progress("Testing FENCE_ACTION_RTL with fence rally point")16611662self.wait_ready_to_arm()16631664# Grab a location for fence return point, and upload it.1665fence_loc = self.home_position_as_mav_location()1666self.location_offset_ne(fence_loc, 50, 50)1667fence_return_mission_items = [1668self.mav.mav.mission_item_int_encode(1669target_system,1670target_component,16710, # seq1672mavutil.mavlink.MAV_FRAME_GLOBAL_INT,1673mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,16740, # current16750, # autocontinue16760, # p116770, # p216780, # p316790, # p41680int(fence_loc.lat * 1e7), # latitude1681int(fence_loc.lng * 1e7), # longitude16820, # altitude1683mavutil.mavlink.MAV_MISSION_TYPE_FENCE1684)1685]1686self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,1687fence_return_mission_items)1688self.delay_sim_time(1)16891690# Grab a location for rally point, and upload it.1691rally_loc = self.home_relative_loc_ne(-50, 50)1692self.upload_rally_points_from_locations([rally_loc])16931694return_radius = 1001695return_alt = 801696self.set_parameters({1697"RTL_RADIUS": return_radius,1698"FENCE_ACTION": 6, # Set Fence Action to Guided1699"FENCE_TYPE": 8, # Only use fence floor1700"FENCE_RET_ALT": return_alt,1701})1702self.do_fence_enable()1703self.assert_fence_enabled()17041705self.takeoff(alt=50, alt_max=300)1706# Trigger fence breach, fly to rally location1707self.set_parameters({1708"FENCE_RET_RALLY": 1,1709"FENCE_ALT_MIN": 60,1710})1711self.wait_circling_point_with_radius(rally_loc, return_radius)1712self.set_parameter("FENCE_ALT_MIN", 0) # Clear fence breach17131714# 10 second fence min retrigger time1715self.delay_sim_time(15)17161717# Fly up before re-triggering fence breach. Fly to fence return point1718self.change_altitude(30, relative=True)1719self.set_parameters({1720"FENCE_RET_RALLY": 0,1721"FENCE_ALT_MIN": 60,1722})1723self.wait_altitude(altitude_min=return_alt-3,1724altitude_max=return_alt+3,1725relative=True)1726self.wait_circling_point_with_radius(fence_loc, return_radius)1727self.do_fence_disable() # Disable fence so we can land1728self.fly_home_land_and_disarm() # Pack it up, we're going home.17291730def TerrainRally(self):1731""" Tests terrain follow with a rally point """1732self.context_push()1733self.install_terrain_handlers_context()17341735def terrain_following_above_80m(mav, m):1736if m.get_type() == 'TERRAIN_REPORT':1737if m.current_height < 50:1738raise NotAchievedException(1739"TERRAIN_REPORT.current_height below 50m %fm" % m.current_height)1740if m.get_type() == 'VFR_HUD':1741if m.groundspeed < 2:1742raise NotAchievedException("hit ground")17431744def terrain_wait_path(loc1, loc2, steps):1745'''wait till we have terrain for N steps from loc1 to loc2'''1746tstart = self.get_sim_time_cached()1747self.progress("Waiting for terrain data")1748while True:1749now = self.get_sim_time_cached()1750if now - tstart > 60:1751raise NotAchievedException("Did not get correct required terrain")1752for i in range(steps):1753lat = loc1.lat + i * (loc2.lat-loc1.lat)/steps1754lon = loc1.lng + i * (loc2.lng-loc1.lng)/steps1755self.mav.mav.terrain_check_send(int(lat*1.0e7), int(lon*1.0e7))17561757report = self.assert_receive_message('TERRAIN_REPORT', timeout=60)1758self.progress("Terrain pending=%u" % report.pending)1759if report.pending == 0:1760break1761self.progress("Got required terrain")17621763self.wait_ready_to_arm()1764homeloc = self.mav.location()17651766guided_loc = mavutil.location(-35.39723762, 149.07284612, homeloc.alt+99.0, 0)1767rally_loc = mavutil.location(-35.3654952000, 149.1558698000, homeloc.alt+100, 0)17681769terrain_wait_path(homeloc, rally_loc, 10)17701771# set a rally point to the west of home1772self.upload_rally_points_from_locations([rally_loc])17731774self.set_parameter("TKOFF_ALT", 100)1775self.change_mode("TAKEOFF")1776self.wait_ready_to_arm()1777self.arm_vehicle()1778self.set_parameter("TERRAIN_FOLLOW", 1)1779self.wait_altitude(90, 120, timeout=30, relative=True)1780self.progress("Done takeoff")17811782self.install_message_hook_context(terrain_following_above_80m)17831784self.change_mode("GUIDED")1785self.send_do_reposition(guided_loc, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT)1786self.progress("Flying to guided location")1787self.wait_location(1788guided_loc,1789accuracy=200,1790timeout=600,1791height_accuracy=10,1792)17931794self.progress("Reached guided location")1795self.set_parameter("RALLY_LIMIT_KM", 50)1796self.change_mode("RTL")1797self.progress("Flying to rally point")1798self.wait_location(1799rally_loc,1800accuracy=200,1801timeout=600,1802height_accuracy=10,1803)1804self.progress("Reached rally point with TERRAIN_FOLLOW")18051806# Fly back to guided location1807self.change_mode("GUIDED")1808self.send_do_reposition(guided_loc, frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT)1809self.progress("Flying to back to guided location")18101811# Disable terrain following and re-load rally point with relative to terrain altitude1812self.set_parameter("TERRAIN_FOLLOW", 0)18131814rally_item = [self.create_MISSION_ITEM_INT(1815mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,1816x=int(rally_loc.lat*1e7),1817y=int(rally_loc.lng*1e7),1818z=rally_loc.alt,1819frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,1820mission_type=mavutil.mavlink.MAV_MISSION_TYPE_RALLY1821)]1822self.correct_wp_seq_numbers(rally_item)1823self.check_rally_upload_download(rally_item)18241825# Once back at guided location re-trigger RTL1826self.wait_location(1827guided_loc,1828accuracy=200,1829timeout=600,1830height_accuracy=10,1831)18321833self.change_mode("RTL")1834self.progress("Flying to rally point")1835self.wait_location(1836rally_loc,1837accuracy=200,1838timeout=600,1839height_accuracy=10,1840)1841self.progress("Reached rally point with terrain alt frame")18421843self.context_pop()1844self.disarm_vehicle(force=True)1845self.reboot_sitl()18461847def Parachute(self):1848'''Test Parachute'''1849self.set_rc(9, 1000)1850self.set_parameters({1851"CHUTE_ENABLED": 1,1852"CHUTE_TYPE": 10,1853"SERVO9_FUNCTION": 27,1854"SIM_PARA_ENABLE": 1,1855"SIM_PARA_PIN": 9,1856})18571858self.load_mission("plane-parachute-mission.txt")1859self.set_current_waypoint(1)1860self.change_mode('AUTO')1861self.wait_ready_to_arm()1862self.arm_vehicle()1863self.wait_statustext("BANG", timeout=60)1864self.disarm_vehicle(force=True)1865self.reboot_sitl()18661867def ParachuteSinkRate(self):1868'''Test Parachute (SinkRate triggering)'''1869self.set_rc(9, 1000)1870self.set_parameters({1871"CHUTE_ENABLED": 1,1872"CHUTE_TYPE": 10,1873"SERVO9_FUNCTION": 27,1874"SIM_PARA_ENABLE": 1,1875"SIM_PARA_PIN": 9,1876"CHUTE_CRT_SINK": 9,1877})18781879self.progress("Takeoff")1880self.takeoff(alt=300)18811882self.progress("Diving")1883self.set_rc(2, 2000)1884self.wait_statustext("BANG", timeout=60)18851886self.disarm_vehicle(force=True)1887self.reboot_sitl()18881889def run_subtest(self, desc, func):1890self.start_subtest(desc)1891func()18921893def fly_ahrs2_test(self):1894'''check secondary estimator is looking OK'''18951896ahrs2 = self.assert_receive_message('AHRS2', verbose=1)1897gpi = self.assert_receive_message('GLOBAL_POSITION_INT', verbose=1)1898if self.get_distance_int(gpi, ahrs2) > 10:1899raise NotAchievedException("Secondary location looks bad")19001901self.check_attitudes_match()19021903def MainFlight(self):1904'''Lots of things in one flight'''1905self.change_mode('MANUAL')19061907self.progress("Asserting we do support transfer of fence via mission item protocol")1908self.assert_capability(mavutil.mavlink.MAV_PROTOCOL_CAPABILITY_MISSION_FENCE)19091910self.run_subtest("Takeoff", self.takeoff)19111912self.run_subtest("Set Attitude Target", self.set_attitude_target)19131914self.run_subtest("Fly left circuit", self.fly_left_circuit)19151916self.run_subtest("Left roll", lambda: self.axial_left_roll(1))19171918self.run_subtest("Inside loop", self.inside_loop)19191920self.run_subtest("Stablize test", self.test_stabilize)19211922self.run_subtest("ACRO test", self.test_acro)19231924self.run_subtest("FBWB test", self.test_FBWB)19251926self.run_subtest("CRUISE test", lambda: self.test_FBWB(mode='CRUISE'))19271928self.run_subtest("RTL test", self.fly_RTL)19291930self.run_subtest("LOITER test", self.fly_LOITER)19311932self.run_subtest("CIRCLE test", self.fly_CIRCLE)19331934self.run_subtest("AHRS2 test", self.fly_ahrs2_test)19351936self.run_subtest("Mission test",1937lambda: self.fly_mission("ap1.txt", strict=False))19381939def PitotBlockage(self):1940'''Test detection and isolation of a blocked pitot tube'''1941self.set_parameters({1942"ARSPD_OPTIONS": 15,1943"ARSPD_USE": 1,1944"SIM_WIND_SPD": 7,1945"SIM_WIND_DIR": 0,1946"ARSPD_WIND_MAX": 15,1947})1948self.takeoff(alt=50, mode='TAKEOFF')1949# simulate the effect of a blocked pitot tube1950self.set_parameter("ARSPD_RATIO", 0.1)1951self.delay_sim_time(10)1952if (self.get_parameter("ARSPD_USE") == 0):1953self.progress("Faulty Sensor Disabled")1954else:1955raise NotAchievedException("Airspeed Sensor Not Disabled")1956self.delay_sim_time(20)1957# simulate the effect of blockage partially clearing1958self.set_parameter("ARSPD_RATIO", 1.0)1959self.delay_sim_time(60)1960if (self.get_parameter("ARSPD_USE") == 0):1961self.progress("Faulty Sensor Remains Disabled")1962else:1963raise NotAchievedException("Fault Sensor Re-Enabled")1964# simulate the effect of blockage fully clearing1965self.set_parameter("ARSPD_RATIO", 2.0)1966self.delay_sim_time(60)1967if (self.get_parameter("ARSPD_USE") == 1):1968self.progress("Sensor Re-Enabled")1969else:1970raise NotAchievedException("Airspeed Sensor Not Re-Enabled")1971self.fly_home_land_and_disarm()19721973def AIRSPEED_AUTOCAL(self):1974'''Test AIRSPEED_AUTOCAL'''1975self.progress("Ensure no AIRSPEED_AUTOCAL on ground")1976self.set_parameters({1977"ARSPD_AUTOCAL": 1,1978"ARSPD_PIN": 2,1979"ARSPD_RATIO": 0,1980"ARSPD2_RATIO": 4,1981"ARSPD2_TYPE": 3, # MS55251982"ARSPD2_BUS": 1,1983"ARSPD2_AUTOCAL": 1,1984"SIM_ARSPD2_OFS": 1900, # default is 201319851986"RTL_AUTOLAND": 1,1987})1988self.context_collect('STATUSTEXT')1989self.reboot_sitl()19901991self.assert_not_receive_message('AIRSPEED_AUTOCAL', timeout=5)19921993# these are boot-time calibration messages:1994self.wait_statustext('Airspeed 1 calibrated', check_context=True, timeout=30)1995self.wait_statustext('Airspeed 2 calibrated', check_context=True)19961997mission_filepath = "flaps.txt"1998self.load_mission(mission_filepath)1999self.wait_ready_to_arm()2000self.arm_vehicle()2001self.change_mode("AUTO")2002self.progress("Ensure AIRSPEED_AUTOCAL in air")2003self.assert_receive_message('AIRSPEED_AUTOCAL')2004self.wait_statustext("Airspeed 0 ratio reset", check_context=True, timeout=70)2005self.wait_statustext("Airspeed 1 ratio reset", check_context=True, timeout=70)2006self.fly_home_land_and_disarm()20072008def deadreckoning_main(self, disable_airspeed_sensor=False):2009self.context_push()2010self.set_parameter("EK3_OPTIONS", 1)2011self.set_parameter("AHRS_OPTIONS", 3)2012self.set_parameter("LOG_REPLAY", 1)2013self.reboot_sitl()2014self.wait_ready_to_arm()20152016if disable_airspeed_sensor:2017max_allowed_divergence = 3002018else:2019max_allowed_divergence = 1502020self.install_message_hook_context(vehicle_test_suite.TestSuite.ValidateGlobalPositionIntAgainstSimState(self, max_allowed_divergence=max_allowed_divergence)) # noqa20212022try:2023# wind is from the West:2024self.set_parameter("SIM_WIND_DIR", 270)2025# light winds:2026self.set_parameter("SIM_WIND_SPD", 10)2027if disable_airspeed_sensor:2028self.set_parameter("ARSPD_USE", 0)20292030self.takeoff(50)2031loc = self.mav.location()2032self.location_offset_ne(loc, 500, 500)2033self.run_cmd_int(2034mavutil.mavlink.MAV_CMD_DO_REPOSITION,2035p1=0,2036p2=mavutil.mavlink.MAV_DO_REPOSITION_FLAGS_CHANGE_MODE,2037p5=int(loc.lat * 1e7),2038p6=int(loc.lng * 1e7),2039p7=100, # alt2040frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT,2041)2042self.wait_location(loc, accuracy=100)2043self.progress("Orbit with GPS and learn wind")2044# allow longer to learn wind if there is no airspeed sensor2045if disable_airspeed_sensor:2046self.delay_sim_time(60)2047else:2048self.delay_sim_time(20)2049self.set_parameter("SIM_GPS1_ENABLE", 0)2050self.progress("Continue orbit without GPS")2051self.delay_sim_time(20)2052self.change_mode("RTL")2053self.wait_distance_to_home(100, 200, timeout=200)2054# go into LOITER to create additonal time for a GPS re-enable test2055self.change_mode("LOITER")2056self.set_parameter("SIM_GPS1_ENABLE", 1)2057t_enabled = self.get_sim_time()2058# The EKF should wait for GPS checks to pass when we are still able to navigate using dead reckoning2059# to prevent bad GPS being used when coming back after loss of lock due to interence.2060self.wait_ekf_flags(mavutil.mavlink.ESTIMATOR_POS_HORIZ_ABS, 0, timeout=15)2061if self.get_sim_time() < (t_enabled+9):2062raise NotAchievedException("GPS use re-started too quickly")2063# wait for EKF and vehicle position to stabilise, then test response to jamming2064self.delay_sim_time(20)20652066self.set_parameter("AHRS_OPTIONS", 1)2067self.set_parameter("SIM_GPS1_JAM", 1)2068self.delay_sim_time(10)2069self.set_parameter("SIM_GPS1_JAM", 0)2070t_enabled = self.get_sim_time()2071# The EKF should wait for GPS checks to pass when we are still able to navigate using dead reckoning2072# to prevent bad GPS being used when coming back after loss of lock due to interence.2073# The EKF_STATUS_REPORT does not tell us when the good to align check passes, so the minimum time2074# value of 3.0 seconds is an arbitrary value set on inspection of dataflash logs from this test2075self.wait_ekf_flags(mavutil.mavlink.ESTIMATOR_POS_HORIZ_ABS, 0, timeout=15)2076time_since_jamming_stopped = self.get_sim_time() - t_enabled2077if time_since_jamming_stopped < 3:2078raise NotAchievedException("GPS use re-started %f sec after jamming stopped" % time_since_jamming_stopped)2079self.set_rc(3, 1000)2080self.fly_home_land_and_disarm()2081finally:2082pass20832084self.context_pop()2085self.reboot_sitl()20862087def Deadreckoning(self):2088'''Test deadreckoning support'''2089self.deadreckoning_main()20902091def DeadreckoningNoAirSpeed(self):2092'''Test deadreckoning support with no airspeed sensor'''2093self.deadreckoning_main(disable_airspeed_sensor=True)20942095def ClimbBeforeTurn(self):2096'''Test climb-before-turn'''2097self.wait_ready_to_arm()2098self.set_parameters({2099"FLIGHT_OPTIONS": 0,2100"RTL_ALTITUDE": 80,2101"RTL_AUTOLAND": 1,2102})2103takeoff_alt = 102104self.takeoff(alt=takeoff_alt)2105self.change_mode("CRUISE")2106self.wait_distance_to_home(500, 1000, timeout=60)2107self.change_mode("RTL")2108expected_alt = self.get_parameter("RTL_ALTITUDE")21092110home = self.home_position_as_mav_location()2111distance = self.get_distance(home, self.mav.location())21122113self.wait_altitude(expected_alt - 10, expected_alt + 10, relative=True, timeout=80)21142115new_distance = self.get_distance(home, self.mav.location())2116# We should be closer to home.2117if new_distance > distance:2118raise NotAchievedException(2119"Expected to be closer to home (was %fm, now %fm)."2120% (distance, new_distance)2121)21222123self.fly_home_land_and_disarm()2124self.set_current_waypoint(0, check_afterwards=False)21252126self.change_mode("MANUAL")2127self.set_rc(3, 1000)21282129self.wait_ready_to_arm()2130self.set_parameters({2131"FLIGHT_OPTIONS": 16,2132"RTL_ALTITUDE": 100,2133})2134self.takeoff(alt=takeoff_alt)2135self.change_mode("CRUISE")2136self.wait_distance_to_home(500, 1000, timeout=60)2137self.change_mode("RTL")21382139home = self.home_position_as_mav_location()2140distance = self.get_distance(home, self.mav.location())21412142self.wait_altitude(expected_alt - 10, expected_alt + 10, relative=True, timeout=80)21432144new_distance = self.get_distance(home, self.mav.location())2145# We should be farther from to home.2146if new_distance < distance:2147raise NotAchievedException(2148"Expected to be farther from home (was %fm, now %fm)."2149% (distance, new_distance)2150)21512152self.fly_home_land_and_disarm(timeout=240)21532154def RTL_CLIMB_MIN(self):2155'''Test RTL_CLIMB_MIN'''2156self.wait_ready_to_arm()2157rtl_climb_min = 1002158self.set_parameter("RTL_CLIMB_MIN", rtl_climb_min)2159takeoff_alt = 502160self.takeoff(alt=takeoff_alt)2161self.change_mode('CRUISE')2162self.wait_distance_to_home(1000, 1500, timeout=60)2163post_cruise_alt = self.get_altitude(relative=True)2164self.change_mode('RTL')2165expected_alt = self.get_parameter("RTL_ALTITUDE")2166if expected_alt == -1:2167expected_alt = self.get_altitude(relative=True)21682169# ensure we're about half-way-down at the half-way-home stage:2170self.wait_distance_to_nav_target(21710,2172500,2173timeout=240,2174)2175alt = self.get_altitude(relative=True)2176expected_halfway_alt = expected_alt + (post_cruise_alt + rtl_climb_min - expected_alt)/2.02177if abs(alt - expected_halfway_alt) > 30:2178raise NotAchievedException("Not half-way-down and half-way-home (want=%f got=%f" %2179(expected_halfway_alt, alt))2180self.progress("Half-way-down at half-way-home (want=%f vs got=%f)" %2181(expected_halfway_alt, alt))21822183rtl_radius = self.get_parameter("RTL_RADIUS")2184if rtl_radius == 0:2185rtl_radius = self.get_parameter("WP_LOITER_RAD")2186self.wait_distance_to_nav_target(21870,2188rtl_radius,2189timeout=120,2190)2191alt = self.get_altitude(relative=True)2192if abs(alt - expected_alt) > 10:2193raise NotAchievedException(2194"Expected to have %fm altitude at end of RTL (got %f)" %2195(expected_alt, alt))2196self.fly_home_land_and_disarm()21972198def sample_enable_parameter(self):2199return "Q_ENABLE"22002201def RangeFinder(self):2202'''Test RangeFinder Basic Functionality'''2203self.progress("Making sure we don't ordinarily get RANGEFINDER")2204self.assert_not_receive_message('RANGEFINDER')22052206self.set_analog_rangefinder_parameters()22072208self.reboot_sitl()22092210'''ensure rangefinder gives height-above-ground'''2211self.load_mission("plane-gripper-mission.txt") # borrow this2212self.set_parameter("RTL_AUTOLAND", 1)2213self.set_current_waypoint(1)2214self.change_mode('AUTO')2215self.wait_ready_to_arm()2216self.arm_vehicle()2217self.wait_waypoint(5, 5, max_dist=100)2218rf = self.assert_receive_message('RANGEFINDER')2219gpi = self.assert_receive_message('GLOBAL_POSITION_INT')2220if abs(rf.distance - gpi.relative_alt/1000.0) > 3:2221raise NotAchievedException(2222"rangefinder alt (%s) disagrees with global-position-int.relative_alt (%s)" %2223(rf.distance, gpi.relative_alt/1000.0))2224self.wait_statustext("Auto disarmed", timeout=60)22252226self.progress("Ensure RFND messages in log")2227if not self.current_onboard_log_contains_message("RFND"):2228raise NotAchievedException("No RFND messages in log")22292230def rc_defaults(self):2231ret = super(AutoTestPlane, self).rc_defaults()2232ret[3] = 10002233ret[8] = 18002234return ret22352236def initial_mode_switch_mode(self):2237return "MANUAL"22382239def default_mode(self):2240return "MANUAL"22412242def PIDTuning(self):2243'''Test PID Tuning'''2244self.change_mode("FBWA") # we don't update PIDs in MANUAL2245super(AutoTestPlane, self).PIDTuning()22462247def AuxModeSwitch(self):2248'''Set modes via auxswitches'''2249self.set_parameter("FLTMODE1", 1) # circle2250self.set_rc(8, 950)2251self.wait_mode("CIRCLE")2252self.set_rc(9, 1000)2253self.set_rc(10, 1000)2254self.set_parameters({2255"RC9_OPTION": 4, # RTL2256"RC10_OPTION": 55, # guided2257})2258self.set_rc(9, 1900)2259self.wait_mode("RTL")2260self.set_rc(10, 1900)2261self.wait_mode("GUIDED")22622263self.progress("resetting both switches - should go back to CIRCLE")2264self.set_rc(9, 1000)2265self.set_rc(10, 1000)2266self.wait_mode("CIRCLE")22672268self.set_rc(9, 1900)2269self.wait_mode("RTL")2270self.set_rc(10, 1900)2271self.wait_mode("GUIDED")22722273self.progress("Resetting switch should repoll mode switch")2274self.set_rc(10, 1000) # this re-polls the mode switch2275self.wait_mode("CIRCLE")2276self.set_rc(9, 1000)22772278def wait_for_collision_threat_to_clear(self):2279'''wait to get a "clear" collision message", then slurp remaining2280messages'''2281last_collision = self.get_sim_time()2282while True:2283now = self.get_sim_time()2284if now - last_collision > 5:2285return2286self.progress("Waiting for collision message")2287m = self.mav.recv_match(type='COLLISION', blocking=True, timeout=1)2288self.progress("Got (%s)" % str(m))2289if m is None:2290continue2291last_collision = now22922293def SimADSB(self):2294'''Tests to ensure simulated ADSB sensor continues to function'''2295self.set_parameters({2296"SIM_ADSB_COUNT": 1,2297"ADSB_TYPE": 1,2298})2299self.reboot_sitl()2300self.assert_receive_message('ADSB_VEHICLE', timeout=30)23012302def ADSBResumeActionResumeLoiter(self):2303'''ensure we resume auto mission or enter loiter'''2304self.set_parameters({2305"ADSB_TYPE": 1,2306"AVD_ENABLE": 1,2307"AVD_F_ACTION": mavutil.mavlink.MAV_COLLISION_ACTION_MOVE_HORIZONTALLY,2308"AVD_F_RCVRY": 3, # resume auto or loiter2309})2310self.reboot_sitl()2311self.takeoff(50)2312# fly North, create thread to east, wait for flying east2313self.start_subtest("Testing loiter resume")2314self.reach_heading_manual(0)2315here = self.mav.location()2316self.test_adsb_send_threatening_adsb_message(here, offset_ne=(0, 30))2317self.wait_mode('AVOID_ADSB')2318# recovery has the vehicle circling a point... but we don't2319# know which point. So wait 'til it looks like it is2320# circling, then grab the point, then check we're circling2321# it...2322self.wait_heading(290)2323self.wait_heading(300)2324dest = self.position_target_loc()2325REALLY_BAD_FUDGE_FACTOR = 1.25 # FIXME2326expected_radius = REALLY_BAD_FUDGE_FACTOR * self.get_parameter('WP_LOITER_RAD')2327self.wait_circling_point_with_radius(dest, expected_radius)23282329self.start_subtest("Testing mission resume")2330self.reach_heading_manual(270)2331self.load_generic_mission("CMAC-circuit.txt", strict=False)2332self.change_mode('AUTO')2333self.wait_current_waypoint(2)2334self.test_adsb_send_threatening_adsb_message(here, offset_ne=(0, 30))2335self.wait_mode('AVOID_ADSB')2336self.wait_mode('AUTO')23372338self.fly_home_land_and_disarm()23392340def ADSBFailActionRTL(self):2341'''test ADSB avoidance action of RTL'''2342# message ADSB_VEHICLE 37 -353632614 1491652305 0 584070 0 0 0 "bob" 3 1 255 172343self.set_parameter("RC12_OPTION", 38) # avoid-adsb2344self.set_rc(12, 2000)2345self.set_parameters({2346"ADSB_TYPE": 1,2347"AVD_ENABLE": 1,2348"AVD_F_ACTION": mavutil.mavlink.MAV_COLLISION_ACTION_RTL,2349})2350self.reboot_sitl()2351self.wait_ready_to_arm()2352here = self.mav.location()2353self.change_mode("FBWA")2354self.delay_sim_time(2) # TODO: work out why this is required...2355self.test_adsb_send_threatening_adsb_message(here)2356self.progress("Waiting for collision message")2357m = self.assert_receive_message('COLLISION', timeout=4)2358if m.threat_level != 2:2359raise NotAchievedException("Expected some threat at least")2360if m.action != mavutil.mavlink.MAV_COLLISION_ACTION_RTL:2361raise NotAchievedException("Incorrect action; want=%u got=%u" %2362(mavutil.mavlink.MAV_COLLISION_ACTION_RTL, m.action))2363self.wait_mode("RTL")23642365self.progress("Sending far-away ABSD_VEHICLE message")2366self.mav.mav.adsb_vehicle_send(236737, # ICAO address2368int(here.lat+1 * 1e7),2369int(here.lng * 1e7),2370mavutil.mavlink.ADSB_ALTITUDE_TYPE_PRESSURE_QNH,2371int(here.alt*1000 + 10000), # 10m up23720, # heading in cdeg23730, # horizontal velocity cm/s23740, # vertical velocity cm/s2375"bob".encode("ascii"), # callsign2376mavutil.mavlink.ADSB_EMITTER_TYPE_LIGHT,23771, # time since last communication237865535, # flags237917 # squawk2380)2381self.wait_for_collision_threat_to_clear()2382self.change_mode("FBWA")23832384self.progress("Disabling ADSB-avoidance with RC channel")2385self.set_rc(12, 1000)2386self.delay_sim_time(1) # let the switch get polled2387self.test_adsb_send_threatening_adsb_message(here)2388m = self.mav.recv_match(type='COLLISION', blocking=True, timeout=4)2389self.progress("Got (%s)" % str(m))2390if m is not None:2391raise NotAchievedException("Got collision message when I shouldn't have")23922393def GuidedRequest(self, target_system=1, target_component=1):2394'''Test handling of MISSION_ITEM in guided mode'''2395self.progress("Takeoff")2396self.takeoff(alt=50)2397self.set_rc(3, 1500)2398self.start_subtest("Ensure command bounced outside guided mode")2399desired_relative_alt = 332400loc = self.mav.location()2401self.location_offset_ne(loc, 300, 300)2402loc.alt += desired_relative_alt2403self.mav.mav.mission_item_int_send(2404target_system,2405target_component,24060, # seq2407mavutil.mavlink.MAV_FRAME_GLOBAL,2408mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,24092, # current - guided-mode request24100, # autocontinue24110, # p124120, # p224130, # p324140, # p42415int(loc.lat * 1e7), # latitude2416int(loc.lng * 1e7), # longitude2417loc.alt, # altitude2418mavutil.mavlink.MAV_MISSION_TYPE_MISSION)2419m = self.assert_receive_message('MISSION_ACK', timeout=5)2420if m.type != mavutil.mavlink.MAV_MISSION_ERROR:2421raise NotAchievedException("Did not get appropriate error")24222423self.start_subtest("Enter guided and flying somewhere constant")2424self.change_mode("GUIDED")2425self.mav.mav.mission_item_int_send(2426target_system,2427target_component,24280, # seq2429mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,2430mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,24312, # current - guided-mode request24320, # autocontinue24330, # p124340, # p224350, # p324360, # p42437int(loc.lat * 1e7), # latitude2438int(loc.lng * 1e7), # longitude2439desired_relative_alt, # altitude2440mavutil.mavlink.MAV_MISSION_TYPE_MISSION)2441m = self.assert_receive_message('MISSION_ACK', timeout=5)2442if m.type != mavutil.mavlink.MAV_MISSION_ACCEPTED:2443raise NotAchievedException("Did not get accepted response")2444self.wait_location(loc, accuracy=100) # based on loiter radius2445self.wait_altitude(altitude_min=desired_relative_alt-3,2446altitude_max=desired_relative_alt+3,2447relative=True,2448timeout=30)24492450self.start_subtest("changing alt with mission item in guided mode")24512452# test changing alt only - NOTE - this is still a2453# NAV_WAYPOINT, not a changel-alt request!2454desired_relative_alt = desired_relative_alt + 502455self.mav.mav.mission_item_int_send(2456target_system,2457target_component,24580, # seq2459mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,2460mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,24613, # current - change-alt request24620, # autocontinue24630, # p124640, # p224650, # p324660, # p424670, # latitude24680,2469desired_relative_alt, # altitude2470mavutil.mavlink.MAV_MISSION_TYPE_MISSION)24712472self.wait_altitude(altitude_min=desired_relative_alt-3,2473altitude_max=desired_relative_alt+3,2474relative=True,2475timeout=30)24762477self.fly_home_land_and_disarm()24782479def LOITER(self):2480'''Test Loiter mode'''2481# first test old loiter behavour2482self.set_parameter("FLIGHT_OPTIONS", 0)2483self.takeoff(alt=200)2484self.set_rc(3, 1500)2485self.change_mode("LOITER")2486self.progress("Doing a bit of loitering to start with")2487tstart = self.get_sim_time()2488while True:2489now = self.get_sim_time_cached()2490if now - tstart > 60:2491break2492m = self.assert_receive_message('VFR_HUD')2493new_throttle = m.throttle2494alt = m.alt2495m = self.assert_receive_message('ATTITUDE', timeout=5)2496pitch = math.degrees(m.pitch)2497self.progress("Pitch:%f throttle:%u alt:%f" % (pitch, new_throttle, alt))2498m = self.assert_receive_message('VFR_HUD', timeout=5)2499initial_throttle = m.throttle2500initial_alt = m.alt2501self.progress("Initial throttle: %u" % initial_throttle)2502# pitch down, ensure throttle decreases:2503rc2_max = self.get_parameter("RC2_MAX")2504self.set_rc(2, int(rc2_max))2505tstart = self.get_sim_time()2506while True:2507now = self.get_sim_time_cached()2508'''stick-mixing is pushing the aircraft down. It doesn't want to go2509down (the target loiter altitude hasn't changed), so it2510tries to add energy by increasing the throttle.2511'''2512if now - tstart > 60:2513raise NotAchievedException("Did not see increase in throttle")2514m = self.assert_receive_message('VFR_HUD', timeout=5)2515new_throttle = m.throttle2516alt = m.alt2517m = self.assert_receive_message('ATTITUDE', timeout=5)2518pitch = math.degrees(m.pitch)2519self.progress("Pitch:%f throttle:%u alt:%f" % (pitch, new_throttle, alt))2520if new_throttle - initial_throttle > 20:2521self.progress("Throttle delta achieved")2522break2523self.progress("Centering elevator and ensuring we get back to loiter altitude")2524self.set_rc(2, 1500)2525self.wait_altitude(initial_alt-1, initial_alt+1)2526# Test new loiter behavour2527self.set_parameter("FLIGHT_OPTIONS", 1 << 12)2528# should decend at max stick2529self.set_rc(2, int(rc2_max))2530self.wait_altitude(initial_alt - 110, initial_alt - 90, timeout=90)2531# should not climb back at mid stick2532self.set_rc(2, 1500)2533self.delay_sim_time(60)2534self.wait_altitude(initial_alt - 110, initial_alt - 90)2535# should climb at min stick2536self.set_rc(2, 1100)2537self.wait_altitude(initial_alt - 10, initial_alt + 10, timeout=90)2538# return stick to center and fly home2539self.set_rc(2, 1500)2540self.fly_home_land_and_disarm()25412542def CPUFailsafe(self):2543'''In lockup Plane should copy RC inputs to RC outputs'''2544self.plane_CPUFailsafe()25452546def LargeMissions(self):2547'''Test Manipulation of Large missions'''2548self.load_mission("Kingaroy-vlarge.txt", strict=False)2549self.load_mission("Kingaroy-vlarge2.txt", strict=False)25502551def Soaring(self):2552'''Test Soaring feature'''25532554model = "plane-soaring"25552556self.customise_SITL_commandline(2557[],2558model=model,2559defaults_filepath=self.model_defaults_filepath(model),2560wipe=True)25612562self.load_mission('CMAC-soar.txt', strict=False)25632564# Enable thermalling RC2565rc_chan = 02566for i in range(8):2567rcx_option = self.get_parameter('RC{0}_OPTION'.format(i+1))2568if rcx_option == 88:2569rc_chan = i+12570break25712572if rc_chan == 0:2573raise NotAchievedException("Did not find soaring enable channel option.")25742575self.set_rc_from_map({2576rc_chan: 1900,2577})25782579self.set_parameters({2580"SOAR_VSPEED": 0.55,2581"SOAR_MIN_THML_S": 25,2582})25832584self.set_current_waypoint(1)2585self.change_mode('AUTO')2586self.wait_ready_to_arm()2587self.arm_vehicle()25882589# Wait to detect thermal2590self.progress("Waiting for thermal")2591self.wait_mode('THERMAL', timeout=600)25922593# Wait to climb to SOAR_ALT_MAX2594self.progress("Waiting for climb to max altitude")2595alt_max = self.get_parameter('SOAR_ALT_MAX')2596self.wait_altitude(alt_max-10, alt_max, timeout=600, relative=True)25972598# Wait for AUTO2599self.progress("Waiting for AUTO mode")2600self.wait_mode('AUTO')26012602# Disable thermals2603self.set_parameter("SIM_THML_SCENARI", 0)26042605# Wait to descend to SOAR_ALT_MIN2606self.progress("Waiting for glide to min altitude")2607alt_min = self.get_parameter('SOAR_ALT_MIN')2608self.wait_altitude(alt_min-10, alt_min, timeout=600, relative=True)26092610self.progress("Waiting for throttle up")2611self.wait_servo_channel_value(3, 1200, timeout=5, comparator=operator.gt)26122613self.progress("Waiting for climb to cutoff altitude")2614alt_ctf = self.get_parameter('SOAR_ALT_CUTOFF')2615self.wait_altitude(alt_ctf-10, alt_ctf, timeout=600, relative=True)26162617# Allow time to suppress throttle and start descent.2618self.delay_sim_time(20)26192620# Now set FBWB mode2621self.change_mode('FBWB')2622self.delay_sim_time(5)26232624# Now disable soaring (should hold altitude)2625self.set_parameter("SOAR_ENABLE", 0)2626self.delay_sim_time(10)26272628# And reenable. This should force throttle-down2629self.set_parameter("SOAR_ENABLE", 1)2630self.delay_sim_time(10)26312632# Now wait for descent and check throttle up2633self.wait_altitude(alt_min-10, alt_min, timeout=600, relative=True)26342635self.progress("Waiting for climb")2636self.wait_altitude(alt_ctf-10, alt_ctf, timeout=600, relative=True)26372638# Back to auto2639self.change_mode('AUTO')26402641# Reenable thermals2642self.set_parameter("SIM_THML_SCENARI", 1)26432644# Disable soaring using RC channel.2645self.set_rc(rc_chan, 1100)26462647# Wait to get back to waypoint before thermal.2648self.progress("Waiting to get back to position")2649self.wait_current_waypoint(3, timeout=1200)26502651# Enable soaring with mode changes suppressed)2652self.set_rc(rc_chan, 1500)26532654# Make sure this causes throttle down.2655self.wait_servo_channel_value(3, 1200, timeout=3, comparator=operator.lt)26562657self.progress("Waiting for next WP with no thermalling")2658self.wait_waypoint(4, 4, timeout=1200, max_dist=120)26592660# Disarm2661self.disarm_vehicle_expect_fail()26622663self.progress("Mission OK")26642665def SpeedToFly(self):2666'''Test soaring speed-to-fly'''26672668model = "plane-soaring"26692670self.customise_SITL_commandline(2671[],2672model=model,2673defaults_filepath=self.model_defaults_filepath(model),2674wipe=True)26752676self.load_mission('CMAC-soar.txt', strict=False)26772678self.set_parameters({2679"SIM_THML_SCENARI": 0, # Turn off environmental thermals.2680"SOAR_ALT_MAX": 1000, # remove source of random failure2681})26822683# Get thermalling RC channel2684rc_chan = 02685for i in range(8):2686rcx_option = self.get_parameter('RC{0}_OPTION'.format(i+1))2687if rcx_option == 88:2688rc_chan = i+12689break26902691if rc_chan == 0:2692raise NotAchievedException("Did not find soaring enable channel option.")26932694# Disable soaring2695self.set_rc(rc_chan, 1100)26962697self.set_current_waypoint(1)2698self.change_mode('AUTO')2699self.wait_ready_to_arm()2700self.arm_vehicle()27012702# Wait for to 400m before starting.2703self.wait_altitude(390, 400, timeout=600, relative=True)27042705# Wait 10s to stabilize.2706self.delay_sim_time(30)27072708# Enable soaring (no automatic thermalling)2709self.set_rc(rc_chan, 1500)27102711self.set_parameters({2712"SOAR_CRSE_ARSPD": -1, # Enable speed to fly.2713"SOAR_VSPEED": 1, # Set appropriate McCready.2714"SIM_WIND_SPD": 0,2715})27162717self.progress('Waiting a few seconds before determining the "trim" airspeed.')2718self.delay_sim_time(20)2719m = self.assert_receive_message('VFR_HUD')2720trim_airspeed = m.airspeed2721self.progress("Using trim_airspeed=%f" % (trim_airspeed,))27222723min_airspeed = self.get_parameter("AIRSPEED_MIN")2724max_airspeed = self.get_parameter("AIRSPEED_MAX")27252726if trim_airspeed > max_airspeed:2727raise NotAchievedException("trim airspeed > max_airspeed (%f>%f)" %2728(trim_airspeed, max_airspeed))2729if trim_airspeed < min_airspeed:2730raise NotAchievedException("trim airspeed < min_airspeed (%f<%f)" %2731(trim_airspeed, min_airspeed))27322733self.progress("Adding updraft")2734self.set_parameters({2735"SIM_WIND_SPD": 1,2736'SIM_WIND_DIR_Z': 90,2737})2738self.progress("Waiting for vehicle to move slower in updraft")2739self.wait_airspeed(0, trim_airspeed-0.5, minimum_duration=10, timeout=120)27402741self.progress("Adding downdraft")2742self.set_parameter('SIM_WIND_DIR_Z', -90)2743self.progress("Waiting for vehicle to move faster in downdraft")2744self.wait_airspeed(trim_airspeed+0.5, trim_airspeed+100, minimum_duration=10, timeout=120)27452746self.progress("Zeroing wind and increasing McCready")2747self.set_parameters({2748"SIM_WIND_SPD": 0,2749"SOAR_VSPEED": 2,2750})2751self.progress("Waiting for airspeed to increase with higher VSPEED")2752self.wait_airspeed(trim_airspeed+0.5, trim_airspeed+100, minimum_duration=10, timeout=120)27532754# mcReady tests don't work ATM, so just return early:2755# takes too long to land, so just make it all go away:2756self.disarm_vehicle(force=True)2757self.reboot_sitl()2758return27592760self.start_subtest('Test McReady values')2761# Disable soaring2762self.set_rc(rc_chan, 1100)27632764# Wait for to 400m before starting.2765self.wait_altitude(390, 400, timeout=600, relative=True)27662767# Enable soaring2768self.set_rc(rc_chan, 2000)27692770self.progress("Find airspeed with 1m/s updraft and mcready=1")2771self.set_parameters({2772"SOAR_VSPEED": 1,2773"SIM_WIND_SPD": 1,2774})2775self.delay_sim_time(20)2776m = self.assert_receive_message('VFR_HUD')2777mcready1_speed = m.airspeed2778self.progress("airspeed is %f" % mcready1_speed)27792780self.progress("Reducing McCready")2781self.set_parameters({2782"SOAR_VSPEED": 0.5,2783})2784self.progress("Waiting for airspeed to decrease with lower McReady")2785self.wait_airspeed(0, mcready1_speed-0.5, minimum_duration=10, timeout=120)27862787self.progress("Increasing McCready")2788self.set_parameters({2789"SOAR_VSPEED": 1.5,2790})2791self.progress("Waiting for airspeed to decrease with lower McReady")2792self.wait_airspeed(mcready1_speed+0.5, mcready1_speed+100, minimum_duration=10, timeout=120)27932794# takes too long to land, so just make it all go away:2795self.disarm_vehicle(force=True)2796self.reboot_sitl()27972798def AirspeedDrivers(self):2799'''Test AirSpeed drivers'''2800airspeed_sensors = [2801("MS5525", 3, 1),2802("DLVR", 7, 2),2803("SITL", 100, 0),2804]2805for (name, t, bus) in airspeed_sensors:2806self.context_push()2807if bus is not None:2808self.set_parameter("ARSPD2_BUS", bus)2809self.set_parameter("ARSPD2_TYPE", t)2810self.reboot_sitl()2811self.wait_ready_to_arm()2812self.arm_vehicle()28132814# insert listener to compare airspeeds:2815airspeed = [None, None]2816# don't start testing until we've seen real speed from2817# both sensors. This gets us out of the noise area.2818global initial_airspeed_threshold_reached2819initial_airspeed_threshold_reached = False28202821def check_airspeeds(mav, m):2822global initial_airspeed_threshold_reached2823m_type = m.get_type()2824if (m_type == 'NAMED_VALUE_FLOAT' and2825m.name == 'AS2'):2826airspeed[1] = m.value2827elif m_type == 'VFR_HUD':2828airspeed[0] = m.airspeed2829else:2830return2831if airspeed[0] is None or airspeed[1] is None:2832return2833if airspeed[0] < 2 or airspeed[1] < 2:2834# this mismatch can occur on takeoff, or when we2835# smack into the ground at the end of the mission2836return2837if not initial_airspeed_threshold_reached:2838if not (airspeed[0] > 10 or airspeed[1] > 10):2839return2840initial_airspeed_threshold_reached = True2841delta = abs(airspeed[0] - airspeed[1])2842if delta > 2:2843raise NotAchievedException("Airspeed mismatch (as1=%f as2=%f)" % (airspeed[0], airspeed[1]))2844self.install_message_hook_context(check_airspeeds)2845self.fly_mission("ap1.txt", strict=False)2846if airspeed[0] is None:2847raise NotAchievedException("Never saw an airspeed1")2848if airspeed[1] is None:2849raise NotAchievedException("Never saw an airspeed2")2850self.context_pop()2851self.reboot_sitl()28522853def TerrainMission(self):2854'''Test terrain following in mission'''2855self.install_terrain_handlers_context()28562857num_wp = self.load_mission("ap-terrain.txt")28582859self.wait_ready_to_arm()2860self.arm_vehicle()28612862global max_alt2863max_alt = 028642865def record_maxalt(mav, m):2866global max_alt2867if m.get_type() != 'GLOBAL_POSITION_INT':2868return2869if m.relative_alt/1000.0 > max_alt:2870max_alt = m.relative_alt/1000.028712872self.install_message_hook_context(record_maxalt)28732874self.fly_mission_waypoints(num_wp-1, mission_timeout=600)28752876if max_alt < 200:2877raise NotAchievedException("Did not follow terrain")28782879def Terrain(self):2880'''test AP_Terrain'''2881self.reboot_sitl() # we know the terrain height at CMAC28822883self.install_terrain_handlers_context()28842885self.wait_ready_to_arm()2886loc = self.mav.location()28872888lng_int = int(loc.lng * 1e7)2889lat_int = int(loc.lat * 1e7)28902891# FIXME: once we have a pre-populated terrain cache this2892# should require an instantly correct report to pass2893tstart = self.get_sim_time_cached()2894last_terrain_report_pending = -12895while True:2896now = self.get_sim_time_cached()2897if now - tstart > 60:2898raise NotAchievedException("Did not get correct terrain report")28992900self.mav.mav.terrain_check_send(lat_int, lng_int)29012902report = self.mav.recv_match(type='TERRAIN_REPORT', blocking=True, timeout=60)2903self.progress(self.dump_message_verbose(report))2904if report.spacing != 0:2905break29062907# we will keep trying to long as the number of pending2908# tiles is dropping:2909if last_terrain_report_pending == -1:2910last_terrain_report_pending = report.pending2911elif report.pending < last_terrain_report_pending:2912last_terrain_report_pending = report.pending2913tstart = now29142915self.delay_sim_time(1)29162917self.progress(self.dump_message_verbose(report))29182919expected_terrain_height = 583.52920if abs(report.terrain_height - expected_terrain_height) > 0.5:2921raise NotAchievedException("Expected terrain height=%f got=%f" %2922(expected_terrain_height, report.terrain_height))29232924def TerrainLoiter(self):2925'''Test terrain following in loiter'''2926self.context_push()2927self.install_terrain_handlers_context()2928self.set_parameters({2929"TERRAIN_FOLLOW": 1, # enable terrain following in loiter2930"WP_LOITER_RAD": 2000, # set very large loiter rad to get some terrain changes2931})2932alt = 2002933self.takeoff(alt*0.9, alt*1.1)2934self.set_rc(3, 1500)2935self.change_mode("LOITER")2936self.progress("loitering at %um" % alt)2937tstart = self.get_sim_time()2938timeout = 60*15 # enough time to do one and a bit circles2939max_delta = 02940while True:2941now = self.get_sim_time_cached()2942if now - tstart > timeout:2943break2944gpi = self.assert_receive_message('GLOBAL_POSITION_INT')2945terrain = self.assert_receive_message('TERRAIN_REPORT')2946rel_alt = terrain.current_height2947self.progress("%um above terrain (%um bove home)" %2948(rel_alt, gpi.relative_alt/1000.0))2949if rel_alt > alt*1.2 or rel_alt < alt * 0.8:2950raise NotAchievedException("Not terrain following")2951delta = abs(rel_alt - gpi.relative_alt/1000.0)2952if delta > max_delta:2953max_delta = delta2954want_max_delta = 302955if max_delta < want_max_delta:2956raise NotAchievedException(2957"Expected terrain and home alts to vary more than they did (max=%u want=%u)" %2958(max_delta, want_max_delta))2959self.context_pop()2960self.progress("Returning home")2961self.fly_home_land_and_disarm(240)29622963def fly_external_AHRS(self, sim, eahrs_type, mission):2964"""Fly with external AHRS"""2965self.customise_SITL_commandline(["--serial4=sim:%s" % sim])29662967self.set_parameters({2968"EAHRS_TYPE": eahrs_type,2969"SERIAL4_PROTOCOL": 36,2970"SERIAL4_BAUD": 230400,2971"GPS1_TYPE": 21,2972"AHRS_EKF_TYPE": 11,2973"INS_GYR_CAL": 1,2974})2975self.reboot_sitl()2976self.delay_sim_time(5)2977self.progress("Running accelcal")2978self.run_cmd(2979mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,2980p5=4,2981timeout=5,2982)29832984self.wait_ready_to_arm()2985self.arm_vehicle()2986self.fly_mission(mission)29872988def wait_and_maintain_wind_estimate(2989self,2990want_speed,2991want_dir,2992timeout=10,2993speed_tolerance=0.5,2994dir_tolerance=5,2995**kwargs):2996'''wait for wind estimate to reach speed and direction'''29972998def validator(last, _min, _max):2999'''returns false of spd or direction is too-far wrong'''3000(spd, di) = last3001_min_spd, _min_dir = _min3002_max_spd, _max_dir = _max3003if spd < _min_spd or spd > _max_spd:3004return False3005# my apologies to whoever is staring at this and wondering3006# why we're not wrapping angles here...3007if di < _min_dir or di > _max_dir:3008return False3009return True30103011def value_getter():3012'''returns a tuple of (wind_speed, wind_dir), where wind_dir is 45 if3013wind is coming from NE'''3014m = self.assert_receive_message("WIND")3015return (m.speed, m.direction)30163017class ValueAverager(object):3018def __init__(self):3019self.speed_average = -13020self.dir_average = -13021self.count = 0.030223023def add_value(self, value):3024(spd, di) = value3025if self.speed_average == -1:3026self.speed_average = spd3027self.dir_average = di3028else:3029self.speed_average += spd3030self.di_average += spd3031self.count += 13032return (self.speed_average/self.count, self.dir_average/self.count)30333034def reset(self):3035self.count = 03036self.speed_average = -13037self.dir_average = -130383039self.wait_and_maintain_range(3040value_name="WindEstimates",3041minimum=(want_speed-speed_tolerance, want_dir-dir_tolerance),3042maximum=(want_speed+speed_tolerance, want_dir+dir_tolerance),3043current_value_getter=value_getter,3044value_averager=ValueAverager(),3045validator=lambda last, _min, _max: validator(last, _min, _max),3046timeout=timeout,3047**kwargs3048)30493050def WindEstimates(self):3051'''fly non-external AHRS, ensure wind estimate correct'''3052self.set_parameters({3053"SIM_WIND_SPD": 5,3054"SIM_WIND_DIR": 45,3055})3056self.wait_ready_to_arm()3057self.takeoff(70) # default wind sim wind is a sqrt function up to 60m3058self.change_mode('LOITER')3059# use default estimator to determine when to check others:3060self.wait_and_maintain_wind_estimate(5, 45, timeout=120)30613062for ahrs_type in 0, 2, 3, 10:3063self.start_subtest("Checking AHRS_EKF_TYPE=%u" % ahrs_type)3064self.set_parameter("AHRS_EKF_TYPE", ahrs_type)3065self.wait_and_maintain_wind_estimate(30665, 45,3067speed_tolerance=1,3068timeout=303069)3070self.fly_home_land_and_disarm()30713072def VectorNavEAHRS(self):3073'''Test VectorNav EAHRS support'''3074self.fly_external_AHRS("VectorNav", 1, "ap1.txt")30753076def MicroStrainEAHRS5(self):3077'''Test MicroStrain EAHRS series 5 support'''3078self.fly_external_AHRS("MicroStrain5", 2, "ap1.txt")30793080def MicroStrainEAHRS7(self):3081'''Test MicroStrain EAHRS series 7 support'''3082self.fly_external_AHRS("MicroStrain7", 7, "ap1.txt")30833084def InertialLabsEAHRS(self):3085'''Test InertialLabs EAHRS support'''3086self.fly_external_AHRS("ILabs", 5, "ap1.txt")30873088def GpsSensorPreArmEAHRS(self):3089'''Test pre-arm checks related to EAHRS_SENSORS using the MicroStrain7 driver'''3090self.customise_SITL_commandline(["--serial4=sim:MicroStrain7"])30913092self.set_parameters({3093"EAHRS_TYPE": 7,3094"SERIAL4_PROTOCOL": 36,3095"SERIAL4_BAUD": 230400,3096"GPS1_TYPE": 0, # Disabled (simulate user setup error)3097"GPS2_TYPE": 0, # Disabled (simulate user setup error)3098"AHRS_EKF_TYPE": 11,3099"INS_GYR_CAL": 1,3100"EAHRS_SENSORS": 13, # GPS is enabled3101})3102self.reboot_sitl()3103self.delay_sim_time(5)3104self.progress("Running accelcal")3105self.run_cmd(3106mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,3107p5=4,3108timeout=5,3109)31103111self.assert_prearm_failure("ExternalAHRS: Incorrect number", # Cut short due to message limits.3112timeout=30,3113other_prearm_failures_fatal=False)31143115self.set_parameters({3116"EAHRS_TYPE": 7,3117"SERIAL4_PROTOCOL": 36,3118"SERIAL4_BAUD": 230400,3119"GPS1_TYPE": 1, # Auto3120"GPS2_TYPE": 21, # EARHS3121"AHRS_EKF_TYPE": 11,3122"INS_GYR_CAL": 1,3123"EAHRS_SENSORS": 13, # GPS is enabled3124})3125self.reboot_sitl()3126self.delay_sim_time(5)3127self.progress("Running accelcal")3128self.run_cmd(3129mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,3130p5=4,3131timeout=5,3132)3133# Check prearm success with MicroStrain when the first GPS is occupied by another GPS.3134# This supports the use case of comparing MicroStrain dual antenna to another GPS.3135self.wait_ready_to_arm()31363137def get_accelvec(self, m):3138return Vector3(m.xacc, m.yacc, m.zacc) * 0.001 * 9.8131393140def get_gyrovec(self, m):3141return Vector3(m.xgyro, m.ygyro, m.zgyro) * 0.001 * math.degrees(1)31423143def IMUTempCal(self):3144'''Test IMU temperature calibration'''3145self.progress("Setting up SITL temperature profile")3146self.set_parameters({3147"SIM_IMUT1_ENABLE" : 1,3148"SIM_IMUT1_ACC1_X" : 120000.000000,3149"SIM_IMUT1_ACC1_Y" : -190000.000000,3150"SIM_IMUT1_ACC1_Z" : 1493.864746,3151"SIM_IMUT1_ACC2_X" : -51.624416,3152"SIM_IMUT1_ACC2_Y" : 10.364172,3153"SIM_IMUT1_ACC2_Z" : -7878.000000,3154"SIM_IMUT1_ACC3_X" : -0.514242,3155"SIM_IMUT1_ACC3_Y" : 0.862218,3156"SIM_IMUT1_ACC3_Z" : -234.000000,3157"SIM_IMUT1_GYR1_X" : -5122.513817,3158"SIM_IMUT1_GYR1_Y" : -3250.470428,3159"SIM_IMUT1_GYR1_Z" : -2136.346676,3160"SIM_IMUT1_GYR2_X" : 30.720505,3161"SIM_IMUT1_GYR2_Y" : 17.778447,3162"SIM_IMUT1_GYR2_Z" : 0.765997,3163"SIM_IMUT1_GYR3_X" : -0.003572,3164"SIM_IMUT1_GYR3_Y" : 0.036346,3165"SIM_IMUT1_GYR3_Z" : 0.015457,3166"SIM_IMUT1_TMAX" : 70.0,3167"SIM_IMUT1_TMIN" : -20.000000,3168"SIM_IMUT2_ENABLE" : 1,3169"SIM_IMUT2_ACC1_X" : -160000.000000,3170"SIM_IMUT2_ACC1_Y" : 198730.000000,3171"SIM_IMUT2_ACC1_Z" : 27812.000000,3172"SIM_IMUT2_ACC2_X" : 30.658159,3173"SIM_IMUT2_ACC2_Y" : 32.085022,3174"SIM_IMUT2_ACC2_Z" : 1572.000000,3175"SIM_IMUT2_ACC3_X" : 0.102912,3176"SIM_IMUT2_ACC3_Y" : 0.229734,3177"SIM_IMUT2_ACC3_Z" : 172.000000,3178"SIM_IMUT2_GYR1_X" : 3173.925644,3179"SIM_IMUT2_GYR1_Y" : -2368.312836,3180"SIM_IMUT2_GYR1_Z" : -1796.497177,3181"SIM_IMUT2_GYR2_X" : 13.029696,3182"SIM_IMUT2_GYR2_Y" : -10.349280,3183"SIM_IMUT2_GYR2_Z" : -15.082653,3184"SIM_IMUT2_GYR3_X" : 0.004831,3185"SIM_IMUT2_GYR3_Y" : -0.020528,3186"SIM_IMUT2_GYR3_Z" : 0.009469,3187"SIM_IMUT2_TMAX" : 70.000000,3188"SIM_IMUT2_TMIN" : -20.000000,3189"SIM_IMUT_END" : 45.000000,3190"SIM_IMUT_START" : 3.000000,3191"SIM_IMUT_TCONST" : 75.000000,3192"SIM_DRIFT_SPEED" : 0,3193"INS_GYR_CAL" : 0,3194})31953196self.set_parameter("SIM_IMUT_FIXED", 12)3197self.progress("Running accel cal")3198self.run_cmd(3199mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,3200p5=4,3201timeout=5,3202)3203self.progress("Running gyro cal")3204self.run_cmd(3205mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,3206p5=1,3207timeout=5,3208)3209self.set_parameters({3210"SIM_IMUT_FIXED": 0,3211"INS_TCAL1_ENABLE": 2,3212"INS_TCAL1_TMAX": 42,3213"INS_TCAL2_ENABLE": 2,3214"INS_TCAL2_TMAX": 42,3215"SIM_SPEEDUP": 200,3216})3217self.set_parameter("LOG_DISARMED", 1)3218self.reboot_sitl()32193220self.progress("Waiting for IMU temperature")3221self.assert_reach_imu_temperature(43, timeout=600)32223223if self.get_parameter("INS_TCAL1_ENABLE") != 1.0:3224raise NotAchievedException("TCAL1 did not complete")3225if self.get_parameter("INS_TCAL2_ENABLE") != 1.0:3226raise NotAchievedException("TCAL2 did not complete")32273228self.progress("Logging with calibration enabled")3229self.reboot_sitl()32303231self.assert_reach_imu_temperature(43, timeout=600)32323233self.progress("Testing with compensation enabled")32343235test_temperatures = range(10, 45, 5)3236corrected = {}3237uncorrected = {}32383239for temp in test_temperatures:3240self.progress("Testing temperature %.1f" % temp)3241self.set_parameter("SIM_IMUT_FIXED", temp)3242self.delay_sim_time(2)3243for msg in ['RAW_IMU', 'SCALED_IMU2']:3244m = self.assert_receive_message(msg, timeout=2)3245temperature = m.temperature*0.0132463247if abs(temperature - temp) > 0.2:3248raise NotAchievedException("incorrect %s temperature %.1f should be %.1f" % (msg, temperature, temp))32493250accel = self.get_accelvec(m)3251gyro = self.get_gyrovec(m)3252accel2 = accel + Vector3(0, 0, 9.81)32533254corrected[temperature] = (accel2, gyro)32553256self.progress("Testing with compensation disabled")3257self.set_parameters({3258"INS_TCAL1_ENABLE": 0,3259"INS_TCAL2_ENABLE": 0,3260})32613262gyro_threshold = 0.23263accel_threshold = 0.232643265for temp in test_temperatures:3266self.progress("Testing temperature %.1f" % temp)3267self.set_parameter("SIM_IMUT_FIXED", temp)3268self.wait_heartbeat()3269self.wait_heartbeat()3270for msg in ['RAW_IMU', 'SCALED_IMU2']:3271m = self.assert_receive_message(msg, timeout=2)3272temperature = m.temperature*0.0132733274if abs(temperature - temp) > 0.2:3275raise NotAchievedException("incorrect %s temperature %.1f should be %.1f" % (msg, temperature, temp))32763277accel = self.get_accelvec(m)3278gyro = self.get_gyrovec(m)32793280accel2 = accel + Vector3(0, 0, 9.81)3281uncorrected[temperature] = (accel2, gyro)32823283for temp in test_temperatures:3284(accel, gyro) = corrected[temp]3285self.progress("Corrected gyro at %.1f %s" % (temp, gyro))3286self.progress("Corrected accel at %.1f %s" % (temp, accel))32873288for temp in test_temperatures:3289(accel, gyro) = uncorrected[temp]3290self.progress("Uncorrected gyro at %.1f %s" % (temp, gyro))3291self.progress("Uncorrected accel at %.1f %s" % (temp, accel))32923293bad_value = False3294for temp in test_temperatures:3295(accel, gyro) = corrected[temp]3296if gyro.length() > gyro_threshold:3297raise NotAchievedException("incorrect corrected at %.1f gyro %s" % (temp, gyro))32983299if accel.length() > accel_threshold:3300raise NotAchievedException("incorrect corrected at %.1f accel %s" % (temp, accel))33013302(accel, gyro) = uncorrected[temp]3303if gyro.length() > gyro_threshold*2:3304bad_value = True33053306if accel.length() > accel_threshold*2:3307bad_value = True33083309if not bad_value:3310raise NotAchievedException("uncompensated IMUs did not vary enough")33113312# the above tests change the internal persistent state of the3313# vehicle in ways that autotest doesn't track (magically set3314# parameters). So wipe the vehicle's eeprom:3315self.reset_SITL_commandline()33163317def EKFlaneswitch(self):3318'''Test EKF3 Affinity and Lane Switching'''33193320# new lane swtich available only with EK33321self.set_parameters({3322"EK3_ENABLE": 1,3323"EK2_ENABLE": 0,3324"AHRS_EKF_TYPE": 3,3325"EK3_AFFINITY": 15, # enable affinity for all sensors3326"EK3_IMU_MASK": 3, # use only 2 IMUs3327"GPS2_TYPE": 1,3328"SIM_GPS2_ENABLE": 1,3329"SIM_BARO_COUNT": 2,3330"SIM_BAR2_DISABLE": 0,3331"ARSPD2_TYPE": 2,3332"ARSPD2_USE": 1,3333"ARSPD2_PIN": 2,3334})33353336# some parameters need reboot to take effect3337self.reboot_sitl()33383339self.lane_switches = []33403341# add an EKF lane switch hook3342def statustext_hook(mav, message):3343if message.get_type() != 'STATUSTEXT':3344return3345# example msg: EKF3 lane switch 13346if not message.text.startswith("EKF3 lane switch "):3347return3348newlane = int(message.text[-1])3349self.lane_switches.append(newlane)3350self.install_message_hook_context(statustext_hook)33513352# get flying3353self.takeoff(alt=50)3354self.change_mode('CIRCLE')33553356###################################################################3357self.progress("Checking EKF3 Lane Switching trigger from all sensors")3358###################################################################3359self.start_subtest("ACCELEROMETER: Change z-axis offset")3360# create an accelerometer error by changing the Z-axis offset3361self.context_collect("STATUSTEXT")3362old_parameter = self.get_parameter("INS_ACCOFFS_Z")3363self.wait_statustext(3364text="EKF3 lane switch",3365timeout=30,3366the_function=self.set_parameter("INS_ACCOFFS_Z", old_parameter + 5),3367check_context=True)3368if self.lane_switches != [1]:3369raise NotAchievedException("Expected lane switch 1, got %s" % str(self.lane_switches[-1]))3370# Cleanup3371self.set_parameter("INS_ACCOFFS_Z", old_parameter)3372self.context_clear_collection("STATUSTEXT")3373self.wait_heading(0, accuracy=10, timeout=60)3374self.wait_heading(180, accuracy=10, timeout=60)3375###################################################################3376self.start_subtest("BAROMETER: Freeze to last measured value")3377self.context_collect("STATUSTEXT")3378# create a barometer error by inhibiting any pressure change while changing altitude3379old_parameter = self.get_parameter("SIM_BAR2_FREEZE")3380self.set_parameter("SIM_BAR2_FREEZE", 1)3381self.wait_statustext(3382text="EKF3 lane switch",3383timeout=30,3384the_function=lambda: self.set_rc(2, 2000),3385check_context=True)3386if self.lane_switches != [1, 0]:3387raise NotAchievedException("Expected lane switch 0, got %s" % str(self.lane_switches[-1]))3388# Cleanup3389self.set_rc(2, 1500)3390self.set_parameter("SIM_BAR2_FREEZE", old_parameter)3391self.context_clear_collection("STATUSTEXT")3392self.wait_heading(0, accuracy=10, timeout=60)3393self.wait_heading(180, accuracy=10, timeout=60)3394###################################################################3395self.start_subtest("GPS: Apply GPS Velocity Error in NED")3396self.context_push()3397self.context_collect("STATUSTEXT")33983399# create a GPS velocity error by adding a random 2m/s3400# noise on each axis3401def sim_gps_verr():3402self.set_parameters({3403"SIM_GPS1_VERR_X": self.get_parameter("SIM_GPS1_VERR_X") + 2,3404"SIM_GPS1_VERR_Y": self.get_parameter("SIM_GPS1_VERR_Y") + 2,3405"SIM_GPS1_VERR_Z": self.get_parameter("SIM_GPS1_VERR_Z") + 2,3406})3407self.wait_statustext(text="EKF3 lane switch", timeout=30, the_function=sim_gps_verr, check_context=True)3408if self.lane_switches != [1, 0, 1]:3409raise NotAchievedException("Expected lane switch 1, got %s" % str(self.lane_switches[-1]))3410# Cleanup3411self.context_pop()3412self.context_clear_collection("STATUSTEXT")3413self.wait_heading(0, accuracy=10, timeout=60)3414self.wait_heading(180, accuracy=10, timeout=60)3415###################################################################3416self.start_subtest("MAGNETOMETER: Change X-Axis Offset")3417self.context_collect("STATUSTEXT")3418# create a magnetometer error by changing the X-axis offset3419old_parameter = self.get_parameter("SIM_MAG2_OFS_X")3420self.wait_statustext(3421text="EKF3 lane switch",3422timeout=30,3423the_function=self.set_parameter("SIM_MAG2_OFS_X", old_parameter + 150),3424check_context=True)3425if self.lane_switches != [1, 0, 1, 0]:3426raise NotAchievedException("Expected lane switch 0, got %s" % str(self.lane_switches[-1]))3427# Cleanup3428self.set_parameter("SIM_MAG2_OFS_X", old_parameter)3429self.context_clear_collection("STATUSTEXT")3430self.wait_heading(0, accuracy=10, timeout=60)3431self.wait_heading(180, accuracy=10, timeout=60)3432###################################################################3433self.start_subtest("AIRSPEED: Fail to constant value")3434self.context_push()3435self.context_collect("STATUSTEXT")34363437old_parameter = self.get_parameter("SIM_ARSPD_FAIL")34383439def fail_speed():3440self.change_mode("GUIDED")3441loc = self.mav.location()3442self.run_cmd_int(3443mavutil.mavlink.MAV_CMD_DO_REPOSITION,3444p5=int(loc.lat * 1e7),3445p6=int(loc.lng * 1e7),3446p7=50, # alt3447frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,3448)3449self.delay_sim_time(5)3450# create an airspeed sensor error by freezing to the3451# current airspeed then changing the airspeed demand3452# to a higher value and waiting for the TECS speed3453# loop to diverge3454m = self.mav.recv_match(type='VFR_HUD', blocking=True)3455self.set_parameter("SIM_ARSPD_FAIL", m.airspeed)3456self.run_cmd(3457mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED,3458p1=0, # airspeed3459p2=30,3460p3=-1, # throttle / no change3461p4=0, # absolute values3462)3463self.wait_statustext(text="EKF3 lane switch", timeout=30, the_function=fail_speed, check_context=True)3464if self.lane_switches != [1, 0, 1, 0, 1]:3465raise NotAchievedException("Expected lane switch 1, got %s" % str(self.lane_switches[-1]))3466# Cleanup3467self.set_parameter("SIM_ARSPD_FAIL", old_parameter)3468self.change_mode('CIRCLE')3469self.context_pop()3470self.context_clear_collection("STATUSTEXT")3471self.wait_heading(0, accuracy=10, timeout=60)3472self.wait_heading(180, accuracy=10, timeout=60)3473###################################################################3474self.progress("GYROSCOPE: Change Y-Axis Offset")3475self.context_collect("STATUSTEXT")3476# create a gyroscope error by changing the Y-axis offset3477old_parameter = self.get_parameter("INS_GYR2OFFS_Y")3478self.wait_statustext(3479text="EKF3 lane switch",3480timeout=30,3481the_function=self.set_parameter("INS_GYR2OFFS_Y", old_parameter + 1),3482check_context=True)3483if self.lane_switches != [1, 0, 1, 0, 1, 0]:3484raise NotAchievedException("Expected lane switch 0, got %s" % str(self.lane_switches[-1]))3485# Cleanup3486self.set_parameter("INS_GYR2OFFS_Y", old_parameter)3487self.context_clear_collection("STATUSTEXT")3488###################################################################34893490self.disarm_vehicle(force=True)34913492def FenceAltCeilFloor(self):3493'''Tests the fence ceiling and floor'''3494self.set_parameters({3495"FENCE_TYPE": 9, # Set fence type to max and min alt3496"FENCE_ACTION": 0, # Set action to report3497"FENCE_ALT_MAX": 200,3498"FENCE_ALT_MIN": 100,3499})35003501# Grab Home Position3502self.wait_ready_to_arm()3503startpos = self.mav.location()35043505cruise_alt = 1503506self.takeoff(cruise_alt)35073508# note that while we enable the fence here, since the action3509# is set to report-only the fence continues to show as3510# not-enabled in the assert calls below3511self.do_fence_enable()35123513self.progress("Fly above ceiling and check for breach")3514self.change_altitude(startpos.alt + cruise_alt + 80)3515self.assert_fence_sys_status(True, False, False)35163517self.progress("Return to cruise alt")3518self.change_altitude(startpos.alt + cruise_alt)35193520self.progress("Ensure breach has clearned")3521self.assert_fence_sys_status(True, False, True)35223523self.progress("Fly below floor and check for breach")3524self.change_altitude(startpos.alt + cruise_alt - 80)35253526self.progress("Ensure breach has clearned")3527self.assert_fence_sys_status(True, False, False)35283529self.do_fence_disable()35303531self.fly_home_land_and_disarm(timeout=150)35323533def FenceMinAltAutoEnable(self):3534'''Tests autoenablement of the alt min fence and fences on arming'''3535self.set_parameters({3536"FENCE_TYPE": 9, # Set fence type to min alt and max alt3537"FENCE_ACTION": 1, # Set action to RTL3538"FENCE_ALT_MIN": 25,3539"FENCE_ALT_MAX": 100,3540"FENCE_AUTOENABLE": 3,3541"FENCE_ENABLE" : 0,3542"RTL_AUTOLAND" : 2,3543})35443545# check we can takeoff again3546for i in [1, 2]:3547# Grab Home Position3548self.wait_ready_to_arm()3549self.arm_vehicle()3550# max alt fence should now be enabled3551if i == 1:3552self.assert_fence_enabled()35533554self.takeoff(alt=50, mode='TAKEOFF')3555self.change_mode("FBWA")3556self.set_rc(3, 1100) # lower throttle35573558self.progress("Waiting for RTL")3559tstart = self.get_sim_time()3560mode = "RTL"3561while not self.mode_is(mode, drain_mav=False):3562self.mav.messages['HEARTBEAT'].custom_mode3563self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3564self.mav.flightmode, mode, self.get_altitude(relative=True)))3565if (self.get_sim_time_cached() > tstart + 120):3566raise WaitModeTimeout("Did not change mode")3567self.progress("Got mode %s" % mode)3568self.fly_home_land_and_disarm()3569self.change_mode("FBWA")3570self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_ALL)3571self.set_current_waypoint(0, check_afterwards=False)3572self.set_rc(3, 1000) # lower throttle35733574def FenceMinAltEnableAutoland(self):3575'''Tests autolanding when alt min fence is enabled'''3576self.set_parameters({3577"FENCE_TYPE": 12, # Set fence type to min alt and max alt3578"FENCE_ACTION": 1, # Set action to RTL3579"FENCE_ALT_MIN": 20,3580"FENCE_AUTOENABLE": 0,3581"FENCE_ENABLE" : 1,3582"RTL_AUTOLAND" : 2,3583})35843585# Grab Home Position3586self.wait_ready_to_arm()3587self.arm_vehicle()35883589self.takeoff(alt=50, mode='TAKEOFF')3590self.change_mode("FBWA")3591self.set_rc(3, 1100) # lower throttle35923593self.progress("Waiting for RTL")3594tstart = self.get_sim_time()3595mode = "RTL"3596while not self.mode_is(mode, drain_mav=False):3597self.mav.messages['HEARTBEAT'].custom_mode3598self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3599self.mav.flightmode, mode, self.get_altitude(relative=True)))3600if (self.get_sim_time_cached() > tstart + 120):3601raise WaitModeTimeout("Did not change mode")3602self.progress("Got mode %s" % mode)3603# switch to FBWA3604self.change_mode("FBWA")3605self.set_rc(3, 1500) # raise throttle3606self.wait_altitude(25, 35, timeout=50, relative=True)3607self.set_rc(3, 1000) # lower throttle3608# Now check we can land3609self.fly_home_land_and_disarm()36103611def FenceMinAltAutoEnableAbort(self):3612'''Tests autoenablement of the alt min fence and fences on arming'''3613self.set_parameters({3614"FENCE_TYPE": 8, # Set fence type to min alt3615"FENCE_ACTION": 1, # Set action to RTL3616"FENCE_ALT_MIN": 25,3617"FENCE_ALT_MAX": 100,3618"FENCE_AUTOENABLE": 3,3619"FENCE_ENABLE" : 0,3620"RTL_AUTOLAND" : 2,3621})36223623self.wait_ready_to_arm()3624self.arm_vehicle()36253626self.takeoff(alt=50, mode='TAKEOFF')3627self.change_mode("FBWA")3628# min alt fence should now be enabled3629self.assert_fence_enabled()3630self.set_rc(3, 1100) # lower throttle36313632self.progress("Waiting for RTL")3633tstart = self.get_sim_time()3634mode = "RTL"3635while not self.mode_is(mode, drain_mav=False):3636self.mav.messages['HEARTBEAT'].custom_mode3637self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3638self.mav.flightmode, mode, self.get_altitude(relative=True)))3639if (self.get_sim_time_cached() > tstart + 120):3640raise WaitModeTimeout("Did not change mode")3641self.progress("Got mode %s" % mode)36423643self.load_generic_mission("flaps.txt")3644self.change_mode("AUTO")3645self.wait_distance_to_waypoint(8, 100, 10000000)3646self.set_current_waypoint(8)3647# abort the landing3648self.wait_altitude(10, 20, timeout=200, relative=True)3649self.change_mode("CRUISE")3650self.set_rc(2, 1200)3651# self.set_rc(3, 1600) # raise throttle3652self.wait_altitude(30, 40, timeout=200, relative=True)3653# min alt fence should now be re-enabled3654self.assert_fence_enabled()36553656self.change_mode("AUTO")3657self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_ALL)3658self.fly_home_land_and_disarm(timeout=150)36593660def FenceAutoEnableDisableSwitch(self):3661'''Tests autoenablement of regular fences and manual disablement'''3662self.set_parameters({3663"FENCE_TYPE": 9, # Set fence type to min alt, max alt3664"FENCE_ACTION": 1, # Set action to RTL3665"FENCE_ALT_MIN": 50,3666"FENCE_ALT_MAX": 100,3667"FENCE_AUTOENABLE": 2,3668"FENCE_OPTIONS" : 1,3669"FENCE_ENABLE" : 1,3670"FENCE_RADIUS" : 300,3671"FENCE_RET_ALT" : 0,3672"FENCE_RET_RALLY" : 0,3673"FENCE_TOTAL" : 0,3674"RTL_ALTITUDE" : 75,3675"TKOFF_ALT" : 75,3676"RC7_OPTION" : 11, # AC_Fence uses Aux switch functionality3677})3678self.reboot_sitl()3679self.context_collect("STATUSTEXT")36803681fence_bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE3682# Grab Home Position3683self.mav.recv_match(type='HOME_POSITION', blocking=True)3684self.set_rc(7, 1000) # Turn fence off with aux function, does not impact later auto-enable36853686self.wait_ready_to_arm()36873688self.progress("Check fence disabled at boot")3689m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3690if (m.onboard_control_sensors_enabled & fence_bit):3691raise NotAchievedException("Fence is enabled at boot")36923693cruise_alt = 753694self.takeoff(cruise_alt, mode='TAKEOFF')36953696self.progress("Fly above ceiling and check there is a breach")3697self.change_mode('FBWA')3698self.set_rc(3, 2000)3699self.set_rc(2, 1000)37003701self.wait_statustext("Max Alt fence breached", timeout=10, check_context=True)3702self.wait_mode('RTL')37033704m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3705if (m.onboard_control_sensors_health & fence_bit):3706raise NotAchievedException("Fence ceiling not breached")37073708self.set_rc(3, 1500)3709self.set_rc(2, 1500)37103711self.progress("Wait for RTL alt reached")3712self.wait_altitude(cruise_alt-5, cruise_alt+5, relative=True, timeout=30)37133714self.progress("Return to cruise alt")3715self.set_rc(3, 1500)3716self.change_altitude(cruise_alt, relative=True)37173718self.progress("Check fence breach cleared")3719m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3720if (not (m.onboard_control_sensors_health & fence_bit)):3721raise NotAchievedException("Fence breach not cleared")37223723self.progress("Fly below floor and check for breach")3724self.set_rc(2, 2000)3725self.wait_statustext("Min Alt fence breached", timeout=10, check_context=True)3726self.wait_mode("RTL")3727m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3728if (m.onboard_control_sensors_health & fence_bit):3729raise NotAchievedException("Fence floor not breached")37303731self.change_mode("FBWA")37323733self.progress("Fly above floor and check fence is enabled")3734self.set_rc(3, 2000)3735self.change_altitude(75, relative=True)3736m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3737if (not (m.onboard_control_sensors_enabled & fence_bit)):3738raise NotAchievedException("Fence Floor not enabled")37393740self.progress("Toggle fence enable/disable")3741self.set_rc(7, 2000)3742self.delay_sim_time(2)3743self.set_rc(7, 1000)3744self.delay_sim_time(2)37453746self.progress("Check fence is disabled")3747m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3748if (m.onboard_control_sensors_enabled & fence_bit):3749raise NotAchievedException("Fence disable with switch failed")37503751self.progress("Fly below floor and check for no breach")3752self.change_altitude(40, relative=True)3753m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3754if (not (m.onboard_control_sensors_health & fence_bit)):3755raise NotAchievedException("Fence floor breached")37563757self.progress("Return to cruise alt")3758self.set_rc(3, 1500)3759self.change_altitude(cruise_alt, relative=True)3760self.fly_home_land_and_disarm(timeout=250)37613762def FenceCircleExclusionAutoEnable(self):3763'''Tests autolanding when alt min fence is enabled'''3764self.set_parameters({3765"FENCE_TYPE": 2, # Set fence type to circle3766"FENCE_ACTION": 1, # Set action to RTL3767"FENCE_AUTOENABLE": 2,3768"FENCE_ENABLE" : 0,3769"RTL_AUTOLAND" : 2,3770})37713772fence_loc = self.home_position_as_mav_location()3773self.location_offset_ne(fence_loc, 300, 0)37743775self.upload_fences_from_locations([(3776mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION, {3777"radius" : 100,3778"loc" : fence_loc3779}3780)])37813782self.takeoff(alt=50, mode='TAKEOFF')3783self.change_mode("FBWA")3784self.set_rc(3, 1100) # lower throttle37853786self.progress("Waiting for RTL")3787self.wait_mode('RTL')3788# Now check we can land3789self.fly_home_land_and_disarm()37903791def FenceEnableDisableSwitch(self):3792'''Tests enablement and disablement of fences on a switch'''3793fence_bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE37943795self.set_parameters({3796"FENCE_TYPE": 4, # Set fence type to polyfence3797"FENCE_ACTION": 6, # Set action to GUIDED3798"FENCE_ALT_MIN": 10,3799"FENCE_ENABLE" : 0,3800"RC7_OPTION" : 11, # AC_Fence uses Aux switch functionality3801})38023803self.progress("Checking fence is not present before being configured")3804m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3805self.progress("Got (%s)" % str(m))3806if (m.onboard_control_sensors_enabled & fence_bit):3807raise NotAchievedException("Fence enabled before being configured")38083809self.wait_ready_to_arm()3810# takeoff at a lower altitude to avoid immediately breaching polyfence3811self.takeoff(alt=25)3812self.change_mode("FBWA")38133814self.load_fence("CMAC-fence.txt")38153816self.set_rc_from_map({38173: 1500,38187: 2000,3819}) # Turn fence on with aux function38203821m = self.mav.recv_match(type='FENCE_STATUS', blocking=True, timeout=2)3822self.progress("Got (%s)" % str(m))3823if m is None:3824raise NotAchievedException("Got FENCE_STATUS unexpectedly")38253826self.progress("Checking fence is initially OK")3827self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE,3828present=True,3829enabled=True,3830healthy=True,3831verbose=False,3832timeout=30)38333834self.progress("Waiting for GUIDED")3835tstart = self.get_sim_time()3836mode = "GUIDED"3837while not self.mode_is(mode, drain_mav=False):3838self.mav.messages['HEARTBEAT'].custom_mode3839self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3840self.mav.flightmode, mode, self.get_altitude(relative=True)))3841if (self.get_sim_time_cached() > tstart + 120):3842raise WaitModeTimeout("Did not change mode")3843self.progress("Got mode %s" % mode)3844# check we are in breach3845self.assert_fence_enabled()38463847self.set_rc_from_map({38487: 1000,3849}) # Turn fence off with aux function38503851# wait to no longer be in breach3852self.delay_sim_time(5)3853self.assert_fence_disabled()38543855self.fly_home_land_and_disarm(timeout=250)3856self.do_fence_disable() # Ensure the fence is disabled after test38573858def FenceEnableDisableAux(self):3859'''Tests enablement and disablement of fences via aux command'''3860fence_bit = mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE38613862enable = 03863self.set_parameters({3864"FENCE_TYPE": 12, # Set fence type to polyfence + AltMin3865"FENCE_ALT_MIN": 10,3866"FENCE_ENABLE" : enable,3867})38683869if not enable:3870self.progress("Checking fence is not present before being configured")3871m = self.mav.recv_match(type='SYS_STATUS', blocking=True)3872self.progress("Got (%s)" % str(m))3873if (m.onboard_control_sensors_enabled & fence_bit):3874raise NotAchievedException("Fence enabled before being configured")38753876self.load_fence("CMAC-fence.txt")38773878self.wait_ready_to_arm()3879# takeoff at a lower altitude to avoid immediately breaching polyfence3880self.takeoff(alt=25)3881self.change_mode("CRUISE")3882self.wait_distance(150, accuracy=20)38833884self.run_auxfunc(388511,38862,3887want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED3888)38893890m = self.mav.recv_match(type='FENCE_STATUS', blocking=True, timeout=2)3891self.progress("Got (%s)" % str(m))3892if m is None:3893raise NotAchievedException("Got FENCE_STATUS unexpectedly")38943895self.progress("Checking fence is initially OK")3896self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_GEOFENCE,3897present=True,3898enabled=True,3899healthy=True,3900verbose=False,3901timeout=30)39023903self.progress("Waiting for RTL")3904tstart = self.get_sim_time()3905mode = "RTL"3906while not self.mode_is(mode, drain_mav=False):3907self.mav.messages['HEARTBEAT'].custom_mode3908self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3909self.mav.flightmode, mode, self.get_altitude(relative=True)))3910if (self.get_sim_time_cached() > tstart + 120):3911raise WaitModeTimeout("Did not change mode")3912self.progress("Got mode %s" % mode)3913# check we are in breach3914self.assert_fence_enabled()3915self.assert_fence_sys_status(True, True, False)39163917# wait until we get home3918self.wait_distance_to_home(50, 100, timeout=200)3919# now check we are now not in breach3920self.assert_fence_sys_status(True, True, True)3921# Turn fence off with aux function3922self.run_auxfunc(392311,39240,3925want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED3926)3927# switch back to cruise3928self.change_mode("CRUISE")3929self.wait_distance(150, accuracy=20)39303931# re-enable the fences3932self.run_auxfunc(393311,39342,3935want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED3936)39373938m = self.mav.recv_match(type='FENCE_STATUS', blocking=True, timeout=2)3939self.progress("Got (%s)" % str(m))3940if m is None:3941raise NotAchievedException("Got FENCE_STATUS unexpectedly")39423943self.progress("Waiting for RTL")3944tstart = self.get_sim_time()3945mode = "RTL"3946while not self.mode_is(mode, drain_mav=False):3947self.mav.messages['HEARTBEAT'].custom_mode3948self.progress("mav.flightmode=%s Want=%s Alt=%f" % (3949self.mav.flightmode, mode, self.get_altitude(relative=True)))3950if (self.get_sim_time_cached() > tstart + 120):3951raise WaitModeTimeout("Did not change mode")3952self.progress("Got mode %s" % mode)39533954# wait to no longer be in breach3955self.wait_distance_to_home(50, 100, timeout=200)3956self.assert_fence_sys_status(True, True, True)39573958# fly home and land with fences still enabled3959self.fly_home_land_and_disarm(timeout=250)3960self.do_fence_disable() # Ensure the fence is disabled after test39613962def FenceBreachedChangeMode(self):3963'''Tests manual mode change after fence breach, as set with FENCE_OPTIONS'''3964""" Attempts to change mode while a fence is breached.3965mode should change should fail if fence option bit is set"""3966self.set_parameters({3967"FENCE_ACTION": 1,3968"FENCE_TYPE": 4,3969})3970home_loc = self.mav.location()3971locs = [3972mavutil.location(home_loc.lat - 0.001, home_loc.lng - 0.001, 0, 0),3973mavutil.location(home_loc.lat - 0.001, home_loc.lng + 0.001, 0, 0),3974mavutil.location(home_loc.lat + 0.001, home_loc.lng + 0.001, 0, 0),3975mavutil.location(home_loc.lat + 0.001, home_loc.lng - 0.001, 0, 0),3976]3977self.upload_fences_from_locations([3978(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, locs),3979])3980self.delay_sim_time(1)3981self.wait_ready_to_arm()3982self.takeoff(alt=50)3983self.change_mode("CRUISE")3984self.wait_distance(250, accuracy=15)39853986self.progress("Enable fence and initiate fence action")3987self.do_fence_enable()3988self.assert_fence_enabled()3989self.wait_mode("RTL") # We should RTL because of fence breach39903991self.progress("User mode change to cruise should retrigger fence action")3992try:3993# mode change should time out, 'WaitModeTimeout' exception is the desired resut3994# cant wait too long or the vehicle will be inside fence and allow the mode change3995self.change_mode("CRUISE", timeout=10)3996raise NotAchievedException("Should not change mode in fence breach")3997except WaitModeTimeout:3998pass3999except Exception as e:4000raise e40014002# enable mode change4003self.set_parameter("FENCE_OPTIONS", 0)4004self.progress("Check user mode change to LOITER is allowed")4005self.change_mode("LOITER")40064007# Fly for 20 seconds and make sure still in LOITER mode4008self.delay_sim_time(20)4009if not self.mode_is("LOITER"):4010raise NotAchievedException("Fence should not re-trigger")40114012# reset options parameter4013self.set_parameter("FENCE_OPTIONS", 1)40144015self.progress("Test complete, disable fence and come home")4016self.do_fence_disable()4017self.fly_home_land_and_disarm()40184019def FenceNoFenceReturnPoint(self):4020'''Tests calculated return point during fence breach when no fence return point present'''4021""" Attempts to change mode while a fence is breached.4022This should revert to the mode specified by the fence action. """4023want_radius = 100 # Fence Return Radius4024self.set_parameters({4025"FENCE_ACTION": 6,4026"FENCE_TYPE": 4,4027"RTL_RADIUS": want_radius,4028"NAVL1_LIM_BANK": 60,4029})4030home_loc = self.mav.location()4031locs = [4032mavutil.location(home_loc.lat - 0.003, home_loc.lng - 0.001, 0, 0),4033mavutil.location(home_loc.lat - 0.003, home_loc.lng + 0.003, 0, 0),4034mavutil.location(home_loc.lat + 0.001, home_loc.lng + 0.003, 0, 0),4035mavutil.location(home_loc.lat + 0.001, home_loc.lng - 0.001, 0, 0),4036]4037self.upload_fences_from_locations([4038(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, locs),4039])4040self.delay_sim_time(1)4041self.wait_ready_to_arm()4042self.takeoff(alt=50)4043self.change_mode("CRUISE")4044self.wait_distance(150, accuracy=20)40454046self.progress("Enable fence and initiate fence action")4047self.do_fence_enable()4048self.assert_fence_enabled()4049self.wait_mode("GUIDED", timeout=120) # We should RTL because of fence breach4050self.delay_sim_time(60)40514052items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)4053if len(items) != 4:4054raise NotAchievedException("Unexpected fencepoint count (want=%u got=%u)" % (4, len(items)))40554056# Check there are no fence return points specified still4057for fence_loc in items:4058if fence_loc.command == mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT:4059raise NotAchievedException(4060"Unexpected fence return point found (%u) got %u" %4061(fence_loc.command,4062mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT))40634064# Work out the approximate return point when no fence return point present4065# Logic taken from AC_PolyFence_loader.cpp4066min_loc = self.mav.location()4067max_loc = self.mav.location()4068for new_loc in locs:4069if new_loc.lat < min_loc.lat:4070min_loc.lat = new_loc.lat4071if new_loc.lng < min_loc.lng:4072min_loc.lng = new_loc.lng4073if new_loc.lat > max_loc.lat:4074max_loc.lat = new_loc.lat4075if new_loc.lng > max_loc.lng:4076max_loc.lng = new_loc.lng40774078# Generate the return location based on min and max locs4079ret_lat = (min_loc.lat + max_loc.lat) / 24080ret_lng = (min_loc.lng + max_loc.lng) / 24081ret_loc = mavutil.location(ret_lat, ret_lng, 0, 0)4082self.progress("Return loc: (%s)" % str(ret_loc))40834084# Wait for guided return to vehicle calculated fence return location4085self.wait_distance_to_location(ret_loc, 90, 110)4086self.wait_circling_point_with_radius(ret_loc, 92)40874088self.progress("Test complete, disable fence and come home")4089self.do_fence_disable()4090self.fly_home_land_and_disarm()40914092def FenceNoFenceReturnPointInclusion(self):4093'''Tests using home as fence return point when none is present, and no inclusion fence is uploaded'''4094""" Test result when a breach occurs and No fence return point is present and4095no inclusion fence is present and exclusion fence is present """4096want_radius = 100 # Fence Return Radius40974098self.set_parameters({4099"FENCE_ACTION": 6,4100"FENCE_TYPE": 2,4101"FENCE_RADIUS": 300,4102"RTL_RADIUS": want_radius,4103"NAVL1_LIM_BANK": 60,4104})41054106self.clear_fence()41074108self.delay_sim_time(1)4109self.wait_ready_to_arm()4110home_loc = self.mav.location()4111self.takeoff(alt=50)4112self.change_mode("CRUISE")4113self.wait_distance(150, accuracy=20)41144115self.progress("Enable fence and initiate fence action")4116self.do_fence_enable()4117self.assert_fence_enabled()4118self.wait_mode("GUIDED") # We should RTL because of fence breach4119self.delay_sim_time(30)41204121items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)4122if len(items) != 0:4123raise NotAchievedException("Unexpected fencepoint count (want=%u got=%u)" % (0, len(items)))41244125# Check there are no fence return points specified still4126for fence_loc in items:4127if fence_loc.command == mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT:4128raise NotAchievedException(4129"Unexpected fence return point found (%u) got %u" %4130(fence_loc.command,4131mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT))41324133# Wait for guided return to vehicle calculated fence return location4134self.wait_distance_to_location(home_loc, 90, 110)4135self.wait_circling_point_with_radius(home_loc, 92)41364137self.progress("Test complete, disable fence and come home")4138self.do_fence_disable()4139self.fly_home_land_and_disarm()41404141def FenceDisableUnderAction(self):4142'''Tests Disabling fence while undergoing action caused by breach'''4143""" Fence breach will cause the vehicle to enter guided mode.4144Upon breach clear, check the vehicle is in the expected mode"""4145self.set_parameters({4146"FENCE_ALT_MIN": 50, # Sets the fence floor4147"FENCE_TYPE": 8, # Only use fence floor for breaches4148})4149self.wait_ready_to_arm()41504151def attempt_fence_breached_disable(start_mode, end_mode, expected_mode, action):4152self.set_parameter("FENCE_ACTION", action) # Set Fence Action to Guided4153self.change_mode(start_mode)4154self.arm_vehicle()4155self.do_fence_enable()4156self.assert_fence_enabled()4157self.wait_mode(expected_mode)4158self.do_fence_disable()4159self.assert_fence_disabled()4160self.wait_mode(end_mode)4161self.disarm_vehicle(force=True)41624163attempt_fence_breached_disable(start_mode="FBWA", end_mode="RTL", expected_mode="RTL", action=1)4164attempt_fence_breached_disable(start_mode="FBWA", end_mode="FBWA", expected_mode="GUIDED", action=6)4165attempt_fence_breached_disable(start_mode="FBWA", end_mode="FBWA", expected_mode="GUIDED", action=7)41664167def _MAV_CMD_DO_AUX_FUNCTION(self, run_cmd):4168'''Test triggering Auxiliary Functions via mavlink'''4169self.context_collect('STATUSTEXT')4170self.run_auxfunc(64, 2, run_cmd=run_cmd) # 64 == reverse throttle4171self.wait_statustext("RevThrottle: ENABLE", check_context=True)4172self.run_auxfunc(64, 0, run_cmd=run_cmd)4173self.wait_statustext("RevThrottle: DISABLE", check_context=True)4174self.run_auxfunc(65, 2, run_cmd=run_cmd) # 65 == GPS_DISABLE41754176self.start_subtest("Bad auxfunc")4177self.run_auxfunc(417865231,41792,4180want_result=mavutil.mavlink.MAV_RESULT_FAILED,4181run_cmd=run_cmd,4182)41834184self.start_subtest("Bad switchpos")4185self.run_auxfunc(418662,418717,4188want_result=mavutil.mavlink.MAV_RESULT_DENIED,4189run_cmd=run_cmd,4190)41914192def MAV_CMD_DO_AUX_FUNCTION(self):4193'''Test triggering Auxiliary Functions via mavlink'''4194self._MAV_CMD_DO_AUX_FUNCTION(run_cmd=self.run_cmd)4195self._MAV_CMD_DO_AUX_FUNCTION(run_cmd=self.run_cmd_int)41964197def FlyEachFrame(self):4198'''Fly each supported internal frame'''4199vinfo = vehicleinfo.VehicleInfo()4200vinfo_options = vinfo.options[self.vehicleinfo_key()]4201known_broken_frames = {4202"plane-tailsitter": "unstable in hover; unflyable in cruise",4203"quadplane-can" : "needs CAN periph",4204"stratoblimp" : "not expected to fly normally",4205"glider" : "needs balloon lift",4206}4207for frame in sorted(vinfo_options["frames"].keys()):4208self.start_subtest("Testing frame (%s)" % str(frame))4209if frame in known_broken_frames:4210self.progress("Actually, no I'm not - it is known-broken (%s)" %4211(known_broken_frames[frame]))4212continue4213frame_bits = vinfo_options["frames"][frame]4214print("frame_bits: %s" % str(frame_bits))4215if frame_bits.get("external", False):4216self.progress("Actually, no I'm not - it is an external simulation")4217continue4218model = frame_bits.get("model", frame)4219defaults = self.model_defaults_filepath(frame)4220if not isinstance(defaults, list):4221defaults = [defaults]4222self.customise_SITL_commandline(4223[],4224defaults_filepath=defaults,4225model=model,4226wipe=True,4227)4228mission_file = "basic.txt"4229quadplane = self.get_parameter('Q_ENABLE')4230if quadplane:4231mission_file = "basic-quadplane.txt"4232tailsitter = self.get_parameter('Q_TAILSIT_ENABLE')4233if tailsitter:4234# tailsitter needs extra re-boot to pick up the rotated AHRS view4235self.reboot_sitl()4236self.wait_ready_to_arm()4237self.arm_vehicle()4238self.fly_mission(mission_file, strict=False, quadplane=quadplane, mission_timeout=400.0)4239self.wait_disarmed()42404241def AutoLandMode(self):4242'''Test AUTOLAND mode'''4243self.customise_SITL_commandline(["--home", "-35.362938,149.165085,585,173"])4244self.context_collect('STATUSTEXT')4245self.takeoff(alt=80, mode='TAKEOFF')4246self.wait_text("Autoland direction", check_context=True)4247self.change_mode(26)4248self.wait_disarmed(120)4249self.progress("Check the landed heading matches takeoff")4250self.wait_heading(173, accuracy=5, timeout=1)4251loc = mavutil.location(-35.362938, 149.165085, 585, 173)4252if self.get_distance(loc, self.mav.location()) > 35:4253raise NotAchievedException("Did not land close to home")42544255def RCDisableAirspeedUse(self):4256'''Test RC DisableAirspeedUse option'''4257self.set_parameter("RC9_OPTION", 106)4258self.delay_sim_time(5)4259self.set_rc(9, 1000)4260self.wait_sensor_state(4261mavutil.mavlink.MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE,4262True,4263True,4264True)4265self.set_rc(9, 2000)4266self.wait_sensor_state(4267mavutil.mavlink.MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE,4268True,4269False,4270True)4271self.set_rc(9, 1000)4272self.wait_sensor_state(4273mavutil.mavlink.MAV_SYS_STATUS_SENSOR_DIFFERENTIAL_PRESSURE,4274True,4275True,4276True)42774278def WatchdogHome(self):4279'''Ensure home is restored after watchdog reset'''4280if self.gdb:4281# we end up signalling the wrong process. I think.4282# Probably need to have a "sitl_pid()" method to get the4283# ardupilot process's PID.4284self.progress("######## Skipping WatchdogHome test under GDB")4285return42864287ex = None4288try:4289self.progress("Enabling watchdog")4290self.set_parameter("BRD_OPTIONS", 1 << 0)4291self.reboot_sitl()4292self.wait_ready_to_arm()4293self.progress("Explicitly setting home to a known location")4294orig_home = self.poll_home_position()4295new_home = orig_home4296new_home.latitude = new_home.latitude + 10004297new_home.longitude = new_home.longitude + 20004298new_home.altitude = new_home.altitude + 300000 # 300 metres4299self.run_cmd_int(4300mavutil.mavlink.MAV_CMD_DO_SET_HOME,4301p5=new_home.latitude,4302p6=new_home.longitude,4303p7=new_home.altitude/1000.0, # mm => m4304)4305old_bootcount = self.get_parameter('STAT_BOOTCNT')4306self.progress("Forcing watchdog reset")4307os.kill(self.sitl.pid, signal.SIGALRM)4308self.detect_and_handle_reboot(old_bootcount)4309self.wait_statustext("WDG:")4310self.wait_statustext("IMU1 is using GPS") # won't be come armable4311self.progress("Verifying home position")4312post_reboot_home = self.poll_home_position()4313delta = self.get_distance_int(new_home, post_reboot_home)4314max_delta = 14315if delta > max_delta:4316raise NotAchievedException(4317"New home not where it should be (dist=%f) (want=%s) (got=%s)" %4318(delta, str(new_home), str(post_reboot_home)))4319except Exception as e:4320self.print_exception_caught(e)4321ex = e43224323self.reboot_sitl()43244325if ex is not None:4326raise ex43274328def AUTOTUNE(self):4329'''Test AutoTune mode'''4330self.takeoff(100)4331self.change_mode('AUTOTUNE')4332self.context_collect('STATUSTEXT')4333tstart = self.get_sim_time()4334axis = "Roll"4335rc_value = 10004336while True:4337timeout = 6004338if self.get_sim_time() - tstart > timeout:4339raise NotAchievedException("Did not complete within %u seconds" % timeout)4340try:4341m = self.wait_statustext("%s: Finished" % axis, check_context=True, timeout=0.1)4342self.progress("Got %s" % str(m))4343if axis == "Roll":4344axis = "Pitch"4345elif axis == "Pitch":4346break4347else:4348raise ValueError("Bug: %s" % axis)4349except AutoTestTimeoutException:4350pass4351self.delay_sim_time(1)43524353if rc_value == 1000:4354rc_value = 20004355elif rc_value == 2000:4356rc_value = 10004357elif rc_value == 1000:4358rc_value = 20004359else:4360raise ValueError("Bug")43614362if axis == "Roll":4363self.set_rc(1, rc_value)4364self.set_rc(2, 1500)4365elif axis == "Pitch":4366self.set_rc(1, 1500)4367self.set_rc(2, rc_value)4368else:4369raise ValueError("Bug")43704371tdelta = self.get_sim_time() - tstart4372self.progress("Finished in %0.1f seconds" % (tdelta,))43734374self.set_rc(1, 1500)4375self.set_rc(2, 1500)43764377self.change_mode('FBWA')4378self.fly_home_land_and_disarm(timeout=tdelta+240)43794380def AutotuneFiltering(self):4381'''Test AutoTune mode with filter updates disabled'''4382self.set_parameters({4383"AUTOTUNE_OPTIONS": 3,4384# some filtering is required for autotune to complete4385"RLL_RATE_FLTD": 10,4386"PTCH_RATE_FLTD": 10,4387"RLL_RATE_FLTT": 20,4388"PTCH_RATE_FLTT": 20,4389})4390self.AUTOTUNE()43914392def LandingDrift(self):4393'''Circuit with baro drift'''4394self.customise_SITL_commandline([], wipe=True)43954396self.set_analog_rangefinder_parameters()43974398self.set_parameters({4399"SIM_BARO_DRIFT": -0.02,4400"SIM_TERRAIN": 0,4401"RNGFND_LANDING": 1,4402"LAND_SLOPE_RCALC": 2,4403"LAND_ABORT_DEG": 1,4404})44054406self.reboot_sitl()44074408self.wait_ready_to_arm()4409self.arm_vehicle()44104411# Load and start mission4412self.load_mission("ap-circuit.txt", strict=True)4413self.set_current_waypoint(1, check_afterwards=True)4414self.change_mode('AUTO')4415self.wait_current_waypoint(1, timeout=5)4416self.wait_groundspeed(0, 10, timeout=5)44174418# Wait for landing waypoint4419self.wait_current_waypoint(9, timeout=1200)44204421# Wait for landing restart4422self.wait_current_waypoint(5, timeout=60)44234424# Wait for landing waypoint (second attempt)4425self.wait_current_waypoint(9, timeout=1200)44264427self.wait_disarmed(timeout=180)44284429def TakeoffAuto1(self):4430'''Test the behaviour of an AUTO takeoff, pt1.'''4431'''4432Conditions:4433- ARSPD_USE=14434- TKOFF_OPTIONS[0]=04435- TKOFF_THR_MAX < THR_MAX4436'''44374438self.customise_SITL_commandline(4439[],4440model='plane-catapult',4441defaults_filepath=self.model_defaults_filepath("plane")4442)4443self.set_parameters({4444"ARSPD_USE": 1.0,4445"THR_MAX": 100.0,4446"TKOFF_THR_MAX": 80.0,4447"TKOFF_THR_MINACC": 3.0,4448"TECS_PITCH_MAX": 35.0,4449"PTCH_LIM_MAX_DEG": 35.0,4450"RTL_AUTOLAND": 2, # The mission contains a DO_LAND_START item.4451})44524453# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4454self.wait_ready_to_arm()44554456# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4457self.load_mission("catapult.txt", strict=True)4458self.change_mode('AUTO')44594460self.arm_vehicle()44614462# Throw the catapult.4463self.set_servo(7, 2000)44644465# Wait until we're midway through the climb.4466test_alt = 504467self.wait_altitude(test_alt, test_alt+2, relative=True)44684469# Ensure that by then the aircraft still goes at max allowed throttle.4470target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4471self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)44724473# Wait for landing waypoint.4474self.wait_current_waypoint(11, timeout=1200)4475self.wait_disarmed(120)44764477def TakeoffAuto2(self):4478'''Test the behaviour of an AUTO takeoff, pt2.'''4479'''4480Conditions:4481- ARSPD_USE=04482- TKOFF_OPTIONS[0]=04483- TKOFF_THR_MAX > THR_MAX4484'''44854486self.customise_SITL_commandline(4487[],4488model='plane-catapult',4489defaults_filepath=self.model_defaults_filepath("plane")4490)4491self.set_parameters({4492"ARSPD_USE": 0.0,4493"THR_MAX": 80.0,4494"TKOFF_THR_MAX": 100.0,4495"TKOFF_THR_MINACC": 3.0,4496"TECS_PITCH_MAX": 35.0,4497"PTCH_LIM_MAX_DEG": 35.0,4498"RTL_AUTOLAND": 2, # The mission contains a DO_LAND_START item.4499})45004501# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4502self.wait_ready_to_arm()45034504# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4505self.load_mission("catapult.txt", strict=True)4506self.change_mode('AUTO')45074508self.arm_vehicle()45094510# Throw the catapult.4511self.set_servo(7, 2000)45124513# Wait until we're midway through the climb.4514test_alt = 504515self.wait_altitude(test_alt, test_alt+2, relative=True)45164517# Ensure that by then the aircraft still goes at max allowed throttle.4518target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4519self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)45204521# Wait for landing waypoint.4522self.wait_current_waypoint(11, timeout=1200)4523self.wait_disarmed(120)45244525def TakeoffAuto3(self):4526'''Test the behaviour of an AUTO takeoff, pt3.'''4527'''4528Conditions:4529- ARSPD_USE=14530- TKOFF_OPTIONS[0]=14531'''45324533self.customise_SITL_commandline(4534[],4535model='plane-catapult',4536defaults_filepath=self.model_defaults_filepath("plane")4537)4538self.set_parameters({4539"ARSPD_USE": 1.0,4540"THR_MAX": 80.0,4541"THR_MIN": 0.0,4542"TKOFF_OPTIONS": 1.0,4543"TKOFF_THR_MAX": 100.0,4544"TKOFF_THR_MINACC": 3.0,4545"TECS_PITCH_MAX": 35.0,4546"TKOFF_THR_MAX_T": 3.0,4547"PTCH_LIM_MAX_DEG": 35.0,4548"RTL_AUTOLAND": 2, # The mission contains a DO_LAND_START item.4549})45504551# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4552self.wait_ready_to_arm()45534554# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4555self.load_mission("catapult.txt", strict=True)4556self.change_mode('AUTO')45574558self.arm_vehicle()45594560# Throw the catapult.4561self.set_servo(7, 2000)45624563# Ensure that TKOFF_THR_MAX_T is respected.4564self.delay_sim_time(self.get_parameter("TKOFF_THR_MAX_T")-1)4565target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4566self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)45674568# Ensure that after that the aircraft does not go full throttle anymore.4569test_alt = 504570self.wait_altitude(test_alt, test_alt+2, relative=True)4571w = vehicle_test_suite.WaitAndMaintainServoChannelValue(4572self,45733, # throttle45741000+10*self.get_parameter("TKOFF_THR_MAX")-10,4575comparator=operator.lt,4576minimum_duration=1,4577)4578w.run()45794580# Wait for landing waypoint.4581self.wait_current_waypoint(11, timeout=1200)4582self.wait_disarmed(120)45834584def TakeoffAuto4(self):4585'''Test the behaviour of an AUTO takeoff, pt4.'''4586'''4587Conditions:4588- ARSPD_USE=04589- TKOFF_OPTIONS[0]=14590'''45914592self.customise_SITL_commandline(4593[],4594model='plane-catapult',4595defaults_filepath=self.model_defaults_filepath("plane")4596)4597self.set_parameters({4598"ARSPD_USE": 0.0,4599"THR_MAX": 80.0,4600"THR_MIN": 0.0,4601"TKOFF_OPTIONS": 1.0,4602"TKOFF_THR_MAX": 100.0,4603"TKOFF_THR_MINACC": 3.0,4604"TECS_PITCH_MAX": 35.0,4605"TKOFF_THR_MAX_T": 3.0,4606"PTCH_LIM_MAX_DEG": 35.0,4607"RTL_AUTOLAND": 2, # The mission contains a DO_LAND_START item.4608})46094610self.wait_ready_to_arm()46114612# Load and start mission. It contains a MAV_CMD_NAV_TAKEOFF item at 100m.4613self.load_mission("catapult.txt", strict=True)4614self.change_mode('AUTO')46154616self.arm_vehicle()46174618# Throw the catapult.4619self.set_servo(7, 2000)46204621# Ensure that TKOFF_THR_MAX_T is respected.4622self.delay_sim_time(self.get_parameter("TKOFF_THR_MAX_T")-1)4623target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4624self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)46254626# Ensure that after that the aircraft still goes to maximum throttle.4627test_alt = 504628self.wait_altitude(test_alt, test_alt+2, relative=True)4629target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4630self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)46314632# Wait for landing waypoint.4633self.wait_current_waypoint(11, timeout=1200)4634self.wait_disarmed(120)46354636def TakeoffTakeoff1(self):4637'''Test the behaviour of a takeoff in TAKEOFF mode, pt1.'''4638'''4639Conditions:4640- ARSPD_USE=14641- TKOFF_OPTIONS[0]=04642- TKOFF_THR_MAX < THR_MAX4643'''46444645self.customise_SITL_commandline(4646[],4647model='plane-catapult',4648defaults_filepath=self.model_defaults_filepath("plane")4649)4650self.set_parameters({4651"ARSPD_USE": 1.0,4652"THR_MAX": 100.0,4653"TKOFF_LVL_ALT": 30.0,4654"TKOFF_ALT": 80.0,4655"TKOFF_OPTIONS": 0.0,4656"TKOFF_THR_MINACC": 3.0,4657"TKOFF_THR_MAX": 80.0,4658"TECS_PITCH_MAX": 35.0,4659"PTCH_LIM_MAX_DEG": 35.0,4660})4661self.change_mode("TAKEOFF")46624663self.wait_ready_to_arm()4664self.arm_vehicle()46654666# Throw the catapult.4667self.set_servo(7, 2000)46684669# Check whether we're at max throttle below TKOFF_LVL_ALT.4670test_alt = self.get_parameter("TKOFF_LVL_ALT")-104671self.wait_altitude(test_alt, test_alt+2, relative=True)4672target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4673self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)46744675# Check whether we're still at max throttle past TKOFF_LVL_ALT.4676test_alt = self.get_parameter("TKOFF_LVL_ALT")+104677self.wait_altitude(test_alt, test_alt+2, relative=True)4678target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4679self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)46804681# Wait for the takeoff to complete.4682target_alt = self.get_parameter("TKOFF_ALT")4683self.wait_altitude(target_alt-5, target_alt, relative=True)46844685# Wait a bit for the Takeoff altitude to settle.4686self.delay_sim_time(5)46874688self.fly_home_land_and_disarm()46894690def TakeoffTakeoff2(self):4691'''Test the behaviour of a takeoff in TAKEOFF mode, pt2.'''4692'''4693Conditions:4694- ARSPD_USE=14695- TKOFF_OPTIONS[0]=14696- TKOFF_THR_MAX < THR_MAX4697'''46984699self.customise_SITL_commandline(4700[],4701model='plane-catapult',4702defaults_filepath=self.model_defaults_filepath("plane")4703)4704self.set_parameters({4705"ARSPD_USE": 1.0,4706"THR_MAX": 100.0,4707"TKOFF_LVL_ALT": 30.0,4708"TKOFF_ALT": 80.0,4709"TKOFF_OPTIONS": 1.0,4710"TKOFF_THR_MINACC": 3.0,4711"TKOFF_THR_MAX": 80.0,4712"TECS_PITCH_MAX": 35.0,4713"PTCH_LIM_MAX_DEG": 35.0,4714})4715self.change_mode("TAKEOFF")47164717self.wait_ready_to_arm()4718self.arm_vehicle()47194720# Throw the catapult.4721self.set_servo(7, 2000)47224723# Check whether we're at max throttle below TKOFF_LVL_ALT.4724test_alt = self.get_parameter("TKOFF_LVL_ALT")-104725self.wait_altitude(test_alt, test_alt+2, relative=True)4726target_throttle = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))4727self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)47284729# Check whether we've receded from max throttle past TKOFF_LVL_ALT.4730test_alt = self.get_parameter("TKOFF_LVL_ALT")+104731self.wait_altitude(test_alt, test_alt+2, relative=True)4732thr_min = 1000+10*(self.get_parameter("TKOFF_THR_MIN"))-14733thr_max = 1000+10*(self.get_parameter("TKOFF_THR_MAX"))-104734self.assert_servo_channel_range(3, thr_min, thr_max)47354736# Wait for the takeoff to complete.4737target_alt = self.get_parameter("TKOFF_ALT")4738self.wait_altitude(target_alt-5, target_alt, relative=True)47394740# Wait a bit for the Takeoff altitude to settle.4741self.delay_sim_time(5)47424743self.fly_home_land_and_disarm()47444745def TakeoffTakeoff3(self):4746'''Test the behaviour of a takeoff in TAKEOFF mode, pt3.'''4747'''4748This is the same as case #1, but with disabled airspeed sensor.47494750Conditions:4751- ARSPD_USE=04752- TKOFF_OPTIONS[0]=04753- TKOFF_THR_MAX < THR_MAX4754'''47554756self.customise_SITL_commandline(4757[],4758model='plane-catapult',4759defaults_filepath=self.model_defaults_filepath("plane")4760)4761self.set_parameters({4762"ARSPD_USE": 0.0,4763"THR_MAX": 100.0,4764"TKOFF_DIST": 400.0,4765"TKOFF_LVL_ALT": 30.0,4766"TKOFF_ALT": 100.0,4767"TKOFF_OPTIONS": 0.0,4768"TKOFF_THR_MINACC": 3.0,4769"TKOFF_THR_MAX": 80.0,4770"TECS_PITCH_MAX": 35.0,4771"PTCH_LIM_MAX_DEG": 35.0,4772})4773self.change_mode("TAKEOFF")47744775self.wait_ready_to_arm()4776self.arm_vehicle()47774778# Throw the catapult.4779self.set_servo(7, 2000)47804781# we expect to maintain this throttle level past the takeoff4782# altitude through to our takeoff altitude:4783expected_takeoff_throttle = 1000+10*self.get_parameter("TKOFF_THR_MAX")47844785# Check whether we're at max throttle below TKOFF_LVL_ALT.4786test_alt = self.get_parameter("TKOFF_LVL_ALT")-104787self.wait_altitude(test_alt, test_alt+2, relative=True)4788w = vehicle_test_suite.WaitAndMaintainServoChannelValue(4789self,47903, # throttle4791expected_takeoff_throttle,4792epsilon=10,4793minimum_duration=1,4794)4795w.run()47964797# Check whether we're still at max throttle past TKOFF_LVL_ALT.4798test_alt = self.get_parameter("TKOFF_LVL_ALT")+104799self.wait_altitude(test_alt, test_alt+2, relative=True)48004801w = vehicle_test_suite.WaitAndMaintainServoChannelValue(4802self,48033, # throttle4804expected_takeoff_throttle,4805epsilon=10,4806minimum_duration=1,4807)4808w.run()48094810# Wait for the takeoff to complete.4811target_alt = self.get_parameter("TKOFF_ALT")4812self.wait_altitude(target_alt-2.5, target_alt+2.5, relative=True, minimum_duration=10, timeout=30)48134814self.reboot_sitl(force=True)48154816def TakeoffTakeoff4(self):4817'''Test the behaviour of a takeoff in TAKEOFF mode, pt4.'''4818'''4819This is the same as case #3, but with almost stock parameters and without a catapult.48204821Conditions:4822- ARSPD_USE=04823'''48244825self.customise_SITL_commandline(4826[],4827model='plane-catapult',4828defaults_filepath=self.model_defaults_filepath("plane")4829)4830self.set_parameters({4831"ARSPD_USE": 0.0,4832})4833self.change_mode("TAKEOFF")48344835self.wait_ready_to_arm()4836self.arm_vehicle()48374838# Check whether we're at max throttle below TKOFF_LVL_ALT.4839test_alt = self.get_parameter("TKOFF_LVL_ALT")-104840self.wait_altitude(test_alt, test_alt+2, relative=True)4841target_throttle = 1000+10*(self.get_parameter("THR_MAX"))4842self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)48434844# Check whether we're still at max throttle past TKOFF_LVL_ALT.4845test_alt = self.get_parameter("TKOFF_LVL_ALT")+104846self.wait_altitude(test_alt, test_alt+2, relative=True)4847target_throttle = 1000+10*(self.get_parameter("THR_MAX"))4848self.assert_servo_channel_range(3, target_throttle-10, target_throttle+10)48494850# Wait for the takeoff to complete.4851target_alt = self.get_parameter("TKOFF_ALT")4852self.wait_altitude(target_alt-5, target_alt, relative=True)48534854# Wait a bit for the Takeoff altitude to settle.4855self.delay_sim_time(5)48564857self.fly_home_land_and_disarm()48584859def TakeoffTakeoff5(self):4860'''Test the behaviour of a takeoff with no compass'''4861self.set_parameters({4862"COMPASS_USE": 0,4863"COMPASS_USE2": 0,4864"COMPASS_USE3": 0,4865})4866import copy4867start_loc = copy.copy(SITL_START_LOCATION)4868start_loc.heading = 1754869self.customise_SITL_commandline(["--home=%.9f,%.9f,%.2f,%.1f" % (4870start_loc.lat, start_loc.lng, start_loc.alt, start_loc.heading)])4871self.reboot_sitl()4872self.change_mode("TAKEOFF")48734874# waiting for the EKF to be happy won't work4875self.delay_sim_time(20)4876self.arm_vehicle()48774878target_alt = self.get_parameter("TKOFF_ALT")4879self.wait_altitude(target_alt-5, target_alt, relative=True)48804881# Wait a bit for the Takeoff altitude to settle.4882self.delay_sim_time(5)48834884bearing_margin = 354885loc = self.mav.location()4886bearing_from_home = self.get_bearing(start_loc, loc)4887if bearing_from_home < 0:4888bearing_from_home += 3604889if abs(bearing_from_home - start_loc.heading) > bearing_margin:4890raise NotAchievedException(f"Did not takeoff in the right direction {bearing_from_home}")48914892self.fly_home_land_and_disarm()48934894def TakeoffGround(self):4895'''Test a rolling TAKEOFF.'''48964897self.set_parameters({4898"TKOFF_ROTATE_SPD": 15.0,4899})4900self.change_mode("TAKEOFF")49014902self.wait_ready_to_arm()4903self.arm_vehicle()49044905# Check that we demand minimum pitch below rotation speed.4906self.wait_groundspeed(8, 10)4907m = self.assert_receive_message('NAV_CONTROLLER_OUTPUT', timeout=5)4908nav_pitch = m.nav_pitch4909if nav_pitch > 5.1 or nav_pitch < 4.9:4910raise NotAchievedException(f"Did not achieve correct takeoff pitch ({nav_pitch}).")49114912# Check whether we've achieved correct target pitch after rotation.4913self.wait_groundspeed(23, 24)4914m = self.assert_receive_message('NAV_CONTROLLER_OUTPUT', timeout=5)4915nav_pitch = m.nav_pitch4916if nav_pitch > 15.1 or nav_pitch < 14.9:4917raise NotAchievedException(f"Did not achieve correct takeoff pitch ({nav_pitch}).")49184919self.fly_home_land_and_disarm()49204921def TakeoffIdleThrottle(self):4922'''Apply idle throttle before takeoff.'''4923self.customise_SITL_commandline(4924[],4925model='plane-catapult',4926defaults_filepath=self.model_defaults_filepath("plane")4927)4928self.set_parameters({4929"TKOFF_THR_IDLE": 20.0,4930"TKOFF_THR_MINSPD": 3.0,4931})4932self.change_mode("TAKEOFF")49334934self.wait_ready_to_arm()4935self.arm_vehicle()49364937# Ensure that the throttle rises to idle throttle.4938expected_idle_throttle = 1000+10*self.get_parameter("TKOFF_THR_IDLE")4939self.assert_servo_channel_range(3, expected_idle_throttle-10, expected_idle_throttle+10)49404941# Launch the catapult4942self.set_servo(6, 1000)49434944self.delay_sim_time(5)4945self.change_mode('RTL')49464947self.fly_home_land_and_disarm()49484949def TakeoffBadLevelOff(self):4950'''Ensure that the takeoff can be completed under 0 pitch demand.'''4951'''4952When using no airspeed, the pitch level-off will eventually command 04953pitch demand. Ensure that the plane can climb the final 2m to deem the4954takeoff complete.4955'''49564957self.customise_SITL_commandline(4958[],4959model='plane-catapult',4960defaults_filepath=self.model_defaults_filepath("plane")4961)4962self.set_parameters({4963"ARSPD_USE": 0.0,4964"PTCH_TRIM_DEG": -10.0,4965"RTL_AUTOLAND": 2, # The mission contains a DO_LAND_START item.4966"TKOFF_ALT": 50.0,4967"TKOFF_DIST": 1000.0,4968"TKOFF_THR_MAX": 75.0,4969"TKOFF_THR_MINACC": 3.0,4970})49714972self.load_mission("flaps_tkoff_50.txt")4973self.change_mode('AUTO')49744975self.wait_ready_to_arm()4976self.arm_vehicle()49774978# Throw the catapult.4979self.set_servo(7, 2000)49804981# Wait until we've reached the takeoff altitude.4982target_alt = 504983self.wait_altitude(target_alt-1, target_alt+1, relative=True, timeout=30)49844985self.delay_sim_time(5)49864987self.disarm_vehicle(force=True)49884989def DCMFallback(self):4990'''Really annoy the EKF and force fallback'''4991self.reboot_sitl()4992self.delay_sim_time(30)49934994self.takeoff(50)4995self.change_mode('CIRCLE')4996self.context_push()4997self.context_collect('STATUSTEXT')4998self.set_parameters({4999"EK3_POS_I_GATE": 0,5000"SIM_GPS1_HZ": 1,5001"SIM_GPS1_LAG_MS": 1000,5002})5003self.wait_statustext("DCM Active", check_context=True, timeout=60)5004self.wait_statustext("EKF3 Active", check_context=True)5005self.wait_statustext("DCM Active", check_context=True)5006self.wait_statustext("EKF3 Active", check_context=True)5007self.wait_statustext("DCM Active", check_context=True)5008self.wait_statustext("EKF3 Active", check_context=True)5009self.context_stop_collecting('STATUSTEXT')50105011self.fly_home_land_and_disarm()5012self.context_pop()5013self.reboot_sitl()50145015def ForcedDCM(self):5016'''Switch to DCM mid-flight'''5017self.wait_ready_to_arm()5018self.arm_vehicle()50195020self.takeoff(50)5021self.context_collect('STATUSTEXT')5022self.set_parameter("AHRS_EKF_TYPE", 0)5023self.wait_statustext("DCM Active", check_context=True)5024self.context_stop_collecting('STATUSTEXT')50255026self.fly_home_land_and_disarm()50275028def EFITest(self, efi_type, name, sim_name, check_fuel_flow=True):5029'''method to be called by EFI tests'''5030self.start_subtest("EFI Test for (%s)" % name)5031self.assert_not_receiving_message('EFI_STATUS')5032self.set_parameters({5033'SIM_EFI_TYPE': efi_type,5034'EFI_TYPE': efi_type,5035'SERIAL5_PROTOCOL': 24,5036'RPM1_TYPE': 10,5037})50385039self.customise_SITL_commandline(5040["--serial5=sim:%s" % sim_name,5041],5042)5043self.wait_ready_to_arm()50445045baro_m = self.assert_receive_message("SCALED_PRESSURE")5046self.progress(self.dump_message_verbose(baro_m))5047baro_temperature = baro_m.temperature / 100.0 # cDeg->deg5048m = self.assert_received_message_field_values("EFI_STATUS", {5049"throttle_out": 0,5050"health": 1,5051}, very_verbose=1)50525053if abs(baro_temperature - m.intake_manifold_temperature) > 1:5054raise NotAchievedException(5055"Bad intake manifold temperature (want=%f got=%f)" %5056(baro_temperature, m.intake_manifold_temperature))50575058self.arm_vehicle()50595060self.set_rc(3, 1300)50615062tstart = self.get_sim_time()5063while True:5064now = self.get_sim_time_cached()5065if now - tstart > 10:5066raise NotAchievedException("RPM1 and EFI_STATUS.rpm did not match")5067rpm_m = self.assert_receive_message("RPM", verbose=1)5068want_rpm = 10005069if rpm_m.rpm1 < want_rpm:5070continue50715072m = self.assert_receive_message("EFI_STATUS", verbose=1)5073if abs(m.rpm - rpm_m.rpm1) > 100:5074continue50755076break50775078self.progress("now we're started, check a few more values")5079# note that megasquirt drver doesn't send throttle, so throttle_out is zero!5080m = self.assert_received_message_field_values("EFI_STATUS", {5081"health": 1,5082}, very_verbose=1)5083m = self.wait_message_field_values("EFI_STATUS", {5084"throttle_position": 31,5085"intake_manifold_temperature": 28,5086}, very_verbose=1, epsilon=2)50875088if check_fuel_flow:5089if abs(m.fuel_flow - 0.2) < 0.0001:5090raise NotAchievedException("Expected fuel flow")50915092self.set_rc(3, 1000)50935094# need to force disarm as the is_flying flag can trigger with the engine running5095self.disarm_vehicle(force=True)50965097def MegaSquirt(self):5098'''test MegaSquirt driver'''5099self.EFITest(51001, "MegaSquirt", "megasquirt",5101check_fuel_flow=False,5102)51035104def Hirth(self):5105'''Test Hirth EFI'''5106self.EFITest(8, "Hirth", "hirth")51075108def GlideSlopeThresh(self):5109'''Test rebuild glide slope if above and climbing'''51105111# Test that GLIDE_SLOPE_THRESHOLD correctly controls re-planning glide slope5112# in the scenario that aircraft is above planned slope and slope is positive (climbing).5113#5114#5115# Behaviour with GLIDE_SLOPE_THRESH = 0 (no slope replanning)5116# (2).. __(4)5117# | \..__/5118# | __/5119# (3)5120#5121# Behaviour with GLIDE_SLOPE_THRESH = 5 (slope replanning when >5m error)5122# (2)........__(4)5123# | __/5124# | __/5125# (3)5126# Solid is plan, dots are actual flightpath.51275128self.load_mission('rapid-descent-then-climb.txt', strict=False)51295130self.set_current_waypoint(1)5131self.change_mode('AUTO')5132self.wait_ready_to_arm()5133self.arm_vehicle()51345135#5136# Initial run with GLIDE_SLOPE_THR = 5 (default).5137#5138self.set_parameter("GLIDE_SLOPE_THR", 5)51395140# Wait for waypoint commanding rapid descent, followed by climb.5141self.wait_current_waypoint(5, timeout=1200)51425143# Altitude should not descend significantly below the initial altitude5144init_altitude = self.get_altitude(relative=True, timeout=2)5145timeout = 6005146wpnum = 75147tstart = self.get_sim_time()5148while True:5149if self.get_sim_time() - tstart > timeout:5150raise AutoTestTimeoutException("Did not get wanted current waypoint")51515152if (self.get_altitude(relative=True, timeout=2) - init_altitude) < -10:5153raise NotAchievedException("Descended >10m before reaching desired waypoint,\5154indicating slope was not replanned")51555156seq = self.mav.waypoint_current()5157self.progress("Waiting for wp=%u current=%u" % (wpnum, seq))5158if seq == wpnum:5159break51605161self.set_current_waypoint(2)51625163#5164# Second run with GLIDE_SLOPE_THR = 0 (no re-plan).5165#5166self.set_parameter("GLIDE_SLOPE_THR", 0)51675168# Wait for waypoint commanding rapid descent, followed by climb.5169self.wait_current_waypoint(5, timeout=1200)51705171# This time altitude should descend significantly below the initial altitude5172init_altitude = self.get_altitude(relative=True, timeout=2)5173timeout = 6005174wpnum = 75175tstart = self.get_sim_time()5176while True:5177if self.get_sim_time() - tstart > timeout:5178raise AutoTestTimeoutException("Did not get wanted altitude")51795180seq = self.mav.waypoint_current()5181self.progress("Waiting for wp=%u current=%u" % (wpnum, seq))5182if seq == wpnum:5183raise NotAchievedException("Reached desired waypoint without first decending 10m,\5184indicating slope was replanned unexpectedly")51855186if (self.get_altitude(relative=True, timeout=2) - init_altitude) < -10:5187break51885189# Disarm5190self.wait_disarmed(timeout=600)51915192self.progress("Mission OK")51935194def MAV_CMD_NAV_LOITER_TURNS(self, target_system=1, target_component=1):5195'''test MAV_CMD_NAV_LOITER_TURNS mission item'''5196alt = 1005197seq = 05198items = []5199tests = [5200(self.home_relative_loc_ne(50, -50), 100, 0.3),5201(self.home_relative_loc_ne(100, 50), 1005, 3),5202]5203# add a home position:5204items.append(self.mav.mav.mission_item_int_encode(5205target_system,5206target_component,5207seq, # seq5208mavutil.mavlink.MAV_FRAME_GLOBAL,5209mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,52100, # current52110, # autocontinue52120, # p152130, # p252140, # p352150, # p452160, # latitude52170, # longitude52180, # altitude5219mavutil.mavlink.MAV_MISSION_TYPE_MISSION))5220seq += 152215222# add takeoff5223items.append(self.mav.mav.mission_item_int_encode(5224target_system,5225target_component,5226seq, # seq5227mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,5228mavutil.mavlink.MAV_CMD_NAV_TAKEOFF,52290, # current52300, # autocontinue52310, # p152320, # p252330, # p352340, # p452350, # latitude52360, # longitude5237alt, # altitude5238mavutil.mavlink.MAV_MISSION_TYPE_MISSION))5239seq += 152405241# add circles5242for (loc, radius, turn) in tests:5243items.append(self.mav.mav.mission_item_int_encode(5244target_system,5245target_component,5246seq, # seq5247mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,5248mavutil.mavlink.MAV_CMD_NAV_LOITER_TURNS,52490, # current52500, # autocontinue5251turn, # p152520, # p25253radius, # p352540, # p45255int(loc.lat*1e7), # latitude5256int(loc.lng*1e7), # longitude5257alt, # altitude5258mavutil.mavlink.MAV_MISSION_TYPE_MISSION))5259seq += 152605261# add an RTL5262items.append(self.mav.mav.mission_item_int_encode(5263target_system,5264target_component,5265seq, # seq5266mavutil.mavlink.MAV_FRAME_GLOBAL,5267mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH,52680, # current52690, # autocontinue52700, # p152710, # p252720, # p352730, # p452740, # latitude52750, # longitude52760, # altitude5277mavutil.mavlink.MAV_MISSION_TYPE_MISSION))5278seq += 152795280self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION, items)5281downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)5282ofs = 25283self.progress("Checking downloaded mission is as expected")5284for (loc, radius, turn) in tests:5285downloaded = downloaded_items[ofs]5286if radius > 255:5287# ArduPilot only stores % 105288radius = radius - radius % 105289if downloaded.param3 != radius:5290raise NotAchievedException(5291"Did not get expected radius for item %u; want=%f got=%f" %5292(ofs, radius, downloaded.param3))5293if turn > 0 and turn < 1:5294# ArduPilot stores fractions in 8 bits (*256) and unpacks it (/256)5295turn = int(turn*256) / 256.05296if downloaded.param1 != turn:5297raise NotAchievedException(5298"Did not get expected turn for item %u; want=%f got=%f" %5299(ofs, turn, downloaded.param1))5300ofs += 153015302self.change_mode('AUTO')5303self.wait_ready_to_arm()5304self.arm_vehicle()5305self.set_parameter("NAVL1_LIM_BANK", 50)53065307self.wait_current_waypoint(2)53085309for (loc, expected_radius, _) in tests:5310self.wait_circling_point_with_radius(5311loc,5312expected_radius,5313epsilon=20.0,5314timeout=240,5315)5316self.set_current_waypoint(self.current_waypoint()+1)53175318self.fly_home_land_and_disarm(timeout=180)53195320def MidAirDisarmDisallowed(self):5321'''Ensure mid-air disarm is not possible'''5322self.takeoff(50)5323disarmed = False5324try:5325self.disarm_vehicle()5326disarmed = True5327except ValueError as e:5328self.progress("Got %s" % repr(e))5329if "Expected MAV_RESULT_ACCEPTED got MAV_RESULT_FAILED" not in str(e):5330raise e5331if disarmed:5332raise NotAchievedException("Disarmed when we shouldn't have")5333# should still be able to force-disarm:5334self.disarm_vehicle(force=True)5335self.reboot_sitl()53365337def AerobaticsScripting(self):5338'''Fixed Wing Aerobatics'''5339applet_script = "Aerobatics/FixedWing/plane_aerobatics.lua"5340airshow = "Aerobatics/FixedWing/Schedules/AirShow.txt"5341trick72 = "trick72.txt"53425343model = "plane-3d"53445345self.customise_SITL_commandline(5346[],5347model=model,5348defaults_filepath="Tools/autotest/models/plane-3d.parm",5349wipe=True)53505351self.context_push()5352self.install_applet_script_context(applet_script)5353self.install_applet_script_context(airshow, install_name=trick72)5354self.context_collect('STATUSTEXT')5355self.reboot_sitl()53565357self.set_parameter("TRIK_ENABLE", 1)5358self.set_rc(7, 1000) # disable tricks53595360self.scripting_restart()5361self.wait_text("Enabled 3 aerobatic tricks", check_context=True)5362self.set_parameters({5363"TRIK1_ID": 72,5364"RC7_OPTION" : 300, # activation switch5365"RC9_OPTION" : 301, # selection switch5366"SIM_SPEEDUP": 5, # need to give some cycles to lua5367})53685369self.wait_ready_to_arm()5370self.change_mode("TAKEOFF")5371self.arm_vehicle()5372self.wait_altitude(30, 40, timeout=30, relative=True)5373self.change_mode("CRUISE")53745375self.set_rc(9, 1000) # select first trick5376self.delay_sim_time(1)5377self.set_rc(7, 1500) # show selected trick53785379self.wait_text("Trick 1 selected (SuperAirShow)", check_context=True)5380self.set_rc(7, 2000) # activate trick5381self.wait_text("Trick 1 started (SuperAirShow)", check_context=True)53825383highest_error = 05384while True:5385m = self.mav.recv_match(type='NAMED_VALUE_FLOAT', blocking=True, timeout=2)5386if not m:5387break5388if m.name != 'PERR':5389continue5390highest_error = max(highest_error, m.value)5391if highest_error > 15:5392raise NotAchievedException("path error %.1f" % highest_error)53935394if highest_error == 0:5395raise NotAchievedException("path error not reported")5396self.progress("Finished trick, max error=%.1fm" % highest_error)5397self.disarm_vehicle(force=True)53985399messages = self.context_collection('STATUSTEXT')5400self.context_pop()5401self.reboot_sitl()54025403# check all messages to see if we got all tricks5404tricks = ["Loop", "HalfReverseCubanEight", "ScaleFigureEight", "Immelmann",5405"Split-S", "RollingCircle", "HumptyBump", "HalfCubanEight",5406"BarrelRoll", "CrossBoxTopHat", "TriangularLoop",5407"Finishing SuperAirShow!"]5408texts = [m.text for m in messages]5409for t in tricks:5410if t in texts:5411self.progress("Completed trick %s" % t)5412else:5413raise NotAchievedException("Missing trick %s" % t)54145415def UniversalAutoLandScript(self):5416'''Test UniversalAutoLandScript'''5417applet_script = "UniversalAutoLand.lua"5418self.customise_SITL_commandline(["--home", "-35.362938,149.165085,585,173"])54195420self.install_applet_script_context(applet_script)5421self.context_collect('STATUSTEXT')5422self.set_parameters({5423"SCR_ENABLE" : 1,5424"SCR_VM_I_COUNT" : 1000000,5425"RTL_AUTOLAND" : 25426})5427self.reboot_sitl()5428self.wait_text("Loaded UniversalAutoLand.lua", check_context=True)5429self.set_parameters({5430"AUTOLAND_ENABLE" : 1,5431"AUTOLAND_WP_ALT" : 55,5432"AUTOLAND_WP_DIST" : 4005433})5434self.scripting_restart()5435self.wait_text("Scripting: restarted", check_context=True)54365437self.wait_ready_to_arm()5438self.arm_vehicle()5439self.change_mode("AUTO")5440self.wait_text("Captured initial takeoff direction", check_context=True)54415442self.wait_disarmed(120)5443self.progress("Check the landed heading matches takeoff")5444self.wait_heading(173, accuracy=5, timeout=1)5445loc = mavutil.location(-35.362938, 149.165085, 585, 173)5446if self.get_distance(loc, self.mav.location()) > 35:5447raise NotAchievedException("Did not land close to home")54485449def SDCardWPTest(self):5450'''test BRD_SD_MISSION support'''5451spiral_script = "mission_spiral.lua"54525453self.context_push()5454self.install_example_script(spiral_script)5455self.context_collect('STATUSTEXT')5456self.set_parameters({5457"BRD_SD_MISSION" : 64,5458"SCR_ENABLE" : 1,5459"SCR_VM_I_COUNT" : 10000005460})54615462self.wait_ready_to_arm()5463self.reboot_sitl()54645465self.wait_text("Loaded spiral mission creator", check_context=True)5466self.set_parameters({5467"SCR_USER2": 19, # radius5468"SCR_USER3": -35.36322, # lat5469"SCR_USER4": 149.16525, # lon5470"SCR_USER5": 684.13, # alt5471})54725473count = (65536 // 15) - 154745475self.progress("Creating spiral mission of size %s" % count)5476self.set_parameter("SCR_USER1", count)54775478self.wait_text("Created spiral of size %u" % count, check_context=True)54795480self.progress("Checking spiral before reboot")5481self.set_parameter("SCR_USER6", count)5482self.wait_text("Compared spiral of size %u OK" % count, check_context=True)5483self.set_parameter("SCR_USER6", 0)54845485self.wait_ready_to_arm()5486self.reboot_sitl()5487self.progress("Checking spiral after reboot")5488self.set_parameter("SCR_USER6", count)5489self.wait_text("Compared spiral of size %u OK" % count, check_context=True)54905491self.remove_installed_script(spiral_script)54925493self.context_pop()5494self.wait_ready_to_arm()5495self.reboot_sitl()54965497def MANUAL_CONTROL(self):5498'''test MANUAL_CONTROL mavlink message'''5499self.set_parameter("SYSID_MYGCS", self.mav.source_system)55005501self.progress("Takeoff")5502self.takeoff(alt=50)55035504self.change_mode('FBWA')55055506tstart = self.get_sim_time_cached()5507roll_input = -5005508want_roll_degrees = -125509while True:5510if self.get_sim_time_cached() - tstart > 10:5511raise AutoTestTimeoutException("Did not reach roll")5512self.progress("Sending roll-left")5513self.mav.mav.manual_control_send(55141, # target system551532767, # x (pitch)5516roll_input, # y (roll)551732767, # z (thrust)551832767, # r (yaw)55190) # button mask5520m = self.mav.recv_match(type='ATTITUDE', blocking=True, timeout=1)5521print("m=%s" % str(m))5522if m is None:5523continue5524p = math.degrees(m.roll)5525self.progress("roll=%f want<=%f" % (p, want_roll_degrees))5526if p <= want_roll_degrees:5527break5528self.mav.mav.manual_control_send(55291, # target system553032767, # x (pitch)553132767, # y (roll)553232767, # z (thrust)553332767, # r (yaw)55340) # button mask5535self.fly_home_land_and_disarm()55365537def mission_home_point(self, target_system=1, target_component=1):5538'''just an empty-ish item-int to store home'''5539return self.mav.mav.mission_item_int_encode(5540target_system,5541target_component,55420, # seq5543mavutil.mavlink.MAV_FRAME_GLOBAL,5544mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,55450, # current55460, # autocontinue55470, # p155480, # p255490, # p355500, # p455510, # latitude55520, # longitude55530, # altitude5554mavutil.mavlink.MAV_MISSION_TYPE_MISSION)55555556def mission_jump_tag(self, tag, target_system=1, target_component=1):5557'''create a jump tag mission item'''5558return self.mav.mav.mission_item_int_encode(5559target_system,5560target_component,55610, # seq5562mavutil.mavlink.MAV_FRAME_GLOBAL,5563mavutil.mavlink.MAV_CMD_JUMP_TAG,55640, # current55650, # autocontinue5566tag, # p155670, # p255680, # p355690, # p455700, # latitude55710, # longitude55720, # altitude5573mavutil.mavlink.MAV_MISSION_TYPE_MISSION)55745575def mission_do_jump_tag(self, tag, target_system=1, target_component=1):5576'''create a jump tag mission item'''5577return self.mav.mav.mission_item_int_encode(5578target_system,5579target_component,55800, # seq5581mavutil.mavlink.MAV_FRAME_GLOBAL,5582mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,55830, # current55840, # autocontinue5585tag, # p155860, # p255870, # p355880, # p455890, # latitude55900, # longitude55910, # altitude5592mavutil.mavlink.MAV_MISSION_TYPE_MISSION)55935594def mission_anonymous_waypoint(self, target_system=1, target_component=1):5595'''just a boring waypoint'''5596return self.mav.mav.mission_item_int_encode(5597target_system,5598target_component,55990, # seq5600mavutil.mavlink.MAV_FRAME_GLOBAL,5601mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,56020, # current56030, # autocontinue56040, # p156050, # p256060, # p356070, # p456081, # latitude56091, # longitude56101, # altitude5611mavutil.mavlink.MAV_MISSION_TYPE_MISSION)56125613def renumber_mission_items(self, mission):5614count = 05615for item in mission:5616item.seq = count5617count += 156185619def MissionJumpTags_missing_jump_target(self, target_system=1, target_component=1):5620self.start_subtest("Check missing-jump-tag behaviour")5621jump_target = 25622mission = [5623self.mission_home_point(),5624self.mission_anonymous_waypoint(),5625self.mission_anonymous_waypoint(),5626self.mission_jump_tag(jump_target),5627self.mission_anonymous_waypoint(),5628self.mission_anonymous_waypoint(),5629]5630self.renumber_mission_items(mission)5631self.check_mission_upload_download(mission)5632self.progress("Checking incorrect tag behaviour")5633self.run_cmd(5634mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,5635p1=jump_target + 1,5636want_result=mavutil.mavlink.MAV_RESULT_FAILED5637)5638self.progress("Checking correct tag behaviour")5639self.run_cmd(5640mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,5641p1=jump_target,5642)5643self.assert_current_waypoint(4)56445645def MissionJumpTags_do_jump_to_bad_tag(self, target_system=1, target_component=1):5646mission = [5647self.mission_home_point(),5648self.mission_anonymous_waypoint(),5649self.mission_do_jump_tag(17),5650self.mission_anonymous_waypoint(),5651]5652self.renumber_mission_items(mission)5653self.check_mission_upload_download(mission)5654self.change_mode('AUTO')5655self.arm_vehicle()5656self.set_current_waypoint(2, check_afterwards=False)5657self.assert_mode('RTL')5658self.disarm_vehicle()56595660def MissionJumpTags_jump_tag_at_end_of_mission(self, target_system=1, target_component=1):5661mission = [5662self.mission_home_point(),5663self.mission_anonymous_waypoint(),5664self.mission_jump_tag(17),5665]5666# Jumping to an end of a mission, either DO_JUMP or DO_JUMP_TAG will result in a failed attempt.5667# The failure is from mission::set_current_cmd() returning false if it can not find any NAV5668# commands on or after the index. Two scenarios:5669# 1) AUTO mission triggered: The the set_command will fail and it will cause an RTL event5670# (Harder to test, need vehicle to actually reach the waypoint)5671# 2) GCS/MAVLink: It will return MAV_RESULT_FAILED and there's on change to the mission. (Easy to test)5672self.renumber_mission_items(mission)5673self.check_mission_upload_download(mission)5674self.progress("Checking correct tag behaviour")5675self.change_mode('AUTO')5676self.arm_vehicle()5677self.run_cmd(5678mavutil.mavlink.MAV_CMD_DO_JUMP_TAG,5679p1=17,5680want_result=mavutil.mavlink.MAV_RESULT_FAILED5681)5682self.disarm_vehicle()56835684def MissionJumpTags(self):5685'''test MAV_CMD_JUMP_TAG'''5686self.wait_ready_to_arm()5687self.MissionJumpTags_missing_jump_target()5688self.MissionJumpTags_do_jump_to_bad_tag()5689self.MissionJumpTags_jump_tag_at_end_of_mission()56905691def AltResetBadGPS(self):5692'''Tests the handling of poor GPS lock pre-arm alt resets'''5693self.set_parameters({5694"SIM_GPS1_GLTCH_Z": 0,5695"SIM_GPS1_ACC": 0.3,5696})5697self.wait_ready_to_arm()56985699m = self.assert_receive_message('GLOBAL_POSITION_INT')5700relalt = m.relative_alt*0.0015701if abs(relalt) > 3:5702raise NotAchievedException("Bad relative alt %.1f" % relalt)57035704self.progress("Setting low accuracy, glitching GPS")5705self.set_parameter("SIM_GPS1_ACC", 40)5706self.set_parameter("SIM_GPS1_GLTCH_Z", -47)57075708self.progress("Waiting 10s for height update")5709self.delay_sim_time(10)57105711self.wait_ready_to_arm()5712self.arm_vehicle()57135714m = self.assert_receive_message('GLOBAL_POSITION_INT')5715relalt = m.relative_alt*0.0015716if abs(relalt) > 3:5717raise NotAchievedException("Bad glitching relative alt %.1f" % relalt)57185719self.disarm_vehicle()5720# reboot to clear potentially bad state57215722def trigger_airspeed_cal(self):5723self.run_cmd(5724mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5725p3=1,5726)57275728def AirspeedCal(self):5729'''test Airspeed calibration'''57305731self.start_subtest('1 airspeed sensor')5732self.context_push()5733self.context_collect('STATUSTEXT')5734self.trigger_airspeed_cal()5735self.wait_statustext('Airspeed 1 calibrated', check_context=True)5736self.context_pop()57375738self.context_push()5739self.context_collect('STATUSTEXT')5740self.start_subtest('0 airspeed sensors')5741self.set_parameter('ARSPD_TYPE', 0)5742self.reboot_sitl()5743self.wait_statustext('No airspeed sensor', check_context=True)5744self.trigger_airspeed_cal()5745self.delay_sim_time(5)5746if self.statustext_in_collections('Airspeed 1 calibrated'):5747raise NotAchievedException("Did not disable airspeed sensor?!")5748self.context_pop()57495750self.start_subtest('2 airspeed sensors')5751self.set_parameter('ARSPD_TYPE', 100)5752self.set_parameter('ARSPD2_TYPE', 100)5753self.reboot_sitl()5754self.context_push()5755self.context_collect('STATUSTEXT')5756self.trigger_airspeed_cal()5757self.wait_statustext('Airspeed 1 calibrated', check_context=True)5758self.wait_statustext('Airspeed 2 calibrated', check_context=True)5759self.context_pop()57605761self.reboot_sitl()57625763def RunMissionScript(self):5764'''Test run_mission.py script'''5765script = os.path.join('Tools', 'autotest', 'run_mission.py')5766self.stop_SITL()5767util.run_cmd([5768util.reltopdir(script),5769self.binary,5770'plane',5771self.generic_mission_filepath_for_filename("flaps.txt"),5772])5773self.start_SITL()57745775def MAV_CMD_GUIDED_CHANGE_ALTITUDE(self):5776'''test handling of MAV_CMD_GUIDED_CHANGE_ALTITUDE'''5777self.install_terrain_handlers_context()5778self.start_subtest("set home relative altitude")5779self.takeoff(30, relative=True)5780self.change_mode('GUIDED')5781for alt in 50, 70:5782self.run_cmd_int(5783mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,5784p7=alt,5785frame=mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,5786)5787self.wait_altitude(alt-1, alt+1, timeout=30, relative=True)57885789# test for #245355790self.start_subtest("switch to loiter and resume guided maintains home relative altitude")5791self.change_mode('LOITER')5792self.delay_sim_time(5)5793self.change_mode('GUIDED')5794self.wait_altitude(5795alt-3, # NOTE: reuse of alt from above loop!5796alt+3,5797minimum_duration=10,5798timeout=30,5799relative=True,5800)5801# test that this works if switching between RELATIVE (HOME) and GLOBAL(AMSL)5802self.start_subtest("set global/AMSL altitude, switch to loiter and resume guided")5803alt = 6255804self.run_cmd_int(5805mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,5806p7=alt,5807frame=mavutil.mavlink.MAV_FRAME_GLOBAL,5808)5809self.wait_altitude(alt-3, alt+3, timeout=30, relative=False)5810self.change_mode('LOITER')5811self.delay_sim_time(5)5812self.change_mode('GUIDED')5813self.wait_altitude(5814alt-5, # NOTE: reuse of alt from above CHANGE_ALTITUDE5815alt+5,5816minimum_duration=10,5817timeout=30,5818relative=False,5819)5820# test that this works if switching between RELATIVE (HOME) and terrain5821self.start_subtest("set terrain altitude, switch to loiter and resume guided")5822self.change_mode('GUIDED')5823alt = 1005824self.run_cmd_int(5825mavutil.mavlink.MAV_CMD_GUIDED_CHANGE_ALTITUDE,5826p7=alt,5827frame=mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,5828)5829self.wait_altitude(5830alt-5, # NOTE: reuse of alt from abovE5831alt+5, # use a 5m buffer as the plane needs to go up and down a bit to maintain terrain distance5832minimum_duration=10,5833timeout=30,5834relative=False,5835altitude_source="TERRAIN_REPORT.current_height"5836)5837self.change_mode('LOITER')5838self.delay_sim_time(5)5839self.change_mode('GUIDED')5840self.wait_altitude(5841alt-5, # NOTE: reuse of alt from abovE5842alt+5, # use a 5m buffer as the plane needs to go up and down a bit to maintain terrain distance5843minimum_duration=10,5844timeout=30,5845relative=False,5846altitude_source="TERRAIN_REPORT.current_height"5847)58485849self.delay_sim_time(5)5850self.fly_home_land_and_disarm()58515852def _MAV_CMD_PREFLIGHT_CALIBRATION(self, command):5853self.context_push()5854self.start_subtest("Denied when armed")5855self.wait_ready_to_arm()5856self.arm_vehicle()5857command(5858mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5859p1=1,5860want_result=mavutil.mavlink.MAV_RESULT_FAILED,5861)5862self.disarm_vehicle()58635864self.context_collect('STATUSTEXT')58655866self.start_subtest("gyro cal")5867command(5868mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5869p1=1,5870)58715872self.start_subtest("baro cal")5873command(5874mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5875p3=1,5876)5877self.wait_statustext('Barometer calibration complete', check_context=True)58785879# accelcal skipped here, it is checked elsewhere58805881self.start_subtest("ins trim")5882command(5883mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5884p5=2,5885)58865887# enforced delay between cals:5888self.delay_sim_time(5)58895890self.start_subtest("simple accel cal")5891command(5892mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5893p5=4,5894)5895# simple gyro cal makes the GPS units go unhealthy as they are5896# not maintaining their update rate (gyro cal is synchronous5897# in the main loop). Usually ~30 seconds to recover...5898self.wait_gps_sys_status_not_present_or_enabled_and_healthy(timeout=60)58995900self.start_subtest("force save accels")5901command(5902mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5903p5=76,5904)59055906self.start_subtest("force save compasses")5907command(5908mavutil.mavlink.MAV_CMD_PREFLIGHT_CALIBRATION,5909p2=76,5910)59115912self.context_pop()59135914def MAV_CMD_PREFLIGHT_CALIBRATION(self):5915'''test MAV_CMD_PREFLIGHT_CALIBRATION mavlink handling'''5916self._MAV_CMD_PREFLIGHT_CALIBRATION(self.run_cmd)5917self._MAV_CMD_PREFLIGHT_CALIBRATION(self.run_cmd_int)59185919def MAV_CMD_DO_INVERTED_FLIGHT(self):5920'''fly upside-down mission item'''5921alt = 305922wps = self.create_simple_relhome_mission([5923(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, alt),5924(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 400, 0, alt),5925self.create_MISSION_ITEM_INT(5926mavutil.mavlink.MAV_CMD_DO_INVERTED_FLIGHT,5927p1=1,5928),5929(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, alt),5930self.create_MISSION_ITEM_INT(5931mavutil.mavlink.MAV_CMD_DO_INVERTED_FLIGHT,5932p1=0,5933),5934(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 1200, 0, alt),5935(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH, 0, 0, 0),5936])5937self.check_mission_upload_download(wps)59385939self.change_mode('AUTO')5940self.wait_ready_to_arm()59415942self.arm_vehicle()59435944self.wait_current_waypoint(2) # upright flight5945self.wait_message_field_values("NAV_CONTROLLER_OUTPUT", {5946"nav_roll": 0,5947"nav_pitch": 0,5948}, epsilon=10)59495950def check_altitude(mav, m):5951global initial_airspeed_threshold_reached5952m_type = m.get_type()5953if m_type != 'GLOBAL_POSITION_INT':5954return5955if abs(30 - m.relative_alt * 0.001) > 15:5956raise NotAchievedException("Bad altitude while flying inverted")59575958self.context_push()5959self.install_message_hook_context(check_altitude)59605961self.wait_current_waypoint(4) # inverted flight5962self.wait_message_field_values("NAV_CONTROLLER_OUTPUT", {5963"nav_roll": 180,5964"nav_pitch": 9,5965}, epsilon=10,)59665967self.wait_current_waypoint(6) # upright flight5968self.wait_message_field_values("NAV_CONTROLLER_OUTPUT", {5969"nav_roll": 0,5970"nav_pitch": 0,5971}, epsilon=10)59725973self.context_pop() # remove the check_altitude call59745975self.wait_current_waypoint(7)59765977self.fly_home_land_and_disarm()59785979def MAV_CMD_DO_AUTOTUNE_ENABLE(self):5980'''test enabling autotune via mavlink'''5981self.context_collect('STATUSTEXT')5982self.run_cmd(mavutil.mavlink.MAV_CMD_DO_AUTOTUNE_ENABLE, p1=1)5983self.wait_statustext('Started autotune', check_context=True)5984self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_AUTOTUNE_ENABLE, p1=0)5985self.wait_statustext('Stopped autotune', check_context=True)59865987def DO_PARACHUTE(self):5988'''test triggering parachute via mavlink'''5989self.set_parameters({5990"CHUTE_ENABLED": 1,5991"CHUTE_TYPE": 10,5992"SERVO9_FUNCTION": 27,5993"SIM_PARA_ENABLE": 1,5994"SIM_PARA_PIN": 9,5995"FS_LONG_ACTN": 3,5996})5997for command in self.run_cmd, self.run_cmd_int:5998self.wait_servo_channel_value(9, 1100)5999self.wait_ready_to_arm()6000self.arm_vehicle()6001command(6002mavutil.mavlink.MAV_CMD_DO_PARACHUTE,6003p1=mavutil.mavlink.PARACHUTE_RELEASE,6004)6005self.wait_servo_channel_value(9, 1300)6006self.disarm_vehicle()6007self.reboot_sitl()60086009def _MAV_CMD_DO_GO_AROUND(self, command):6010self.load_mission("mission.txt")6011self.set_parameter("RTL_AUTOLAND", 3)6012self.change_mode('AUTO')6013self.wait_ready_to_arm()6014self.arm_vehicle()6015self.wait_current_waypoint(6)6016command(mavutil.mavlink.MAV_CMD_DO_GO_AROUND, p1=150)6017self.wait_current_waypoint(5)6018self.wait_altitude(135, 165, relative=True)6019self.wait_disarmed(timeout=300)60206021def MAV_CMD_DO_GO_AROUND(self):6022'''test MAV_CMD_DO_GO_AROUND as a mavlink command'''6023self._MAV_CMD_DO_GO_AROUND(self.run_cmd)6024self._MAV_CMD_DO_GO_AROUND(self.run_cmd_int)60256026def _MAV_CMD_DO_FLIGHTTERMINATION(self, command):6027self.set_parameters({6028"AFS_ENABLE": 1,6029"SYSID_MYGCS": self.mav.source_system,6030"AFS_TERM_ACTION": 42,6031})6032self.wait_ready_to_arm()6033self.arm_vehicle()6034self.context_collect('STATUSTEXT')6035command(mavutil.mavlink.MAV_CMD_DO_FLIGHTTERMINATION, p1=1)6036self.wait_disarmed()6037self.wait_text('Terminating due to GCS request', check_context=True)6038self.reboot_sitl()60396040def MAV_CMD_DO_FLIGHTTERMINATION(self):6041'''test MAV_CMD_DO_FLIGHTTERMINATION works on Plane'''6042self._MAV_CMD_DO_FLIGHTTERMINATION(self.run_cmd)6043self._MAV_CMD_DO_FLIGHTTERMINATION(self.run_cmd_int)60446045def MAV_CMD_DO_LAND_START(self):6046'''test MAV_CMD_DO_LAND_START as mavlink command'''6047self.set_parameters({6048"RTL_AUTOLAND": 3,6049})6050self.upload_simple_relhome_mission([6051(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 30),6052(mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM, 0, 0, 30),6053self.create_MISSION_ITEM_INT(6054mavutil.mavlink.MAV_CMD_DO_LAND_START,6055),6056(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, 0),6057])60586059self.change_mode('AUTO')6060self.wait_ready_to_arm()60616062self.arm_vehicle()60636064self.start_subtest("DO_LAND_START as COMMAND_LONG")6065self.wait_current_waypoint(2)6066self.run_cmd(mavutil.mavlink.MAV_CMD_DO_LAND_START)6067self.wait_current_waypoint(4)60686069self.start_subtest("DO_LAND_START as COMMAND_INT")6070self.set_current_waypoint(2)6071self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_LAND_START)6072self.wait_current_waypoint(4)60736074self.fly_home_land_and_disarm()60756076def MAV_CMD_NAV_ALTITUDE_WAIT(self):6077'''test MAV_CMD_NAV_ALTITUDE_WAIT mission item, wiggling only'''60786079# Load a single waypoint6080self.upload_simple_relhome_mission([6081self.create_MISSION_ITEM_INT(6082mavutil.mavlink.MAV_CMD_NAV_ALTITUDE_WAIT,6083p1=1000, # 1000m alt threshold, this should not trigger6084p2=10, # 10m/s descent rate, this should not trigger6085p3=10 # servo wiggle every 10 seconds6086)6087])60886089# Set initial conditions for servo wiggle testing6090servo_wiggled = {1: False, 2: False, 4: False}60916092def look_for_wiggle(mav, m):6093if m.get_type() == 'SERVO_OUTPUT_RAW':6094# Throttle must be zero6095if m.servo3_raw != 1000:6096raise NotAchievedException(6097"Throttle must be 0 in altitude wait, got %f" % m.servo3_raw)60986099# Check if all servos wiggle6100if m.servo1_raw != 1500:6101servo_wiggled[1] = True6102if m.servo2_raw != 1500:6103servo_wiggled[2] = True6104if m.servo4_raw != 1500:6105servo_wiggled[4] = True61066107# Start mission6108self.change_mode('AUTO')6109self.wait_ready_to_arm()6110self.arm_vehicle()61116112# Check outputs6113self.context_push()6114self.install_message_hook_context(look_for_wiggle)61156116# Wait for a bit to let message hook sample6117self.delay_sim_time(60)61186119self.context_pop()61206121# If the mission item completes as there is no other waypoints we will end up in RTL6122if not self.mode_is('AUTO'):6123raise NotAchievedException("Must still be in AUTO")61246125# Raise error if not all servos have wiggled6126if not all(servo_wiggled.values()):6127raise NotAchievedException("Not all servos have moved within the test frame")61286129self.disarm_vehicle()61306131def start_flying_simple_rehome_mission(self, items):6132'''uploads items, changes mode to auto, waits ready to arm and arms6133vehicle. If the first item it a takeoff you can expect the6134vehicle to fly after this method returns6135'''61366137self.upload_simple_relhome_mission(items)61386139self.change_mode('AUTO')6140self.wait_ready_to_arm()61416142self.arm_vehicle()61436144def InteractTest(self):6145'''just takeoff'''61466147if self.mavproxy is None:6148raise NotAchievedException("Must be started with --map")61496150self.start_flying_simple_rehome_mission([6151(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 30),6152(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, 0),6153(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 800, 0),6154(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 0, 400, 0),6155])61566157self.wait_current_waypoint(4)61586159self.set_parameter('SIM_SPEEDUP', 1)61606161self.mavproxy.interact()61626163def MAV_CMD_MISSION_START(self):6164'''test MAV_CMD_MISSION_START starts AUTO'''6165self.upload_simple_relhome_mission([6166(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, 0),6167])6168for run_cmd in self.run_cmd, self.run_cmd_int:6169self.change_mode('LOITER')6170run_cmd(mavutil.mavlink.MAV_CMD_MISSION_START)6171self.wait_mode('AUTO')61726173def MAV_CMD_NAV_LOITER_UNLIM(self):6174'''test receiving MAV_CMD_NAV_LOITER_UNLIM from GCS'''6175self.takeoff(10)6176self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM)6177self.wait_mode('LOITER')6178self.change_mode('GUIDED')6179self.run_cmd_int(mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM)6180self.wait_mode('LOITER')6181self.fly_home_land_and_disarm()61826183def MAV_CMD_NAV_RETURN_TO_LAUNCH(self):6184'''test receiving MAV_CMD_NAV_RETURN_TO_LAUNCH from GCS'''6185self.set_parameter('RTL_AUTOLAND', 1)6186self.start_flying_simple_rehome_mission([6187(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 30),6188(mavutil.mavlink.MAV_CMD_NAV_LOITER_UNLIM, 0, 0, 30),6189self.create_MISSION_ITEM_INT(6190mavutil.mavlink.MAV_CMD_DO_LAND_START,6191),6192(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, 0),6193])61946195for i in self.run_cmd, self.run_cmd_int:6196self.wait_current_waypoint(2)6197self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH)6198self.wait_current_waypoint(4)6199self.set_current_waypoint(2)6200self.fly_home_land_and_disarm()62016202def location_from_ADSB_VEHICLE(self, m):6203'''return a mavutil.location extracted from an ADSB_VEHICLE mavlink6204message'''6205if m.altitude_type != mavutil.mavlink.ADSB_ALTITUDE_TYPE_GEOMETRIC:6206raise ValueError("Expected geometric alt")6207return mavutil.location(6208m.lat*1e-7,6209m.lon*1e-7,6210m.altitude/1000.0585, # mm -> m6211m.heading * 0.01 # centidegrees -> degrees6212)62136214def SagetechMXS(self):6215'''test Sagetech MXS ADSB device driver'''6216sim_name = "sagetech_mxs"6217self.set_parameters({6218"SERIAL5_PROTOCOL": 35,6219"ADSB_TYPE": 4, # Sagetech-MXS6220"SIM_ADSB_TYPES": 8, # Sagetech-MXS6221"SIM_ADSB_COUNT": 5,6222})6223self.customise_SITL_commandline(["--serial5=sim:%s" % sim_name])6224m = self.assert_receive_message("ADSB_VEHICLE")6225adsb_vehicle_loc = self.location_from_ADSB_VEHICLE(m)6226self.progress("ADSB Vehicle at loc %s" % str(adsb_vehicle_loc))6227home = self.home_position_as_mav_location()6228self.assert_distance(home, adsb_vehicle_loc, 0, 10000)62296230def MinThrottle(self):6231'''Make sure min throttle does not apply in manual mode and does in FBWA'''62326233servo_min = self.get_parameter("RC3_MIN")6234servo_max = self.get_parameter("RC3_MAX")6235min_throttle = 106236servo_min_throttle = servo_min + (servo_max - servo_min) * (min_throttle / 100)62376238# Set min throttle6239self.set_parameter('THR_MIN', min_throttle)62406241# Should be 0 throttle while disarmed6242self.change_mode("MANUAL")6243self.drain_mav() # make sure we have the latest data before checking throttle output6244self.assert_servo_channel_value(3, servo_min)62456246# Arm and check throttle is still 0 in manual6247self.wait_ready_to_arm()6248self.arm_vehicle()6249self.drain_mav()6250self.assert_servo_channel_value(3, servo_min)62516252# FBWA should apply throttle min6253self.change_mode("FBWA")6254self.drain_mav()6255self.assert_servo_channel_value(3, servo_min_throttle)62566257# But not when disarmed6258self.disarm_vehicle()6259self.drain_mav()6260self.assert_servo_channel_value(3, servo_min)62616262def ClimbThrottleSaturation(self):6263'''check what happens when throttle is saturated in GUIDED'''6264self.set_parameters({6265"TECS_CLMB_MAX": 30,6266"TKOFF_ALT": 1000,6267})62686269self.change_mode("TAKEOFF")6270self.wait_ready_to_arm()6271self.arm_vehicle()6272self.wait_message_field_values('VFR_HUD', {6273"throttle": 100,6274}, minimum_duration=30, timeout=90)6275self.disarm_vehicle(force=True)6276self.reboot_sitl()62776278def GuidedAttitudeNoGPS(self):6279'''test that guided-attitude still works with no GPS'''6280self.takeoff(50)6281self.change_mode('GUIDED')6282self.context_push()6283self.set_parameter('SIM_GPS1_ENABLE', 0)6284self.delay_sim_time(30)6285self.set_attitude_target()6286self.context_pop()6287self.fly_home_land_and_disarm()62886289def ScriptStats(self):6290'''test script stats logging'''6291self.context_push()6292self.set_parameters({6293'SCR_ENABLE': 1,6294'SCR_DEBUG_OPTS': 8, # runtime memory usage and time6295})6296self.install_test_scripts_context([6297"math.lua",6298"strings.lua",6299])6300self.install_example_script_context('simple_loop.lua')6301self.context_collect('STATUSTEXT')63026303self.reboot_sitl()63046305self.wait_statustext('hello, world')6306delay = 206307self.delay_sim_time(delay, reason='gather some stats')6308self.wait_statustext("math.lua exceeded time limit", check_context=True, timeout=0)63096310dfreader = self.dfreader_for_current_onboard_log()6311seen_hello_world = False6312# runtime = None6313while True:6314m = dfreader.recv_match(type=['SCR'])6315if m is None:6316break6317if m.Name == "simple_loop.lua":6318seen_hello_world = True6319# if m.Name == "math.lua":6320# runtime = m.Runtime63216322if not seen_hello_world:6323raise NotAchievedException("Did not see simple_loop.lua script")63246325# self.progress(f"math took {runtime} seconds to run over {delay} seconds")6326# if runtime == 0:6327# raise NotAchievedException("Expected non-zero runtime for math")63286329self.context_pop()6330self.reboot_sitl()63316332def GPSPreArms(self):6333'''ensure GPS prearm checks work'''6334self.wait_ready_to_arm()6335self.start_subtest('DroneCAN sanity checks')6336self.set_parameter('GPS1_TYPE', 9)6337self.set_parameter('GPS2_TYPE', 9)6338self.set_parameter('GPS1_CAN_OVRIDE', 130)6339self.set_parameter('GPS2_CAN_OVRIDE', 130)6340self.assert_prearm_failure(6341"set for multiple GPS",6342other_prearm_failures_fatal=False,6343)63446345def SetHomeAltChange(self):6346'''check modes retain altitude when home alt changed'''6347for mode in 'FBWB', 'CRUISE', 'LOITER':6348self.set_rc(3, 1000)6349self.wait_ready_to_arm()6350home = self.home_position_as_mav_location()6351target_alt = 206352self.takeoff(target_alt, mode="TAKEOFF")6353self.delay_sim_time(20) # Give some time to altitude to stabilize.6354self.set_rc(3, 1500)6355self.change_mode(mode)6356higher_home = copy.copy(home)6357higher_home.alt += 406358self.set_home(higher_home)6359self.wait_altitude(home.alt+target_alt-5, home.alt+target_alt+5, relative=False, minimum_duration=10, timeout=11)6360self.disarm_vehicle(force=True)6361self.reboot_sitl()63626363def SetHomeAltChange2(self):6364'''ensure TECS operates predictably as home altitude changes continuously'''6365'''6366This can happen when performing a ship landing, where the home6367coordinates are continuously set by the ship GNSS RX.6368'''6369self.set_parameter('TRIM_THROTTLE', 70)6370self.wait_ready_to_arm()6371home = self.home_position_as_mav_location()6372target_alt = 206373self.takeoff(target_alt, mode="TAKEOFF")6374self.change_mode("LOITER")6375self.delay_sim_time(20) # Let the plane settle.63766377tstart = self.get_sim_time()6378test_time = 10 # Run the test for 10s.6379pub_freq = 106380for i in range(test_time*pub_freq):6381tnow = self.get_sim_time()6382higher_home = copy.copy(home)6383# Produce 1Hz sine waves in home altitude change.6384higher_home.alt += 40*math.sin((tnow-tstart)*(2*math.pi))6385self.set_home(higher_home)6386if tnow-tstart > test_time:6387break6388self.delay_sim_time(1.0/pub_freq)63896390# Test if the altitude is still within bounds.6391self.wait_altitude(home.alt+target_alt-5, home.alt+target_alt+5, relative=False, minimum_duration=1, timeout=2)6392self.disarm_vehicle(force=True)6393self.reboot_sitl()63946395def SetHomeAltChange3(self):6396'''same as SetHomeAltChange, but the home alt change occurs during TECS operation'''6397self.wait_ready_to_arm()6398home = self.home_position_as_mav_location()6399target_alt = 206400self.takeoff(target_alt, mode="TAKEOFF")6401self.change_mode("LOITER")6402self.delay_sim_time(20) # Let the plane settle.64036404higher_home = copy.copy(home)6405higher_home.alt += 406406self.set_home(higher_home)6407self.wait_altitude(home.alt+target_alt-5, home.alt+target_alt+5, relative=False, minimum_duration=10, timeout=10.1)64086409self.disarm_vehicle(force=True)6410self.reboot_sitl()64116412def ForceArm(self):6413'''check force-arming functionality'''6414self.set_parameter("SIM_GPS1_ENABLE", 0)6415# 21196 is the mavlink standard, 2989 is legacy6416for magic_value in 21196, 2989:6417self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_PREARM_CHECK,6418present=True,6419enabled=True,6420healthy=False,6421)6422self.run_cmd(6423mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,6424p1=1, # ARM6425p2=0,6426want_result=mavutil.mavlink.MAV_RESULT_FAILED,6427)6428self.run_cmd(6429mavutil.mavlink.MAV_CMD_COMPONENT_ARM_DISARM,6430p1=1, # ARM6431p2=magic_value,6432want_result=mavutil.mavlink.MAV_RESULT_ACCEPTED,6433)6434self.disarm_vehicle()64356436def _MAV_CMD_EXTERNAL_WIND_ESTIMATE(self, command):6437self.reboot_sitl()64386439def cmp_with_variance(a, b, p):6440return abs(a - b) < p64416442def check_eq(speed, direction, ret_dir, timeout=1):6443command(mavutil.mavlink.MAV_CMD_EXTERNAL_WIND_ESTIMATE, p1=speed, p3=direction)64446445tstart = self.get_sim_time()6446while True:6447if self.get_sim_time_cached() - tstart > timeout:6448raise NotAchievedException(6449f"Failed to set wind speed or/and direction: speed != {speed} or direction != {direction}")64506451m = self.assert_receive_message("WIND")6452if cmp_with_variance(m.speed, speed, 0.5) and cmp_with_variance(m.direction, ret_dir, 5):6453return True64546455check_eq(1, 45, 45)6456check_eq(2, 90, 90)6457check_eq(3, 120, 120)6458check_eq(4, 180, -180)6459check_eq(5, 240, -120)6460check_eq(6, 320, -40)6461check_eq(7, 360, 0)64626463command(mavutil.mavlink.MAV_CMD_EXTERNAL_WIND_ESTIMATE, p1=-2, p3=90, want_result=mavutil.mavlink.MAV_RESULT_DENIED)6464command(mavutil.mavlink.MAV_CMD_EXTERNAL_WIND_ESTIMATE, p1=2, p3=-90, want_result=mavutil.mavlink.MAV_RESULT_DENIED)6465command(mavutil.mavlink.MAV_CMD_EXTERNAL_WIND_ESTIMATE, p1=-2, p3=-90, want_result=mavutil.mavlink.MAV_RESULT_DENIED)6466command(mavutil.mavlink.MAV_CMD_EXTERNAL_WIND_ESTIMATE, p1=2, p3=370, want_result=mavutil.mavlink.MAV_RESULT_DENIED)64676468def MAV_CMD_EXTERNAL_WIND_ESTIMATE(self):6469'''test MAV_CMD_EXTERNAL_WIND_ESTIMATE as a mavlink command'''6470self._MAV_CMD_EXTERNAL_WIND_ESTIMATE(self.run_cmd)6471self._MAV_CMD_EXTERNAL_WIND_ESTIMATE(self.run_cmd_int)64726473def GliderPullup(self):6474'''test pullup of glider after ALTITUDE_WAIT'''6475self.start_subtest("test glider pullup")64766477self.customise_SITL_commandline(6478[],6479model="glider",6480defaults_filepath="Tools/autotest/default_params/glider.parm",6481wipe=True)64826483self.set_parameter('LOG_DISARMED', 1)64846485self.set_parameters({6486"PUP_ENABLE": 1,6487"SERVO6_FUNCTION": 0, # balloon lift6488"SERVO10_FUNCTION": 156, # lift release6489"EK3_IMU_MASK": 1, # lane switches just make log harder to read6490"AHRS_OPTIONS": 4, # don't disable airspeed based on EKF checks6491"ARSPD_OPTIONS": 0, # don't disable airspeed6492"ARSPD_WIND_GATE": 0,6493})64946495self.set_servo(6, 1000)64966497self.load_mission("glider-pullup-mission.txt")6498self.change_mode("AUTO")6499self.wait_ready_to_arm()6500self.arm_vehicle()6501self.context_collect('STATUSTEXT')65026503self.progress("Start balloon lift")6504self.set_servo(6, 2000)65056506self.wait_text("Reached altitude", check_context=True, timeout=1000)6507self.wait_text("Start pullup airspeed", check_context=True)6508self.wait_text("Pullup airspeed", check_context=True)6509self.wait_text("Pullup pitch", check_context=True)6510self.wait_text("Pullup level", check_context=True)6511self.wait_text("Loiter to alt complete", check_context=True, timeout=1000)6512self.wait_text("Flare", check_context=True, timeout=400)6513self.wait_text("Auto disarmed", check_context=True, timeout=200)65146515def BadRollChannelDefined(self):6516'''ensure we don't die with a bad Roll channel defined'''6517self.set_parameter("RCMAP_ROLL", 17)65186519def MAV_CMD_NAV_LOITER_TO_ALT(self):6520'''test loiter to alt mission item'''6521self.upload_simple_relhome_mission([6522(mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 30),6523(mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT, 0, 0, 500),6524(mavutil.mavlink.MAV_CMD_NAV_LOITER_TO_ALT, 0, 0, 100),6525(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 800, 0, 0),6526])6527self.change_mode('AUTO')6528self.wait_ready_to_arm()6529self.arm_vehicle()6530self.wait_altitude(450, 475, relative=True, timeout=600)6531self.wait_altitude(75, 125, relative=True, timeout=600)6532self.wait_current_waypoint(4)6533self.fly_home_land_and_disarm()65346535def VolzMission(self):6536'''test Volz serially-connected servos in a mission'''6537volz_motor_mask = ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 8) | (1 << 9) | (1 << 11))6538self.set_parameters({6539'SERIAL5_PROTOCOL': 14,6540'SERVO_VOLZ_MASK': volz_motor_mask,6541'RTL_AUTOLAND': 2,65426543'SIM_VOLZ_ENA': 1,6544'SIM_VOLZ_MASK': volz_motor_mask,6545})6546# defaults file not working?6547self.set_parameters({6548"SERVO2_REVERSED": 0, # elevator65496550"SERVO9_FUNCTION": 4,65516552"SERVO10_FUNCTION": 19, # elevator65536554"SERVO12_FUNCTION": 21, # rudder6555"SERVO12_REVERSED": 1, # rudder65566557})6558self.customise_SITL_commandline([6559"--serial5=sim:volz",6560], model="plane-redundant",6561)6562self.wait_ready_to_arm()6563self.arm_vehicle()6564self.takeoff()6565self.fly_home_land_and_disarm()65666567def Volz(self):6568'''test Volz serially-connected'''6569volz_motor_mask = ((1 << 0) | (1 << 1) | (1 << 3) | (1 << 8) | (1 << 9) | (1 << 11))6570self.set_parameters({6571'SERIAL5_PROTOCOL': 14,6572'SERVO_VOLZ_MASK': volz_motor_mask,6573'RTL_AUTOLAND': 2,65746575'SIM_VOLZ_ENA': 1,6576'SIM_VOLZ_MASK': volz_motor_mask,6577})6578# defaults file not working?6579self.set_parameters({6580"SERVO2_REVERSED": 0, # elevator65816582"SERVO9_FUNCTION": 4,65836584"SERVO10_FUNCTION": 19, # elevator65856586"SERVO12_FUNCTION": 21, # rudder6587"SERVO12_REVERSED": 1, # rudder65886589})6590self.customise_SITL_commandline([6591"--serial5=sim:volz",6592], model="plane-redundant",6593)6594self.wait_ready_to_arm()6595self.takeoff()6596self.change_mode('FBWA')6597straight_and_level_text = "straight-and-level"6598self.send_statustext(straight_and_level_text)6599self.delay_sim_time(2)6600self.progress("sticking servo with constant deflection")6601self.set_rc(1, 1400)6602self.change_mode('MANUAL')6603self.delay_sim_time(0.5)6604self.progress("Failing servo")6605self.set_parameter('SIM_VOLZ_FMASK', 1)6606self.change_mode('FBWA')6607aileron_failed_text = "aileron has been failed"6608self.send_statustext(aileron_failed_text)6609self.delay_sim_time(5)6610self.set_parameter('SIM_VOLZ_FMASK', 0)66116612log_filepath = self.current_onboard_log_filepath()6613self.fly_home_land_and_disarm()66146615self.progress("Inspecting DFReader to ensure servo failure is recorded in the log")6616dfreader = self.dfreader_for_path(log_filepath)6617while True:6618m = dfreader.recv_match(type=['MSG'])6619if m is None:6620raise NotAchievedException("Did not see straight_and_level_text")6621if m.Message == "SRC=250/250:" + straight_and_level_text:6622break66236624self.progress("Ensuring deflections are close to zero in straight-and-level flight")6625chan1_good = False6626chan9_good = False6627while not (chan1_good and chan9_good):6628m = dfreader.recv_match()6629if m is None:6630raise NotAchievedException("Did not see chan1 and chan9 as close-to-0")6631if m.get_type() != 'CSRV':6632continue6633if m.Id == 0 and abs(m.Pos) < 3:6634chan1_good = True6635elif m.Id == 8 and abs(m.Pos) < 3:6636chan9_good = True66376638while True:6639m = dfreader.recv_match(type=['MSG'])6640if m is None:6641raise NotAchievedException("Did not see aileron_failed_text")6642if m.Message == "SRC=250/250:" + aileron_failed_text:6643break66446645self.progress("Checking servo9 is deflected")6646while True:6647# m = dfreader.recv_match(type=['CSRV'])6648m = dfreader.recv_match()6649if m is None:6650raise NotAchievedException("Did not see chan9 deflection")6651if m.get_type() != 'CSRV':6652continue6653if m.Id != 8:6654continue6655if m.Pos < 20:6656continue6657break66586659self.progress("Ensuring the vehicle stabilised with a single aileron")6660while True:6661m = dfreader.recv_match()6662if m is None:6663raise NotAchievedException("Did not see good attitude")6664if m.get_type() != 'ATT':6665continue6666if abs(m.Roll) < 5:6667break66686669self.progress("Ensure the roll integrator is wound up")6670while True:6671m = dfreader.recv_match()6672if m is None:6673raise NotAchievedException("Did not see wound-up roll integrator")6674if m.get_type() != 'PIDR':6675continue6676if m.I > 5:6677break66786679self.progress("Checking that aileron is stuck at some deflection")6680while True:6681m = dfreader.recv_match()6682if m is None:6683raise NotAchievedException("Did not see csrv Pos/PosCmd discrepency")6684if m.get_type() != 'CSRV':6685continue6686if m.Id != 1:6687continue6688if abs(m.Pos - m.PosCmd) > 20:6689break66906691def tests(self):6692'''return list of all tests'''6693ret = []6694ret.extend(self.tests1a())6695ret.extend(self.tests1b())6696return ret66976698def tests1a(self):6699ret = []6700ret = super(AutoTestPlane, self).tests()6701ret.extend([6702self.AuxModeSwitch,6703self.TestRCCamera,6704self.TestRCRelay,6705self.ThrottleFailsafe,6706self.NeedEKFToArm,6707self.ThrottleFailsafeFence,6708self.TestFlaps,6709self.DO_CHANGE_SPEED,6710self.DO_REPOSITION,6711self.GuidedRequest,6712self.MainFlight,6713self.TestGripperMission,6714self.Parachute,6715self.ParachuteSinkRate,6716self.DO_PARACHUTE,6717self.PitotBlockage,6718self.AIRSPEED_AUTOCAL,6719self.RangeFinder,6720self.FenceStatic,6721self.FenceRTL,6722self.FenceRTLRally,6723self.FenceRetRally,6724self.FenceAltCeilFloor,6725self.FenceMinAltAutoEnable,6726self.FenceMinAltEnableAutoland,6727self.FenceMinAltAutoEnableAbort,6728self.FenceAutoEnableDisableSwitch,6729Test(self.FenceCircleExclusionAutoEnable, speedup=20),6730self.FenceEnableDisableSwitch,6731self.FenceEnableDisableAux,6732self.FenceBreachedChangeMode,6733self.FenceNoFenceReturnPoint,6734self.FenceNoFenceReturnPointInclusion,6735self.FenceDisableUnderAction,6736self.ADSBFailActionRTL,6737self.ADSBResumeActionResumeLoiter,6738self.SimADSB,6739self.Button,6740self.FRSkySPort,6741self.FRSkyPassThroughStatustext,6742self.FRSkyPassThroughSensorIDs,6743self.FRSkyMAVlite,6744self.FRSkyD,6745self.LTM,6746self.DEVO,6747self.AdvancedFailsafe,6748self.LOITER,6749self.MAV_CMD_NAV_LOITER_TURNS,6750self.MAV_CMD_NAV_LOITER_TO_ALT,6751self.DeepStall,6752self.WatchdogHome,6753self.LargeMissions,6754self.Soaring,6755self.Terrain,6756self.TerrainMission,6757self.UniversalAutoLandScript,6758])6759return ret67606761def tests1b(self):6762return [6763self.TerrainLoiter,6764self.VectorNavEAHRS,6765self.MicroStrainEAHRS5,6766self.MicroStrainEAHRS7,6767self.InertialLabsEAHRS,6768self.GpsSensorPreArmEAHRS,6769self.Deadreckoning,6770self.DeadreckoningNoAirSpeed,6771self.EKFlaneswitch,6772self.AirspeedDrivers,6773self.RTL_CLIMB_MIN,6774self.ClimbBeforeTurn,6775self.IMUTempCal,6776self.MAV_CMD_DO_AUX_FUNCTION,6777self.SmartBattery,6778self.FlyEachFrame,6779self.AutoLandMode,6780self.RCDisableAirspeedUse,6781self.AHRS_ORIENTATION,6782self.AHRSTrim,6783self.LandingDrift,6784self.TakeoffAuto1,6785self.TakeoffAuto2,6786self.TakeoffAuto3,6787self.TakeoffAuto4,6788self.TakeoffTakeoff1,6789self.TakeoffTakeoff2,6790self.TakeoffTakeoff3,6791self.TakeoffTakeoff4,6792self.TakeoffTakeoff5,6793self.TakeoffGround,6794self.TakeoffIdleThrottle,6795self.TakeoffBadLevelOff,6796self.ForcedDCM,6797self.DCMFallback,6798self.MAVFTP,6799self.AUTOTUNE,6800self.AutotuneFiltering,6801self.MegaSquirt,6802self.Hirth,6803self.MSP_DJI,6804self.SpeedToFly,6805self.GlideSlopeThresh,6806self.HIGH_LATENCY2,6807self.MidAirDisarmDisallowed,6808self.AerobaticsScripting,6809self.MANUAL_CONTROL,6810self.RunMissionScript,6811self.WindEstimates,6812self.AltResetBadGPS,6813self.AirspeedCal,6814self.MissionJumpTags,6815Test(self.GCSFailsafe, speedup=8),6816self.SDCardWPTest,6817self.NoArmWithoutMissionItems,6818self.MODE_SWITCH_RESET,6819self.ExternalPositionEstimate,6820self.SagetechMXS,6821self.MAV_CMD_GUIDED_CHANGE_ALTITUDE,6822self.MAV_CMD_PREFLIGHT_CALIBRATION,6823self.MAV_CMD_DO_INVERTED_FLIGHT,6824self.MAV_CMD_DO_AUTOTUNE_ENABLE,6825self.MAV_CMD_DO_GO_AROUND,6826self.MAV_CMD_DO_FLIGHTTERMINATION,6827self.MAV_CMD_DO_LAND_START,6828self.MAV_CMD_NAV_ALTITUDE_WAIT,6829self.InteractTest,6830self.MAV_CMD_MISSION_START,6831self.TerrainRally,6832self.MAV_CMD_NAV_LOITER_UNLIM,6833self.MAV_CMD_NAV_RETURN_TO_LAUNCH,6834self.MinThrottle,6835self.ClimbThrottleSaturation,6836self.GuidedAttitudeNoGPS,6837self.ScriptStats,6838self.GPSPreArms,6839self.SetHomeAltChange,6840self.SetHomeAltChange2,6841self.SetHomeAltChange3,6842self.ForceArm,6843self.MAV_CMD_EXTERNAL_WIND_ESTIMATE,6844self.GliderPullup,6845self.BadRollChannelDefined,6846self.VolzMission,6847self.Volz,6848]68496850def disabled_tests(self):6851return {6852"LandingDrift": "Flapping test. See https://github.com/ArduPilot/ardupilot/issues/20054",6853"InteractTest": "requires user interaction",6854"ClimbThrottleSaturation": "requires https://github.com/ArduPilot/ardupilot/pull/27106 to pass",6855}685668576858class AutoTestPlaneTests1a(AutoTestPlane):6859def tests(self):6860return self.tests1a()686168626863class AutoTestPlaneTests1b(AutoTestPlane):6864def tests(self):6865return self.tests1b()686668676868