def get(self, request): kml = Kml(name='AUVSI SUAS LIVE Flight Data') kml_mission = kml.newfolder(name='Missions') (mission, err) = active_mission() if err: return err MissionConfig.kml_all(kml_mission, [mission]) kml_flyzone = kml.newfolder(name='Fly Zones') FlyZone.kml_all(kml_flyzone) parameters = '?sessionid={}'.format(request.COOKIES['sessionid']) uri = request.build_absolute_uri( '/auvsi_admin/update.kml') + parameters netlink = kml.newnetworklink(name="Live Data") netlink.link.href = uri netlink.link.refreshmode = RefreshMode.oninterval netlink.link.refreshinterval = 0.5 response = HttpResponse(kml.kml()) response['Content-Type'] = 'application/vnd.google-earth.kml+xml' response['Content-Disposition'] = 'attachment; filename=live.kml' response['Content-Length'] = str(len(response.content)) return response
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_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 range(len(wpts)): (lat, lon) = wpts[wpt_id] wpt = Waypoint() wpt.order = wpt_id wpt.latitude = lat wpt.longitude = lon wpt.altitude_msl = 0 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: log = UasTelemetry() log.user = user log.latitude = lat log.longitude = lon log.altitude_msl = alt 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)
def get(self, request): kml = Kml(name='AUVSI SUAS Flight Data') kml_teams = kml.newfolder(name='Teams') kml_mission = kml.newfolder(name='Missions') users = User.objects.all() for user in users: # Ignore admins if user.is_superuser: continue UasTelemetry.kml(user=user, logs=UasTelemetry.by_user(user), kml=kml_teams, kml_doc=kml.document) MissionConfig.kml_all(kml_mission) kml_flyzone = kml.newfolder(name='Fly Zones') FlyZone.kml_all(kml_flyzone) response = HttpResponse(kml.kml()) response['Content-Type'] = 'application/vnd.google-earth.kml+xml' response['Content-Disposition'] = 'attachment; filename=mission.kml' response['Content-Length'] = str(len(response.content)) return response
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_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, exp_out_of_bounds_time)
def generate_feedback(mission_config, user, team_eval): """Generates mission feedback for the given team and mission. Args: mission_config: The mission to evaluate the team against. user: The team user object for which to evaluate and provide feedback. team_eval: The team evaluation to fill. """ feedback = team_eval.feedback # Calculate the total mission clock time. missions = MissionClockEvent.missions(user) mission_clock_time = datetime.timedelta(seconds=0) for mission in missions: duration = mission.duration() if duration is None: team_eval.warnings.append('Infinite mission clock.') else: mission_clock_time += duration feedback.mission_clock_time_sec = mission_clock_time.total_seconds() # Calculate total time in air. flight_periods = TakeoffOrLandingEvent.flights(user) if flight_periods: flight_time = reduce(lambda x, y: x + y, [p.duration() for p in flight_periods]) feedback.flight_time_sec = flight_time.total_seconds() else: feedback.flight_time_sec = 0 # Find the user's flights. for period in flight_periods: if period.duration() is None: team_eval.warnings.append('Infinite flight period.') uas_period_logs = [ UasTelemetry.dedupe(logs) for logs in UasTelemetry.by_time_period(user, flight_periods) ] uas_logs = list(itertools.chain.from_iterable(uas_period_logs)) if not uas_logs: team_eval.warnings.append('No UAS telemetry logs.') # Determine interop telemetry rates. telem_max, telem_avg = UasTelemetry.rates(user, flight_periods, time_period_logs=uas_period_logs) if telem_max: feedback.uas_telemetry_time_max_sec = telem_max if telem_avg: feedback.uas_telemetry_time_avg_sec = telem_avg # Determine if the uas went out of bounds. This must be done for # each period individually so time between periods isn't counted as # out of bounds time. Note that this calculates reported time out # of bounds, not actual or possible time spent out of bounds. out_of_bounds = datetime.timedelta(seconds=0) feedback.boundary_violations = 0 for logs in uas_period_logs: bv, bt = FlyZone.out_of_bounds(mission_config.fly_zones.all(), logs) feedback.boundary_violations += bv out_of_bounds += bt feedback.out_of_bounds_time_sec = out_of_bounds.total_seconds() # Determine if the uas hit the waypoints. feedback.waypoints.extend( UasTelemetry.satisfied_waypoints( mission_config.home_pos, mission_config.mission_waypoints.order_by('order'), uas_logs)) # Evaluate the object detections. user_odlcs = Odlc.objects.filter(user=user).all() evaluator = OdlcEvaluator(user_odlcs, mission_config.odlcs.all()) feedback.odlc.CopyFrom(evaluator.evaluate()) # Determine collisions with stationary and moving obstacles. for obst in mission_config.stationary_obstacles.all(): obst_eval = feedback.stationary_obstacles.add() obst_eval.id = obst.pk obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs) for obst in mission_config.moving_obstacles.all(): obst_eval = feedback.moving_obstacles.add() obst_eval.id = obst.pk obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs) # Add judge feedback. try: judge_feedback = MissionJudgeFeedback.objects.get( mission=mission_config.pk, user=user.pk) feedback.judge.CopyFrom(judge_feedback.proto()) except MissionJudgeFeedback.DoesNotExist: team_eval.warnings.append('No MissionJudgeFeedback for team.') # Sanity check mission time. judge_mission_clock = (feedback.judge.flight_time_sec + feedback.judge.post_process_time_sec) if abs(feedback.mission_clock_time_sec - judge_mission_clock) > 30: team_eval.warnings.append( 'Mission clock differs between interop and judge.')
def generate_feedback(mission_config, user, team_eval): """Generates mission feedback for the given team and mission. Args: mission_config: The mission to evaluate the team against. user: The team user object for which to evaluate and provide feedback. team_eval: The team evaluation to fill. """ feedback = team_eval.feedback # Calculate the total mission clock time. missions = MissionClockEvent.missions(user) mission_clock_time = datetime.timedelta(seconds=0) for mission in missions: duration = mission.duration() if duration is None: team_eval.warnings.append('Infinite mission clock.') else: mission_clock_time += duration feedback.mission_clock_time_sec = mission_clock_time.total_seconds() # Calculate total time in air. flight_periods = TakeoffOrLandingEvent.flights(user) if flight_periods: flight_time = reduce(lambda x, y: x + y, [p.duration() for p in flight_periods]) feedback.flight_time_sec = flight_time.total_seconds() else: feedback.flight_time_sec = 0 # Find the user's flights. for period in flight_periods: if period.duration() is None: team_eval.warnings.append('Infinite flight period.') uas_period_logs = [ UasTelemetry.dedupe(logs) for logs in UasTelemetry.by_time_period(user, flight_periods) ] uas_logs = list(itertools.chain.from_iterable(uas_period_logs)) if not uas_logs: team_eval.warnings.append('No UAS telemetry logs.') # Determine interop telemetry rates. telem_max, telem_avg = UasTelemetry.rates(user, flight_periods, time_period_logs=uas_period_logs) if telem_max: feedback.uas_telemetry_time_max_sec = telem_max if telem_avg: feedback.uas_telemetry_time_avg_sec = telem_avg # Determine if the uas went out of bounds. This must be done for # each period individually so time between periods isn't counted as # out of bounds time. Note that this calculates reported time out # of bounds, not actual or possible time spent out of bounds. out_of_bounds = datetime.timedelta(seconds=0) feedback.boundary_violations = 0 for logs in uas_period_logs: bv, bt = FlyZone.out_of_bounds(mission_config.fly_zones.all(), logs) feedback.boundary_violations += bv out_of_bounds += bt feedback.out_of_bounds_time_sec = out_of_bounds.total_seconds() # Determine if the uas hit the waypoints. feedback.waypoints.extend(UasTelemetry.satisfied_waypoints( mission_config.home_pos, mission_config.mission_waypoints.order_by( 'order'), uas_logs)) # Evaluate the targets. user_targets = Target.objects.filter(user=user).all() evaluator = TargetEvaluator(user_targets, mission_config.targets.all()) feedback.target.CopyFrom(evaluator.evaluate()) # Determine collisions with stationary and moving obstacles. for obst in mission_config.stationary_obstacles.all(): obst_eval = feedback.stationary_obstacles.add() obst_eval.id = obst.pk obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs) for obst in mission_config.moving_obstacles.all(): obst_eval = feedback.moving_obstacles.add() obst_eval.id = obst.pk obst_eval.hit = obst.evaluate_collision_with_uas(uas_logs) # Add judge feedback. try: judge_feedback = MissionJudgeFeedback.objects.get( mission=mission_config.pk, user=user.pk) feedback.judge.CopyFrom(judge_feedback.proto()) except MissionJudgeFeedback.DoesNotExist: team_eval.warnings.append('No MissionJudgeFeedback for team.') # Sanity check mission time. judge_mission_clock = ( feedback.judge.flight_time_sec + feedback.judge.post_process_time_sec) if abs(feedback.mission_clock_time_sec - judge_mission_clock) > 30: team_eval.warnings.append( 'Mission clock differs between interop and judge.')
def create_sample_mission(superuser): """Creates a sample mission. Args: superuser: A superuser account to create mission under. Returns: MissionConfig for the created mission. """ mission = MissionConfig() gpos = GpsPosition(latitude=38.145103, longitude=-76.427856) gpos.save() mission.home_pos = gpos gpos = GpsPosition(latitude=38.145111, longitude=-76.427861) gpos.save() mission.emergent_last_known_pos = gpos gpos = GpsPosition(latitude=38.145111, longitude=-76.427861) gpos.save() mission.off_axis_odlc_pos = gpos gpos = GpsPosition(latitude=38.1458416666667, longitude=-76.426375) gpos.save() mission.air_drop_pos = gpos # All foreign keys must be defined before the first save. # All many-to-many must be defined after the first save. mission.save() bounds = FlyZone(altitude_msl_min=100, altitude_msl_max=750) bounds.save() # yapf: disable pts = [(38.1462694444444, -76.4281638888889), (38.1516250000000, -76.4286833333333), (38.1518888888889, -76.4314666666667), (38.1505944444444, -76.4353611111111), (38.1475666666667, -76.4323416666667), (38.1446666666667, -76.4329472222222), (38.1432555555556, -76.4347666666667), (38.1404638888889, -76.4326361111111), (38.1407194444444, -76.4260138888889), (38.1437611111111, -76.4212055555556), (38.1473472222222, -76.4232111111111), (38.1461305555556, -76.4266527777778)] # yapf: enable for ix, (lat, lon) in enumerate(pts): wpt = Waypoint(latitude=lat, longitude=lon, altitude_msl=0, order=ix + 1) wpt.save() bounds.boundary_pts.add(wpt) bounds.save() mission.fly_zones.add(bounds) # yapf: disable pts = [(38.146689, -76.426475, 150, 750), (38.142914, -76.430297, 300, 300), (38.149504, -76.433110, 100, 750), (38.148711, -76.429061, 300, 750), (38.144203, -76.426155, 50, 400), (38.146003, -76.430733, 225, 500)] # yapf: enable for lat, lon, radius, height in pts: obst = StationaryObstacle(latitude=lat, longitude=lon, cylinder_radius=radius, cylinder_height=height) obst.save() mission.stationary_obstacles.add(obst) # yapf: disable pts = [(38.1446916666667, -76.4279944444445, 200), (38.1461944444444, -76.4237138888889, 300), (38.1438972222222, -76.4225500000000, 400), (38.1417722222222, -76.4251083333333, 400), (38.1453500000000, -76.4286750000000, 300), (38.1508972222222, -76.4292972222222, 300), (38.1514944444444, -76.4313833333333, 300), (38.1505333333333, -76.4341750000000, 300), (38.1479472222222, -76.4316055555556, 200), (38.1443333333333, -76.4322888888889, 200), (38.1433166666667, -76.4337111111111, 300), (38.1410944444444, -76.4321555555556, 400), (38.1415777777778, -76.4252472222222, 400), (38.1446083333333, -76.4282527777778, 200)] # yapf: enable for ix, (lat, lon, alt) in enumerate(pts): wpt = Waypoint(latitude=lat, longitude=lon, altitude_msl=alt, order=ix + 1) wpt.save() mission.mission_waypoints.add(wpt) # yapf: disable pts = [(38.1444444444444, -76.4280916666667), (38.1459444444444, -76.4237944444445), (38.1439305555556, -76.4227444444444), (38.1417138888889, -76.4253805555556), (38.1412111111111, -76.4322361111111), (38.1431055555556, -76.4335972222222), (38.1441805555556, -76.4320111111111), (38.1452611111111, -76.4289194444444), (38.1444444444444, -76.4280916666667)] # yapf: enable for ix, (lat, lon) in enumerate(pts): wpt = Waypoint(latitude=lat, longitude=lon, altitude_msl=0, order=ix + 1) wpt.save() mission.search_grid_points.add(wpt) gpos = GpsPosition(latitude=38.143844, longitude=-76.426469) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.N, shape=interop_api_pb2.Odlc.STAR, shape_color=interop_api_pb2.Odlc.RED, alphanumeric='A', alphanumeric_color=interop_api_pb2.Odlc.WHITE) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.141872, longitude=-76.426183) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.NE, shape=interop_api_pb2.Odlc.CROSS, shape_color=interop_api_pb2.Odlc.BLUE, alphanumeric='I', alphanumeric_color=interop_api_pb2.Odlc.BLACK) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.142828, longitude=-76.427644) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.E, shape=interop_api_pb2.Odlc.QUARTER_CIRCLE, shape_color=interop_api_pb2.Odlc.YELLOW, alphanumeric='R', alphanumeric_color=interop_api_pb2.Odlc.ORANGE) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.144925, longitude=-76.425100) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.SE, shape=interop_api_pb2.Odlc.CIRCLE, shape_color=interop_api_pb2.Odlc.BROWN, alphanumeric='V', alphanumeric_color=interop_api_pb2.Odlc.RED) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.146747, longitude=-76.422131) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.S, shape=interop_api_pb2.Odlc.TRAPEZOID, shape_color=interop_api_pb2.Odlc.WHITE, alphanumeric='E', alphanumeric_color=interop_api_pb2.Odlc.GRAY) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.144097, longitude=-76.431089) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.SW, shape=interop_api_pb2.Odlc.SQUARE, shape_color=interop_api_pb2.Odlc.GREEN, alphanumeric='H', alphanumeric_color=interop_api_pb2.Odlc.BLUE) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.144878, longitude=-76.423681) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.W, shape=interop_api_pb2.Odlc.RECTANGLE, shape_color=interop_api_pb2.Odlc.PURPLE, alphanumeric='I', alphanumeric_color=interop_api_pb2.Odlc.GREEN) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.142819, longitude=-76.432375) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.NW, shape=interop_api_pb2.Odlc.SEMICIRCLE, shape_color=interop_api_pb2.Odlc.ORANGE, alphanumeric='C', alphanumeric_color=interop_api_pb2.Odlc.YELLOW) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.141639, longitude=-76.429347) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.N, shape=interop_api_pb2.Odlc.TRIANGLE, shape_color=interop_api_pb2.Odlc.BLACK, alphanumeric='L', alphanumeric_color=interop_api_pb2.Odlc.PURPLE) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.142478, longitude=-76.424967) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.STANDARD, location=gpos, orientation=interop_api_pb2.Odlc.NE, shape=interop_api_pb2.Odlc.PENTAGON, shape_color=interop_api_pb2.Odlc.GRAY, alphanumeric='E', alphanumeric_color=interop_api_pb2.Odlc.BROWN) odlc.save() mission.odlcs.add(odlc) gpos = GpsPosition(latitude=38.143411, longitude=-76.424489) gpos.save() odlc = Odlc(mission=mission, user=superuser, odlc_type=interop_api_pb2.Odlc.EMERGENT, location=gpos, description='Randy the backpacker.') odlc.save() mission.odlcs.add(odlc) mission.save() return mission