Пример #1
0
    def execute_charge(self):
        self.robot.disable_avoid_ball()
        main.debug_drawer().draw_line(
            robocup.Line(self.robot.pos, self.aim_target_point),
            constants.Colors.White, "LineKickOld")
        main.debug_drawer().draw_line(
            robocup.Line(main.ball().pos, self.aim_target_point),
            constants.Colors.White, "LineKickOld")

        # drive directly into the ball
        ball2target = (self.aim_target_point - main.ball().pos).normalized()
        robot2ball = (main.ball().pos - self.robot.pos).normalized()
        speed = min(self.robot.vel.mag() + LineKickOld.AccelBias,
                    self.MaxChargeSpeed)
        self.robot.set_world_vel(robot2ball.normalized() * speed)

        self.robot.face(self.aim_target_point)

        if main.ball().pos.dist_to(
                self.robot.pos) < LineKickOld.ClosenessThreshold:
            self._got_close = True

        if self.robot.has_ball():
            if self.use_chipper:
                self.robot.chip(self.chip_power)
            else:
                self.robot.kick(self.kick_power)
    def in_shot_triangle(self, best_point, alt_point):
        # get the two points of the enemies goal
        goalSegment = constants.Field.TheirGoalSegment

        right_post = goalSegment.get_pt(0)
        left_post = goalSegment.get_pt(1)
        # draw the line from the ideal passing position to the goal corners
        main.system_state().draw_line(robocup.Line(right_post, best_point),
                                      (255, 0, 255), "Shot Range")
        main.system_state().draw_line(robocup.Line(left_post, best_point),
                                      (255, 0, 255), "Shot Range")
        # angle between the line from ideal pass point and the goal corner and between the line ideal pass point and other goal corner
        shot_angle = (right_post - best_point).angle_between(
            (left_post - best_point))
        # angle between the line from ideal pass point and goal corner 1 and between the line from ideal pass point and 2nd best pass point
        left_post_alt_pos_angle = (best_point -
                                   alt_point).angle_between(best_point -
                                                            right_post)
        # angle between the line from ideal pass point and goal corner 2 and between the line from ideal pass point and 2nd best pass point
        right_post_alt_pos_angle = (best_point -
                                    alt_point).angle_between(best_point -
                                                             left_post)

        # decides which side is closer to point by the smaller theta
        if left_post_alt_pos_angle < right_post_alt_pos_angle:
            self.closest_post = left_post
        else:
            self.closest_post = right_post
        # if interior angles near sum to 0 then robot is inside the the zone.
        return abs(shot_angle - left_post_alt_pos_angle -
                   right_post_alt_pos_angle) < self.epsilon
Пример #3
0
    def recalculate(self):
        # can't do squat if we don't know what we're supposed to do
        if self.receive_point == None or self.robot == None:
            return

        ball = main.ball()

        if self.ball_kicked:
            # when the ball's in motion, the line is based on the ball's velocity
            self._pass_line = robocup.Line(ball.pos, ball.pos + ball.vel * 10)
        else:
            # if the ball hasn't been kicked yet, we assume it's going to go through the receive point
            self._pass_line = robocup.Line(ball.pos, self.receive_point)

        target_angle_rad = (ball.pos - self.robot.pos).angle()
        angle_rad = self.robot.angle
        self._angle_error = target_angle_rad - angle_rad

        if self.ball_kicked:
            actual_receive_point = self._pass_line.nearest_point(
                self.robot.pos)
        else:
            actual_receive_point = self.receive_point

        pass_line_dir = (self._pass_line.get_pt(1) -
                         self._pass_line.get_pt(0)).normalized()
        self._target_pos = actual_receive_point + pass_line_dir * constants.Robot.Radius

        # vector pointing down the pass line toward the kicker
        pass_dir = (self._pass_line.get_pt(0) -
                    self._pass_line.get_pt(1)).normalized()

        pos_error = self._target_pos - self.robot.pos
        self._x_error = pos_error.dot(pass_dir.perp_ccw())
        self._y_error = pos_error.dot(pass_dir)
Пример #4
0
    def recalculate(self):
        if abs(self.robot.angle_vel) > self.max_steady_ang_vel:
            self._last_unsteady_time = time.time()

        # find the point we're actually aiming at that's on the line going through target_point
        # and perpendicular to the line from the ball to target_point
        if self.target_point == None:
            self._shot_point = None
        else:
            ball2target = self.target_point - main.ball().pos
            target_line = robocup.Line(
                self.target_point, self.target_point + ball2target.perp_ccw()
            )  # line perpendicular to aim_line that passes through the target

            # ideally the angle we're aiming at would be the angle of the robot, but the bot doesn't kick straight
            # it tends to kick in the direction of the side of the mouth that the ball is in
            # we draw a line from the center of the bot through the ball and a line along the angle the bot is facing
            # our 'actual' aim line is somewhere in-between the two
            bot_angle_rad = self.robot.angle
            ball_angle_rad = (main.ball().pos - self.robot.pos).angle()
            # if the ball angle rad is off by too much, we probably lost sight of it and are going off last known position
            # if we detect this big of an error, we just default to using bot_angle_rad
            if abs(ball_angle_rad - bot_angle_rad) > math.pi / 3.0:
                ball_angle_rad = bot_angle_rad
            #TODO: TUNE THIS
            ball_angle_bias = 0.4  # NOTE: THIS IS TUNABLE
            aim_angle = ball_angle_rad * ball_angle_bias + (
                1.0 - ball_angle_bias) * bot_angle_rad

            # the line we're aiming down
            angle_dir = robocup.Point.direction(aim_angle)
            aim_line = robocup.Line(self.robot.pos, self.robot.pos + angle_dir)

            # we need to change our face target a bit to account for the difference between bot angle and aim angle
            face_angle_offset = bot_angle_rad - aim_angle
            target_angle_rad = (self.target_point - self.robot.pos).angle()
            face_dir_offset = robocup.Point.direction(target_angle_rad +
                                                      face_angle_offset)
            self._face_target = self.robot.pos + face_dir_offset

            # self._shot_poitn is the point along target_line that we'll hit if we shoot now
            # We check to make sure we're not facing backwards from where we want to be or else
            # the line intersection will return us a point 180 degrees off from our aim angle
            if angle_dir.dot(ball2target) < 0:
                self._shot_point = None
            else:
                self._shot_point = aim_line.line_intersection(target_line)

        # error
        if self.target_point != None and self._shot_point != None:
            self._error = (
                self.target_point -
                self._shot_point).mag() if self._shot_point != None else float(
                    "inf"
                )  # distance in meters off that we'll be if we shoot right now
        else:
            self._error = float("inf")
