コード例 #1
0
    def __init__(
        self, launch_delay_s=0.1, enable_thunderscope=True, runtime_dir="/tmp/tbots"
    ):
        """Initialize the TacticTestRunner

        :param launch_delay_s: How long to wait after launching the processes
        :param enable_thunderscope: If true, thunderscope opens and the test runs
                                  in realtime
        :param runtime_dir: Directory to open sockets, store logs and any output files

        """

        # Setup runtime directory
        try:
            os.mkdir(runtime_dir)
        except:
            pass

        self.enable_thunderscope = enable_thunderscope

        if self.enable_thunderscope:
            self.thunderscope = Thunderscope()
            self.thunderscope.configure_default_layout()
            self.eventually_validation_sender = ThreadedUnixSender(
                runtime_dir + "/eventually_validation"
            )
            self.always_validation_sender = ThreadedUnixSender(
                runtime_dir + "/always_validation"
            )

        self.simulator = ErForceSimulator()
        self.yellow_full_system = FullSystem()
        time.sleep(launch_delay_s)

        self.last_exception = None
コード例 #2
0
    def __init__(self, runtime_dir="/tmp/tbots"):
        """Runs our standalone er-force simulator binary and sets up the unix
        sockets to communicate with it

        :param runtime_dir: The runtime directory

        """

        # inputs to full_system
        self.robot_status_sender = ThreadedUnixSender(runtime_dir +
                                                      ROBOT_STATUS_PATH)
        self.ssl_wrapper_sender = ThreadedUnixSender(runtime_dir +
                                                     SSL_WRAPPER_PATH)
        self.ssl_referee_sender = ThreadedUnixSender(runtime_dir +
                                                     SSL_REFEREE_PATH)
        self.sensor_proto_sender = ThreadedUnixSender(runtime_dir +
                                                      SENSOR_PROTO_PATH)

        # outputs from full_system
        self.world_listener = ThreadedUnixListener(runtime_dir + WORLD_PATH,
                                                   World)
        self.primitive_listener = ThreadedUnixListener(
            runtime_dir + PRIMITIVE_PATH, PrimitiveSet)

        # override the tactic
        self.tactic_override = ThreadedUnixSender(runtime_dir +
                                                  TACTIC_OVERRIDE_PATH)

        # TODO (#2510) rename to full_system
        self.full_system_process = Popen(["software/unix_full_system"])
コード例 #3
0
class TacticTestRunner(object):

    """Run a tactic"""

    def __init__(
        self, launch_delay_s=0.1, enable_thunderscope=True, runtime_dir="/tmp/tbots"
    ):
        """Initialize the TacticTestRunner

        :param launch_delay_s: How long to wait after launching the processes
        :param enable_thunderscope: If true, thunderscope opens and the test runs
                                  in realtime
        :param runtime_dir: Directory to open sockets, store logs and any output files

        """

        # Setup runtime directory
        try:
            os.mkdir(runtime_dir)
        except:
            pass

        self.enable_thunderscope = enable_thunderscope

        if self.enable_thunderscope:
            self.thunderscope = Thunderscope()
            self.thunderscope.configure_default_layout()
            self.eventually_validation_sender = ThreadedUnixSender(
                runtime_dir + "/eventually_validation"
            )
            self.always_validation_sender = ThreadedUnixSender(
                runtime_dir + "/always_validation"
            )

        self.simulator = ErForceSimulator()
        self.yellow_full_system = FullSystem()
        time.sleep(launch_delay_s)

        self.last_exception = None

    def run_test(
        self,
        always_validation_sequence_set=[[]],
        eventually_validation_sequence_set=[[]],
        test_timeout_s=3,
        tick_duration_s=0.0166,  # Default to 60hz
    ):
        """Run a test

        :param always_validation_sequence_set: Validation functions that should
                                hold on every tick
        :param eventually_validation_sequence_set: Validation that should
                                eventually be true, before the test ends
        :param test_timeout_s: The timeout for the test, if any eventually_validations
                                remain after the timeout, the test fails.
        :param tick_duration_s: The simulation step duration

        """

        def __stopper(delay=PROCESS_BUFFER_DELAY_S):
            """Stop running the test

            :param delay: How long to wait before closing everything, defaults
                          to PROCESS_BUFFER_DELAY_S to minimize buffer warnings

            """
            time.sleep(delay)

            # Close everything
            self.simulator.simulator_process.kill()
            self.yellow_full_system.full_system_process.kill()
            self.simulator.simulator_process.wait()
            self.yellow_full_system.full_system_process.wait()

            if self.enable_thunderscope:
                self.thunderscope.close()

        def __runner():
            """Step simulation, full_system and run validation
            """

            time_elapsed_s = 0

            while time_elapsed_s < test_timeout_s:

                self.simulator.tick(tick_duration_s * MILLISECONDS_PER_SECOND)
                time_elapsed_s += tick_duration_s

                if self.enable_thunderscope:
                    time.sleep(tick_duration_s)

                # Send the sensor_proto and get world
                ssl_wrapper = self.simulator.get_ssl_wrapper_packet(block=True)
                self.yellow_full_system.send_sensor_proto(
                    self.simulator.get_yellow_sensor_proto(ssl_wrapper)
                )
                world = self.yellow_full_system.get_world(block=True)

                # Validate
                (
                    eventually_validation_proto_set,
                    always_validation_proto_set,
                ) = validation.run_validation_sequence_sets(
                    world,
                    eventually_validation_sequence_set,
                    always_validation_sequence_set,
                )

                if self.enable_thunderscope:
                    # Send out the validation proto to thunderscope
                    self.eventually_validation_sender.send(
                        eventually_validation_proto_set
                    )
                    self.always_validation_sender.send(always_validation_proto_set)

                # Check that all always validations are always valid
                validation.check_validation(always_validation_proto_set)

                # Step the primtives
                self.simulator.send_yellow_primitive_set_and_world(
                    world, self.yellow_full_system.get_primitive_set(),
                )

            # Check that all eventually validations are eventually valid
            validation.check_validation(eventually_validation_proto_set)

            __stopper()

        def excepthook(args):
            """This function is _critical_ for enable_thunderscope to work.
            If the test Thread will raises an exception we won't be able to close
            the window from the main thread.

            :param args: The args passed in from the hook

            """

            __stopper(delay=PAUSE_AFTER_FAIL_DELAY_S)
            self.last_exception = args.exc_value
            raise self.last_exception

        threading.excepthook = excepthook

        # If thunderscope is enabled, run the test in a thread and show
        # thunderscope on this thread. The excepthook is setup to catch
        # any test failures and propagate them to the main thread
        if self.enable_thunderscope:

            run_sim_thread = threading.Thread(target=__runner, daemon=True)
            run_sim_thread.start()

            self.thunderscope.show()
            run_sim_thread.join()

            if self.last_exception:
                pytest.fail(str(self.last_exception))

        # If thunderscope is disabled, just run the test
        else:
            __runner()
