Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Goalie utility function #1723

Closed
wants to merge 9 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 120 additions & 45 deletions rj_gameplay/rj_gameplay/tactic/goalie_tactic.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,82 @@ def get_requests(self, world_state: rc.WorldState,
"""
:return: A list of role requests for move skills needed
"""
def track_utility() -> float:
"""
:return: the utility of track action
"""
if ball_speed == 0:
ball_to_goal_time = 100
else:
ball_to_goal_time = ball_dist / ball_speed
return ball_to_goal_time / 100

def receive_utility() -> float:
"""
:return: the utility of receive action
"""
# this probably makes sense to stay hard coded like this
# but maybe there is a better option?
if ball_speed < .5 and (
abs(ball_pos[0]) < box_w / 2 + line_w + MAX_OOB
and ball_pos[1] < box_h + line_w + MAX_OOB
) and not world_state.game_info.is_stopped():
return 1
else:
return 0

def block_utility() -> float:
"""Increases as ball to goal time approaches 0.
:return: the utility of block action
"""
if ball_speed > 0 and np.dot(towards_goal,
world_state.ball.vel) > 0.3:
# if ball is moving and coming at goal, move laterally to block ball
ball_to_goal_time = ball_dist / ball_speed
else:
ball_to_goal_time = 100
return 1 - (ball_to_goal_time / 100)

def clear_utility() -> float:
"""
:return: the utility of clear action
"""
# should clear if no open pass available
# how do I check that?
return 1

def pass_utility() -> float:
"""
:return: the utility of clear action
"""
# should pass if open pass available
# same problem as clear
return 0

def get_best_action():
"""Compares utility functions of all actions.
:return: The best action based on the utility functions.
"""
if world_state and world_state.ball.visible:
# if tied earlier index will be selected
utility_values = np.array([
pass_utility(),
clear_utility(),
track_utility(),
receive_utility(),
block_utility()
])

utilities = np.array([
pass_utility, clear_utility, track_utility,
receive_utility, block_utility
])
return utilities[np.argmax(utility_values)]
else:
return None

# TODO: this calculation is copy-pasted from wall_tactic
# variables
# put into common param file: https://www.geeksforgeeks.org/global-keyword-in-python/

# dist is slightly greater than penalty box bounds
Expand All @@ -115,7 +189,6 @@ def get_requests(self, world_state: rc.WorldState,
# max out of box to cap for goalie
MAX_OOB = RobotConstants.RADIUS

role_requests = {}
if world_state and world_state.ball.visible:
ball_speed = np.linalg.norm(world_state.ball.vel)
ball_pos = world_state.ball.pos
Expand All @@ -124,6 +197,12 @@ def get_requests(self, world_state: rc.WorldState,
goal_pos = world_state.field.our_goal_loc
towards_goal = goal_pos - ball_pos

role_requests = {}
best_action = get_best_action()

if best_action is not None:

# TODO (1724) remove this from the code
if self.brick:
self.move_se.skill.target_point = world_state.field.our_goal_loc
self.move_se.skill.face_point = world_state.ball.pos
Expand All @@ -132,51 +211,47 @@ def get_requests(self, world_state: rc.WorldState,
]
return role_requests

if ball_speed < 0.5 and (
abs(ball_pos[0]) < box_w / 2 + line_w + MAX_OOB
and ball_pos[1] < box_h + line_w + MAX_OOB
) and not world_state.game_info.is_stopped():
if best_action is receive_utility:
# if ball is stopped and inside goalie box, collect it
self.move_se = tactic.SkillEntry(move.Move(ignore_ball=True))
if ball_speed < 1e-6:
# if ball is stopped and inside goalie box, collect it
role_requests[self.receive_se] = [
role.RoleRequest(role.Priority.HIGH, True,
self.role_cost)
]
else:
# if ball has been stopped already, chip toward center field
self.pivot_kick_se.skill.target_point = np.array(
[0.0, 6.0])
role_requests[self.pivot_kick_se] = [
role.RoleRequest(role.Priority.HIGH, True,
self.role_cost)
]
else:
if ball_speed > 0 and np.dot(towards_goal,
world_state.ball.vel) > 0.3:
# if ball is moving and coming at goal, move laterally to block ball
# TODO (#1676): replace this logic with a real intercept planner
goalie_pos = world_state.our_robots[
world_state.
goalie_id].pose[:
2] if world_state.goalie_id is not None else np.array(
[0., 0.])
self.move_se.skill.target_point = get_block_pt(
world_state, goalie_pos)
self.move_se.skill.face_point = world_state.ball.pos
role_requests[self.move_se] = [
role.RoleRequest(role.Priority.HIGH, True,
self.role_cost)
]
else:
# else, track ball normally
self.move_se.skill.target_point = get_goalie_pt(
world_state)
self.move_se.skill.face_point = world_state.ball.pos
role_requests[self.move_se] = [
role.RoleRequest(role.Priority.HIGH, True,
self.role_cost)
]
role_requests[self.receive_se] = [
role.RoleRequest(role.Priority.HIGH, True, self.role_cost)
]
elif best_action is clear_utility:
# clear
# if ball has been stopped already, chip toward center field
self.move_se = tactic.SkillEntry(move.Move(ignore_ball=True))
self.pivot_kick_se.skill.target_point = np.array([0.0, 6.0])
role_requests[self.pivot_kick_se] = [
role.RoleRequest(role.Priority.HIGH, True, self.role_cost)
]

elif best_action is block_utility:
# if ball is moving and coming at goal, move laterally to block ball
# TODO (#1676): replace this logic with a real intercept planner
goalie_pos = world_state.our_robots[
world_state.
goalie_id].pose[:
2] if world_state.goalie_id is not None else np.array(
[0., 0.])
self.move_se.skill.target_point = get_block_pt(
world_state, goalie_pos)
self.move_se.skill.face_point = world_state.ball.pos
role_requests[self.move_se] = [
role.RoleRequest(role.Priority.HIGH, True, self.role_cost)
]
elif best_action is track_utility:
# track ball normally
self.move_se.skill.target_point = get_goalie_pt(world_state)
self.move_se.skill.face_point = world_state.ball.pos
role_requests[self.move_se] = [
role.RoleRequest(role.Priority.HIGH, True, self.role_cost)
]
elif best_action is pass_utility:
# TODO : under current system, should assign pass tactic here
pass

# reminder : remove during testing
if self.pivot_kick_se.skill.is_done(world_state):
self.pivot_kick_se = tactic.SkillEntry(
line_kick.LineKickSkill(None,
Expand Down