def create_moving_obstacle(self, waypoints): """Create a new MovingObstacle model. Args: waypoints: List of (lat, lon, alt) tuples Returns: Saved MovingObstacle """ obstacle = MovingObstacle(speed_avg=40, sphere_radius=100) obstacle.save() for num, waypoint in enumerate(waypoints): (lat, lon, alt) = waypoint gps = GpsPosition(latitude=lat, longitude=lon) gps.save() pos = AerialPosition(gps_position=gps, altitude_msl=alt) pos.save() waypoint = Waypoint(order=num, position=pos) waypoint.save() obstacle.waypoints.add(waypoint) obstacle.save() return obstacle
def setUp(self): """Populates an active mission to test a cached view.""" pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() self.pos = pos obst = StationaryObstacle() obst.gps_position = pos obst.cylinder_radius = 10 obst.cylinder_height = 10 obst.save() self.obst = obst config = MissionConfig() config.is_active = True config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_target_pos = pos config.air_drop_pos = pos config.save() self.config = config config.stationary_obstacles.add(obst) config.save() self.login_url = reverse('auvsi_suas:login') self.obst_url = reverse('auvsi_suas:obstacles') self.clear_cache_url = reverse('auvsi_suas:clear_cache')
def create_uas_logs(self, user, entries): """Create a list of uas telemetry logs. Args: user: User to create logs for. entries: List of (lat, lon, alt) tuples for each entry. Returns: List of UasTelemetry objects """ ret = [] for (lat, lon, alt) in entries: pos = GpsPosition() pos.latitude = lat pos.longitude = lon pos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = pos apos.save() log = UasTelemetry() log.user = user log.uas_position = apos log.uas_heading = 0 log.save() ret.append(log) return ret
def test_get_waypoint_travel_time(self): """Tests travel time calc.""" test_spds = [1, 10, 100, 500] for (lon2, lat2, lon1, lat1, dist_km) in TESTDATA_COMPETITION_DIST: dist_ft = units.kilometers_to_feet(dist_km) for speed in test_spds: speed_fps = units.knots_to_feet_per_second(speed) time = dist_ft / speed_fps gpos1 = GpsPosition() gpos1.latitude = lat1 gpos1.longitude = lon1 gpos1.save() apos1 = AerialPosition() apos1.gps_position = gpos1 apos1.altitude_msl = 0 apos1.save() wpt1 = Waypoint() wpt1.position = apos1 gpos2 = GpsPosition() gpos2.latitude = lat2 gpos2.longitude = lon2 gpos2.save() apos2 = AerialPosition() apos2.gps_position = gpos2 apos2.altitude_msl = 0 apos2.save() wpt2 = Waypoint() wpt2.position = apos2 waypoints = [wpt1, wpt2] obstacle = MovingObstacle() obstacle.speed_avg = speed self.assertTrue(self.eval_travel_time( obstacle.get_waypoint_travel_time(waypoints, 0, 1), time))
def create_logs(self, user, num=10, start=None, delta=None, altitude=100, heading=90): if start is None: start = timezone.now() if delta is None: delta = datetime.timedelta(seconds=1) logs = [] for i in xrange(num): gps = GpsPosition(latitude=38 + 0.001 * i, longitude=-78 + 0.001 * i) gps.save() pos = AerialPosition(gps_position=gps, altitude_msl=altitude) pos.save() log = UasTelemetry(user=user, uas_position=pos, uas_heading=heading) log.save() log.timestamp = start + i * delta log.save() logs.append(log) return logs
def setUp(self): """Creates test data.""" # Form test set for contains position self.testdata_containspos = [] for test_data in TESTDATA_FLYZONE_CONTAINSPOS: # Create the FlyZone zone = FlyZone() zone.altitude_msl_min = test_data['min_alt'] zone.altitude_msl_max = test_data['max_alt'] zone.save() for waypoint_id in range(len(test_data['waypoints'])): (lat, lon) = test_data['waypoints'][waypoint_id] gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.gps_position = gpos apos.altitude_msl = 0 apos.save() wpt = Waypoint() wpt.order = waypoint_id wpt.position = apos wpt.save() zone.boundary_pts.add(wpt) # Form test set test_pos = [] for pos in test_data['inside_pos']: test_pos.append((pos, True)) for pos in test_data['outside_pos']: test_pos.append((pos, False)) # Store self.testdata_containspos.append((zone, test_pos))
def test_put_one(self): """PUT update one field without affecting others.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Test target') t.save() data = {'shape': 'circle'} response = self.client.put( targets_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(200, response.status_code) t.refresh_from_db() t.location.refresh_from_db() self.assertEqual(self.user, t.user) self.assertEqual(TargetType.standard, t.target_type) self.assertEqual(38, t.location.latitude) self.assertEqual(-76, t.location.longitude) self.assertEqual(Orientation.s, t.orientation) self.assertEqual(Shape.circle, t.shape) self.assertEqual(Color.white, t.background_color) self.assertEqual('ABC', t.alphanumeric) self.assertEqual(Color.black, t.alphanumeric_color) self.assertEqual('Test target', t.description)
def test_duplicate_unequal(self): """Tests the duplicate function for nonequal positions.""" gps1 = GpsPosition(latitude=0, longitude=0) gps2 = GpsPosition(latitude=1, longitude=0) gps3 = GpsPosition(latitude=0, longitude=1) self.assertFalse(gps1.duplicate(gps2)) self.assertFalse(gps1.duplicate(gps3))
def setUp(self): self.user = User.objects.create_user('testuser', '*****@*****.**', 'testpass') self.user.save() # Create an active mission. pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.is_active = True config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_target_pos = pos config.air_drop_pos = pos config.save() # Add a couple of stationary obstacles obst = self.create_stationary_obstacle(lat=38.142233, lon=-76.434082, radius=300, height=500) config.stationary_obstacles.add(obst) obst = self.create_stationary_obstacle(lat=38.442233, lon=-76.834082, radius=100, height=750) config.stationary_obstacles.add(obst) # And a couple of moving obstacles obst = self.create_moving_obstacle([ # (lat, lon, alt) (38.142233, -76.434082, 300), (38.141878, -76.425198, 700), ]) config.moving_obstacles.add(obst) obst = self.create_moving_obstacle([ # (lat, lon, alt) (38.145405, -76.428310, 100), (38.146582, -76.424099, 200), (38.144662, -76.427634, 300), (38.147729, -76.419185, 200), (38.147573, -76.420832, 100), (38.148522, -76.419507, 750), ]) config.moving_obstacles.add(obst) config.save() # Login response = self.client.post(login_url, { 'username': '******', 'password': '******' }) self.assertEqual(200, response.status_code)
def test_unicode(self): """Tests the unicode method executes.""" gps = GpsPosition(latitude=10, longitude=100) gps.save() pos = AerialPosition(gps_position=gps, altitude_msl=100) pos.save() pos.__unicode__()
def test_unicode(self): """Tests the unicode method executes.""" pos = GpsPosition(latitude=100, longitude=200) pos.save() obst = StationaryObstacle(gps_position=pos, cylinder_radius=10, cylinder_height=100) obst.save() self.assertTrue(obst.__unicode__())
def test_similar_classifications(self): """Tests similar classification counts are computed correctly.""" # Test equal standard targets. l = GpsPosition(latitude=38, longitude=-76) l.save() t1 = Target(user=self.user, target_type=TargetType.standard, location=l, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Test target', autonomous=True) t1.save() t2 = Target(user=self.user, target_type=TargetType.standard, location=l, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Test other target', autonomous=True) t2.save() self.assertAlmostEqual(1.0, t1.similar_classifications(t2)) # Test unequal standard targets. t1.alphanumeric = 'DEF' t1.alphanumeric_color = Color.blue t1.save() self.assertAlmostEqual(3.0 / 5.0, t1.similar_classifications(t2)) t1.shape = Shape.circle t1.background_color = Color.orange t1.save() self.assertAlmostEqual(1.0 / 5.0, t1.similar_classifications(t2)) # Test different types. t1.target_type = TargetType.off_axis t1.save() self.assertAlmostEqual(0, t1.similar_classifications(t2)) # Test off_axis is same as standard. t2.target_type = TargetType.off_axis t2.alphanumeric = 'DEF' t2.save() self.assertAlmostEqual(2.0 / 5.0, t1.similar_classifications(t2)) # Test emergent type is always 1. t1.target_type = TargetType.emergent t1.save() t2.target_type = TargetType.emergent t2.save() self.assertAlmostEqual(1.0, t1.similar_classifications(t2))
def setUp(self): """Create the obstacles for testing.""" # Obstacle with no waypoints obst_no_wpt = MovingObstacle() obst_no_wpt.speed_avg = 1 obst_no_wpt.sphere_radius = 1 obst_no_wpt.save() self.obst_no_wpt = obst_no_wpt # Obstacle with single waypoint self.single_wpt_lat = 40 self.single_wpt_lon = 76 self.single_wpt_alt = 100 obst_single_wpt = MovingObstacle() obst_single_wpt.speed_avg = 1 obst_single_wpt.sphere_radius = 1 obst_single_wpt.save() single_gpos = GpsPosition() single_gpos.latitude = self.single_wpt_lat single_gpos.longitude = self.single_wpt_lon single_gpos.save() single_apos = AerialPosition() single_apos.gps_position = single_gpos single_apos.altitude_msl = self.single_wpt_alt single_apos.save() single_wpt = Waypoint() single_wpt.position = single_apos single_wpt.order = 1 single_wpt.save() obst_single_wpt.waypoints.add(single_wpt) self.obst_single_wpt = obst_single_wpt # Obstacles with predefined path self.obstacles = [] for path in TESTDATA_MOVOBST_PATHS: cur_obst = MovingObstacle() cur_obst.speed_avg = 68 cur_obst.sphere_radius = 10 cur_obst.save() for pt_id in range(len(path)): (lat, lon, alt) = path[pt_id] cur_gpos = GpsPosition() cur_gpos.latitude = lat cur_gpos.longitude = lon cur_gpos.save() cur_apos = AerialPosition() cur_apos.gps_position = cur_gpos cur_apos.altitude_msl = alt cur_apos.save() cur_wpt = Waypoint() cur_wpt.position = cur_apos cur_wpt.order = pt_id cur_wpt.save() cur_obst.waypoints.add(cur_wpt) cur_obst.save() self.obstacles.append(cur_obst)
def create_log_element(self, lat, lon, alt, user, log_time): pos = GpsPosition(latitude=lat, longitude=lon) pos.save() apos = AerialPosition(gps_position=pos, altitude_msl=alt) apos.save() log = UasTelemetry(user=user, uas_position=apos, uas_heading=100, ) log.save() log.timestamp = log_time log.save() return log
def create_log_element(self, timestamp, user, lat, lon, alt, heading): pos = GpsPosition(latitude=lat, longitude=lon) pos.save() apos = AerialPosition(gps_position=pos, altitude_msl=alt) apos.save() log = UasTelemetry(timestamp=timezone.now(), user=user, uas_position=apos, uas_heading=heading) log.save() return log
def test_contains_pos(self): """Tests the contains_pos method.""" for (zone, test_pos) in self.testdata_containspos: for ((lat, lon, alt), inside) in test_pos: gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = gpos self.assertEqual(zone.contains_pos(apos), inside)
def test_put_invalid_json(self): """PUT request body must be valid JSON.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l) t.save() response = self.client.put( targets_id_url(args=[t.pk]), data="latitude=76", content_type='multipart/form-data') self.assertEqual(400, response.status_code)
def test_put_partial_clear_location(self): """PUT can't clear location with only one of lat/lon.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l) t.save() data = {'latitude': None} response = self.client.put( targets_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(400, response.status_code)
def create_config(self): """Creates a dummy config for testing.""" pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.is_active = False config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_target_pos = pos config.air_drop_pos = pos return config
def test_json(self): """Test target JSON.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Test target', autonomous=True) t.save() d = t.json() self.assertIn('id', d) self.assertEqual(self.user.pk, d['user']) self.assertEqual('standard', d['type']) self.assertEqual(38, d['latitude']) self.assertEqual(-76, d['longitude']) self.assertEqual('s', d['orientation']) self.assertEqual('square', d['shape']) self.assertEqual('white', d['background_color']) self.assertEqual('ABC', d['alphanumeric']) self.assertEqual('black', d['alphanumeric_color']) self.assertEqual('Test target', d['description']) self.assertEqual(True, d['autonomous']) self.assertNotIn('thumbnail_approved', d) d = t.json(is_superuser=True) self.assertIn('description_approved', d) self.assertIn('thumbnail_approved', d) t.description_approved = True t.thumbnail_approved = True t.actionable_override = True t.save() d = t.json(is_superuser=True) self.assertEqual(True, d['description_approved']) self.assertEqual(None, d['thumbnail']) self.assertEqual(True, d['thumbnail_approved']) self.assertEqual(True, d['actionable_override'])
def setUp(self): """Setup a single active mission to test live kml with.""" super(TestGenerateLiveKMLNoFixture, self).setUp() pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.is_active = True config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_target_pos = pos config.air_drop_pos = pos config.save() self.config = config
def test_contains_many_pos(self): """Tests the contains_many_pos method.""" for (zone, test_pos) in self.testdata_containspos: aerial_pos_list = [] expected_results = [] for ((lat, lon, alt), inside) in test_pos: gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = gpos aerial_pos_list.append(apos) expected_results.append(inside) self.assertEqual( zone.contains_many_pos(aerial_pos_list), expected_results)
def test_put_clear_location(self): """PUT clear location by clearing lat and lon.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l) t.save() data = {'latitude': None, 'longitude': None} response = self.client.put( targets_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(200, response.status_code) t.refresh_from_db() self.assertEqual(None, t.location)
def post(self, request): try: data = json.loads(request.body) except ValueError: return HttpResponseBadRequest('Request body is not valid JSON.') # Target type is required. if 'type' not in data: return HttpResponseBadRequest('Target type required.') latitude = data.get('latitude') longitude = data.get('longitude') # Require zero or both of latitude and longitude. if (latitude is not None and longitude is None) or \ (latitude is None and longitude is not None): return HttpResponseBadRequest( 'Either none or both of latitude and longitude required.') try: data = normalize_data(data) except ValueError as e: return HttpResponseBadRequest(str(e)) l = None if latitude is not None and longitude is not None: l = GpsPosition(latitude=data['latitude'], longitude=data['longitude']) l.save() # Use the dictionary get() method to default non-existent values to None. t = Target(user=request.user, target_type=data['type'], location=l, orientation=data.get('orientation'), shape=data.get('shape'), background_color=data.get('background_color'), alphanumeric=data.get('alphanumeric', ''), alphanumeric_color=data.get('alphanumeric_color'), description=data.get('description', ''), autonomous=data.get('autonomous', False)) t.save() return JsonResponse( t.json(is_superuser=request.user.is_superuser), status=201)
def test_put_update_location(self): """PUT updating location only requires one of lat/lon.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l) t.save() data = {'latitude': 39} response = self.client.put( targets_id_url(args=[t.pk]), data=json.dumps(data)) self.assertEqual(200, response.status_code) t.refresh_from_db() t.location.refresh_from_db() self.assertEqual(39, t.location.latitude) self.assertEqual(-76, t.location.longitude)
def waypoints_from_data(self, waypoints_data): """Converts tuples of lat/lon/alt to a waypoint.""" waypoints = [] for i, waypoint in enumerate(waypoints_data): (lat, lon, alt) = waypoint pos = GpsPosition() pos.latitude = lat pos.longitude = lon pos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = i wpt.save() waypoints.append(wpt) return waypoints
def create_data(self): """Create a basic sample dataset.""" self.user1 = User.objects.create_user('user1', '*****@*****.**', 'testpass') self.user1.save() self.user2 = User.objects.create_user('user2', '*****@*****.**', 'testpass') self.user2.save() # user1 is on mission event = MissionClockEvent(user=self.user1, team_on_clock=True, team_on_timeout=False) event.save() # user1 is flying event = TakeoffOrLandingEvent(user=self.user1, uas_in_air=True) event.save() # user2 has landed event = TakeoffOrLandingEvent(user=self.user2, uas_in_air=True) event.save() event = TakeoffOrLandingEvent(user=self.user2, uas_in_air=False) event.save() # user2 is active self.timestamp = timezone.now() gps = GpsPosition(latitude=38.6462, longitude=-76.2452) gps.save() pos = AerialPosition(gps_position=gps, altitude_msl=0) pos.save() self.telem = UasTelemetry(user=self.user2, uas_position=pos, uas_heading=90) self.telem.save() self.telem.timestamp = dateutil.parser.parse( u'2016-10-01T00:00:00.0+00:00') self.telem.save()
def create_stationary_obstacle(self, lat, lon, radius, height): """Create a new StationaryObstacle model. Args: lat: Latitude of centroid lon: Longitude of centroid radius: Cylinder radius height: Cylinder height Returns: Saved StationaryObstacle """ gps = GpsPosition(latitude=lat, longitude=lon) gps.save() obstacle = StationaryObstacle(gps_position=gps, cylinder_radius=radius, cylinder_height=height) obstacle.save() return obstacle
def test_valid(self): """Test creating a valid target.""" with open(os.path.join(settings.BASE_DIR, 'auvsi_suas/fixtures/testdata/S.jpg')) as f: thumb = SimpleUploadedFile('thumb.jpg', f.read()) l = GpsPosition(latitude=38, longitude=-76) l.save() t = Target(user=self.user, target_type=TargetType.standard, location=l, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Test target', thumbnail=thumb) t.save()
def test_unicode(self): """Tests the unicode method executes.""" zone = FlyZone() zone.altitude_msl_min = 1 zone.altitude_msl_max = 2 zone.save() for _ in range(3): pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() apos = AerialPosition() apos.altitude_msl = 1000 apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = 10 wpt.save() zone.boundary_pts.add(wpt) self.assertTrue(zone.__unicode__())
def test_put_clear_shape(self): """PUT clear a field with None.""" l = GpsPosition(latitude=38, longitude=-76) l.save() t = Odlc(mission=self.mission, user=self.user, odlc_type=interop_api_pb2.Odlc.STANDARD, location=l, orientation=interop_api_pb2.Odlc.S, shape=interop_api_pb2.Odlc.SQUARE, shape_color=interop_api_pb2.Odlc.WHITE, alphanumeric='ABC', alphanumeric_color=interop_api_pb2.Odlc.BLACK, description='Test odlc') t.save() updated = { 'mission': self.mission.pk, 'type': 'STANDARD', } response = self.client.put(odlcs_id_url(args=[t.pk]), data=json.dumps(updated)) self.assertEqual(200, response.status_code) t.refresh_from_db() self.assertEqual(self.user, t.user) self.assertEqual(interop_api_pb2.Odlc.STANDARD, t.odlc_type) self.assertIsNone(t.location) self.assertIsNone(t.orientation) self.assertIsNone(t.shape) self.assertIsNone(t.shape_color) self.assertEqual('', t.alphanumeric) self.assertIsNone(t.alphanumeric_color) self.assertEqual('', t.description)
def evaluate_inputs(self, io_list): for (lon1, lat1, alt1, lon2, lat2, alt2, dist) in io_list: gps1 = GpsPosition(latitude=lat1, longitude=lon1) gps1.save() gps2 = GpsPosition(latitude=lat2, longitude=lon2) gps2.save() pos1 = AerialPosition(gps_position=gps1, altitude_msl=alt1) pos1.save() pos2 = AerialPosition(gps_position=gps2, altitude_msl=alt2) pos2.save() wpt1 = Waypoint(position=pos1) wpt2 = Waypoint(position=pos2) self.assertDistanceEqual(wpt1, wpt2, dist)
def test_evaluate_collision_with_uas(self): """Tests the collision with UAS method.""" # Get test data user = User.objects.create_user('testuser', '*****@*****.**', 'testpass') user.save() testdata = TESTDATA_MOVOBST_EVALCOLLISION (obst_rad, obst_speed, obst_pos, log_details) = testdata # Create the obstacle obst = MovingObstacle() obst.speed_avg = obst_speed obst.sphere_radius = obst_rad obst.save() for pos_id in xrange(len(obst_pos)): (lat, lon, alt) = obst_pos[pos_id] gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.gps_position = gpos apos.altitude_msl = alt apos.save() wpt = Waypoint() wpt.order = pos_id wpt.position = apos wpt.save() obst.waypoints.add(wpt) obst.save() # Create sets of logs epoch = timezone.now().replace(year=1970, month=1, day=1, hour=0, minute=0, second=0, microsecond=0) inside_logs = [] outside_logs = [] for (time_sec, inside_pos, outside_pos) in log_details: log_time = epoch + datetime.timedelta(seconds=time_sec) logs_pos = [(inside_pos, inside_logs), (outside_pos, outside_logs)] for (positions, log_list) in logs_pos: for (lat, lon, alt) in positions: log = self.create_log(lat, lon, alt, user, log_time) log_list.append(log) # Assert the obstacle correctly computes collisions log_collisions = [(True, inside_logs), (False, outside_logs)] for (inside, logs) in log_collisions: self.assertEqual(obst.evaluate_collision_with_uas(logs), inside) for log in logs: self.assertEqual(obst.evaluate_collision_with_uas([log]), inside)
def test_contains_pos(self): """Tests the inside obstacle method.""" # Form the test obstacle pos = GpsPosition(latitude=TESTDATA_STATOBST_CONTAINSPOS_OBJ[0], longitude=TESTDATA_STATOBST_CONTAINSPOS_OBJ[1]) pos.save() obst = StationaryObstacle( gps_position=pos, cylinder_radius=TESTDATA_STATOBST_CONTAINSPOS_OBJ[2], cylinder_height=TESTDATA_STATOBST_CONTAINSPOS_OBJ[3]) # Run test points against obstacle test_data = [(TESTDATA_STATOBST_CONTAINSPOS_INSIDE, True), (TESTDATA_STATOBST_CONTAINSPOS_OUTSIDE, False)] for (cur_data, cur_contains) in test_data: for (lat, lon, alt) in cur_data: pos = GpsPosition(latitude=lat, longitude=lon) pos.save() apos = AerialPosition(gps_position=pos, altitude_msl=alt) self.assertEqual(obst.contains_pos(apos), cur_contains)
def setUp(self): self.user = User.objects.create_user('testuser', '*****@*****.**', 'testpass') self.user.save() # Create an active mission. pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.is_active = True config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_odlc_pos = pos config.air_drop_pos = pos config.save() # Add a couple of stationary obstacles obst = self.create_stationary_obstacle( lat=38.142233, lon=-76.434082, radius=300, height=500) config.stationary_obstacles.add(obst) obst = self.create_stationary_obstacle( lat=38.442233, lon=-76.834082, radius=100, height=750) config.stationary_obstacles.add(obst) # And a couple of moving obstacles obst = self.create_moving_obstacle([ # (lat, lon, alt) (38.142233, -76.434082, 300), (38.141878, -76.425198, 700), ]) config.moving_obstacles.add(obst) obst = self.create_moving_obstacle([ # (lat, lon, alt) (38.145405, -76.428310, 100), (38.146582, -76.424099, 200), (38.144662, -76.427634, 300), (38.147729, -76.419185, 200), (38.147573, -76.420832, 100), (38.148522, -76.419507, 750), ]) config.moving_obstacles.add(obst) config.save() # Login response = self.client.post( login_url, {'username': '******', 'password': '******'}) self.assertEqual(200, response.status_code)
def test_evaluate_collision_with_uas(self): """Tests the collision with UAS method.""" # Create testing data user = User.objects.create_user('testuser', '*****@*****.**', 'testpass') user.save() (cyl_details, inside_pos, outside_pos) = TESTDATA_STATOBST_EVALCOLLISION (cyl_lat, cyl_lon, cyl_height, cyl_rad) = cyl_details gpos = GpsPosition(latitude=cyl_lat, longitude=cyl_lon) gpos.save() obst = StationaryObstacle(gps_position=gpos, cylinder_radius=cyl_rad, cylinder_height=cyl_height) obst.save() inside_logs = [] outside_logs = [] logs_to_create = [ (inside_pos, inside_logs), (outside_pos, outside_logs) ] for (positions, log_list) in logs_to_create: for (lat, lon, alt) in positions: gpos = GpsPosition(latitude=lat, longitude=lon) gpos.save() apos = AerialPosition(gps_position=gpos, altitude_msl=alt) apos.save() log = UasTelemetry(user=user, uas_position=apos, uas_heading=0) log.save() log_list.append(log) # Assert collisions correctly evaluated collisions = [(inside_logs, True), (outside_logs, False)] for (log_list, inside) in collisions: self.assertEqual( obst.evaluate_collision_with_uas(log_list), inside) for log in log_list: self.assertEqual( obst.evaluate_collision_with_uas([log]), inside)
def create_config(self): """Creates a dummy config for testing.""" pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.is_active = False config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_odlc_pos = pos config.air_drop_pos = pos return config
def setUp(self): super(TestTakeoffOrLandingEventModel, self).setUp() # Mission pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() apos = AerialPosition() apos.latitude = 10 apos.longitude = 100 apos.altitude_msl = 1000 apos.save() wpt = Waypoint() wpt.latitude = 10 wpt.longitude = 100 wpt.altitude_msl = 1000 wpt.order = 10 wpt.save() self.mission = MissionConfig() self.mission.home_pos = pos self.mission.lost_comms_pos = pos self.mission.emergent_last_known_pos = pos self.mission.off_axis_odlc_pos = pos self.mission.map_center_pos = pos self.mission.map_height_ft = 1 self.mission.air_drop_pos = pos self.mission.ugv_drive_pos = pos self.mission.save() self.mission.mission_waypoints.add(wpt) self.mission.search_grid_points.add(wpt) self.mission.save() # Mission 2 self.mission2 = MissionConfig() self.mission2.home_pos = pos self.mission2.lost_comms_pos = pos self.mission2.emergent_last_known_pos = pos self.mission2.off_axis_odlc_pos = pos self.mission2.map_center_pos = pos self.mission2.map_height_ft = 1 self.mission2.air_drop_pos = pos self.mission2.ugv_drive_pos = pos self.mission2.save() self.mission2.mission_waypoints.add(wpt) self.mission2.search_grid_points.add(wpt) self.mission2.save() self.ten_minutes = datetime.timedelta(minutes=10)
def setUp(self): """Setup a single mission to test live kml with.""" super(TestGenerateLiveKMLNoFixture, self).setUp() pos = GpsPosition() pos.latitude = 10 pos.longitude = 10 pos.save() config = MissionConfig() config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_odlc_pos = pos config.air_drop_pos = pos config.save() self.config = config
def test_contains_many_pos(self): """Tests the contains_many_pos method.""" for (zone, test_pos) in self.testdata_containspos: aerial_pos_list = [] expected_results = [] for ((lat, lon, alt), inside) in test_pos: gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = gpos aerial_pos_list.append(apos) expected_results.append(inside) self.assertEqual(zone.contains_many_pos(aerial_pos_list), expected_results)
def setUp(self): pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() wpt = Waypoint() wpt.order = 10 wpt.latitude = 10 wpt.longitude = 100 wpt.altitude_msl = 1000 wpt.save() config = MissionConfig() config.home_pos = pos config.lost_comms_pos = pos config.emergent_last_known_pos = pos config.off_axis_odlc_pos = pos config.map_center_pos = pos config.map_height_ft = 1 config.air_drop_pos = pos config.ugv_drive_pos = pos config.save() config.mission_waypoints.add(wpt) config.search_grid_points.add(wpt) config.save() user = User.objects.create_user('user', '*****@*****.**', 'pass') self.feedback = MissionJudgeFeedback( mission=config, user=user, flight_time=datetime.timedelta(seconds=1), post_process_time=datetime.timedelta(seconds=2), used_timeout=True, min_auto_flight_time=True, safety_pilot_takeovers=3, out_of_bounds=6, unsafe_out_of_bounds=7, things_fell_off_uas=False, crashed=False, air_drop_accuracy=interop_admin_api_pb2.MissionJudgeFeedback. WITHIN_05_FT, ugv_drove_to_location=False, operational_excellence_percent=9) self.feedback.save()
def setUp(self): # Mission pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() wpt = Waypoint() wpt.order = 10 wpt.latitude = 10 wpt.longitude = 100 wpt.altitude_msl = 0 wpt.save() self.mission = MissionConfig() self.mission.home_pos = pos self.mission.lost_comms_pos = pos self.mission.emergent_last_known_pos = pos self.mission.off_axis_odlc_pos = pos self.mission.map_center_pos = pos self.mission.map_height_ft = 1 self.mission.air_drop_pos = pos self.mission.ugv_drive_pos = pos self.mission.save() self.mission.mission_waypoints.add(wpt) self.mission.search_grid_points.add(wpt) self.mission.save() # Mission 2 self.mission2 = MissionConfig() self.mission2.home_pos = pos self.mission2.lost_comms_pos = pos self.mission2.emergent_last_known_pos = pos self.mission2.off_axis_odlc_pos = pos self.mission2.map_center_pos = pos self.mission2.map_height_ft = 1 self.mission2.air_drop_pos = pos self.mission2.ugv_drive_pos = pos self.mission2.save() self.mission2.mission_waypoints.add(wpt) self.mission2.search_grid_points.add(wpt) self.mission2.save() self.user = User.objects.create_user('testuser', '*****@*****.**', 'testpass')
def setUp(self): pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() apos = AerialPosition() apos.altitude_msl = 1000 apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = 10 wpt.save() config = MissionConfig() config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_odlc_pos = pos config.air_drop_pos = pos config.save() config.mission_waypoints.add(wpt) config.search_grid_points.add(wpt) config.save() user = User.objects.create_user('user', '*****@*****.**', 'pass') self.feedback = MissionJudgeFeedback( mission=config, user=user, flight_time=datetime.timedelta(seconds=1), post_process_time=datetime.timedelta(seconds=2), used_timeout=True, min_auto_flight_time=True, safety_pilot_takeovers=3, waypoints_captured=5, out_of_bounds=6, unsafe_out_of_bounds=7, things_fell_off_uas=False, crashed=False, air_delivery_accuracy_ft=8, operational_excellence_percent=9) self.feedback.save()
def test_unicode(self): """Tests the unicode method executes.""" obst = MovingObstacle() obst.speed_avg = 10 obst.sphere_radius = 100 obst.save() for _ in range(3): pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() apos = AerialPosition() apos.altitude_msl = 1000 apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = 10 wpt.save() obst.waypoints.add(wpt) self.assertTrue(obst.__unicode__())
def test_contains_pos(self): """Tests the inside obstacle method.""" # Form the test obstacle obst = MovingObstacle() obst.sphere_radius = TESTDATA_MOVOBST_CONTAINSPOS_OBJ[2] # Run test points against obstacle test_data = [(TESTDATA_MOVOBST_CONTAINSPOS_INSIDE, True), (TESTDATA_MOVOBST_CONTAINSPOS_OUTSIDE, False)] for (cur_data, cur_contains) in test_data: for (lat, lon, alt) in cur_data: gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.gps_position = gpos apos.altitude_msl = alt self.assertEqual( obst.contains_pos(TESTDATA_MOVOBST_CONTAINSPOS_OBJ[0], TESTDATA_MOVOBST_CONTAINSPOS_OBJ[1], TESTDATA_MOVOBST_CONTAINSPOS_OBJ[3], apos), cur_contains)
def test_unicode(self): """Tests the unicode method executes.""" pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() apos = AerialPosition() apos.altitude_msl = 1000 apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = 10 wpt.save() config = MissionConfig() config.home_pos = pos config.emergent_last_known_pos = pos config.off_axis_target_pos = pos config.air_drop_pos = pos config.save() config.mission_waypoints.add(wpt) config.search_grid_points.add(wpt) config.save() self.assertTrue(config.__unicode__())
def test_out_of_bounds(self): """Tests the UAS out of bounds method.""" (zone_details, uas_details) = TESTDATA_FLYZONE_EVALBOUNDS # Create FlyZone objects zones = [] for (alt_min, alt_max, wpts) in zone_details: zone = FlyZone() zone.altitude_msl_min = alt_min zone.altitude_msl_max = alt_max zone.save() for wpt_id in xrange(len(wpts)): (lat, lon) = wpts[wpt_id] gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.gps_position = gpos apos.altitude_msl = 0 apos.save() wpt = Waypoint() wpt.order = wpt_id wpt.position = apos wpt.save() zone.boundary_pts.add(wpt) zone.save() zones.append(zone) # For each user, validate time out of bounds user_id = 0 epoch = timezone.now().replace(year=1970, month=1, day=1, hour=0, minute=0, second=0, microsecond=0) for exp_violations, exp_out_of_bounds_time, log_details in uas_details: # Create the logs user = User.objects.create_user('testuser%d' % user_id, '*****@*****.**', 'testpass') user_id += 1 uas_logs = [] for (lat, lon, alt, timestamp) in log_details: gpos = GpsPosition() gpos.latitude = lat gpos.longitude = lon gpos.save() apos = AerialPosition() apos.gps_position = gpos apos.altitude_msl = alt apos.save() log = UasTelemetry() log.user = user log.uas_position = apos log.uas_heading = 0 log.save() log.timestamp = epoch + datetime.timedelta(seconds=timestamp) log.save() uas_logs.append(log) # Assert out of bounds time matches expected num_violations, out_of_bounds_time = \ FlyZone.out_of_bounds(zones, uas_logs) self.assertEqual(num_violations, exp_violations) self.assertAlmostEqual(out_of_bounds_time.total_seconds(), exp_out_of_bounds_time)
from auvsi_suas.models.gps_position import GpsPosition from auvsi_suas.models.mission_config import MissionConfig # Print all mission objects. print MissionConfig.objects.all() # Create and save a GPS position. gpos = GpsPosition(latitudel=38.145335, longitude=-76.427512) gpos.save()
def test_get_waypoint_travel_time(self): """Tests travel time calc.""" test_spds = [1, 10, 100, 500] for (lon2, lat2, lon1, lat1, dist_km) in TESTDATA_COMPETITION_DIST: dist_ft = units.kilometers_to_feet(dist_km) for speed in test_spds: speed_fps = units.knots_to_feet_per_second(speed) time = dist_ft / speed_fps gpos1 = GpsPosition() gpos1.latitude = lat1 gpos1.longitude = lon1 gpos1.save() apos1 = AerialPosition() apos1.gps_position = gpos1 apos1.altitude_msl = 0 apos1.save() wpt1 = Waypoint() wpt1.position = apos1 gpos2 = GpsPosition() gpos2.latitude = lat2 gpos2.longitude = lon2 gpos2.save() apos2 = AerialPosition() apos2.gps_position = gpos2 apos2.altitude_msl = 0 apos2.save() wpt2 = Waypoint() wpt2.position = apos2 waypoints = [wpt1, wpt2] obstacle = MovingObstacle() obstacle.speed_avg = speed self.assertTrue( self.eval_travel_time( obstacle.get_waypoint_travel_time(waypoints, 0, 1), time))
def setUp(self): """Setup the test case.""" super(TestTargetEvaluator, self).setUp() self.maxDiff = None self.user = User.objects.create_user('user', '*****@*****.**', 'pass') l1 = GpsPosition(latitude=38, longitude=-76) l1.save() l2 = GpsPosition(latitude=38.0003, longitude=-76) l2.save() l3 = GpsPosition(latitude=-38, longitude=76) l3.save() event = MissionClockEvent(user=self.user, team_on_clock=True, team_on_timeout=False) event.save() event = TakeoffOrLandingEvent(user=self.user, uas_in_air=True) event.save() # A target worth full points. self.submit1 = Target(user=self.user, target_type=TargetType.standard, location=l1, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Submit test target 1', autonomous=True, thumbnail_approved=True) self.submit1.save() self.real1 = Target(user=self.user, target_type=TargetType.standard, location=l1, orientation=Orientation.s, shape=Shape.square, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Real target 1') self.real1.save() event = MissionClockEvent(user=self.user, team_on_clock=False, team_on_timeout=False) event.save() # A target worth less than full points. self.submit2 = Target(user=self.user, target_type=TargetType.standard, location=l1, orientation=Orientation.n, shape=Shape.circle, background_color=Color.white, # alphanumeric set below alphanumeric_color=Color.black, description='Submit test target 2', autonomous=False, thumbnail_approved=True) self.submit2.save() self.real2 = Target(user=self.user, target_type=TargetType.standard, location=l2, orientation=Orientation.s, shape=Shape.triangle, background_color=Color.white, alphanumeric='ABC', alphanumeric_color=Color.black, description='Real test target 2') self.real2.save() # A target worth no points, so unmatched. self.submit3 = Target(user=self.user, target_type=TargetType.standard, location=l1, orientation=Orientation.nw, shape=Shape.pentagon, background_color=Color.gray, alphanumeric='XYZ', alphanumeric_color=Color.orange, description='Incorrect description', autonomous=False, thumbnail_approved=True) self.submit3.save() self.real3 = Target(user=self.user, target_type=TargetType.standard, orientation=Orientation.e, shape=Shape.semicircle, background_color=Color.yellow, alphanumeric='LMN', # alphanumeric_color set below location=l3, description='Test target 3') self.real3.save() # Targets without approved image may still match. self.submit4 = Target(user=self.user, target_type=TargetType.emergent, location=l1, description='Test target 4', autonomous=False, thumbnail_approved=False) self.submit4.save() self.real4 = Target(user=self.user, target_type=TargetType.emergent, location=l1, description='Test target 4') self.real4.save() # A target without location worth fewer points. self.submit5 = Target(user=self.user, target_type=TargetType.standard, orientation=Orientation.n, shape=Shape.trapezoid, background_color=Color.purple, alphanumeric='PQR', alphanumeric_color=Color.blue, description='Test target 5', autonomous=False, thumbnail_approved=True) self.submit5.save() self.real5 = Target(user=self.user, target_type=TargetType.standard, location=l1, orientation=Orientation.n, shape=Shape.trapezoid, background_color=Color.purple, alphanumeric='PQR', alphanumeric_color=Color.blue, description='Test target 5') self.real5.save() event = TakeoffOrLandingEvent(user=self.user, uas_in_air=False) event.save() # submit2 updated after landing. self.submit2.alphanumeric = 'ABC' self.submit2.save() self.submit3.alphanumeric_color = Color.yellow self.submit3.save() self.submitted_targets = [self.submit5, self.submit4, self.submit3, self.submit2, self.submit1] self.real_targets = [self.real1, self.real2, self.real3, self.real4, self.real5] self.real_matched_targets = [self.real1, self.real2, self.real4, self.real5]
def test_satisfied_waypoints(self): """Tests the evaluation of waypoints method.""" # Create mission config gpos = GpsPosition() gpos.latitude = 10 gpos.longitude = 10 gpos.save() waypoints = self.waypoints_from_data([ (38, -76, 100), (39, -77, 200), (40, -78, 0), ]) # Only first is valid. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 40, -78, 600, 0), (2, 37, -75, 40, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0, closest_for_mission_ft=170), WaypointEvaluation(id=2, score_ratio=0, closest_for_mission_ft=600) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # First and last are valid. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 40, -78, 600, 0), (2, 40, -78, 40, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0, closest_for_mission_ft=170), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Hit all. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 39, -77, 180, 0), (2, 40, -78, 40, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Only hit the first waypoint on run one, hit all on run two. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 40, -78, 600, 0), (2, 37, -75, 40, 0), # Run two: (3, 38, -76, 140, 0), (4, 39, -77, 180, 0), (5, 40, -78, 40, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Hit all on run one, only hit the first waypoint on run two. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 39, -77, 180, 0), (2, 40, -78, 40, 0), # Run two: (3, 38, -76, 140, 0), (4, 40, -78, 600, 0), (5, 37, -75, 40, 0) ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Keep flying after hitting all waypoints. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 39, -77, 180, 0), (2, 40, -78, 40, 0), (3, 30.1, -78.1, 100, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Hit all in first run, but second is higher scoring. logs = self.create_uas_logs([ (0, 38, -76, 140, 0), (1, 39, -77, 180, 0), (2, 40, -78, 60, 0), # Run two: (3, 38, -76, 100, 0), (4, 39, -77, 200, 0), (5, 40, -78, 110, 0) ]) expect = [ WaypointEvaluation(id=0, score_ratio=1, closest_for_scored_approach_ft=0, closest_for_mission_ft=0), WaypointEvaluation(id=1, score_ratio=1, closest_for_scored_approach_ft=0, closest_for_mission_ft=0), WaypointEvaluation(id=2, score_ratio=0, closest_for_mission_ft=60) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Restart waypoint path in the middle, use path in between points. waypoints = self.waypoints_from_data([ (38, -76, 100), (39, -77, 200), (40, -78, 0), ]) logs = self.create_uas_logs([ (0, 38, -76, 140, 0), # Use (1, 39, -77, 180, 0), # Use # Restart: (2, 38, -76, 70, 0), (3, 39, -77, 150, 0), (4, 40, -78, 10, 0), # Use ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=30), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.9, closest_for_scored_approach_ft=10, closest_for_mission_ft=10) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs)) # Sanity check waypoint scoring with interpolation. waypoints = self.waypoints_from_data([ (38, -76, 70), (38, -76, 110), ]) logs = self.create_uas_logs([ (0, 38, -76, 0, 0), (1, 38, -76, 200, 0), ]) expect = [ WaypointEvaluation(id=0, score_ratio=0.9, closest_for_scored_approach_ft=10, closest_for_mission_ft=10), WaypointEvaluation(id=1, score_ratio=0.9, closest_for_scored_approach_ft=10, closest_for_mission_ft=10) ] self.assertSatisfiedWaypoints( expect, UasTelemetry.satisfied_waypoints(gpos, waypoints, logs))
def test_satisfied_waypoints(self): """Tests the evaluation of waypoints method.""" # Create mission config gpos = GpsPosition() gpos.latitude = 10 gpos.longitude = 10 gpos.save() # Create waypoints for testing. waypoints = self.waypoints_from_data([(38, -76, 100), (39, -77, 200), ( 40, -78, 0)]) # Create UAS telemetry logs # Only first is valid. entries = [(38, -76, 140), (40, -78, 600), (37, -75, 40)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0, closest_for_mission_ft=460785.17), WaypointEvaluation(id=2, score_ratio=0)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # First and last are valid, but missed second, so third doesn't count. entries = [(38, -76, 140), (40, -78, 600), (40, -78, 40)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0, closest_for_mission_ft=460785.03), WaypointEvaluation(id=2, score_ratio=0)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Hit all. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 40)] expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40)] logs = self.create_uas_logs(self.user, entries) self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Only hit the first waypoint on run one, hit all on run two. entries = [(38, -76, 140), (40, -78, 600), (37, -75, 40), # Run two: (38, -76, 140), (39, -77, 180), (40, -78, 40)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Hit all on run one, only hit the first waypoint on run two. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 40), # Run two: (38, -76, 140), (40, -78, 600), (37, -75, 40)] expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40)] logs = self.create_uas_logs(self.user, entries) self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Keep flying after hitting all waypoints. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 40), (30.1, -78.1, 100)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40), WaypointEvaluation(id=1, score_ratio=0.8, closest_for_scored_approach_ft=20, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.6, closest_for_scored_approach_ft=40, closest_for_mission_ft=40)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Hit all in first run, but second is higher scoring. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 60), # Run two: (38, -76, 100), (39, -77, 200), (40, -78, 110)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=1, closest_for_scored_approach_ft=0, closest_for_mission_ft=0), WaypointEvaluation(id=1, score_ratio=1, closest_for_scored_approach_ft=0, closest_for_mission_ft=0), WaypointEvaluation(id=2, score_ratio=0, closest_for_mission_ft=60)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs)) # Restart waypoint path in the middle. waypoints = self.waypoints_from_data([(38, -76, 100), (39, -77, 200), ( 40, -78, 0)]) entries = [(38, -76, 140), (39, -77, 180), # Restart: (38, -76, 70), (39, -77, 150), (40, -78, 10)] logs = self.create_uas_logs(self.user, entries) expect = [WaypointEvaluation(id=0, score_ratio=0.7, closest_for_scored_approach_ft=30, closest_for_mission_ft=30), WaypointEvaluation(id=1, score_ratio=0.5, closest_for_scored_approach_ft=50, closest_for_mission_ft=20), WaypointEvaluation(id=2, score_ratio=0.9, closest_for_scored_approach_ft=10, closest_for_mission_ft=10)] self.assertSatisfiedWaypoints(expect, UasTelemetry.satisfied_waypoints( gpos, waypoints, logs))
def create_data(self): """Create a basic sample dataset.""" self.user1 = User.objects.create_user('user1', '*****@*****.**', 'testpass') self.user1.save() self.user2 = User.objects.create_user('user2', '*****@*****.**', 'testpass') self.user2.save() # Mission pos = GpsPosition() pos.latitude = 10 pos.longitude = 100 pos.save() wpt = Waypoint() wpt.order = 10 wpt.latitude = 10 wpt.longitude = 100 wpt.altitude_msl = 1000 wpt.save() self.mission = MissionConfig() self.mission.home_pos = pos self.mission.lost_comms_pos = pos self.mission.emergent_last_known_pos = pos self.mission.off_axis_odlc_pos = pos self.mission.map_center_pos = pos self.mission.map_height_ft = 1 self.mission.air_drop_pos = pos self.mission.ugv_drive_pos = pos self.mission.save() self.mission.mission_waypoints.add(wpt) self.mission.search_grid_points.add(wpt) self.mission.save() # user1 is flying event = TakeoffOrLandingEvent(user=self.user1, mission=self.mission, uas_in_air=True) event.save() # user2 has landed event = TakeoffOrLandingEvent(user=self.user2, mission=self.mission, uas_in_air=True) event.save() event = TakeoffOrLandingEvent(user=self.user2, mission=self.mission, uas_in_air=False) event.save() # user2 is active self.timestamp = timezone.now() self.telem = UasTelemetry(user=self.user2, latitude=38.6462, longitude=-76.2452, altitude_msl=0, uas_heading=90) self.telem.save() self.telem.timestamp = dateutil.parser.parse( u'2016-10-01T00:00:00.0+00:00') self.telem.save()
def post(self, request): try: data = json.loads(request.body) except ValueError: return HttpResponseBadRequest('Request body is not valid JSON.') # Must be a json dictionary. if not isinstance(data, dict): return HttpResponseBadRequest('Request body not a JSON dict.') # Odlc type is required. if 'type' not in data: return HttpResponseBadRequest('Odlc type required.') # Team id can only be specified if superuser. user = request.user if 'team_id' in data: if request.user.is_superuser: user = User.objects.get(username=data['team_id']) else: return HttpResponseForbidden( 'Non-admin users cannot send team_id') latitude = data.get('latitude') longitude = data.get('longitude') # Require zero or both of latitude and longitude. if (latitude is not None and longitude is None) or \ (latitude is None and longitude is not None): return HttpResponseBadRequest( 'Either none or both of latitude and longitude required.') # Cannot submit JSON with actionable_override if not superuser. if 'actionable_override' in data and not request.user.is_superuser: return HttpResponseForbidden( 'Non-admin users cannot submit actionable override.') try: data = normalize_data(data) except ValueError as e: return HttpResponseBadRequest(str(e)) l = None if latitude is not None and longitude is not None: l = GpsPosition(latitude=data['latitude'], longitude=data['longitude']) l.save() # Use the dictionary get() method to default non-existent values to None. t = Odlc(user=user, odlc_type=data['type'], location=l, orientation=data.get('orientation'), shape=data.get('shape'), background_color=data.get('background_color'), alphanumeric=data.get('alphanumeric', ''), alphanumeric_color=data.get('alphanumeric_color'), description=data.get('description', ''), autonomous=data.get('autonomous', False), actionable_override=data.get('actionable_override', False)) t.save() return JsonResponse(t.json(is_superuser=request.user.is_superuser), status=201)
def put(self, request, pk): try: odlc = find_odlc(request, int(pk)) except Odlc.DoesNotExist: return HttpResponseNotFound('Odlc %s not found' % pk) except ValueError as e: return HttpResponseForbidden(str(e)) try: data = json.loads(request.body) except ValueError: return HttpResponseBadRequest('Request body is not valid JSON.') # Must be a json dictionary. if not isinstance(data, dict): return HttpResponseBadRequest('Request body not a JSON dict.') # Cannot submit JSON with actionable_override if not superuser. if 'actionable_override' in data and not request.user.is_superuser: return HttpResponseForbidden( 'Non-admin users cannot submit actionable override.') try: data = normalize_data(data) except ValueError as e: return HttpResponseBadRequest(str(e)) # We update any of the included values, except id and user if 'type' in data: odlc.odlc_type = data['type'] if 'orientation' in data: odlc.orientation = data['orientation'] if 'shape' in data: odlc.shape = data['shape'] if 'background_color' in data: odlc.background_color = data['background_color'] if 'alphanumeric' in data: odlc.alphanumeric = data['alphanumeric'] if 'alphanumeric_color' in data: odlc.alphanumeric_color = data['alphanumeric_color'] if 'description' in data: odlc.description = data['description'] if 'autonomous' in data: odlc.autonomous = data['autonomous'] if 'actionable_override' in data: odlc.actionable_override = data['actionable_override'] # Location is special because it is in a GpsPosition model # If lat/lon exist and are None, the user wants to clear them. # If they exist and are not None, the user wants to update/add them. # If they don't exist, the user wants to leave them alone. clear_lat = False clear_lon = False update_lat = False update_lon = False if 'latitude' in data: if data['latitude'] is None: clear_lat = True else: update_lat = True if 'longitude' in data: if data['longitude'] is None: clear_lon = True else: update_lon = True if (clear_lat and not clear_lon) or (not clear_lat and clear_lon): # Location must be cleared entirely, we can't clear just lat or # just lon. return HttpResponseBadRequest( 'Only none or both of latitude and longitude can be cleared.') if clear_lat and clear_lon: odlc.location = None elif update_lat or update_lon: if odlc.location is not None: # We can directly update individual components if update_lat: odlc.location.latitude = data['latitude'] if update_lon: odlc.location.longitude = data['longitude'] odlc.location.save() else: # We need a new GpsPosition, this requires both lat and lon if not update_lat or not update_lon: return HttpResponseBadRequest( 'Either none or both of latitude and longitude required.' ) l = GpsPosition(latitude=data['latitude'], longitude=data['longitude']) l.save() odlc.location = l odlc.description_approved = None if not request.user.is_superuser: odlc.update_last_modified() odlc.save() return JsonResponse(odlc.json(is_superuser=request.user.is_superuser))
def test_satisfied_waypoints(self): """Tests the evaluation of waypoints method.""" # Create mission config gpos = GpsPosition() gpos.latitude = 10 gpos.longitude = 10 gpos.save() config = MissionConfig() config.home_pos = gpos config.emergent_last_known_pos = gpos config.off_axis_target_pos = gpos config.air_drop_pos = gpos config.save() # Create waypoints for config waypoints = [(38, -76, 100), (39, -77, 200), (40, -78, 0)] for i, waypoint in enumerate(waypoints): (lat, lon, alt) = waypoint pos = GpsPosition() pos.latitude = lat pos.longitude = lon pos.save() apos = AerialPosition() apos.altitude_msl = alt apos.gps_position = pos apos.save() wpt = Waypoint() wpt.position = apos wpt.order = i wpt.save() config.mission_waypoints.add(wpt) config.save() # Create UAS telemetry logs user = User.objects.create_user('testuser', '*****@*****.**', 'testpass') # Only first is valid. entries = [(38, -76, 140), (40, -78, 600), (37, -75, 40)] expect = ({0: 40}, {0: 0.6, 1: 0.0, 2: 0.0}, {0: 40, 1: 460785.17}) logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # First and last are valid, but missed second, so third doesn't count. entries = [(38, -76, 140), (40, -78, 600), (40, -78, 40)] expect = ({0: 40}, {0: 0.6, 1: 0.0, 2: 0.0}, {0: 40, 1: 460785.03}) logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Hit all. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 40)] expect = ({0: 40, 1: 20, 2: 40}, {0: 0.6, 1: 0.8, 2: 0.6}, {0: 40, 1: 20, 2: 40}) # yapf: disable logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Only hit the first waypoint on run one, hit all on run two. entries = [ (38, -76, 140), (40, -78, 600), (37, -75, 40), # Run two: (38, -76, 140), (39, -77, 180), (40, -78, 40) ] expect = ({0: 40, 1: 20, 2: 40}, {0: 0.6, 1: 0.8, 2: 0.6}, {0: 40, 1: 20, 2: 40}) # yapf: disable logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Hit all on run one, only hit the first waypoint on run two. entries = [ (38, -76, 140), (39, -77, 180), (40, -78, 40), # Run two: (38, -76, 140), (40, -78, 600), (37, -75, 40) ] expect = ({0: 40, 1: 20, 2: 40}, {0: 0.6, 1: 0.8, 2: 0.6}, {0: 40, 1: 20, 2: 40}) # yapf: disable logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Keep flying after hitting all waypoints. entries = [(38, -76, 140), (39, -77, 180), (40, -78, 40), (30.1, -78.1, 100)] expect = ({0: 40, 1: 20, 2: 40}, {0: 0.6, 1: 0.8, 2: 0.6}, {0: 40, 1: 20, 2: 40}) # yapf: disable logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Hit all in first run, but second is higher scoring. entries = [ (38, -76, 140), (39, -77, 180), (40, -78, 60), # Run two: (38, -76, 100), (39, -77, 200), (40, -78, 110) ] expect = ({0: 0, 1: 0}, {0: 1, 1: 1, 2: 0}, {0: 0, 1: 0, 2: 60}) logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs)) # Restart waypoint path in the middle. waypoints = [(38, -76, 100), (39, -77, 200), (40, -78, 0)] entries = [ (38, -76, 140), (39, -77, 180), # Restart: (38, -76, 70), (39, -77, 150), (40, -78, 10) ] expect = ({0: 30, 1: 50, 2: 10}, {0: 0.7, 1: 0.5, 2: 0.9}, {0: 30, 1: 20, 2: 10}) # yapf: disable logs = self.create_uas_logs(user, entries) self.assertSatisfiedWaypoints(expect, config.satisfied_waypoints(logs))