Пример #5
0
    def obstacle_robot(self, windows, origin, target, bot_pos):
        n = (bot_pos - origin).normalized()
        t = n.perp_ccw()
        r = constants.Robot.Radius + constants.Ball.Radius
        seg = robocup.Segment(bot_pos - n*constants.Robot.Radius + t * r,
                                bot_pos - n*constants.Robot.Radius - t * r)

        if self.debug:
            main.system_state().draw_line(seg, constants.Colors.Red, "debug")

        end = target.delta().magsq()
        extent = [0, end]

        for i in range(2):
            edge = robocup.Line(origin, seg.get_pt(i))
            d = edge.delta().magsq()

            intersect = edge.line_intersection(target)
            if intersect != None and (intersect - origin).dot(edge.delta()) > d:
                t = (intersect - target.get_pt(0)).dot(target.delta())
                if t < 0:
                    extent[i] = 0
                elif t > end:
                    extent[i] = end
                else:
                    extent[i] = t
            else:
                # Obstacle has no effect
                return
        self.obstacle_range(windows, extent[0], extent[1])
Пример #6
0
    def __init__(self):
        super().__init__(continuous=False)

        self.target = robocup.Point(0, constants.Field.Length)

        self.add_state(Bump.State.lineup, behavior.Behavior.State.running)
        self.add_state(Bump.State.charge, behavior.Behavior.State.running)

        self.add_transition(behavior.Behavior.State.start, Bump.State.lineup,
                            lambda: True, 'immediately')

        self.add_transition(
            Bump.State.lineup, Bump.State.charge, lambda: self.target_line(
            ).dist_to(self.robot.pos) <= Bump.LineupToChargeThresh and self.
            target_line().delta().dot(self.robot.pos - main.ball().pos) <=
            -constants.Robot.Radius and not self.facing_err_above_threshold(),
            'lined up')

        # FIXME: this condition was never setup in the C++ one...
        self.add_transition(
            Bump.State.charge, behavior.Behavior.State.completed, lambda:
            (main.ball().pos - self.robot.pos).mag() <
            (constants.Robot.Radius + constants.Ball.Radius + 0.03),
            'ball has been bumped')

        self.add_transition(
            Bump.State.charge, Bump.State.lineup,
            lambda: robocup.Line(self.robot.pos, self.target).dist_to(
                main.ball().pos) > Bump.EscapeChargeThresh,
            'bad ball placement')
Пример #7
0
    def execute_running(self):
        # checks if there is an offensive behavior for the various plays and set the normal speed
        for sub in self.subbehaviors_by_name():
            if (sub != 'passer'):
                robo = self.subbehavior_with_name(sub).robot
                # checks if there is a chasing robot and set their speed to defense speed
                if (robo != None):
                    if (sub == 'chasing'):
                        robo.set_max_speed(self.defense_speed)
                    # otherwise sets to the offensive normal speed rate
                    else:
                        robo.set_max_speed(self.normal_speed)

        # chasing robot positon should always follow the ball within a smaller inside box of the
        # four corners.
        if (self.has_subbehavior_with_name('chasing')):
            self.chaser.pos = self.cut_off_pos(main.ball().pos)

        #draw the four courner field
        # takes in the square points and form lines and create a square on the field
        for i in range(len(self.square_points)):
            main.debug_drawer().draw_line(
                robocup.Line(self.square_points[i],
                             self.square_points[(i + 1) % 4]), (135, 0, 255),
                "Square")

        # speed of the hunting robots
        #TODO Create python pull from Config values. Currently this breaks the world.
        #tmp = copy.deepcopy(robocup.Configuration.FromRegisteredConfigurables().nameLookup("MotionConstraints/Max Velocity").value)
        self.normal_speed = 1.0  # tmp
        #speed of the defending robots can decrease value to make it easier for offense
        self.defense_speed = 2 * self.normal_speed / 3.0  #self.normal_speed/2.0#self.variable_square/(min(self.width,self.length) * 2) * self.normal_speed
Пример #8
0
    def execute_running(self):
        if self.robot.has_ball():
            self.last_ball_time = time.time()
            self.startBallLocation = main.ball().pos

        self.recalculate()

        self.robot.set_max_speed(0.3)
        self.robot.set_max_accel(0.3)

        # slowly pivot toward the target
        #self.robot.set_max_angle_speed(4)
        self.robot.pivot(self._face_target)
        self.robot.set_dribble_speed(self.dribbler_power)

        # draw current shot line
        if self._shot_point != None:
            color = constants.Colors.Green if self.is_aimed(
            ) else constants.Colors.Red
            main.system_state().draw_line(
                robocup.Line(self.robot.pos, self._shot_point), color, "Aim")
            main.system_state().draw_circle(self._shot_point, 0.02, color,
                                            "Aim")

        # draw where we're supposed to be aiming
        if self.target_point != None:
            main.system_state().draw_circle(self.target_point, 0.02,
                                            constants.Colors.Blue, "Aim")
Пример #9
0
    def execute_running(self):
        # make sure teammates don't bump into us
        self.robot.shield_from_teammates(constants.Robot.Radius * 2.0)

        if self.robot.has_ball():
            self.last_ball_time = time.time()

        self.recalculate()

        # slowly pivot toward the target
        self.robot.set_max_angle_speed(4)
        self.robot.pivot(self._face_target)
        self.robot.set_dribble_speed(self.dribbler_speed)

        # draw current shot line
        if self._shot_point != None:
            color = constants.Colors.Green if self.is_aimed(
            ) else constants.Colors.Red
            main.system_state().draw_line(
                robocup.Line(self.robot.pos, self._shot_point), color, "Aim")
            main.system_state().draw_circle(self._shot_point, 0.02, color,
                                            "Aim")

        # draw where we're supposed to be aiming
        if self.target_point != None:
            main.system_state().draw_circle(self.target_point, 0.02,
                                            constants.Colors.Blue, "Aim")
Пример #10
0
 def execute_block(self):
     opposing_kicker = evaluation.ball.opponent_with_ball()
     if opposing_kicker is not None:
         winEval = evaluation.window_evaluator.WindowEvaluator()
         winEval.excluded_robots = [self.robot]
         best = winEval.eval_pt_to_our_goal(main.ball().pos)[1]
         if best is not None:
             shot_line = robocup.Line(opposing_kicker.pos, main.ball().pos)
             block_line = robocup.Line(robocup.Point(best.segment.get_pt(0).x - constants.Robot.Radius, constants.Robot.Radius),
                                 robocup.Point(best.segment.get_pt(1).x + constants.Robot.Radius, constants.Robot.Radius))
             main.system_state().draw_line(block_line, (255,0,0), "Debug")
             dest = block_line.line_intersection(shot_line)
             dest.x = min(Goalie.MaxX, dest.x)
             dest.x = max(-Goalie.MaxX, dest.x)
             self.robot.move_to(dest)
             return
     self.robot.move_to(robocup.Point(0,constants.Robot.Radius))
