Example #1
0
    def __init__(self, objects, draw=True, space=None, screen=None, dimensions=None):
       
        # Make a space if none was given
        if not space:
            space = pymunk.Space()
        if not dimensions:
            dimensions = Params.pitchSize

        if draw and not screen:
            # Make a pygame instance if none was given *and* we want one
            pygame.init()
            screen = pygame.display.set_mode(dimensions)
        elif screen and not draw:
            # Ensure the screen is None if we shouldn't have one
            screen = None

        # Add the objects to the space, including a pitch
        self.pitch = Pitch(dimensions)
        self.pitch.add_to_space(space)

        for key in objects:
            objects[key].add_to_space(space)

        startFrame = dict()

        try:
            bot = objects['blue']
            body = bot.body
            (x, y) = tuple(body.position)
            a = body.angle
            self.blueRobot = Array('f', [x, y, a])
            startFrame['blue'] = { 'position' : (x, y)
                                 , 'velocity' : tuple(body.velocity)
                                 , 'wheels' : (bot.lwheelVel, bot.rwheelVel)
                                 , 'angle' : a
                                 }
        except KeyError:
            self.blueRobot = None

        try:
            bot = objects['yellow']
            body = bot.body
            (x, y) = tuple(body.position)
            a = body.angle
            self.yellowRobot = Array('f', [x, y, a])
            startFrame['yellow'] = { 'position' : (x, y)
                                   , 'velocity' : tuple(body.velocity)
                                   , 'wheels' : (bot.lwheelVel, bot.rwheelVel)
                                   , 'angle' : a
                                   }
        except KeyError:
            self.yellowRobot = None

        try:
            body = objects['ball'].body
            (x, y) = tuple(body.position)
            objects['ball'].originals = (x, y)
            self.ball = Array('f', [x, y])
            startFrame['ball'] = { 'position' : (x, y)
                                 , 'velocity' : tuple(body.velocity)
                                 , 'angle' : body.angle
                                 }
        except KeyError:
            self.ball = None

        # Set some attributes
        self.clock = pygame.time.Clock()
        self.space = space
        self.screen = screen
        self.objects = objects
        self.dims = dimensions
        self.command_queue = Queue()
        self.done = Value('b', False)
        self.moving = None
        self.startFrame = startFrame
        self.us_color = 'blue'
