Пример #1
0
def generate_commands(program,
                      drone_config_map: Dict[str, DroneConfig] = None,
                      boundary_checker: BoundaryChecker = None,
                      collision_checker: CollisionChecker = None,
                      has_checks: bool = True,
                      symbol_table: SymbolTable = None,
                      function_table: FunctionTable = None):
    if drone_config_map is None:
        drone_config_map = {"DEFAULT": DefaultDroneConfig()}
    if boundary_checker is None:
        boundary_checker = BoundaryChecker(BoundaryConfig.no_limit())
    if collision_checker is None:
        collision_checker = CollisionChecker(drone_config_map,
                                             DefaultCollisionConfig())
    if symbol_table is None:
        symbol_table = SymbolTable()
    if function_table is None:
        function_table = FunctionTable()
    state_updater_map = {
        name: StateUpdater(config)
        for name, config in drone_config_map.items()
    }

    tree = _parse_program(program)

    drone_commands = Compiler(drone_config_map, symbol_table,
                              function_table).visit(tree)

    if has_checks:
        boundary_checker.check(drone_commands, state_updater_map)
        collision_checker.check(drone_commands, state_updater_map)

    return drone_commands
Пример #2
0
 def test_check_should_call_update_states_and_check_drone_commands_with_correct_parameters(
         self):
     boundary_checker = BoundaryChecker(self.boundary_config)
     boundary_checker._update_states_and_check_drone_commands = Mock()
     drone_state_map = {"DRONE1": State(), "DRONE2": State(x_meters=1)}
     drones_involved = {"DRONE1", "DRONE2"}
     boundary_checker.check([], self.state_updater_map)
     boundary_checker._update_states_and_check_drone_commands.assert_called_once_with(
         [], self.state_updater_map, drone_state_map, drones_involved)
Пример #3
0
 def test_check_parallel_drone_commands_should_check_state_and_catch_error(
         self):
     boundary_checker = BoundaryChecker(self.boundary_config)
     boundary_checker.boundary_config.check_state = Mock(
         side_effect=SafetyCheckError)
     drone_commands = [ParallelDroneCommands([[], []])]
     with self.assertRaises(SafetyCheckError) as context:
         BoundaryChecker(self.boundary_config).check(
             drone_commands, self.state_updater_map)
Пример #4
0
 def test_check_single_drone_command_should_check_state_and_catch_error(
         self):
     boundary_checker = BoundaryChecker(self.boundary_config)
     boundary_checker.boundary_config.check_state = Mock(
         side_effect=SafetyCheckError)
     drone_commands = [
         SingleDroneCommand("DRONE1", Command.takeoff()),
         SingleDroneCommand("DRONE1", Command.land())
     ]
     with self.assertRaises(SafetyCheckError) as context:
         BoundaryChecker(self.boundary_config).check(
             drone_commands, self.state_updater_map)
Пример #5
0
 def test_check_in_the_end_not_land_should_give_error(self):
     with self.assertRaises(SafetyCheckError) as context:
         drone_commands = [SingleDroneCommand("DRONE1", Command.takeoff())]
         BoundaryChecker(self.boundary_config).check(
             drone_commands, self.state_updater_map)
     self.assertTrue(
         "Drone 'DRONE1' did not land in the end" in str(context.exception))
Пример #6
0
 def test_check_parallel_drone_commands_nested_should_update_states_correctly(
         self):
     drone_commands = \
         [
             ParallelDroneCommands([
                 [SingleDroneCommand("DRONE1", Command.wait(5))],
                 [SingleDroneCommand("DRONE2", Command.wait(3)),
                  ParallelDroneCommands([
                      [SingleDroneCommand("DRONE3", Command.wait(4))],
                      [SingleDroneCommand("DRONE4", Command.wait(1))]
                  ])]
             ]),
             SingleDroneCommand("DRONE1", Command.wait(1))
         ]
     drones_involved = {"DRONE1", "DRONE2", "DRONE3", "DRONE4", "DRONE5"}
     state_updaters = {
         name: StateUpdater(DroneConfig((1, 0, 0), 2, 180, 2))
         for name in drones_involved
     }
     drone_state_map = {name: State() for name in drones_involved}
     BoundaryChecker(
         self.boundary_config)._update_states_and_check_drone_commands(
             drone_commands, state_updaters, drone_state_map,
             drones_involved)
     expected = {
         name: State(time_used_seconds=8)
         for name in drones_involved
     }
     self.assertEqual(expected, drone_state_map)