Пример #11
0
def find_robot_intercept_point(robot):
    if (robot is not None):
        passline = robocup.Line(
            main.ball().pos, main.ball().pos + main.ball().vel * 10)
        pos = passline.nearest_point(robot.pos) + (main.ball().vel * Capture.DampenMult)
        return pos
    else:
        return None
Пример #12
0
    def execute_aiming(self):
        self.set_aim_params()

        if isinstance(self.target, robocup.Segment):
            for i in range(2):
                main.system_state().draw_line(
                    robocup.Line(main.ball().pos, self.target.get_pt(i)),
                    constants.Colors.Blue, "PivotKick")
Пример #13
0
    def execute_charge(self):
        main.system_state().draw_line(robocup.Line(self.robot.pos, self.target),
            constants.Colors.White,
            "bump")
        main.system_state().draw_line(robocup.Line(main.ball().pos, self.target),
            constants.Colors.White,
            "bump")

        ball2target = (self.target - main.ball().pos).normalized()
        drive_dir = (main.ball().pos - ball2target * constants.Robot.Radius) - self.robot.pos

        # we want to drive toward the ball without using the path planner
        # we do this by setting the speed directly
        # AccelBias forces us to accelerate a bit more
        speed = self.robot.vel.mag() + Bump.AccelBias

        self.robot.set_world_vel(drive_dir.normalized() * speed)
        self.robot.face(main.ball().pos)
Пример #14
0
        def set_block_lines_for_threat_handlers(threat):
            if len(threat.assigned_handlers) == 0:
                return

            # make sure goalie is in the middle
            if len(threat.assigned_handlers) > 1:
                if goalie in threat.assigned_handlers:
                    idx = threat.assigned_handlers.index(goalie)
                    if idx != 1:
                        del threat.assigned_handlers[idx]
                        threat.assigned_handlers.insert(1, goalie)

            if threat.best_shot_window != None:
                center_line = robocup.Line(
                    threat.pos, threat.best_shot_window.segment.center())
            else:
                center_line = robocup.Line(
                    threat.pos, constants.Field.OurGoalSegment.center())

            # find the angular width that each defender can block.  We then space these out accordingly
            angle_widths = []
            for handler in threat.assigned_handlers:
                dist_from_threat = handler.robot.pos.dist_to(threat.pos)
                w = min(
                    2.0 * math.atan2(constants.Robot.Radius, dist_from_threat),
                    0.15)
                angle_widths.append(w)

            # start on one edge of our available angle coverage and work counter-clockwise,
            # assigning block lines to the bots as we go
            spacing = 0.01 if len(
                threat.assigned_handlers
            ) < 3 else 0.0  # spacing between each bot in radians
            total_angle_coverage = sum(angle_widths) + (len(angle_widths) -
                                                        1) * spacing
            start_vec = center_line.delta().normalized()
            start_vec.rotate(robocup.Point(0, 0), -total_angle_coverage / 2.0)
            for i in range(len(angle_widths)):
                handler = threat.assigned_handlers[i]
                w = angle_widths[i]
                start_vec.rotate(robocup.Point(0, 0), w / 2.0)
                handler.block_line = robocup.Line(threat.pos,
                                                  threat.pos + start_vec * 10)
                start_vec.rotate(robocup.Point(0, 0), w / 2.0 + spacing)
Пример #15
0
    def role_assignment_cost(robot):
        # Estimate the time it takes to intercept the ball
        # Use straight line distance to closest point along line
        # Then movement down the line

        # Represents ball movement line
        ball_move_line = robocup.Line(main.ball().pos,
                                      main.ball().pos + main.ball().vel * 10)

        # Closest point to robot on ball movement line
        ball_line_intercept = ball_move_line.nearest_point(robot.pos)

        ball_to_robot = robot.pos - main.ball().pos
        ball_to_intercept = ball_line_intercept - main.ball().pos
        robot_to_intercept = ball_line_intercept - robot.pos

        # If we are actually in front of the ball angle wise
        # OR close enough that it could be a bounce off the robot due to noisy vision
        in_front = ball_move_line.delta().angle_between(ball_to_robot) < math.pi/2 or \
                   ball_to_robot.mag() < 1.5*(constants.Robot.Radius + constants.Ball.Radius)

        # Calculate how much further the ball will move before we reach the point

        max_speed = robocup.MotionConstraints.MaxRobotSpeed.value
        max_acc = robocup.MotionConstraints.MaxRobotAccel.value

        # How long it will take the robot/ball to reach that intercept point
        ball_secs = main.ball().estimate_seconds_to(ball_line_intercept)
        robot_secs = robocup.get_trapezoidal_time(robot_to_intercept.mag(),
                                                  robot_to_intercept.mag(),
                                                  max_speed, max_acc, 0, 0)

        time_to_hit = robot_secs

        # If we aren't in front of the ball, we need to get time to catch up
        if (not in_front):
            # Difference in speed between us and ball
            delta_speed = max_speed - main.ball().vel.mag()

            # if we are slower than the ball, don't even try and just exclude it automatically
            if (delta_speed < 0):
                time_to_hit += 100
            # If we are fast, figure out how much more time we need
            else:
                delta_time = robocup.get_trapezoidal_time(
                    ball_to_intercept.mag(), ball_to_intercept.mag(),
                    delta_speed, max_acc, 0, 0)
                time_to_hit += delta_time

        #main.debug_drawer().draw_text(str(time_to_hit), robot.pos + robocup.Point(0.1,0.1), (255,255,255), "test")

        return time_to_hit * Capture.SETTLE_COST_MULTIPLIER
Пример #16
0
    def execute_running(self):
        # draw laps
        # indices = list(range(len(self.points))) + [0]
        # for i in range(len(indices)):
        main.system_state().draw_line(
            robocup.Line(self.points[0], self.points[1]), (255, 0, 0),
            "StressTest")

        m = self.subbehavior_with_name('move')
        if m.state == behavior.Behavior.State.completed:
            # increment index
            self.index = (self.index + 1) % len(self.points)
        m.pos = self.points[self.index]