コード例 #4
0
class FullSystem(object):
    def __init__(self, runtime_dir="/tmp/tbots"):
        """Runs our standalone er-force simulator binary and sets up the unix
        sockets to communicate with it

        :param runtime_dir: The runtime directory

        """

        # inputs to full_system
        self.robot_status_sender = ThreadedUnixSender(runtime_dir +
                                                      ROBOT_STATUS_PATH)
        self.ssl_wrapper_sender = ThreadedUnixSender(runtime_dir +
                                                     SSL_WRAPPER_PATH)
        self.ssl_referee_sender = ThreadedUnixSender(runtime_dir +
                                                     SSL_REFEREE_PATH)
        self.sensor_proto_sender = ThreadedUnixSender(runtime_dir +
                                                      SENSOR_PROTO_PATH)

        # outputs from full_system
        self.world_listener = ThreadedUnixListener(runtime_dir + WORLD_PATH,
                                                   World)
        self.primitive_listener = ThreadedUnixListener(
            runtime_dir + PRIMITIVE_PATH, PrimitiveSet)

        # override the tactic
        self.tactic_override = ThreadedUnixSender(runtime_dir +
                                                  TACTIC_OVERRIDE_PATH)

        # TODO (#2510) rename to full_system
        self.full_system_process = Popen(["software/unix_full_system"])

    def send_robot_status(self, robot_status):
        """Send the robot_status to full_system

        :param robot_status: The RobotStatus to send

        """
        self.robot_status_sender.send(robot_status)

    def send_ssl_wrapper(self, ssl_wrapper_packet):
        """Send the ssl_wrapper_packet to full_system

        :param ssl_wrapper_packet: The packet to send

        """
        self.ssl_wrapper_sender.send(ssl_wrapper_packet)

    def send_ssl_referee(self, ssl_referee_packet):
        """Send the ssl_referee_packet to full_system

        :param ssl_referee_packet: The packet to send

        """
        self.ssl_referee_sender.send(ssl_referee_packet)

    def send_sensor_proto(self, sensor_proto):
        """Send a sensor msg to full system.

        :param sensor_proto: The sensor msg to send

        """
        self.sensor_proto_sender.send(sensor_proto)

    def send_tactic_override(self, assigned_tactic_play_control_params):
        """Send the control params for the assigned tactic play to
        run specific tactics on assigned robots.

        :param assigned_tactic_play_control_params:
                The control params of the AssignedTacticPlay
        
        """
        self.tactic_override.send(assigned_tactic_play_control_params)

    def get_world(self, block=False):
        """Grabs the world msg from the buffer if it exists, returns None
        if buffer is empty.

        :param block: Whether or not we should block until we receive a packet
        :return: World or None

        """
        return self.world_listener.get_most_recent_message(block)

    def get_primitive_set(self):
        """Grabs the primitive msg set from the buffer if it exists, returns
        None if buffer is empty.

        :return: PrimitiveSet or None

        """
        return self.primitive_listener.get_most_recent_message()

    def stop():
        """Stop all listeners and senders.

        """

        for unix_socket in [
                self.robot_status_sender,
                self.ssl_wrapper_sender,
                self.ssl_referee_sender,
                self.tactic_override,
                self.sensor_proto_sender,
                self.world_listener,
        ]:
            unix_socket.force_stop()
        self.primitive_listener.force_stop()
