Esempio n. 1
0
class Final_Driver(Driver):

    def __init__(self, steering_values, global_max_speed):
        super(Final_Driver, self).__init__()
        self.steer = ffnn_steer.Steer(10)
        self.steer.load_state_dict(torch.load("./steer.data"))
        self.speed = ffnn_speed.Speed(10)
        self.speed.load_state_dict(torch.load("./ffnn_speed.data"))
        self.back_up_driver = Driver(logdata=False)
        self.bad_counter = 0
        self.lap_counter = 0
        self.brake_row = 0
        self.angles = [90, 75, 60, 45, 30, 20, 15, 10, 5, 0, -5, -10, -15, -20, -30, -45, -60, -75, -90]
        self.alphas = [math.radians(x) for x in self.angles]
        self.last_opponents = [0 for x in range(36)]
        self.steering_values = steering_values
        self.global_max_speed = global_max_speed

    def update_trackers(self, carstate):
        if carstate.current_lap_time == 0:
            self.lap_counter += 1
            print("Lap={}".format(self.lap_counter))
        print("distance:",carstate.distance_raced)

    def drive(self, carstate: State) -> Command:
        self.update_trackers(carstate)
        if self.in_a_bad_place(carstate):
            command = self.back_up_driver.drive(carstate)
            if self.bad_counter >= 600 and is_stuck(carstate):
                # we try reversing
                command.gear = -command.gear
                if command.gear < 0:
                    command.steering = -command.steering
                    command.gear = -1
                self.bad_counter = 200
        else:
            # since the data and python's values differ we need to adjust them
            carstate.angle = math.radians(carstate.angle)
            carstate.speed_x = carstate.speed_x*3.6
            command = self.make_next_command(carstate)
            # based on target, implement speed/steering manually
        print("Executing command: gear={}, acc={}, break={}, steering={}".format(command.gear,
                                                                                 command.accelerator,
                                                                                 command.brake,
                                                                                 command.steering))

        return command

    def make_next_command(self, carstate):
        command = Command()

        # we switch gears manually
        gear = self.gear_decider(carstate)
        # we get the steering prediction
        steer_pred = self.steer_decider(carstate, steering_values=self.steering_values)
        # steer_pred = self.steer_decider_nn(carstate)
        # pedal =[-1;1], combining breaking and accelerating to one variable
        pedal = self.speed_decider(carstate, max_speed=self.global_max_speed)

        # make sure we don't drive at people
        opponents_deltas = list(map(sub, carstate.opponents, self.last_opponents))
        steer_pred, pedal = self.deal_with_opponents(steer_pred, pedal, carstate.speed_x, carstate.distance_from_center, carstate.opponents, opponents_deltas)
        # disambiguate pedal with smoothing
        brake, accel = self.disambiguate_pedal(pedal, accel_cap=1.0, break_cap=0.75, break_max_length=5)

        command.brake = brake
        command.accelerator = accel
        command.steering = steer_pred
        command.gear = gear
        return command

    def deal_with_opponents(self, steer_pred, pedal, speed, distance_from_center, opponents_new, opponents_delta):
        # index 18 is in front
        # index 35 in behind us
        adjustment = 0.1
        # if there are cars infront-left -> move to right
        if opponents_new[17] < 10 or opponents_new[16] < 10 or opponents_new[15] < 10:
            print("ADJUSTING SO NOT TO HIT")
            steer_pred -= adjustment
        if opponents_new[19] < 10 or  opponents_new[20] < 10 or opponents_new[21] < 10:
            print("ADJUSTING SO NOT TO HIT")
            # move to left
            steer_pred += adjustment
        if opponents_new[18] < 50:
            # we are on left side -> move right
            if distance_from_center > 0:
                steer_pred -= adjustment
            # o.w. move left
            else:
                steer_pred += adjustment
        if speed > 100:
            # we are getting closer to the car in front (and we can't avoid it). We need to slow down a bit
            if (opponents_delta[18] < 0 and opponents_new[18] < 20) or (opponents_delta[17] < 0 and opponents_new[17] < 4) or (opponents_delta[19] < 0 and opponents_new[19] < 4):
                pedal -= 0.1

        return steer_pred, pedal

    def disambiguate_pedal(self, pedal, accel_cap=0.5, break_cap=0.75, break_max_length=5):
        if pedal >= 0.0:
            accelerator = pedal*accel_cap
            brake = 0
        else:
            # we need to make sure that we don't break hard enough and not too long
            self.brake_row += 1
            if self.brake_row <= break_max_length:
                brake = abs(pedal)*break_cap
            else:
                self.brake_row = 0
                brake = 0
            accelerator = 0
        return brake, accelerator

    def steer_decider(self, carstate, steering_values):
        alpha_index = np.argmax(carstate.distances_from_edge)
        if is_straight_line(carstate=carstate, radians=self.alphas[alpha_index], factor=steering_values[4]):
            return carstate.angle*0.5

        steering_function = lambda index, offset: (self.alphas[index-offset]*carstate.distances_from_edge[index-offset] + self.alphas[index+offset]*carstate.distances_from_edge[index+offset])/(carstate.distances_from_edge[index+offset]+carstate.distances_from_edge[index-offset])

        steer = steering_values[0]*self.alphas[alpha_index]
        for x in range(1, 4):
            if alpha_index - x > -1 and alpha_index + x < len(steering_values):
                steer += steering_values[x]*steering_function(alpha_index, x)
        return steer


    def speed_decider(self, carstate, max_speed=120):
        # we predict speed and map that to pedal
        x_in = ffnn_speed.carstate_to_variable(carstate)
        target_speed = self.speed(x_in).data[0]
        # we limit the speed
        if target_speed >= max_speed:
            target_speed = max_speed
        pedal = 2/(1 + np.exp(carstate.speed_x - target_speed))-1
        return pedal

    def gear_decider(self, carstate):
        gear = carstate.gear
        rpm = carstate.rpm
        # we do gears by hand
        # up if {9500 9500 9500 9500 9000}
        # down if {4000 6300 7000 7300 7300}
        if gear == -1:
            return 1
        elif gear == 0:
            if rpm >= 5000:
                gear = 1
        elif gear == 1:
            if rpm >= 9500:
                gear = 2
        elif gear == 2:
            if rpm >= 9500:
                gear = 3
            elif rpm <= 4000:
                gear = 2
        elif gear == 3:
            if rpm >= 9500:
                gear = 4
            elif rpm <= 6300:
                gear = 3
        elif gear == 4:
            if rpm >= 9500:
                gear = 5
            elif rpm <= 7000:
                gear = 3
        elif gear == 5:
            if rpm >= 9000:
                gear = 6
            elif rpm <= 7300:
                gear = 4
        elif gear == 6:
            if rpm <= 7300:
                gear = 5

        return gear


    def in_a_bad_place(self, carstate):
        something_wrong = False
        if is_offroad(carstate):
            print("I'm offroad!")
            something_wrong = True
        if is_reversed(carstate):
            print("I'm reversed!")
            something_wrong = True
        if is_stuck(carstate):
            print("I'm stuck!")
            something_wrong = True
        if (something_wrong):
            self.bad_counter += 1
        else:
            self.bad_counter = 0
        # if we have been in a bad place for 2 seconds
        if self.bad_counter >= 100:
            return True
        return False