Пример #7
0
 def test_check_single_drone_command_should_check_state(self):
     boundary_checker = BoundaryChecker(self.boundary_config)
     boundary_checker.boundary_config.check_state = Mock()
     drone_commands = [
         SingleDroneCommand("DRONE1", Command.takeoff()),
         SingleDroneCommand("DRONE1", Command.land())
     ]
     BoundaryChecker(self.boundary_config).check(drone_commands,
                                                 self.state_updater_map)
     calls = [
         call("DRONE1",
              State(has_taken_off=True, time_used_seconds=1, z_meters=1)),
         call("DRONE2", State(time_used_seconds=1, x_meters=1)),
         call("DRONE1", State(time_used_seconds=2)),
         call("DRONE2", State(time_used_seconds=2, x_meters=1))
     ]
     boundary_checker.boundary_config.check_state.assert_has_calls(calls)
Пример #8
0
 def test_check_single_drone_command_wait_when_taken_off_should_not_give_error(
         self):
     drone_commands = [
         SingleDroneCommand("DRONE1", Command.takeoff()),
         SingleDroneCommand("DRONE1", Command.wait(1)),
         SingleDroneCommand("DRONE1", Command.land())
     ]
     BoundaryChecker(self.boundary_config).check(drone_commands,
                                                 self.state_updater_map)
Пример #9
0
def generate_commands_with_config(program, config_json, has_checks):
    drone_config_map, boundary_config, collision_config = ConfigParser.parse(
        config_json)
    boundary_checker = BoundaryChecker(boundary_config)
    collision_checker = CollisionChecker(drone_config_map, collision_config)
    generated_commands = generate_commands(program, drone_config_map,
                                           boundary_checker, collision_checker,
                                           has_checks)
    return generated_commands, drone_config_map, boundary_config
Пример #10
0
 def test_if_given_boundary_checker_should_use_it_to_check_safety(self):
     commands = "main() {takeoff(); up(1000); land();}"
     with self.assertRaises(SafetyCheckError) as context:
         generate_commands(commands,
                           boundary_checker=BoundaryChecker(
                               BoundaryConfig(max_seconds=10000,
                                              max_z_meters=1)))
     self.assertTrue(
         "Drone 'DEFAULT': the z coordinate 1001 will go beyond its upper limit 1"
         in str(context.exception))
Пример #11
0
 def test_check_single_drone_command_takeoff_when_taken_off_should_give_error(
         self):
     with self.assertRaises(SafetyCheckError) as context:
         drone_commands = [
             SingleDroneCommand("DRONE1", Command.takeoff()),
             SingleDroneCommand("DRONE1", Command.takeoff())
         ]
         BoundaryChecker(self.boundary_config).check(
             drone_commands, self.state_updater_map)
     self.assertTrue(
         "'takeoff' command used when drone 'DRONE1' has already been taken off"
         in str(context.exception))
Пример #12
0
 def test_check_parallel_drone_commands_should_check_state(self):
     boundary_checker = BoundaryChecker(self.boundary_config)
     boundary_checker.boundary_config.check_state = Mock()
     drone_commands = [
         ParallelDroneCommands(
             [[
                 SingleDroneCommand("DRONE1", Command.takeoff()),
                 SingleDroneCommand("DRONE1", Command.land())
             ],
              [
                  SingleDroneCommand("DRONE2", Command.takeoff()),
                  SingleDroneCommand("DRONE2", Command.land())
              ]])
     ]
     BoundaryChecker(self.boundary_config).check(drone_commands,
                                                 self.state_updater_map)
     last_two_calls = [
         call("DRONE1", State(time_used_seconds=2)),
         call("DRONE2", State(time_used_seconds=2, x_meters=1))
     ]
     boundary_checker.boundary_config.check_state.assert_has_calls(
         last_two_calls)