コード例 #5
0
    def __init__(self, runtime_dir="/tmp/tbots"):
        """Runs our standalone er-force simulator binary and sets up the unix
        sockets to communicate with it

        :param runtime_dir: The unix path to run everything

        """
        # inputs to er_force_simulator_main
        self.sim_tick_sender = ThreadedUnixSender(runtime_dir +
                                                  SIMULATION_TICK_PATH)
        self.world_state_sender = ThreadedUnixSender(runtime_dir +
                                                     WORLD_STATE_PATH)
        self.blue_world_sender = ThreadedUnixSender(runtime_dir +
                                                    BLUE_WORLD_PATH)
        self.yellow_world_sender = ThreadedUnixSender(runtime_dir +
                                                      YELLOW_WORLD_PATH)
        self.blue_primitive_set_sender = ThreadedUnixSender(runtime_dir +
                                                            BLUE_PRIMITIVE_SET)
        self.yellow_primitive_set_sender = ThreadedUnixSender(
            runtime_dir + YELLOW_PRIMITIVE_SET)

        # outputs from er_force_sim_main
        self.ssl_wrapper_listener = ThreadedUnixListener(
            runtime_dir + SSL_WRAPPER_PACKET_PATH, SSL_WrapperPacket)
        self.blue_robot_status_listener = ThreadedUnixListener(
            runtime_dir + BLUE_ROBOT_STATUS_PATH, RobotStatus)
        self.yellow_robot_status_listener = ThreadedUnixListener(
            runtime_dir + YELLOW_ROBOT_STATUS_PATH,
            RobotStatus,
        )

        self.world_state = WorldState()

        self.simulator_process = Popen(["software/er_force_simulator_main"])