Esempio n. 2
0
class CrisisDriver(Driver):

    def __init__(self, logdata=True):
        """ Handles difficult situations in which the car gets stuck
        """
        super(CrisisDriver, self).__init__(logdata=logdata)
        self.iter = 0
        self.driver = Driver(logdata=False)
        self.is_in_control = False
        self.approaches = [self.navigate_to_middle, self.original_implementation]
        self.previous_angles = []
        self.previous_accels = []
        self.previous_gears  = []
        self.bad_counter = 0
        self.needs_help = False

    def drive(self, carstate):
        """ Gets the car out of a difficult situation

        Tries different approaches and gives each one a time out.
        A class level variable keeps track of the current approach
        across game cycles. If the timer runs out, the approach
        is terminated and the next approach gets initiated.

        Args:
            carstate:   All parameters packed in a State object

        Returns:
            command:    The next move packed in a Command object

        """
        command = Command()
        command.accelerator = 0
        self.appr_counter += 1
        if self.appr_counter > APPROACH_TIMEOUT:
            self.next_approach()
        try:
            command = self.approaches[self.approach](carstate, command)
            self.previous_accels.append(command.accelerator)
            self.previous_gears.append(command.gear)
        except Exception as e:
            err(self.iter, "ERROR:", str(e))

        return command

    def pass_control(self, carstate):
        """ Initializes a new crisis that has not been handled yet

        Args:
            carstate:   The original carstate

        """
        err(self.iter,"CRISIS: control received")
        self.is_in_control = True
        self.approach = 0
        self.appr_counter = 0
        # check if car in front
        # check if car behind
        # check track angle and side of the road
        # determine reverse or straight ahead

    def return_control(self):
        """ Passes control back to the main driver """
        err(self.iter,"CRISIS: control returned")
        self.is_in_control = False
        self.needs_help = False
    
    def next_approach(self):
        """ Adjusts state to next approach """
        self.approach += 1
        self.appr_counter = 0
        if self.approach >= len(self.approaches):
            self.approach -= 1
            self.return_control()
        else:
            err(self.iter,"CRISIS: next approach:",
                self.approaches[self.approach].__name__)

    def approach_succesful(self):
        """ Called when a technique finished executing
        """
        err(self.iter,"CRISIS: approach succesful:",
            self.approaches[self.approach].__name__)
        if self.has_problem:
            self.next_approach()
        else:
            self.return_control()

    def update_status(self, carstate):
        """ Updates the status of the car regarding its problems

        Args:
            carstate:   The full carstate

        """
        self.iter += 1
        if len(self.previous_angles) >= MAX_ANGLES:
            self.previous_angles.pop(0)
        self.previous_angles.append(carstate.angle)
        if len(self.previous_accels) >= MAX_ACCELS:
            self.previous_accels.pop(0)
        self.previous_gears.append(sign(carstate.gear))
        if len(self.previous_gears)  >= MAX_GEARS:
            self.previous_gears.pop(0)

        self.is_on_left_side  = sign(carstate.distance_from_center) == DFC_L
        self.is_on_right_side = not self.is_on_left_side
        self.faces_left   = sign(carstate.angle) == ANG_L
        self.faces_right  = not self.faces_left
        self.faces_front  = abs(carstate.angle) < 90
        self.faces_back   = not self.faces_front
        self.faces_middle = self.is_on_left_side == self.faces_right

        self.is_standing_still = abs(carstate.speed_x) < 0.1 
        self.has_car_in_front  = car_in_front(carstate.opponents)
        self.has_car_behind    = car_behind(carstate.opponents)
        self.is_blocked        = blocked(self.previous_accels,
                                         self.previous_gears,
                                         carstate.speed_x)
        self.is_off_road = max(carstate.distances_from_edge) == -1
        self.is_reversed = self.faces_back
        self.is_going_in_circles = going_in_circles(self.previous_angles)
        self.is_traveling_sideways = abs(carstate.speed_y) > 15
        self.has_problem = self.is_off_road or \
                           self.is_going_in_circles or \
                           self.is_blocked or \
                           self.is_reversed or \
                           self.is_traveling_sideways
        if self.has_problem:
            self.bad_counter += 1
            if self.bad_counter >= BAD_COUNTER_THRESHOLD:
                if self.is_off_road:
                    debug(self.iter, "        off road")
                if self.is_going_in_circles:
                    debug(self.iter, "        going in circles")
                if self.is_blocked:
                    debug(self.iter, "        blocked")
                if self.is_reversed:
                    debug(self.iter, "        reversed")
                self.needs_help = True
        else:
            self.bad_counter = 0
            self.needs_help = False

    #
    # Approach Implementations
    #
    def original_implementation(self, carstate, command):
        """

        approach 0)

        Args:
            carstate:       The full carstate as passed down by the server
            command:        The command to adjust

        """
        if not self.is_off_road and abs(carstate.angle) < CTR_ANG_MARGIN:
            self.approach_succesful()
        command.gear, carstate.gear = 1, 1
        command = self.driver.drive(carstate) # TODO is this legal?
        is_stuck = abs(carstate.speed_x) <= 5 and carstate.current_lap_time >= 10
        #if self.bad_counter >= BAD_COUNTER_MANUAL_THRESHOLD and is_stuck:
            # we try reversing
            # command.gear = -command.gear
            # if command.gear < 0:
            #     command.steering = -command.steering
            #     command.gear = -1
            # self.bad_counter = 200
        command.accelerator /= 2.0
        return command

    def navigate_to_middle(self, carstate, command):
        """ Finds it way to the middle of the road by driving in reverse

        approach 1) reverse towards the road, then once on the road,
                    reverse towards the the middle until facing foward
                    with an angle that's within the margin

        Args:
            carstate:       The full carstate as passed down by the server
            command:        The command to adjust

        """
        debug(self.iter,"CRISIS: navigate_to_middle")

        dfc = carstate.distance_from_center
        if self.is_off_road:
            dist_spd = 2 if abs(dfc) > 10 else 1
            perp_angle = 90 * sign(dfc)
            if self.faces_middle:
                debug(self.iter,"        off road and facing road")
                diff_with_perp_angle = perp_angle - carstate.angle
                if not abs(diff_with_perp_angle) < PRP_ANG_MARGIN:
                    command.steering = sign(diff_with_perp_angle) * STR_R
                command.gear = 1
                command.accelerator = OFF_ROAD_ACC * dist_spd
            else:
                debug(self.iter,"        off road and not facing road")
                diff_with_perp_angle = perp_angle + carstate.angle
                if not abs(diff_with_perp_angle) < PRP_ANG_MARGIN:
                    command.steering = sign(diff_with_perp_angle) * STR_R
                command.gear = -1
                command.accelerator = OFF_ROAD_REV_ACC * dist_spd
        else:
            if abs(carstate.angle) < CTR_ANG_MARGIN:
                self.approach_succesful()
            else:
                if self.faces_middle or abs(carstate.angle) < 50: # TODO globalize
                    debug(self.iter,"        on road facing middle")
                    command.steering = to_ang(carstate.angle)
                    command.gear = 1
                    command.accelerator = ACC
                elif abs(dfc) > 0.5:
                    debug(self.iter,"        on road not facing middle")
                    command.steering = away_from_ang(carstate.angle)
                    command.gear = -1
                    command.accelerator = REV_ACC
        
        if self.is_blocked:
            command.gear = 1
            command.accelerator *= 2
            debug(self.iter, "ang=%.2f, spd=%.2f, dfc=%.2f"
                      %(carstate.angle, carstate.speed_x, carstate.distance_from_center))
            debug(self.iter, "ste=%.2f, acc=%.2f, gea=%.2f"
                      %(command.steering, command.accelerator, command.gear))
        
        # when spinning out of control, don't do anything
        if self.is_traveling_sideways or self.is_going_in_circles:
            command.acceleration = 0
        
        gstc = GEAR_SHIFTING_TRANSITION_CYCLES
        # braking when shifting gear so it doesn't continue its course
        if any(not g == command.gear for g in self.previous_gears[-gstc:]):
            command.brake = 1
            command.acceleration = 0
        # faster acceleration after having shifted gears
        elif any(not g == command.gear for g in self.previous_gears[-gstc*2:-gstc]):
            command.brake = 0
            command.acceleration = 1.0
        return command