Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ardupilot
GitHub Repository: Ardupilot/ardupilot
Path: blob/master/Tools/autotest/rover.py
9670 views
1
'''
2
Drive Rover in SITL
3
4
AP_FLAKE8_CLEAN
5
6
'''
7
8
import copy
9
import math
10
import operator
11
import os
12
import pathlib
13
import sys
14
import time
15
16
import vehicle_test_suite
17
18
from pysim import util
19
from pysim import vehicleinfo
20
21
from vehicle_test_suite import AutoTestTimeoutException
22
from vehicle_test_suite import NotAchievedException
23
from vehicle_test_suite import PreconditionFailedException
24
25
from pymavlink import mavextra
26
from pymavlink import mavutil
27
28
# get location of scripts
29
testdir = os.path.dirname(os.path.realpath(__file__))
30
31
SITL_START_LOCATION = mavutil.location(40.071374969556928,
32
-105.22978898137808,
33
1583.702759,
34
246)
35
36
37
class AutoTestRover(vehicle_test_suite.TestSuite):
38
@staticmethod
39
def get_not_armable_mode_list():
40
return ["RTL", "SMART_RTL"]
41
42
@staticmethod
43
def get_not_disarmed_settable_modes_list():
44
return ["FOLLOW"]
45
46
@staticmethod
47
def get_no_position_not_settable_modes_list():
48
return []
49
50
@staticmethod
51
def get_position_armable_modes_list():
52
return ["GUIDED", "LOITER", "STEERING", "AUTO"]
53
54
@staticmethod
55
def get_normal_armable_modes_list():
56
return ["ACRO", "HOLD", "MANUAL"]
57
58
def log_name(self):
59
return "Rover"
60
61
def test_filepath(self):
62
return os.path.realpath(__file__)
63
64
def set_current_test_name(self, name):
65
self.current_test_name_directory = "ArduRover_Tests/" + name + "/"
66
67
def sitl_start_location(self):
68
return SITL_START_LOCATION
69
70
def default_frame(self):
71
return "rover"
72
73
def default_speedup(self):
74
return 30
75
76
def is_rover(self):
77
return True
78
79
def get_stick_arming_channel(self):
80
return int(self.get_parameter("RCMAP_ROLL"))
81
82
##########################################################
83
# TESTS DRIVE
84
##########################################################
85
# Drive a square in manual mode
86
def DriveSquare(self, side=50):
87
"""Learn/Drive Square with Ch7 option"""
88
89
self.progress("TEST SQUARE")
90
self.set_parameters({
91
"RC7_OPTION": 7,
92
"RC9_OPTION": 58,
93
})
94
95
self.change_mode('MANUAL')
96
97
self.wait_ready_to_arm()
98
self.arm_vehicle()
99
100
self.clear_wp(9)
101
102
# first aim north
103
self.progress("\nTurn right towards north")
104
self.reach_heading_manual(10)
105
# save bottom left corner of box as home AND waypoint
106
self.progress("Save HOME")
107
self.save_wp()
108
109
self.progress("Save WP")
110
self.save_wp()
111
112
# pitch forward to fly north
113
self.progress("\nGoing north %u meters" % side)
114
self.reach_distance_manual(side)
115
# save top left corner of square as waypoint
116
self.progress("Save WP")
117
self.save_wp()
118
119
# roll right to fly east
120
self.progress("\nGoing east %u meters" % side)
121
self.reach_heading_manual(100)
122
self.reach_distance_manual(side)
123
# save top right corner of square as waypoint
124
self.progress("Save WP")
125
self.save_wp()
126
127
# pitch back to fly south
128
self.progress("\nGoing south %u meters" % side)
129
self.reach_heading_manual(190)
130
self.reach_distance_manual(side)
131
# save bottom right corner of square as waypoint
132
self.progress("Save WP")
133
self.save_wp()
134
135
# roll left to fly west
136
self.progress("\nGoing west %u meters" % side)
137
self.reach_heading_manual(280)
138
self.reach_distance_manual(side)
139
# save bottom left corner of square (should be near home) as waypoint
140
self.progress("Save WP")
141
self.save_wp()
142
143
self.progress("Checking number of saved waypoints")
144
mavproxy = self.start_mavproxy()
145
num_wp = self.save_mission_to_file_using_mavproxy(
146
mavproxy,
147
os.path.join(testdir, "ch7_mission.txt"))
148
self.stop_mavproxy(mavproxy)
149
expected = 7 # home + 6 toggled in
150
if num_wp != expected:
151
raise NotAchievedException("Did not get %u waypoints; got %u" %
152
(expected, num_wp))
153
154
# TODO: actually drive the mission
155
156
self.clear_wp(9)
157
158
self.disarm_vehicle()
159
160
def drive_left_circuit(self):
161
"""Drive a left circuit, 50m on a side."""
162
self.change_mode('MANUAL')
163
self.set_rc(3, 2000)
164
165
self.progress("Driving left circuit")
166
# do 4 turns
167
for i in range(0, 4):
168
# hard left
169
self.progress("Starting turn %u" % i)
170
self.set_rc(1, 1000)
171
self.wait_heading(270 - (90*i), accuracy=10)
172
self.set_rc(1, 1500)
173
self.progress("Starting leg %u" % i)
174
self.wait_distance(50, accuracy=7)
175
self.set_rc(3, 1500)
176
self.progress("Circuit complete")
177
178
def ThrottleFailsafe(self):
179
"""Trigger throttle failsafes"""
180
self.progress("Testing throttle failsafe")
181
# set failsafe to Loiter_or_Hold
182
self.set_parameters({
183
"FS_THR_ENABLE": 1,
184
"FS_ACTION": 6,
185
})
186
self.change_mode("MANUAL")
187
self.wait_ready_to_arm()
188
self.arm_vehicle()
189
190
self.progress("Testing failsafe to loiter")
191
self.set_parameter("SIM_RC_FAIL", 1) # no-pulses failsafe
192
self.wait_mode("LOITER", timeout=10)
193
194
# restore RC and prepare to test hold fallback
195
self.set_parameter("SIM_RC_FAIL", 0)
196
self.set_parameter("SIM_GPS1_ENABLE", 0)
197
self.change_mode("MANUAL")
198
199
self.progress("Testing failsafe to hold")
200
self.set_parameter("SIM_RC_FAIL", 1)
201
self.wait_mode("HOLD", timeout=10)
202
self.disarm_vehicle()
203
self.progress("Loiter or Hold as throttle failsafe OK")
204
205
def PARAM_ERROR(self):
206
'''test PARAM_ERROR mavlink message'''
207
self.start_subtest("Non-existent parameter (get)")
208
self.context_push()
209
self.context_collect('PARAM_ERROR')
210
self.install_messageprinter_handlers_context(['PARAM_ERROR'])
211
self.send_get_parameter_direct("BOB")
212
self.assert_received_message_field_values('PARAM_ERROR', {
213
"target_system": 250,
214
"target_component": 250,
215
"param_id": 'BOB',
216
"param_index": -1,
217
"error": mavutil.mavlink.MAV_PARAM_ERROR_DOES_NOT_EXIST,
218
}, check_context=True, very_verbose=True)
219
self.context_pop()
220
221
self.start_subtest("Non-existent parameter (get-by-id)")
222
self.context_push()
223
self.context_collect('PARAM_ERROR')
224
self.install_messageprinter_handlers_context(['PARAM_ERROR'])
225
non_existent_param_index = 32764 # hopefully, anyway....
226
self.mav.mav.param_request_read_send(
227
self.sysid_thismav(),
228
1,
229
bytes("", 'ascii'),
230
non_existent_param_index
231
)
232
self.assert_received_message_field_values('PARAM_ERROR', {
233
"target_system": 250,
234
"target_component": 250,
235
"param_id": '',
236
"param_index": non_existent_param_index,
237
"error": mavutil.mavlink.MAV_PARAM_ERROR_DOES_NOT_EXIST,
238
}, check_context=True, very_verbose=True)
239
self.context_pop()
240
241
self.start_subtest("Non-existent parameter (set)")
242
self.context_push()
243
self.context_collect('PARAM_ERROR')
244
self.send_set_parameter_direct("BOB", 1)
245
self.assert_received_message_field_values('PARAM_ERROR', {
246
"target_system": 250,
247
"target_component": 250,
248
"param_id": 'BOB',
249
"param_index": -1,
250
"error": mavutil.mavlink.MAV_PARAM_ERROR_DOES_NOT_EXIST,
251
}, check_context=True, very_verbose=True)
252
self.context_pop()
253
254
self.start_subtest("Try to set a bad parameter value")
255
self.context_push()
256
self.context_collect('PARAM_ERROR')
257
self.send_set_parameter_direct("SPRAY_ENABLE", float("nan"))
258
self.assert_received_message_field_values('PARAM_ERROR', {
259
"target_system": 250,
260
"target_component": 250,
261
"param_id": 'SPRAY_ENABLE',
262
"param_index": -1,
263
"error": mavutil.mavlink.MAV_PARAM_ERROR_VALUE_OUT_OF_RANGE,
264
}, check_context=True, very_verbose=True)
265
self.context_pop()
266
267
def Sprayer(self):
268
"""Test sprayer functionality."""
269
rc_ch = 5
270
pump_ch = 5
271
spinner_ch = 6
272
pump_ch_min = 1050
273
pump_ch_trim = 1520
274
pump_ch_max = 1950
275
spinner_ch_min = 975
276
spinner_ch_trim = 1510
277
spinner_ch_max = 1975
278
279
self.set_parameters({
280
"SPRAY_ENABLE": 1,
281
282
"SERVO%u_FUNCTION" % pump_ch: 22,
283
"SERVO%u_MIN" % pump_ch: pump_ch_min,
284
"SERVO%u_TRIM" % pump_ch: pump_ch_trim,
285
"SERVO%u_MAX" % pump_ch: pump_ch_max,
286
287
"SERVO%u_FUNCTION" % spinner_ch: 23,
288
"SERVO%u_MIN" % spinner_ch: spinner_ch_min,
289
"SERVO%u_TRIM" % spinner_ch: spinner_ch_trim,
290
"SERVO%u_MAX" % spinner_ch: spinner_ch_max,
291
292
"SIM_SPR_ENABLE": 1,
293
"SIM_SPR_PUMP": pump_ch,
294
"SIM_SPR_SPIN": spinner_ch,
295
296
"RC%u_OPTION" % rc_ch: 15,
297
"LOG_DISARMED": 1,
298
})
299
300
self.reboot_sitl()
301
302
self.wait_ready_to_arm()
303
self.arm_vehicle()
304
305
self.progress("test boot-up state - it's zero-output!")
306
self.wait_servo_channel_value(spinner_ch, 0)
307
self.wait_servo_channel_value(pump_ch, 0)
308
309
self.progress("Enable sprayer")
310
self.set_rc(rc_ch, 2000)
311
312
self.progress("Testing zero-speed state")
313
self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
314
self.wait_servo_channel_value(pump_ch, pump_ch_min)
315
316
self.progress("Testing turning it off")
317
self.set_rc(rc_ch, 1000)
318
self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
319
self.wait_servo_channel_value(pump_ch, pump_ch_min)
320
321
self.progress("Testing turning it back on")
322
self.set_rc(rc_ch, 2000)
323
self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
324
self.wait_servo_channel_value(pump_ch, pump_ch_min)
325
326
self.progress("Testing speed-ramping")
327
self.set_rc(3, 1700) # start driving forward
328
329
# this is somewhat empirical...
330
self.wait_servo_channel_value(pump_ch, 1695, timeout=60)
331
332
self.progress("Turning it off again")
333
self.set_rc(rc_ch, 1000)
334
self.wait_servo_channel_value(spinner_ch, spinner_ch_min)
335
self.wait_servo_channel_value(pump_ch, pump_ch_min)
336
337
self.start_subtest("Sprayer Mission")
338
self.load_mission("sprayer-mission.txt")
339
self.change_mode("AUTO")
340
# self.send_debug_trap()
341
self.progress("Waiting for sprayer to start")
342
self.wait_servo_channel_value(pump_ch, 1250, timeout=60, comparator=operator.gt)
343
self.progress("Waiting for sprayer to stop")
344
self.wait_servo_channel_value(pump_ch, pump_ch_min, timeout=120)
345
346
self.start_subtest("Checking mavlink commands")
347
self.change_mode("MANUAL")
348
self.progress("Starting Sprayer")
349
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=1)
350
351
self.progress("Testing speed-ramping")
352
self.set_rc(3, 1700) # start driving forward
353
self.wait_servo_channel_value(pump_ch, 1690, timeout=60, comparator=operator.gt)
354
self.start_subtest("Stopping Sprayer")
355
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_SPRAYER, p1=0)
356
self.wait_servo_channel_value(pump_ch, pump_ch_min)
357
self.set_rc(3, 1000) # stop driving forward
358
359
self.progress("Sprayer OK")
360
self.disarm_vehicle()
361
362
def DriveMaxRCIN(self, timeout=30):
363
"""Drive rover at max RC inputs"""
364
self.progress("Testing max RC inputs")
365
self.change_mode("MANUAL")
366
367
self.wait_ready_to_arm()
368
self.arm_vehicle()
369
370
self.set_rc(3, 2000)
371
self.set_rc(1, 1000)
372
373
tstart = self.get_sim_time()
374
while self.get_sim_time_cached() - tstart < timeout:
375
m = self.assert_receive_message('VFR_HUD')
376
self.progress("Current speed: %f" % m.groundspeed)
377
378
self.disarm_vehicle()
379
380
#################################################
381
# AUTOTEST ALL
382
#################################################
383
def drive_mission(self, filename, strict=True, ignore_MANUAL_mode_change=False):
384
"""Drive a mission from a file."""
385
self.progress("Driving mission %s" % filename)
386
wp_count = self.load_mission(filename, strict=strict)
387
self.wait_ready_to_arm()
388
self.arm_vehicle()
389
self.change_mode('AUTO')
390
self.wait_waypoint(1, wp_count-1, max_dist=5, ignore_MANUAL_mode_change=ignore_MANUAL_mode_change)
391
self.wait_statustext("Mission Complete", timeout=600)
392
self.disarm_vehicle()
393
self.progress("Mission OK")
394
395
def DriveMission(self):
396
'''Drive Mission rover1.txt'''
397
self.drive_mission("rover1.txt", strict=False)
398
399
def GripperMission(self):
400
'''Test Gripper Mission Items'''
401
self.load_mission("rover-gripper-mission.txt")
402
self.change_mode('AUTO')
403
self.wait_ready_to_arm()
404
self.arm_vehicle()
405
self.context_collect('STATUSTEXT')
406
self.wait_statustext("Gripper Grabbed", timeout=60, check_context=True)
407
self.wait_statustext("Gripper Released", timeout=60, check_context=True)
408
self.wait_statustext("Mission Complete", timeout=60, check_context=True)
409
self.disarm_vehicle()
410
411
def _MAV_CMD_DO_SEND_BANNER(self, run_cmd):
412
'''Get Banner'''
413
self.context_push()
414
self.context_collect('STATUSTEXT')
415
run_cmd(mavutil.mavlink.MAV_CMD_DO_SEND_BANNER)
416
self.wait_statustext("ArduRover", timeout=1, check_context=True)
417
self.context_pop()
418
419
def MAV_CMD_DO_SEND_BANNER(self):
420
'''test MAV_CMD_DO_SEND_BANNER'''
421
self._MAV_CMD_DO_SEND_BANNER(self.run_cmd)
422
self._MAV_CMD_DO_SEND_BANNER(self.run_cmd_int)
423
424
def drive_brake_get_stopping_distance(self, speed):
425
'''measure our stopping distance'''
426
427
self.context_push()
428
429
# controller tends not to meet cruise speed (max of ~14 when 15
430
# set), thus *1.2
431
# at time of writing, the vehicle is only capable of 10m/s/s accel
432
self.set_parameters({
433
'CRUISE_SPEED': speed*1.2,
434
'ATC_ACCEL_MAX': 15,
435
})
436
self.change_mode("STEERING")
437
self.set_rc(3, 2000)
438
self.wait_groundspeed(15, 100)
439
initial = self.mav.location()
440
initial_time = time.time()
441
while time.time() - initial_time < 2:
442
# wait for a position update from the autopilot
443
start = self.mav.location()
444
if start != initial:
445
break
446
self.set_rc(3, 1500)
447
self.wait_groundspeed(0, 0.2) # why do we not stop?!
448
initial = self.mav.location()
449
initial_time = time.time()
450
while time.time() - initial_time < 2:
451
# wait for a position update from the autopilot
452
stop = self.mav.location()
453
if stop != initial:
454
break
455
delta = self.get_distance(start, stop)
456
457
self.context_pop()
458
459
return delta
460
461
def DriveBrake(self):
462
'''Test braking'''
463
self.set_parameters({
464
'CRUISE_SPEED': 15,
465
'ATC_BRAKE': 0,
466
})
467
468
self.arm_vehicle()
469
470
distance_without_brakes = self.drive_brake_get_stopping_distance(15)
471
472
# brakes on:
473
self.set_parameter('ATC_BRAKE', 1)
474
distance_with_brakes = self.drive_brake_get_stopping_distance(15)
475
476
delta = distance_without_brakes - distance_with_brakes
477
478
self.disarm_vehicle()
479
480
if delta < distance_without_brakes * 0.05: # 5% isn't asking for much
481
raise NotAchievedException("""
482
Brakes have negligible effect (with=%0.2fm without=%0.2fm delta=%0.2fm)
483
""" %
484
(distance_with_brakes,
485
distance_without_brakes,
486
delta))
487
488
self.progress(
489
"Brakes work (with=%0.2fm without=%0.2fm delta=%0.2fm)" %
490
(distance_with_brakes, distance_without_brakes, delta))
491
492
def drive_rtl_mission_max_distance_from_home(self):
493
'''maximum distance allowed from home at end'''
494
return 6.5
495
496
def DriveRTL(self, timeout=120):
497
'''Drive an RTL Mission'''
498
self.wait_ready_to_arm()
499
self.arm_vehicle()
500
501
self.load_mission("rtl.txt")
502
self.change_mode("AUTO")
503
504
tstart = self.get_sim_time()
505
while True:
506
now = self.get_sim_time_cached()
507
if now - tstart > timeout:
508
raise AutoTestTimeoutException("Didn't see wp 3")
509
m = self.assert_receive_message('MISSION_CURRENT')
510
self.progress("MISSION_CURRENT: %s" % str(m))
511
if m.seq == 3:
512
break
513
514
self.drain_mav()
515
516
m = self.assert_receive_message('NAV_CONTROLLER_OUTPUT')
517
518
wp_dist_min = 5
519
if m.wp_dist < wp_dist_min:
520
raise PreconditionFailedException(
521
"Did not start at least %f metres from destination (is=%f)" %
522
(wp_dist_min, m.wp_dist))
523
524
self.progress("NAV_CONTROLLER_OUTPUT.wp_dist looks good (%u >= %u)" %
525
(m.wp_dist, wp_dist_min,))
526
527
# wait for mission to complete
528
self.wait_statustext("Mission Complete", timeout=70)
529
530
# the EKF doesn't pull us down to 0 speed:
531
self.wait_groundspeed(0, 0.5, timeout=600)
532
533
# current Rover blows straight past the home position and ends
534
# up ~6m past the home point.
535
home_distance = self.distance_to_home()
536
home_distance_min = 5.5
537
home_distance_max = self.drive_rtl_mission_max_distance_from_home()
538
if home_distance > home_distance_max:
539
raise NotAchievedException(
540
"Did not stop near home (%f metres distant (%f > want > %f))" %
541
(home_distance, home_distance_min, home_distance_max))
542
self.disarm_vehicle()
543
self.progress("RTL Mission OK (%fm)" % home_distance)
544
545
def RTL_SPEED(self, timeout=120):
546
'''Test RTL_SPEED is honoured'''
547
548
self.upload_simple_relhome_mission([
549
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 300, 0, 0),
550
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 1000, 0, 0),
551
])
552
553
self.wait_ready_to_arm()
554
self.arm_vehicle()
555
556
self.change_mode('AUTO')
557
self.wait_current_waypoint(2, timeout=120)
558
for speed in 1, 5.5, 1.5, 7.5:
559
self.set_parameter("RTL_SPEED", speed)
560
self.change_mode('RTL')
561
self.wait_groundspeed(speed-0.1, speed+0.1, minimum_duration=10)
562
self.change_mode('HOLD')
563
self.do_RTL()
564
self.disarm_vehicle()
565
566
def AC_Avoidance(self):
567
'''Test AC Avoidance switch'''
568
self.load_fence("rover-fence-ac-avoid.txt")
569
self.set_parameters({
570
"FENCE_ENABLE": 0,
571
"PRX1_TYPE": 10,
572
"RC10_OPTION": 40, # proximity-enable
573
})
574
self.reboot_sitl()
575
# start = self.mav.location()
576
self.wait_ready_to_arm()
577
self.arm_vehicle()
578
# first make sure we can breach the fence:
579
self.set_rc(10, 1000)
580
self.change_mode("ACRO")
581
self.set_rc(3, 1550)
582
self.wait_distance_to_home(25, 100000, timeout=60)
583
self.change_mode("RTL")
584
self.wait_statustext("Reached destination", timeout=60)
585
# now enable avoidance and make sure we can't:
586
self.set_rc(10, 2000)
587
self.change_mode("ACRO")
588
self.wait_groundspeed(0, 0.7, timeout=60)
589
# watch for speed zero
590
self.wait_groundspeed(0, 0.2, timeout=120)
591
self.disarm_vehicle()
592
593
def ServoRelayEvents(self):
594
'''Test ServoRelayEvents'''
595
for method in self.run_cmd, self.run_cmd_int:
596
self.context_push()
597
598
self.set_parameters({
599
"RELAY1_FUNCTION": 1, # Enable relay 1 as a standard relay pin
600
"RELAY2_FUNCTION": 1, # Enable relay 2 as a standard relay pin
601
})
602
self.reboot_sitl() # Needed for relay functions to take effect
603
604
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=0)
605
off = self.get_parameter("SIM_PIN_MASK")
606
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=1)
607
on = self.get_parameter("SIM_PIN_MASK")
608
if on == off:
609
raise NotAchievedException(
610
"Pin mask unchanged after relay cmd")
611
self.progress("Pin mask changed after relay command")
612
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=0)
613
614
self.set_message_rate_hz("RELAY_STATUS", 10)
615
616
# default configuration for relays in sim have one relay:
617
self.assert_received_message_field_values('RELAY_STATUS', {
618
"present": 3,
619
"on": 0,
620
})
621
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=1)
622
self.assert_received_message_field_values('RELAY_STATUS', {
623
"present": 3,
624
"on": 1,
625
})
626
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=1, p2=1)
627
self.assert_received_message_field_values('RELAY_STATUS', {
628
"present": 3,
629
"on": 3,
630
})
631
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=0)
632
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=1, p2=0)
633
self.assert_received_message_field_values('RELAY_STATUS', {
634
"present": 3,
635
"on": 0,
636
})
637
638
# add another relay and ensure that it changes the "present field"
639
self.set_parameters({
640
"RELAY6_FUNCTION": 1, # Enable relay 6 as a standard relay pin
641
"RELAY6_PIN": 14, # Set pin number
642
})
643
self.reboot_sitl() # Needed for relay function to take effect
644
self.set_message_rate_hz("RELAY_STATUS", 10) # Need to re-request the message since reboot
645
646
self.assert_received_message_field_values('RELAY_STATUS', {
647
"present": 35,
648
"on": 0,
649
})
650
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=5, p2=1)
651
self.assert_received_message_field_values('RELAY_STATUS', {
652
"present": 35,
653
"on": 32,
654
})
655
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=0, p2=1)
656
self.assert_received_message_field_values('RELAY_STATUS', {
657
"present": 35,
658
"on": 33,
659
})
660
method(mavutil.mavlink.MAV_CMD_DO_SET_RELAY, p1=5, p2=0)
661
self.assert_received_message_field_values('RELAY_STATUS', {
662
"present": 35,
663
"on": 1,
664
})
665
666
self.start_subtest("test MAV_CMD_DO_REPEAT_RELAY")
667
self.context_push()
668
self.set_parameter("SIM_SPEEDUP", 1)
669
method(
670
mavutil.mavlink.MAV_CMD_DO_REPEAT_RELAY,
671
p1=0, # servo 1
672
p2=5, # 5 times
673
p3=0.5, # 1 second between being on
674
)
675
for value in 0, 1, 0, 1, 0, 1, 0, 1:
676
self.wait_message_field_values('RELAY_STATUS', {
677
"on": value,
678
})
679
self.context_pop()
680
self.delay_sim_time(3)
681
self.assert_received_message_field_values('RELAY_STATUS', {
682
"on": 1, # back to initial state
683
})
684
self.context_pop()
685
686
self.start_subtest("test MAV_CMD_DO_SET_SERVO")
687
for value in 1678, 2300, 0:
688
method(mavutil.mavlink.MAV_CMD_DO_SET_SERVO, p1=13, p2=value)
689
self.wait_servo_channel_value(13, value)
690
691
self.start_subtest("test MAV_CMD_DO_REPEAT_SERVO")
692
693
self.context_push()
694
self.set_parameter("SIM_SPEEDUP", 1)
695
trim = self.get_parameter("SERVO13_TRIM")
696
value = 2000
697
method(
698
mavutil.mavlink.MAV_CMD_DO_REPEAT_SERVO,
699
p1=12, # servo12
700
p2=value, # pwm
701
p3=5, # count
702
p4=0.5, # cycle time (1 second between high and high)
703
)
704
for value in trim, value, trim, value, trim, value, trim, value:
705
self.wait_servo_channel_value(12, value)
706
self.context_pop()
707
708
self.set_message_rate_hz("RELAY_STATUS", 0)
709
710
def MAVProxy_SetModeUsingSwitch(self):
711
"""Set modes via mavproxy switch"""
712
port = self.sitl_rcin_port(offset=1)
713
self.customise_SITL_commandline([
714
"--rc-in-port", str(port),
715
])
716
ex = None
717
try:
718
self.load_mission(self.arming_test_mission())
719
self.wait_ready_to_arm()
720
fnoo = [(1, 'MANUAL'),
721
(2, 'MANUAL'),
722
(3, 'RTL'),
723
(4, 'AUTO'),
724
(5, 'AUTO'), # non-existent mode, should stay in RTL
725
(6, 'MANUAL')]
726
mavproxy = self.start_mavproxy(sitl_rcin_port=port)
727
for (num, expected) in fnoo:
728
mavproxy.send('switch %u\n' % num)
729
self.wait_mode(expected)
730
self.stop_mavproxy(mavproxy)
731
except Exception as e:
732
self.print_exception_caught(e)
733
ex = e
734
735
# if we don't put things back ourselves then the test cleanup
736
# doesn't go well as we can't set the RC defaults correctly:
737
self.customise_SITL_commandline([
738
])
739
740
if ex is not None:
741
raise ex
742
743
def MAVProxy_SetModeUsingMode(self):
744
'''Set modes via mavproxy mode command'''
745
fnoo = [(1, 'ACRO'),
746
(3, 'STEERING'),
747
(4, 'HOLD'),
748
]
749
mavproxy = self.start_mavproxy()
750
for (num, expected) in fnoo:
751
mavproxy.send('mode manual\n')
752
self.wait_mode("MANUAL")
753
mavproxy.send('mode %u\n' % num)
754
self.wait_mode(expected)
755
mavproxy.send('mode manual\n')
756
self.wait_mode("MANUAL")
757
mavproxy.send('mode %s\n' % expected)
758
self.wait_mode(expected)
759
self.stop_mavproxy(mavproxy)
760
761
def ModeSwitch(self):
762
''''Set modes via modeswitch'''
763
self.set_parameter("MODE_CH", 8)
764
self.set_rc(8, 1000)
765
# mavutil.mavlink.ROVER_MODE_HOLD:
766
self.set_parameter("MODE6", 4)
767
# mavutil.mavlink.ROVER_MODE_ACRO
768
self.set_parameter("MODE5", 1)
769
self.set_rc(8, 1800) # PWM for mode6
770
self.wait_mode("HOLD")
771
self.set_rc(8, 1700) # PWM for mode5
772
self.wait_mode("ACRO")
773
self.set_rc(8, 1800) # PWM for mode6
774
self.wait_mode("HOLD")
775
self.set_rc(8, 1700) # PWM for mode5
776
self.wait_mode("ACRO")
777
778
def AuxModeSwitch(self):
779
'''Set modes via auxswitches'''
780
# from mavproxy_rc.py
781
mapping = [0, 1165, 1295, 1425, 1555, 1685, 1815]
782
self.set_parameter("MODE1", 1) # acro
783
self.set_rc(8, mapping[1])
784
self.wait_mode('ACRO')
785
786
self.set_rc(9, 1000)
787
self.set_rc(10, 1000)
788
self.set_parameters({
789
"RC9_OPTION": 53, # steering
790
"RC10_OPTION": 54, # hold
791
})
792
self.set_rc(9, 1900)
793
self.wait_mode("STEERING")
794
self.set_rc(10, 1900)
795
self.wait_mode("HOLD")
796
797
# reset both switches - should go back to ACRO
798
self.set_rc(9, 1000)
799
self.set_rc(10, 1000)
800
self.wait_mode("ACRO")
801
802
self.set_rc(9, 1900)
803
self.wait_mode("STEERING")
804
self.set_rc(10, 1900)
805
self.wait_mode("HOLD")
806
807
self.set_rc(10, 1000) # this re-polls the mode switch
808
self.wait_mode("ACRO")
809
self.set_rc(9, 1000)
810
811
def RCOverridesCancel(self):
812
'''Test RC overrides Cancel'''
813
self.set_parameter("MAV_GCS_SYSID", self.mav.source_system)
814
self.change_mode('MANUAL')
815
self.wait_ready_to_arm()
816
self.zero_throttle()
817
self.arm_vehicle()
818
# start moving forward a little:
819
normal_rc_throttle = 1700
820
throttle_override = 1900
821
822
self.progress("Establishing baseline RC input")
823
self.set_rc(3, normal_rc_throttle)
824
self.drain_mav()
825
tstart = self.get_sim_time()
826
while True:
827
if self.get_sim_time_cached() - tstart > 10:
828
raise AutoTestTimeoutException("Did not get rc change")
829
m = self.assert_receive_message('RC_CHANNELS')
830
if m.chan3_raw == normal_rc_throttle:
831
break
832
833
self.progress("Set override with RC_CHANNELS_OVERRIDE")
834
self.drain_mav()
835
tstart = self.get_sim_time()
836
while True:
837
if self.get_sim_time_cached() - tstart > 10:
838
raise AutoTestTimeoutException("Did not override")
839
self.progress("Sending throttle of %u" % (throttle_override,))
840
self.mav.mav.rc_channels_override_send(
841
1, # target system
842
1, # targe component
843
65535, # chan1_raw
844
65535, # chan2_raw
845
throttle_override, # chan3_raw
846
65535, # chan4_raw
847
65535, # chan5_raw
848
65535, # chan6_raw
849
65535, # chan7_raw
850
65535) # chan8_raw
851
852
m = self.assert_receive_message('RC_CHANNELS')
853
self.progress("chan3=%f want=%f" % (m.chan3_raw, throttle_override))
854
if m.chan3_raw == throttle_override:
855
break
856
857
self.progress("disabling override and making sure we revert to RC input in good time")
858
self.drain_mav()
859
tstart = self.get_sim_time()
860
while True:
861
if self.get_sim_time_cached() - tstart > 0.5:
862
raise AutoTestTimeoutException("Did not cancel override")
863
self.progress("Sending cancel of throttle override")
864
self.mav.mav.rc_channels_override_send(
865
1, # target system
866
1, # targe component
867
65535, # chan1_raw
868
65535, # chan2_raw
869
0, # chan3_raw
870
65535, # chan4_raw
871
65535, # chan5_raw
872
65535, # chan6_raw
873
65535, # chan7_raw
874
65535) # chan8_raw
875
self.do_timesync_roundtrip()
876
m = self.assert_receive_message('RC_CHANNELS')
877
self.progress("chan3=%f want=%f" % (m.chan3_raw, normal_rc_throttle))
878
if m.chan3_raw == normal_rc_throttle:
879
break
880
self.disarm_vehicle()
881
882
def RCOverrides(self):
883
'''Test RC overrides'''
884
self.set_parameter("MAV_GCS_SYSID", self.mav.source_system)
885
self.set_parameter("RC12_OPTION", 46)
886
self.reboot_sitl()
887
888
self.change_mode('MANUAL')
889
self.wait_ready_to_arm()
890
self.set_rc(3, 1500) # throttle at zero
891
self.arm_vehicle()
892
# start moving forward a little:
893
normal_rc_throttle = 1700
894
self.set_rc(3, normal_rc_throttle)
895
self.wait_groundspeed(5, 100)
896
897
# allow overrides:
898
self.set_rc(12, 2000)
899
900
# now override to stop:
901
throttle_override = 1500
902
903
tstart = self.get_sim_time_cached()
904
while True:
905
if self.get_sim_time_cached() - tstart > 10:
906
raise AutoTestTimeoutException("Did not reach speed")
907
self.progress("Sending throttle of %u" % (throttle_override,))
908
self.mav.mav.rc_channels_override_send(
909
1, # target system
910
1, # targe component
911
65535, # chan1_raw
912
65535, # chan2_raw
913
throttle_override, # chan3_raw
914
65535, # chan4_raw
915
65535, # chan5_raw
916
65535, # chan6_raw
917
65535, # chan7_raw
918
65535) # chan8_raw
919
920
m = self.assert_receive_message('VFR_HUD')
921
want_speed = 2.0
922
self.progress("Speed=%f want=<%f" % (m.groundspeed, want_speed))
923
if m.groundspeed < want_speed:
924
break
925
926
# now override to stop - but set the switch on the RC
927
# transmitter to deny overrides; this should send the
928
# speed back up to 5 metres/second:
929
self.set_rc(12, 1000)
930
931
throttle_override = 1500
932
tstart = self.get_sim_time_cached()
933
while True:
934
if self.get_sim_time_cached() - tstart > 10:
935
raise AutoTestTimeoutException("Did not speed back up")
936
self.progress("Sending throttle of %u" % (throttle_override,))
937
self.mav.mav.rc_channels_override_send(
938
1, # target system
939
1, # targe component
940
65535, # chan1_raw
941
65535, # chan2_raw
942
throttle_override, # chan3_raw
943
65535, # chan4_raw
944
65535, # chan5_raw
945
65535, # chan6_raw
946
65535, # chan7_raw
947
65535) # chan8_raw
948
949
m = self.assert_receive_message('VFR_HUD')
950
want_speed = 5.0
951
self.progress("Speed=%f want=>%f" % (m.groundspeed, want_speed))
952
953
if m.groundspeed > want_speed:
954
break
955
956
# re-enable RC overrides
957
self.set_rc(12, 2000)
958
959
# check we revert to normal RC inputs when gcs overrides cease:
960
self.progress("Waiting for RC to revert to normal RC input")
961
self.wait_rc_channel_value(3, normal_rc_throttle, timeout=10)
962
963
self.start_subtest("Check override time of zero disables overrides")
964
old = self.get_parameter("RC_OVERRIDE_TIME")
965
ch = 2
966
self.set_rc(ch, 1000)
967
channels = [65535] * 18
968
ch_override_value = 1700
969
channels[ch-1] = ch_override_value
970
channels[7] = 1234 # that's channel 8!
971
self.progress("Sending override message %u" % ch_override_value)
972
self.mav.mav.rc_channels_override_send(
973
1, # target system
974
1, # targe component
975
*channels
976
)
977
# long timeout required here as we may have sent a lot of
978
# things via MAVProxy...
979
self.wait_rc_channel_value(ch, ch_override_value, timeout=30)
980
self.set_parameter("RC_OVERRIDE_TIME", 0)
981
self.wait_rc_channel_value(ch, 1000)
982
self.set_parameter("RC_OVERRIDE_TIME", old)
983
self.wait_rc_channel_value(ch, ch_override_value)
984
985
ch_override_value = 1720
986
channels[ch-1] = ch_override_value
987
self.progress("Sending override message %u" % ch_override_value)
988
self.mav.mav.rc_channels_override_send(
989
1, # target system
990
1, # targe component
991
*channels
992
)
993
self.wait_rc_channel_value(ch, ch_override_value, timeout=10)
994
self.set_parameter("RC_OVERRIDE_TIME", 0)
995
self.wait_rc_channel_value(ch, 1000)
996
self.set_parameter("RC_OVERRIDE_TIME", old)
997
998
self.progress("Ensuring timeout works")
999
self.wait_rc_channel_value(ch, 1000, timeout=5)
1000
self.delay_sim_time(10)
1001
1002
self.set_parameter("RC_OVERRIDE_TIME", 10)
1003
self.progress("Sending override message")
1004
1005
ch_override_value = 1730
1006
channels[ch-1] = ch_override_value
1007
self.progress("Sending override message %u" % ch_override_value)
1008
self.mav.mav.rc_channels_override_send(
1009
1, # target system
1010
1, # targe component
1011
*channels
1012
)
1013
self.wait_rc_channel_value(ch, ch_override_value, timeout=10)
1014
tstart = self.get_sim_time()
1015
self.progress("Waiting for channel to revert to 1000 in ~10s")
1016
self.wait_rc_channel_value(ch, 1000, timeout=15)
1017
delta = self.get_sim_time() - tstart
1018
if delta > 12:
1019
raise NotAchievedException("Took too long to revert RC channel value (delta=%f)" % delta)
1020
min_delta = 9
1021
if delta < min_delta:
1022
raise NotAchievedException("Didn't take long enough to revert RC channel value (delta=%f want>=%f)" %
1023
(delta, min_delta))
1024
self.progress("Disabling RC override timeout")
1025
self.set_parameter("RC_OVERRIDE_TIME", -1)
1026
ch_override_value = 1740
1027
channels[ch-1] = ch_override_value
1028
self.progress("Sending override message %u" % ch_override_value)
1029
self.mav.mav.rc_channels_override_send(
1030
1, # target system
1031
1, # targe component
1032
*channels
1033
)
1034
self.wait_rc_channel_value(ch, ch_override_value, timeout=10)
1035
tstart = self.get_sim_time()
1036
while True:
1037
# warning: this is get_sim_time() and can slurp messages on you!
1038
delta = self.get_sim_time() - tstart
1039
if delta > 20:
1040
break
1041
m = self.assert_receive_message('RC_CHANNELS')
1042
channel_field = "chan%u_raw" % ch
1043
m_value = getattr(m, channel_field)
1044
if m_value != ch_override_value:
1045
raise NotAchievedException("Value reverted after %f seconds when it should not have (got=%u) (want=%u)" % (delta, m_value, ch_override_value)) # noqa
1046
self.set_parameter("RC_OVERRIDE_TIME", old)
1047
1048
self.delay_sim_time(10)
1049
1050
self.start_subtest("Checking higher-channel semantics")
1051
self.context_push()
1052
self.set_parameter("RC_OVERRIDE_TIME", 30)
1053
1054
ch = 11
1055
rc_value = 1010
1056
self.set_rc(ch, rc_value)
1057
1058
channels = [65535] * 18
1059
ch_override_value = 1234
1060
channels[ch-1] = ch_override_value
1061
self.progress("Sending override message ch%u=%u" % (ch, ch_override_value))
1062
self.mav.mav.rc_channels_override_send(
1063
1, # target system
1064
1, # targe component
1065
*channels
1066
)
1067
self.progress("Wait for override value")
1068
self.wait_rc_channel_value(ch, ch_override_value, timeout=10)
1069
1070
self.progress("Sending return-to-RC-input value")
1071
channels[ch-1] = 65534
1072
self.mav.mav.rc_channels_override_send(
1073
1, # target system
1074
1, # targe component
1075
*channels
1076
)
1077
self.wait_rc_channel_value(ch, rc_value, timeout=10)
1078
1079
channels[ch-1] = ch_override_value
1080
self.progress("Sending override message ch%u=%u" % (ch, ch_override_value))
1081
self.mav.mav.rc_channels_override_send(
1082
1, # target system
1083
1, # targe component
1084
*channels
1085
)
1086
self.progress("Wait for override value")
1087
self.wait_rc_channel_value(ch, ch_override_value, timeout=10)
1088
1089
# make we keep the override value for at least 10 seconds:
1090
tstart = self.get_sim_time()
1091
while True:
1092
if self.get_sim_time_cached() - tstart > 10:
1093
break
1094
# try both ignore values:
1095
ignore_value = 0
1096
if self.get_sim_time_cached() - tstart > 5:
1097
ignore_value = 65535
1098
self.progress("Sending ignore value %u" % ignore_value)
1099
channels[ch-1] = ignore_value
1100
self.mav.mav.rc_channels_override_send(
1101
1, # target system
1102
1, # targe component
1103
*channels
1104
)
1105
if self.get_rc_channel_value(ch) != ch_override_value:
1106
raise NotAchievedException("Did not maintain value")
1107
1108
self.context_pop()
1109
1110
self.end_subtest("Checking higher-channel semantics")
1111
1112
self.disarm_vehicle()
1113
1114
def MANUAL_CONTROL(self):
1115
'''Test mavlink MANUAL_CONTROL'''
1116
self.set_parameters({
1117
"MAV_GCS_SYSID": self.mav.source_system,
1118
"RC12_OPTION": 46, # enable/disable rc overrides
1119
})
1120
self.reboot_sitl()
1121
1122
self.change_mode("MANUAL")
1123
self.wait_ready_to_arm()
1124
self.arm_vehicle()
1125
self.progress("start moving forward a little")
1126
normal_rc_throttle = 1700
1127
self.set_rc(3, normal_rc_throttle)
1128
self.wait_groundspeed(5, 100)
1129
1130
self.progress("allow overrides")
1131
self.set_rc(12, 2000)
1132
1133
self.progress("now override to stop")
1134
throttle_override_normalized = 0
1135
expected_throttle = 0 # in VFR_HUD
1136
1137
tstart = self.get_sim_time_cached()
1138
while True:
1139
if self.get_sim_time_cached() - tstart > 10:
1140
raise AutoTestTimeoutException("Did not reach speed")
1141
self.progress("Sending normalized throttle of %d" % (throttle_override_normalized,))
1142
self.mav.mav.manual_control_send(
1143
1, # target system
1144
32767, # x (pitch)
1145
32767, # y (roll)
1146
throttle_override_normalized, # z (thrust)
1147
32767, # r (yaw)
1148
0) # button mask
1149
1150
m = self.assert_receive_message('VFR_HUD')
1151
want_speed = 2.0
1152
self.progress("Speed=%f want=<%f throttle=%u want=%u" %
1153
(m.groundspeed, want_speed, m.throttle, expected_throttle))
1154
if m.groundspeed < want_speed and m.throttle == expected_throttle:
1155
break
1156
1157
self.progress("now override to stop - but set the switch on the RC transmitter to deny overrides; this should send the speed back up to 5 metres/second") # noqa
1158
self.set_rc(12, 1000)
1159
1160
throttle_override_normalized = 500
1161
expected_throttle = 36 # in VFR_HUD, corresponding to normal_rc_throttle adjusted for channel min/max
1162
1163
tstart = self.get_sim_time_cached()
1164
while True:
1165
if self.get_sim_time_cached() - tstart > 10:
1166
raise AutoTestTimeoutException("Did not stop")
1167
self.progress("Sending normalized throttle of %u" % (throttle_override_normalized,))
1168
self.mav.mav.manual_control_send(
1169
1, # target system
1170
32767, # x (pitch)
1171
32767, # y (roll)
1172
throttle_override_normalized, # z (thrust)
1173
32767, # r (yaw)
1174
0) # button mask
1175
1176
m = self.assert_receive_message('VFR_HUD')
1177
want_speed = 5.0
1178
1179
self.progress("Speed=%f want=>%f throttle=%u want=%u" %
1180
(m.groundspeed, want_speed, m.throttle, expected_throttle))
1181
if m.groundspeed > want_speed and m.throttle == expected_throttle:
1182
break
1183
1184
# re-enable RC overrides
1185
self.set_rc(12, 2000)
1186
1187
# check we revert to normal RC inputs when gcs overrides cease:
1188
self.progress("Waiting for RC to revert to normal RC input")
1189
self.wait_rc_channel_value(3, normal_rc_throttle, timeout=10)
1190
1191
self.disarm_vehicle()
1192
1193
def CameraMission(self):
1194
'''Test Camera Mission Items'''
1195
self.set_parameter("CAM1_TYPE", 1) # Camera with servo trigger
1196
self.reboot_sitl() # needed for CAM1_TYPE to take effect
1197
self.load_mission("rover-camera-mission.txt")
1198
self.wait_ready_to_arm()
1199
self.change_mode("AUTO")
1200
self.wait_ready_to_arm()
1201
self.arm_vehicle()
1202
prev_cf = None
1203
while True:
1204
cf = self.assert_receive_message('CAMERA_FEEDBACK')
1205
if prev_cf is None:
1206
prev_cf = cf
1207
continue
1208
dist_travelled = self.get_distance_int(prev_cf, cf)
1209
prev_cf = cf
1210
mc = self.mav.messages.get("MISSION_CURRENT", None)
1211
if mc is None:
1212
continue
1213
elif mc.seq == 2:
1214
expected_distance = 2
1215
elif mc.seq == 4:
1216
expected_distance = 5
1217
elif mc.seq == 5:
1218
break
1219
else:
1220
continue
1221
self.progress("Expected distance %f got %f" %
1222
(expected_distance, dist_travelled))
1223
error = abs(expected_distance - dist_travelled)
1224
# Rover moves at ~5m/s; we appear to do something at
1225
# 5Hz, so we do see over a meter of error!
1226
max_error = 1.5
1227
if error > max_error:
1228
raise NotAchievedException("Camera distance error: %f (%f)" %
1229
(error, max_error))
1230
1231
self.disarm_vehicle()
1232
1233
def DO_SET_MODE(self):
1234
'''Set mode via MAV_COMMAND_DO_SET_MODE'''
1235
self.do_set_mode_via_command_long("HOLD")
1236
self.do_set_mode_via_command_long("MANUAL")
1237
self.do_set_mode_via_command_int("HOLD")
1238
self.do_set_mode_via_command_int("MANUAL")
1239
1240
def RoverInitialMode(self):
1241
'''test INITIAL_MODE parameter works'''
1242
# from mavproxy_rc.py
1243
self.wait_ready_to_arm()
1244
mapping = [0, 1165, 1295, 1425, 1555, 1685, 1815]
1245
mode_ch = 8
1246
throttle_ch = 3
1247
self.set_parameter('MODE5', 3)
1248
self.set_rc(mode_ch, mapping[5])
1249
self.wait_mode('STEERING')
1250
self.set_rc(mode_ch, mapping[6])
1251
self.wait_mode('MANUAL')
1252
self.set_parameter("INITIAL_MODE", 1) # acro
1253
# stop the vehicle polling the mode switch at boot:
1254
self.set_parameter('FS_ACTION', 0) # do nothing when radio fails
1255
self.set_rc(throttle_ch, 900) # RC fail
1256
self.reboot_sitl()
1257
self.wait_mode(1)
1258
self.progress("Make sure we stay in this mode")
1259
self.delay_sim_time(5)
1260
self.wait_mode(1)
1261
# now change modes with a switch:
1262
self.set_rc(throttle_ch, 1100)
1263
self.delay_sim_time(3)
1264
self.set_rc(mode_ch, mapping[5])
1265
self.wait_mode('STEERING')
1266
1267
def MAVProxy_DO_SET_MODE(self):
1268
'''Set mode using MAVProxy commandline DO_SET_MODE'''
1269
mavproxy = self.start_mavproxy()
1270
self.mavproxy_do_set_mode_via_command_long(mavproxy, "HOLD")
1271
self.mavproxy_do_set_mode_via_command_long(mavproxy, "MANUAL")
1272
self.stop_mavproxy(mavproxy)
1273
1274
def MAV_GCS_ENFORCE(self):
1275
'''Test enforcement of strict mode for MAV_GCS_SYSID'''
1276
'''Run the same arming code with correct then incorrect SYSID'''
1277
1278
if self.mav.source_system != self.mav.mav.srcSystem:
1279
raise PreconditionFailedException("Expected mav.source_system and mav.srcSystem to match")
1280
1281
self.context_push()
1282
old_srcSystem = self.mav.mav.srcSystem
1283
ex = None
1284
try:
1285
self.set_parameter("MAV_GCS_SYSID", self.mav.source_system)
1286
self.set_parameter("MAV_OPTIONS", 1, add_to_context=False)
1287
1288
self.change_mode('MANUAL')
1289
1290
self.progress("make sure I can arm ATM")
1291
self.wait_ready_to_arm()
1292
self.arm_vehicle(timeout=5)
1293
self.disarm_vehicle()
1294
1295
self.do_timesync_roundtrip()
1296
1297
# should not be able to arm from a system id which is not MY_SYSID
1298
self.progress("Attempting to arm vehicle from bad system-id")
1299
success = None
1300
try:
1301
# temporarily set a different system ID than normal:
1302
self.mav.mav.srcSystem = 72
1303
self.arm_vehicle(timeout=5)
1304
self.disarm_vehicle()
1305
success = False
1306
except AutoTestTimeoutException:
1307
success = True
1308
self.mav.mav.srcSystem = old_srcSystem
1309
if not success:
1310
raise NotAchievedException("Managed to arm with MAV_GCS enforce set")
1311
1312
# should be able to arm from the vehicle's own components:
1313
self.progress("Attempting to arm vehicle from vehicle component")
1314
comp_arm_exception = None
1315
try:
1316
self.mav.mav.srcSystem = 1
1317
self.arm_vehicle(timeout=5)
1318
self.disarm_vehicle()
1319
except Exception as e:
1320
comp_arm_exception = e
1321
self.mav.mav.srcSystem = old_srcSystem
1322
if comp_arm_exception is not None:
1323
raise comp_arm_exception
1324
1325
except Exception as e:
1326
self.print_exception_caught(e)
1327
ex = e
1328
self.mav.mav.srcSystem = old_srcSystem
1329
self.set_parameter("MAV_OPTIONS", 0, add_to_context=False)
1330
self.context_pop()
1331
if ex is not None:
1332
raise ex
1333
1334
def Rally(self):
1335
'''Test Rally Points'''
1336
self.load_rally_using_mavproxy("rover-test-rally.txt")
1337
self.assert_parameter_value('RALLY_TOTAL', 2)
1338
1339
self.wait_ready_to_arm()
1340
self.arm_vehicle()
1341
1342
# calculate early to avoid round-trips while vehicle is moving:
1343
accuracy = self.get_parameter("WP_RADIUS")
1344
1345
self.reach_heading_manual(10)
1346
self.reach_distance_manual(50)
1347
1348
self.change_mode("RTL")
1349
1350
# location copied in from rover-test-rally.txt:
1351
loc = mavutil.location(40.071553,
1352
-105.229401,
1353
1583,
1354
0)
1355
1356
self.wait_location(loc, accuracy=accuracy, minimum_duration=10, timeout=45)
1357
self.disarm_vehicle()
1358
1359
def fence_with_bad_frame(self, target_system=1, target_component=1):
1360
return [
1361
self.mav.mav.mission_item_int_encode(
1362
target_system,
1363
target_component,
1364
0, # seq
1365
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
1366
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1367
0, # current
1368
0, # autocontinue
1369
0, # p1
1370
0, # p2
1371
0, # p3
1372
0, # p4
1373
int(1.0017 * 1e7), # latitude
1374
int(1.0017 * 1e7), # longitude
1375
31.0000, # altitude
1376
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1377
]
1378
1379
def fence_with_zero_vertex_count(self, target_system=1, target_component=1):
1380
return [
1381
self.mav.mav.mission_item_int_encode(
1382
target_system,
1383
target_component,
1384
0, # seq
1385
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1386
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1387
0, # current
1388
0, # autocontinue
1389
0, # p1
1390
0, # p2
1391
0, # p3
1392
0, # p4
1393
int(1.0017 * 1e7), # latitude
1394
int(1.0017 * 1e7), # longitude
1395
31.0000, # altitude
1396
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1397
]
1398
1399
def fence_with_wrong_vertex_count(self, target_system=1, target_component=1):
1400
return [
1401
self.mav.mav.mission_item_int_encode(
1402
target_system,
1403
target_component,
1404
0, # seq
1405
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1406
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1407
0, # current
1408
0, # autocontinue
1409
2, # p1
1410
0, # p2
1411
0, # p3
1412
0, # p4
1413
int(1.0017 * 1e7), # latitude
1414
int(1.0017 * 1e7), # longitude
1415
31.0000, # altitude
1416
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1417
]
1418
1419
def fence_with_multiple_return_points(self, target_system=1, target_component=1):
1420
return [
1421
self.mav.mav.mission_item_int_encode(
1422
target_system,
1423
target_component,
1424
0, # seq
1425
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1426
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1427
0, # current
1428
0, # autocontinue
1429
0, # p1
1430
0, # p2
1431
0, # p3
1432
0, # p4
1433
int(1.0017 * 1e7), # latitude
1434
int(1.0017 * 1e7), # longitude
1435
31.0000, # altitude
1436
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1437
self.mav.mav.mission_item_int_encode(
1438
target_system,
1439
target_component,
1440
1, # seq
1441
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1442
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1443
0, # current
1444
0, # autocontinue
1445
0, # p1
1446
0, # p2
1447
0, # p3
1448
0, # p4
1449
int(1.0017 * 1e7), # latitude
1450
int(1.0017 * 1e7), # longitude
1451
31.0000, # altitude
1452
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1453
]
1454
1455
def fence_with_invalid_latlon(self, target_system=1, target_component=1):
1456
return [
1457
self.mav.mav.mission_item_int_encode(
1458
target_system,
1459
target_component,
1460
0, # seq
1461
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1462
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1463
0, # current
1464
0, # autocontinue
1465
0, # p1
1466
0, # p2
1467
0, # p3
1468
0, # p4
1469
int(100 * 1e7), # bad latitude. bad.
1470
int(1.0017 * 1e7), # longitude
1471
31.0000, # altitude
1472
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1473
]
1474
1475
def fence_with_multiple_return_points_with_bad_sequence_numbers(self, target_system=1, target_component=1):
1476
return [
1477
self.mav.mav.mission_item_int_encode(
1478
target_system,
1479
target_component,
1480
0, # seq
1481
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1482
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1483
0, # current
1484
0, # autocontinue
1485
0, # p1
1486
0, # p2
1487
0, # p3
1488
0, # p4
1489
int(1.0 * 1e7), # latitude
1490
int(1.0017 * 1e7), # longitude
1491
31.0000, # altitude
1492
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1493
self.mav.mav.mission_item_int_encode(
1494
target_system,
1495
target_component,
1496
0, # seq
1497
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1498
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1499
0, # current
1500
0, # autocontinue
1501
0, # p1
1502
0, # p2
1503
0, # p3
1504
0, # p4
1505
int(2.0 * 1e7), # latitude
1506
int(2.0017 * 1e7), # longitude
1507
31.0000, # altitude
1508
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1509
]
1510
1511
def fence_which_exceeds_storage_space(self, target_system=1, target_component=1):
1512
ret = []
1513
for i in range(0, 60):
1514
ret.append(self.mav.mav.mission_item_int_encode(
1515
target_system,
1516
target_component,
1517
i, # seq
1518
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1519
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
1520
0, # current
1521
0, # autocontinue
1522
10, # p1
1523
0, # p2
1524
0, # p3
1525
0, # p4
1526
int(1.0 * 1e7), # latitude
1527
int(1.0017 * 1e7), # longitude
1528
31.0000, # altitude
1529
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1530
)
1531
return ret
1532
1533
def fences_which_should_not_upload(self, target_system=1, target_component=1):
1534
return [
1535
("Bad Frame", self.fence_with_bad_frame(
1536
target_system=target_system,
1537
target_component=target_component)),
1538
("Zero Vertex Count", self.fence_with_zero_vertex_count(
1539
target_system=target_system,
1540
target_component=target_component)),
1541
("Wrong Vertex Count", self.fence_with_wrong_vertex_count(
1542
target_system=target_system,
1543
target_component=target_component)),
1544
("Multiple return points", self.fence_with_multiple_return_points(
1545
target_system=target_system,
1546
target_component=target_component)),
1547
("Invalid lat/lon", self.fence_with_invalid_latlon(
1548
target_system=target_system,
1549
target_component=target_component)),
1550
("Multiple Return points with bad sequence numbers",
1551
self.fence_with_multiple_return_points_with_bad_sequence_numbers( # noqa
1552
target_system=target_system,
1553
target_component=target_component)),
1554
("Fence which exceeds storage space",
1555
self.fence_which_exceeds_storage_space(
1556
target_system=target_system,
1557
target_component=target_component)),
1558
]
1559
1560
def fence_with_single_return_point(self, target_system=1, target_component=1):
1561
return [
1562
self.mav.mav.mission_item_int_encode(
1563
target_system,
1564
target_component,
1565
0, # seq
1566
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1567
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1568
0, # current
1569
0, # autocontinue
1570
0, # p1
1571
0, # p2
1572
0, # p3
1573
0, # p4
1574
int(1.0017 * 1e7), # latitude
1575
int(1.0017 * 1e7), # longitude
1576
31.0000, # altitude
1577
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1578
]
1579
1580
def fence_with_single_return_point_and_5_vertex_inclusion(self,
1581
target_system=1,
1582
target_component=1):
1583
return [
1584
self.mav.mav.mission_item_int_encode(
1585
target_system,
1586
target_component,
1587
0, # seq
1588
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1589
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
1590
0, # current
1591
0, # autocontinue
1592
0, # p1
1593
0, # p2
1594
0, # p3
1595
0, # p4
1596
int(1.0017 * 1e7), # latitude
1597
int(1.0017 * 1e7), # longitude
1598
31.0000, # altitude
1599
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1600
self.mav.mav.mission_item_int_encode(
1601
target_system,
1602
target_component,
1603
1, # seq
1604
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1605
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1606
0, # current
1607
0, # autocontinue
1608
5, # p1
1609
0, # p2
1610
0, # p3
1611
0, # p4
1612
int(1.0000 * 1e7), # latitude
1613
int(1.0000 * 1e7), # longitude
1614
31.0000, # altitude
1615
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1616
self.mav.mav.mission_item_int_encode(
1617
target_system,
1618
target_component,
1619
2, # seq
1620
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1621
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1622
0, # current
1623
0, # autocontinue
1624
5, # p1
1625
0, # p2
1626
0, # p3
1627
0, # p4
1628
int(1.0001 * 1e7), # latitude
1629
int(1.0000 * 1e7), # longitude
1630
32.0000, # altitude
1631
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1632
self.mav.mav.mission_item_int_encode(
1633
target_system,
1634
target_component,
1635
3, # seq
1636
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1637
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1638
0, # current
1639
0, # autocontinue
1640
5, # p1
1641
0, # p2
1642
0, # p3
1643
0, # p4
1644
int(1.0001 * 1e7), # latitude
1645
int(1.0001 * 1e7), # longitude
1646
33.0000, # altitude
1647
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1648
self.mav.mav.mission_item_int_encode(
1649
target_system,
1650
target_component,
1651
4, # seq
1652
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1653
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1654
0, # current
1655
0, # autocontinue
1656
5, # p1
1657
0, # p2
1658
0, # p3
1659
0, # p4
1660
int(1.0002 * 1e7), # latitude
1661
int(1.0002 * 1e7), # longitude
1662
33.0000, # altitude
1663
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1664
self.mav.mav.mission_item_int_encode(
1665
target_system,
1666
target_component,
1667
5, # seq
1668
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1669
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1670
0, # current
1671
0, # autocontinue
1672
5, # p1
1673
0, # p2
1674
0, # p3
1675
0, # p4
1676
int(1.0002 * 1e7), # latitude
1677
int(1.0003 * 1e7), # longitude
1678
33.0000, # altitude
1679
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1680
]
1681
1682
def fence_with_many_exclusion_circles(self, count=50, target_system=1, target_component=1):
1683
ret = []
1684
for i in range(0, count):
1685
lat_deg = 1.0003 + count/10
1686
lng_deg = 1.0002 + count/10
1687
item = self.mav.mav.mission_item_int_encode(
1688
target_system,
1689
target_component,
1690
i, # seq
1691
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1692
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
1693
0, # current
1694
0, # autocontinue
1695
count, # p1
1696
0, # p2
1697
0, # p3
1698
0, # p4
1699
int(lat_deg * 1e7), # latitude
1700
int(lng_deg * 1e7), # longitude
1701
33.0000, # altitude
1702
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1703
ret.append(item)
1704
return ret
1705
1706
def fence_with_many_exclusion_polyfences(self, target_system=1, target_component=1):
1707
ret = []
1708
seq = 0
1709
for fencenum in range(0, 4):
1710
pointcount = fencenum + 6
1711
for p in range(0, pointcount):
1712
lat_deg = 1.0003 + p/10 + fencenum/100
1713
lng_deg = 1.0002 + p/10 + fencenum/100
1714
item = self.mav.mav.mission_item_int_encode(
1715
target_system,
1716
target_component,
1717
seq, # seq
1718
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1719
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION,
1720
0, # current
1721
0, # autocontinue
1722
pointcount, # p1
1723
0, # p2
1724
0, # p3
1725
0, # p4
1726
int(lat_deg * 1e7), # latitude
1727
int(lng_deg * 1e7), # longitude
1728
33.0000, # altitude
1729
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1730
ret.append(item)
1731
seq += 1
1732
return ret
1733
1734
def fences_which_should_upload(self, target_system=1, target_component=1):
1735
return [
1736
("Single Return Point",
1737
self.fence_with_single_return_point(
1738
target_system=target_system,
1739
target_component=target_component)),
1740
("Return and 5-vertex-inclusion",
1741
self.fence_with_single_return_point_and_5_vertex_inclusion(
1742
target_system=target_system,
1743
target_component=target_component)),
1744
("Many exclusion circles",
1745
self.fence_with_many_exclusion_circles(
1746
target_system=target_system,
1747
target_component=target_component)),
1748
("Many exclusion polyfences",
1749
self.fence_with_many_exclusion_polyfences(
1750
target_system=target_system,
1751
target_component=target_component)),
1752
("Empty fence", []),
1753
]
1754
1755
def assert_fence_does_not_upload(self, fence, target_system=1, target_component=1):
1756
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
1757
target_system=target_system,
1758
target_component=target_component)
1759
# upload single item using mission item protocol:
1760
upload_failed = False
1761
try:
1762
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
1763
fence)
1764
except NotAchievedException:
1765
# TODO: make sure we failed for correct reason
1766
upload_failed = True
1767
if not upload_failed:
1768
raise NotAchievedException("Uploaded fence when should not be possible")
1769
self.progress("Fence rightfully bounced")
1770
1771
def send_fencepoint_expect_statustext(self,
1772
offset,
1773
count,
1774
lat,
1775
lng,
1776
statustext_fragment,
1777
target_system=1,
1778
target_component=1,
1779
timeout=10):
1780
self.mav.mav.fence_point_send(target_system,
1781
target_component,
1782
offset,
1783
count,
1784
lat,
1785
lng)
1786
1787
tstart = self.get_sim_time_cached()
1788
while True:
1789
if self.get_sim_time_cached() - tstart > timeout:
1790
raise NotAchievedException("Did not get error message back")
1791
m = self.assert_receive_message('STATUSTEXT')
1792
self.progress("statustext: %s (want='%s')" %
1793
(str(m), statustext_fragment))
1794
if m is None:
1795
continue
1796
if statustext_fragment in m.text:
1797
break
1798
1799
def GCSFailsafe(self, side=60, timeout=360):
1800
"""Test GCS Failsafe"""
1801
try:
1802
self.test_gcs_failsafe(side=side, timeout=timeout)
1803
except Exception as ex:
1804
self.setGCSfailsafe(0)
1805
self.set_parameter('FS_ACTION', 0)
1806
self.disarm_vehicle(force=True)
1807
self.reboot_sitl()
1808
raise ex
1809
1810
def test_gcs_failsafe(self, side=60, timeout=360):
1811
self.set_parameter("MAV_GCS_SYSID", self.mav.source_system)
1812
self.set_parameter("FS_ACTION", 1)
1813
self.set_parameter("FS_THR_ENABLE", 0) # disable radio FS as it inhibt GCS one's
1814
1815
def go_somewhere():
1816
self.change_mode("MANUAL")
1817
self.wait_ready_to_arm()
1818
self.arm_vehicle()
1819
self.set_rc(3, 2000)
1820
self.delay_sim_time(5)
1821
self.set_rc(3, 1500)
1822
# Trigger telemetry loss with failsafe disabled. Verify no action taken.
1823
self.start_subtest("GCS failsafe disabled test: FS_GCS_ENABLE=0 should take no failsafe action")
1824
self.setGCSfailsafe(0)
1825
go_somewhere()
1826
self.set_heartbeat_rate(0)
1827
self.delay_sim_time(5)
1828
self.wait_mode("MANUAL")
1829
self.set_heartbeat_rate(self.speedup)
1830
self.delay_sim_time(5)
1831
self.wait_mode("MANUAL")
1832
self.end_subtest("Completed GCS failsafe disabled test")
1833
1834
# Trigger telemetry loss with failsafe enabled. Verify
1835
# failsafe triggers to RTL. Restore telemetry, verify failsafe
1836
# clears, and change modes.
1837
# TODO not implemented
1838
# self.start_subtest("GCS failsafe recovery test: FS_GCS_ENABLE=1")
1839
# self.setGCSfailsafe(1)
1840
# self.set_heartbeat_rate(0)
1841
# self.wait_mode("RTL")
1842
# self.set_heartbeat_rate(self.speedup)
1843
# self.wait_statustext("GCS Failsafe Cleared", timeout=60)
1844
# self.change_mode("MANUAL")
1845
# self.end_subtest("Completed GCS failsafe recovery test")
1846
1847
# Trigger telemetry loss with failsafe enabled. Verify failsafe triggers and RTL completes
1848
self.start_subtest("GCS failsafe RTL with no options test: FS_GCS_ENABLE=1")
1849
self.setGCSfailsafe(1)
1850
self.set_heartbeat_rate(0)
1851
self.wait_mode("RTL")
1852
self.wait_statustext("Reached destination", timeout=60)
1853
self.set_heartbeat_rate(self.speedup)
1854
self.wait_statustext("GCS Failsafe Cleared", timeout=60)
1855
self.end_subtest("Completed GCS failsafe RTL")
1856
1857
# Trigger telemetry loss with an invalid failsafe value. Verify failsafe triggers and RTL completes
1858
self.start_subtest("GCS failsafe invalid value with no options test: FS_GCS_ENABLE=99")
1859
self.setGCSfailsafe(99)
1860
go_somewhere()
1861
self.set_heartbeat_rate(0)
1862
self.wait_mode("RTL")
1863
self.wait_statustext("Reached destination", timeout=60)
1864
self.set_heartbeat_rate(self.speedup)
1865
self.wait_statustext("GCS Failsafe Cleared", timeout=60)
1866
self.end_subtest("Completed GCS failsafe invalid value")
1867
1868
self.start_subtest("Testing continue in auto mission")
1869
self.disarm_vehicle()
1870
self.setGCSfailsafe(2)
1871
self.load_mission("test_arming.txt")
1872
self.change_mode("AUTO")
1873
self.delay_sim_time(5)
1874
self.set_heartbeat_rate(0)
1875
self.wait_statustext("Failsafe - Continuing Auto Mode", timeout=60)
1876
self.delay_sim_time(5)
1877
self.wait_mode("AUTO")
1878
self.set_heartbeat_rate(self.speedup)
1879
self.wait_statustext("GCS Failsafe Cleared", timeout=60)
1880
1881
self.start_subtest("GCS failsafe RTL with no options test: FS_GCS_ENABLE=1 and FS_GCS_TIMEOUT=10")
1882
self.setGCSfailsafe(1)
1883
old_gcs_timeout = self.get_parameter("FS_GCS_TIMEOUT")
1884
new_gcs_timeout = old_gcs_timeout * 2
1885
self.set_parameter("FS_GCS_TIMEOUT", new_gcs_timeout)
1886
go_somewhere()
1887
self.set_heartbeat_rate(0)
1888
self.delay_sim_time(old_gcs_timeout + (new_gcs_timeout - old_gcs_timeout) / 2)
1889
self.assert_mode("MANUAL")
1890
self.wait_mode("RTL")
1891
self.wait_statustext("Reached destination", timeout=60)
1892
self.set_heartbeat_rate(self.speedup)
1893
self.wait_statustext("GCS Failsafe Cleared", timeout=60)
1894
self.disarm_vehicle()
1895
self.end_subtest("Completed GCS failsafe RTL")
1896
1897
self.setGCSfailsafe(0)
1898
self.progress("All GCS failsafe tests complete")
1899
1900
def test_gcs_fence_centroid(self, target_system=1, target_component=1):
1901
self.start_subtest("Ensuring if we don't have a centroid it gets calculated")
1902
items = self.test_gcs_fence_need_centroid(
1903
target_system=target_system,
1904
target_component=target_component)
1905
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
1906
items)
1907
centroid = self.get_fence_point(0)
1908
want_lat = 1.0001
1909
want_lng = 1.00005
1910
if abs(centroid.lat - want_lat) > 0.000001:
1911
raise NotAchievedException("Centroid lat not as expected (want=%f got=%f)" % (want_lat, centroid.lat))
1912
if abs(centroid.lng - want_lng) > 0.000001:
1913
raise NotAchievedException("Centroid lng not as expected (want=%f got=%f)" % (want_lng, centroid.lng))
1914
1915
def test_gcs_fence_update_fencepoint(self, target_system=1, target_component=1):
1916
self.start_subtest("Ensuring we can move a fencepoint")
1917
items = self.test_gcs_fence_boring_triangle(
1918
target_system=target_system,
1919
target_component=target_component)
1920
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
1921
items)
1922
# downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1923
item_seq = 2
1924
item = items[item_seq]
1925
print("item is (%s)" % str(item))
1926
self.progress("original x=%d" % item.x)
1927
item.x += int(0.1 * 1e7)
1928
self.progress("new x=%d" % item.x)
1929
self.progress("try to overwrite item %u" % item_seq)
1930
self.mav.mav.mission_write_partial_list_send(
1931
target_system,
1932
target_component,
1933
item_seq,
1934
item_seq,
1935
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1936
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_FENCE, item_seq)
1937
item.pack(self.mav.mav)
1938
self.mav.mav.send(item)
1939
self.progress("Answered request for fence point %u" % item_seq)
1940
1941
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1942
downloaded_items2 = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
1943
if downloaded_items2[item_seq].x != item.x:
1944
raise NotAchievedException("Item did not update")
1945
self.check_fence_items_same([items[0], items[1], item, items[3]], downloaded_items2)
1946
1947
def test_gcs_fence_boring_triangle(self, target_system=1, target_component=1):
1948
return copy.copy([
1949
self.mav.mav.mission_item_int_encode(
1950
target_system,
1951
target_component,
1952
0, # seq
1953
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1954
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1955
0, # current
1956
0, # autocontinue
1957
3, # p1
1958
0, # p2
1959
0, # p3
1960
0, # p4
1961
int(1.0000 * 1e7), # latitude
1962
int(1.0000 * 1e7), # longitude
1963
31.0000, # altitude
1964
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1965
self.mav.mav.mission_item_int_encode(
1966
target_system,
1967
target_component,
1968
1, # seq
1969
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1970
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1971
0, # current
1972
0, # autocontinue
1973
3, # p1
1974
0, # p2
1975
0, # p3
1976
0, # p4
1977
int(1.0001 * 1e7), # latitude
1978
int(1.0000 * 1e7), # longitude
1979
32.0000, # altitude
1980
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1981
self.mav.mav.mission_item_int_encode(
1982
target_system,
1983
target_component,
1984
2, # seq
1985
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
1986
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
1987
0, # current
1988
0, # autocontinue
1989
3, # p1
1990
0, # p2
1991
0, # p3
1992
0, # p4
1993
int(1.0001 * 1e7), # latitude
1994
int(1.0001 * 1e7), # longitude
1995
33.0000, # altitude
1996
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
1997
self.mav.mav.mission_item_int_encode(
1998
target_system,
1999
target_component,
2000
3, # seq
2001
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2002
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT,
2003
0, # current
2004
0, # autocontinue
2005
0, # p1
2006
0, # p2
2007
0, # p3
2008
0, # p4
2009
int(1.00015 * 1e7), # latitude
2010
int(1.00015 * 1e7), # longitude
2011
33.0000, # altitude
2012
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
2013
])
2014
2015
def test_gcs_fence_need_centroid(self, target_system=1, target_component=1):
2016
return copy.copy([
2017
self.mav.mav.mission_item_int_encode(
2018
target_system,
2019
target_component,
2020
0, # seq
2021
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2022
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
2023
0, # current
2024
0, # autocontinue
2025
4, # p1
2026
0, # p2
2027
0, # p3
2028
0, # p4
2029
int(1.0000 * 1e7), # latitude
2030
int(1.0000 * 1e7), # longitude
2031
31.0000, # altitude
2032
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
2033
self.mav.mav.mission_item_int_encode(
2034
target_system,
2035
target_component,
2036
1, # seq
2037
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2038
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
2039
0, # current
2040
0, # autocontinue
2041
4, # p1
2042
0, # p2
2043
0, # p3
2044
0, # p4
2045
int(1.0002 * 1e7), # latitude
2046
int(1.0000 * 1e7), # longitude
2047
32.0000, # altitude
2048
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
2049
self.mav.mav.mission_item_int_encode(
2050
target_system,
2051
target_component,
2052
2, # seq
2053
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2054
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
2055
0, # current
2056
0, # autocontinue
2057
4, # p1
2058
0, # p2
2059
0, # p3
2060
0, # p4
2061
int(1.0002 * 1e7), # latitude
2062
int(1.0001 * 1e7), # longitude
2063
33.0000, # altitude
2064
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
2065
self.mav.mav.mission_item_int_encode(
2066
target_system,
2067
target_component,
2068
3, # seq
2069
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2070
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
2071
0, # current
2072
0, # autocontinue
2073
4, # p1
2074
0, # p2
2075
0, # p3
2076
0, # p4
2077
int(1.0000 * 1e7), # latitude
2078
int(1.0001 * 1e7), # longitude
2079
33.0000, # altitude
2080
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
2081
])
2082
2083
def click_location_from_item(self, mavproxy, item):
2084
mavproxy.send("click %f %f\n" % (item.x*1e-7, item.y*1e-7))
2085
2086
def test_gcs_fence_via_mavproxy(self, target_system=1, target_component=1):
2087
self.start_subtest("Fence via MAVProxy")
2088
if not self.mavproxy_can_do_mision_item_protocols():
2089
return
2090
mavproxy = self.start_mavproxy()
2091
self.start_subsubtest("fence addcircle")
2092
self.clear_fence_using_mavproxy(mavproxy)
2093
self.delay_sim_time(1)
2094
radius = 20
2095
item = self.mav.mav.mission_item_int_encode(
2096
target_system,
2097
target_component,
2098
0, # seq
2099
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2100
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION,
2101
0, # current
2102
0, # autocontinue
2103
radius, # p1
2104
0, # p2
2105
0, # p3
2106
0, # p4
2107
int(1.0017 * 1e7), # latitude
2108
int(1.0017 * 1e7), # longitude
2109
0.0000, # altitude
2110
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2111
print("item is (%s)" % str(item))
2112
self.click_location_from_item(mavproxy, item)
2113
mavproxy.send("fence addcircle inc %u\n" % radius)
2114
self.delay_sim_time(1)
2115
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2116
print("downloaded items: %s" % str(downloaded_items))
2117
self.check_fence_items_same([item], downloaded_items)
2118
2119
radius_exc = 57.3
2120
item2 = self.mav.mav.mission_item_int_encode(
2121
target_system,
2122
target_component,
2123
0, # seq
2124
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
2125
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
2126
0, # current
2127
0, # autocontinue
2128
radius_exc, # p1
2129
0, # p2
2130
0, # p3
2131
0, # p4
2132
int(1.0017 * 1e7), # latitude
2133
int(1.0017 * 1e7), # longitude
2134
0.0000, # altitude
2135
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2136
self.click_location_from_item(mavproxy, item2)
2137
mavproxy.send("fence addcircle exc %f\n" % radius_exc)
2138
self.delay_sim_time(1)
2139
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2140
print("downloaded items: %s" % str(downloaded_items))
2141
self.check_fence_items_same([item, item2], downloaded_items)
2142
self.end_subsubtest("fence addcircle")
2143
2144
self.start_subsubtest("fence addpoly")
2145
self.clear_fence_using_mavproxy(mavproxy)
2146
self.delay_sim_time(1)
2147
pointcount = 7
2148
mavproxy.send("fence addpoly inc 20 %u 37.2\n" % pointcount) # radius, pointcount, rotation
2149
self.delay_sim_time(5)
2150
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2151
if len(downloaded_items) != pointcount:
2152
raise NotAchievedException("Did not get expected number of points returned (want=%u got=%u)" %
2153
(pointcount, len(downloaded_items)))
2154
self.end_subsubtest("fence addpoly")
2155
2156
self.start_subsubtest("fence movepolypoint")
2157
self.clear_fence_using_mavproxy(mavproxy)
2158
self.delay_sim_time(1)
2159
triangle = self.test_gcs_fence_boring_triangle(
2160
target_system=target_system,
2161
target_component=target_component)
2162
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
2163
triangle)
2164
mavproxy.send("fence list\n")
2165
self.delay_sim_time(1)
2166
triangle[2].x += 500
2167
triangle[2].y += 700
2168
self.click_location_from_item(mavproxy, triangle[2])
2169
mavproxy.send("fence movepolypoint 0 2\n")
2170
self.delay_sim_time(10)
2171
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2172
self.check_fence_items_same(triangle, downloaded_items)
2173
self.end_subsubtest("fence movepolypoint")
2174
2175
self.start_subsubtest("fence enable and disable")
2176
mavproxy.send("fence enable\n")
2177
mavproxy.expect("fence enabled")
2178
mavproxy.send("fence disable\n")
2179
mavproxy.expect("fence disabled")
2180
self.end_subsubtest("fence enable and disable")
2181
2182
self.stop_mavproxy(mavproxy)
2183
2184
# MANUAL> usage: fence <addcircle|addpoly|changealt|clear|disable|draw|enable|list|load|move|movemulti|movepolypoint|param|remove|save|savecsv|savelocal|show|status|undo|update> # noqa
2185
2186
def GCSFence(self):
2187
'''Upload and download of fence'''
2188
target_system = 1
2189
target_component = 1
2190
2191
self.progress("Testing FENCE_POINT protocol")
2192
2193
self.start_subtest("FENCE_TOTAL manipulation")
2194
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2195
self.assert_parameter_value("FENCE_TOTAL", 0)
2196
2197
self.set_parameter("FENCE_TOTAL", 5)
2198
self.assert_parameter_value("FENCE_TOTAL", 5)
2199
2200
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2201
self.assert_parameter_value("FENCE_TOTAL", 0)
2202
2203
self.progress("sending out-of-range fencepoint")
2204
self.send_fencepoint_expect_statustext(0,
2205
0,
2206
1.2345,
2207
5.4321,
2208
"index past total",
2209
target_system=target_component,
2210
target_component=target_component)
2211
2212
self.progress("sending another out-of-range fencepoint")
2213
self.send_fencepoint_expect_statustext(0,
2214
1,
2215
1.2345,
2216
5.4321,
2217
"bad count",
2218
target_system=target_component,
2219
target_component=target_component)
2220
2221
self.set_parameter("FENCE_TOTAL", 1)
2222
self.assert_parameter_value("FENCE_TOTAL", 1)
2223
2224
self.send_fencepoint_expect_statustext(0,
2225
1,
2226
1.2345,
2227
5.4321,
2228
"Invalid FENCE_TOTAL",
2229
target_system=target_component,
2230
target_component=target_component)
2231
2232
self.set_parameter("FENCE_TOTAL", 5)
2233
self.progress("Checking default points")
2234
for i in range(5):
2235
m = self.get_fence_point(i)
2236
if m.count != 5:
2237
raise NotAchievedException("Unexpected count in fence point (want=%u got=%u" %
2238
(5, m.count))
2239
if m.lat != 0 or m.lng != 0:
2240
raise NotAchievedException("Unexpected lat/lon in fencepoint")
2241
2242
self.progress("Storing a return point")
2243
self.roundtrip_fencepoint_protocol(0,
2244
5,
2245
1.2345,
2246
5.4321,
2247
target_system=target_system,
2248
target_component=target_component)
2249
2250
lat = 2.345
2251
lng = 4.321
2252
self.roundtrip_fencepoint_protocol(0,
2253
5,
2254
lat,
2255
lng,
2256
target_system=target_system,
2257
target_component=target_component)
2258
2259
if not self.mavproxy_can_do_mision_item_protocols():
2260
self.progress("MAVProxy too old to do fence point protocols")
2261
return
2262
2263
self.progress("Download with new protocol")
2264
items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2265
if len(items) != 1:
2266
raise NotAchievedException("Unexpected fencepoint count (want=%u got=%u)" % (1, len(items)))
2267
if items[0].command != mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT:
2268
raise NotAchievedException(
2269
"Fence return point not of correct type expected (%u) got %u" %
2270
(items[0].command,
2271
mavutil.mavlink.MAV_CMD_NAV_FENCE_RETURN_POINT))
2272
if items[0].frame != mavutil.mavlink.MAV_FRAME_GLOBAL:
2273
raise NotAchievedException(
2274
"Unexpected frame want=%s got=%s," %
2275
(self.string_for_frame(mavutil.mavlink.MAV_FRAME_GLOBAL),
2276
self.string_for_frame(items[0].frame)))
2277
got_lat = items[0].x
2278
want_lat = lat * 1e7
2279
if abs(got_lat - want_lat) > 1:
2280
raise NotAchievedException("Disagree in lat (got=%f want=%f)" % (got_lat, want_lat))
2281
if abs(items[0].y - lng * 1e7) > 1:
2282
raise NotAchievedException("Disagree in lng")
2283
if items[0].seq != 0:
2284
raise NotAchievedException("Disagree in offset")
2285
self.progress("Downloaded with new protocol OK")
2286
2287
# upload using mission protocol:
2288
items = self.test_gcs_fence_boring_triangle(
2289
target_system=target_system,
2290
target_component=target_component)
2291
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
2292
items)
2293
2294
self.progress("Download with new protocol")
2295
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2296
if len(downloaded_items) != len(items):
2297
raise NotAchievedException("Did not download expected number of items (wanted=%u got=%u)" %
2298
(len(items), len(downloaded_items)))
2299
self.assert_parameter_value("FENCE_TOTAL", len(items) + 1) # +1 for closing
2300
self.progress("Ensuring fence items match what we sent up")
2301
self.check_fence_items_same(items, downloaded_items)
2302
2303
# now check centroid
2304
self.progress("Requesting fence return point")
2305
self.mav.mav.fence_fetch_point_send(target_system,
2306
target_component,
2307
0)
2308
m = self.assert_receive_message("FENCE_POINT")
2309
print("m: %s" % str(m))
2310
2311
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
2312
target_system=target_system,
2313
target_component=target_component)
2314
self.progress("Checking count post-nuke")
2315
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
2316
target_system=target_system,
2317
target_component=target_component)
2318
self.assert_mission_count_on_link(self.mav,
2319
0,
2320
target_system,
2321
target_component,
2322
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2323
2324
self.start_subtest("Ensuring bad fences get bounced")
2325
for fence in self.fences_which_should_not_upload(target_system=target_system, target_component=target_component):
2326
(name, items) = fence
2327
self.progress("Ensuring (%s) gets bounced" % (name,))
2328
self.assert_fence_does_not_upload(items)
2329
2330
self.start_subtest("Ensuring good fences don't get bounced")
2331
for fence in self.fences_which_should_upload(target_system=target_system, target_component=target_component):
2332
(name, items) = fence
2333
self.progress("Ensuring (%s) gets uploaded" % (name,))
2334
self.check_fence_upload_download(items)
2335
self.progress("(%s) uploaded just fine" % (name,))
2336
2337
self.test_gcs_fence_update_fencepoint(target_system=target_system,
2338
target_component=target_component)
2339
2340
self.test_gcs_fence_centroid(target_system=target_system,
2341
target_component=target_component)
2342
2343
self.test_gcs_fence_via_mavproxy(target_system=target_system,
2344
target_component=target_component)
2345
2346
def GCSFenceInvalidPoint(self):
2347
'''Test fetch non-existent fencepoint'''
2348
target_system = 1
2349
target_component = 1
2350
2351
here = self.mav.location()
2352
self.upload_fences_from_locations([
2353
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
2354
# east
2355
self.offset_location_ne(here, -50, 20), # bl
2356
self.offset_location_ne(here, 50, 20), # br
2357
self.offset_location_ne(here, 50, 40), # tr
2358
]),
2359
])
2360
for i in 0, 1, 2:
2361
self.assert_fetch_mission_item_int(target_system, target_component, i, mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
2362
self.progress("Requesting invalid point")
2363
self.mav.mav.mission_request_int_send(
2364
target_system,
2365
target_component,
2366
3,
2367
mavutil.mavlink.MAV_MISSION_TYPE_FENCE
2368
)
2369
self.context_push()
2370
self.context_collect('MISSION_COUNT')
2371
m = self.assert_receive_mission_ack(
2372
mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
2373
want_type=mavutil.mavlink.MAV_MISSION_INVALID_SEQUENCE,
2374
)
2375
self.delay_sim_time(0.1)
2376
found = False
2377
for m in self.context_collection('MISSION_COUNT'):
2378
if m.mission_type != mavutil.mavlink.MAV_MISSION_TYPE_FENCE:
2379
continue
2380
if m.count != 3:
2381
raise NotAchievedException("Unexpected count in MISSION_COUNT")
2382
found = True
2383
self.context_pop()
2384
if not found:
2385
raise NotAchievedException("Did not see correction for fencepoint count")
2386
2387
# explode the write_type_to_storage method
2388
# FIXME: test converting invalid fences / minimally valid fences / normal fences
2389
# FIXME: show that uploading smaller items take up less space
2390
# FIXME: add test for consecutive breaches within the manual recovery period
2391
# FIXME: ensure truncation does the right thing by fence_total
2392
2393
# FIXME: test vehicle escape from outside inclusion zones to
2394
# inside inclusion zones (and inside exclusion zones to outside
2395
# exclusion zones)
2396
# FIXME: add test that a fence with edges that cross can't be uploaded
2397
# FIXME: add a test that fences enclose an area (e.g. all the points aren't the same value!
2398
def Offboard(self, timeout=90):
2399
'''Test Offboard Control'''
2400
self.load_mission("rover-guided-mission.txt")
2401
self.wait_ready_to_arm(require_absolute=True)
2402
self.arm_vehicle()
2403
self.change_mode("AUTO")
2404
2405
offboard_expected_duration = 10 # see mission file
2406
2407
if self.mav.messages.get("SET_POSITION_TARGET_GLOBAL_INT", None):
2408
raise PreconditionFailedException("Already have SET_POSITION_TARGET_GLOBAL_INT")
2409
2410
tstart = self.get_sim_time_cached()
2411
last_heartbeat_sent = 0
2412
got_ptgi = False
2413
magic_waypoint_tstart = 0
2414
magic_waypoint_tstop = 0
2415
while True:
2416
now = self.get_sim_time_cached()
2417
if now - last_heartbeat_sent > 1:
2418
last_heartbeat_sent = now
2419
self.mav.mav.heartbeat_send(mavutil.mavlink.MAV_TYPE_ONBOARD_CONTROLLER,
2420
mavutil.mavlink.MAV_AUTOPILOT_INVALID,
2421
0,
2422
0,
2423
0)
2424
2425
if now - tstart > timeout:
2426
raise AutoTestTimeoutException("Didn't complete")
2427
magic_waypoint = 3
2428
mc = self.mav.recv_match(type=["MISSION_CURRENT", "STATUSTEXT"],
2429
blocking=False)
2430
if mc is not None:
2431
print("%s" % str(mc))
2432
if mc.get_type() == "STATUSTEXT":
2433
if "Mission Complete" in mc.text:
2434
break
2435
continue
2436
if mc.seq == magic_waypoint:
2437
print("At magic waypoint")
2438
if magic_waypoint_tstart == 0:
2439
magic_waypoint_tstart = self.get_sim_time_cached()
2440
ptgi = self.mav.messages.get("POSITION_TARGET_GLOBAL_INT", None)
2441
if ptgi is not None:
2442
got_ptgi = True
2443
elif mc.seq > magic_waypoint:
2444
if magic_waypoint_tstop == 0:
2445
magic_waypoint_tstop = self.get_sim_time_cached()
2446
2447
self.disarm_vehicle()
2448
offboard_duration = magic_waypoint_tstop - magic_waypoint_tstart
2449
if abs(offboard_duration - offboard_expected_duration) > 1:
2450
raise NotAchievedException("Did not stay in offboard control for correct time (want=%f got=%f)" %
2451
(offboard_expected_duration, offboard_duration))
2452
2453
if not got_ptgi:
2454
raise NotAchievedException("Did not get ptgi message")
2455
print("pgti: %s" % str(ptgi))
2456
2457
def assert_mission_count_on_link(self, mav, expected_count, target_system, target_component, mission_type):
2458
self.drain_mav_unparsed(mav=mav, freshen_sim_time=True)
2459
self.progress("waiting for a message - any message....")
2460
m = mav.recv_match(blocking=True, timeout=1)
2461
self.progress("Received (%s)" % str(m))
2462
2463
if not mav.mavlink20():
2464
raise NotAchievedException("Not doing mavlink2")
2465
mav.mav.mission_request_list_send(target_system,
2466
target_component,
2467
mission_type)
2468
self.assert_receive_mission_count_on_link(mav,
2469
expected_count,
2470
target_system,
2471
target_component,
2472
mission_type)
2473
2474
def assert_receive_mission_count_on_link(self,
2475
mav,
2476
expected_count,
2477
target_system,
2478
target_component,
2479
mission_type,
2480
expected_target_system=None,
2481
expected_target_component=None,
2482
timeout=120):
2483
if expected_target_system is None:
2484
expected_target_system = mav.mav.srcSystem
2485
if expected_target_component is None:
2486
expected_target_component = mav.mav.srcComponent
2487
self.progress("Waiting for mission count of (%u) from (%u:%u) to (%u:%u)" %
2488
(expected_count, target_system, target_component, expected_target_system, expected_target_component))
2489
2490
tstart = self.get_sim_time_cached()
2491
while True:
2492
delta = self.get_sim_time_cached() - tstart
2493
if delta > timeout:
2494
raise NotAchievedException("Did not receive MISSION_COUNT on link after %fs" % delta)
2495
m = mav.recv_match(blocking=True, timeout=1)
2496
if m is None:
2497
self.progress("No messages")
2498
continue
2499
# self.progress("Received (%s)" % str(m))
2500
if m.get_type() == "MISSION_ACK":
2501
if m.type != mavutil.mavlink.MAV_MISSION_ACCEPTED:
2502
raise NotAchievedException("Expected MAV_MISSION_ACCEPTED, got (%s)" % m)
2503
if m.get_type() == "MISSION_COUNT":
2504
break
2505
if m.target_system != expected_target_system:
2506
raise NotAchievedException("Incorrect target system in MISSION_COUNT (want=%u got=%u)" %
2507
(expected_target_system, m.target_system))
2508
if m.target_component != expected_target_component:
2509
raise NotAchievedException("Incorrect target component in MISSION_COUNT")
2510
if m.mission_type != mission_type:
2511
raise NotAchievedException("Did not get expected mission type (want=%u got=%u)" % (mission_type, m.mission_type))
2512
if m.count != expected_count:
2513
raise NotAchievedException("Bad count received (want=%u got=%u)" %
2514
(expected_count, m.count))
2515
self.progress("Asserted mission count (type=%u) is %u after %fs" % (
2516
(mission_type, m.count, delta)))
2517
2518
def get_mission_item_int_on_link(self, item, mav, target_system, target_component, mission_type, delay_fn=None):
2519
self.drain_mav(mav=mav, unparsed=True)
2520
mav.mav.mission_request_int_send(target_system,
2521
target_component,
2522
item,
2523
mission_type)
2524
m = self.assert_receive_message(
2525
'MISSION_ITEM_INT',
2526
timeout=60,
2527
condition='MISSION_ITEM_INT.mission_type==%u' % mission_type,
2528
delay_fn=delay_fn)
2529
if m is None:
2530
raise NotAchievedException("Did not receive MISSION_ITEM_INT")
2531
if m.mission_type != mission_type:
2532
raise NotAchievedException("Mission item of incorrect type")
2533
if m.target_system != mav.mav.srcSystem:
2534
raise NotAchievedException("Unexpected target system %u want=%u" %
2535
(m.target_system, mav.mav.srcSystem))
2536
if m.seq != item:
2537
raise NotAchievedException(
2538
"Incorrect sequence number on received item got=%u want=%u" %
2539
(m.seq, item))
2540
if m.mission_type != mission_type:
2541
raise NotAchievedException(
2542
"Mission type incorrect on received item (want=%u got=%u)" %
2543
(mission_type, m.mission_type))
2544
if m.target_component != mav.mav.srcComponent:
2545
raise NotAchievedException(
2546
"Unexpected target component %u want=%u" %
2547
(m.target_component, mav.mav.srcComponent))
2548
return m
2549
2550
def get_mission_item_on_link(self, item, mav, target_system, target_component, mission_type):
2551
self.drain_mav(mav=mav, unparsed=True)
2552
mav.mav.mission_request_send(target_system,
2553
target_component,
2554
item,
2555
mission_type)
2556
m = self.assert_receive_message('MISSION_ITEM', timeout=60)
2557
if m.target_system != mav.mav.srcSystem:
2558
raise NotAchievedException("Unexpected target system %u want=%u" %
2559
(m.target_system, mav.mav.srcSystem))
2560
if m.seq != item:
2561
raise NotAchievedException("Incorrect sequence number on received item_int got=%u want=%u" %
2562
(m.seq, item))
2563
if m.mission_type != mission_type:
2564
raise NotAchievedException("Mission type incorrect on received item_int (want=%u got=%u)" %
2565
(mission_type, m.mission_type))
2566
if m.target_component != mav.mav.srcComponent:
2567
raise NotAchievedException("Unexpected target component %u want=%u" %
2568
(m.target_component, mav.mav.srcComponent))
2569
return m
2570
2571
def assert_receive_mission_item_request(self, mission_type, seq):
2572
self.progress("Expecting request for item %u" % seq)
2573
m = self.assert_receive_message('MISSION_REQUEST')
2574
if m.mission_type != mission_type:
2575
raise NotAchievedException("Incorrect mission type (wanted=%u got=%u)" %
2576
(mission_type, m.mission_type))
2577
if m.seq != seq:
2578
raise NotAchievedException("Unexpected sequence number (want=%u got=%u)" % (seq, m.seq))
2579
self.progress("Received item request OK")
2580
2581
def assert_receive_mission_ack(self, mission_type,
2582
want_type=mavutil.mavlink.MAV_MISSION_ACCEPTED,
2583
target_system=None,
2584
target_component=None,
2585
mav=None):
2586
if mav is None:
2587
mav = self.mav
2588
if target_system is None:
2589
target_system = mav.mav.srcSystem
2590
if target_component is None:
2591
target_component = mav.mav.srcComponent
2592
self.progress("Expecting mission ack")
2593
m = self.assert_receive_message(
2594
'MISSION_ACK',
2595
timeout=5,
2596
verbose=True,
2597
)
2598
if m.target_system != target_system:
2599
raise NotAchievedException("ACK not targeted at correct system want=%u got=%u" %
2600
(target_system, m.target_system))
2601
if m.target_component != target_component:
2602
raise NotAchievedException("ACK not targeted at correct component")
2603
if m.mission_type != mission_type:
2604
raise NotAchievedException("Unexpected mission type %u want=%u" %
2605
(m.mission_type, mission_type))
2606
if m.type != want_type:
2607
raise NotAchievedException("Expected ack type %u got %u" %
2608
(want_type, m.type))
2609
return m
2610
2611
def assert_filepath_content(self, filepath, want):
2612
got = pathlib.Path(filepath).read_text()
2613
if want != got:
2614
raise NotAchievedException("Did not get expected file content (want=%s) (got=%s)" % (want, got))
2615
2616
def mavproxy_can_do_mision_item_protocols(self):
2617
return False
2618
if not self.mavproxy_version_gt(1, 8, 69):
2619
self.progress("MAVProxy is too old; skipping tests")
2620
return False
2621
return True
2622
2623
def check_rally_items_same(self, want, got, epsilon=None):
2624
check_atts = ['mission_type', 'command', 'x', 'y', 'z', 'seq', 'param1']
2625
return self.check_mission_items_same(check_atts, want, got, epsilon=epsilon)
2626
2627
def click_three_in(self, mavproxy, target_system=1, target_component=1):
2628
mavproxy.send('rally clear\n')
2629
self.drain_mav()
2630
# there are race conditions in MAVProxy. Beware.
2631
mavproxy.send("click 1.0 1.0\n")
2632
mavproxy.send("rally add\n")
2633
self.delay_sim_time(1)
2634
mavproxy.send("click 2.0 2.0\n")
2635
mavproxy.send("rally add\n")
2636
self.delay_sim_time(1)
2637
mavproxy.send("click 3.0 3.0\n")
2638
mavproxy.send("rally add\n")
2639
self.delay_sim_time(10)
2640
self.assert_mission_count_on_link(
2641
self.mav,
2642
3,
2643
target_system,
2644
target_component,
2645
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2646
)
2647
2648
def GCSRally(self, target_system=1, target_component=1):
2649
'''Upload and download of rally using MAVProxy'''
2650
self.start_subtest("Testing mavproxy CLI for rally points")
2651
mavproxy = self.start_mavproxy()
2652
2653
rallyalt = 87 # note that this exists as a string in expected results below
2654
mavproxy.send(f'set rallyalt {rallyalt}\n')
2655
mavproxy.send('rally clear\n')
2656
2657
self.start_subsubtest("rally add")
2658
mavproxy.send('rally clear\n')
2659
lat_s = "-5.6789"
2660
lng_s = "98.2341"
2661
lat = float(lat_s)
2662
lng = float(lng_s)
2663
mavproxy.send(f'click {lat_s} {lng_s}\n')
2664
self.drain_mav()
2665
mavproxy.send('rally add\n')
2666
self.delay_sim_time(2)
2667
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2668
if len(downloaded_items) != 1:
2669
raise NotAchievedException("Unexpected count (got=%u want=1)" %
2670
(len(downloaded_items), ))
2671
if abs(downloaded_items[0].x - int(lat * 1e7)) > 1:
2672
raise NotAchievedException("Bad rally lat. Want=%d got=%d" %
2673
(int(lat * 1e7), downloaded_items[0].x))
2674
if abs(downloaded_items[0].y - int(lng * 1e7)) > 1:
2675
raise NotAchievedException("Bad rally lng. Want=%d got=%d" %
2676
(int(lng * 1e7), downloaded_items[0].y))
2677
if abs(downloaded_items[0].z - rallyalt) > 1:
2678
raise NotAchievedException(f"Bad rally alt. Want={rallyalt} got={downloaded_items[0].z}")
2679
self.end_subsubtest("rally add")
2680
2681
self.start_subsubtest("rally list")
2682
util.pexpect_drain(mavproxy)
2683
mavproxy.send('rally list\n')
2684
mavproxy.expect(r"Saved 1 rally items to ([^\s]*)\s")
2685
filename = mavproxy.match.group(1)
2686
self.assert_rally_filepath_content(filename, '''QGC WPL 110
2687
0 0 3 5100 0.000000 0.000000 0.000000 0.000000 -5.678900 98.234100 87.000000 0
2688
''')
2689
self.end_subsubtest("rally list")
2690
2691
self.start_subsubtest("rally save")
2692
util.pexpect_drain(mavproxy)
2693
save_tmppath = self.buildlogs_path("rally-testing-tmp.txt")
2694
mavproxy.send('rally save %s\n' % save_tmppath)
2695
mavproxy.expect(r"Saved 1 rally items to ([^\s]*)\s")
2696
filename = mavproxy.match.group(1)
2697
if filename != save_tmppath:
2698
raise NotAchievedException("Bad save filepath; want=%s got=%s" % (save_tmppath, filename))
2699
self.assert_rally_filepath_content(filename, '''QGC WPL 110
2700
0 0 3 5100 0.000000 0.000000 0.000000 0.000000 -5.678900 98.234100 87.000000 0
2701
''')
2702
self.end_subsubtest("rally save")
2703
2704
self.start_subsubtest("rally savecsv")
2705
util.pexpect_drain(mavproxy)
2706
csvpath = self.buildlogs_path("rally-testing-tmp.csv")
2707
mavproxy.send('rally savecsv %s\n' % csvpath)
2708
(major, minor, micro, releaselevel, serial) = sys.version_info
2709
if major == 3 and minor == 12:
2710
# greater precision output by default
2711
expected_content = '''"0","Rel","NAV_RALLY_POINT","0.0","0.0","0.0","0.0","-5.678899899999999","98.2341","87.0"
2712
''' # noqa
2713
# wait for the file to appear:
2714
for i in range(1, 10):
2715
if os.path.exists(csvpath):
2716
break
2717
time.sleep(0.1)
2718
# file content does not seem stable, even within a Python major version
2719
self.assert_filepath_content(csvpath, expected_content)
2720
2721
self.end_subsubtest("rally savecsv")
2722
2723
self.start_subsubtest("rally load")
2724
self.drain_mav()
2725
mavproxy.send('rally clear\n')
2726
self.wait_heartbeat()
2727
self.wait_heartbeat()
2728
self.assert_mission_count_on_link(self.mav,
2729
0,
2730
target_system,
2731
target_component,
2732
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2733
2734
# warning: uses file saved from previous test
2735
self.start_subtest("Check rally load from filepath")
2736
mavproxy.send('rally load %s\n' % save_tmppath)
2737
mavproxy.expect(r"Loaded 1 rally items from ([^\s]*)\s")
2738
mavproxy.expect("Sent all .* rally items") # notional race condition here
2739
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2740
if len(downloaded_items) != 1:
2741
raise NotAchievedException("Unexpected item count (%u)" % len(downloaded_items))
2742
if abs(int(downloaded_items[0].x) - int(lat * 1e7)) > 3:
2743
raise NotAchievedException("Expected lat=%d got=%d" %
2744
(lat * 1e7, downloaded_items[0].x))
2745
if abs(int(downloaded_items[0].y) - int(lng * 1e7)) > 10:
2746
raise NotAchievedException("Expected lng=%d got=%d" %
2747
(lng * 1e7, downloaded_items[0].y))
2748
self.end_subsubtest("rally load")
2749
2750
self.start_subsubtest("rally changealt")
2751
mavproxy.send('rally clear\n')
2752
mavproxy.send("click 1.0 1.0\n")
2753
mavproxy.send("rally add\n")
2754
mavproxy.send("click 2.0 2.0\n")
2755
mavproxy.send("rally add\n")
2756
self.delay_sim_time(2)
2757
self.assert_mission_count_on_link(
2758
self.mav,
2759
2,
2760
target_system,
2761
target_component,
2762
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2763
)
2764
self.drain_mav()
2765
mavproxy.send("rally changealt 1 17.6\n")
2766
self.wait_heartbeat()
2767
self.wait_heartbeat()
2768
mavproxy.send("rally changealt 2 19.1\n")
2769
self.delay_sim_time(2)
2770
2771
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2772
if len(downloaded_items) != 2:
2773
raise NotAchievedException("Unexpected item count (%u)" % len(downloaded_items))
2774
if abs(int(downloaded_items[0].x) - int(1 * 1e7)) > 3:
2775
raise NotAchievedException("Expected lat=%d got=%d" % (1 * 1e7, downloaded_items[0].x))
2776
if abs(int(downloaded_items[0].y) - int(1 * 1e7)) > 10:
2777
raise NotAchievedException("Expected lng=%d got=%d" % (1 * 1e7, downloaded_items[0].y))
2778
# at some stage ArduPilot will stop rounding altitude. This
2779
# will break then.
2780
if abs(downloaded_items[0].z - int(17.6)) > 0.0001:
2781
raise NotAchievedException("Expected alt=%f got=%f" % (17.6, downloaded_items[0].z))
2782
2783
if abs(int(downloaded_items[1].x) - int(2 * 1e7)) > 3:
2784
raise NotAchievedException("Expected lat=%d got=%d" % (2 * 1e7, downloaded_items[0].x))
2785
if abs(int(downloaded_items[1].y) - int(2 * 1e7)) > 10:
2786
raise NotAchievedException("Expected lng=%d got=%d" % (2 * 1e7, downloaded_items[0].y))
2787
# at some stage ArduPilot will stop rounding altitude. This
2788
# will break then.
2789
if abs(downloaded_items[1].z - int(19.1)) > 0.0001:
2790
raise NotAchievedException("Expected alt=%f got=%f" % (19.1, downloaded_items[1].z))
2791
2792
self.progress("Now change two at once")
2793
mavproxy.send("rally changealt 1 17.3 2\n")
2794
self.delay_sim_time(2)
2795
mavproxy.send('rally list\n')
2796
self.drain_mav()
2797
self.wait_heartbeat()
2798
2799
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2800
if len(downloaded_items) != 2:
2801
raise NotAchievedException("Unexpected item count (%u)" % len(downloaded_items))
2802
2803
if abs(int(downloaded_items[0].x) - int(1 * 1e7)) > 3:
2804
raise NotAchievedException("Expected lat=%d got=%d" % (1 * 1e7, downloaded_items[0].x))
2805
if abs(int(downloaded_items[0].y) - int(1 * 1e7)) > 10:
2806
raise NotAchievedException("Expected lng=%d got=%d" % (1 * 1e7, downloaded_items[0].y))
2807
# at some stage ArduPilot will stop rounding altitude. This
2808
# will break then.
2809
if abs(int(downloaded_items[0].z) - int(17.3)) > 0.0001:
2810
raise NotAchievedException("Expected alt=%f got=%f" % (17.3, downloaded_items[0].z))
2811
2812
if abs(int(downloaded_items[1].x) - int(2 * 1e7)) > 3:
2813
raise NotAchievedException("Expected lat=%d got=%d" % (2 * 1e7, downloaded_items[0].x))
2814
if abs(int(downloaded_items[1].y) - int(2 * 1e7)) > 10:
2815
raise NotAchievedException("Expected lng=%d got=%d" % (2 * 1e7, downloaded_items[0].y))
2816
# at some stage ArduPilot will stop rounding altitude. This
2817
# will break then.
2818
if abs(int(downloaded_items[1].z) - int(17.3)) > 0.0001:
2819
raise NotAchievedException("Expected alt=%f got=%f" % (17.3, downloaded_items[0].z))
2820
2821
self.end_subsubtest("rally changealt")
2822
2823
self.start_subsubtest("rally move")
2824
mavproxy.send('rally clear\n')
2825
mavproxy.send("click 1.0 1.0\n")
2826
mavproxy.send("rally add\n")
2827
mavproxy.send("click 2.0 2.0\n")
2828
mavproxy.send("rally add\n")
2829
self.delay_sim_time(2)
2830
self.assert_mission_count_on_link(
2831
self.mav,
2832
2,
2833
target_system,
2834
target_component,
2835
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2836
)
2837
mavproxy.send("click 3.0 3.0\n")
2838
mavproxy.send("rally move 2\n")
2839
self.delay_sim_time(2)
2840
mavproxy.send("click 4.12345 4.987654\n")
2841
mavproxy.send("rally move 1\n")
2842
self.delay_sim_time(2)
2843
2844
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2845
if len(downloaded_items) != 2:
2846
raise NotAchievedException("Unexpected item count (%u)" % len(downloaded_items))
2847
if downloaded_items[0].x != 41234500:
2848
raise NotAchievedException("Bad latitude")
2849
if downloaded_items[0].y != 49876540:
2850
raise NotAchievedException("Bad longitude")
2851
if downloaded_items[0].z != rallyalt:
2852
raise NotAchievedException("Bad altitude (want=%u got=%u)" %
2853
(90, downloaded_items[0].z))
2854
2855
if downloaded_items[1].x != 30000000:
2856
raise NotAchievedException("Bad latitude")
2857
if downloaded_items[1].y != 30000000:
2858
raise NotAchievedException("Bad longitude")
2859
if downloaded_items[1].z != rallyalt:
2860
raise NotAchievedException("Bad altitude (want=%u got=%u)" %
2861
(rallyalt, downloaded_items[1].z))
2862
self.end_subsubtest("rally move")
2863
2864
# no "rally movemulti"> test for rally here
2865
# no "rally param" test for rally here
2866
2867
self.start_subsubtest("rally remove")
2868
self.click_three_in(mavproxy, target_system=target_system, target_component=target_component)
2869
pure_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2870
self.progress("Removing last in list")
2871
mavproxy.send("rally remove 3\n")
2872
self.delay_sim_time(2)
2873
self.assert_mission_count_on_link(
2874
self.mav,
2875
2,
2876
target_system,
2877
target_component,
2878
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2879
)
2880
fewer_downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2881
if len(fewer_downloaded_items) != 2:
2882
raise NotAchievedException("Unexpected download list length")
2883
shorter_items = copy.copy(pure_items)
2884
shorter_items = shorter_items[0:2]
2885
self.check_rally_items_same(shorter_items, fewer_downloaded_items)
2886
2887
self.progress("Removing first in list")
2888
mavproxy.send("rally remove 1\n")
2889
self.delay_sim_time(2)
2890
self.assert_mission_count_on_link(
2891
self.mav,
2892
1,
2893
target_system,
2894
target_component,
2895
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2896
)
2897
fewer_downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2898
if len(fewer_downloaded_items) != 1:
2899
raise NotAchievedException("Unexpected download list length")
2900
shorter_items = shorter_items[1:]
2901
self.check_rally_items_same(shorter_items, fewer_downloaded_items)
2902
2903
self.progress("Removing remaining item")
2904
mavproxy.send("rally remove 1\n")
2905
self.delay_sim_time(2)
2906
self.assert_mission_count_on_link(
2907
self.mav,
2908
0,
2909
target_system,
2910
target_component,
2911
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2912
)
2913
self.end_subsubtest("rally remove")
2914
2915
self.start_subsubtest("rally show")
2916
# what can we test here?
2917
mavproxy.send("rally show %s\n" % save_tmppath)
2918
self.end_subsubtest("rally show")
2919
2920
# savelocal must be run immediately after show!
2921
self.start_subsubtest("rally savelocal")
2922
util.pexpect_drain(mavproxy)
2923
savelocal_path = self.buildlogs_path("rally-testing-tmp-local.txt")
2924
mavproxy.send('rally savelocal %s\n' % savelocal_path)
2925
self.delay_sim_time(2)
2926
self.assert_rally_filepath_content(savelocal_path, '''QGC WPL 110
2927
0 0 3 5100 0.000000 0.000000 0.000000 0.000000 -5.678900 98.234100 87.000000 0
2928
''')
2929
self.end_subsubtest("rally savelocal")
2930
2931
self.start_subsubtest("rally status")
2932
self.click_three_in(mavproxy, target_system=target_system, target_component=target_component)
2933
mavproxy.send("rally status\n")
2934
mavproxy.expect("Have 3 of 3 rally items")
2935
mavproxy.send("rally clear\n")
2936
mavproxy.send("rally status\n")
2937
mavproxy.expect("Have 0 of 0 rally items")
2938
self.end_subsubtest("rally status")
2939
2940
self.start_subsubtest("rally undo")
2941
self.progress("Testing undo-remove")
2942
self.click_three_in(mavproxy, target_system=target_system, target_component=target_component)
2943
pure_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2944
self.progress("Removing first in list")
2945
mavproxy.send("rally remove 1\n")
2946
self.delay_sim_time(2)
2947
self.assert_mission_count_on_link(
2948
self.mav,
2949
2,
2950
target_system,
2951
target_component,
2952
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
2953
)
2954
mavproxy.send("rally undo\n")
2955
self.delay_sim_time(2)
2956
undone_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2957
self.check_rally_items_same(pure_items, undone_items)
2958
2959
self.progress("Testing undo-move")
2960
2961
pure_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2962
mavproxy.send("click 4.12345 4.987654\n")
2963
mavproxy.send("rally move 1\n")
2964
# move has already been tested, assume it works...
2965
self.delay_sim_time(2)
2966
mavproxy.send("rally undo\n")
2967
self.delay_sim_time(2)
2968
undone_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
2969
self.check_rally_items_same(pure_items, undone_items)
2970
2971
self.end_subsubtest("rally undo")
2972
2973
# no tests for "rally update" here
2974
2975
self.stop_mavproxy(mavproxy)
2976
2977
# MANUAL> usage: rally <add|alt|changealt|clear|list|load|move|movemulti|param|remove|save|savecsv|savelocal|show|status|undo|update> # noqa
2978
2979
def RallyUploadDownload(self, target_system=1, target_component=1):
2980
'''Upload and download of rally'''
2981
old_srcSystem = self.mav.mav.srcSystem
2982
2983
self.drain_mav()
2984
try:
2985
item1_lat = int(2.0000 * 1e7)
2986
items = [
2987
self.mav.mav.mission_item_int_encode(
2988
target_system,
2989
target_component,
2990
0, # seq
2991
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
2992
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
2993
0, # current
2994
0, # autocontinue
2995
0, # p1
2996
0, # p2
2997
0, # p3
2998
0, # p4
2999
int(1.0000 * 1e7), # latitude
3000
int(1.0000 * 1e7), # longitude
3001
31.0000, # altitude
3002
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3003
self.mav.mav.mission_item_int_encode(
3004
target_system,
3005
target_component,
3006
1, # seq
3007
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3008
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
3009
0, # current
3010
0, # autocontinue
3011
0, # p1
3012
0, # p2
3013
0, # p3
3014
0, # p4
3015
item1_lat, # latitude
3016
int(2.0000 * 1e7), # longitude
3017
32.0000, # altitude
3018
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3019
self.mav.mav.mission_item_int_encode(
3020
target_system,
3021
target_component,
3022
2, # seq
3023
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3024
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
3025
0, # current
3026
0, # autocontinue
3027
0, # p1
3028
0, # p2
3029
0, # p3
3030
0, # p4
3031
int(3.0000 * 1e7), # latitude
3032
int(3.0000 * 1e7), # longitude
3033
33.0000, # altitude
3034
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3035
]
3036
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3037
items)
3038
downloaded = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3039
print("Got items (%s)" % str(items))
3040
if len(downloaded) != len(items):
3041
raise NotAchievedException(
3042
"Did not download correct number of items want=%u got=%u" %
3043
(len(downloaded), len(items)))
3044
3045
rally_total = self.get_parameter("RALLY_TOTAL")
3046
if rally_total != len(downloaded):
3047
raise NotAchievedException(
3048
"Unexpected rally point count: want=%u got=%u" %
3049
(len(items), rally_total))
3050
3051
self.progress("Pruning count by setting parameter (urgh)")
3052
self.set_parameter("RALLY_TOTAL", 2)
3053
downloaded = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3054
if len(downloaded) != 2:
3055
raise NotAchievedException(
3056
"Failed to prune rally points by setting parameter. want=%u got=%u" %
3057
(2, len(downloaded)))
3058
3059
self.progress("Uploading a third item using old protocol")
3060
new_item2_lat = int(6.0 * 1e7)
3061
self.set_parameter("RALLY_TOTAL", 3)
3062
self.mav.mav.rally_point_send(target_system,
3063
target_component,
3064
2, # sequence number
3065
3, # total count
3066
new_item2_lat,
3067
int(7.0 * 1e7),
3068
15,
3069
0, # "break" alt?!
3070
0, # "land dir"
3071
0) # flags
3072
downloaded = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3073
if len(downloaded) != 3:
3074
raise NotAchievedException(
3075
"resetting rally point count didn't change items returned")
3076
if downloaded[2].x != new_item2_lat:
3077
raise NotAchievedException(
3078
"Bad latitude in downloaded item: want=%u got=%u" %
3079
(new_item2_lat, downloaded[2].x))
3080
3081
self.progress("Grabbing original item 1 using original protocol")
3082
self.mav.mav.rally_fetch_point_send(target_system,
3083
target_component,
3084
1)
3085
m = self.assert_receive_message("RALLY_POINT")
3086
if m.target_system != self.mav.source_system:
3087
raise NotAchievedException(
3088
"Bad target_system on received rally point (want=%u got=%u)" %
3089
(255, m.target_system))
3090
if m.target_component != self.mav.source_component: # autotest's component ID
3091
raise NotAchievedException("Bad target_component on received rally point")
3092
if m.lat != item1_lat:
3093
raise NotAchievedException("Bad latitude on received rally point")
3094
3095
self.start_subtest("Test upload lockout and timeout")
3096
self.progress("Starting upload from normal sysid")
3097
self.mav.mav.mission_count_send(target_system,
3098
target_component,
3099
len(items),
3100
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3101
self.drain_mav() # throw away requests for items
3102
self.mav.mav.srcSystem = 243
3103
3104
self.progress("Attempting upload from sysid=%u" %
3105
(self.mav.mav.srcSystem,))
3106
self.mav.mav.mission_count_send(target_system,
3107
target_component,
3108
len(items),
3109
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3110
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3111
want_type=mavutil.mavlink.MAV_MISSION_DENIED)
3112
3113
self.progress("Attempting download from sysid=%u" %
3114
(self.mav.mav.srcSystem,))
3115
self.mav.mav.mission_request_list_send(target_system,
3116
target_component,
3117
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3118
3119
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3120
want_type=mavutil.mavlink.MAV_MISSION_DENIED)
3121
3122
# wait for the upload from sysid=1 to time out:
3123
tstart = self.get_sim_time()
3124
got_statustext = False
3125
got_ack = False
3126
while True:
3127
if got_statustext and got_ack:
3128
self.progress("Got both ack and statustext")
3129
break
3130
if self.get_sim_time_cached() - tstart > 100:
3131
raise NotAchievedException("Did not get both ack and statustext")
3132
m = self.mav.recv_match(type=['STATUSTEXT', 'MISSION_ACK'],
3133
blocking=True,
3134
timeout=1)
3135
if m is None:
3136
continue
3137
self.progress("Got (%s)" % str(m))
3138
if m.get_type() == 'STATUSTEXT':
3139
if "upload timeout" in m.text:
3140
got_statustext = True
3141
self.progress("Received desired statustext")
3142
continue
3143
if m.get_type() == 'MISSION_ACK':
3144
if m.target_system != old_srcSystem:
3145
raise NotAchievedException("Incorrect sourcesystem")
3146
if m.type != mavutil.mavlink.MAV_MISSION_OPERATION_CANCELLED:
3147
raise NotAchievedException("Incorrect result")
3148
if m.mission_type != mavutil.mavlink.MAV_MISSION_TYPE_RALLY:
3149
raise NotAchievedException("Incorrect mission_type")
3150
got_ack = True
3151
self.progress("Received desired ACK")
3152
continue
3153
raise NotAchievedException("Huh?")
3154
3155
self.progress("Now trying to upload empty mission after timeout")
3156
self.mav.mav.mission_count_send(target_system,
3157
target_component,
3158
0,
3159
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3160
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3161
3162
self.drain_mav()
3163
self.start_subtest("Check rally upload/download across separate links")
3164
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3165
items)
3166
self.progress("ensure a mavlink1 connection can't do anything useful with new item types")
3167
self.set_parameter("SERIAL2_PROTOCOL", 1)
3168
self.reboot_sitl()
3169
mav2 = mavutil.mavlink_connection("tcp:localhost:5763",
3170
robust_parsing=True,
3171
source_system=7,
3172
source_component=7)
3173
mav2.mav.mission_request_list_send(target_system,
3174
target_component,
3175
mission_type=mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3176
# so this looks a bit odd; the other end isn't sending
3177
# mavlink2 so can't fill in the extension here.
3178
self.assert_receive_mission_ack(
3179
mavutil.mavlink.MAV_MISSION_TYPE_MISSION,
3180
want_type=mavutil.mavlink.MAV_MISSION_UNSUPPORTED,
3181
mav=mav2,
3182
)
3183
# this relies on magic upgrade to serial2:
3184
self.set_parameter("SERIAL2_PROTOCOL", 2)
3185
expected_count = 3
3186
self.progress("Assert mission count on new link")
3187
self.assert_mission_count_on_link(
3188
mav2,
3189
expected_count,
3190
target_system,
3191
target_component,
3192
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3193
self.progress("Assert mission count on original link")
3194
self.assert_mission_count_on_link(
3195
self.mav,
3196
expected_count,
3197
target_system,
3198
target_component,
3199
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3200
self.progress("Get first item on new link")
3201
3202
def drain_self_mav_fn():
3203
self.drain_mav(self.mav)
3204
m2 = self.get_mission_item_int_on_link(
3205
2,
3206
mav2,
3207
target_system,
3208
target_component,
3209
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3210
delay_fn=drain_self_mav_fn)
3211
self.progress("Get first item on original link")
3212
m = self.get_mission_item_int_on_link(
3213
2,
3214
self.mav,
3215
target_system,
3216
target_component,
3217
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3218
if m2.x != m.x:
3219
raise NotAchievedException("mission items do not match (%d vs %d)" % (m2.x, m.x))
3220
self.get_mission_item_on_link(2, self.mav, target_system, target_component, mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3221
# ensure we get nacks for bad mission item requests:
3222
self.mav.mav.mission_request_send(target_system,
3223
target_component,
3224
65,
3225
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3226
self.assert_receive_mission_ack(
3227
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3228
want_type=mavutil.mavlink.MAV_MISSION_INVALID_SEQUENCE,
3229
)
3230
self.mav.mav.mission_request_int_send(target_system,
3231
target_component,
3232
65,
3233
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3234
self.assert_receive_mission_ack(
3235
mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3236
want_type=mavutil.mavlink.MAV_MISSION_INVALID_SEQUENCE,
3237
)
3238
3239
self.start_subtest("Should enforce items come from correct GCS")
3240
self.drain_mav(unparsed=True)
3241
self.mav.mav.mission_count_send(target_system,
3242
target_component,
3243
1,
3244
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3245
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 0)
3246
self.progress("Attempting to upload from bad sysid")
3247
old_sysid = self.mav.mav.srcSystem
3248
self.mav.mav.srcSystem = 17
3249
items[0].pack(self.mav.mav)
3250
self.drain_mav(unparsed=True)
3251
self.mav.mav.send(items[0])
3252
self.mav.mav.srcSystem = old_sysid
3253
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3254
want_type=mavutil.mavlink.MAV_MISSION_DENIED,
3255
target_system=17)
3256
self.progress("Sending from correct sysid")
3257
items[0].pack(self.mav.mav)
3258
self.drain_mav(unparsed=True)
3259
self.mav.mav.send(items[0])
3260
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3261
3262
self.drain_mav()
3263
self.drain_all_pexpects()
3264
3265
self.start_subtest("Attempt to send item on different link to that which we are sending requests on")
3266
self.progress("Sending count")
3267
self.drain_mav(unparsed=True)
3268
self.mav.mav.mission_count_send(target_system,
3269
target_component,
3270
2,
3271
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3272
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 0)
3273
old_mav2_system = mav2.mav.srcSystem
3274
old_mav2_component = mav2.mav.srcComponent
3275
mav2.mav.srcSystem = self.mav.mav.srcSystem
3276
mav2.mav.srcComponent = self.mav.mav.srcComponent
3277
self.progress("Sending item on second link")
3278
# note that the routing table in ArduPilot now will say
3279
# this sysid/compid is on both links which may cause
3280
# weirdness...
3281
items[0].pack(mav2.mav)
3282
self.drain_mav(mav=self.mav, unparsed=True)
3283
mav2.mav.send(items[0])
3284
mav2.mav.srcSystem = old_mav2_system
3285
mav2.mav.srcComponent = old_mav2_component
3286
# we continue to receive requests on the original link:
3287
m = self.assert_receive_message('MISSION_REQUEST')
3288
if m.mission_type != mavutil.mavlink.MAV_MISSION_TYPE_RALLY:
3289
raise NotAchievedException("Mission request of incorrect type")
3290
if m.seq != 1:
3291
raise NotAchievedException("Unexpected sequence number (expected=%u got=%u)" % (1, m.seq))
3292
items[1].pack(self.mav.mav)
3293
self.drain_mav(unparsed=True)
3294
self.mav.mav.send(items[1])
3295
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3296
3297
self.drain_mav()
3298
self.drain_all_pexpects()
3299
3300
self.start_subtest("Upload mission and rally points at same time")
3301
self.progress("Sending rally count")
3302
self.drain_mav(unparsed=True)
3303
self.mav.mav.mission_count_send(target_system,
3304
target_component,
3305
3,
3306
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3307
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 0)
3308
3309
self.progress("Sending wp count")
3310
self.mav.mav.mission_count_send(target_system,
3311
target_component,
3312
3,
3313
mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3314
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_MISSION, 0)
3315
3316
self.progress("Answering request for mission item 0")
3317
self.drain_mav(mav=self.mav, unparsed=True)
3318
self.mav.mav.mission_item_int_send(
3319
target_system,
3320
target_component,
3321
0, # seq
3322
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3323
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3324
0, # current
3325
0, # autocontinue
3326
0, # p1
3327
0, # p2
3328
0, # p3
3329
0, # p4
3330
int(1.1000 * 1e7), # latitude
3331
int(1.2000 * 1e7), # longitude
3332
321.0000, # altitude
3333
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3334
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_MISSION, 1)
3335
3336
self.progress("Answering request for rally point 0")
3337
items[0].pack(self.mav.mav)
3338
self.drain_mav(unparsed=True)
3339
self.mav.mav.send(items[0])
3340
self.progress("Expecting request for rally item 1")
3341
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 1)
3342
self.progress("Answering request for rally point 1")
3343
items[1].pack(self.mav.mav)
3344
self.drain_mav(unparsed=True)
3345
self.mav.mav.send(items[1])
3346
self.progress("Expecting request for rally item 2")
3347
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 2)
3348
3349
self.progress("Answering request for rally point 2")
3350
items[2].pack(self.mav.mav)
3351
self.drain_mav(unparsed=True)
3352
self.mav.mav.send(items[2])
3353
self.progress("Expecting mission ack for rally")
3354
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3355
3356
self.progress("Answering request for waypoints item 1")
3357
self.drain_mav(unparsed=True)
3358
self.mav.mav.mission_item_int_send(
3359
target_system,
3360
target_component,
3361
1, # seq
3362
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3363
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3364
0, # current
3365
0, # autocontinue
3366
0, # p1
3367
0, # p2
3368
0, # p3
3369
0, # p4
3370
int(1.1000 * 1e7), # latitude
3371
int(1.2000 * 1e7), # longitude
3372
321.0000, # altitude
3373
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3374
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_MISSION, 2)
3375
3376
self.progress("Answering request for waypoints item 2")
3377
self.drain_mav(unparsed=True)
3378
self.mav.mav.mission_item_int_send(
3379
target_system,
3380
target_component,
3381
2, # seq
3382
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3383
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3384
0, # current
3385
0, # autocontinue
3386
0, # p1
3387
0, # p2
3388
0, # p3
3389
0, # p4
3390
int(1.1000 * 1e7), # latitude
3391
int(1.2000 * 1e7), # longitude
3392
321.0000, # altitude
3393
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3394
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3395
3396
self.start_subtest("Test write-partial-list")
3397
self.progress("Clearing rally points using count-send")
3398
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3399
target_system=target_system,
3400
target_component=target_component)
3401
self.progress("Should not be able to set items completely past the waypoint count")
3402
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3403
items)
3404
self.drain_mav(unparsed=True)
3405
self.mav.mav.mission_write_partial_list_send(
3406
target_system,
3407
target_component,
3408
17,
3409
20,
3410
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3411
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3412
want_type=mavutil.mavlink.MAV_MISSION_ERROR)
3413
3414
self.progress("Should not be able to set items overlapping the waypoint count")
3415
self.drain_mav(unparsed=True)
3416
self.mav.mav.mission_write_partial_list_send(
3417
target_system,
3418
target_component,
3419
0,
3420
20,
3421
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3422
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3423
want_type=mavutil.mavlink.MAV_MISSION_ERROR)
3424
3425
self.progress("try to overwrite items 1 and 2")
3426
self.drain_mav(unparsed=True)
3427
self.mav.mav.mission_write_partial_list_send(
3428
target_system,
3429
target_component,
3430
1,
3431
2,
3432
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3433
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 1)
3434
self.progress("Try shoving up an incorrectly sequenced item")
3435
self.drain_mav(unparsed=True)
3436
self.mav.mav.mission_item_int_send(
3437
target_system,
3438
target_component,
3439
0, # seq
3440
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3441
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
3442
0, # current
3443
0, # autocontinue
3444
0, # p1
3445
0, # p2
3446
0, # p3
3447
0, # p4
3448
int(1.1000 * 1e7), # latitude
3449
int(1.2000 * 1e7), # longitude
3450
321.0000, # altitude
3451
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3452
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3453
want_type=mavutil.mavlink.MAV_MISSION_INVALID_SEQUENCE)
3454
3455
self.progress("Try shoving up an incorrectly sequenced item (but within band)")
3456
self.drain_mav(unparsed=True)
3457
self.mav.mav.mission_item_int_send(
3458
target_system,
3459
target_component,
3460
2, # seq
3461
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3462
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
3463
0, # current
3464
0, # autocontinue
3465
0, # p1
3466
0, # p2
3467
0, # p3
3468
0, # p4
3469
int(1.1000 * 1e7), # latitude
3470
int(1.2000 * 1e7), # longitude
3471
321.0000, # altitude
3472
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3473
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3474
want_type=mavutil.mavlink.MAV_MISSION_INVALID_SEQUENCE)
3475
3476
self.progress("Now provide correct item")
3477
item1_latitude = int(1.2345 * 1e7)
3478
self.drain_mav(unparsed=True)
3479
self.mav.mav.mission_item_int_send(
3480
target_system,
3481
target_component,
3482
1, # seq
3483
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
3484
mavutil.mavlink.MAV_CMD_NAV_RALLY_POINT,
3485
0, # current
3486
0, # autocontinue
3487
0, # p1
3488
0, # p2
3489
0, # p3
3490
0, # p4
3491
item1_latitude, # latitude
3492
int(1.2000 * 1e7), # longitude
3493
321.0000, # altitude
3494
mavutil.mavlink.MAV_MISSION_TYPE_RALLY),
3495
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_RALLY, 2)
3496
self.progress("Answering request for rally point 2")
3497
items[2].pack(self.mav.mav)
3498
self.drain_mav(unparsed=True)
3499
self.mav.mav.send(items[2])
3500
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3501
self.progress("TODO: ensure partial mission write was good")
3502
3503
self.start_subtest("clear mission types")
3504
self.assert_mission_count_on_link(
3505
self.mav,
3506
3,
3507
target_system,
3508
target_component,
3509
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3510
self.assert_mission_count_on_link(
3511
self.mav,
3512
3,
3513
target_system,
3514
target_component,
3515
mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3516
self.drain_mav(unparsed=True)
3517
self.mav.mav.mission_clear_all_send(target_system, target_component, mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3518
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3519
self.assert_mission_count_on_link(
3520
self.mav,
3521
0,
3522
target_system,
3523
target_component,
3524
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3525
self.assert_mission_count_on_link(
3526
self.mav,
3527
3,
3528
target_system,
3529
target_component,
3530
mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3531
self.drain_mav(unparsed=True)
3532
self.mav.mav.mission_clear_all_send(target_system, target_component, mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3533
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3534
self.assert_mission_count_on_link(
3535
self.mav,
3536
0,
3537
target_system,
3538
target_component,
3539
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3540
self.assert_mission_count_on_link(
3541
self.mav,
3542
0,
3543
target_system,
3544
target_component,
3545
mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3546
3547
self.start_subtest("try sending out-of-range counts")
3548
self.drain_mav(unparsed=True)
3549
self.mav.mav.mission_count_send(target_system,
3550
target_component,
3551
1,
3552
230)
3553
self.assert_receive_mission_ack(230,
3554
want_type=mavutil.mavlink.MAV_MISSION_UNSUPPORTED)
3555
self.drain_mav(unparsed=True)
3556
self.mav.mav.mission_count_send(target_system,
3557
target_component,
3558
16000,
3559
mavutil.mavlink.MAV_MISSION_TYPE_RALLY)
3560
self.assert_receive_mission_ack(mavutil.mavlink.MAV_MISSION_TYPE_RALLY,
3561
want_type=mavutil.mavlink.MAV_MISSION_NO_SPACE)
3562
3563
except Exception as e:
3564
self.progress("Received exception (%s)" % self.get_exception_stacktrace(e))
3565
self.mav.mav.srcSystem = old_srcSystem
3566
raise e
3567
self.reboot_sitl()
3568
3569
def ClearMission(self, target_system=1, target_component=1):
3570
'''check mission clearing'''
3571
3572
self.start_subtest("Clear via mission_clear_all message")
3573
self.upload_simple_relhome_mission([
3574
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 20, 0, 20),
3575
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 20, 0, 20),
3576
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 20, 0, 20),
3577
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 20, 0, 20),
3578
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 20, 0, 20),
3579
])
3580
self.set_current_waypoint(3)
3581
3582
self.mav.mav.mission_clear_all_send(
3583
target_system,
3584
target_component,
3585
mavutil.mavlink.MAV_MISSION_TYPE_MISSION
3586
)
3587
3588
self.assert_current_waypoint(0)
3589
3590
self.drain_mav()
3591
3592
self.start_subtest("No clear mission while it is being uploaded by a different node")
3593
mav2 = mavutil.mavlink_connection("tcp:localhost:5763",
3594
robust_parsing=True,
3595
source_system=7,
3596
source_component=7)
3597
self.context_push()
3598
self.context_collect("MISSION_REQUEST")
3599
mav2.mav.mission_count_send(target_system,
3600
target_component,
3601
17,
3602
mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3603
ack = self.assert_receive_message('MISSION_REQUEST', check_context=True, mav=mav2)
3604
self.context_pop()
3605
3606
self.context_push()
3607
self.context_collect("MISSION_ACK")
3608
self.mav.mav.mission_clear_all_send(
3609
target_system,
3610
target_component,
3611
mavutil.mavlink.MAV_MISSION_TYPE_MISSION
3612
)
3613
ack = self.assert_receive_message('MISSION_ACK', check_context=True)
3614
self.assert_message_field_values(ack, {
3615
"type": mavutil.mavlink.MAV_MISSION_DENIED,
3616
})
3617
self.context_pop()
3618
3619
self.progress("Test cancel upload from second connection")
3620
self.context_push()
3621
self.context_collect("MISSION_ACK")
3622
mav2.mav.mission_clear_all_send(
3623
target_system,
3624
target_component,
3625
mavutil.mavlink.MAV_MISSION_TYPE_MISSION
3626
)
3627
ack = self.assert_receive_message('MISSION_ACK', mav=mav2, check_context=True)
3628
self.assert_message_field_values(ack, {
3629
"type": mavutil.mavlink.MAV_MISSION_ACCEPTED,
3630
})
3631
self.context_pop()
3632
mav2.close()
3633
del mav2
3634
3635
def GCSMission(self):
3636
'''check MAVProxy's waypoint handling of missions'''
3637
# vehicle with state may have non-zero MISSION_CURRENT.seq, so reboot
3638
self.reboot_sitl()
3639
target_system = 1
3640
target_component = 1
3641
mavproxy = self.start_mavproxy()
3642
self.wait_parameter_value('MIS_TOTAL', 1)
3643
mavproxy.send('wp clear\n')
3644
self.wait_parameter_value('MIS_TOTAL', 0)
3645
self.assert_received_message_field_values('MISSION_CURRENT', {
3646
"seq": 0,
3647
}, timeout=5, verbose=True)
3648
self.load_mission_using_mavproxy(mavproxy, "rover-gripper-mission.txt")
3649
set_wp = 1
3650
mavproxy.send('wp set %u\n' % set_wp)
3651
self.wait_current_waypoint(set_wp)
3652
3653
self.start_subsubtest("wp changealt")
3654
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3655
changealt_item = 1
3656
# oldalt = downloaded_items[changealt_item].z
3657
want_newalt = 37.2
3658
mavproxy.send('wp changealt %u %f\n' % (changealt_item, want_newalt))
3659
self.delay_sim_time(15)
3660
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3661
if abs(downloaded_items[changealt_item].z - want_newalt) > 0.0001:
3662
raise NotAchievedException(
3663
"changealt didn't (want=%f got=%f)" %
3664
(want_newalt, downloaded_items[changealt_item].z))
3665
self.end_subsubtest("wp changealt")
3666
3667
self.start_subsubtest("wp sethome")
3668
new_home_lat = 3.14159
3669
new_home_lng = 2.71828
3670
mavproxy.send('click %f %f\n' % (new_home_lat, new_home_lng))
3671
mavproxy.send('wp sethome\n')
3672
self.delay_sim_time(5)
3673
# any way to close the loop on this one?
3674
# downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3675
# if abs(downloaded_items[0].x - new_home_lat) > 0.0001:
3676
# raise NotAchievedException("wp sethome didn't work")
3677
# if abs(downloaded_items[0].y - new_home_lng) > 0.0001:
3678
# raise NotAchievedException("wp sethome didn't work")
3679
self.end_subsubtest("wp sethome")
3680
3681
self.start_subsubtest("wp slope")
3682
mavproxy.send('wp slope\n')
3683
mavproxy.expect("WP3: slope 0.1")
3684
self.delay_sim_time(5)
3685
self.end_subsubtest("wp slope")
3686
3687
if not self.mavproxy_can_do_mision_item_protocols():
3688
# adding based on click location yet to be merged into MAVProxy
3689
return
3690
3691
self.start_subsubtest("wp split")
3692
mavproxy.send("wp clear\n")
3693
self.delay_sim_time(5)
3694
mavproxy.send("wp list\n")
3695
self.delay_sim_time(5)
3696
items = [
3697
None,
3698
self.mav.mav.mission_item_int_encode(
3699
target_system,
3700
target_component,
3701
1, # seq
3702
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3703
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3704
0, # current
3705
0, # autocontinue
3706
0, # p1
3707
0, # p2
3708
0, # p3
3709
0, # p4
3710
int(1.0 * 1e7), # latitude
3711
int(1.0 * 1e7), # longitude
3712
33.0000, # altitude
3713
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3714
self.mav.mav.mission_item_int_encode(
3715
target_system,
3716
target_component,
3717
2, # seq
3718
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3719
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3720
0, # current
3721
0, # autocontinue
3722
0, # p1
3723
0, # p2
3724
0, # p3
3725
0, # p4
3726
int(2.0 * 1e7), # latitude
3727
int(2.0 * 1e7), # longitude
3728
33.0000, # altitude
3729
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3730
]
3731
mavproxy.send("click 5 5\n") # space for home position
3732
mavproxy.send("wp add\n")
3733
self.delay_sim_time(5)
3734
self.click_location_from_item(mavproxy, items[1])
3735
mavproxy.send("wp add\n")
3736
self.delay_sim_time(5)
3737
self.click_location_from_item(mavproxy, items[2])
3738
mavproxy.send("wp add\n")
3739
self.delay_sim_time(5)
3740
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3741
self.check_mission_waypoint_items_same(items, downloaded_items)
3742
mavproxy.send("wp split 2\n")
3743
self.delay_sim_time(5)
3744
items_with_split_in = [
3745
items[0],
3746
items[1],
3747
self.mav.mav.mission_item_int_encode(
3748
target_system,
3749
target_component,
3750
2, # seq
3751
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3752
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
3753
0, # current
3754
0, # autocontinue
3755
0, # p1
3756
0, # p2
3757
0, # p3
3758
0, # p4
3759
int(1.5 * 1e7), # latitude
3760
int(1.5 * 1e7), # longitude
3761
33.0000, # altitude
3762
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
3763
items[2],
3764
]
3765
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_MISSION)
3766
self.check_mission_waypoint_items_same(items_with_split_in,
3767
downloaded_items)
3768
3769
mavproxy.send('wp clear\n')
3770
self.wait_parameter_value('MIS_TOTAL', 0)
3771
3772
self.stop_mavproxy(mavproxy)
3773
3774
# MANUAL> usage: wp <changealt|clear|draw|editor|list|load|loop|move|movemulti|noflyadd|param|remove|save|savecsv|savelocal|set|sethome|show|slope|split|status|undo|update> # noqa
3775
3776
def wait_location_sending_target(self, loc, target_system=1, target_component=1, timeout=60, max_delta=2):
3777
tstart = self.get_sim_time()
3778
last_sent = 0
3779
3780
type_mask = (mavutil.mavlink.POSITION_TARGET_TYPEMASK_VX_IGNORE +
3781
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VY_IGNORE +
3782
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VZ_IGNORE +
3783
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AX_IGNORE +
3784
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AY_IGNORE +
3785
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AZ_IGNORE +
3786
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_IGNORE +
3787
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE)
3788
3789
self.change_mode('GUIDED')
3790
tstart = self.get_sim_time()
3791
while True:
3792
now = self.get_sim_time_cached()
3793
if now - tstart > timeout:
3794
raise AutoTestTimeoutException("Did not get to location")
3795
if now - last_sent > 10:
3796
last_sent = now
3797
self.mav.mav.set_position_target_global_int_send(
3798
0,
3799
target_system,
3800
target_component,
3801
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3802
type_mask,
3803
int(loc.lat * 1.0e7),
3804
int(loc.lng * 1.0e7),
3805
0, # alt
3806
0, # x-ve
3807
0, # y-vel
3808
0, # z-vel
3809
0, # afx
3810
0, # afy
3811
0, # afz
3812
0, # yaw,
3813
0, # yaw-rate
3814
)
3815
m = self.mav.recv_match(blocking=True,
3816
timeout=1)
3817
if m is None:
3818
continue
3819
t = m.get_type()
3820
if t == "POSITION_TARGET_GLOBAL_INT":
3821
self.progress("Target: (%s)" % str(m), send_statustext=False)
3822
elif t == "GLOBAL_POSITION_INT":
3823
self.progress("Position: (%s)" % str(m), send_statustext=False)
3824
delta = self.get_distance(
3825
mavutil.location(m.lat * 1e-7, m.lon * 1e-7, 0, 0),
3826
loc)
3827
self.progress("delta: %s" % str(delta), send_statustext=False)
3828
if delta < max_delta:
3829
self.progress("Reached destination")
3830
3831
def drive_to_location(self, loc, tolerance=1, timeout=30, target_system=1, target_component=1):
3832
self.assert_mode('GUIDED')
3833
3834
type_mask = (mavutil.mavlink.POSITION_TARGET_TYPEMASK_VX_IGNORE +
3835
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VY_IGNORE +
3836
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VZ_IGNORE +
3837
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AX_IGNORE +
3838
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AY_IGNORE +
3839
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AZ_IGNORE +
3840
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_IGNORE +
3841
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE)
3842
3843
last_sent = 0
3844
tstart = self.get_sim_time()
3845
while True:
3846
now = self.get_sim_time_cached()
3847
if now - tstart > timeout:
3848
raise NotAchievedException("Did not get to location")
3849
if now - last_sent > 10:
3850
last_sent = now
3851
self.mav.mav.set_position_target_global_int_send(
3852
0,
3853
target_system,
3854
target_component,
3855
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3856
type_mask,
3857
int(loc.lat * 1.0e7),
3858
int(loc.lng * 1.0e7),
3859
0, # alt
3860
0, # x-ve
3861
0, # y-vel
3862
0, # z-vel
3863
0, # afx
3864
0, # afy
3865
0, # afz
3866
0, # yaw,
3867
0, # yaw-rate
3868
)
3869
if self.get_distance(self.mav.location(), loc) > tolerance:
3870
continue
3871
return
3872
3873
def drive_somewhere_breach_boundary_and_rtl(self, loc, target_system=1, target_component=1, timeout=60):
3874
tstart = self.get_sim_time()
3875
last_sent = 0
3876
seen_fence_breach = False
3877
3878
type_mask = (mavutil.mavlink.POSITION_TARGET_TYPEMASK_VX_IGNORE +
3879
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VY_IGNORE +
3880
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VZ_IGNORE +
3881
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AX_IGNORE +
3882
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AY_IGNORE +
3883
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AZ_IGNORE +
3884
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_IGNORE +
3885
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE)
3886
3887
self.change_mode('GUIDED')
3888
while True:
3889
now = self.get_sim_time_cached()
3890
if now - tstart > timeout:
3891
raise NotAchievedException("Did not breach boundary + RTL")
3892
if now - last_sent > 10:
3893
last_sent = now
3894
self.mav.mav.set_position_target_global_int_send(
3895
0,
3896
target_system,
3897
target_component,
3898
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3899
type_mask,
3900
int(loc.lat * 1.0e7),
3901
int(loc.lng * 1.0e7),
3902
0, # alt
3903
0, # x-ve
3904
0, # y-vel
3905
0, # z-vel
3906
0, # afx
3907
0, # afy
3908
0, # afz
3909
0, # yaw,
3910
0, # yaw-rate
3911
)
3912
m = self.mav.recv_match(blocking=True,
3913
timeout=1)
3914
if m is None:
3915
continue
3916
t = m.get_type()
3917
if t == "POSITION_TARGET_GLOBAL_INT":
3918
self.progress("Target: (%s)" % str(m))
3919
elif t == "GLOBAL_POSITION_INT":
3920
self.progress("Position: (%s)" % str(m))
3921
elif t == "FENCE_STATUS":
3922
self.progress("Fence: %s" % str(m))
3923
if m.breach_status != 0:
3924
seen_fence_breach = True
3925
self.progress("Fence breach detected!")
3926
if m.breach_type != mavutil.mavlink.FENCE_BREACH_BOUNDARY:
3927
raise NotAchievedException("Breach of unexpected type")
3928
if self.mode_is("RTL", cached=True) and seen_fence_breach:
3929
break
3930
self.wait_distance_to_home(3, 7, timeout=30)
3931
3932
def drive_somewhere_stop_at_boundary(self,
3933
loc,
3934
expected_stopping_point,
3935
expected_distance_epsilon=1.0,
3936
target_system=1,
3937
target_component=1,
3938
timeout=120):
3939
tstart = self.get_sim_time()
3940
last_sent = 0
3941
3942
type_mask = (mavutil.mavlink.POSITION_TARGET_TYPEMASK_VX_IGNORE +
3943
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VY_IGNORE +
3944
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VZ_IGNORE +
3945
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AX_IGNORE +
3946
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AY_IGNORE +
3947
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AZ_IGNORE +
3948
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_IGNORE +
3949
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE)
3950
3951
self.change_mode('GUIDED')
3952
at_stopping_point = False
3953
while True:
3954
now = self.get_sim_time_cached()
3955
if now - tstart > timeout:
3956
raise NotAchievedException("Did not arrive and stop at boundary")
3957
if now - last_sent > 10:
3958
last_sent = now
3959
self.mav.mav.set_position_target_global_int_send(
3960
0,
3961
target_system,
3962
target_component,
3963
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
3964
type_mask,
3965
int(loc.lat * 1.0e7),
3966
int(loc.lng * 1.0e7),
3967
0, # alt
3968
0, # x-ve
3969
0, # y-vel
3970
0, # z-vel
3971
0, # afx
3972
0, # afy
3973
0, # afz
3974
0, # yaw,
3975
0, # yaw-rate
3976
)
3977
m = self.mav.recv_match(blocking=True,
3978
timeout=1)
3979
if m is None:
3980
continue
3981
t = m.get_type()
3982
if t == "POSITION_TARGET_GLOBAL_INT":
3983
print("Target: (%s)" % str(m))
3984
elif t == "GLOBAL_POSITION_INT":
3985
print("Position: (%s)" % str(m))
3986
delta = self.get_distance(
3987
mavutil.location(m.lat * 1e-7, m.lon * 1e-7, 0, 0),
3988
mavutil.location(expected_stopping_point.lat,
3989
expected_stopping_point.lng,
3990
0,
3991
0))
3992
print("delta: %s want_delta<%f" % (str(delta), expected_distance_epsilon))
3993
at_stopping_point = delta < expected_distance_epsilon
3994
elif t == "VFR_HUD":
3995
print("groundspeed: %f" % m.groundspeed)
3996
if at_stopping_point:
3997
if m.groundspeed < 1:
3998
self.progress("Seemed to have stopped at stopping point")
3999
return
4000
4001
def assert_fence_breached(self):
4002
m = self.assert_receive_message('FENCE_STATUS', timeout=10)
4003
if m.breach_status != 1:
4004
raise NotAchievedException("Expected to be breached")
4005
4006
def wait_fence_not_breached(self, timeout=5):
4007
tstart = self.get_sim_time()
4008
while True:
4009
if self.get_sim_time_cached() - tstart > timeout:
4010
raise AutoTestTimeoutException("Fence remains breached")
4011
m = self.mav.recv_match(type='FENCE_STATUS',
4012
blocking=True,
4013
timeout=1)
4014
if m is None:
4015
self.progress("No FENCE_STATUS received")
4016
continue
4017
self.progress("STATUS: %s" % str(m))
4018
if m.breach_status == 0:
4019
break
4020
4021
def test_poly_fence_noarms(self, target_system=1, target_component=1):
4022
'''various tests to ensure we can't arm when in breach of a polyfence'''
4023
self.start_subtest("Ensure PolyFence arming checks work")
4024
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4025
target_system=target_system,
4026
target_component=target_component)
4027
self.set_parameters({
4028
"FENCE_TYPE": 2, # circle only
4029
})
4030
self.delay_sim_time(5) # let breaches clear
4031
# FIXME: should we allow this?
4032
self.progress("Ensure we can arm with no poly in place")
4033
self.change_mode("GUIDED")
4034
self.wait_ready_to_arm()
4035
self.arm_vehicle()
4036
self.disarm_vehicle()
4037
self.set_parameters({
4038
"FENCE_TYPE": 6, # polyfence + circle
4039
})
4040
4041
self.test_poly_fence_noarms_exclusion_circle(target_system=target_system,
4042
target_component=target_component)
4043
self.test_poly_fence_noarms_inclusion_circle(target_system=target_system,
4044
target_component=target_component)
4045
self.test_poly_fence_noarms_exclusion_polyfence(target_system=target_system,
4046
target_component=target_component)
4047
self.test_poly_fence_noarms_inclusion_polyfence(target_system=target_system,
4048
target_component=target_component)
4049
4050
def test_poly_fence_noarms_exclusion_circle(self, target_system=1, target_component=1):
4051
self.start_subtest("Ensure not armable when within an exclusion circle")
4052
4053
here = self.mav.location()
4054
4055
items = [
4056
self.mav.mav.mission_item_int_encode(
4057
target_system,
4058
target_component,
4059
0, # seq
4060
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4061
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
4062
0, # current
4063
0, # autocontinue
4064
5, # p1 - radius
4065
0, # p2
4066
0, # p3
4067
0, # p4
4068
int(here.lat * 1e7), # latitude
4069
int(here.lng * 1e7), # longitude
4070
33.0000, # altitude
4071
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
4072
self.mav.mav.mission_item_int_encode(
4073
target_system,
4074
target_component,
4075
1, # seq
4076
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4077
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
4078
0, # current
4079
0, # autocontinue
4080
5, # p1 - radius
4081
0, # p2
4082
0, # p3
4083
0, # p4
4084
int(self.offset_location_ne(here, 100, 100).lat * 1e7), # latitude
4085
int(here.lng * 1e7), # longitude
4086
33.0000, # altitude
4087
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
4088
]
4089
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4090
items)
4091
self.delay_sim_time(5) # ArduPilot only checks for breaches @1Hz
4092
self.drain_mav()
4093
self.assert_fence_breached()
4094
try:
4095
self.arm_motors_with_rc_input()
4096
except NotAchievedException:
4097
pass
4098
if self.armed():
4099
raise NotAchievedException(
4100
"Armed when within exclusion zone")
4101
4102
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4103
[])
4104
self.wait_fence_not_breached()
4105
4106
def test_poly_fence_noarms_inclusion_circle(self, target_system=1, target_component=1):
4107
self.start_subtest("Ensure not armable when outside an inclusion circle (but within another")
4108
4109
here = self.mav.location()
4110
4111
items = [
4112
self.mav.mav.mission_item_int_encode(
4113
target_system,
4114
target_component,
4115
0, # seq
4116
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4117
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION,
4118
0, # current
4119
0, # autocontinue
4120
5, # p1 - radius
4121
0, # p2
4122
0, # p3
4123
0, # p4
4124
int(here.lat * 1e7), # latitude
4125
int(here.lng * 1e7), # longitude
4126
33.0000, # altitude
4127
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
4128
self.mav.mav.mission_item_int_encode(
4129
target_system,
4130
target_component,
4131
1, # seq
4132
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4133
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION,
4134
0, # current
4135
0, # autocontinue
4136
5, # p1 - radius
4137
0, # p2
4138
0, # p3
4139
0, # p4
4140
int(self.offset_location_ne(here, 100, 100).lat * 1e7), # latitude
4141
int(here.lng * 1e7), # longitude
4142
33.0000, # altitude
4143
mavutil.mavlink.MAV_MISSION_TYPE_FENCE),
4144
]
4145
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4146
items)
4147
self.delay_sim_time(5) # ArduPilot only checks for breaches @1Hz
4148
self.drain_mav()
4149
self.assert_fence_breached()
4150
try:
4151
self.arm_motors_with_rc_input()
4152
except NotAchievedException:
4153
pass
4154
if self.armed():
4155
raise NotAchievedException(
4156
"Armed when outside an inclusion zone")
4157
4158
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4159
[])
4160
self.wait_fence_not_breached()
4161
4162
def test_poly_fence_noarms_exclusion_polyfence(self, target_system=1, target_component=1):
4163
self.start_subtest("Ensure not armable when inside an exclusion polyfence (but outside another")
4164
4165
here = self.mav.location()
4166
4167
self.upload_fences_from_locations([
4168
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4169
# east
4170
self.offset_location_ne(here, -50, 20), # bl
4171
self.offset_location_ne(here, 50, 20), # br
4172
self.offset_location_ne(here, 50, 40), # tr
4173
self.offset_location_ne(here, -50, 40), # tl,
4174
]),
4175
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4176
# over the top of the vehicle
4177
self.offset_location_ne(here, -50, -50), # bl
4178
self.offset_location_ne(here, -50, 50), # br
4179
self.offset_location_ne(here, 50, 50), # tr
4180
self.offset_location_ne(here, 50, -50), # tl,
4181
]),
4182
])
4183
self.delay_sim_time(5) # ArduPilot only checks for breaches @1Hz
4184
self.drain_mav()
4185
self.assert_fence_breached()
4186
try:
4187
self.arm_motors_with_rc_input()
4188
except NotAchievedException:
4189
pass
4190
if self.armed():
4191
raise NotAchievedException(
4192
"Armed when within polygon exclusion zone")
4193
4194
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4195
[])
4196
self.wait_fence_not_breached()
4197
4198
def test_poly_fence_noarms_inclusion_polyfence(self, target_system=1, target_component=1):
4199
self.start_subtest("Ensure not armable when outside an inclusion polyfence (but within another")
4200
4201
here = self.mav.location()
4202
4203
self.upload_fences_from_locations([
4204
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
4205
# east
4206
self.offset_location_ne(here, -50, 20), # bl
4207
self.offset_location_ne(here, 50, 20), # br
4208
self.offset_location_ne(here, 50, 40), # tr
4209
self.offset_location_ne(here, -50, 40), # tl,
4210
]),
4211
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
4212
# over the top of the vehicle
4213
self.offset_location_ne(here, -50, -50), # bl
4214
self.offset_location_ne(here, -50, 50), # br
4215
self.offset_location_ne(here, 50, 50), # tr
4216
self.offset_location_ne(here, 50, -50), # tl,
4217
]),
4218
])
4219
self.delay_sim_time(5) # ArduPilot only checks for breaches @1Hz
4220
self.drain_mav()
4221
self.assert_fence_breached()
4222
try:
4223
self.arm_motors_with_rc_input()
4224
except NotAchievedException:
4225
pass
4226
if self.armed():
4227
raise NotAchievedException(
4228
"Armed when outside polygon inclusion zone")
4229
4230
self.upload_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4231
[])
4232
self.wait_fence_not_breached()
4233
4234
def test_fence_upload_timeouts_1(self, target_system=1, target_component=1):
4235
self.start_subtest("fence_upload timeouts 1")
4236
self.progress("Telling victim there will be one item coming")
4237
self.mav.mav.mission_count_send(target_system,
4238
target_component,
4239
1,
4240
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4241
m = self.assert_receive_message(['MISSION_REQUEST', 'MISSION_ACK'], verbose=True)
4242
if m.get_type() == "MISSION_ACK":
4243
raise NotAchievedException("Expected MISSION_REQUEST")
4244
4245
if m.seq != 0:
4246
raise NotAchievedException("Expected request for seq=0")
4247
4248
if m.target_system != self.mav.mav.srcSystem:
4249
raise NotAchievedException("Incorrect target system in MISSION_REQUEST")
4250
if m.target_component != self.mav.mav.srcComponent:
4251
raise NotAchievedException("Incorrect target component in MISSION_REQUEST")
4252
tstart = self.get_sim_time()
4253
rerequest_count = 0
4254
received_text = False
4255
received_ack = False
4256
while True:
4257
if received_ack and received_text:
4258
break
4259
if self.get_sim_time_cached() - tstart > 10:
4260
raise NotAchievedException("Did not get expected ack and statustext")
4261
m = self.mav.recv_match(type=['MISSION_REQUEST', 'MISSION_ACK', 'STATUSTEXT'],
4262
blocking=True,
4263
timeout=1)
4264
self.progress("Got (%s)" % str(m))
4265
if m is None:
4266
self.progress("Did not receive any messages")
4267
continue
4268
if m.get_type() == "MISSION_REQUEST":
4269
if m.seq != 0:
4270
raise NotAchievedException("Received request for invalid seq")
4271
if m.target_system != self.mav.mav.srcSystem:
4272
raise NotAchievedException("Incorrect target system in MISSION_REQUEST")
4273
if m.target_component != self.mav.mav.srcComponent:
4274
raise NotAchievedException("Incorrect target component in MISSION_REQUEST")
4275
rerequest_count += 1
4276
self.progress("Valid re-request received.")
4277
continue
4278
if m.get_type() == "MISSION_ACK":
4279
if m.mission_type != mavutil.mavlink.MAV_MISSION_TYPE_FENCE:
4280
raise NotAchievedException("Wrong mission type")
4281
if m.type != mavutil.mavlink.MAV_MISSION_OPERATION_CANCELLED:
4282
raise NotAchievedException("Wrong result")
4283
received_ack = True
4284
continue
4285
if m.get_type() == "STATUSTEXT":
4286
if "upload time" in m.text:
4287
received_text = True
4288
continue
4289
if rerequest_count < 3:
4290
raise NotAchievedException("Expected several re-requests of mission item")
4291
self.end_subtest("fence upload timeouts 1")
4292
4293
def expect_request_for_item(self, item):
4294
m = self.assert_receive_message(['MISSION_REQUEST', 'MISSION_ACK'], verbose=-True)
4295
if m.get_type() == "MISSION_ACK":
4296
raise NotAchievedException("Expected MISSION_REQUEST")
4297
4298
if m.seq != item.seq:
4299
raise NotAchievedException("Expected request for seq=%u" % item.seq)
4300
4301
if m.target_system != self.mav.mav.srcSystem:
4302
raise NotAchievedException("Incorrect target system in MISSION_REQUEST")
4303
if m.target_component != self.mav.mav.srcComponent:
4304
raise NotAchievedException("Incorrect target component in MISSION_REQUEST")
4305
4306
def test_fence_upload_timeouts_2(self, target_system=1, target_component=1):
4307
self.start_subtest("fence upload timeouts 2")
4308
self.progress("Telling victim there will be two items coming")
4309
# avoid a timeout race condition where ArduPilot re-requests a
4310
# fence point before we receive and respond to the first one.
4311
# Since ArduPilot has a 1s timeout on re-requesting, This only
4312
# requires a round-trip delay of 1/speedup seconds to trigger
4313
# - and that has been seen in practise on Travis
4314
old_speedup = self.get_parameter("SIM_SPEEDUP")
4315
self.set_parameter("SIM_SPEEDUP", 1)
4316
self.mav.mav.mission_count_send(target_system,
4317
target_component,
4318
2,
4319
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4320
self.progress("Sending item with seq=0")
4321
item = self.mav.mav.mission_item_int_encode(
4322
target_system,
4323
target_component,
4324
0, # seq
4325
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4326
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
4327
0, # current
4328
0, # autocontinue
4329
1, # p1 radius
4330
0, # p2
4331
0, # p3
4332
0, # p4
4333
int(1.1 * 1e7), # latitude
4334
int(1.2 * 1e7), # longitude
4335
33.0000, # altitude
4336
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4337
self.expect_request_for_item(item)
4338
item.pack(self.mav.mav)
4339
self.mav.mav.send(item)
4340
4341
self.progress("Sending item with seq=1")
4342
item = self.mav.mav.mission_item_int_encode(
4343
target_system,
4344
target_component,
4345
1, # seq
4346
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
4347
mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION,
4348
0, # current
4349
0, # autocontinue
4350
1, # p1 radius
4351
0, # p2
4352
0, # p3
4353
0, # p4
4354
int(1.1 * 1e7), # latitude
4355
int(1.2 * 1e7), # longitude
4356
33.0000, # altitude
4357
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4358
4359
self.expect_request_for_item(item)
4360
4361
self.set_parameter("SIM_SPEEDUP", old_speedup)
4362
4363
self.progress("Now waiting for a timeout")
4364
tstart = self.get_sim_time()
4365
rerequest_count = 0
4366
received_text = False
4367
received_ack = False
4368
while True:
4369
if received_ack and received_text:
4370
break
4371
if self.get_sim_time_cached() - tstart > 10:
4372
raise NotAchievedException("Did not get expected ack and statustext")
4373
m = self.mav.recv_match(type=['MISSION_REQUEST', 'MISSION_ACK', 'STATUSTEXT'],
4374
blocking=True,
4375
timeout=0.1)
4376
self.progress("Got (%s)" % str(m))
4377
if m is None:
4378
self.progress("Did not receive any messages")
4379
continue
4380
if m.get_type() == "MISSION_REQUEST":
4381
if m.seq != 1:
4382
raise NotAchievedException("Received request for invalid seq")
4383
if m.target_system != self.mav.mav.srcSystem:
4384
raise NotAchievedException("Incorrect target system in MISSION_REQUEST")
4385
if m.target_component != self.mav.mav.srcComponent:
4386
raise NotAchievedException("Incorrect target component in MISSION_REQUEST")
4387
rerequest_count += 1
4388
self.progress("Valid re-request received.")
4389
continue
4390
if m.get_type() == "MISSION_ACK":
4391
if m.mission_type != mavutil.mavlink.MAV_MISSION_TYPE_FENCE:
4392
raise NotAchievedException("Wrong mission type")
4393
if m.type != mavutil.mavlink.MAV_MISSION_OPERATION_CANCELLED:
4394
raise NotAchievedException("Wrong result")
4395
received_ack = True
4396
continue
4397
if m.get_type() == "STATUSTEXT":
4398
if "upload time" in m.text:
4399
received_text = True
4400
continue
4401
if rerequest_count < 3:
4402
raise NotAchievedException("Expected several re-requests of mission item")
4403
self.end_subtest("fence upload timeouts 2")
4404
4405
def test_fence_upload_timeouts(self, target_system=1, target_component=1):
4406
self.test_fence_upload_timeouts_1(target_system=target_system,
4407
target_component=target_component)
4408
self.test_fence_upload_timeouts_2(target_system=target_system,
4409
target_component=target_component)
4410
4411
def test_poly_fence_compatability_ordering(self, target_system=1, target_component=1):
4412
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4413
target_system=target_system,
4414
target_component=target_component)
4415
here = self.mav.location()
4416
self.progress("try uploading return point last")
4417
self.roundtrip_fence_using_fencepoint_protocol([
4418
self.offset_location_ne(here, 0, 0), # bl // return point
4419
self.offset_location_ne(here, -50, 20), # bl
4420
self.offset_location_ne(here, 50, 20), # br
4421
self.offset_location_ne(here, 50, 40), # tr
4422
self.offset_location_ne(here, -50, 40), # tl,
4423
self.offset_location_ne(here, -50, 20), # closing point
4424
], ordering=[1, 2, 3, 4, 5, 0])
4425
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4426
target_system=target_system,
4427
target_component=target_component)
4428
4429
self.progress("try uploading return point in middle")
4430
self.roundtrip_fence_using_fencepoint_protocol([
4431
self.offset_location_ne(here, 0, 0), # bl // return point
4432
self.offset_location_ne(here, -50, 20), # bl
4433
self.offset_location_ne(here, 50, 20), # br
4434
self.offset_location_ne(here, 50, 40), # tr
4435
self.offset_location_ne(here, -50, 40), # tl,
4436
self.offset_location_ne(here, -50, 20), # closing point
4437
], ordering=[1, 2, 3, 0, 4, 5])
4438
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4439
target_system=target_system,
4440
target_component=target_component)
4441
4442
self.progress("try closing point in middle")
4443
self.roundtrip_fence_using_fencepoint_protocol([
4444
self.offset_location_ne(here, 0, 0), # bl // return point
4445
self.offset_location_ne(here, -50, 20), # bl
4446
self.offset_location_ne(here, 50, 20), # br
4447
self.offset_location_ne(here, 50, 40), # tr
4448
self.offset_location_ne(here, -50, 40), # tl,
4449
self.offset_location_ne(here, -50, 20), # closing point
4450
], ordering=[0, 1, 2, 5, 3, 4])
4451
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4452
target_system=target_system,
4453
target_component=target_component)
4454
4455
# this is expected to fail as we don't return the closing
4456
# point correctly until the first is uploaded
4457
# self.progress("try closing point first")
4458
# failed = False
4459
# try:
4460
# self.roundtrip_fence_using_fencepoint_protocol([
4461
# self.offset_location_ne(here, 0, 0), # bl // return point
4462
# self.offset_location_ne(here, -50, 20), # bl
4463
# self.offset_location_ne(here, 50, 20), # br
4464
# self.offset_location_ne(here, 50, 40), # tr
4465
# self.offset_location_ne(here, -50, 40), # tl,
4466
# self.offset_location_ne(here, -50, 20), # closing point
4467
# ], ordering=[5, 0, 1, 2, 3, 4])
4468
# except NotAchievedException as e:
4469
# failed = "got=0.000000 want=" in str(e)
4470
# if not failed:
4471
# raise NotAchievedException("Expected failure, did not get it")
4472
# self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4473
# target_system=target_system,
4474
# target_component=target_component)
4475
4476
self.progress("try (almost) reverse order")
4477
self.roundtrip_fence_using_fencepoint_protocol([
4478
self.offset_location_ne(here, 0, 0), # bl // return point
4479
self.offset_location_ne(here, -50, 20), # bl
4480
self.offset_location_ne(here, 50, 20), # br
4481
self.offset_location_ne(here, 50, 40), # tr
4482
self.offset_location_ne(here, -50, 40), # tl,
4483
self.offset_location_ne(here, -50, 20), # closing point
4484
], ordering=[4, 3, 2, 1, 0, 5])
4485
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4486
target_system=target_system,
4487
target_component=target_component)
4488
4489
def test_poly_fence_big_then_small(self, target_system=1, target_component=1):
4490
here = self.mav.location()
4491
4492
self.roundtrip_fence_using_fencepoint_protocol([
4493
self.offset_location_ne(here, 0, 0), # bl // return point
4494
self.offset_location_ne(here, -50, 20), # bl
4495
self.offset_location_ne(here, 50, 20), # br
4496
self.offset_location_ne(here, 50, 40), # tr
4497
self.offset_location_ne(here, -50, 40), # tl,
4498
self.offset_location_ne(here, -50, 20), # closing point
4499
], ordering=[1, 2, 3, 4, 5, 0])
4500
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4501
if len(downloaded_items) != 5:
4502
# that's one return point and then bl, br, tr, then tl
4503
raise NotAchievedException("Bad number of downloaded items in original download")
4504
4505
self.roundtrip_fence_using_fencepoint_protocol([
4506
self.offset_location_ne(here, 0, 0), # bl // return point
4507
self.offset_location_ne(here, -50, 20), # bl
4508
self.offset_location_ne(here, 50, 40), # tr
4509
self.offset_location_ne(here, -50, 40), # tl,
4510
self.offset_location_ne(here, -50, 20), # closing point
4511
], ordering=[1, 2, 3, 4, 0])
4512
4513
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4514
want_count = 4
4515
if len(downloaded_items) != want_count:
4516
# that's one return point and then bl, tr, then tl
4517
raise NotAchievedException("Bad number of downloaded items in second download got=%u wanted=%u" %
4518
(len(downloaded_items), want_count))
4519
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4520
if len(downloaded_items) != 4:
4521
# that's one return point and then bl, tr, then tl
4522
raise NotAchievedException("Bad number of downloaded items in second download (second time) got=%u want=%u" %
4523
(len(downloaded_items), want_count))
4524
4525
def test_poly_fence_compatability(self, target_system=1, target_component=1):
4526
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
4527
target_system=target_system,
4528
target_component=target_component)
4529
4530
self.test_poly_fence_compatability_ordering(target_system=target_system, target_component=target_component)
4531
4532
here = self.mav.location()
4533
4534
self.progress("Playing with changing point count")
4535
self.roundtrip_fence_using_fencepoint_protocol(
4536
[
4537
self.offset_location_ne(here, 0, 0), # bl // return point
4538
self.offset_location_ne(here, -50, 20), # bl
4539
self.offset_location_ne(here, 50, 20), # br
4540
self.offset_location_ne(here, 50, 40), # tr
4541
self.offset_location_ne(here, -50, 40), # tl,
4542
self.offset_location_ne(here, -50, 20), # closing point
4543
])
4544
self.roundtrip_fence_using_fencepoint_protocol(
4545
[
4546
self.offset_location_ne(here, 0, 0), # bl // return point
4547
self.offset_location_ne(here, -50, 20), # bl
4548
self.offset_location_ne(here, 50, 20), # br
4549
self.offset_location_ne(here, -50, 40), # tl,
4550
self.offset_location_ne(here, -50, 20), # closing point
4551
])
4552
self.roundtrip_fence_using_fencepoint_protocol(
4553
[
4554
self.offset_location_ne(here, 0, 0), # bl // return point
4555
self.offset_location_ne(here, -50, 20), # bl
4556
self.offset_location_ne(here, 50, 20), # br
4557
self.offset_location_ne(here, 50, 40), # tr
4558
self.offset_location_ne(here, -50, 40), # tl,
4559
self.offset_location_ne(here, -50, 20), # closing point
4560
])
4561
4562
def test_poly_fence_reboot_survivability(self):
4563
here = self.mav.location()
4564
4565
self.upload_fences_from_locations([
4566
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4567
# east
4568
self.offset_location_ne(here, -50, 20), # bl
4569
self.offset_location_ne(here, 50, 20), # br
4570
self.offset_location_ne(here, 50, 40), # tr
4571
self.offset_location_ne(here, -50, 40), # tl,
4572
]),
4573
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4574
# over the top of the vehicle
4575
self.offset_location_ne(here, -50, -50), # bl
4576
self.offset_location_ne(here, -50, 50), # br
4577
self.offset_location_ne(here, 50, 50), # tr
4578
self.offset_location_ne(here, 50, -50), # tl,
4579
]),
4580
])
4581
self.reboot_sitl()
4582
downloaded_items = self.download_using_mission_protocol(mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
4583
downloaded_len = len(downloaded_items)
4584
if downloaded_len != 8:
4585
raise NotAchievedException("Items did not survive reboot (want=%u got=%u)" %
4586
(8, downloaded_len))
4587
4588
def PolyFence(self):
4589
'''test fence-related functions'''
4590
target_system = 1
4591
target_component = 1
4592
4593
self.change_mode("LOITER")
4594
self.wait_ready_to_arm()
4595
here = self.mav.location()
4596
self.progress("here: %f %f" % (here.lat, here.lng))
4597
self.set_parameters({
4598
"FENCE_ENABLE": 1,
4599
"AVOID_ENABLE": 0,
4600
})
4601
4602
# self.set_parameter("SIM_SPEEDUP", 1)
4603
4604
self.test_poly_fence_big_then_small()
4605
4606
self.test_poly_fence_compatability()
4607
4608
self.test_fence_upload_timeouts()
4609
4610
self.test_poly_fence_noarms(target_system=target_system, target_component=target_component)
4611
4612
self.arm_vehicle()
4613
4614
self.test_poly_fence_inclusion(here, target_system=target_system, target_component=target_component)
4615
self.test_poly_fence_exclusion(here, target_system=target_system, target_component=target_component)
4616
4617
self.disarm_vehicle()
4618
4619
self.test_poly_fence_reboot_survivability()
4620
4621
def test_poly_fence_inclusion_overlapping_inclusion_circles(self, here, target_system=1, target_component=1):
4622
self.start_subtest("Overlapping circular inclusion")
4623
self.upload_fences_from_locations([
4624
(mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION, {
4625
"radius": 30,
4626
"loc": self.offset_location_ne(here, -20, 0),
4627
}),
4628
(mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION, {
4629
"radius": 30,
4630
"loc": self.offset_location_ne(here, 20, 0),
4631
}),
4632
])
4633
if self.mavproxy is not None:
4634
# handy for getting pretty pictures
4635
self.mavproxy.send("fence list\n")
4636
4637
self.delay_sim_time(5)
4638
self.progress("Drive outside top circle")
4639
fence_middle = self.offset_location_ne(here, -150, 0)
4640
self.drive_somewhere_breach_boundary_and_rtl(
4641
fence_middle,
4642
target_system=target_system,
4643
target_component=target_component)
4644
4645
self.delay_sim_time(5)
4646
self.progress("Drive outside bottom circle")
4647
fence_middle = self.offset_location_ne(here, 150, 0)
4648
self.drive_somewhere_breach_boundary_and_rtl(
4649
fence_middle,
4650
target_system=target_system,
4651
target_component=target_component)
4652
4653
def test_poly_fence_inclusion(self, here, target_system=1, target_component=1):
4654
self.progress("Circle and Polygon inclusion")
4655
self.test_poly_fence_inclusion_overlapping_inclusion_circles(
4656
here,
4657
target_system=target_system,
4658
target_component=target_component)
4659
4660
self.upload_fences_from_locations([
4661
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
4662
self.offset_location_ne(here, -40, -20), # tl
4663
self.offset_location_ne(here, 50, -20), # tr
4664
self.offset_location_ne(here, 50, 20), # br
4665
self.offset_location_ne(here, -40, 20), # bl,
4666
]),
4667
(mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION, {
4668
"radius": 30,
4669
"loc": self.offset_location_ne(here, -20, 0),
4670
}),
4671
])
4672
4673
self.delay_sim_time(5)
4674
if self.mavproxy is not None:
4675
self.mavproxy.send("fence list\n")
4676
self.progress("Drive outside polygon")
4677
fence_middle = self.offset_location_ne(here, -150, 0)
4678
self.drive_somewhere_breach_boundary_and_rtl(
4679
fence_middle,
4680
target_system=target_system,
4681
target_component=target_component)
4682
4683
self.delay_sim_time(5)
4684
self.progress("Drive outside circle")
4685
fence_middle = self.offset_location_ne(here, 150, 0)
4686
self.drive_somewhere_breach_boundary_and_rtl(
4687
fence_middle,
4688
target_system=target_system,
4689
target_component=target_component)
4690
4691
self.upload_fences_from_locations([
4692
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
4693
self.offset_location_ne(here, -20, -25), # tl
4694
self.offset_location_ne(here, 50, -25), # tr
4695
self.offset_location_ne(here, 50, 15), # br
4696
self.offset_location_ne(here, -20, 15), # bl,
4697
]),
4698
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
4699
self.offset_location_ne(here, 20, -20), # tl
4700
self.offset_location_ne(here, -50, -20), # tr
4701
self.offset_location_ne(here, -50, 20), # br
4702
self.offset_location_ne(here, 20, 20), # bl,
4703
]),
4704
])
4705
4706
self.delay_sim_time(5)
4707
if self.mavproxy is not None:
4708
self.mavproxy.send("fence list\n")
4709
self.progress("Drive outside top polygon")
4710
fence_middle = self.offset_location_ne(here, -150, 0)
4711
self.drive_somewhere_breach_boundary_and_rtl(
4712
fence_middle,
4713
target_system=target_system,
4714
target_component=target_component)
4715
4716
self.delay_sim_time(5)
4717
self.progress("Drive outside bottom polygon")
4718
fence_middle = self.offset_location_ne(here, 150, 0)
4719
self.drive_somewhere_breach_boundary_and_rtl(
4720
fence_middle,
4721
target_system=target_system,
4722
target_component=target_component)
4723
4724
def test_poly_fence_exclusion(self, here, target_system=1, target_component=1):
4725
4726
self.upload_fences_from_locations([
4727
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4728
# east
4729
self.offset_location_ne(here, -50, 20), # bl
4730
self.offset_location_ne(here, 50, 20), # br
4731
self.offset_location_ne(here, 50, 40), # tr
4732
self.offset_location_ne(here, -50, 40), # tl,
4733
]),
4734
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4735
# west
4736
self.offset_location_ne(here, -50, -20), # tl
4737
self.offset_location_ne(here, 50, -20), # tr
4738
self.offset_location_ne(here, 50, -40), # br
4739
self.offset_location_ne(here, -50, -40), # bl,
4740
]),
4741
(mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_EXCLUSION, {
4742
"radius": 30,
4743
"loc": self.offset_location_ne(here, -60, 0),
4744
}),
4745
])
4746
self.delay_sim_time(5)
4747
if self.mavproxy is not None:
4748
self.mavproxy.send("fence list\n")
4749
4750
self.progress("Breach eastern boundary")
4751
fence_middle = self.offset_location_ne(here, 0, 30)
4752
self.drive_somewhere_breach_boundary_and_rtl(fence_middle,
4753
target_system=target_system,
4754
target_component=target_component)
4755
4756
self.progress("delaying - hack to work around manual recovery bug")
4757
self.delay_sim_time(5)
4758
4759
self.progress("Breach western boundary")
4760
fence_middle = self.offset_location_ne(here, 0, -30)
4761
self.drive_somewhere_breach_boundary_and_rtl(fence_middle,
4762
target_system=target_system,
4763
target_component=target_component)
4764
4765
self.progress("delaying - hack to work around manual recovery bug")
4766
self.delay_sim_time(5)
4767
4768
self.progress("Breach southern circle")
4769
fence_middle = self.offset_location_ne(here, -150, 0)
4770
self.drive_somewhere_breach_boundary_and_rtl(fence_middle,
4771
target_system=target_system,
4772
target_component=target_component)
4773
4774
def SmartRTL(self):
4775
'''Test SmartRTL'''
4776
self.change_mode("STEERING")
4777
self.wait_ready_to_arm()
4778
self.arm_vehicle()
4779
# drive two sides of a square, make sure we don't go back through
4780
# the middle of the square
4781
self.progress("Driving North")
4782
self.reach_heading_manual(0)
4783
self.set_rc(3, 2000)
4784
self.delay_sim_time(5)
4785
self.set_rc(3, 1000)
4786
self.wait_groundspeed(0, 1)
4787
loc = self.mav.location()
4788
self.progress("Driving East")
4789
self.set_rc(3, 2000)
4790
self.reach_heading_manual(90)
4791
self.set_rc(3, 2000)
4792
self.delay_sim_time(5)
4793
self.set_rc(3, 1000)
4794
4795
self.progress("Entering smartrtl")
4796
self.change_mode("SMART_RTL")
4797
4798
self.progress("Ensure we go via intermediate point")
4799
self.wait_distance_to_location(loc, 0, 5, timeout=60)
4800
4801
self.progress("Ensure we get home")
4802
self.wait_distance_to_home(3, 7, timeout=30)
4803
4804
self.disarm_vehicle()
4805
4806
def MotorTest(self):
4807
'''Motor Test triggered via mavlink'''
4808
magic_throttle_value = 1812
4809
self.wait_ready_to_arm()
4810
self.run_cmd(
4811
mavutil.mavlink.MAV_CMD_DO_MOTOR_TEST,
4812
p1=1, # motor instance
4813
p2=mavutil.mavlink.MOTOR_TEST_THROTTLE_PWM, # throttle type
4814
p3=magic_throttle_value, # throttle
4815
p4=5, # timeout
4816
p5=1, # motor count
4817
p6=0, # test order (see MOTOR_TEST_ORDER)
4818
)
4819
self.wait_armed()
4820
self.progress("Waiting for magic throttle value")
4821
self.wait_servo_channel_value(3, magic_throttle_value)
4822
self.wait_servo_channel_value(3, self.get_parameter("RC3_TRIM", 5), timeout=10)
4823
self.wait_disarmed()
4824
4825
def PolyFenceObjectAvoidanceGuided(self, target_system=1, target_component=1):
4826
'''PolyFence object avoidance tests - guided mode'''
4827
if not self.mavproxy_can_do_mision_item_protocols():
4828
return
4829
4830
self.test_poly_fence_object_avoidance_guided_pathfinding(
4831
target_system=target_system,
4832
target_component=target_component)
4833
self.test_poly_fence_object_avoidance_guided_two_squares(
4834
target_system=target_system,
4835
target_component=target_component)
4836
4837
def PolyFenceObjectAvoidanceAuto(self, target_system=1, target_component=1):
4838
'''PolyFence object avoidance tests - auto mode'''
4839
mavproxy = self.start_mavproxy()
4840
self.load_fence_using_mavproxy(mavproxy, "rover-path-planning-fence.txt")
4841
self.stop_mavproxy(mavproxy)
4842
# self.load_fence("rover-path-planning-fence.txt")
4843
self.load_mission("rover-path-planning-mission.txt")
4844
self.set_parameters({
4845
"AVOID_ENABLE": 3,
4846
"OA_TYPE": 2,
4847
"FENCE_MARGIN": 0, # FIXME: https://github.com/ArduPilot/ardupilot/issues/11601
4848
})
4849
self.reboot_sitl()
4850
self.change_mode('AUTO')
4851
self.wait_ready_to_arm()
4852
self.arm_vehicle()
4853
self.set_parameter("FENCE_ENABLE", 1)
4854
# target_loc is copied from the mission file
4855
target_loc = mavutil.location(40.073799, -105.229156)
4856
self.wait_location(target_loc, height_accuracy=None, timeout=300)
4857
# mission has RTL as last item
4858
self.wait_distance_to_home(3, 7, timeout=300)
4859
self.disarm_vehicle()
4860
4861
def send_guided_mission_item(self, loc, target_system=1, target_component=1):
4862
self.mav.mav.mission_item_send(
4863
target_system,
4864
target_component,
4865
0,
4866
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
4867
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
4868
2, # current
4869
0, # autocontinue
4870
0, # param1
4871
0, # param2
4872
0, # param3
4873
0, # param4
4874
loc.lat, # x
4875
loc.lng, # y
4876
0 # z
4877
)
4878
4879
def test_poly_fence_object_avoidance_guided_pathfinding(self, target_system=1, target_component=1):
4880
self.load_fence("rover-path-planning-fence.txt")
4881
self.set_parameters({
4882
"AVOID_ENABLE": 3,
4883
"OA_TYPE": 2,
4884
"FENCE_MARGIN": 0, # FIXME: https://github.com/ArduPilot/ardupilot/issues/11601
4885
})
4886
self.reboot_sitl()
4887
self.change_mode('GUIDED')
4888
self.wait_ready_to_arm()
4889
self.arm_vehicle()
4890
self.set_parameter("FENCE_ENABLE", 1)
4891
target_loc = mavutil.location(40.073800, -105.229172)
4892
self.send_guided_mission_item(target_loc,
4893
target_system=target_system,
4894
target_component=target_component)
4895
self.wait_location(target_loc, timeout=300)
4896
self.do_RTL(timeout=300)
4897
self.disarm_vehicle()
4898
4899
def WheelEncoders(self):
4900
'''make sure wheel encoders are generally working'''
4901
self.set_parameters({
4902
"WENC_TYPE": 10,
4903
"EK3_ENABLE": 1,
4904
"AHRS_EKF_TYPE": 3,
4905
})
4906
self.reboot_sitl()
4907
self.change_mode("LOITER")
4908
self.wait_ready_to_arm()
4909
self.change_mode("MANUAL")
4910
self.arm_vehicle()
4911
self.set_rc(3, 1600)
4912
4913
m = self.assert_receive_message('WHEEL_DISTANCE', timeout=5)
4914
4915
tstart = self.get_sim_time()
4916
while True:
4917
if self.get_sim_time_cached() - tstart > 10:
4918
break
4919
dist_home = self.distance_to_home(use_cached_home=True)
4920
m = self.mav.messages.get("WHEEL_DISTANCE")
4921
delta = abs(m.distance[0] - dist_home)
4922
self.progress("dist-home=%f wheel-distance=%f delta=%f" %
4923
(dist_home, m.distance[0], delta))
4924
if delta > 5:
4925
raise NotAchievedException("wheel distance incorrect")
4926
self.disarm_vehicle()
4927
4928
def test_poly_fence_object_avoidance_guided_two_squares(self, target_system=1, target_component=1):
4929
self.start_subtest("Ensure we can steer around obstacles in guided mode")
4930
here = self.mav.location()
4931
self.upload_fences_from_locations([
4932
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4933
# east
4934
self.offset_location_ne(here, -50, 20), # bl
4935
self.offset_location_ne(here, 50, 10), # tl
4936
self.offset_location_ne(here, 50, 30), # tr
4937
self.offset_location_ne(here, -50, 40), # br,
4938
]),
4939
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4940
# further east (and south
4941
self.offset_location_ne(here, -60, 60), # bl
4942
self.offset_location_ne(here, 40, 70), # tl
4943
self.offset_location_ne(here, 40, 90), # tr
4944
self.offset_location_ne(here, -60, 80), # br,
4945
]),
4946
])
4947
if self.mavproxy is not None:
4948
self.mavproxy.send("fence list\n")
4949
self.context_push()
4950
ex = None
4951
try:
4952
self.set_parameters({
4953
"AVOID_ENABLE": 3,
4954
"OA_TYPE": 2,
4955
})
4956
self.reboot_sitl()
4957
self.change_mode('GUIDED')
4958
self.wait_ready_to_arm()
4959
self.set_parameter("FENCE_ENABLE", 1)
4960
if self.mavproxy is not None:
4961
self.mavproxy.send("fence list\n")
4962
self.arm_vehicle()
4963
4964
self.change_mode("GUIDED")
4965
target = mavutil.location(40.071382, -105.228340, 0, 0)
4966
self.send_guided_mission_item(target,
4967
target_system=target_system,
4968
target_component=target_component)
4969
self.wait_location(target, timeout=300)
4970
self.do_RTL()
4971
self.disarm_vehicle()
4972
except Exception as e:
4973
self.print_exception_caught(e)
4974
ex = e
4975
self.context_pop()
4976
self.reboot_sitl()
4977
if ex is not None:
4978
raise ex
4979
4980
def test_poly_fence_avoidance_dont_breach_exclusion(self, target_system=1, target_component=1):
4981
self.start_subtest("Ensure we stop before breaching an exclusion fence")
4982
here = self.mav.location()
4983
self.upload_fences_from_locations([
4984
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4985
# east
4986
self.offset_location_ne(here, -50, 20), # bl
4987
self.offset_location_ne(here, 50, 20), # br
4988
self.offset_location_ne(here, 50, 40), # tr
4989
self.offset_location_ne(here, -50, 40), # tl,
4990
]),
4991
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
4992
# west
4993
self.offset_location_ne(here, -50, -20), # tl
4994
self.offset_location_ne(here, 50, -20), # tr
4995
self.offset_location_ne(here, 50, -40), # br
4996
self.offset_location_ne(here, -50, -40), # bl,
4997
]),
4998
(mavutil.mavlink.MAV_CMD_NAV_FENCE_CIRCLE_INCLUSION, {
4999
"radius": 30,
5000
"loc": self.offset_location_ne(here, -60, 0),
5001
}),
5002
])
5003
if self.mavproxy is not None:
5004
self.mavproxy.send("fence list\n")
5005
self.set_parameters({
5006
"FENCE_ENABLE": 1,
5007
"AVOID_ENABLE": 3,
5008
})
5009
fence_middle = self.offset_location_ne(here, 0, 30)
5010
# FIXME: this might be nowhere near "here"!
5011
expected_stopping_point = mavutil.location(40.0713376, -105.2295738, 0, 0)
5012
self.drive_somewhere_stop_at_boundary(
5013
fence_middle,
5014
expected_stopping_point,
5015
target_system=target_system,
5016
target_component=target_component,
5017
expected_distance_epsilon=3)
5018
self.set_parameter("AVOID_ENABLE", 0)
5019
self.do_RTL()
5020
5021
def do_RTL(self, distance_min=3, distance_max=7, timeout=60):
5022
self.change_mode("RTL")
5023
self.wait_distance_to_home(distance_min, distance_max, timeout=timeout)
5024
5025
def PolyFenceAvoidance(self, target_system=1, target_component=1):
5026
'''PolyFence avoidance tests'''
5027
self.change_mode("LOITER")
5028
self.wait_ready_to_arm()
5029
self.arm_vehicle()
5030
self.change_mode("MANUAL")
5031
self.reach_heading_manual(180, turn_right=False)
5032
self.change_mode("GUIDED")
5033
5034
self.test_poly_fence_avoidance_dont_breach_exclusion(target_system=target_system, target_component=target_component)
5035
5036
self.disarm_vehicle()
5037
5038
def PolyFenceObjectAvoidanceBendyRuler(self, target_system=1, target_component=1):
5039
'''PolyFence object avoidance tests - bendy ruler'''
5040
self.load_fence_using_mavwp("rover-path-bendyruler-fence.txt")
5041
self.set_parameters({
5042
"AVOID_ENABLE": 3,
5043
"OA_TYPE": 1,
5044
"FENCE_ENABLE": 1,
5045
"WP_RADIUS": 5,
5046
})
5047
self.reboot_sitl()
5048
self.set_parameters({
5049
"OA_BR_LOOKAHEAD": 50,
5050
})
5051
self.change_mode('GUIDED')
5052
self.wait_ready_to_arm()
5053
self.arm_vehicle()
5054
target_loc = mavutil.location(40.071060, -105.227734, 1584, 0)
5055
self.send_guided_mission_item(target_loc,
5056
target_system=target_system,
5057
target_component=target_component)
5058
# FIXME: we don't get within WP_RADIUS of our target?!
5059
self.wait_location(target_loc, timeout=300, accuracy=15)
5060
self.do_RTL(timeout=300)
5061
self.disarm_vehicle()
5062
5063
def PolyFenceObjectAvoidanceBendyRulerEasierGuided(self, target_system=1, target_component=1):
5064
'''finish-line issue means we can't complete the harder one. This
5065
test can go away once we've nailed that one. The only
5066
difference here is the target point.
5067
'''
5068
self.load_fence_using_mavwp("rover-path-bendyruler-fence.txt")
5069
self.set_parameters({
5070
"AVOID_ENABLE": 3,
5071
"OA_TYPE": 1,
5072
"FENCE_ENABLE": 1,
5073
"WP_RADIUS": 5,
5074
})
5075
self.reboot_sitl()
5076
self.set_parameters({
5077
"OA_BR_LOOKAHEAD": 60,
5078
})
5079
self.change_mode('GUIDED')
5080
self.wait_ready_to_arm()
5081
self.arm_vehicle()
5082
target_loc = mavutil.location(40.071260, -105.227000, 1584, 0)
5083
self.send_guided_mission_item(target_loc,
5084
target_system=target_system,
5085
target_component=target_component)
5086
# FIXME: we don't get within WP_RADIUS of our target?!
5087
self.wait_location(target_loc, timeout=300, accuracy=15)
5088
self.do_RTL(timeout=300)
5089
self.disarm_vehicle()
5090
5091
def PolyFenceObjectAvoidanceBendyRulerEasierAuto(self, target_system=1, target_component=1):
5092
'''finish-line issue means we can't complete the harder one. This
5093
test can go away once we've nailed that one. The only
5094
difference here is the target point.
5095
'''
5096
self.load_fence_using_mavwp("rover-path-bendyruler-fence.txt")
5097
self.load_mission("rover-path-bendyruler-mission-easier.txt")
5098
5099
self.set_parameters({
5100
"AVOID_ENABLE": 3,
5101
"OA_TYPE": 1, # BendyRuler
5102
"FENCE_ENABLE": 1,
5103
"WP_RADIUS": 5,
5104
})
5105
self.reboot_sitl()
5106
self.set_parameters({
5107
"OA_BR_LOOKAHEAD": 60,
5108
})
5109
self.change_mode('AUTO')
5110
self.wait_ready_to_arm()
5111
self.arm_vehicle()
5112
target_loc = mavutil.location(40.071260, -105.227000, 1584, 0)
5113
# target_loc is copied from the mission file
5114
self.wait_location(target_loc, timeout=300)
5115
# mission has RTL as last item
5116
self.wait_distance_to_home(3, 7, timeout=300)
5117
self.disarm_vehicle()
5118
5119
def test_scripting_simple_loop(self):
5120
self.start_subtest("Scripting simple loop")
5121
5122
self.context_push()
5123
5124
messages = []
5125
5126
def my_message_hook(mav, message):
5127
if message.get_type() != 'STATUSTEXT':
5128
return
5129
messages.append(message)
5130
5131
self.install_message_hook_context(my_message_hook)
5132
5133
self.set_parameter("SCR_ENABLE", 1)
5134
self.install_example_script_context("simple_loop.lua")
5135
self.reboot_sitl()
5136
self.delay_sim_time(10)
5137
5138
self.context_pop()
5139
self.reboot_sitl()
5140
5141
# check all messages to see if we got our message
5142
count = 0
5143
for m in messages:
5144
if "hello, world" in m.text:
5145
count += 1
5146
self.progress("Got %u hellos" % count)
5147
if count < 3:
5148
raise NotAchievedException("Expected at least three hellos")
5149
5150
def test_scripting_internal_test(self):
5151
self.start_subtest("Scripting internal test")
5152
5153
self.context_push()
5154
5155
self.set_parameters({
5156
"SCR_ENABLE": 1,
5157
"SCR_HEAP_SIZE": 1024000,
5158
"SCR_VM_I_COUNT": 1000000,
5159
})
5160
self.install_test_modules_context()
5161
self.install_mavlink_module_context()
5162
5163
self.install_test_scripts_context([
5164
"scripting_test.lua",
5165
"scripting_require_test_2.lua",
5166
"math.lua",
5167
"strings.lua",
5168
"mavlink_test.lua",
5169
])
5170
5171
self.context_collect('STATUSTEXT')
5172
self.context_collect('NAMED_VALUE_FLOAT')
5173
5174
self.reboot_sitl()
5175
5176
for success_text in [
5177
"Internal tests passed",
5178
"Require test 2 passed",
5179
"Math tests passed",
5180
"String tests passed",
5181
"Received heartbeat from"
5182
]:
5183
self.wait_statustext(success_text, check_context=True)
5184
5185
for success_nvf in [
5186
"test",
5187
]:
5188
self.assert_received_message_field_values("NAMED_VALUE_FLOAT", {
5189
"name": success_nvf,
5190
}, check_context=True)
5191
5192
self.context_pop()
5193
self.reboot_sitl()
5194
5195
def test_scripting_hello_world(self):
5196
self.start_subtest("Scripting hello world")
5197
5198
self.context_push()
5199
self.context_collect("STATUSTEXT")
5200
self.set_parameter("SCR_ENABLE", 1)
5201
self.install_example_script_context("hello_world.lua")
5202
self.reboot_sitl()
5203
5204
self.wait_statustext('hello, world', check_context=True, timeout=30)
5205
5206
self.context_pop()
5207
self.reboot_sitl()
5208
5209
def ScriptingSteeringAndThrottle(self):
5210
'''Scripting test - steering and throttle'''
5211
self.start_subtest("Scripting square")
5212
5213
self.context_push()
5214
self.install_example_script_context("rover-set-steering-and-throttle.lua")
5215
self.set_parameter("SCR_ENABLE", 1)
5216
self.reboot_sitl()
5217
5218
self.wait_ready_to_arm()
5219
self.arm_vehicle()
5220
self.set_rc(6, 2000)
5221
tstart = self.get_sim_time()
5222
while not self.mode_is("HOLD"):
5223
if self.get_sim_time_cached() - tstart > 30:
5224
raise NotAchievedException("Did not move to hold")
5225
m = self.assert_receive_message('VFR_HUD')
5226
if m is not None:
5227
self.progress("Current speed: %f" % m.groundspeed)
5228
self.disarm_vehicle()
5229
5230
self.context_pop()
5231
self.reboot_sitl()
5232
5233
def test_scripting_auxfunc(self):
5234
self.start_subtest("Scripting aufunc triggering")
5235
5236
self.context_push()
5237
self.context_collect("STATUSTEXT")
5238
self.set_parameters({
5239
"SCR_ENABLE": 1,
5240
"RELAY1_FUNCTION": 1,
5241
"RELAY1_PIN": 1
5242
})
5243
self.install_example_script_context("RCIN_test.lua")
5244
self.reboot_sitl()
5245
5246
self.wait_parameter_value("SIM_PIN_MASK", 121)
5247
self.wait_parameter_value("SIM_PIN_MASK", 123)
5248
self.wait_parameter_value("SIM_PIN_MASK", 121)
5249
5250
self.context_pop()
5251
self.reboot_sitl()
5252
5253
def test_scripting_print_home_and_origin(self):
5254
self.start_subtest("Scripting print home and origin")
5255
5256
self.context_push()
5257
5258
self.set_parameter("SCR_ENABLE", 1)
5259
self.install_example_script_context("ahrs-print-home-and-origin.lua")
5260
self.reboot_sitl()
5261
self.wait_ready_to_arm()
5262
self.wait_statustext("Home - ")
5263
self.wait_statustext("Origin - ")
5264
5265
self.context_pop()
5266
self.reboot_sitl()
5267
5268
def test_scripting_set_home_to_vehicle_location(self):
5269
self.start_subtest("Scripting set home to vehicle location")
5270
5271
self.context_push()
5272
self.set_parameter("SCR_ENABLE", 1)
5273
self.install_example_script_context("ahrs-set-home-to-vehicle-location.lua")
5274
self.reboot_sitl()
5275
5276
self.wait_statustext("Home position reset")
5277
5278
self.context_pop()
5279
self.reboot_sitl()
5280
5281
def test_scripting_serial_loopback(self):
5282
self.start_subtest("Scripting serial loopback test")
5283
5284
self.context_push()
5285
self.context_collect('STATUSTEXT')
5286
self.set_parameters({
5287
"SCR_ENABLE": 1,
5288
"SCR_SDEV_EN": 1,
5289
"SCR_SDEV1_PROTO": 28,
5290
})
5291
self.install_test_script_context("serial_loopback.lua")
5292
self.reboot_sitl()
5293
5294
for success_text in [
5295
"driver -> device good",
5296
"device -> driver good",
5297
]:
5298
self.wait_statustext(success_text, check_context=True)
5299
5300
self.context_pop()
5301
self.reboot_sitl()
5302
5303
def Scripting(self):
5304
'''Scripting test'''
5305
self.test_scripting_set_home_to_vehicle_location()
5306
self.test_scripting_print_home_and_origin()
5307
self.test_scripting_hello_world()
5308
self.test_scripting_simple_loop()
5309
self.test_scripting_internal_test()
5310
self.test_scripting_auxfunc()
5311
self.test_scripting_serial_loopback()
5312
5313
def test_mission_frame(self, frame, target_system=1, target_component=1):
5314
self.clear_mission(mavutil.mavlink.MAV_MISSION_TYPE_MISSION,
5315
target_system=target_system,
5316
target_component=target_component)
5317
items = [
5318
# first item is ignored for missions
5319
self.mav.mav.mission_item_int_encode(
5320
target_system,
5321
target_component,
5322
0, # seq
5323
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
5324
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
5325
0, # current
5326
0, # autocontinue
5327
3, # p1
5328
0, # p2
5329
0, # p3
5330
0, # p4
5331
int(1.0000 * 1e7), # latitude
5332
int(1.0000 * 1e7), # longitude
5333
31.0000, # altitude
5334
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
5335
self.mav.mav.mission_item_int_encode(
5336
target_system,
5337
target_component,
5338
1, # seq
5339
frame,
5340
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
5341
0, # current
5342
0, # autocontinue
5343
3, # p1
5344
0, # p2
5345
0, # p3
5346
0, # p4
5347
int(1.0000 * 1e7), # latitude
5348
int(1.0000 * 1e7), # longitude
5349
31.0000, # altitude
5350
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
5351
]
5352
5353
self.check_mission_upload_download(items)
5354
5355
def MissionFrames(self, target_system=1, target_component=1):
5356
'''Upload/Download of items in different frames'''
5357
for frame in (mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT_INT,
5358
mavutil.mavlink.MAV_FRAME_GLOBAL_TERRAIN_ALT,
5359
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT,
5360
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT,
5361
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
5362
mavutil.mavlink.MAV_FRAME_GLOBAL):
5363
self.test_mission_frame(frame,
5364
target_system=1,
5365
target_component=1)
5366
5367
def mavlink_time_boot_ms(self):
5368
'''returns a time suitable for putting into the time_boot_ms entry in mavlink packets'''
5369
return int(time.time() * 1000000)
5370
5371
def mavlink_time_boot_us(self):
5372
'''returns a time suitable for putting into the time_boot_ms entry in mavlink packets'''
5373
return int(time.time() * 1000000000)
5374
5375
def ap_proximity_mav_obstacle_distance_send(self, data):
5376
increment = data.get("increment", 0)
5377
increment_f = data.get("increment_f", 0.0)
5378
max_distance = data["max_distance"]
5379
invalid_distance = max_distance + 1 # per spec
5380
distances = data["distances"][:]
5381
distances.extend([invalid_distance] * (72-len(distances)))
5382
self.mav.mav.obstacle_distance_send(
5383
self.mavlink_time_boot_us(),
5384
mavutil.mavlink.MAV_DISTANCE_SENSOR_LASER,
5385
distances,
5386
increment,
5387
data["min_distance"],
5388
data["max_distance"],
5389
increment_f,
5390
data["angle_offset"],
5391
mavutil.mavlink.MAV_FRAME_BODY_FRD
5392
)
5393
5394
def send_obstacle_distances_expect_distance_sensor_messages(self, obstacle_distances_in, expect_distance_sensor_messages):
5395
self.delay_sim_time(11) # allow obstacles to time out
5396
self.do_timesync_roundtrip()
5397
expect_distance_sensor_messages_copy = expect_distance_sensor_messages[:]
5398
last_sent = 0
5399
while True:
5400
now = self.get_sim_time_cached()
5401
if now - last_sent > 1:
5402
self.progress("Sending")
5403
self.ap_proximity_mav_obstacle_distance_send(obstacle_distances_in)
5404
last_sent = now
5405
m = self.mav.recv_match(type='DISTANCE_SENSOR', blocking=True, timeout=1)
5406
self.progress("Got (%s)" % str(m))
5407
if m is None:
5408
self.delay_sim_time(1)
5409
continue
5410
orientation = m.orientation
5411
found = False
5412
if m.current_distance == m.max_distance:
5413
# ignored
5414
continue
5415
for expected_distance_sensor_message in expect_distance_sensor_messages_copy:
5416
if expected_distance_sensor_message["orientation"] != orientation:
5417
continue
5418
found = True
5419
if not expected_distance_sensor_message.get("__found__", False):
5420
self.progress("Marking message as found")
5421
expected_distance_sensor_message["__found__"] = True
5422
if (m.current_distance - expected_distance_sensor_message["distance"] > 1):
5423
raise NotAchievedException(
5424
"Bad distance for orient=%u want=%u got=%u" %
5425
(orientation, expected_distance_sensor_message["distance"], m.current_distance))
5426
break
5427
if not found:
5428
raise NotAchievedException("Got unexpected DISTANCE_SENSOR message")
5429
all_found = True
5430
for expected_distance_sensor_message in expect_distance_sensor_messages_copy:
5431
if not expected_distance_sensor_message.get("__found__", False):
5432
self.progress("message still not found (orient=%u" % expected_distance_sensor_message["orientation"])
5433
all_found = False
5434
break
5435
if all_found:
5436
self.progress("Have now seen all expected messages")
5437
break
5438
5439
def AP_Proximity_MAV(self):
5440
'''Test MAV proximity backend'''
5441
5442
self.set_parameters({
5443
"PRX1_TYPE": 2, # AP_Proximity_MAV
5444
"OA_TYPE": 2, # dijkstra
5445
"OA_DB_OUTPUT": 3, # send all items
5446
})
5447
self.reboot_sitl()
5448
5449
# 1 laser pointing straight forward:
5450
self.send_obstacle_distances_expect_distance_sensor_messages(
5451
{
5452
"distances": [234],
5453
"increment_f": 10,
5454
"angle_offset": 0.0,
5455
"min_distance": 0,
5456
"max_distance": 1000, # cm
5457
}, [
5458
{"orientation": 0, "distance": 234},
5459
])
5460
5461
# 5 lasers at front of vehicle, spread over 40 degrees:
5462
self.send_obstacle_distances_expect_distance_sensor_messages(
5463
{
5464
"distances": [111, 222, 333, 444, 555],
5465
"increment_f": 10,
5466
"angle_offset": -20.0,
5467
"min_distance": 0,
5468
"max_distance": 1000, # cm
5469
}, [
5470
{"orientation": 0, "distance": 111},
5471
])
5472
5473
# lots of dense readings (e.g. vision camera:
5474
distances = [0] * 72
5475
for i in range(0, 72):
5476
distances[i] = 1000 + 10*abs(36-i)
5477
5478
self.send_obstacle_distances_expect_distance_sensor_messages(
5479
{
5480
"distances": distances,
5481
"increment_f": 90/72.0,
5482
"angle_offset": -45.0,
5483
"min_distance": 0,
5484
"max_distance": 2000, # cm
5485
}, [
5486
{"orientation": 0, "distance": 1000},
5487
{"orientation": 1, "distance": 1190},
5488
{"orientation": 7, "distance": 1190},
5489
])
5490
5491
def SendToComponents(self):
5492
'''Test ArduPilot send_to_components function'''
5493
self.set_parameter("CAM1_TYPE", 5) # Camera with MAVlink trigger
5494
self.reboot_sitl() # needed for CAM1_TYPE to take effect
5495
self.progress("Introducing ourselves to the autopilot as a component")
5496
old_srcSystem = self.mav.mav.srcSystem
5497
self.mav.mav.srcSystem = 1
5498
self.mav.mav.heartbeat_send(
5499
mavutil.mavlink.MAV_TYPE_ONBOARD_CONTROLLER,
5500
mavutil.mavlink.MAV_AUTOPILOT_INVALID,
5501
0,
5502
0,
5503
0)
5504
5505
self.progress("Sending control message")
5506
self.context_push()
5507
self.context_collect('COMMAND_LONG')
5508
self.mav.mav.digicam_control_send(
5509
1, # target_system
5510
1, # target_component
5511
1, # start or keep it up
5512
1, # zoom_pos
5513
0, # zoom_step
5514
0, # focus_lock
5515
0, # 1 shot or start filming
5516
17, # command id (de-dupe field)
5517
0, # extra_param
5518
0.0, # extra_value
5519
)
5520
self.mav.mav.srcSystem = old_srcSystem
5521
5522
self.assert_received_message_field_values('COMMAND_LONG', {
5523
'command': mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONTROL,
5524
'param6': 17,
5525
}, timeout=2, check_context=True)
5526
self.context_pop()
5527
5528
# test sending via commands:
5529
for run_cmd in self.run_cmd, self.run_cmd_int:
5530
self.progress("Sending control command")
5531
self.context_push()
5532
self.context_collect('COMMAND_LONG')
5533
run_cmd(mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONTROL,
5534
p1=1, # start or keep it up
5535
p2=1, # zoom_pos
5536
p3=0, # zoom_step
5537
p4=0, # focus_lock
5538
p5=0, # 1 shot or start filming
5539
p6=37, # command id (de-dupe field)
5540
)
5541
5542
self.assert_received_message_field_values('COMMAND_LONG', {
5543
'command': mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONTROL,
5544
'param6': 37,
5545
}, timeout=2, check_context=True)
5546
5547
self.context_pop()
5548
5549
# test sending via commands:
5550
for run_cmd in self.run_cmd, self.run_cmd_int:
5551
self.progress("Sending configure command")
5552
self.context_push()
5553
self.context_collect('COMMAND_LONG')
5554
run_cmd(mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONFIGURE,
5555
p1=1,
5556
p2=1,
5557
p3=0,
5558
p4=0,
5559
p5=12,
5560
p6=37
5561
)
5562
5563
self.assert_received_message_field_values('COMMAND_LONG', {
5564
'command': mavutil.mavlink.MAV_CMD_DO_DIGICAM_CONFIGURE,
5565
'param5': 12,
5566
'param6': 37,
5567
}, timeout=2, check_context=True)
5568
5569
self.context_pop()
5570
5571
self.mav.mav.srcSystem = old_srcSystem
5572
5573
def SkidSteer(self):
5574
'''Check skid-steering'''
5575
model = "rover-skid"
5576
5577
self.customise_SITL_commandline([],
5578
model=model,
5579
defaults_filepath=self.model_defaults_filepath(model))
5580
5581
self.change_mode("MANUAL")
5582
self.wait_ready_to_arm()
5583
self.arm_vehicle()
5584
self.progress("get a known heading to avoid worrying about wrap")
5585
# this is steering-type-two-paddles
5586
self.set_rc(1, 1400)
5587
self.set_rc(3, 1500)
5588
self.wait_heading(90)
5589
self.progress("straighten up")
5590
self.set_rc(1, 1500)
5591
self.set_rc(3, 1500)
5592
self.progress("steer one way")
5593
self.set_rc(1, 1600)
5594
self.set_rc(3, 1400)
5595
self.wait_heading(120)
5596
self.progress("steer the other")
5597
self.set_rc(1, 1400)
5598
self.set_rc(3, 1600)
5599
self.wait_heading(60)
5600
self.zero_throttle()
5601
self.disarm_vehicle()
5602
5603
def SlewRate(self):
5604
"""Test Motor Slew Rate feature."""
5605
self.context_push()
5606
self.change_mode("MANUAL")
5607
self.wait_ready_to_arm()
5608
self.arm_vehicle()
5609
5610
self.start_subtest("Test no slew behavior")
5611
throttle_channel = 3
5612
throttle_max = 2000
5613
self.set_parameter("MOT_SLEWRATE", 0)
5614
self.set_rc(throttle_channel, throttle_max)
5615
tstart = self.get_sim_time()
5616
self.wait_servo_channel_value(throttle_channel, throttle_max)
5617
tstop = self.get_sim_time()
5618
achieved_time = tstop - tstart
5619
self.progress("achieved_time: %0.1fs" % achieved_time)
5620
if achieved_time > 0.5:
5621
raise NotAchievedException("Output response should be instant, got %f" % achieved_time)
5622
self.zero_throttle()
5623
self.wait_groundspeed(0, 0.5) # why do we not stop?!
5624
5625
self.start_subtest("Test 100% slew rate")
5626
self.set_parameter("MOT_SLEWRATE", 100)
5627
self.set_rc(throttle_channel, throttle_max)
5628
tstart = self.get_sim_time()
5629
self.wait_servo_channel_value(throttle_channel, throttle_max)
5630
tstop = self.get_sim_time()
5631
achieved_time = tstop - tstart
5632
self.progress("achieved_time: %0.1fs" % achieved_time)
5633
if achieved_time < 0.9 or achieved_time > 1.1:
5634
raise NotAchievedException("Output response should be 1s, got %f" % achieved_time)
5635
self.zero_throttle()
5636
self.wait_groundspeed(0, 0.5) # why do we not stop?!
5637
5638
self.start_subtest("Test 50% slew rate")
5639
self.set_parameter("MOT_SLEWRATE", 50)
5640
self.set_rc(throttle_channel, throttle_max)
5641
tstart = self.get_sim_time()
5642
self.wait_servo_channel_value(throttle_channel, throttle_max, timeout=10)
5643
tstop = self.get_sim_time()
5644
achieved_time = tstop - tstart
5645
self.progress("achieved_time: %0.1fs" % achieved_time)
5646
if achieved_time < 1.8 or achieved_time > 2.2:
5647
raise NotAchievedException("Output response should be 2s, got %f" % achieved_time)
5648
self.zero_throttle()
5649
self.wait_groundspeed(0, 0.5) # why do we not stop?!
5650
5651
self.start_subtest("Test 25% slew rate")
5652
self.set_parameter("MOT_SLEWRATE", 25)
5653
self.set_rc(throttle_channel, throttle_max)
5654
tstart = self.get_sim_time()
5655
self.wait_servo_channel_value(throttle_channel, throttle_max, timeout=10)
5656
tstop = self.get_sim_time()
5657
achieved_time = tstop - tstart
5658
self.progress("achieved_time: %0.1fs" % achieved_time)
5659
if achieved_time < 3.6 or achieved_time > 4.4:
5660
raise NotAchievedException("Output response should be 4s, got %f" % achieved_time)
5661
self.zero_throttle()
5662
self.wait_groundspeed(0, 0.5) # why do we not stop?!
5663
5664
self.start_subtest("Test 10% slew rate")
5665
self.set_parameter("MOT_SLEWRATE", 10)
5666
self.set_rc(throttle_channel, throttle_max)
5667
tstart = self.get_sim_time()
5668
self.wait_servo_channel_value(throttle_channel, throttle_max, timeout=20)
5669
tstop = self.get_sim_time()
5670
achieved_time = tstop - tstart
5671
self.progress("achieved_time: %0.1fs" % achieved_time)
5672
if achieved_time < 9 or achieved_time > 11:
5673
raise NotAchievedException("Output response should be 10s, got %f" % achieved_time)
5674
self.zero_throttle()
5675
self.wait_groundspeed(0, 0.5) # why do we not stop?!
5676
self.disarm_vehicle()
5677
self.context_pop()
5678
5679
def SET_ATTITUDE_TARGET(self, target_sysid=None, target_compid=1):
5680
'''Test handling of SET_ATTITUDE_TARGET'''
5681
if target_sysid is None:
5682
target_sysid = self.sysid_thismav()
5683
self.change_mode('GUIDED')
5684
self.wait_ready_to_arm()
5685
self.arm_vehicle()
5686
tstart = self.get_sim_time()
5687
while True:
5688
now = self.get_sim_time_cached()
5689
if now - tstart > 10:
5690
raise AutoTestTimeoutException("Didn't get to speed")
5691
self.mav.mav.set_attitude_target_send(
5692
0, # time_boot_ms
5693
target_sysid,
5694
target_compid,
5695
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_ROLL_RATE_IGNORE |
5696
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_PITCH_RATE_IGNORE |
5697
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_ATTITUDE_IGNORE,
5698
mavextra.euler_to_quat([0,
5699
math.radians(0),
5700
math.radians(0)]), # att
5701
0, # yaw rate (rad/s)
5702
0, # pitch rate
5703
0, # yaw rate
5704
1) # thrust
5705
5706
msg = self.assert_receive_message('VFR_HUD')
5707
if msg.groundspeed > 5:
5708
break
5709
self.disarm_vehicle()
5710
5711
def SET_ATTITUDE_TARGET_heading(self, target_sysid=None, target_compid=1):
5712
'''Test handling of SET_ATTITUDE_TARGET'''
5713
self.change_mode('GUIDED')
5714
self.wait_ready_to_arm()
5715
self.arm_vehicle()
5716
5717
for angle in 0, 290, 70, 180, 0:
5718
self.SET_ATTITUDE_TARGET_heading_test_target(angle, target_sysid, target_compid)
5719
self.disarm_vehicle()
5720
5721
def SET_ATTITUDE_TARGET_heading_test_target(self, angle, target_sysid, target_compid):
5722
if target_sysid is None:
5723
target_sysid = self.sysid_thismav()
5724
5725
def poke_set_attitude(value, target):
5726
self.mav.mav.set_attitude_target_send(
5727
0, # time_boot_ms
5728
target_sysid,
5729
target_compid,
5730
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_ROLL_RATE_IGNORE |
5731
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_PITCH_RATE_IGNORE |
5732
mavutil.mavlink.ATTITUDE_TARGET_TYPEMASK_BODY_YAW_RATE_IGNORE,
5733
mavextra.euler_to_quat([
5734
math.radians(0),
5735
math.radians(0),
5736
math.radians(angle)
5737
]), # att
5738
0, # roll rate (rad/s)
5739
0, # pitch rate
5740
0, # yaw rate
5741
1) # thrust
5742
5743
self.wait_heading(angle, called_function=poke_set_attitude, minimum_duration=5)
5744
5745
def SET_POSITION_TARGET_LOCAL_NED(self, target_sysid=None, target_compid=1):
5746
'''Test handling of SET_POSITION_TARGET_LOCAL_NED'''
5747
if target_sysid is None:
5748
target_sysid = self.sysid_thismav()
5749
self.change_mode('GUIDED')
5750
self.wait_ready_to_arm()
5751
self.arm_vehicle()
5752
ofs_x = 30.0
5753
ofs_y = 30.0
5754
5755
def send_target():
5756
self.mav.mav.set_position_target_local_ned_send(
5757
0, # time_boot_ms
5758
target_sysid,
5759
target_compid,
5760
mavutil.mavlink.MAV_FRAME_LOCAL_NED,
5761
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VX_IGNORE |
5762
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VY_IGNORE |
5763
mavutil.mavlink.POSITION_TARGET_TYPEMASK_VZ_IGNORE |
5764
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AX_IGNORE |
5765
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AY_IGNORE |
5766
mavutil.mavlink.POSITION_TARGET_TYPEMASK_AZ_IGNORE |
5767
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_IGNORE |
5768
mavutil.mavlink.POSITION_TARGET_TYPEMASK_YAW_RATE_IGNORE,
5769
ofs_x, # pos-x
5770
ofs_y, # pos-y
5771
0, # pos-z
5772
0, # vel-x
5773
0, # vel-y
5774
0, # vel-z
5775
0, # acc-x
5776
0, # acc-y
5777
0, # acc-z
5778
0, # yaw
5779
0, # yaw rate
5780
)
5781
5782
self.wait_distance_to_local_position(
5783
(ofs_x, ofs_y, 0),
5784
distance_min=0,
5785
distance_max=3,
5786
timeout=60,
5787
called_function=lambda last_value, target : send_target(),
5788
minimum_duration=5, # make sure we stop!
5789
)
5790
5791
self.do_RTL()
5792
self.disarm_vehicle()
5793
5794
def EndMissionBehavior(self, timeout=60):
5795
'''Test end mission behavior'''
5796
self.context_push()
5797
5798
self.load_mission("end-mission.txt")
5799
self.wait_ready_to_arm()
5800
self.arm_vehicle()
5801
5802
self.start_subtest("Test End Mission Behavior HOLD")
5803
self.context_collect("STATUSTEXT")
5804
self.change_mode("AUTO")
5805
self.wait_text("Mission Complete", check_context=True, wallclock_timeout=2)
5806
# On Hold we should just stop and don't update the navigation target anymore
5807
tstart = self.get_sim_time()
5808
while True:
5809
if self.get_sim_time_cached() - tstart > 15:
5810
raise AutoTestTimeoutException("Still getting POSITION_TARGET_GLOBAL_INT")
5811
m = self.mav.recv_match(type="POSITION_TARGET_GLOBAL_INT",
5812
blocking=True,
5813
timeout=10)
5814
if m is None:
5815
self.progress("No POSITION_TARGET_GLOBAL_INT received, all good !")
5816
break
5817
self.context_clear_collection("STATUSTEXT")
5818
self.change_mode("GUIDED")
5819
self.context_collect("STATUSTEXT")
5820
5821
self.start_subtest("Test End Mission Behavior LOITER")
5822
self.set_parameter("MIS_DONE_BEHAVE", 1)
5823
self.change_mode("AUTO")
5824
self.wait_text("Mission Complete", check_context=True, wallclock_timeout=2)
5825
# On LOITER we should update the navigation target
5826
tstart = self.get_sim_time()
5827
while True:
5828
if self.get_sim_time_cached() - tstart > 15:
5829
raise AutoTestTimeoutException("Not getting POSITION_TARGET_GLOBAL_INT")
5830
m = self.mav.recv_match(type="POSITION_TARGET_GLOBAL_INT",
5831
blocking=True,
5832
timeout=5)
5833
if m is None:
5834
self.progress("No POSITION_TARGET_GLOBAL_INT received")
5835
continue
5836
else:
5837
if self.get_sim_time_cached() - tstart > 15:
5838
self.progress("Got POSITION_TARGET_GLOBAL_INT, all good !")
5839
break
5840
5841
self.start_subtest("Test End Mission Behavior ACRO")
5842
self.set_parameter("MIS_DONE_BEHAVE", 2)
5843
# race conditions here to do with get_sim_time()
5844
# swallowing heartbeats means we have to be a little
5845
# circuitous when testing here:
5846
self.change_mode("GUIDED")
5847
self.send_cmd_do_set_mode('AUTO')
5848
self.wait_mode("ACRO")
5849
5850
self.start_subtest("Test End Mission Behavior MANUAL")
5851
self.set_parameter("MIS_DONE_BEHAVE", 3)
5852
# race conditions here to do with get_sim_time()
5853
# swallowing heartbeats means we have to be a little
5854
# circuitous when testing here:
5855
self.change_mode("GUIDED")
5856
self.send_cmd_do_set_mode("AUTO")
5857
self.wait_mode("MANUAL")
5858
self.disarm_vehicle()
5859
5860
self.context_pop()
5861
self.reboot_sitl()
5862
5863
def MAVProxyParam(self):
5864
'''Test MAVProxy parameter handling'''
5865
mavproxy = self.start_mavproxy()
5866
mavproxy.send("param fetch\n")
5867
mavproxy.expect("Received [0-9]+ parameters")
5868
self.stop_mavproxy(mavproxy)
5869
5870
def MAV_CMD_DO_SET_MISSION_CURRENT_mission(self, target_system=1, target_component=1):
5871
return copy.copy([
5872
self.mav.mav.mission_item_int_encode(
5873
target_system,
5874
target_component,
5875
0, # seq
5876
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
5877
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
5878
0, # current
5879
0, # autocontinue
5880
3, # p1
5881
0, # p2
5882
0, # p3
5883
0, # p4
5884
int(1.0000 * 1e7), # latitude
5885
int(1.0000 * 1e7), # longitude
5886
31.0000, # altitude
5887
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
5888
self.mav.mav.mission_item_int_encode(
5889
target_system,
5890
target_component,
5891
1, # seq
5892
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
5893
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
5894
0, # current
5895
0, # autocontinue
5896
3, # p1
5897
0, # p2
5898
0, # p3
5899
0, # p4
5900
int(1.0000 * 1e7), # latitude
5901
int(1.0000 * 1e7), # longitude
5902
31.0000, # altitude
5903
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
5904
self.mav.mav.mission_item_int_encode(
5905
target_system,
5906
target_component,
5907
2, # seq
5908
mavutil.mavlink.MAV_FRAME_GLOBAL_INT,
5909
mavutil.mavlink.MAV_CMD_NAV_WAYPOINT,
5910
0, # current
5911
0, # autocontinue
5912
3, # p1
5913
0, # p2
5914
0, # p3
5915
0, # p4
5916
int(1.0000 * 1e7), # latitude
5917
int(1.0000 * 1e7), # longitude
5918
31.0000, # altitude
5919
mavutil.mavlink.MAV_MISSION_TYPE_MISSION),
5920
])
5921
5922
def MAV_CMD_DO_SET_MISSION_CURRENT(self, target_sysid=None, target_compid=1):
5923
'''Test handling of CMD_DO_SET_MISSION_CURRENT'''
5924
if target_sysid is None:
5925
target_sysid = self.sysid_thismav()
5926
self.check_mission_upload_download(self.MAV_CMD_DO_SET_MISSION_CURRENT_mission())
5927
5928
self.set_current_waypoint(2)
5929
5930
self.set_current_waypoint_using_mav_cmd_do_set_mission_current(2)
5931
5932
self.run_cmd(
5933
mavutil.mavlink.MAV_CMD_DO_SET_MISSION_CURRENT,
5934
p1=17,
5935
timeout=1,
5936
target_sysid=target_sysid,
5937
target_compid=target_compid,
5938
want_result=mavutil.mavlink.MAV_RESULT_DENIED,
5939
)
5940
5941
def FlashStorage(self):
5942
'''Test flash storage (for parameters etc)'''
5943
self.set_parameter("LOG_BITMASK", 1)
5944
self.reboot_sitl()
5945
5946
self.customise_SITL_commandline([
5947
"--set-storage-posix-enabled", "0",
5948
"--set-storage-flash-enabled", "1",
5949
])
5950
if self.get_parameter("LOG_BITMASK") == 1:
5951
raise NotAchievedException("not using flash storage?")
5952
self.set_parameter("LOG_BITMASK", 2)
5953
self.reboot_sitl()
5954
self.assert_parameter_value("LOG_BITMASK", 2)
5955
self.set_parameter("LOG_BITMASK", 3)
5956
self.reboot_sitl()
5957
self.assert_parameter_value("LOG_BITMASK", 3)
5958
5959
self.customise_SITL_commandline([])
5960
# make sure we're back at our original value:
5961
self.assert_parameter_value("LOG_BITMASK", 1)
5962
5963
def FRAMStorage(self):
5964
'''Test FRAM storage (for parameters etc)'''
5965
self.set_parameter("LOG_BITMASK", 1)
5966
self.reboot_sitl()
5967
5968
self.customise_SITL_commandline([
5969
"--set-storage-posix-enabled", "0",
5970
"--set-storage-fram-enabled", "1",
5971
])
5972
# TODO: ensure w'ere actually taking stuff from flash storage:
5973
# if self.get_parameter("LOG_BITMASK") == 1:
5974
# raise NotAchievedException("not using flash storage?")
5975
self.set_parameter("LOG_BITMASK", 2)
5976
self.reboot_sitl()
5977
self.assert_parameter_value("LOG_BITMASK", 2)
5978
self.set_parameter("LOG_BITMASK", 3)
5979
self.reboot_sitl()
5980
self.assert_parameter_value("LOG_BITMASK", 3)
5981
5982
self.customise_SITL_commandline([])
5983
# make sure we're back at our original value:
5984
self.assert_parameter_value("LOG_BITMASK", 1)
5985
5986
def RangeFinder(self):
5987
'''Test RangeFinder'''
5988
# the following magic numbers correspond to the post locations in SITL
5989
home_string = "%s,%s,%s,%s" % (51.8752066, 14.6487840, 54.15, 231)
5990
5991
rangefinder_params = {
5992
"SIM_SONAR_ROT": 0,
5993
}
5994
rangefinder_params.update(self.analog_rangefinder_parameters())
5995
5996
self.set_parameters(rangefinder_params)
5997
self.customise_SITL_commandline([
5998
"--home", home_string,
5999
])
6000
self.wait_ready_to_arm()
6001
if self.mavproxy is not None:
6002
self.mavproxy.send('script /tmp/post-locations.scr\n')
6003
self.context_push()
6004
self.context_set_message_rate_hz('RANGEFINDER', self.sitl_streamrate())
6005
m = self.assert_receive_message('RANGEFINDER', very_verbose=True)
6006
self.context_pop()
6007
if m.voltage == 0:
6008
raise NotAchievedException("Did not get non-zero voltage")
6009
want_range = 10
6010
if abs(m.distance - want_range) > 0.5:
6011
raise NotAchievedException("Expected %fm got %fm" % (want_range, m.distance))
6012
6013
def AIS(self):
6014
'''Test AIS receiver'''
6015
self.customise_SITL_commandline([
6016
"--serial5=sim:AIS",
6017
])
6018
self.set_parameters({
6019
"SERIAL5_PROTOCOL": 40,
6020
"SERIAL5_BAUD": 38,
6021
"AIS_TYPE": 1,
6022
})
6023
self.reboot_sitl()
6024
6025
# Set SIM parameter after reboot when AIS sim is loaded
6026
self.set_parameter("SIM_AIS_COUNT", 5)
6027
6028
self.delay_sim_time(10)
6029
6030
m = self.assert_receive_message('AIS_VESSEL', timeout=60)
6031
6032
if m.MMSI == 0:
6033
raise NotAchievedException("Invalid MMSI")
6034
6035
self.progress("Received AIS vessel MMSI=%u" % m.MMSI)
6036
6037
def AISMultipleVessels(self):
6038
'''Test tracking multiple AIS vessels'''
6039
self.customise_SITL_commandline([
6040
"--serial5=sim:AIS",
6041
])
6042
self.set_parameters({
6043
"SERIAL5_PROTOCOL": 40,
6044
"SERIAL5_BAUD": 38,
6045
"AIS_TYPE": 1,
6046
})
6047
self.reboot_sitl()
6048
6049
# Test with 1 vessel
6050
self.set_parameter("SIM_AIS_COUNT", 1)
6051
m = self.assert_receive_message('AIS_VESSEL', timeout=30)
6052
if m.MMSI == 0:
6053
raise NotAchievedException("No vessel with count=1")
6054
self.progress("Received vessel with count=1")
6055
6056
# Test with 3 vessels
6057
self.set_parameter("SIM_AIS_COUNT", 3)
6058
vessels_seen = set()
6059
start_time = self.get_sim_time()
6060
while len(vessels_seen) < 3:
6061
if self.get_sim_time() - start_time > 60:
6062
raise NotAchievedException(
6063
"Only saw %d vessels, expected 3" % len(vessels_seen)
6064
)
6065
m = self.assert_receive_message('AIS_VESSEL', timeout=10)
6066
vessels_seen.add(m.MMSI)
6067
self.progress("Tracked 3 unique vessels")
6068
6069
# Test with 5 vessels
6070
self.set_parameter("SIM_AIS_COUNT", 5)
6071
vessels_seen = set()
6072
start_time = self.get_sim_time()
6073
while len(vessels_seen) < 5:
6074
if self.get_sim_time() - start_time > 90:
6075
raise NotAchievedException(
6076
"Only saw %d vessels, expected 5" % len(vessels_seen)
6077
)
6078
m = self.assert_receive_message('AIS_VESSEL', timeout=10)
6079
vessels_seen.add(m.MMSI)
6080
6081
self.progress("Successfully tracked vessels with counts 1, 3, and 5")
6082
6083
def AISDataValidation(self):
6084
'''Test AIS vessel data validity'''
6085
self.customise_SITL_commandline([
6086
"--serial5=sim:AIS",
6087
])
6088
self.set_parameters({
6089
"SERIAL5_PROTOCOL": 40,
6090
"SERIAL5_BAUD": 38,
6091
"AIS_TYPE": 1,
6092
})
6093
self.reboot_sitl()
6094
6095
self.set_parameter("SIM_AIS_COUNT", 3)
6096
6097
m = self.assert_receive_message('AIS_VESSEL', timeout=60)
6098
6099
# Validate MMSI
6100
if m.MMSI == 0:
6101
raise NotAchievedException("Invalid MMSI: must be non-zero")
6102
6103
# Validate latitude (-90 to +90 degrees)
6104
lat_deg = m.lat / 1e7
6105
if abs(lat_deg) > 90:
6106
raise NotAchievedException("Invalid latitude: %f" % lat_deg)
6107
6108
# Validate longitude (-180 to +180 degrees)
6109
lon_deg = m.lon / 1e7
6110
if abs(lon_deg) > 180:
6111
raise NotAchievedException("Invalid longitude: %f" % lon_deg)
6112
6113
# Validate heading is reasonable (allow up to 65535 for unavailable)
6114
if m.heading > 65535:
6115
raise NotAchievedException("Invalid heading: %u" % m.heading)
6116
6117
# Validate COG is reasonable (allow up to 65535 for unavailable)
6118
if m.COG > 65535:
6119
raise NotAchievedException("Invalid COG: %u" % m.COG)
6120
6121
# Validate velocity (max ~100 knots = 10000 in 0.01 knot units)
6122
if m.velocity > 10000 and m.velocity != 65535:
6123
raise NotAchievedException("Invalid velocity: %u" % m.velocity)
6124
6125
self.progress("AIS data validation passed: MMSI=%u lat=%.6f lon=%.6f" %
6126
(m.MMSI, lat_deg, lon_deg))
6127
6128
def DepthFinder(self):
6129
'''Test multiple depthfinders for boats'''
6130
# Setup rangefinders
6131
self.customise_SITL_commandline([
6132
"--serial7=sim:nmea", # NMEA Rangefinder
6133
])
6134
6135
# RANGEFINDER_INSTANCES = [0, 2, 5]
6136
self.set_parameters({
6137
"RNGFND1_TYPE" : 17, # NMEA must attach uart to SITL
6138
"RNGFND1_ORIENT" : 25, # Set to downward facing
6139
"SERIAL7_PROTOCOL" : 9, # Rangefinder on serial7
6140
"SERIAL7_BAUD" : 9600, # Rangefinder specific baudrate
6141
6142
"RNGFND3_TYPE" : 2, # MaxbotixI2C
6143
"RNGFND3_ADDR" : 112, # 0x70 address from SIM_I2C.cpp
6144
"RNGFND3_ORIENT" : 0, # Set to forward facing, thus we should not receive DPTH messages from this one
6145
6146
"RNGFND6_ADDR" : 113, # 0x71 address from SIM_I2C.cpp
6147
"RNGFND6_ORIENT" : 25, # Set to downward facing
6148
"RNGFND6_TYPE" : 2, # MaxbotixI2C
6149
})
6150
6151
self.reboot_sitl()
6152
self.wait_ready_to_arm()
6153
6154
# should not get WATER_DEPTH messages or DPTH logs when the FRAME_CLASS is not a boat
6155
self.assert_not_receive_message("WATER_DEPTH", timeout=2)
6156
6157
# Set FRAME_CLASS to start receiving WATER_DEPTH messages & logging DPTH
6158
self.set_parameters({
6159
"FRAME_CLASS": 2, # Boat
6160
})
6161
6162
# Check each rangefinder instance is in collection
6163
rangefinder = [None, None, None, None, None, None] # Be lazy FIXME only need [3]
6164
6165
def check_rangefinder(mav, m):
6166
if m.get_type() != 'WATER_DEPTH':
6167
return
6168
6169
id = m.id
6170
6171
# Should not find instance 3 as it is forward facing
6172
if id == 2:
6173
raise NotAchievedException("Depthfinder Instance %i with non-downward orientation found" % (id))
6174
6175
rangefinder[id] = True
6176
6177
if id == 0:
6178
if float(m.temperature) == 0.0:
6179
raise NotAchievedException("Depthfinder Instance %i NMEA with temperature not found" % (id))
6180
elif id == 5:
6181
if float(m.temperature) != 0.0:
6182
raise NotAchievedException("Depthfinder Instance %i should not have temperature" % (id))
6183
6184
self.wait_ready_to_arm()
6185
self.arm_vehicle()
6186
6187
self.install_message_hook_context(check_rangefinder)
6188
self.drive_mission("rover1.txt", strict=False)
6189
6190
if rangefinder[0] is None:
6191
raise NotAchievedException("Never saw Depthfinder 1")
6192
if rangefinder[2] is not None:
6193
raise NotAchievedException("Should not have found a Depthfinder 3")
6194
if rangefinder[5] is None:
6195
raise NotAchievedException("Never saw Depthfinder 6")
6196
if not self.current_onboard_log_contains_message("DPTH"):
6197
raise NotAchievedException("Expected DPTH log message")
6198
6199
self.progress("Ensuring we get WATER_DEPTH at 12Hz with 2 backends")
6200
self.set_message_rate_hz('WATER_DEPTH', 12)
6201
self.assert_message_rate_hz('WATER_DEPTH', 12)
6202
6203
def EStopAtBoot(self):
6204
'''Ensure EStop prevents arming when asserted at boot time'''
6205
self.context_push()
6206
self.set_parameters({
6207
"RC9_OPTION": 31,
6208
})
6209
self.set_rc(9, 2000)
6210
self.reboot_sitl()
6211
self.assert_prearm_failure(
6212
"Motors Emergency Stopped",
6213
other_prearm_failures_fatal=False)
6214
self.context_pop()
6215
self.reboot_sitl()
6216
6217
def assert_mode(self, mode):
6218
if not self.mode_is(mode):
6219
raise NotAchievedException("Mode is not %s" % str(mode))
6220
6221
def ChangeModeByNumber(self):
6222
'''ensure we can set a mode by number, handy when we don't have a
6223
pymavlink number for it yet'''
6224
for (x, want) in (0, 'MANUAL'), (1, 'ACRO'), (3, 3):
6225
self.change_mode(x)
6226
self.assert_mode(want)
6227
6228
def StickMixingAuto(self):
6229
'''Ensure Stick Mixing works in auto'''
6230
items = []
6231
self.set_parameter('STICK_MIXING', 1)
6232
# home
6233
items.append((mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 0, 0, 0),)
6234
# 1 waypoint a long way away
6235
items.append((mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 2000, 0, 0),)
6236
self.upload_simple_relhome_mission(items)
6237
if self.mavproxy is not None:
6238
# handy for getting pretty pictures
6239
self.mavproxy.send("wp list\n")
6240
self.change_mode('AUTO')
6241
self.wait_ready_to_arm()
6242
self.arm_vehicle()
6243
self.set_rc(1, 1150)
6244
self.wait_heading(45)
6245
self.wait_heading(90)
6246
self.disarm_vehicle()
6247
6248
def AutoDock(self):
6249
'''Test automatic docking of rover for multiple FOVs of simulated beacon'''
6250
self.set_parameters({
6251
"PLND_ENABLED": 1,
6252
"PLND_TYPE": 4,
6253
"PLND_ORIENT": 0,
6254
})
6255
6256
start = self.mav.location()
6257
target = self.offset_location_ne(start, 50, 0)
6258
self.progress("Setting target to %f %f" % (start.lat, start.lng))
6259
stopping_dist = 0.5
6260
6261
self.set_parameters({
6262
"SIM_PLD_ENABLE": 1,
6263
"SIM_PLD_LAT": target.lat,
6264
"SIM_PLD_LON": target.lng,
6265
"SIM_PLD_HEIGHT": 0,
6266
"SIM_PLD_ALT_LMT": 30,
6267
"SIM_PLD_DIST_LMT": 30,
6268
"SIM_PLD_ORIENT": 4, # emit beams towards south, vehicle's heading must be north to see it
6269
"SIM_PLD_OPTIONS": 1,
6270
"DOCK_SPEED": 2,
6271
"DOCK_STOP_DIST": stopping_dist,
6272
})
6273
6274
for type in range(0, 3): # CYLINDRICAL FOV, CONICAL FOV, SPHERICAL FOV
6275
self.set_parameter("SIM_PLD_TYPE", type)
6276
self.reboot_sitl()
6277
self.change_mode('GUIDED')
6278
self.wait_ready_to_arm()
6279
self.arm_vehicle()
6280
initial_position = self.offset_location_ne(target, -20, -2)
6281
self.drive_to_location(initial_position)
6282
self.change_mode(8) # DOCK mode
6283
max_delta = 1
6284
self.wait_distance_to_location(target, 0, max_delta, timeout=180)
6285
self.disarm_vehicle()
6286
self.assert_receive_message('GLOBAL_POSITION_INT')
6287
new_pos = self.mav.location()
6288
delta = abs(self.get_distance(target, new_pos) - stopping_dist)
6289
self.progress("Docked %f metres from stopping point" % delta)
6290
if delta > max_delta:
6291
raise NotAchievedException("Did not dock close enough to stopping point (%fm > %fm" % (delta, max_delta))
6292
6293
if not self.current_onboard_log_contains_message("PL"):
6294
raise NotAchievedException("Did not see expected PL message")
6295
6296
self.progress("All done")
6297
6298
def PrivateChannel(self):
6299
'''test the serial option bit specifying a mavlink channel as private'''
6300
global mav2
6301
port = self.adjust_ardupilot_port(5763)
6302
mav2 = mavutil.mavlink_connection("tcp:localhost:%u" % port,
6303
robust_parsing=True,
6304
source_system=7,
6305
source_component=7)
6306
# send a heartbeat or two to make sure ArduPilot's aware:
6307
6308
def heartbeat_on_mav2(mav, m):
6309
'''send a heartbeat on mav2 whenever we get one on mav'''
6310
if mav == mav2:
6311
return
6312
if m.get_type() == 'HEARTBEAT':
6313
mav2.mav.heartbeat_send(
6314
mavutil.mavlink.MAV_TYPE_ONBOARD_CONTROLLER,
6315
mavutil.mavlink.MAV_AUTOPILOT_INVALID,
6316
0,
6317
0,
6318
0)
6319
return
6320
6321
self.assert_receive_message("HEARTBEAT", mav=mav2)
6322
6323
# ensure a targeted message is received:
6324
self.install_message_hook_context(heartbeat_on_mav2)
6325
6326
self.progress("Ensuring we can get a message normally")
6327
self.poll_message("AUTOPILOT_VERSION", mav=mav2)
6328
6329
self.progress("Polling AUTOPILOT_VERSION from random sysid")
6330
self.send_poll_message("AUTOPILOT_VERSION", mav=mav2, target_sysid=134)
6331
self.assert_not_receive_message("AUTOPILOT_VERSION", mav=mav2, timeout=10)
6332
6333
# make sure we get heartbeats on the main channel from the non-private mav2:
6334
tstart = self.get_sim_time()
6335
while True:
6336
if self.get_sim_time_cached() - tstart > 5:
6337
raise NotAchievedException("Did not get expected heartbeat from %u" % 7)
6338
m = self.assert_receive_message("HEARTBEAT")
6339
if m.get_srcSystem() == 7:
6340
self.progress("Got heartbeat from (%u) on non-private channel" % 7)
6341
break
6342
6343
# make sure we receive heartbeats from the autotest suite into
6344
# the component:
6345
tstart = self.get_sim_time()
6346
while True:
6347
if self.get_sim_time_cached() - tstart > 5:
6348
raise NotAchievedException("Did not get expected heartbeat from %u" % self.mav.source_system)
6349
m = self.assert_receive_message("HEARTBEAT", mav=mav2)
6350
if m.get_srcSystem() == self.mav.source_system:
6351
self.progress("Got heartbeat from (%u) on non-private channel" % self.mav.source_system)
6352
break
6353
6354
def printmessage(mav, m):
6355
if mav == mav2:
6356
return
6357
6358
print("Got (%u/%u) (%s) " % (m.get_srcSystem(), m.get_srcComponent(), str(m)))
6359
6360
# self.install_message_hook_context(printmessage)
6361
6362
# ensure setting the private channel mask doesn't cause us to
6363
# execute these commands:
6364
self.set_parameter("MAV3_OPTIONS", 2)
6365
self.reboot_sitl() # mavlink-private is reboot-required
6366
mav2 = mavutil.mavlink_connection("tcp:localhost:5763",
6367
robust_parsing=True,
6368
source_system=7,
6369
source_component=7)
6370
# self.send_debug_trap()
6371
self.send_poll_message("AUTOPILOT_VERSION", mav=mav2, target_sysid=134)
6372
self.assert_not_receive_message("AUTOPILOT_VERSION", mav=mav2, timeout=10)
6373
6374
# make sure messages from a private channel don't make it to
6375
# the main channel:
6376
self.drain_mav(self.mav)
6377
self.drain_mav(mav2)
6378
6379
# make sure we do NOT get heartbeats on the main channel from
6380
# the private mav2:
6381
tstart = self.get_sim_time()
6382
while True:
6383
if self.get_sim_time_cached() - tstart > 5:
6384
break
6385
m = self.assert_receive_message("HEARTBEAT")
6386
if m.get_srcSystem() == 7:
6387
raise NotAchievedException("Got heartbeat from private channel")
6388
6389
self.progress("ensure no outside heartbeats reach private channels")
6390
tstart = self.get_sim_time()
6391
while True:
6392
if self.get_sim_time_cached() - tstart > 5:
6393
break
6394
m = self.assert_receive_message("HEARTBEAT")
6395
if m.get_srcSystem() == 1 and m.get_srcComponent() == 1:
6396
continue
6397
# note the above test which shows we get heartbeats from
6398
# both the vehicle and this tests's special heartbeat
6399
raise NotAchievedException("Got heartbeat on private channel from non-vehicle")
6400
6401
def MAV_CMD_DO_SET_REVERSE(self):
6402
'''test MAV_CMD_DO_SET_REVERSE command'''
6403
self.change_mode('GUIDED')
6404
self.wait_ready_to_arm()
6405
self.arm_vehicle()
6406
6407
here = self.mav.location()
6408
target_loc = self.offset_location_ne(here, 2000, 0)
6409
self.send_guided_mission_item(target_loc)
6410
6411
self.wait_groundspeed(3, 100, minimum_duration=5)
6412
6413
for method in self.run_cmd, self.run_cmd_int:
6414
self.progress("Forwards!")
6415
method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=0)
6416
self.wait_heading(0)
6417
6418
self.progress("Backwards!")
6419
method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=1)
6420
self.wait_heading(180)
6421
6422
self.progress("Forwards!")
6423
method(mavutil.mavlink.MAV_CMD_DO_SET_REVERSE, p1=0)
6424
self.wait_heading(0)
6425
6426
self.disarm_vehicle()
6427
6428
def MAV_CMD_NAV_RETURN_TO_LAUNCH(self):
6429
'''test MAV_CMD_NAV_RETURN_TO_LAUNCH mavlink command'''
6430
self.change_mode('GUIDED')
6431
self.wait_ready_to_arm()
6432
self.arm_vehicle()
6433
6434
here = self.mav.location()
6435
target_loc = self.offset_location_ne(here, 2000, 0)
6436
self.send_guided_mission_item(target_loc)
6437
self.wait_distance_to_home(20, 100)
6438
6439
self.run_cmd(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH)
6440
self.wait_mode('RTL')
6441
6442
self.change_mode('GUIDED')
6443
6444
self.run_cmd_int(mavutil.mavlink.MAV_CMD_NAV_RETURN_TO_LAUNCH)
6445
self.wait_mode('RTL')
6446
6447
self.wait_distance_to_home(0, 5, timeout=30)
6448
self.disarm_vehicle()
6449
6450
def MAV_CMD_DO_CHANGE_SPEED(self):
6451
'''test MAV_CMD_NAV_RETURN_TO_LAUNCH mavlink command'''
6452
self.change_mode('GUIDED')
6453
self.wait_ready_to_arm()
6454
self.arm_vehicle()
6455
6456
original_loc = self.mav.location()
6457
here = original_loc
6458
target_loc = self.offset_location_ne(here, 2000, 0)
6459
self.send_guided_mission_item(target_loc)
6460
self.wait_distance_to_home(20, 100)
6461
6462
speeds = 3, 7, 12, 4
6463
6464
for speed in speeds:
6465
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED, p2=speed)
6466
self.wait_groundspeed(speed-0.5, speed+0.5, minimum_duration=5)
6467
6468
self.send_guided_mission_item(original_loc)
6469
6470
for speed in speeds:
6471
self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_CHANGE_SPEED, p2=speed)
6472
self.wait_groundspeed(speed-0.5, speed+0.5, minimum_duration=5)
6473
6474
self.change_mode('RTL')
6475
6476
self.wait_distance_to_home(0, 5, timeout=30)
6477
self.disarm_vehicle()
6478
6479
def MAV_CMD_MISSION_START(self):
6480
'''simple test for starting missing using this command'''
6481
# home and 1 waypoint a long way away:
6482
self.upload_simple_relhome_mission([
6483
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 0, 0, 0),
6484
(mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 2000, 0, 0),
6485
])
6486
self.change_mode('AUTO')
6487
self.wait_ready_to_arm()
6488
self.arm_vehicle()
6489
for method in self.run_cmd, self.run_cmd_int:
6490
self.change_mode('MANUAL')
6491
self.wait_groundspeed(0, 1)
6492
method(mavutil.mavlink.MAV_CMD_MISSION_START)
6493
self.wait_mode('AUTO')
6494
self.wait_groundspeed(3, 100)
6495
self.disarm_vehicle()
6496
6497
def MAV_CMD_NAV_SET_YAW_SPEED(self):
6498
'''tests for MAV_CMD_NAV_SET_YAW_SPEED guided-mode command'''
6499
self.change_mode('GUIDED')
6500
self.wait_ready_to_arm()
6501
self.arm_vehicle()
6502
6503
for method in self.run_cmd, self.run_cmd_int:
6504
self.change_mode('MANUAL')
6505
self.wait_groundspeed(0, 1)
6506
self.change_mode('GUIDED')
6507
self.start_subtest("Absolute angles")
6508
for (heading, speed) in (10, 5), (190, 10), (0, 2), (135, 6):
6509
def cf(*args, **kwargs):
6510
method(
6511
mavutil.mavlink.MAV_CMD_NAV_SET_YAW_SPEED,
6512
p1=heading,
6513
p2=speed,
6514
p3=0, # zero is absolute-angles
6515
)
6516
self.wait_groundspeed(speed-0.5, speed+0.5, called_function=cf, minimum_duration=2)
6517
self.wait_heading(heading-0.5, heading+0.5, called_function=cf, minimum_duration=2)
6518
6519
self.start_subtest("relative angles")
6520
original_angle = 90
6521
method(
6522
mavutil.mavlink.MAV_CMD_NAV_SET_YAW_SPEED,
6523
p1=original_angle,
6524
p2=5,
6525
p3=0, # zero is absolute-angles
6526
)
6527
self.wait_groundspeed(4, 6)
6528
self.wait_heading(original_angle-0.5, original_angle+0.5)
6529
6530
expected_angle = original_angle
6531
for (angle_delta, speed) in (5, 6), (-30, 2), (180, 7):
6532
method(
6533
mavutil.mavlink.MAV_CMD_NAV_SET_YAW_SPEED,
6534
p1=angle_delta,
6535
p2=speed,
6536
p3=1, # one is relative-angles
6537
)
6538
6539
def cf(*args, **kwargs):
6540
method(
6541
mavutil.mavlink.MAV_CMD_NAV_SET_YAW_SPEED,
6542
p1=0,
6543
p2=speed,
6544
p3=1, # one is absolute-angles
6545
)
6546
expected_angle += angle_delta
6547
if expected_angle < 0:
6548
expected_angle += 360
6549
if expected_angle > 360:
6550
expected_angle -= 360
6551
self.wait_groundspeed(speed-0.5, speed+0.5, called_function=cf, minimum_duration=2)
6552
self.wait_heading(expected_angle, called_function=cf, minimum_duration=2)
6553
self.do_RTL()
6554
self.disarm_vehicle()
6555
6556
def _MAV_CMD_GET_HOME_POSITION(self, run_cmd):
6557
'''test handling of mavlink command MAV_CMD_GET_HOME_POSITION'''
6558
self.context_collect('HOME_POSITION')
6559
run_cmd(mavutil.mavlink.MAV_CMD_GET_HOME_POSITION)
6560
self.assert_receive_message('HOME_POSITION', check_context=True)
6561
6562
def MAV_CMD_GET_HOME_POSITION(self):
6563
'''test handling of mavlink command MAV_CMD_GET_HOME_POSITION'''
6564
self.change_mode('LOITER')
6565
self.wait_ready_to_arm()
6566
self._MAV_CMD_GET_HOME_POSITION(self.run_cmd)
6567
self._MAV_CMD_GET_HOME_POSITION(self.run_cmd_int)
6568
6569
def MAV_CMD_DO_FENCE_ENABLE(self):
6570
'''ensure MAV_CMD_DO_FENCE_ENABLE mavlink command works'''
6571
here = self.mav.location()
6572
6573
self.upload_fences_from_locations([
6574
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
6575
# east
6576
self.offset_location_ne(here, -50, 20), # bl
6577
self.offset_location_ne(here, 50, 20), # br
6578
self.offset_location_ne(here, 50, 40), # tr
6579
self.offset_location_ne(here, -50, 40), # tl,
6580
]),
6581
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION, [
6582
# over the top of the vehicle
6583
self.offset_location_ne(here, -50, -50), # bl
6584
self.offset_location_ne(here, -50, 50), # br
6585
self.offset_location_ne(here, 50, 50), # tr
6586
self.offset_location_ne(here, 50, -50), # tl,
6587
]),
6588
])
6589
6590
# enable:
6591
self.run_cmd(mavutil.mavlink.MAV_CMD_DO_FENCE_ENABLE, p1=1)
6592
self.assert_fence_enabled()
6593
6594
# disable
6595
self.run_cmd_int(mavutil.mavlink.MAV_CMD_DO_FENCE_ENABLE, p1=0)
6596
self.assert_fence_disabled()
6597
6598
def MAV_CMD_BATTERY_RESET(self):
6599
'''manipulate battery levels with MAV_CMD_BATTERY_RESET'''
6600
for (run_cmd, value) in (self.run_cmd, 56), (self.run_cmd_int, 97):
6601
run_cmd(
6602
mavutil.mavlink.MAV_CMD_BATTERY_RESET,
6603
p1=65535, # battery mask
6604
p2=value,
6605
)
6606
self.assert_received_message_field_values('BATTERY_STATUS', {
6607
"battery_remaining": value,
6608
}, {
6609
"poll": True,
6610
})
6611
6612
def TestWebServer(self, url):
6613
'''test active web server'''
6614
self.progress("Accessing webserver main page")
6615
import urllib.request
6616
6617
main_page = urllib.request.urlopen(url).read().decode('utf-8')
6618
if main_page.find('ArduPilot Web Server') == -1:
6619
raise NotAchievedException("Expected banner on main page")
6620
6621
board_status = urllib.request.urlopen(url + '/@DYNAMIC/board_status.shtml').read().decode('utf-8')
6622
if board_status.find('0 hours') == -1:
6623
raise NotAchievedException("Expected uptime in board status")
6624
if board_status.find('40.713') == -1:
6625
raise NotAchievedException("Expected latitude in board status")
6626
6627
self.progress("WebServer tests OK")
6628
6629
def NetworkingWebServer(self):
6630
'''web server'''
6631
applet_script = "net_webserver.lua"
6632
6633
self.context_push()
6634
self.install_applet_script_context(applet_script)
6635
6636
self.set_parameters({
6637
"SCR_ENABLE": 1,
6638
"SCR_VM_I_COUNT": 1000000,
6639
"SIM_SPEEDUP": 20,
6640
"NET_ENABLE": 1,
6641
})
6642
6643
self.reboot_sitl()
6644
6645
self.context_push()
6646
self.context_collect('STATUSTEXT')
6647
6648
self.set_parameters({
6649
"WEB_BIND_PORT": 8081,
6650
})
6651
6652
self.scripting_restart()
6653
self.wait_text("WebServer: starting on port 8081", check_context=True)
6654
6655
self.wait_ready_to_arm()
6656
6657
self.TestWebServer("http://127.0.0.1:8081")
6658
6659
self.context_pop()
6660
self.context_pop()
6661
self.reboot_sitl()
6662
6663
def NetworkingWebServerPPP(self):
6664
'''web server over PPP'''
6665
applet_script = "net_webserver.lua"
6666
6667
self.context_push()
6668
self.install_applet_script_context(applet_script)
6669
6670
self.set_parameters({
6671
"SCR_ENABLE": 1,
6672
"SCR_VM_I_COUNT": 1000000,
6673
"SIM_SPEEDUP": 20,
6674
"NET_ENABLE": 1,
6675
"SERIAL5_PROTOCOL": 48,
6676
})
6677
6678
self.progress('rebuilding rover with ppp enabled')
6679
import shutil
6680
shutil.copy('build/sitl/bin/ardurover', 'build/sitl/bin/ardurover.noppp')
6681
util.build_SITL('bin/ardurover', clean=False, configure=True, extra_configure_args=['--enable-PPP', '--debug'])
6682
6683
self.reboot_sitl()
6684
6685
self.progress("Starting PPP daemon")
6686
pppd = util.start_PPP_daemon("192.168.14.15:192.168.14.13", '127.0.0.1:5765')
6687
6688
self.context_push()
6689
self.context_collect('STATUSTEXT')
6690
6691
pppd.expect("remote IP address 192.168.14.13")
6692
6693
self.progress("PPP daemon started")
6694
6695
self.set_parameters({
6696
"WEB_BIND_PORT": 8081,
6697
})
6698
6699
self.scripting_restart()
6700
self.wait_text("WebServer: starting on port 8081", check_context=True)
6701
6702
self.wait_ready_to_arm()
6703
6704
self.TestWebServer("http://192.168.14.13:8081")
6705
6706
self.context_pop()
6707
self.context_pop()
6708
6709
# restore rover without ppp enabled for next test
6710
os.unlink('build/sitl/bin/ardurover')
6711
shutil.copy('build/sitl/bin/ardurover.noppp', 'build/sitl/bin/ardurover')
6712
self.reboot_sitl()
6713
6714
def FenceFullAndPartialTransfer(self, target_system=1, target_component=1):
6715
'''ensure starting a fence transfer then a partial transfer behaves
6716
appropriately'''
6717
# start uploading a 10 item list:
6718
self.mav.mav.mission_count_send(
6719
target_system,
6720
target_component,
6721
10,
6722
mavutil.mavlink.MAV_MISSION_TYPE_FENCE
6723
)
6724
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_FENCE, 0)
6725
# change our mind and try a partial mission upload:
6726
self.mav.mav.mission_write_partial_list_send(
6727
target_system,
6728
target_component,
6729
3,
6730
3,
6731
mavutil.mavlink.MAV_MISSION_TYPE_FENCE)
6732
# should get denied for that one:
6733
self.assert_receive_mission_ack(
6734
mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
6735
want_type=mavutil.mavlink.MAV_MISSION_DENIED,
6736
)
6737
# now wait for the original upload to be "cancelled"
6738
self.assert_receive_mission_ack(
6739
mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
6740
want_type=mavutil.mavlink.MAV_MISSION_OPERATION_CANCELLED,
6741
)
6742
6743
def MissionRetransfer(self, target_system=1, target_component=1):
6744
'''torture-test with MISSION_COUNT'''
6745
# self.send_debug_trap()
6746
self.mav.mav.mission_count_send(
6747
target_system,
6748
target_component,
6749
10,
6750
mavutil.mavlink.MAV_MISSION_TYPE_FENCE
6751
)
6752
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_FENCE, 0)
6753
self.context_push()
6754
self.context_collect('STATUSTEXT')
6755
self.mav.mav.mission_count_send(
6756
target_system,
6757
target_component,
6758
10000,
6759
mavutil.mavlink.MAV_MISSION_TYPE_FENCE
6760
)
6761
self.wait_statustext('Only [0-9]+ items are supported', regex=True, check_context=True)
6762
self.context_pop()
6763
self.assert_not_receive_message('MISSION_REQUEST')
6764
self.mav.mav.mission_count_send(
6765
target_system,
6766
target_component,
6767
10,
6768
mavutil.mavlink.MAV_MISSION_TYPE_FENCE
6769
)
6770
self.assert_receive_mission_item_request(mavutil.mavlink.MAV_MISSION_TYPE_FENCE, 0)
6771
self.assert_receive_mission_ack(
6772
mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
6773
want_type=mavutil.mavlink.MAV_MISSION_OPERATION_CANCELLED,
6774
)
6775
6776
def MissionPolyEnabledPreArm(self):
6777
'''check Polygon porearm checks'''
6778
self.set_parameters({
6779
'FENCE_ENABLE': 1,
6780
})
6781
self.progress("Ensure that we can arm if polyfence is enabled but we have no polyfence")
6782
self.assert_parameter_value('FENCE_TYPE', 6)
6783
self.wait_ready_to_arm()
6784
self.reboot_sitl()
6785
self.wait_ready_to_arm()
6786
6787
self.progress("Ensure we can arm when we have an inclusion fence we are inside of")
6788
here = self.mav.location()
6789
self.upload_fences_from_locations([
6790
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
6791
# over the top of the vehicle
6792
self.offset_location_ne(here, -50, -50), # bl
6793
self.offset_location_ne(here, -50, 50), # br
6794
self.offset_location_ne(here, 50, 50), # tr
6795
self.offset_location_ne(here, 50, -50), # tl,
6796
]),
6797
])
6798
self.delay_sim_time(5)
6799
self.wait_ready_to_arm()
6800
6801
self.reboot_sitl()
6802
self.wait_ready_to_arm()
6803
6804
self.progress("Ensure we can't arm when we are in breacnh of a polyfence")
6805
self.clear_fence()
6806
6807
self.progress("Now create a fence we are in breach of")
6808
here = self.mav.location()
6809
self.upload_fences_from_locations([
6810
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
6811
# over the top of the vehicle
6812
self.offset_location_ne(here, 20, 20), # bl
6813
self.offset_location_ne(here, 20, 50), # br
6814
self.offset_location_ne(here, 50, 50), # tr
6815
self.offset_location_ne(here, 50, 20), # tl,
6816
]),
6817
])
6818
6819
self.assert_prearm_failure('Vehicle breaching Polygon fence', other_prearm_failures_fatal=False)
6820
self.reboot_sitl()
6821
6822
self.assert_prearm_failure('Vehicle breaching Polygon fence', other_prearm_failures_fatal=False, timeout=120)
6823
6824
self.progress("Ensure we can arm when a polyfence fence is cleared when we've previously been in breach")
6825
self.clear_fence()
6826
self.wait_ready_to_arm()
6827
6828
self.upload_fences_from_locations([
6829
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
6830
# over the top of the vehicle
6831
self.offset_location_ne(here, 20, 20), # bl
6832
self.offset_location_ne(here, 20, 50), # br
6833
self.offset_location_ne(here, 50, 50), # tr
6834
self.offset_location_ne(here, 50, 20), # tl,
6835
]),
6836
])
6837
self.reboot_sitl()
6838
self.assert_prearm_failure('Vehicle breaching Polygon fence', other_prearm_failures_fatal=False, timeout=120)
6839
self.clear_fence()
6840
self.wait_ready_to_arm()
6841
6842
self.progress("Ensure we can arm after clearing polygon fence type enabled")
6843
self.upload_fences_from_locations([
6844
(mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION, [
6845
# over the top of the vehicle
6846
self.offset_location_ne(here, 20, 20), # bl
6847
self.offset_location_ne(here, 20, 50), # br
6848
self.offset_location_ne(here, 50, 50), # tr
6849
self.offset_location_ne(here, 50, 20), # tl,
6850
]),
6851
])
6852
self.assert_prearm_failure('Vehicle breaching Polygon fence', other_prearm_failures_fatal=False, timeout=120)
6853
self.set_parameter('FENCE_TYPE', 2)
6854
self.wait_ready_to_arm()
6855
self.set_parameter('FENCE_TYPE', 6)
6856
self.assert_prearm_failure('Vehicle breaching Polygon fence', other_prearm_failures_fatal=False, timeout=120)
6857
6858
def OpticalFlow(self):
6859
'''lightly test OpticalFlow'''
6860
self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW, False, False, False, verbose=True)
6861
6862
self.context_push()
6863
self.set_parameter("SIM_FLOW_ENABLE", 1)
6864
self.set_parameter("FLOW_TYPE", 10)
6865
6866
self.reboot_sitl()
6867
self.wait_sensor_state(mavutil.mavlink.MAV_SYS_STATUS_SENSOR_OPTICAL_FLOW, True, True, True, verbose=True)
6868
6869
self.context_pop()
6870
self.reboot_sitl()
6871
6872
def RCDuplicateOptionsExist(self):
6873
'''ensure duplicate RC option detection works'''
6874
self.wait_ready_to_arm()
6875
self.set_parameters({
6876
"RC6_OPTION": 118,
6877
"RC7_OPTION": 118,
6878
})
6879
self.assert_arm_failure("Duplicate Aux Switch Options")
6880
6881
def JammingSimulation(self):
6882
'''Test jamming simulation works'''
6883
self.wait_ready_to_arm()
6884
start_loc = self.assert_receive_message('GPS_RAW_INT')
6885
self.set_parameter("SIM_GPS1_JAM", 1)
6886
6887
class Requirement():
6888
def __init__(self, field, min_value):
6889
self.field = field
6890
self.min_value = min_value
6891
6892
def met(self, m):
6893
return getattr(m, self.field) > self.min_value
6894
6895
requirements = set([
6896
Requirement('v_acc', 50000),
6897
Requirement('h_acc', 50000),
6898
Requirement('vel_acc', 1000),
6899
Requirement('vel', 10000),
6900
])
6901
low_sats_seen = False
6902
seen_bad_loc = False
6903
tstart = self.get_sim_time()
6904
6905
while True:
6906
if self.get_sim_time() - tstart > 120:
6907
raise NotAchievedException("Did not see all jamming")
6908
m = self.assert_receive_message('GPS_RAW_INT')
6909
new_requirements = copy.copy(requirements)
6910
for requirement in requirements:
6911
if requirement.met(m):
6912
new_requirements.remove(requirement)
6913
requirements = new_requirements
6914
if m.satellites_visible < 6:
6915
low_sats_seen = True
6916
here = self.assert_receive_message('GPS_RAW_INT')
6917
if self.get_distance_int(start_loc, here) > 100:
6918
seen_bad_loc = True
6919
6920
if len(requirements) == 0 and low_sats_seen and seen_bad_loc:
6921
break
6922
6923
def BatteryInvalid(self):
6924
'''check Battery prearms report useful data to user'''
6925
self.start_subtest("Changing battery types makes no difference")
6926
self.set_parameter("BATT_MONITOR", 0)
6927
self.assert_prearm_failure("Battery 1 unhealthy", other_prearm_failures_fatal=False)
6928
self.set_parameter("BATT_MONITOR", 4)
6929
self.wait_ready_to_arm()
6930
6931
self.start_subtest("No battery monitor should be armable")
6932
self.set_parameter("BATT_MONITOR", 0)
6933
self.reboot_sitl()
6934
self.wait_ready_to_arm()
6935
6936
self.set_parameter("BATT_MONITOR", 4)
6937
self.assert_prearm_failure("Battery 1 unhealthy", other_prearm_failures_fatal=False)
6938
self.reboot_sitl()
6939
self.wait_ready_to_arm()
6940
6941
self.start_subtest("Invalid backend should have a clear error")
6942
self.set_parameter("BATT_MONITOR", 98)
6943
self.reboot_sitl()
6944
self.assert_prearm_failure("Battery 1 unhealthy", other_prearm_failures_fatal=False)
6945
6946
self.start_subtest("Switching from an invalid backend to a valid backend should require a reboot")
6947
self.set_parameter("BATT_MONITOR", 4)
6948
self.assert_prearm_failure("Battery 1 unhealthy", other_prearm_failures_fatal=False)
6949
6950
self.start_subtest("Switching to None should NOT require a reboot")
6951
self.set_parameter("BATT_MONITOR", 0)
6952
self.wait_ready_to_arm()
6953
6954
# this method modified from cmd_addpoly in the MAVProxy code:
6955
def generate_polyfence(self, centre_loc, command, radius, count, rotation=0):
6956
'''adds a number of waypoints equally spaced around a circle
6957
6958
'''
6959
if count < 3:
6960
raise ValueError("Invalid count (%s)" % str(count))
6961
if radius <= 0:
6962
raise ValueError("Invalid radius (%s)" % str(radius))
6963
6964
latlon = (centre_loc.lat, centre_loc.lng)
6965
6966
items = []
6967
for i in range(0, count):
6968
(lat, lon) = mavextra.gps_newpos(latlon[0],
6969
latlon[1],
6970
360/float(count)*i + rotation,
6971
radius)
6972
6973
m = mavutil.mavlink.MAVLink_mission_item_int_message(
6974
1, # target system
6975
1, # target component
6976
0, # seq
6977
mavutil.mavlink.MAV_FRAME_GLOBAL, # frame
6978
command, # command
6979
0, # current
6980
0, # autocontinue
6981
count, # param1,
6982
0.0, # param2,
6983
0.0, # param3
6984
0.0, # param4
6985
int(lat*1e7), # x (latitude)
6986
int(lon*1e7), # y (longitude)
6987
0, # z (altitude)
6988
mavutil.mavlink.MAV_MISSION_TYPE_FENCE,
6989
)
6990
items.append(m)
6991
6992
return items
6993
6994
def SDPolyFence(self):
6995
'''test storage of fence on SD card'''
6996
self.set_parameters({
6997
'BRD_SD_FENCE': 32767,
6998
})
6999
self.reboot_sitl()
7000
7001
home = self.home_position_as_mav_location()
7002
fence = self.generate_polyfence(
7003
home,
7004
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_INCLUSION,
7005
radius=100,
7006
count=100,
7007
)
7008
7009
for bearing in range(0, 359, 60):
7010
x = self.offset_location_heading_distance(home, bearing, 100)
7011
fence.extend(self.generate_polyfence(
7012
x,
7013
mavutil.mavlink.MAV_CMD_NAV_FENCE_POLYGON_VERTEX_EXCLUSION,
7014
radius=100,
7015
count=100,
7016
))
7017
7018
self.correct_wp_seq_numbers(fence)
7019
self.check_fence_upload_download(fence)
7020
7021
self.delay_sim_time(1000)
7022
7023
def ManyMAVLinkConnections(self):
7024
'''test testing >8 MAVLink connections'''
7025
self.set_parameters({
7026
"SERIAL3_PROTOCOL": 2,
7027
"SERIAL4_PROTOCOL": 2,
7028
"SERIAL5_PROTOCOL": 2,
7029
"SERIAL6_PROTOCOL": 2,
7030
"SERIAL7_PROTOCOL": 2,
7031
7032
"NET_ENABLE": 1,
7033
7034
"NET_P1_TYPE": 4,
7035
"NET_P1_IP0": 127,
7036
"NET_P1_IP1": 0,
7037
"NET_P1_IP2": 0,
7038
"NET_P1_IP3": 1,
7039
"NET_P1_PORT": 6700,
7040
"NET_P1_PROTOCOL": 2,
7041
7042
"NET_P2_TYPE": 4,
7043
"NET_P2_IP0": 127,
7044
"NET_P2_IP1": 0,
7045
"NET_P2_IP2": 0,
7046
"NET_P2_IP3": 1,
7047
"NET_P2_PORT": 6701,
7048
"NET_P2_PROTOCOL": 2,
7049
7050
"NET_P3_TYPE": 4,
7051
"NET_P3_IP0": 127,
7052
"NET_P3_IP1": 0,
7053
"NET_P3_IP2": 0,
7054
"NET_P3_IP3": 1,
7055
"NET_P3_PORT": 6702,
7056
"NET_P3_PROTOCOL": 2,
7057
7058
"NET_P4_TYPE": 4,
7059
"NET_P4_IP0": 127,
7060
"NET_P4_IP1": 0,
7061
"NET_P4_IP2": 0,
7062
"NET_P4_IP3": 1,
7063
"NET_P4_PORT": 6703,
7064
"NET_P4_PROTOCOL": 2,
7065
7066
"SCR_ENABLE": 1,
7067
})
7068
7069
self.install_example_script_context("simple_loop.lua")
7070
self.customise_SITL_commandline([
7071
"--serial3=tcp:4",
7072
"--serial4=tcp:1",
7073
])
7074
7075
self.wait_statustext("hello, world")
7076
conns = {}
7077
for port in 5761, 5762, 5763, 5764, 5765, 5766, 5767, 6700, 6701, 6702, 6703:
7078
cstring = f"tcp:localhost:{port}"
7079
self.progress(f"Connecting to {cstring}")
7080
c = mavutil.mavlink_connection(
7081
cstring,
7082
robust_parsing=True,
7083
source_system=7,
7084
source_component=7,
7085
)
7086
conns[port] = c
7087
7088
for repeats in range(1, 5):
7089
for (port, conn) in conns.items():
7090
while True:
7091
self.progress(f"Checking port {port}")
7092
m = self.assert_receive_message('STATUSTEXT', mav=conn, timeout=120)
7093
self.drain_all_pexpects()
7094
self.drain_mav()
7095
if m.text == "hello, world":
7096
self.progress(f"Received {m.text} from port {port}")
7097
break
7098
7099
def REQUIRE_LOCATION_FOR_ARMING(self):
7100
'''check DriveOption::REQUIRE_POSITION_FOR_ARMING works'''
7101
self.context_push()
7102
self.set_parameters({
7103
"SIM_GPS1_NUMSATS": 3, # EKF does not like < 6
7104
"AHRS_GPS_USE": 0, # stop DCM supplying home
7105
})
7106
self.reboot_sitl()
7107
self.change_mode('MANUAL')
7108
self.wait_prearm_sys_status_healthy()
7109
self.arm_vehicle()
7110
self.disarm_vehicle()
7111
7112
self.change_mode('GUIDED')
7113
self.assert_prearm_failure("Need Position Estimate", other_prearm_failures_fatal=False)
7114
7115
self.change_mode('MANUAL')
7116
self.set_parameters({
7117
"ARMING_NEED_LOC": 1,
7118
})
7119
self.assert_prearm_failure("Need Position Estimate", other_prearm_failures_fatal=False)
7120
self.context_pop()
7121
self.reboot_sitl()
7122
7123
def SafetySwitch(self):
7124
'''check safety switch works'''
7125
self.start_subtest("Make sure we don't start moving when safety switch enabled")
7126
self.wait_ready_to_arm()
7127
self.set_rc(1, 2000)
7128
self.wait_armed()
7129
self.set_rc(1, 1500)
7130
self.set_safetyswitch_on()
7131
self.wait_groundspeed(0, 0.1, minimum_duration=2)
7132
self.set_safetyswitch_off()
7133
self.disarm_vehicle()
7134
7135
self.start_subtest("Make sure we stop moving when safety switch enabled")
7136
self.wait_ready_to_arm()
7137
self.arm_vehicle()
7138
self.set_rc(3, 1700)
7139
self.wait_groundspeed(5, 100, minimum_duration=2)
7140
self.set_safetyswitch_on()
7141
self.wait_groundspeed(0, 0.1, minimum_duration=2)
7142
self.set_safetyswitch_off()
7143
self.wait_groundspeed(5, 100, minimum_duration=2)
7144
self.set_rc(3, 1500)
7145
self.disarm_vehicle()
7146
7147
def GetMessageInterval(self):
7148
'''check that the two methods for requesting a MESSAGE_INTERVAL message are equivalent'''
7149
target_msg = mavutil.mavlink.MAVLINK_MSG_ID_HOME_POSITION
7150
old_cmd = (mavutil.mavlink.MAV_CMD_GET_MESSAGE_INTERVAL, target_msg, 0)
7151
new_cmd = (mavutil.mavlink.MAV_CMD_REQUEST_MESSAGE, mavutil.mavlink.MAVLINK_MSG_ID_MESSAGE_INTERVAL, target_msg)
7152
7153
interval_us = None
7154
7155
for run_command in self.run_cmd, self.run_cmd_int:
7156
for cmd in old_cmd, new_cmd:
7157
cmd_id, p1, p2 = cmd
7158
7159
self.context_collect("MESSAGE_INTERVAL")
7160
run_command(cmd_id, p1=p1, p2=p2)
7161
m = self.assert_receive_message('MESSAGE_INTERVAL', timeout=1, check_context=True)
7162
self.context_clear_collection("MESSAGE_INTERVAL")
7163
7164
if m.message_id != target_msg:
7165
raise NotAchievedException(f"Unexpected ID in MESSAGE_INTERVAL (want={target_msg}, got={m.message_id})")
7166
7167
if interval_us is None:
7168
interval_us = m.interval_us
7169
7170
if m.interval_us != interval_us:
7171
raise NotAchievedException(f"Unexpected interval_us (want={interval_us}, got={m.interval_us})")
7172
7173
def ScriptingLocationBindings(self):
7174
'''test scripting bindings'''
7175
self.install_script_content_context("test-scripting-bindings.lua", """
7176
function main()
7177
here = ahrs:get_location()
7178
if here == nil then
7179
gcs:send_text(0, "Need location")
7180
return
7181
end
7182
if here.alt == 0 then
7183
gcs:send_text(0, "zero altitude?!")
7184
return
7185
end
7186
ALT_FRAME = { ABSOLUTE = 0, ABOVE_HOME = 1, ABOVE_ORIGIN = 2, ABOVE_TERRAIN = 3 }
7187
here:set_alt_m(12.34, ALT_FRAME.ABSOLUTE)
7188
want = 1234
7189
if here:alt() ~= want then
7190
gcs:send_text(0, string.format("Bad altitude" .. here:alt() .. " want " .. want))
7191
return
7192
end
7193
gcs:send_text(0, "Tests OK")
7194
end
7195
function update()
7196
main()
7197
return update, 1000
7198
end
7199
7200
return update()
7201
""")
7202
self.set_parameter('SCR_ENABLE', 1)
7203
self.reboot_sitl()
7204
self.wait_statustext('Tests OK')
7205
7206
def DriveEachFrame(self):
7207
'''drive each frame (except BalanceBot) in a mission to ensure basic functionality'''
7208
vinfo = vehicleinfo.VehicleInfo()
7209
vinfo_options = vinfo.options[self.vehicleinfo_key()]
7210
known_broken_frames = {
7211
"balancebot": "needs special stay-upright code",
7212
"motorboat-skid": "gets stuck between waypoints 2 and 3",
7213
}
7214
for frame in sorted(vinfo_options["frames"].keys()):
7215
self.start_subtest("Testing frame (%s)" % str(frame))
7216
if frame in known_broken_frames:
7217
self.progress("Actually, no I'm not - it is known-broken (%s)" %
7218
(known_broken_frames[frame]))
7219
continue
7220
frame_bits = vinfo_options["frames"][frame]
7221
print("frame_bits: %s" % str(frame_bits))
7222
if frame_bits.get("external", False):
7223
self.progress("Actually, no I'm not - it is an external simulation")
7224
continue
7225
model = frame_bits.get("model", frame)
7226
defaults = self.model_defaults_filepath(frame)
7227
if not isinstance(defaults, list):
7228
defaults = [defaults]
7229
self.customise_SITL_commandline(
7230
[],
7231
defaults_filepath=defaults,
7232
model=model,
7233
wipe=True,
7234
)
7235
mission_file = "basic.txt"
7236
self.wait_ready_to_arm()
7237
self.set_parameters({
7238
"MIS_DONE_BEHAVE": 3,
7239
"SIM_WIND_SPD": 10,
7240
})
7241
self.arm_vehicle()
7242
self.drive_mission(mission_file, strict=False, ignore_MANUAL_mode_change=True)
7243
self.wait_mode('MANUAL')
7244
7245
if self.distance_to_home() > 2:
7246
raise NotAchievedException("Did not get home!")
7247
7248
def AP_ROVER_AUTO_ARM_ONCE_ENABLED(self):
7249
'''test Rover arm-once-when-ready behaviour'''
7250
# do a little dance so we don't arm after setting the parameter:
7251
self.wait_ready_to_arm()
7252
self.arm_vehicle()
7253
self.disarm_vehicle()
7254
self.set_parameter("ARMING_REQUIRE", 3)
7255
self.reboot_sitl()
7256
self.wait_armed(timeout=120)
7257
self.disarm_vehicle()
7258
vehicle_test_suite.WaitAndMaintainDisarmed(
7259
self,
7260
minimum_duration=10,
7261
timeout=30,
7262
).run()
7263
7264
def tests(self):
7265
'''return list of all tests'''
7266
ret = super(AutoTestRover, self).tests()
7267
7268
ret.extend([
7269
self.MAVProxy_SetModeUsingSwitch,
7270
self.HIGH_LATENCY2,
7271
self.MAVProxy_SetModeUsingMode,
7272
self.ModeSwitch,
7273
self.AuxModeSwitch,
7274
self.DriveRTL,
7275
self.SmartRTL,
7276
self.DriveSquare,
7277
self.DriveMission,
7278
# self.DriveBrake, # disabled due to frequent failures
7279
self.MAV_CMD_DO_SEND_BANNER,
7280
self.DO_SET_MODE,
7281
self.MAVProxy_DO_SET_MODE,
7282
self.ServoRelayEvents,
7283
self.RCOverrides,
7284
self.RCOverridesCancel,
7285
self.MANUAL_CONTROL,
7286
self.Sprayer,
7287
self.AC_Avoidance,
7288
self.CameraMission,
7289
self.Gripper,
7290
self.GripperMission,
7291
self.SET_MESSAGE_INTERVAL,
7292
self.MESSAGE_INTERVAL_COMMAND_INT,
7293
self.REQUEST_MESSAGE,
7294
self.MAV_GCS_ENFORCE,
7295
self.SET_ATTITUDE_TARGET,
7296
self.SET_ATTITUDE_TARGET_heading,
7297
self.SET_POSITION_TARGET_LOCAL_NED,
7298
self.MAV_CMD_DO_SET_MISSION_CURRENT,
7299
self.MAV_CMD_DO_CHANGE_SPEED,
7300
self.MAV_CMD_MISSION_START,
7301
self.MAV_CMD_NAV_SET_YAW_SPEED,
7302
self.Button,
7303
self.Rally,
7304
self.Offboard,
7305
self.MAVProxyParam,
7306
self.GCSFence,
7307
self.GCSFenceInvalidPoint,
7308
self.GCSMission,
7309
# self.GCSRally, # enable me in 2026, needs MAVProxy fixes
7310
self.MotorTest,
7311
self.WheelEncoders,
7312
self.DataFlashOverMAVLink,
7313
self.DataFlash,
7314
self.SkidSteer,
7315
self.PolyFence,
7316
self.SDPolyFence,
7317
self.PolyFenceAvoidance,
7318
self.PolyFenceObjectAvoidanceAuto,
7319
self.PolyFenceObjectAvoidanceGuided,
7320
self.PolyFenceObjectAvoidanceBendyRuler,
7321
self.SendToComponents,
7322
self.PolyFenceObjectAvoidanceBendyRulerEasierGuided,
7323
self.PolyFenceObjectAvoidanceBendyRulerEasierAuto,
7324
self.SlewRate,
7325
self.Scripting,
7326
self.ScriptingSteeringAndThrottle,
7327
self.MissionFrames,
7328
self.SetpointGlobalPos,
7329
self.SetpointGlobalVel,
7330
self.AccelCal,
7331
self.RangeFinder,
7332
self.AIS,
7333
self.AISMultipleVessels,
7334
self.AISDataValidation,
7335
self.AP_Proximity_MAV,
7336
self.EndMissionBehavior,
7337
self.FlashStorage,
7338
self.FRAMStorage,
7339
self.DepthFinder,
7340
self.ChangeModeByNumber,
7341
self.EStopAtBoot,
7342
self.MAV_CMD_NAV_RETURN_TO_LAUNCH,
7343
self.StickMixingAuto,
7344
self.AutoDock,
7345
self.PrivateChannel,
7346
self.GCSFailsafe,
7347
self.RoverInitialMode,
7348
self.DriveMaxRCIN,
7349
self.NoArmWithoutMissionItems,
7350
self.PARAM_ERROR,
7351
self.CompassPrearms,
7352
self.ManyMAVLinkConnections,
7353
self.MAV_CMD_DO_SET_REVERSE,
7354
self.MAV_CMD_GET_HOME_POSITION,
7355
self.MAV_CMD_DO_FENCE_ENABLE,
7356
self.MAV_CMD_BATTERY_RESET,
7357
self.NetworkingWebServer,
7358
self.NetworkingWebServerPPP,
7359
self.RTL_SPEED,
7360
self.ScriptingLocationBindings,
7361
self.MissionRetransfer,
7362
self.FenceFullAndPartialTransfer,
7363
self.MissionPolyEnabledPreArm,
7364
self.OpticalFlow,
7365
self.RCDuplicateOptionsExist,
7366
self.ClearMission,
7367
self.JammingSimulation,
7368
self.BatteryInvalid,
7369
self.REQUIRE_LOCATION_FOR_ARMING,
7370
self.GetMessageInterval,
7371
self.SafetySwitch,
7372
self.ThrottleFailsafe,
7373
self.DriveEachFrame,
7374
self.AP_ROVER_AUTO_ARM_ONCE_ENABLED,
7375
])
7376
return ret
7377
7378
def disabled_tests(self):
7379
return {
7380
"SlewRate": "got timing report failure on CI",
7381
"MAV_CMD_NAV_SET_YAW_SPEED": "compiled out of code by default",
7382
"PolyFenceObjectAvoidanceBendyRuler": "unreliable",
7383
}
7384
7385
def rc_defaults(self):
7386
ret = super(AutoTestRover, self).rc_defaults()
7387
ret[3] = 1500
7388
ret[8] = 1800
7389
return ret
7390
7391
def initial_mode_switch_mode(self):
7392
return "MANUAL"
7393
7394
def default_mode(self):
7395
return 'MANUAL'
7396
7397