コード例 #6
0
class ErForceSimulator(object):
    def __init__(self, runtime_dir="/tmp/tbots"):
        """Runs our standalone er-force simulator binary and sets up the unix
        sockets to communicate with it

        :param runtime_dir: The unix path to run everything

        """
        # inputs to er_force_simulator_main
        self.sim_tick_sender = ThreadedUnixSender(runtime_dir +
                                                  SIMULATION_TICK_PATH)
        self.world_state_sender = ThreadedUnixSender(runtime_dir +
                                                     WORLD_STATE_PATH)
        self.blue_world_sender = ThreadedUnixSender(runtime_dir +
                                                    BLUE_WORLD_PATH)
        self.yellow_world_sender = ThreadedUnixSender(runtime_dir +
                                                      YELLOW_WORLD_PATH)
        self.blue_primitive_set_sender = ThreadedUnixSender(runtime_dir +
                                                            BLUE_PRIMITIVE_SET)
        self.yellow_primitive_set_sender = ThreadedUnixSender(
            runtime_dir + YELLOW_PRIMITIVE_SET)

        # outputs from er_force_sim_main
        self.ssl_wrapper_listener = ThreadedUnixListener(
            runtime_dir + SSL_WRAPPER_PACKET_PATH, SSL_WrapperPacket)
        self.blue_robot_status_listener = ThreadedUnixListener(
            runtime_dir + BLUE_ROBOT_STATUS_PATH, RobotStatus)
        self.yellow_robot_status_listener = ThreadedUnixListener(
            runtime_dir + YELLOW_ROBOT_STATUS_PATH,
            RobotStatus,
        )

        self.world_state = WorldState()

        self.simulator_process = Popen(["software/er_force_simulator_main"])

    def __setup_robots(self, robot_locations, team_colour):
        """Initializes the world from a list of robot locations

        :param robot_locations: A list of robot locations (index is robot id)
        :param team_colour: The color (either "blue" or "yellow")

        """

        if "blue" in team_colour:
            robot_map = self.world_state.blue_robots
        else:
            robot_map = self.world_state.yellow_robots

        for robot_id, robot_location in enumerate(robot_locations):
            robot_map[robot_id].CopyFrom(
                RobotState(
                    global_position=Point(x_meters=robot_location.x(),
                                          y_meters=robot_location.y()),
                    global_orientation=Angle(radians=0),
                    global_velocity=Vector(x_component_meters=0,
                                           y_component_meters=0),
                    global_angular_velocity=AngularVelocity(
                        radians_per_second=0),
                ))

        self.setup_world(self.world_state)

    def setup_blue_robots(self, robot_locations):
        """Initializes the world from a list of robot locations

        :param robot_locations: A list of robot locations (index is robot id)

        """
        self.__setup_robots(robot_locations, "blue")

    def setup_yellow_robots(self, robot_locations):
        """Initializes the world from a list of robot locations

        :param robot_locations: A list of robot locations (index is robot id)

        """
        self.__setup_robots(robot_locations, "yellow")

    def setup_ball(self, ball_position, ball_velocity, distance_from_ground=0):
        """Setup the ball with the x, y coordinates in meters

        :param ball_position: A tuple with the x,y coordinates
        :param ball_velocity: A tuple with the x,y velocity components
        :param distance_from_ground: How high up to start the ball

        """
        self.world_state.ball_state.CopyFrom(
            BallState(
                global_position=Point(
                    x_meters=ball_position.x(),
                    y_meters=ball_position.y(),
                ),
                global_velocity=Vector(
                    x_component_meters=ball_velocity.x(),
                    y_component_meters=ball_velocity.y(),
                ),
                distance_from_ground=distance_from_ground,
            ))

        self.setup_world(self.world_state)

    def setup_world(self, world_state):
        """Pass in a world_state proto directly to setup the simulator

        :param world_state: The world state to initialize with

        """
        self.world_state_sender.send(world_state)

    def __get_sensor_proto(self, ssl_wrapper, robot_status_listener):
        """Helper function to create a sensor proto

        :param ssl_wrapper: The ssl_wrapper packet to put in the sensor proto
        :param robot_status_listener: The robot status listener (blue or yellow)
        :returns: A sensor proto with the robot status from the listener

        """
        sensor_proto = SensorProto()

        if ssl_wrapper:
            sensor_proto.ssl_vision_msg.CopyFrom(ssl_wrapper)

        robot_status = robot_status_listener.get_most_recent_message()

        packets = []
        while robot_status is not None:
            packets.append(robot_status)
            robot_status = robot_status_listener.get_most_recent_message()

        sensor_proto.robot_status_msgs.extend(packets)
        return sensor_proto

    def get_blue_sensor_proto(self, ssl_wrapper):
        """Returns the blue sensor proto

        :param ssl_wrapper: The wrapper to pack in the sensor proto

        """
        return self.__get_sensor_proto(ssl_wrapper,
                                       self.blue_robot_status_listener)

    def get_yellow_sensor_proto(self, ssl_wrapper):
        """Returns the yellow sensor proto

        :param ssl_wrapper: The wrapper to pack in the sensor proto

        """
        return self.__get_sensor_proto(ssl_wrapper,
                                       self.yellow_robot_status_listener)

    def get_ssl_wrapper_packet(self, block=False):
        """Get wrapper packet

        :param block: If true, block until we receive a packet
        :return: SSL_WrapperPacket

        """
        return self.ssl_wrapper_listener.get_most_recent_message(block)

    def tick(self, duration_ms):
        """Tick the simulator with the given duration

        :param duration_ms: The duration to step the sim

        """
        tick = SimulatorTick()
        tick.milliseconds = duration_ms
        self.sim_tick_sender.send(tick)

    def send_blue_primitive_set_and_world(self, world, primitive_set):
        """Blue primitive set and world

        :param world: The world msg to send
        :param primitive_set: The primitive set to send

        """
        self.blue_world_sender.send(world)
        self.blue_primitive_set_sender.send(primitive_set)

    def send_yellow_primitive_set_and_world(self, world, primitive_set):
        """Yellow primitive set and world

        :param world: The world msg to send
        :param primitive_set: The primitive set to send

        """
        self.yellow_world_sender.send(world)
        self.yellow_primitive_set_sender.send(primitive_set)

    def stop():
        """Stop all listeners and senders.
        """
        for unix_socket in [
                self.sim_tick_sender,
                self.world_state_sender,
                self.blue_world_sender,
                self.yellow_world_sender,
                self.blue_primitive_set_sender,
                self.yellow_primitive_set_sender,
                self.ssl_wrapper_listener,
                self.blue_robot_status_listener,
                self.yellow_robot_status_listener,
        ]:
            unix_socket.force_stop()