Example #2
0
class Simulation:
    """ The simulation class. Keeps track of useful information to ease manipulation of the simulation """
    # Special functions {
    def __init__(self, objects, draw=True, space=None, screen=None, dimensions=None):
       
        # Make a space if none was given
        if not space:
            space = pymunk.Space()
        if not dimensions:
            dimensions = Params.pitchSize

        if draw and not screen:
            # Make a pygame instance if none was given *and* we want one
            pygame.init()
            screen = pygame.display.set_mode(dimensions)
        elif screen and not draw:
            # Ensure the screen is None if we shouldn't have one
            screen = None

        # Add the objects to the space, including a pitch
        self.pitch = Pitch(dimensions)
        self.pitch.add_to_space(space)

        for key in objects:
            objects[key].add_to_space(space)

        startFrame = dict()

        try:
            bot = objects['blue']
            body = bot.body
            (x, y) = tuple(body.position)
            a = body.angle
            self.blueRobot = Array('f', [x, y, a])
            startFrame['blue'] = { 'position' : (x, y)
                                 , 'velocity' : tuple(body.velocity)
                                 , 'wheels' : (bot.lwheelVel, bot.rwheelVel)
                                 , 'angle' : a
                                 }
        except KeyError:
            self.blueRobot = None

        try:
            bot = objects['yellow']
            body = bot.body
            (x, y) = tuple(body.position)
            a = body.angle
            self.yellowRobot = Array('f', [x, y, a])
            startFrame['yellow'] = { 'position' : (x, y)
                                   , 'velocity' : tuple(body.velocity)
                                   , 'wheels' : (bot.lwheelVel, bot.rwheelVel)
                                   , 'angle' : a
                                   }
        except KeyError:
            self.yellowRobot = None

        try:
            body = objects['ball'].body
            (x, y) = tuple(body.position)
            objects['ball'].originals = (x, y)
            self.ball = Array('f', [x, y])
            startFrame['ball'] = { 'position' : (x, y)
                                 , 'velocity' : tuple(body.velocity)
                                 , 'angle' : body.angle
                                 }
        except KeyError:
            self.ball = None

        # Set some attributes
        self.clock = pygame.time.Clock()
        self.space = space
        self.screen = screen
        self.objects = objects
        self.dims = dimensions
        self.command_queue = Queue()
        self.done = Value('b', False)
        self.moving = None
        self.startFrame = startFrame
        self.us_color = 'blue'
    # }


    def set_us_color(self, color):
        assert color in ["blue", "yellow"]
        self.us_color = color

    def get_us_robot(self):
        return self.objects[self.us_color]

    # Simulation subprocess functions {
    def start(self, FPS=Params.FPS):
        """ Start the simulation subprocess """
        self._running_process = Process(target=self._run, args=(FPS,))
        self._running_process.start()

    def _run(self, FPS=Params.FPS):
        """ Do the simulation loop """
        self.done.value = False
        q = self.command_queue
        while not self.done.value: # Perhaps we could pull some of this code out into functions
            try:
                # Run all the things
                self._do_draw_if_screen()
                self._run_control_queue(q)
                self._try_vision_serve()
                self._tick(FPS)
            except KeyboardInterrupt:
                print "SIMULATION: Finishing"
                self.done.value = True

    def run_until(self, timeout, control=False):
        if control:
            self._run_until(timeout)
        else:
            self._run_until_without_control(timeout)

    def _run_until(self, timeout):
        self.done.value = False
        self.timing = 0
        while not self.done.value:
            self._run_control_queue(self.command_queue)
            self._tick_until(timeout)

    def _run_until_without_control(self, timeout):
        self.done.value = False
        self.timing = 0
        while not self.done.value:
            self._tick_until(timeout)

    def _tick_until(self, timeout):
        dt = 1/300.0
        self.timing += dt
        self.space.step(dt)
        if self.timing >= timeout:
            self.done.value = True

    def finish(self):
        """ Stop simulating """
        print "SIMULATION: Finishing"
        self.done.value = True
        self._running_process.terminate()

    def _do_draw_if_screen(self):
        """ Draw the objects to the screen if we're supposed to """
        if self.screen:
            self._handle_events()
            self._draw()
            pygame.display.flip()

    def _run_control_queue(self, q):
        """ Control the blue robot using commands from comms """
        blue = self.objects['blue']
        while True:
            # Loop through getting commands from the queue
            try:
                # Run through commands, running them on the blue robot
                command = q.get_nowait()
                if not blue.turning:
                    try:
                        command(blue)
                    except TypeError:
                        self.keyFrame(command)
                else:
                    q.put(command)
            except Empty:
                break
        if blue.blocking:
            blue.do_timeout()
        if blue.turning:
            blue.do_turnout()

    def _try_vision_serve(self):
        """ Serve vision data for the objects that exist """
        try:
            body = self.objects['blue'].body
            (x, y) = tuple(body.position)
            a = simpleAngle(body.angle)
            self.blueRobot[0] = x
            self.blueRobot[1] = y
            self.blueRobot[2] = a
        except KeyError:
            pass

        try:
            body = self.objects['yellow'].body
            (x, y) = tuple(body.position)
            a = simpleAngle(body.angle)
            self.yellowRobot[0] = x
            self.yellowRobot[1] = y
            self.yellowRobot[2] = a
        except KeyError:
            pass

        try:
            body = self.objects['ball'].body
            (x, y) = tuple(body.position)
            self.ball[0] = x
            self.ball[1] = y
        except KeyError:
            pass

    def _tick(self, FPS):
        """ Advance the simulation and limit the drawing framerate """
        if FPS != 'unlimited':
            self.space.step(Params.simulationSpeed/float(FPS))
            self.clock.tick_busy_loop(FPS)
        else:
            self.space.step(1/30.0)

    # }

    # Collision functions {
    def addRobotCollisionFunc(self, func):
        def run_func(space, arbiter):
            return func(self, space, arbiter)
        self.space.add_collision_handler(CT_YELLOW_ROBOT, CT_BLUE_ROBOT, run_func)

    def addBallCollisionFunc(self, func, obj):
        def run_func(space, arbiter):
            return func(self, space, arbiter, obj)
        self.space.add_collision_handler(obj.shape.collision_type, CT_BALL, run_func)

    def addGoalCollisionFunc(self, func, obj, goal):
        def run_func(space, arbiter):
            return func(self, space, arbiter, obj, goal)
        self.space.add_collision_handler(obj.shape.collision_type, goal, run_func)
    # }

    # Functions used by vision server {
    def getBlueRobot(self):
        """ Return the position and angle of the blue robot """
        try:
            return tuple(self.blueRobot)
        except AttributeError:
            return None
        except TypeError:
            return None

    def getBlueBot(self):
        return self.getBlueRobot()

    def getYellowRobot(self):
        """ Return the position and angle of the yellow robot """
        try:
            return tuple(self.yellowRobot)
        except AttributeError:
            return None
        except TypeError:
            return None

    def getYellowBot(self):
        return self.getYellowRobot()

    def getBall(self):
        """ Return the position of the ball """
        try:
            return tuple(self.ball)
        except AttributeError:
            return None
        except TypeError:
            return None

    def getDimensions(self):
        """ Return the pixel dimensions of the pitch """
        return self.dims
    def getAbstractDims(self):
        return self.dims
    # }
    def set_us(self, color):
        assert color in ["blue", "yellow"]
        self.us_color = color

    def get_us(self):
        return self.objects[self.us_color]

    # Pygame functions {
    def _draw(self):
        """ Draw the pitch and all objects on the pygame screen """
        self.screen.fill(green)
        self.pitch.draw_on_screen(self.screen)
        for key in self.objects:
            self.objects[key].draw_on_screen(self.screen)

    def _handle_events(self):
        """ Do all of the pygame event handling """
        def do_keys():
            """ Check the keys and respond appropriately """
            blue = self.objects['yellow']
            keys = pygame.key.get_pressed()
            move = blue.move
            if keys[K_k]:
                blue.kick()
            if keys[K_r]:
                self.reset()
            if keys[K_SPACE]:
                move(0,0)
            elif keys[K_w]:
                if keys[K_a]:
                    move(60,128)
                elif keys[K_d]:
                    move(128, 60)
                elif keys[K_s]:
                    move(0,0)
                else:
                    move(127, 127)
            elif keys[K_s]:
                if keys[K_a]:
                    move(-60,-128)
                elif keys[K_d]:
                    move(-128, -60)
                elif keys[K_w]:
                    move(0,0)
                else:
                    move(-110, -110)
            elif keys[K_a]:
                move(-40, 40)
            elif keys[K_d]:
                move(40, -40)
            elif keys[K_o]:
                blue.turn(pi)

        for event in pygame.event.get():
            if event.type == MOUSEBUTTONDOWN:
                for key in self.objects:
                    if self.objects[key].hasPoint(pygame.mouse.get_pos()):
                        self.moving = self.objects[key]
                        self.moving.setVelocity((0,0))

            elif event.type == MOUSEMOTION:
                if self.moving:
                    self.moving.setPosition(pygame.mouse.get_pos())
                    self.moving.setVelocity((0,0))
            elif event.type == KEYDOWN:
                do_keys()
            elif event.type == KEYUP:
                do_keys()
            elif event.type == MOUSEBUTTONUP:
                self.moving = None
    # }

    # Robot control commands {
    def move(self, left, right):
        """ Make the wheels turn """
        self.command_queue.put(Move(left, right))

    def kick(self):
        """ Make the robot kick """
        self.command_queue.put(Kick())

    def turn(self, angle):
        """ Make the robot turn """
        self.command_queue.put(Turn(angle))

    def stop(self):
        """ Make the robot stay put """
        self.command_queue.put(Stop())

    def forwards(self, move_speed=40):
        self.move(move_speed, move_speed)

    def backwards(self, move_speed=20):
        self.move(move_speed, move_speed)

    def exit(self):
        pass
    # }

    # State change at runtime methods {
    def keyFrame(self, keyframe, external=False):
        """ Change the entire state of the pitch during runtime without making the physics simulator become strange """
        if external:
            self.command_queue.put(keyframe)
        else:
            for key in keyframe:
                self.objects[key].setKeyFrame(keyframe[key])

    def reset(self):
        """ Set everything to the way it was at initialisation """
        print "SIMULATION: Resetting"
        self.keyFrame(self.startFrame)