Пример #17
0
    def on_enter_kick(self):
        OurFreeKick.Running = False
        kicker = skills.line_kick.LineKick()
        kicker.use_chipper = True
        kicker.min_chip_range = OurFreeKick.MinChipRange
        kicker.max_chip_range = OurFreeKick.MaxChipRange

        kicker.target = self.gap

        shooting_line = robocup.Line(main.ball().pos, self.gap)

        # If we are at their goal, shoot full power
        if shooting_line.segment_intersection(
                constants.Field.TheirGoalSegment) is not None:
            kicker.kick_power = self.FullKickPower
        # If we are aiming in the forward direction and not at one of the "endzones", shoot full power
        elif (shooting_line.line_intersection(constants.Field.FieldBorders[0])
              or
              shooting_line.line_intersection(constants.Field.FieldBorders[2])
              and self.gap.y - main.ball().pos.y > 0):
            kicker.kick_power = self.FullKickPower
        # If we are probably aiming down the field, slowly kick so we dont carpet
        else:
            kicker.kick_power = self.BumpKickPower

        # Try passing if we are doing an indirect kick
        if self.indirect:
            pass
            # Check for valid target pass position
            if self.receive_value != 0 and len(main.our_robots()) >= 5:
                self.remove_all_subbehaviors()
                pass_behavior = tactics.coordinated_pass.CoordinatedPass(
                    self.receive_pt,
                    None, (kicker, lambda x: True),
                    receiver_required=False,
                    kicker_required=False,
                    prekick_timeout=7,
                    use_chipper=True)
                # We don't need to manage this anymore
                self.add_subbehavior(pass_behavior, 'kicker')
            else:
                kicker.target = (self.pos_up_field)
                self.add_subbehavior(kicker,
                                     'kicker',
                                     required=False,
                                     priority=5)
        else:
            kicker.target = constants.Field.TheirGoalSegment
            self.add_subbehavior(kicker, 'kicker', required=False, priority=5)
Пример #18
0
def is_moving_towards_our_goal():
    # see if the ball is moving much
    if main.ball().vel.mag() > 0.1:
        # see if it's moving somewhat towards our goal
        if main.ball().vel.dot(robocup.Point(0, -1)) > 0:
            ball_path = robocup.Line(main.ball().pos, (main.ball().pos + main.ball().vel.normalized()))

            fudge_factor = 0.15 # TODO: this could be tuned better
            WiderGoalSegment = robocup.Segment(robocup.Point(constants.Field.GoalWidth / 2.0 + fudge_factor, 0),
                                        robocup.Point(-constants.Field.GoalWidth / 2.0 - fudge_factor, 0))

            pt = ball_path.line_intersection(WiderGoalSegment)
            return pt != None and abs(pt.x) < WiderGoalSegment.delta().mag() / 2.0

    return False
Пример #19
0
    def eval_pt_to_seg(self, origin, target):
        end = target.delta().magsq()

        # if target is a zero-length segment, there are no windows
        if end == 0:
            return [], None

        if self.debug:
            main.system_state().draw_line(target, constants.Colors.Blue, "Debug")

        windows = [Window(0, end)]

        # apply the obstacles
        bots = filter(lambda bot: bot not in self.excluded_robots and bot.visible, (list(main.our_robots()) + list(main.their_robots())))
        bot_locations = list(map(lambda bot: bot.pos, bots))
        bot_locations.extend(self.hypothetical_robot_locations)
        for pos in bot_locations:
            d = (pos - origin).mag()
            # whether or not we can chip over this bot
            chip_overable = (self.chip_enabled
                            and (d < self.max_chip_range - constants.Robot.Radius)
                            and (d > self.min_chip_range + constants.Robot.Radius))
            if not chip_overable:
                self.obstacle_robot(windows, origin, target, pos)

        # set the segment and angles for each window
        p0 = target.get_pt(0)
        delta = target.delta() / end

        for w in windows:
            w.segment = robocup.Segment(p0 + delta * w.t0, p0 + delta * w.t1)
            w.a0 = (w.segment.get_pt(0) - origin).angle() * constants.RadiansToDegrees
            w.a1 = (w.segment.get_pt(1) - origin).angle() * constants.RadiansToDegrees

        best = max(windows, key=lambda w: w.segment.delta().magsq()) if len(windows) > 0 else None

        if self.debug and best is not None:
            main.system_state().draw_line(best.segment, constants.Colors.Green, "Debug")
            main.system_state().draw_line(robocup.Line(origin, best.segment.center()), constants.Colors.Green, "Debug")

        # # draw the windows if we're in debug mode
        # if self.debug:
        #     for w in windows:
        #         pts = [origin, w.segment.get_pt(0), w.segment.get_pt(1)]
        #         color = (255, 0, 0) if w == best else (0, 255, 0)
        #         main.system_state().draw_polygon(pts, 3, color, "Windows")

        return windows, best