Пример #13
0
 def test_check_single_drone_command_should_update_state_correctly(self):
     drone_commands = [SingleDroneCommand("DRONE1", Command.takeoff())]
     drone_state_map = {"DRONE1": State(), "DRONE2": State(x_meters=1)}
     drones_involved = {"DRONE1", "DRONE2"}
     BoundaryChecker(
         self.boundary_config)._update_states_and_check_drone_commands(
             drone_commands, self.state_updater_map, drone_state_map,
             drones_involved)
     expected = {
         "DRONE1": State(has_taken_off=True,
                         time_used_seconds=1,
                         z_meters=1),
         "DRONE2": State(time_used_seconds=1, x_meters=1)
     }
     self.assertEqual(expected, drone_state_map)
Пример #14
0
 def test_if_given_state_updater_should_use_it_to_update_state(self):
     commands = "main() {takeoff(); land();}"
     with self.assertRaises(SafetyCheckError) as context:
         generate_commands(commands,
                           drone_config_map={
                               "DEFAULT":
                               DroneConfig(init_position=(0, 0, 0),
                                           speed_mps=1,
                                           rotate_speed_dps=90,
                                           takeoff_height_meters=10)
                           },
                           boundary_checker=BoundaryChecker(
                               BoundaryConfig(max_seconds=10,
                                              max_z_meters=1)))
     self.assertTrue(
         "Drone 'DEFAULT': the z coordinate 10 will go beyond its upper limit 1"
         in str(context.exception))
Пример #15
0
 def test_check_parallel_drone_commands_should_let_drone_not_involved_wait(
         self):
     drone_commands = [
         ParallelDroneCommands(
             [[], [SingleDroneCommand("DRONE2", Command.wait(5))]])
     ]
     drone_state_map = {"DRONE1": State(), "DRONE2": State(x_meters=1)}
     drones_involved = {"DRONE1", "DRONE2"}
     BoundaryChecker(
         self.boundary_config)._update_states_and_check_drone_commands(
             drone_commands, self.state_updater_map, drone_state_map,
             drones_involved)
     expected = {
         "DRONE1": State(time_used_seconds=5),
         "DRONE2": State(time_used_seconds=5, x_meters=1)
     }
     self.assertEqual(expected, drone_state_map)
Пример #16
0
 def test_check_parallel_drone_commands_should_wait_for_slower_branch(self):
     drone_commands = [
         ParallelDroneCommands(
             [[SingleDroneCommand("DRONE1", Command.takeoff())],
              [SingleDroneCommand("DRONE2", Command.wait(5))]])
     ]
     drone_state_map = {"DRONE1": State(), "DRONE2": State(x_meters=1)}
     drones_involved = {"DRONE1", "DRONE2"}
     BoundaryChecker(
         self.boundary_config)._update_states_and_check_drone_commands(
             drone_commands, self.state_updater_map, drone_state_map,
             drones_involved)
     expected = {
         "DRONE1": State(has_taken_off=True,
                         time_used_seconds=5,
                         z_meters=1),
         "DRONE2": State(time_used_seconds=5, x_meters=1)
     }
     self.assertEqual(expected, drone_state_map)
Пример #17
0
 def test_check_single_drone_command_other_command_when_not_taken_off_should_give_error(
         self):
     commands = [
         Command.land(),
         Command.up(1),
         Command.down(1),
         Command.left(1),
         Command.right(1),
         Command.forward(1),
         Command.backward(1),
         Command.rotate_left(90),
         Command.rotate_right(90)
     ]
     for command in commands:
         with self.assertRaises(SafetyCheckError) as context:
             drone_commands = [SingleDroneCommand("DRONE1", command)]
             BoundaryChecker(self.boundary_config).check(
                 drone_commands, self.state_updater_map)
         self.assertTrue(
             "'{}' command used when drone 'DRONE1' has not been taken off".
             format(command.opcode) in str(context.exception))
Пример #18
0
 def test_if_not_given_state_updater_should_use_default_to_update_state(
         self):
     commands = "main() {takeoff(); land();}"
     generate_commands(commands,
                       boundary_checker=BoundaryChecker(
                           BoundaryConfig(max_seconds=10, max_z_meters=1)))