def should_defending(self): ball = self.info.ball car = self.info.my_car our_goal = self.info.my_goal.center car_to_ball = ball.pos - car.pos in_front_of_ball = distance_2d(ball.pos, our_goal) < distance_2d( car.pos, our_goal) backline_intersect = line_backline_intersect( self.info.my_goal.center[1], vec2(car.pos), vec2(car_to_ball)) return in_front_of_ball and abs(backline_intersect) < 2000
def should_defend(self): """Method which returns a boolean regarding whether we should defend or not""" ball = self.info.ball car = self.info.my_car car_to_ball = ball.position - car.position in_front_of_ball = self.in_front_off_ball backline_intersect = line_backline_intersect(self.my_goal.center[1], vec2(car.position), vec2(car_to_ball)) return (in_front_of_ball and abs(backline_intersect) < 2000) or self.conceding
def should_dodge(agent): """"Method that checks if we should dodge""" car = agent.info.my_car their_goal = agent.their_goal close_to_goal = distance_2d(car.position, their_goal.center) < 4000 aiming_for_goal = abs(line_backline_intersect( their_goal.center[1], vec2(car.position), vec2(car.forward()))) < 850 bot_to_target = agent.info.ball.position - car.position local_bot_to_target = dot(bot_to_target, agent.info.my_car.orientation) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) close_to_ball = norm(vec2(bot_to_target)) < 750 good_angle = abs(angle_front_to_target) < math.radians(15) return close_to_ball and close_to_goal and aiming_for_goal and good_angle
def should_dodge(agent): car = agent.info.my_car their_goal = agent.info.their_goal close_to_goal = distance_2d(car.pos, their_goal.center) < 4000 aiming_for_goal = abs( line_backline_intersect(their_goal.center[1], vec2(car.pos), vec2(car.forward()))) < 850 bot_to_target = agent.info.ball.pos - car.pos local_bot_to_target = dot(bot_to_target, agent.info.my_car.theta) angle_front_to_target = math.atan2(local_bot_to_target[1], local_bot_to_target[0]) close_to_ball = norm(vec2(bot_to_target)) < 850 good_angle = math.radians(-10) < angle_front_to_target < math.radians(10) return close_to_ball and close_to_goal and aiming_for_goal and good_angle
def should_defending(self): return False # Don't. """Method which returns a boolean regarding whether we should defend or not""" ball = self.info.ball car = self.info.my_car our_goal = self.my_goal.center car_to_ball = ball.location - car.location in_front_of_ball = distance_2d(ball.location, our_goal) < distance_2d( car.location, our_goal) backline_intersect = line_backline_intersect(self.my_goal.center[1], vec2(car.location), vec2(car_to_ball)) return (in_front_of_ball and abs(backline_intersect) < 2000) or self.conceding
def shooting_target(agent): """"Method that gives the target for the shooting strategy""" ball = agent.info.ball car = agent.info.my_car car_to_ball = ball.location - car.location backline_intersect = line_backline_intersect(agent.their_goal.center[1], vec2(car.location), vec2(car_to_ball)) if abs(backline_intersect) < 700: goal_to_ball = normalize(car.location - ball.location) error = 0 else: # Right of the ball if -500 > backline_intersect: target = agent.their_goal.corners[3] + vec3(400, 0, 0) # Left of the ball elif backline_intersect > 500: target = agent.their_goal.corners[2] - vec3(400, 0, 0) goal_to_ball = normalize(ball.location - target) # Subtract the goal to car vector difference = goal_to_ball - normalize(car.location - target) error = cap(abs(difference[0]) + abs(difference[1]), 0, 5) goal_to_ball_2d = vec2(goal_to_ball[0], goal_to_ball[1]) test_vector_2d = dot(rotation(0.5 * math.pi), goal_to_ball_2d) test_vector = vec3(test_vector_2d[0], test_vector_2d[1], 0) distance = cap( (40 + distance_2d(ball.location, car.location) * (error**2)) / 1.8, 0, 4000) location = ball.location + vec3( (goal_to_ball[0] * distance), goal_to_ball[1] * distance, 0) # this adjusts the target based on the ball velocity perpendicular # to the direction we're trying to hit it multiplier = cap(distance_2d(car.location, location) / 1500, 0, 2) distance_modifier = cap( dot(test_vector, ball.velocity) * multiplier, -1000, 1000) location += vec3(test_vector[0] * distance_modifier, test_vector[1] * distance_modifier, 0) # another target adjustment that applies if the ball is close to the wall extra = 3850 - abs(location[0]) if extra < 0: location[0] = cap(location[0], -3850, 3850) location[1] = location[1] + (-sign(agent.team) * cap(extra, -800, 800)) return location
def shooting_target(agent): ball = agent.info.ball car = agent.info.my_car car_to_ball = ball.pos - car.pos backline_intersect = line_backline_intersect( agent.info.their_goal.center[1], vec2(car.pos), vec2(car_to_ball)) if -500 < backline_intersect < 500: goal_to_ball = normalize(car.pos - ball.pos) error = cap(distance_2d(ball.pos, car.pos) / 1000, 0, 1) else: # Right of the ball if -500 > backline_intersect: target = agent.info.their_goal.corners[3] + vec3(400, 0, 0) # Left of the ball elif 500 < backline_intersect: target = agent.info.their_goal.corners[2] - vec3(400, 0, 0) goal_to_ball = normalize(ball.pos - target) goal_to_car = normalize(car.pos - target) difference = goal_to_ball - goal_to_car error = cap(abs(difference[0]) + abs(difference[1]), 1, 10) goal_to_ball_2d = vec2(goal_to_ball[0], goal_to_ball[1]) test_vector_2d = dot(rotation(0.5 * math.pi), goal_to_ball_2d) test_vector = vec3(test_vector_2d[0], test_vector_2d[1], 0) distance = cap((40 + distance_2d(ball.pos, car.pos) * (error**2)) / 1.8, 0, 4000) location = ball.pos + vec3( (goal_to_ball[0] * distance), goal_to_ball[1] * distance, 0) # this adjusts the target based on the ball velocity perpendicular to the direction we're trying to hit it multiplier = cap(distance_2d(car.pos, location) / 1500, 0, 2) distance_modifier = cap( dot(test_vector, ball.vel) * multiplier, -1000, 1000) modified_vector = vec3(test_vector[0] * distance_modifier, test_vector[1] * distance_modifier, 0) location += modified_vector # another target adjustment that applies if the ball is close to the wall extra = 3850 - abs(location[0]) if extra < 0: location[0] = cap(location[0], -3850, 3850) location[1] = location[1] + (-sign(agent.team) * cap(extra, -800, 800)) return location
def step(self): """"Gives output for the dribbling strategy""" # direction of ball relative to center of car (where should we aim) # direction of ball relative to yaw of car (where should we aim verse where we are aiming) local_bot_to_ball = dot(self.ball.position - self.car.position, self.car.orientation) angle_front_to_ball = math.atan2(local_bot_to_ball[1], local_bot_to_ball[0]) # distance between bot and ball distance = distance_2d(self.car.position, self.ball.position) # direction of ball velocity relative to yaw of car (which way the ball is moving verse which way we are moving) if velocity_2d(self.ball.velocity) < 1e-10: angle_car_forward_to_ball_velocity = 0 else: angle_car_forward_to_ball_velocity = angle_between( z_0(self.car.forward()), z_0(self.ball.velocity)) # magnitude of ball_bot_angle (squared) ball_bot_diff = (self.ball.velocity[0]**2 + self.ball.velocity[1]**2) - (self.car.velocity[0]**2 + self.car.velocity[1]**2) # p is the distance between ball and car # i is the magnitude of the ball's velocity (squared) the i term would normally # be the integral of p over time, but the ball's velocity is essentially that number # d is the relative speed between ball and car # note that bouncing a ball is distinctly different than balancing something that doesnt bounce # p_s is the x component of the distance to the ball # d_s is the one frame change of p_s, that's why p_s has to be global # we modify distance and ball_bot_diff so that only the component along the car's path is counted # if the ball is too far to the left, we don't want the bot to think it has to drive forward # to catch it distance_y = math.fabs(distance * math.cos(angle_front_to_ball)) distance_x = math.fabs(distance * math.sin(angle_front_to_ball)) # ball moving forward WRT car yaw? forward = False if math.fabs(angle_car_forward_to_ball_velocity) < math.radians(90): forward = True # first we give the distance values signs if forward: d = ball_bot_diff i = (self.ball.velocity[0]**2 + self.ball.velocity[1]**2) else: d = -ball_bot_diff i = -(self.ball.velocity[0]**2 + self.ball.velocity[1]**2) if math.fabs(math.degrees(angle_front_to_ball)) < 90: p = distance_y else: p = -1 * distance_y # this is the PID correction. all of the callibration goes on right here # there is literature about how to set the variables but it doesn't work quite the same # because the car is only touching the ball (and interacting with the system) on bounces # we run the PID formula through tanh to give a value between -1 and 1 for steering input # if the ball is lower we have no velocity bias bias_v = 600000 # 600000 # just the basic PID if the ball is too low if self.ball.position[2] < 120: correction = np.tanh((20 * p + .0015 * i + .006 * d) / 500) # if the ball is on top of the car we use our bias (the bias is in velocity units squared) else: correction = np.tanh( (20 * p + .0015 * (i - bias_v) + .006 * d) / 500) # makes sure we don't get value over .99 so we dont exceed maximum thrust self.controls.throttle = correction * .99 # anything over .9 is boost if correction > .99: self.controls.boost = True else: self.controls.boost = False # this is the PID steering section # p_s is the x component of the distance to the ball (relative to the cars direction) # d_s is the on frame change in p_s # we use absolute value and then set the sign later d_s = math.fabs(self.p_s) - math.fabs(distance_x) self.p_s = math.fabs(distance_x) # give the values the correct sign if angle_front_to_ball < 0: self.p_s = -self.p_s d_s = -d_s # d_s is actually -d_s ...whoops d_s = -d_s max_bias = 35 backline_intersect = line_backline_intersect(self.goal.center[1], vec2(self.car.position), vec2(self.car.forward())) if abs(backline_intersect) < 1000 or self.ball.position[2] > 200: bias = 0 # Right of the ball elif -850 > backline_intersect: bias = max_bias # Left of the ball elif 850 < backline_intersect: bias = -max_bias # the correction settings can be altered to change performance correction = np.tanh((100 * (self.p_s + bias) + 1500 * d_s) / 8000) # apply the correction self.controls.steer = correction