Пример #20
0
    def execute_setup_penalty(self):
        pt = robocup.Point(0, robocup.Field_PenaltyDist)
        penalty_kicker = min(main.their_robots(),
                             key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(
            penalty_kicker.pos,
            penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = shot_line.intersection(Goalie.RobotSegment)
        if dest == None:
            self.robot.move_to(robocup.Point(0, constants.Robot.Radius))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.y = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
        self.robot.move_to(dest)
Пример #21
0
    def get_transition_point(self):
        segment = constants.Field.OurGoalSegment
        line = robocup.Line(main.ball().pos, main.their_robots()[0].pos)

        goalie_pos = constants.Field.OurGoalSegment.center()
        if (self.has_subbehavior_with_name('block')):
            block_robot = self.subbehavior_with_name('block').robot
            if (block_robot != None):
                goalie_pos = block_robot.pos

        #find the point that the robot is most likely going to shoot at
        goal_intercept = segment.line_intersection(line)

        #if robot is not lined up with the goal assume the bot will shoot center
        if goal_intercept == None:
            goal_intercept = segment.center()

        #get the vector of the ball to the ideal shot point
        ball_to_goal_intercept = goal_intercept - main.ball().pos

        #normalize the vector
        ball_to_goal_intercept = ball_to_goal_intercept.normalized()

        #the ideal spot to be will be the chip distance times the normalized vector from the ball's
        #current point.
        ideal_defence = ball_to_goal_intercept * self.chip_distance + main.ball(
        ).pos

        #find the line of the shot the robot will make
        ball_to_goal_segment = robocup.Segment(main.ball().pos, goal_intercept)

        #this is the point to get our robot to block the shot the quickest.
        fastest_defence = ball_to_goal_segment.nearest_point(goalie_pos)

        #if robot is blocking the shot already just go to the ideal point otherwise average the vectors
        #based on the blocking percentage.
        if (goalie_pos.dist_to(fastest_defence) <
            (constants.Robot.Radius / 4)):
            move_to_point = ideal_defence
        else:
            move_to_point = robocup.Point(
                (ideal_defence.x * (self.block_percentage)) +
                (fastest_defence.x * (1 - self.block_percentage)),
                ((ideal_defence.y * self.block_percentage) +
                 fastest_defence.y * (1 - self.block_percentage)))

        return move_to_point
Пример #22
0
    def estimate_potential_recievers_score(self, bot):
        ball_travel_line = robocup.Line(main.ball().pos,
                                        main.ball().pos + main.ball().vel)

        dot_product = (bot.pos - main.ball().pos).dot(ball_travel_line.delta())
        nearest_pt = ball_travel_line.nearest_point(bot.pos)
        dx = (nearest_pt - main.ball().pos).mag()
        dy = (bot.pos - nearest_pt).mag()
        angle = abs(math.atan2(dy, dx))

        # Only returns 1 if the opp is moving in the opposite direction as the ball
        # and the angle between the ball ray starting at its current position and the opp position
        # is less than pi/4
        if (angle < math.pi / 4 and dot_product > 0):
            return 1
        else:
            return 0
Пример #23
0
    def find_intercept_point(self, adjusted=True):
        approach_vec = self.approach_vector()

        adjFactor = robocup.Point.direction(self.robot.angle) \
                    * -TouchBall.AdjDist
        robotPos = self.robot.pos - adjFactor

        # multiply by a large enough value to cover the field.
        approach_line = robocup.Line(
            main.ball().pos,
            main.ball().pos + approach_vec * constants.Field.Length)
        pos = approach_line.nearest_point(robotPos)

        if adjusted:
            pos += adjFactor

        return pos
Пример #24
0
    def execute_setup_penalty(self):
        pt = robocup.Point(0, constants.Field.PenaltyDist)
        penalty_kicker = min(main.their_robots(),
                             key=lambda r: (r.pos - pt).mag())
        angle_rad = penalty_kicker.angle
        shot_line = robocup.Line(
            penalty_kicker.pos,
            penalty_kicker.pos + robocup.Point.direction(angle_rad))

        dest = Goalie.RobotSegment.line_intersection(shot_line)
        if dest is None:
            self.robot.move_to(
                robocup.Point(0, constants.Robot.Radius + Goalie.OFFSET))
        else:
            dest.x = max(-Goalie.MaxX + constants.Robot.Radius, dest.x)
            dest.x = min(Goalie.MaxX - constants.Robot.Radius, dest.x)
            # Shots don't follow the top threat, they follow the inverse
            # FIXME this is kind of a hack
            dest.x = -dest.x
            self.robot.move_to(dest)
Пример #25
0
    def opp_robot_blocking(self):
        if (self.robot is None):
            return False

        # Closest opp robot in any direction
        # To us, not the ball   
        closest_opp_robot = None
        closest_opp_dist = float("inf")
        for r in main.their_robots():
            if ((r.pos - self.robot.pos).mag() < closest_opp_dist):
                closest_opp_robot = r
                closest_opp_dist = (r.pos - self.robot.pos).mag()

        # Only do this if a robot is in range
        robot_in_range = closest_opp_dist < .2 + 2 * constants.Robot.Radius

        aim_dir = robocup.Point.direction(self.robot.angle)
        robot_dir = (closest_opp_robot.pos - self.robot.pos)

        # Only trigger if they are infront of us
        robot_in_front = aim_dir.dot(robot_dir) > 0

        closest_pt = robocup.Line(
            self.robot.pos,
            self.robot.pos + aim_dir).nearest_point(closest_opp_robot.pos)

        does_hit_robot = (closest_opp_robot.pos - closest_pt
                          ).mag() < constants.Robot.Radius

        facing_their_side = robocup.Point.direction(self.robot.angle).y > 0

        ret = (facing_their_side and robot_in_range and robot_in_front and
               does_hit_robot)

        if ret:
            print("Panic kick")
            main.debug_drawer().draw_text('panic kick', self.robot.pos,
                                          (255, 255, 255), 'PivotKick')

        return ret
Пример #26
0
    def execute_running(self):
        if self.robot.has_ball():
            self.startBallLocation = main.ball().pos

        self.recalculate()

        self.robot.set_max_speed(0.9)
        self.robot.set_max_accel(0.9)

        # slowly pivot toward the target
        #self.robot.set_max_angle_speed(4)
        self.robot.pivot(self._face_target)
        self.robot.set_dribble_speed(self.dribbler_power)

        # draw current shot line
        if self._shot_point != None:
            color = constants.Colors.Green if self.is_aimed(
            ) else constants.Colors.Red
            main.debug_drawer().draw_line(
                robocup.Line(self.robot.pos, self._shot_point), color, "Aim")
            main.debug_drawer().draw_circle(self._shot_point, 0.02, color,
                                            "Aim")

        # draw where we're supposed to be aiming
        if self.target_point != None:
            main.debug_drawer().draw_circle(self.target_point, 0.02,
                                            constants.Colors.Blue, "Aim")

        # If we are within X degrees of the target, start the fine timeout
        if (self.target_point is not None and self._fine_start == 0
                and robocup.Point.direction(
                    self.robot.angle).angle_between(self.target_point -
                                                    self.robot.pos) <
                45 * constants.DegreesToRadians and robocup.Point.direction(
                    self.robot.angle).dot(self.target_point - self.robot.pos) >
                0):

            self._fine_start = time.time()
Пример #27
0
 def recalculate(self):
     self._target_line = robocup.Line(main.ball().pos,
                                      self.aim_target_point)
Пример #28
0
    def recalculate(self):
        goalie = self.subbehavior_with_name('goalie')
        defender1 = self.subbehavior_with_name('defender1')
        defender2 = self.subbehavior_with_name('defender2')
        behaviors = [goalie, defender1, defender2]

        # if we don't have any bots to work with, don't waste time calculating
        if all(bhvr.robot == None for bhvr in behaviors):
            return

        # A threat to our goal - something we'll actively defend against
        class Threat:
            def __init__(self, source=None):
                self.source = source
                self.ball_acquire_chance = 1.0
                self.shot_chance = 1.0
                self.assigned_handlers = []
                self.best_shot_window = None

            # an OpponentRobot or Point
            @property
            def source(self):
                return self._source

            @source.setter
            def source(self, value):
                self._source = value

            # our source can be a Point or an OpponentRobot, this method returns the location of it
            @property
            def pos(self):
                if self.source != None:
                    return self.source if isinstance(
                        self.source, robocup.Point) else self.source.pos

            # a list of our behaviors that will be defending against this threat
            # as of now only Defender and Goalie
            @property
            def assigned_handlers(self):
                return self._assigned_handlers

            @assigned_handlers.setter
            def assigned_handlers(self, value):
                self._assigned_handlers = value

            # our estimate of the chance that this threat will acquire the ball
            # 1.0 if it already has it
            # otherwise, a value from 0 to 1 gauging its likelihood to receive a pass
            @property
            def ball_acquire_chance(self):
                return self._ball_acquire_chance

            @ball_acquire_chance.setter
            def ball_acquire_chance(self, value):
                self._ball_acquire_chance = value

            # our estimate of the chance of this threat making its shot on the goal given that it gets/has the ball
            # NOTE: this is calculated excluding all of our robots on the field as obstacles
            @property
            def shot_chance(self):
                return self._shot_chance

            @shot_chance.setter
            def shot_chance(self, value):
                self._shot_chance = value

            # his best window on our goal
            @property
            def best_shot_window(self):
                return self._best_shot_window

            @best_shot_window.setter
            def best_shot_window(self, value):
                self._best_shot_window = value

            # our assessment of the risk of this threat
            # should be between 0 and 1
            @property
            def score(self):
                return self.ball_acquire_chance * self.shot_chance

            # available behaviors we have to assign to threats
            # only look at ones that have robots
            # as we handle threats, we remove the handlers from this list

        unused_threat_handlers = list(
            filter(lambda bhvr: bhvr.robot != None,
                   [goalie, defender1, defender2]))

        def set_block_lines_for_threat_handlers(threat):
            if len(threat.assigned_handlers) == 0:
                return

            # make sure goalie is in the middle
            if len(threat.assigned_handlers) > 1:
                if goalie in threat.assigned_handlers:
                    idx = threat.assigned_handlers.index(goalie)
                    if idx != 1:
                        del threat.assigned_handlers[idx]
                        threat.assigned_handlers.insert(1, goalie)

            if threat.best_shot_window != None:
                center_line = robocup.Line(
                    threat.pos, threat.best_shot_window.segment.center())
            else:
                center_line = robocup.Line(
                    threat.pos, constants.Field.OurGoalSegment.center())

            # find the angular width that each defender can block.  We then space these out accordingly
            angle_widths = []
            for handler in threat.assigned_handlers:
                dist_from_threat = handler.robot.pos.dist_to(threat.pos)
                w = min(
                    2.0 * math.atan2(constants.Robot.Radius, dist_from_threat),
                    0.15)
                angle_widths.append(w)

            # start on one edge of our available angle coverage and work counter-clockwise,
            # assigning block lines to the bots as we go
            spacing = 0.01 if len(
                threat.assigned_handlers
            ) < 3 else 0.0  # spacing between each bot in radians
            total_angle_coverage = sum(angle_widths) + (len(angle_widths) -
                                                        1) * spacing
            start_vec = center_line.delta().normalized()
            start_vec.rotate(robocup.Point(0, 0), -total_angle_coverage / 2.0)
            for i in range(len(angle_widths)):
                handler = threat.assigned_handlers[i]
                w = angle_widths[i]
                start_vec.rotate(robocup.Point(0, 0), w / 2.0)
                handler.block_line = robocup.Line(threat.pos,
                                                  threat.pos + start_vec * 10)
                start_vec.rotate(robocup.Point(0, 0), w / 2.0 + spacing)

        def recalculate_threat_shot(threat_index):
            if not isinstance(threat_index, int):
                raise TypeError("threat_index should be an int")

            # ignore all of our robots
            excluded_robots = list(main.our_robots())

            # behaviors before this threat are counted as obstacles in their TARGET position (where we've
            # assigned them to go, not where they are right now)
            hypothetical_obstacles = []
            for t in threats[0:threat_index]:
                hypothetical_obstacles.extend(
                    map(lambda bhvr: bhvr.move_target, t.assigned_handlers))

            threat = threats[threat_index]
            self.win_eval.excluded_robots.clear()
            for r in excluded_robots:
                self.win_eval.add_excluded_robot(r)
            _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal(
                threat.pos)
            if threat.best_shot_window is not None:
                threat.shot_chance = threat.best_shot_window.shot_success
            else:
                threat.shot_chance = 0.0

        threats = []

        # secondary threats are those that are somewhat close to our goal and open for a pass
        # if they're farther than this down the field, we don't consider them threats
        threat_max_y = constants.Field.Length / 2.0
        potential_threats = [
            opp for opp in main.their_robots() if opp.pos.y < threat_max_y
        ]

        # find the primary threat
        # if the ball is not moving OR it's moving towards our goal, it's the primary threat
        # if it's moving, but not towards our goal, the primary threat is the robot on their team most likely to catch it
        if main.ball().vel.mag() > 0.4:
            # the line the ball's moving along
            ball_travel_line = robocup.Line(main.ball().pos,
                                            main.ball().pos + main.ball().vel)

            # this is a shot on the goal!
            if evaluation.ball.is_moving_towards_our_goal():
                ball_threat = Threat(main.ball().pos)
                ball_threat.ball_acquire_chance = 1.0
                ball_threat.shot_chance = 1.0
                threats.append(ball_threat)
            else:
                # Check for a bot that's about to capture this ball and potentially shoot on the goal
                # potential_receivers is an array of (OpponentRobot, angle) tuples, where the angle
                # is the angle between the ball_travel_line and the line from the ball to the opponent
                # bot - this is our metric for receiver likeliness.
                potential_receivers = []
                for opp in potential_threats:
                    # see if the bot is in the direction the ball is moving
                    if (opp.pos - ball_travel_line.get_pt(0)).dot(
                            ball_travel_line.delta()) > 0:
                        # calculate the angle and add it to the list if it's within reason
                        nearest_pt = ball_travel_line.nearest_point(opp.pos)
                        dx = (nearest_pt - main.ball().pos).mag()
                        dy = (opp.pos - nearest_pt).mag()
                        angle = abs(math.atan2(dy, dx))
                        if angle < math.pi / 4.0:
                            potential_receivers.append((opp, 1.0))

                # choose the receiver with the smallest angle from the ball travel line
                if len(potential_receivers) > 0:
                    best_receiver_tuple = min(
                        potential_receivers,
                        key=lambda rcrv_tuple: rcrv_tuple[1])
                    if best_receiver_tuple != None:
                        receiver_threat = Threat(best_receiver_tuple[0])
                        receiver_threat.ball_acquire_chance = 0.9  # note: this value is arbitrary
                        receiver_threat.shot_chance = 0.9  # FIXME: calculate this
                        threats.append(receiver_threat)
                else:
                    ball_threat = Threat(main.ball().pos)
                    ball_threat.ball_acquire_chance = 1.0
                    ball_threat.shot_chance = 0.9
                    threats.append(ball_threat)

        else:
            # primary threat is the ball or the opponent holding it
            opp_with_ball = evaluation.ball.opponent_with_ball()

            threat = Threat(
                opp_with_ball if opp_with_ball != None else main.ball().pos)
            threat.ball_acquire_chance = 1.0
            threat.shot_chance = 1.0  # FIXME: calculate, don't use 1.0
            threats.append(threat)

# if an opponent has the ball or is potentially about to receive the ball,
# we look at potential receivers of it as threats
        if isinstance(threats[0].source, robocup.OpponentRobot):
            for opp in filter(lambda t: t.visible, potential_threats):
                pass_chance = evaluation.passing.eval_pass(
                    main.ball().pos, opp.pos, excluded_robots=[opp])
                # give it a small chance because the obstacles in the way could move soon and we don't want to consider it a zero threatos, )
                if pass_chance < 0.001: pass_chance = 0.4

                # record the threat
                threat = Threat(opp)
                threat.ball_acquire_chance = pass_chance
                threats.append(threat)

                # Now we evaluate this opponent's shot on the goal
                # exclude robots that have already been assigned to handle other threats
                self.win_eval.excluded_robots.clear()
                for r in map(lambda bhvr: bhvr.robot, unused_threat_handlers):
                    self.win_eval.add_excluded_robot(r)
                _, threat.best_shot_window = self.win_eval.eval_pt_to_our_goal(
                    opp.pos)
                if threat.best_shot_window is not None:
                    threat.shot_chance = threat.best_shot_window.shot_success
                else:
                    threat.shot_chance = 0.0

                if threat.shot_chance == 0:
                    # gve it a small chance because the shot could clear up a bit later and we don't want to consider it a zero threat
                    threat.shot_chance = 0.2

        else:
            # the ball isn't possessed by an opponent, so we just look at opponents with shots on the goal
            for opp in potential_threats:
                # record the threat
                lurker = Threat(opp)
                lurker.ball_acquire_chance = 0.5  # note: this is a bullshit value
                threats.append(lurker)
                recalculate_threat_shot(len(threats) - 1)

        # only consider the top three threats
        threats.sort(key=lambda threat: threat.score, reverse=True)
        threats = threats[0:3]

        # print("sorted threats:")
        # for idx, t in enumerate(threats):
        #     print("t[" + str(idx) + "]: " + str(t.source) + "shot: " + str(t.shot_chance) + "; pass:"******"; score:" + str(t.score))

        # print("sorted threat scores: " + str(list(map(lambda t: str(t.score) + " " + str(t.source), threats))))

        # print("Unused handlers: " + str(unused_threat_handlers))
        # print("---------------------")

        smart = False
        if not smart:

            # only deal with top two threats
            threats_to_block = threats[0:2]

            # print('threats to block: ' + str(list(map(lambda t: t.source, threats_to_block))))
            threat_idx = 0
            while len(unused_threat_handlers) > 0:
                threats_to_block[threat_idx].assigned_handlers.append(
                    unused_threat_handlers[0])
                del unused_threat_handlers[0]

                threat_idx = (threat_idx + 1) % len(threats_to_block)

            for t_idx, t in enumerate(threats_to_block):
                recalculate_threat_shot(t_idx)
                set_block_lines_for_threat_handlers(t)

        else:
            # assign all of our defenders to do something
            while len(unused_threat_handlers) > 0:
                # prioritize by threat score, highest first
                top_threat = max(threats, key=lambda threat: threat.score)

                # assign the next handler to this threat
                handler = unused_threat_handlers[0]
                top_threat.assigned_handlers.append(handler)
                del unused_threat_handlers[0]

                # reassign the block line for each handler of this threat
                set_block_lines_for_threat_handlers(top_threat)

                # recalculate the shot now that we have
                recalculate_threat_shot(0)

        # tell the bots where to move / what to block and draw some debug stuff
        for idx, threat in enumerate(threats):

            # recalculate, including all current bots
            # FIXME: do we want this?
            # recalculate_threat_shot(idx)

            # the line they'll be shooting down/on
            if threat.best_shot_window != None:
                shot_line = robocup.Segment(
                    threat.pos, threat.best_shot_window.segment.center())
            else:
                shot_line = robocup.Segment(threat.pos, robocup.Point(0, 0))

            # debug output
            if self.debug:
                for handler in threat.assigned_handlers:
                    # handler.robot.add_text("Marking: " + str(threat.source), constants.Colors.White, "Defense")
                    main.system_state().draw_circle(handler.move_target, 0.02,
                                                    constants.Colors.Blue,
                                                    "Defense")

                # draw some debug stuff
                if threat.best_shot_window != None:
                    # draw shot triangle
                    pts = [
                        threat.pos,
                        threat.best_shot_window.segment.get_pt(0),
                        threat.best_shot_window.segment.get_pt(1)
                    ]
                    shot_color = (255, 0, 0, 150)  # translucent red
                    main.system_state().draw_polygon(pts, shot_color,
                                                     "Defense")
                    main.system_state().draw_segment(
                        threat.best_shot_window.segment, constants.Colors.Red,
                        "Defense")

                    self.win_eval.excluded_robots.clear()
                    _, best_window = self.win_eval.eval_pt_to_our_goal(
                        threat.pos)
                    if best_window is not None:
                        chance = best_window.shot_success
                    else:
                        chance = 0.0

                    main.system_state().draw_text(
                        "Shot: " + str(int(threat.shot_chance * 100.0)) +
                        "% / " + str(int(chance * 100)) + "%",
                        shot_line.center(), constants.Colors.White, "Defense")

                # draw pass lines
                if idx > 0:
                    pass_line = robocup.Segment(main.ball().pos, threat.pos)
                    main.system_state().draw_line(pass_line,
                                                  constants.Colors.Red,
                                                  "Defense")
                    main.system_state().draw_text(
                        "Pass: "******"%",
                        pass_line.center(), constants.Colors.White, "Defense")
Пример #29
0
    def execute_marking(self):
        #main.system_state().draw_line(robocup.Line(self._area.get_pt(0), self._area.get_pt(1)), (127,0,255), "Defender")
        self.block_robot = self.find_robot_to_block()
        if self.block_robot is not None:
            # self.robot.add_text("Blocking Robot " + str(self.block_robot.shell_id()), (255,255,255), "RobotText")
            pass
        if self.robot.pos.near_point(robocup.Point(0, 0),
                                     self._opponent_avoid_threshold):
            self.robot.set_avoid_opponents(False)
        else:
            self.robot.set_avoid_opponents(True)

        target = None
        if self.block_robot is None:
            target = main.ball().pos + main.ball().vel * 0.3
        else:
            target = self.block_robot.pos + self.block_robot.vel * 0.3

        goal_line = robocup.Segment(
            robocup.Point(-constants.Field.GoalWidth / 2.0, 0),
            robocup.Point(constants.Field.GoalWidth / 2.0, 0))

        self._win_eval.excluded_robots = [self.robot]

        # TODO defenders should register themselves with some static list on init
        # TODO make this happen in python-land
        # for (Defender *f :  otherDefenders)
        # {
        # 	if (f->robot)
        # 	{
        # 		_winEval.exclude.push_back(f->robot->pos);
        # 	}
        # }

        windows = self._win_eval.eval_pt_to_seg(target, goal_line)[0]

        best = None
        goalie = main.our_robot_with_id(main.root_play().goalie_id)

        if goalie is not None and self.side is not Defender.Side.center:
            for window in windows:
                if best is None:
                    best = window
                elif self.side is Defender.Side.left and window.segment.center.x < goalie.pos.x and window.segment.length > best.segment.length:
                    best = window
                elif self.side is Defender.Side.right and window.segment.center.x > goalie.pos.x and window.segment.length > best.segment.length:
                    best = window
        else:
            best_dist = 0
            for window in windows:
                seg = robocup.Segment(window.segment.center(), main.ball().pos)
                new_dist = seg.dist_to(self.robot.pos)
                if best is None or new_dist < best_dist:
                    best = window
                    best_dist = new_dist

        shoot_seg = None
        if best is not None:
            if self.block_robot is not None:
                dirvec = robocup.Point.direction(self.block_robot.angle *
                                                 (math.pi / 180.0))
                shoot_seg = robocup.Segment(
                    self.block_robot.pos, self.block_robot.pos + dirvec * 7.0)
            else:
                shoot_seg = robocup.Segment(
                    main.ball().pos,
                    main.ball().pos + main.ball().vel.normalized() * 7.0)

        need_task = False
        if best is not None:
            winseg = best.segment
            if main.ball().vel.magsq() > 0.03 and winseg.segment_intersection(
                    shoot_seg) != None:
                self.robot.move_to(shoot_seg.nearest_point(self.robot.pos))
                self.robot.face_none()
            else:
                winsize = winseg.length()

                if winsize < constants.Ball.Radius:
                    need_task = True
                else:
                    arc = robocup.Circle(robocup.Point(0, 0),
                                         self._defend_goal_radius)
                    shot = robocup.Line(winseg.center(), target)
                    dest = [robocup.Point(0, 0), robocup.Point(0, 0)]

                    intersected, dest[0], dest[1] = shot.intersects_circle(arc)

                    if intersected:
                        self.robot.move_to(
                            dest[0] if dest[0].y > 0 else dest[1])
                        if self.block_robot is not None:
                            self.robot.face(self.block_robot.pos)
                        else:
                            self.robot.face(main.ball().pos)
                    else:
                        need_task = True
        if need_task:
            self.robot.face(main.ball().pos)

        backVec = robocup.Point(1, 0)
        backPos = robocup.Point(-constants.Field.Width / 2, 0)
        shotVec = robocup.Point(main.ball().pos - self.robot.pos)
        backVecRot = robocup.Point(backVec.perp_ccw())
        facing_back_line = (backVecRot.dot(shotVec) < 0)
        if not facing_back_line and self.robot.has_ball():
            if self.robot.has_chipper():
                self.robot.chip(255)
            else:
                self.robot.kick(255)
Пример #30
0
    def recalculate(self):
        # can't do squat if we don't know what we're supposed to do
        if self.receive_point == None or self.robot == None or self.target_point == None:
            return

        ball = main.ball()

        if self.ball_kicked:
            # when the ball's in motion, the line is based on the ball's velocity
            self._pass_line = robocup.Line(ball.pos, ball.pos + ball.vel * 10)

            # After kicking, apply angle calculations
            target_angle_rad = self.adjust_angle(
                (self.target_point - self.robot.pos).angle())
            # Removes angle adjustment
            # target_angle_rad = (self.target_point - self.robot.pos).angle()

            self._kick_line = robocup.Line(
                self.robot.pos,
                robocup.Point(
                    self.robot.pos.x + math.cos(self.robot.angle) * 10,
                    self.robot.pos.y + math.sin(self.robot.angle) * 10))
        else:
            # if the ball hasn't been kicked yet, we assume it's going to go through the receive point
            self._pass_line = robocup.Line(ball.pos, self.receive_point)
            # Assume ball is kicked at max speed and is coming from the ball point to the location of our robot. Then average this with the target angle.
            target_angle_rad = self.adjust_angle(
                (self.target_point - self.robot.pos).angle(),
                (self.robot.pos - main.ball().pos).angle(),
                constants.Robot.MaxKickSpeed)
            # TODO make this faster by caching the .angle() part
            target_angle_rad = (
                target_angle_rad +
                (self.target_point - self.robot.pos).angle()) / 2

            self._kick_line = robocup.Line(self.receive_point,
                                           self.target_point)

        self._angle_facing = target_angle_rad
        angle_rad = self.robot.angle
        self._angle_error = target_angle_rad - angle_rad

        if self.ball_kicked:
            receive_before_adjust = self._pass_line.nearest_point(
                self.robot.pos)
        else:
            receive_before_adjust = self.receive_point

        # Make the receive point be the mouth, rather than the center of the robot.
        # Assumes mouth of robot is at the edge.
        self._target_pos = receive_before_adjust - robocup.Point(
            constants.Robot.Radius * math.cos(self.robot.angle),
            constants.Robot.Radius * math.sin(self.robot.angle))

        # Code to provide slipback when receiving the ball
        # pass_line_dir = (self._pass_line.get_pt(1) - self._pass_line.get_pt(0)).normalized()
        # self._target_pos = actual_receive_point + pass_line_dir * constants.Robot.Radius

        # vector pointing down the pass line toward the kicker
        pass_dir = (self._pass_line.get_pt(0) -
                    self._pass_line.get_pt(1)).normalized()

        pos_error = self._target_pos - self.robot.pos
        self._x_error = self._target_pos.x - self.robot.pos.x
        self._y_error = self._target_pos.y - self.robot.pos.y