RoboSkate-RL / scripts / python / RoboSkate / hardcoded_agents.py
hardcoded_agents.py
Raw
# Here the remote control for the agent is defined!
# PyGame was used for this purpose.
# Here are also agents that play the level 1 completely automatically. For this, an optimal trajectoire is defined.

import math
import numpy as np
import pygame

class HardcodedAgents():
    """
    Hardcoded Agents for expert data collection
    """

    def __init__(self, obs, Teleoperation=False):
        super(HardcodedAgents, self).__init__()

        self.obs = obs
        self.info = {   "step": 0,
                        "board_pitch": 0,
                        "steering_angle": 0}
        self.reward = 0
        self.done = False
        self.step = 0
        self.stearing = 0
        self.keyoffset = 0
        self.level = 0
        self.backwards = False


        if Teleoperation:
            pygame.init()
            self.gameDisplay = pygame.display.set_mode((400, 400))
            pygame.display.set_caption('RoboSkate Teleoperation')


    # funktion to display information on the PyGame screen
    def RoboPos(self, x, y):

        self.gameDisplay.fill((255, 255, 255))
        font = pygame.font.SysFont('Arial', 25)

        pygame.draw.line(self.gameDisplay, (0,0,0), (200,0), (200,400), 1)
        pygame.draw.line(self.gameDisplay, (0, 0, 0), (0, 200), (400, 200), 1)
        pygame.draw.circle(self.gameDisplay, (255, 0, 0), (200-x*3,200-y*3), 15, 2)

        space = 25
        self.gameDisplay.blit(font.render("Arrow left = arm to the left", False, (0, 0, 0)), (10, space*0))
        self.gameDisplay.blit(font.render("Arrow right = arm to the right", False, (0, 0, 0)), (10 ,space*1))
        self.gameDisplay.blit(font.render("Arrow down = arm lower", False, (0, 0, 0)), (10 ,space*2))
        self.gameDisplay.blit(font.render("Arrow up = arm higher", False, (0, 0, 0)), (10 ,space*3))
        self.gameDisplay.blit(font.render("spacebar = control reset", False, (0, 0, 0)), (10 ,space*4))
        self.gameDisplay.blit(font.render("0-4 = set level", False, (0, 0, 0)), (10 ,space*5))
        self.gameDisplay.blit(font.render("x = reset", False, (0, 0, 0)), (10 ,space*6))
        self.gameDisplay.blit(font.render("r = backward", False, (0, 0, 0)), (10 ,space*7))

        pygame.display.update()

    # -----------------------------------------------------------------------------------------------------------------
    # follow a list of Checkpoints
    # -----------------------------------------------------------------------------------------------------------------

    def checkpoint_follower(self):

        # calculate steering angle
        self.steering = np.clip(self.info["steering_angle"], -70, 70)


        # ------------------------------- generate repetetiv movement ---------------------
        # scaled time to adjust movement speed
        time = self.step * 0.3

        # if the board is pitched correct the joint 2 angle
        offset_high = (self.info["board_pitch"]-0.5) * 200
        # continuous movement to move forward
        mean_angle_joint_2 = 90 - 30 + offset_high
        mean_angle_joint_3 = 125 - 70
        phase_shift = math.pi * 0.5
        range_of_motion_joint_2 = 30
        range_of_motion_joint_3 = 70

        joint2 = mean_angle_joint_2 - math.cos(time) * range_of_motion_joint_2
        joint3 = mean_angle_joint_3 - math.cos(time + phase_shift) * range_of_motion_joint_3

        # use Direction error directly for P controller of Joint 1
        joint1 = self.steering

        # P controler for actions
        # scale joint agnles to [-1, 1], calculate error, multiply with proportional parameter
        joint1_KP = 1
        joint2_KP = 1
        joint3_KP = 3  # as fast as possible to accelerate

        action1 = ((joint1 / 180) - self.obs[0]) * joint1_KP
        action2 = ((joint2 / 90) - self.obs[1]) * joint2_KP
        action3 = ((joint3 / 125) - self.obs[2]) * joint3_KP

        # limit actions to [-1, 1]
        action1 = 1 if (action1 > 1) else action1
        action1 = -1 if (action1 < -1) else action1

        action2 = 1 if (action2 > 1) else action2
        action2 = -1 if (action2 < -1) else action2

        action3 = 1 if (action3 > 1) else action3
        action3 = -1 if (action3 < -1) else action3

        # return actions
        return np.array([action1, action2, action3]).astype(np.float)



        # -----------------------------------------------------------------------------------------------------------------
        # Teleoperation
        # -----------------------------------------------------------------------------------------------------------------
    def Teleoperation(self):

        stop = False

        if pygame.key.get_pressed()[pygame.K_LEFT]:
            self.stearing += 1
        if pygame.key.get_pressed()[pygame.K_RIGHT]:
            self.stearing -= 1
        if pygame.key.get_pressed()[pygame.K_UP]:
            self.keyoffset += 1
        if pygame.key.get_pressed()[pygame.K_DOWN]:
            self.keyoffset -= 1


        # Cycles through all the events currently occuring
        for event in pygame.event.get():


            # Condition becomes true when keyboard is pressed
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    self.stearing = 0
                    self.keyoffset = 0
                    print("reset control")
                if event.key == pygame.K_x:
                    stop = True
                    print("reset game")
                if event.key == pygame.K_0:
                    self.level = 0
                    print("level 0 at next start")
                if event.key == pygame.K_1:
                    self.level = 1
                    print("level 1 at next start")
                if event.key == pygame.K_2:
                    self.level = 2
                    print("level 2 at next start")
                if event.key == pygame.K_3:
                    self.level = 3
                    print("level 3 at next start")
                if event.key == pygame.K_4:
                    self.level = 4
                    print("level 4 at next start")
                if event.key == pygame.K_r:
                    self.backwards = not self.backwards
                    print("backwards: " + str(self.backwards))

        self.RoboPos(self.stearing, self.keyoffset)


        # scaled time to adjust movement speed
        time = self.step * 0.3
        if self.backwards:
            time = time * (-1)

        # continuous movement to move forward
        mean_angle_joint_2 = 90 - 30 - self.keyoffset
        mean_angle_joint_3 = 125 - 70
        phase_shift = +math.pi * 0.5
        range_of_motion_joint_2 = 30
        range_of_motion_joint_3 = 70

        joint2 = mean_angle_joint_2 - math.cos(time) * range_of_motion_joint_2
        joint3 = mean_angle_joint_3 - math.cos(time + phase_shift) * range_of_motion_joint_3

        # use Direction error directly for P controller of Joint 1
        joint1 = self.stearing

        # P controler for actions
        # scale joint agnles to [-1, 1], calculate error, multiply with proportional parameter
        joint1_KP = 1
        joint2_KP = 1
        joint3_KP = 3  # as fast as possible to accelerate

        action1 = ((joint1 / 180) - self.obs[0]) * joint1_KP
        action2 = ((joint2 / 90) - self.obs[1]) * joint2_KP
        action3 = ((joint3 / 125) - self.obs[2]) * joint3_KP

        # limit actions to [-1, 1]
        action1 = 1 if (action1 > 1) else action1
        action1 = -1 if (action1 < -1) else action1

        action2 = 1 if (action2 > 1) else action2
        action2 = -1 if (action2 < -1) else action2

        action3 = 1 if (action3 > 1) else action3
        action3 = -1 if (action3 < -1) else action3

        # return actions
        return np.array([action1, action2, action3]).astype(np.float), stop, self.level