From 330dd2c4094dea8803b303b4111903fcb66d047f Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 14:38:09 -0400 Subject: [PATCH 01/58] Fix (in)direct positionning --- Util/constant.py | 1 - ai/STA/Strategy/direct_free_kick.py | 84 +------------------- ai/STA/Strategy/free_kick.py | 108 ++++++++++++++++++++++++++ ai/STA/Strategy/indirect_free_kick.py | 85 +------------------- ai/STA/Tactic/position_for_pass.py | 6 +- ai/STA/Tactic/rotate_around_ball.py | 2 +- 6 files changed, 118 insertions(+), 168 deletions(-) create mode 100644 ai/STA/Strategy/free_kick.py diff --git a/Util/constant.py b/Util/constant.py index 1cc5f9aa..d72bf0dd 100644 --- a/Util/constant.py +++ b/Util/constant.py @@ -59,7 +59,6 @@ def for_dist(cls, dist): return KickForce.HIGH - class KickType(Enum): DIRECT = 0 CHIP = 1 diff --git a/ai/STA/Strategy/direct_free_kick.py b/ai/STA/Strategy/direct_free_kick.py index 0a21de2f..e68dfa1a 100644 --- a/ai/STA/Strategy/direct_free_kick.py +++ b/ai/STA/Strategy/direct_free_kick.py @@ -1,87 +1,9 @@ # Under MIT License, see LICENSE.txt -from functools import partial +from ai.STA.Strategy.free_kick import FreeKick -from Util.constant import KickForce -from Util.pose import Position, Pose -from Util.role import Role - -from ai.Algorithm.evaluation_module import closest_player_to_point, closest_players_to_point -from ai.STA.Strategy.strategy import Strategy -from ai.STA.Tactic.go_kick import GoKick -from ai.STA.Tactic.goalkeeper import GoalKeeper -from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.rotate_around_ball import RotateAroundBall -from ai.STA.Tactic.tactic_constants import Flags -from ai.states.game_state import GameState - - -# noinspection PyMethodMayBeStatic,PyMethodMayBeStatic -class DirectFreeKick(Strategy): +class DirectFreeKick(FreeKick): def __init__(self, p_game_state): - super().__init__(p_game_state) - - their_goal = p_game_state.field.their_goal_pose - - formation = [p for r, p in self.assigned_roles.items() if p != Role.GOALKEEPER] - for role, player in self.assigned_roles.items(): - if role == Role.GOALKEEPER: - self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) - else: - node_position_for_pass = self.create_node(role, PositionForPass(self.game_state, - player, - robots_in_formation=formation, - auto_position=True, - forbidden_areas=[ - self.game_state.field.free_kick_avoid_area, - self.game_state.field.our_goal_forbidden_area])) - node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, their_goal)) - node_go_kick = self.create_node(role, GoKick(self.game_state, player, their_goal, auto_update_target=True, kick_force=KickForce.HIGH)) - - player_is_closest = partial(self.is_closest_not_goalkeeper, player) - player_is_not_closest = partial(self.is_not_closest, player) - player_has_kicked = partial(self.has_kicked, player) - player_is_ready_to_kick = partial(self.is_ready_to_kick, player) - - node_position_for_pass.connect_to(node_rotate_around_ball, when=player_is_closest) - node_rotate_around_ball.connect_to(node_position_for_pass, when=player_is_not_closest) - node_go_kick.connect_to(node_position_for_pass, when=player_is_not_closest) - node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) - node_go_kick.connect_to(node_go_kick, when=player_has_kicked) - - @classmethod - def required_roles(cls): - return [Role.GOALKEEPER, - Role.MIDDLE] - - @classmethod - def optional_roles(cls): - return [Role.FIRST_ATTACK, - Role.SECOND_ATTACK, - Role.FIRST_DEFENCE, - Role.SECOND_DEFENCE] - - def is_closest_not_goalkeeper(self, player): - closest_players = closest_players_to_point(GameState().ball_position, our_team=True) - if player == closest_players[0].player: - return True - return closest_players[0].player == self.game_state.get_player_by_role(Role.GOALKEEPER) \ - and player == closest_players[1].player - - def is_not_closest(self, player): - return not self.is_closest_not_goalkeeper(player) - - def has_kicked(self, player): - role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'GoKick': - return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS - else: - return False + super().__init__(p_game_state, can_kick_in_goal=True) - def is_ready_to_kick(self, player): - role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'RotateAroundBall': - return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS - else: - return False diff --git a/ai/STA/Strategy/free_kick.py b/ai/STA/Strategy/free_kick.py new file mode 100644 index 00000000..493a3e62 --- /dev/null +++ b/ai/STA/Strategy/free_kick.py @@ -0,0 +1,108 @@ +# Under MIT License, see LICENSE.txt + +from functools import partial + +from Util.pose import Position, Pose +from Util.role import Role + +from ai.Algorithm.evaluation_module import closest_player_to_point, closest_players_to_point +from ai.STA.Strategy.strategy import Strategy +from ai.STA.Tactic.go_kick import GoKick +from ai.STA.Tactic.goalkeeper import GoalKeeper +from ai.STA.Tactic.position_for_pass import PositionForPass +from ai.STA.Tactic.rotate_around_ball import RotateAroundBall +from ai.STA.Tactic.tactic_constants import Flags +from ai.states.game_state import GameState + + +# noinspection PyMethodMayBeStatic,PyMethodMayBeStatic +class FreeKick(Strategy): + + def __init__(self, p_game_state, can_kick_in_goal): + super().__init__(p_game_state) + + formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] + + initial_position_for_pass_center = {} + for role, player in self.assigned_roles.items(): + if role == Role.GOALKEEPER: + self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) + else: + node_pass = self.create_node(role, PositionForPass(self.game_state, + player, + robots_in_formation=formation, + auto_position=True, + forbidden_areas=[self.game_state.field.free_kick_avoid_area, + self.game_state.field.our_goal_forbidden_area])) + initial_position_for_pass_center[role] = node_pass.tactic.area.center # Hack + node_go_kick = self.create_node(role, GoKick(self.game_state, + player, + auto_update_target=True, + can_kick_in_goal=can_kick_in_goal)) + + node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, p_game_state.field.their_goal_pose)) + + player_is_closest = partial(self.is_closest_not_goalkeeper, player) + player_is_not_closest = partial(self.is_not_closest, player) + player_has_kicked = partial(self.has_kicked, player) + player_is_ready_to_kick = partial(self.is_ready_to_kick, player) + + node_pass.connect_to(node_rotate_around_ball, when=player_is_closest) + node_rotate_around_ball.connect_to(node_pass, when=player_is_not_closest) + node_go_kick.connect_to(node_pass, when=player_is_not_closest) + node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) + node_go_kick.connect_to(node_go_kick, when=player_has_kicked) + + # Find position for ball player closest to ball + self.closest_role = None + ball_position = self.game_state.ball_position + for r, position in initial_position_for_pass_center.items(): + if self.closest_role is None \ + or (initial_position_for_pass_center[self.closest_role] - ball_position).norm > (position - ball_position).norm: + self.closest_role = r + + self.has_ball_move = False + + @classmethod + def required_roles(cls): + return [Role.GOALKEEPER, + Role.FIRST_ATTACK, + Role.MIDDLE] + + @classmethod + def optional_roles(cls): + return [Role.SECOND_ATTACK, + Role.FIRST_DEFENCE, + Role.SECOND_DEFENCE] + + def is_closest_not_goalkeeper(self, player): + if self.game_state.ball.is_mobile(): + self.has_ball_move = True + role = GameState().get_role_by_player_id(player.id) + if not self.has_ball_move: + return role == self.closest_role + + closest_players = closest_players_to_point(GameState().ball_position, our_team=True) + if player == closest_players[0].player: + return True + return closest_players[0].player == self.game_state.get_player_by_role(Role.GOALKEEPER) \ + and player == closest_players[1].player + + def is_not_closest(self, player): + return not self.is_closest_not_goalkeeper(player) + + def has_kicked(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'GoKick': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False + + def is_ready_to_kick(self, player): + if self.has_ball_move: + return True # FIXME: Test irl, might Cause a lot of problem + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'RotateAroundBall': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False diff --git a/ai/STA/Strategy/indirect_free_kick.py b/ai/STA/Strategy/indirect_free_kick.py index 16e58889..55afa71f 100644 --- a/ai/STA/Strategy/indirect_free_kick.py +++ b/ai/STA/Strategy/indirect_free_kick.py @@ -1,88 +1,9 @@ # Under MIT License, see LICENSE.txt -from functools import partial +from ai.STA.Strategy.free_kick import FreeKick -from Util.pose import Position, Pose -from Util.role import Role - -from ai.Algorithm.evaluation_module import closest_player_to_point, closest_players_to_point -from ai.STA.Strategy.strategy import Strategy -from ai.STA.Tactic.go_kick import GoKick -from ai.STA.Tactic.goalkeeper import GoalKeeper -from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.rotate_around_ball import RotateAroundBall -from ai.STA.Tactic.tactic_constants import Flags -from ai.states.game_state import GameState - - -# noinspection PyMethodMayBeStatic,PyMethodMayBeStatic -class IndirectFreeKick(Strategy): +class IndirectFreeKick(FreeKick): def __init__(self, p_game_state): - super().__init__(p_game_state) - - formation = [p for r, p in self.assigned_roles.items() if p != Role.GOALKEEPER] - for role, player in self.assigned_roles.items(): - if role == Role.GOALKEEPER: - self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) - else: - node_pass = self.create_node(role, PositionForPass(self.game_state, - player, - robots_in_formation=formation, - auto_position=True, - forbidden_areas=[self.game_state.field.free_kick_avoid_area, - self.game_state.field.our_goal_forbidden_area])) - - node_go_kick = self.create_node(role, GoKick(self.game_state, - player, - auto_update_target=True, - can_kick_in_goal=False)) - - node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, p_game_state.field.their_goal_pose)) - - player_is_closest = partial(self.is_closest_not_goalkeeper, player) - player_is_not_closest = partial(self.is_not_closest, player) - player_has_kicked = partial(self.has_kicked, player) - player_is_ready_to_kick = partial(self.is_ready_to_kick, player) - - node_pass.connect_to(node_rotate_around_ball, when=player_is_closest) - node_rotate_around_ball.connect_to(node_pass, when=player_is_not_closest) - node_go_kick.connect_to(node_pass, when=player_is_not_closest) - node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) - node_go_kick.connect_to(node_go_kick, when=player_has_kicked) - - @classmethod - def required_roles(cls): - return [Role.GOALKEEPER, - Role.FIRST_ATTACK, - Role.MIDDLE] - - @classmethod - def optional_roles(cls): - return [Role.SECOND_ATTACK, - Role.FIRST_DEFENCE, - Role.SECOND_DEFENCE] - - def is_closest_not_goalkeeper(self, player): - closest_players = closest_players_to_point(GameState().ball_position, our_team=True) - if player == closest_players[0].player: - return True - return closest_players[0].player == self.game_state.get_player_by_role(Role.GOALKEEPER) \ - and player == closest_players[1].player - - def is_not_closest(self, player): - return not self.is_closest_not_goalkeeper(player) - - def has_kicked(self, player): - role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'GoKick': - return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS - else: - return False + super().__init__(p_game_state, can_kick_in_goal=False) - def is_ready_to_kick(self, player): - role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'RotateAroundBall': - return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS - else: - return False diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 6fb13612..4b6b76dd 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -37,14 +37,14 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a else: self.robots_in_formation = robots_in_formation - self.number_of_robots = len(self.robots_in_formation) self.is_offense = self.is_player_offense(player) self.robots_in_formation = [player for player in self.robots_in_formation if self.is_offense == self.is_player_offense(player)] + self.idx_in_formation = self.robots_in_formation.index(player) + self.area = None # Use for debug_cmd - self.area = None - self.best_position = None + self.best_position = self._find_best_player_position() if self.auto_position else self.target def is_player_offense(self, player): role = self.game_state.get_role_by_player_id(player.id) diff --git a/ai/STA/Tactic/rotate_around_ball.py b/ai/STA/Tactic/rotate_around_ball.py index f40771ac..d6c71f43 100644 --- a/ai/STA/Tactic/rotate_around_ball.py +++ b/ai/STA/Tactic/rotate_around_ball.py @@ -21,7 +21,7 @@ class RotateAroundBall(Tactic): def __init__(self, game_state: GameState, player: Player, target: Pose, - args: Optional[List[str]] = None, rotate_time=4, switch_time=1.5): + args: Optional[List[str]] = None, rotate_time=3, switch_time=1.5): super().__init__(game_state, player, target, args) self.rotate_time = rotate_time self.switch_time = switch_time From 4112be7ce6738e5ad7652171360151ac96ae9bb4 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 17:31:28 -0400 Subject: [PATCH 02/58] Make profiling work again, also improve performance --- Engine/Framework.py | 4 ++-- Engine/engine.py | 21 ++++++++++++--------- ai/STA/Tactic/position_for_pass.py | 29 +++++++++++++++++++---------- ai/STA/Tactic/tactic.py | 2 +- ai/coach.py | 23 +++++++++++++---------- 5 files changed, 47 insertions(+), 32 deletions(-) diff --git a/Engine/Framework.py b/Engine/Framework.py index f3926b22..8b6a49a1 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -58,6 +58,6 @@ def start(self): self.stop_game() def stop_game(self): - self.engine.terminate() - self.coach.terminate() + self.engine.join(timeout=0.1) + self.coach.join(timeout=0.1) sys.exit() diff --git a/Engine/engine.py b/Engine/engine.py index 2d3009ff..b623013d 100644 --- a/Engine/engine.py +++ b/Engine/engine.py @@ -75,9 +75,7 @@ def callback(excess_time): self.fps_sleep = create_fps_timer(self.fps, on_miss_callback=callback) # profiling - self.profiler = cProfile.Profile() - if self.framework.profiling: - self.profiler.enable() + self.profiler = None def start(self): super().start() @@ -96,6 +94,10 @@ def run(self): self.logger.debug(logged_string) + self.profiler = cProfile.Profile() + if self.framework.profiling: + self.profiler.enable() + try: self.wait_for_vision() self.last_time = time() @@ -105,12 +107,15 @@ def run(self): self.main_loop() if self.is_fps_locked: self.fps_sleep() self.framework.engine_watchdog.value = time() + except KeyboardInterrupt: pass except BrokenPipeError: self.logger.info('A connection was broken.') except: self.logger.exception('An error occurred.') + finally: + self.dump_profiling_stats() def wait_for_vision(self): self.logger.debug('Waiting for vision frame from the VisionReceiver...') @@ -151,9 +156,8 @@ def get_engine_commands(self): def dump_profiling_stats(self): if self.framework.profiling: - if self.frame_count % (self.fps * config['ENGINE']['profiling_dump_time']) == 0: - self.profiler.dump_stats(config['ENGINE']['profiling_filename']) - self.logger.debug('Profiling data written to {}.'.format(config['ENGINE']['profiling_filename'])) + self.profiler.dump_stats(config['ENGINE']['profiling_filename']) + self.logger.debug('Profiling data written to {}.'.format(config['ENGINE']['profiling_filename'])) def is_alive(self): @@ -168,11 +172,10 @@ def is_alive(self): self.referee_recver.is_alive())) return borked_process_not_found and super().is_alive() - def terminate(self): - self.dump_profiling_stats() + def join(self, timeout=None): self.vision_receiver.terminate() self.ui_sender.terminate() self.ui_recver.terminate() self.referee_recver.terminate() self.logger.debug('Terminated') - super().terminate() + super().join(timeout=timeout) diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 4b6b76dd..4e895c7b 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -19,6 +19,8 @@ ATTENUATION = 1000 ** 3 # Can be consider the constant that limit the effect of the enemy robot MIN_DIST_FROM_CENTER = 200 # An enemy player closer than this distance from the area center, its distance will clamp +EVALUATION_INTERVAL = 0.5 + class PositionForPass(Tactic): """ @@ -43,6 +45,8 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a self.idx_in_formation = self.robots_in_formation.index(player) self.area = None + self.last_evaluation = time.time() + # Use for debug_cmd self.best_position = self._find_best_player_position() if self.auto_position else self.target @@ -53,7 +57,9 @@ def is_player_offense(self, player): def move_to_pass_position(self): destination_orientation = (self.game_state.ball_position - self.player.pose.position).angle - self.best_position = self._find_best_player_position() if self.auto_position else self.target + if (time.time() - self.last_evaluation) > EVALUATION_INTERVAL: + self.best_position = self._find_best_player_position() if self.auto_position else self.target + self.last_evaluation = time.time() return MoveTo(Pose(self.best_position, destination_orientation), ball_collision=False) def _find_best_player_position(self): @@ -69,7 +75,7 @@ def _find_best_player_position(self): left = self.game_state.field.our_goal_area.left + ball_offset right = ball_offset - idx = self.robots_in_formation.index(self.player) + idx = self.idx_in_formation len_formation = len(self.robots_in_formation) PADDING = 300 # Add buffer zone between area and the field limit @@ -89,8 +95,10 @@ def _find_best_player_position(self): d = MIN_DIST_FROM_CENTER * normalize(d) if d.norm < MIN_DIST_FROM_CENTER else d # Square of the inverse of the distance, a bit like Newton's law of universal gravitation v -= ATTENUATION * d / (d.norm ** 3) - offset_from_center = Line(center, center + v) + if self.area.point_inside(center + v): + return center + v + offset_from_center = Line(center, center + v) # The position must stay inside the area limits, so let's find the intersection between our vector and the area area_inter = self.area.intersect(offset_from_center) if area_inter: @@ -98,11 +106,12 @@ def _find_best_player_position(self): return center + v def debug_cmd(self): - if self.area is None: - return [] - color = VIOLET if self.is_offense else RED - area_lines = DebugCommandFactory().area(self.area, color=color) - line_test = DebugCommandFactory().line(self.area.center, self.best_position, color=color) - - return area_lines + [line_test] + return [] + # if self.area is None: + # return [] + # color = VIOLET if self.is_offense else RED + # area_lines = DebugCommandFactory().area(self.area, color=color) + # line_test = DebugCommandFactory().line(self.area.center, self.best_position, color=color) + # + # return area_lines + [line_test] diff --git a/ai/STA/Tactic/tactic.py b/ai/STA/Tactic/tactic.py index 55f08def..8b7903af 100644 --- a/ai/STA/Tactic/tactic.py +++ b/ai/STA/Tactic/tactic.py @@ -96,7 +96,7 @@ def _check_for_forbidden_area(self, next_ai_command): new_target = Pose(target_position, next_ai_command.target.orientation) if closest_new_target is None \ - or (closest_new_target - self.player.position).norm > (new_target - self.player.position).norm: + or (closest_n ew_target - self.player.position).norm > (new_target - self.player.position).norm: closest_new_target = new_target if closest_new_target is not None: diff --git a/ai/coach.py b/ai/coach.py index 0f396235..202a8ac7 100644 --- a/ai/coach.py +++ b/ai/coach.py @@ -65,9 +65,7 @@ def callback(excess_time): self.fps_sleep = create_fps_timer(self.fps, on_miss_callback=callback) # profiling - self.profiler = cProfile.Profile() - if self.framework.profiling: - self.profiler.enable() + self.profiler = None def wait_for_geometry(self): self.logger.debug('Waiting for field\'s geometry from the Engine.') @@ -90,6 +88,11 @@ def run(self): self.logger.debug('Running with process ID {} at {} fps.'.format(os.getpid(), self.fps)) + # profiling + self.profiler = cProfile.Profile() + if self.framework.profiling: + self.profiler.enable() + try: self.wait_for_geometry() self.wait_for_referee() @@ -106,11 +109,12 @@ def run(self): self.logger.info('A connection was broken.') except: self.logger.exception('An error occurred.') + finally: + self.dump_profiling_stats() - def terminate(self): - self.dump_profiling_stats() + def join(self, timeout=None): self.logger.info('Terminated') - super().terminate() + super().join(timeout=timeout) def main_loop(self): self.game_state.update(self.engine_game_state) @@ -128,13 +132,12 @@ def update_time(self): def dump_profiling_stats(self): if self.framework.profiling: - if self.frame_count % (self.fps * config['GAME']['profiling_dump_time']) == 0: - self.profiler.dump_stats(config['GAME']['profiling_filename']) - self.logger.debug('Profiling data written to {}.'.format(config['GAME']['profiling_filename'])) + self.profiler.dump_stats(config['GAME']['profiling_filename']) + self.logger.debug('Profiling data written to {}.'.format(config['GAME']['profiling_filename'])) def is_alive(self): if config['GAME']['competition_mode']: if time() - self.framework.ai_watchdog.value > self.framework.MAX_HANGING_TIME: self.logger.critical('Process is hanging. Shutting down.') return False - return super().is_alive() \ No newline at end of file + return super().is_alive() From 57f5ce417fa7c89ed9931861b681ce3db95df2fb Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 17:33:37 -0400 Subject: [PATCH 03/58] Fail --- ai/STA/Tactic/tactic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/STA/Tactic/tactic.py b/ai/STA/Tactic/tactic.py index 8b7903af..55f08def 100644 --- a/ai/STA/Tactic/tactic.py +++ b/ai/STA/Tactic/tactic.py @@ -96,7 +96,7 @@ def _check_for_forbidden_area(self, next_ai_command): new_target = Pose(target_position, next_ai_command.target.orientation) if closest_new_target is None \ - or (closest_n ew_target - self.player.position).norm > (new_target - self.player.position).norm: + or (closest_new_target - self.player.position).norm > (new_target - self.player.position).norm: closest_new_target = new_target if closest_new_target is not None: From 000f561c5f17f2aec0d8c8307d381e009707df26 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 18:52:14 -0400 Subject: [PATCH 04/58] Done PR fixes --- config/config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/config/config.py b/config/config.py index 5521523d..2b749e23 100644 --- a/config/config.py +++ b/config/config.py @@ -135,7 +135,6 @@ def default_config(): }, 'ENGINE': { 'profiling_filename': 'profile_data_engine.prof', - 'profiling_dump_time': 10, 'number_of_camera': 4, 'max_robot_id': 12, 'max_undetected_robot_time': 5, From a32d6fb42a665c29c387cccf550ab2668d9e05e6 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 19:07:45 -0400 Subject: [PATCH 05/58] Wall member can not kick the ball if an enemy is close --- ai/STA/Tactic/align_to_defense_wall.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/ai/STA/Tactic/align_to_defense_wall.py b/ai/STA/Tactic/align_to_defense_wall.py index fe4f1170..d1551507 100644 --- a/ai/STA/Tactic/align_to_defense_wall.py +++ b/ai/STA/Tactic/align_to_defense_wall.py @@ -122,7 +122,9 @@ def main_state(self): self.compute_wall_segment() if self.game_state.field.is_ball_in_our_goal_area(): return Idle # We must not block the goalkeeper - elif self._should_ball_be_kick_by_wall() and self._is_closest_not_goaler(self.player): + elif self._should_ball_be_kick_by_wall() \ + and self._is_closest_not_goaler(self.player) \ + and self._no_enemy_around_ball(): self.next_state = self.go_kick dest = self.position_on_wall_segment() dest_orientation = (self.object_to_block.position - dest).angle @@ -136,7 +138,8 @@ def go_kick(self): if not self._should_ball_be_kick_by_wall() \ or self.game_state.field.is_ball_in_our_goal_area() \ - or not self._is_closest_not_goaler(self.player): + or not self._is_closest_not_goaler(self.player) \ + or not self._no_enemy_around_ball(): self.go_kick_tactic = None self.next_state = self.main_state return Idle @@ -164,5 +167,13 @@ def _closest_point_away_from_ball(self): else: return inters[1] + def _no_enemy_around_ball(self): + DANGEROUS_ENEMY_MIN_DISTANCE = 500 + ball_position = self.game_state.ball_position + for enemy in self.game_state.enemy_team.available_players.values(): + if (enemy.position - ball_position).norm < DANGEROUS_ENEMY_MIN_DISTANCE: + return False + return True + From d210f7b2aa8a76cdf367e79ac793523bea8b48d1 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sat, 16 Jun 2018 19:24:35 -0400 Subject: [PATCH 06/58] Fix comments --- config/config.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/config.py b/config/config.py index 2b749e23..89a1ede5 100644 --- a/config/config.py +++ b/config/config.py @@ -130,8 +130,7 @@ def default_config(): 'is_autonomous_play_at_startup': False, 'on_negative_side': True, 'fps': 10, - 'profiling_filename': 'profile_data_ai.prof', - 'profiling_dump_time': 10 + 'profiling_filename': 'profile_data_ai.prof' }, 'ENGINE': { 'profiling_filename': 'profile_data_engine.prof', From 6258a63ef6ad3ced4c08f2660be8defb80bcf0bc Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sun, 17 Jun 2018 10:31:52 -0400 Subject: [PATCH 07/58] Fix line for competition, add field for competition, not official port yet --- Util/geometry.py | 8 ++++++++ ai/GameDomainObjects/field.py | 7 +++++-- config/field/montreal_div_b_comp.cfg | 5 +++++ config/montreal_div_b_comp.cfg | 12 ++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 config/field/montreal_div_b_comp.cfg create mode 100644 config/montreal_div_b_comp.cfg diff --git a/Util/geometry.py b/Util/geometry.py index 6857ed1e..7a16efaf 100644 --- a/Util/geometry.py +++ b/Util/geometry.py @@ -126,6 +126,14 @@ def from_limits(cls, top, bottom, right, left): def flip_x(cls, area): return Area.from_limits(area.top, area.bottom, -area.left, -area.right) + @classmethod + def from_4_point(cls, p1, p2, p3, p4): + top = max(p1.y, p2.y, p3.y, p4.y) + bot = min(p1.y, p2.y, p3.y, p4.y) + right = max(p1.x, p2.x, p3.x, p4.x) + left = min(p1.x, p2.x, p3.x, p4.x) + return Area.from_limits(top, bot, right, left) + def find_bisector_of_triangle(c, a, b): """ diff --git a/ai/GameDomainObjects/field.py b/ai/GameDomainObjects/field.py index 75e36b6e..64c96491 100644 --- a/ai/GameDomainObjects/field.py +++ b/ai/GameDomainObjects/field.py @@ -161,8 +161,11 @@ def _update_field_const(self): self.their_goal = Position(self.their_goal_x, 0) self.their_goal_pose = Pose(self.their_goal, 0) - self.our_goal_area = Area(self.field_lines["RightPenaltyStretch"].p2, - self.field_lines["RightFieldLeftPenaltyStretch"].p1) + p1 = self.field_lines["RightPenaltyStretch"].p1 + p2 = self.field_lines["RightPenaltyStretch"].p2 + p3 = self.field_lines["RightFieldLeftPenaltyStretch"].p1 + p4 = self.field_lines["RightFieldLeftPenaltyStretch"].p2 + self.our_goal_area = Area.from_4_point(p1, p2, p3, p4) self.their_goal_area = Area.flip_x(self.our_goal_area) diff --git a/config/field/montreal_div_b_comp.cfg b/config/field/montreal_div_b_comp.cfg new file mode 100644 index 00000000..669735ad --- /dev/null +++ b/config/field/montreal_div_b_comp.cfg @@ -0,0 +1,5 @@ +[COMMUNICATION] +referee_address = 224.5.23.1 +referee_port=10023 +vision_address = 224.5.23.2 +vision_port=10006 \ No newline at end of file diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg new file mode 100644 index 00000000..b371552c --- /dev/null +++ b/config/montreal_div_b_comp.cfg @@ -0,0 +1,12 @@ +[GAME] +type=real + +[COMMUNICATION] +type=serial +field_port_file=config/field/montreal_div_b_comp.cfg +ui_debug_address=127.0.0.1 + +[ENGINE] +number_of_camera=4 +disabled_camera_id=[] + From a3ea9bd95afcbc7c2362ad7d1daa7849cc96fa48 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sun, 17 Jun 2018 11:25:36 -0400 Subject: [PATCH 08/58] Make max id 16, fix bug where the goalkeeper crash when there is no enemy player --- Engine/tracker.py | 2 +- Util/constant.py | 1 - ai/GameDomainObjects/player.py | 3 ++- ai/GameDomainObjects/team.py | 4 ++-- ai/STA/Strategy/robocup_choreography.py | 2 -- ai/STA/Tactic/goalkeeper.py | 30 ++++++++++++------------- config/config.py | 2 +- 7 files changed, 21 insertions(+), 23 deletions(-) diff --git a/Engine/tracker.py b/Engine/tracker.py index 1dddbf75..661a1ac9 100644 --- a/Engine/tracker.py +++ b/Engine/tracker.py @@ -97,7 +97,6 @@ def _remove_undetected(self): config['ENGINE']['max_undetected_robot_time'], undetected_robots) - for ball in self.active_balls: if time() - ball.last_update_time > config['ENGINE']['max_undetected_ball_time']: ball.reset() @@ -120,6 +119,7 @@ def _log_new_robots_on_field(self, detection_frame: Dict[str, List[Dict[str, Any for robot_obs in detection_frame.get('robots_blue', ()): if not self._blue_team[robot_obs['robot_id']].is_active: new_robots['blue'].add(robot_obs['robot_id']) + if new_robots['blue']: self.logger.debug('Blue robot(s) detected: %r', new_robots['blue']) diff --git a/Util/constant.py b/Util/constant.py index d72bf0dd..d8bb68a7 100644 --- a/Util/constant.py +++ b/Util/constant.py @@ -8,7 +8,6 @@ ROBOT_DIAMETER = ROBOT_RADIUS * 2 ROBOT_CENTER_TO_KICKER = 50 BALL_RADIUS = 21 -PLAYER_PER_TEAM = 12 MAX_PLAYER_ON_FIELD_PER_TEAM = 6 BALL_OUTSIDE_FIELD_BUFFER = 200 diff --git a/ai/GameDomainObjects/player.py b/ai/GameDomainObjects/player.py index 256a7868..3820e071 100644 --- a/ai/GameDomainObjects/player.py +++ b/ai/GameDomainObjects/player.py @@ -1,13 +1,14 @@ # Under MIT License, see LICENSE.txt from Util.pose import Pose +from config.config import Config class Player: def __init__(self, number_id: int, team): assert isinstance(number_id, int) - assert number_id in [x for x in range(0, 13)] + assert number_id in range(0, Config()['ENGINE']['max_robot_id']) self._id = number_id self._team = team diff --git a/ai/GameDomainObjects/team.py b/ai/GameDomainObjects/team.py index 2966966f..88a50503 100644 --- a/ai/GameDomainObjects/team.py +++ b/ai/GameDomainObjects/team.py @@ -1,9 +1,9 @@ # Under MIT License, see LICENSE.txt from typing import Dict -from Util.constant import PLAYER_PER_TEAM from Util.team_color_service import TeamColor from ai.GameDomainObjects.player import Player +from config.config import Config class Team: @@ -11,7 +11,7 @@ def __init__(self, team_color: TeamColor): assert isinstance(team_color, TeamColor) self._team_color = team_color - self._players = {i: Player(i, self) for i in range(PLAYER_PER_TEAM)} + self._players = {i: Player(i, self) for i in range(Config()['ENGINE']['max_robot_id'])} self._available_players = {} def update(self, players: Dict): diff --git a/ai/STA/Strategy/robocup_choreography.py b/ai/STA/Strategy/robocup_choreography.py index 6629369b..e34b7d0a 100644 --- a/ai/STA/Strategy/robocup_choreography.py +++ b/ai/STA/Strategy/robocup_choreography.py @@ -3,13 +3,11 @@ from functools import partial from random import shuffle -from Util.constant import PLAYER_PER_TEAM from Util.pose import Pose, Position from ai.STA.Strategy.strategy import Strategy from ai.STA.Tactic.go_to_position import GoToPosition -from ai.STA.Tactic.stop import Stop from ai.STA.Tactic.tactic_constants import Flags from Util.role import Role diff --git a/ai/STA/Tactic/goalkeeper.py b/ai/STA/Tactic/goalkeeper.py index 16fdfaa6..e82b8b9d 100644 --- a/ai/STA/Tactic/goalkeeper.py +++ b/ai/STA/Tactic/goalkeeper.py @@ -137,21 +137,21 @@ def _is_ball_safe_to_kick(self): area_in_front_of_goal.point_inside(self.game_state.ball.position) and self._no_enemy_around_ball() def _best_target_into_goal(self): - - enemy_player_with_ball = player_with_ball(min_dist_from_ball=200, our_team=False) - if enemy_player_with_ball is not None: - if player_pointing_toward_segment(enemy_player_with_ball, self.GOAL_LINE): - ball = self.game_state.ball - where_ball_enter_goal = intersection_between_lines(self.GOAL_LINE.p1, - self.GOAL_LINE.p2, - ball.position, - ball.position + - Position(1000 * np.cos(enemy_player_with_ball.pose.orientation), - 1000 * np.sin(enemy_player_with_ball.pose.orientation))) - where_ball_enter_goal = closest_point_on_segment(where_ball_enter_goal, - self.GOAL_LINE.p1, - self.GOAL_LINE.p2) - return where_ball_enter_goal + if 0 < len(self.game_state.enemy_team.available_players): + enemy_player_with_ball = player_with_ball(min_dist_from_ball=200, our_team=False) + if enemy_player_with_ball is not None: + if player_pointing_toward_segment(enemy_player_with_ball, self.GOAL_LINE): + ball = self.game_state.ball + where_ball_enter_goal = intersection_between_lines(self.GOAL_LINE.p1, + self.GOAL_LINE.p2, + ball.position, + ball.position + + Position(1000 * np.cos(enemy_player_with_ball.pose.orientation), + 1000 * np.sin(enemy_player_with_ball.pose.orientation))) + where_ball_enter_goal = closest_point_on_segment(where_ball_enter_goal, + self.GOAL_LINE.p1, + self.GOAL_LINE.p2) + return where_ball_enter_goal return find_bisector_of_triangle(self.game_state.ball.position, self.GOAL_LINE.p2, diff --git a/config/config.py b/config/config.py index 89a1ede5..3c78fec5 100644 --- a/config/config.py +++ b/config/config.py @@ -135,7 +135,7 @@ def default_config(): 'ENGINE': { 'profiling_filename': 'profile_data_engine.prof', 'number_of_camera': 4, - 'max_robot_id': 12, + 'max_robot_id': 16, 'max_undetected_robot_time': 5, 'max_undetected_ball_time': 0.5, 'max_ball_on_field': 2, From b06b0ce377bff286b94516dc9845ddf62ad900fa Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sun, 17 Jun 2018 14:40:01 -0400 Subject: [PATCH 09/58] Fix goalkeeper --- ai/STA/Tactic/goalkeeper.py | 8 ++++++-- config/montreal_div_b_comp.cfg | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/ai/STA/Tactic/goalkeeper.py b/ai/STA/Tactic/goalkeeper.py index e82b8b9d..d12adedd 100644 --- a/ai/STA/Tactic/goalkeeper.py +++ b/ai/STA/Tactic/goalkeeper.py @@ -15,7 +15,7 @@ from Util.ai_command import MoveTo, Idle from Util.constant import ROBOT_RADIUS, KEEPOUT_DISTANCE_FROM_GOAL, ROBOT_DIAMETER from Util.geometry import intersection_line_and_circle, intersection_between_lines, \ - closest_point_on_segment, find_bisector_of_triangle, Area + closest_point_on_segment, find_bisector_of_triangle, Area, Line from ai.GameDomainObjects import Player from ai.STA.Tactic.go_kick import GRAB_BALL_SPACING, GoKick @@ -95,9 +95,13 @@ def intercept(self): # This is where the ball is going to enter the goal where_ball_enter_goal = closest_point_on_segment(where_ball_enter_goal, self.GOAL_LINE.p1, self.GOAL_LINE.p2) + enter_goal_to_ball = Line(where_ball_enter_goal, ball.position) + + # The goalkeeper can not enter goal since there a line blocking vision + end_segment = enter_goal_to_ball.direction * ROBOT_RADIUS + where_ball_enter_goal intersect_pts = closest_point_on_segment(self.player.position, - ball.position, where_ball_enter_goal) + ball.position, end_segment) self.last_intersection = intersect_pts return MoveTo(Pose(intersect_pts, self.player.pose.orientation), # It's a bit faster, to keep our orientation cruise_speed=3, diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index b371552c..938d9afd 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[] +disabled_camera_id=[2, 1] From d383c64820bc9277971763de9afb35185a9e396d Mon Sep 17 00:00:00 2001 From: philippe Date: Sun, 17 Jun 2018 17:53:24 -0400 Subject: [PATCH 10/58] eat this babin --- Engine/controller.py | 2 +- Engine/filters/robot_kalman_filter.py | 4 ++-- Engine/robot.py | 4 ++-- ai/STA/Tactic/go_kick.py | 25 ++++++++++++++++++------- config/real.cfg | 2 +- 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Engine/controller.py b/Engine/controller.py index 2c58bbb5..5ffec0bc 100644 --- a/Engine/controller.py +++ b/Engine/controller.py @@ -58,7 +58,7 @@ def execute(self, dt: float) -> RobotState: for robot in self.active_robots: robot.path, robot.target_speed = path_smoother(robot.raw_path, robot.cruise_speed, robot.end_speed) - if robot.target_speed < 10: + if robot.target_speed < 10 and False: commands[robot.id] = min(robot.velocity_regulator.execute(robot, dt), robot.position_regulator.execute(robot, dt), key=lambda cmd: cmd.norm) diff --git a/Engine/filters/robot_kalman_filter.py b/Engine/filters/robot_kalman_filter.py index 7259d1d6..c73078f6 100644 --- a/Engine/filters/robot_kalman_filter.py +++ b/Engine/filters/robot_kalman_filter.py @@ -43,8 +43,8 @@ def control_input_model(self, dt): [0, 0, dt]]) # Speed Theta def process_covariance(self, dt): - sigma_acc_x = 500 - sigma_acc_y = 500 + sigma_acc_x = 1000 + sigma_acc_y = 1000 sigma_acc_o = 20000 * np.pi/180 process_covariance = \ diff --git a/Engine/robot.py b/Engine/robot.py index 849192f8..ab94bd8b 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -4,8 +4,8 @@ from Util.geometry import wrap_to_pi MAX_LINEAR_SPEED = 4000 # mm/s -MAX_LINEAR_ACCELERATION = 4000 # mm/s^2 -MAX_ANGULAR_SPEED = 50 # rad/s +MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 +MAX_ANGULAR_SPEED = 100 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 9ce37e81..04b10467 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -80,7 +80,7 @@ def go_behind_ball(self): distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.is_able_to_grab_ball_directly(0.8) \ + if self.is_able_to_grab_ball_directly(0.95) \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/100)): self.next_state = self.grab_ball else: @@ -94,7 +94,7 @@ def go_behind_ball(self): def grab_ball(self): if self.auto_update_target: self._find_best_passing_option() - if not self.is_able_to_grab_ball_directly(0.8): + if not self.is_able_to_grab_ball_directly(0.95): self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: @@ -102,18 +102,20 @@ def grab_ball(self): self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm orientation = (self.target.position - self.game_state.ball_position).angle - distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING * (1 + ball_speed / 1000)) + distance_behind = self.get_destination_behind_ball(-(GRAB_BALL_SPACING)) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, + end_speed=0, ball_collision=False)\ .addForceDribbler()\ .addChargeKicker()\ + .addKick(self.kick_force)\ .build() def kick(self): if self.auto_update_target: self._find_best_passing_option() - if not self.is_able_to_grab_ball_directly(0.8): + if not self.is_able_to_grab_ball_directly(0.95): self.next_state = self.go_behind_ball return self.go_behind_ball() self.next_state = self.validate_kick @@ -123,7 +125,8 @@ def kick(self): orientation = (self.target.position - self.game_state.ball_position).angle return CmdBuilder().addMoveTo(Pose(behind_ball, orientation), - ball_collision=False)\ + ball_collision=False, + end_speed=0)\ .addKick(self.kick_force)\ .addForceDribbler().build() @@ -176,13 +179,21 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ + dir_ball_to_target = normalize(self.target.position - self.game_state.ball.position) - return self.game_state.ball.position - dir_ball_to_target * ball_spacing + position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing + + if velocity: + position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * + np.dot(dir_ball_to_target.array, + self.game_state.ball.velocity.array))) / 300 + + return position_behind def is_able_to_grab_ball_directly(self, threshold): # plus que le threshold est gors (1 max), plus qu'on veut que le robot soit direct deriere la balle. diff --git a/config/real.cfg b/config/real.cfg index 333ba799..1af92714 100644 --- a/config/real.cfg +++ b/config/real.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[] +disabled_camera_id=[1,2] From fa5b86a70ab8ab82625715a9d4f80fa170340558 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Sun, 17 Jun 2018 21:20:32 -0400 Subject: [PATCH 11/58] Naming error in competition mode --- ai/STA/Tactic/place_ball.py | 4 +++- ai/coach.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ai/STA/Tactic/place_ball.py b/ai/STA/Tactic/place_ball.py index a2d991bc..78fdb3fd 100644 --- a/ai/STA/Tactic/place_ball.py +++ b/ai/STA/Tactic/place_ball.py @@ -44,7 +44,9 @@ def __init__(self, game_state: GameState, player: Player, self.steady_orientation = None def _fetch_ball(self): - if self.game_state.field.is_outside_wall_limit(self.game_state.ball_position) or self._check_success(): + #if self.game_state.field.is_outside_wall_limit(self.game_state.ball_position) or \ + # self._check_success(): + if self._check_success(): self.next_state = self.halt else: self.next_state = self.go_behind_ball diff --git a/ai/coach.py b/ai/coach.py index 202a8ac7..b50d90b8 100644 --- a/ai/coach.py +++ b/ai/coach.py @@ -137,7 +137,7 @@ def dump_profiling_stats(self): def is_alive(self): if config['GAME']['competition_mode']: - if time() - self.framework.ai_watchdog.value > self.framework.MAX_HANGING_TIME: + if time() - self.framework.coach_watchdog.value > self.framework.MAX_HANGING_TIME: self.logger.critical('Process is hanging. Shutting down.') return False return super().is_alive() From f43d63e574d27ae552bc7f568483b2fb9c6eaa92 Mon Sep 17 00:00:00 2001 From: philippe Date: Sun, 17 Jun 2018 21:42:07 -0400 Subject: [PATCH 12/58] Change orientation of grab_ball --- ai/STA/Tactic/go_kick.py | 4 ++-- config/real.cfg | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 04b10467..018c5b31 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -101,7 +101,7 @@ def grab_ball(self): self.next_state = self.kick self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm - orientation = (self.target.position - self.game_state.ball_position).angle + orientation = (self.game_state.ball_position - self.player.position).angle distance_behind = self.get_destination_behind_ball(-(GRAB_BALL_SPACING)) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, @@ -191,7 +191,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True) -> Position: if velocity: position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * np.dot(dir_ball_to_target.array, - self.game_state.ball.velocity.array))) / 300 + self.game_state.ball.velocity.array))) / 50 return position_behind diff --git a/config/real.cfg b/config/real.cfg index 1af92714..5133eccd 100644 --- a/config/real.cfg +++ b/config/real.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[1,2] +disabled_camera_id=[1, 2] From babb4505b1af46bd328ccad8229eddfa25cdd574 Mon Sep 17 00:00:00 2001 From: philippe Date: Sun, 17 Jun 2018 23:05:11 -0400 Subject: [PATCH 13/58] Fix cruise speed team go to position --- ai/STA/Strategy/team_go_to_position.py | 5 ++++- autoref_dual_launch.sh | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ai/STA/Strategy/team_go_to_position.py b/ai/STA/Strategy/team_go_to_position.py index e7d1af49..bfb5e6b8 100644 --- a/ai/STA/Strategy/team_go_to_position.py +++ b/ai/STA/Strategy/team_go_to_position.py @@ -22,7 +22,10 @@ def assign_tactics(self, role_to_positions): continue position = role_to_positions[role] position.orientation = np.pi - node_go_to_position = self.create_node(role, GoToPosition(self.game_state, player, position)) + node_go_to_position = self.create_node(role, GoToPosition(self.game_state, + player, + position, + cruise_speed=1)) node_stop = self.create_node(role, Stop(self.game_state, player)) player_arrived_to_position = partial(self.arrived_to_position, player) diff --git a/autoref_dual_launch.sh b/autoref_dual_launch.sh index 32963adc..4d5c7d5f 100755 --- a/autoref_dual_launch.sh +++ b/autoref_dual_launch.sh @@ -1,6 +1,6 @@ #!/bin/bash # Start two AI: yellow one in auto mode, blue in manual with a UI-debug. -python ../UI-Debug/main.py config/field/autoref.cfg blue \ -| python main.py config/autoref.cfg yellow negative --start_in_auto --engine_fps 65 \ -| python main.py config/autoref.cfg blue positive --engine_fps 65 +python ../UI-Debug/main.py config/field/sim.cfg blue \ +| python main.py config/sim.cfg yellow negative --start_in_auto --engine_fps 30 --competition_mode \ +| python main.py config/sim.cfg blue positive --engine_fps 30 --competition_mode From deb37e909ccab804710056e891aa464a9a6f3137 Mon Sep 17 00:00:00 2001 From: philippe Date: Sun, 17 Jun 2018 23:55:36 -0400 Subject: [PATCH 14/58] g0_kick full cool, commit --force_no_babin hard --- Engine/regulators/velocity_regulators.py | 2 +- ai/STA/Tactic/go_kick.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index f8f461e5..ef32eee4 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -13,7 +13,7 @@ class RealVelocityController(RegulatorBaseClass): settings = {'kp': 10, 'ki': 0, 'kd': 1} - v_d = 5 # lower = bigger path correction + v_d = 10 # lower = bigger path correction emergency_break_constant = 0.4 # Higher = higher correction of trajectory emergency_break_safety_factor = 1 # lower = bigger break distance diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 018c5b31..d24693a5 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -102,7 +102,7 @@ def grab_ball(self): self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm orientation = (self.game_state.ball_position - self.player.position).angle - distance_behind = self.get_destination_behind_ball(-(GRAB_BALL_SPACING)) + distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, end_speed=0, @@ -179,7 +179,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing, velocity=True) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=25) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ @@ -191,7 +191,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True) -> Position: if velocity: position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * np.dot(dir_ball_to_target.array, - self.game_state.ball.velocity.array))) / 50 + self.game_state.ball.velocity.array))) / velocity_offset return position_behind From e5fe3471ac99c04462c1a26b000050e0b5229b7b Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 01:27:13 -0400 Subject: [PATCH 15/58] draw with EMI 18 juin 2018 --- .../sender/serial_command_sender.py | 16 +++++++++++++--- config/montreal_div_b_comp.cfg | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Engine/Communication/sender/serial_command_sender.py b/Engine/Communication/sender/serial_command_sender.py index 18a24cec..7195a115 100644 --- a/Engine/Communication/sender/serial_command_sender.py +++ b/Engine/Communication/sender/serial_command_sender.py @@ -3,7 +3,10 @@ from pyhermes import McuCommunicator from Engine.Communication.sender.sender_base_class import Sender +from Engine.robot import MAX_LINEAR_SPEED, MAX_ANGULAR_SPEED from Util.constant import KickForce, DribbleState +from Util.geometry import clamp +import numpy as np class SerialCommandSender(Sender): @@ -14,10 +17,17 @@ def connect(self, connection_info): def send_packet(self, packets_frame): try: for packet in packets_frame.packet: + if np.isnan(packet.command.x) or \ + np.isnan(packet.command.y) or \ + np.isnan(packet.command.orientation): + continue + cx = clamp(packet.command.x, -MAX_LINEAR_SPEED, MAX_LINEAR_SPEED) + cy = clamp(packet.command.y, -MAX_LINEAR_SPEED, MAX_LINEAR_SPEED) + orien = clamp(packet.command.orientation, -MAX_ANGULAR_SPEED, MAX_ANGULAR_SPEED) self.connection.sendSpeedAdvance(packet.robot_id, - packet.command.x/1000, - packet.command.y/1000, - packet.command.orientation, + cx/1000, + cy/1000, + orien, packet.charge_kick, self.translate_kick_force(packet.kick_force), self.translate_dribbler_speed(packet.dribbler_state)) diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index 938d9afd..b371552c 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[2, 1] +disabled_camera_id=[] From 4f8a7c3ffcb371231a1affc5b9438d1918306148 Mon Sep 17 00:00:00 2001 From: SimLemay Date: Mon, 18 Jun 2018 08:42:59 -0400 Subject: [PATCH 16/58] Force no disabled camera in competition mode --- config/config.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.py b/config/config.py index e04d1001..1bc51334 100644 --- a/config/config.py +++ b/config/config.py @@ -178,6 +178,9 @@ def load_parameters(self, cli_args): logging.basicConfig(level=logging.NOTSET, handlers=[file_handler, console_handler]) + # NO CAMERA DISABLED IN COMPETITION MODE + self._config['ENGINE']['disabled_camera_id'] = [] + self._config_was_set = False self.update_ports() self._config_was_set = True From 93986d39fd60ff3c4abdb2d9c6d3e02051a50187 Mon Sep 17 00:00:00 2001 From: SimLemay Date: Mon, 18 Jun 2018 08:50:49 -0400 Subject: [PATCH 17/58] Add logger --- config/config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.py b/config/config.py index 1bc51334..585131f8 100644 --- a/config/config.py +++ b/config/config.py @@ -179,6 +179,7 @@ def load_parameters(self, cli_args): logging.basicConfig(level=logging.NOTSET, handlers=[file_handler, console_handler]) # NO CAMERA DISABLED IN COMPETITION MODE + self.logger.warning("There is one or more disabled cameras. Reenabling them for competition mode") self._config['ENGINE']['disabled_camera_id'] = [] self._config_was_set = False From ffdd45a6fceeac734f488a1e585d0afc345226ac Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Mon, 18 Jun 2018 09:27:31 -0400 Subject: [PATCH 18/58] Apply review comments --- Engine/controller.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Engine/controller.py b/Engine/controller.py index 5ffec0bc..d06b0739 100644 --- a/Engine/controller.py +++ b/Engine/controller.py @@ -57,13 +57,13 @@ def execute(self, dt: float) -> RobotState: for robot in self.active_robots: robot.path, robot.target_speed = path_smoother(robot.raw_path, robot.cruise_speed, robot.end_speed) - - if robot.target_speed < 10 and False: - commands[robot.id] = min(robot.velocity_regulator.execute(robot, dt), - robot.position_regulator.execute(robot, dt), - key=lambda cmd: cmd.norm) - else: - commands[robot.id] = robot.velocity_regulator.execute(robot, dt) + # + # if robot.target_speed < 10 and False: + # commands[robot.id] = min(robot.velocity_regulator.execute(robot, dt), + # robot.position_regulator.execute(robot, dt), + # key=lambda cmd: cmd.norm) + # else: + commands[robot.id] = robot.velocity_regulator.execute(robot, dt) self.send_debug(commands) From 41c9659e91ddccd7cd0f768d32c35464eb840b45 Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Mon, 18 Jun 2018 09:35:11 -0400 Subject: [PATCH 19/58] add join to sender and receiver --- Engine/Communication/receiver/receiver_base_class.py | 8 +++----- Engine/Communication/sender/sender_base_class.py | 9 +++------ Engine/engine.py | 9 ++++----- ai/coach.py | 2 +- config/fake.cfg | 2 +- main.py | 2 +- 6 files changed, 13 insertions(+), 19 deletions(-) diff --git a/Engine/Communication/receiver/receiver_base_class.py b/Engine/Communication/receiver/receiver_base_class.py index 6558f826..f9aece37 100644 --- a/Engine/Communication/receiver/receiver_base_class.py +++ b/Engine/Communication/receiver/receiver_base_class.py @@ -46,8 +46,6 @@ def run(self): except: self.logger.exception('An error occurred.') raise - - def terminate(self): - self.connection.close() - self.logger.debug('Terminated') - super().terminate() + finally: + self.connection.close() + self.logger.debug('Terminated') diff --git a/Engine/Communication/sender/sender_base_class.py b/Engine/Communication/sender/sender_base_class.py index 22593095..ad90a509 100644 --- a/Engine/Communication/sender/sender_base_class.py +++ b/Engine/Communication/sender/sender_base_class.py @@ -43,9 +43,6 @@ def run(self): except: self.logger.exception('An error occurred.') raise - - def terminate(self): - self.logger.debug('Terminated') - self._queue.close() - self.connection.close() - super().terminate() + finally: + self.connection.close() + self.logger.debug('Terminated') diff --git a/Engine/engine.py b/Engine/engine.py index 2d3009ff..3861b063 100644 --- a/Engine/engine.py +++ b/Engine/engine.py @@ -125,7 +125,6 @@ def update_time(self): def main_loop(self): engine_cmds = self.get_engine_commands() - game_state = self.tracker.update() self.game_state.update(game_state) @@ -170,9 +169,9 @@ def is_alive(self): def terminate(self): self.dump_profiling_stats() - self.vision_receiver.terminate() - self.ui_sender.terminate() - self.ui_recver.terminate() - self.referee_recver.terminate() + self.vision_receiver.join(timeout=0.1) + self.ui_sender.join(timeout=0.1) + self.ui_recver.join(timeout=0.1) + self.referee_recver.join(timeout=0.1) self.logger.debug('Terminated') super().terminate() diff --git a/ai/coach.py b/ai/coach.py index 0f396235..5f5a72ca 100644 --- a/ai/coach.py +++ b/ai/coach.py @@ -134,7 +134,7 @@ def dump_profiling_stats(self): def is_alive(self): if config['GAME']['competition_mode']: - if time() - self.framework.ai_watchdog.value > self.framework.MAX_HANGING_TIME: + if time() - self.framework.coach_watchdog.value > self.framework.MAX_HANGING_TIME: self.logger.critical('Process is hanging. Shutting down.') return False return super().is_alive() \ No newline at end of file diff --git a/config/fake.cfg b/config/fake.cfg index 193683cc..9a240213 100644 --- a/config/fake.cfg +++ b/config/fake.cfg @@ -1,5 +1,5 @@ [GAME] -type=real +type=sim [COMMUNICATION] type=disabled diff --git a/main.py b/main.py index 916f5c03..566700a1 100644 --- a/main.py +++ b/main.py @@ -88,4 +88,4 @@ def set_arg_parser(): stop_framework = True else: logger.debug('Restarting Framework.') - sleep(0.5) + sleep(5) From 24786dbddbb48bc3fe8ae61ce14b73b29a89935b Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 10:52:51 -0400 Subject: [PATCH 20/58] babin try this --- ai/STA/Strategy/strategy_book.py | 4 +- ai/STA/Strategy/test_passing.py | 131 +++++++++++++++++++++++++++++++ ai/STA/Tactic/reveive_pass.py | 122 ++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+), 1 deletion(-) create mode 100644 ai/STA/Strategy/test_passing.py create mode 100644 ai/STA/Tactic/reveive_pass.py diff --git a/ai/STA/Strategy/strategy_book.py b/ai/STA/Strategy/strategy_book.py index 0ccce6c4..c57e656c 100644 --- a/ai/STA/Strategy/strategy_book.py +++ b/ai/STA/Strategy/strategy_book.py @@ -28,6 +28,7 @@ from ai.STA.Strategy.bamba_follow import BambaFollow from ai.STA.Strategy.stay_away import StayAway from ai.STA.Strategy.test_goal_keeper import TestGoalKeeper +from ai.STA.Strategy.test_passing import TestPassing __author__ = "Maxime Gagnon-Legault, and others" @@ -42,7 +43,8 @@ def __init__(self): default_strategies = [Offense, DefenseWall] - strategy_book = {HumanControl, + strategy_book = {TestPassing, + HumanControl, IndianaJones, RobocupChoreography, BambaFollow, diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py new file mode 100644 index 00000000..ce157a33 --- /dev/null +++ b/ai/STA/Strategy/test_passing.py @@ -0,0 +1,131 @@ +# Under MIT License, see LICENSE.txt + +from functools import partial +from math import acos + +from Util.geometry import normalize +from Util.role import Role + +from ai.Algorithm.evaluation_module import closest_players_to_point +from ai.STA.Strategy.strategy import Strategy +from ai.STA.Tactic.go_kick import GoKick +from ai.STA.Tactic.goalkeeper import GoalKeeper +from ai.STA.Tactic.position_for_pass import PositionForPass +from ai.STA.Tactic.reveive_pass import ReceivePass +from ai.STA.Tactic.tactic_constants import Flags +from ai.states.game_state import GameState +import numpy as np + + +# noinspection PyMethodMayBeStatic,PyMethodMayBeStatic +class TestPassing(Strategy): + + def __init__(self, p_game_state, can_kick_in_goal=False): + super().__init__(p_game_state) + + formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] + + initial_position_for_pass_center = {} + for role, player in self.assigned_roles.items(): + if role == Role.GOALKEEPER: + self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) + else: + node_pass = self.create_node(role, PositionForPass(self.game_state, + player, + robots_in_formation=formation, + auto_position=True, + forbidden_areas=[self.game_state.field.free_kick_avoid_area, + self.game_state.field.our_goal_forbidden_area])) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) + initial_position_for_pass_center[role] = node_pass.tactic.area.center # Hack + node_go_kick = self.create_node(role, GoKick(self.game_state, + player, + auto_update_target=True, + can_kick_in_goal=can_kick_in_goal)) + + player_is_not_closest = partial(self.is_not_closest, player) + player_has_kicked = partial(self.has_kicked, player) + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) + player_is_closest = partial(self.is_closest_not_goalkeeper, player) + + node_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_pass.connect_to(node_go_kick, when=player_is_closest) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_wait_for_pass.connect_to(node_pass, when=player_is_not_receiving_pass) + node_go_kick.connect_to(node_pass, when=player_is_not_closest) + node_go_kick.connect_to(node_go_kick, when=player_has_kicked) + + # Find position for ball player closest to ball + self.closest_role = None + ball_position = self.game_state.ball_position + for r, position in initial_position_for_pass_center.items(): + if self.closest_role is None \ + or (initial_position_for_pass_center[self.closest_role] - ball_position).norm > \ + (position - ball_position).norm: + self.closest_role = r + + self.has_ball_move = False + + @classmethod + def required_roles(cls): + return [Role.GOALKEEPER, + Role.FIRST_ATTACK, + Role.MIDDLE] + + @classmethod + def optional_roles(cls): + return [Role.SECOND_ATTACK, + Role.FIRST_DEFENCE, + Role.SECOND_DEFENCE] + + def is_closest_not_goalkeeper(self, player): + if self.game_state.ball.is_mobile(): + self.has_ball_move = True + role = GameState().get_role_by_player_id(player.id) + if not self.has_ball_move: + return role == self.closest_role + + closest_players = closest_players_to_point(GameState().ball_position, our_team=True) + if player == closest_players[0].player: + return True + return closest_players[0].player == self.game_state.get_player_by_role(Role.GOALKEEPER) \ + and player == closest_players[1].player + + def is_not_closest(self, player): + return not self.is_closest_not_goalkeeper(player) + + def has_kicked(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'GoKick': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False + + def is_ready_to_kick(self, player): + if self.has_ball_move: + return True # FIXME: Test irl, might Cause a lot of problem + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'RotateAroundBall': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False + + def ball_going_toward_player(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'PositionForPass': + if self.game_state.ball.velocity.norm > 50: + return np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array) > 0.9 + return False + + def ball_not_going_toward_player(self, player): + return not self.ball_going_toward_player(player) + + def has_received(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'ReceivePass': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False \ No newline at end of file diff --git a/ai/STA/Tactic/reveive_pass.py b/ai/STA/Tactic/reveive_pass.py new file mode 100644 index 00000000..a8e565df --- /dev/null +++ b/ai/STA/Tactic/reveive_pass.py @@ -0,0 +1,122 @@ +# Under MIT licence, see LICENCE.txt + +import math as m +import time +from typing import List, Union + +import numpy as np + +from Util.constant import ROBOT_CENTER_TO_KICKER, BALL_RADIUS, KickForce +from Util import Pose, Position +from Util.ai_command import CmdBuilder, Idle +from Util.geometry import compare_angle, normalize +from ai.Algorithm.evaluation_module import best_passing_option, player_covered_from_goal +from ai.GameDomainObjects import Player +from ai.STA.Tactic.tactic import Tactic +from ai.STA.Tactic.tactic_constants import Flags +from ai.states.game_state import GameState + + +GO_BEHIND_SPACING = 250 +GRAB_BALL_SPACING = 100 +HAS_BALL_DISTANCE = 130 +KICK_SUCCEED_THRESHOLD = 300 + + +# noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences +class ReceivePass(Tactic): + def __init__(self, game_state: GameState, player: Player): + + super().__init__(game_state, player) + self.current_state = self.initialize + self.next_state = self.initialize + + def initialize(self): + self.status_flag = Flags.WIP + if self.is_ball_going_to_collide(): + if self.game_state.ball.velocity.norm < 100: + self.next_state = self.grab_ball + else: + self.next_state = self.wait_for_ball + else: + self.next_state = self.go_behind_ball + + return Idle + + def go_behind_ball(self): + orientation = (self.game_state.ball_position - self.player.position).angle + ball_speed = self.game_state.ball.velocity.norm + ball_speed_modifier = (ball_speed/1000 + 1) + effective_ball_spacing = GRAB_BALL_SPACING * 3 * ball_speed_modifier + distance_behind = self.get_destination_behind_ball(effective_ball_spacing) + dist_from_ball = (self.player.position - self.game_state.ball_position).norm + + if self.is_ball_going_to_collide(threshold=0.95) \ + and compare_angle(self.player.pose.orientation, orientation, + abs_tol=max(0.1, 0.1 * dist_from_ball/100)): + self.next_state = self.grab_ball + else: + self.next_state = self.go_behind_ball + return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), + cruise_speed=3, + end_speed=0, + ball_collision=True)\ + .addChargeKicker().build() + + def grab_ball(self): + if not self.is_ball_going_to_collide(threshold=0.95): + self.next_state = self.go_behind_ball + + if self._get_distance_from_ball() < HAS_BALL_DISTANCE: + self.next_state = self.halt + return self.halt() + orientation = (self.game_state.ball_position - self.player.position).angle + distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) + return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), + cruise_speed=3, + end_speed=0, + ball_collision=False).addForceDribbler().build() + + def wait_for_ball(self): + if self._get_distance_from_ball() < HAS_BALL_DISTANCE: + self.next_state = self.halt + return self.halt() + if not self.is_ball_going_to_collide(threshold=0.95): + self.next_state = self.go_behind_ball + return CmdBuilder().build() + orientation = (self.game_state.ball_position - self.player.position).angle + return CmdBuilder().addMoveTo(Pose(self.player.position, orientation), + cruise_speed=3, + end_speed=0, + ball_collision=False).addForceDribbler().build() + + def halt(self): + if self.status_flag == Flags.INIT: + self.next_state = self.initialize + else: + self.status_flag = Flags.SUCCESS + return Idle + + def _get_distance_from_ball(self): + return (self.player.pose.position - self.game_state.ball_position).norm + + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=25) -> Position: + """ + Compute the point which is at ball_spacing mm behind the ball from the target. + """ + + dir_ball_to_target = normalize(self.game_state.ball.velocity) + + position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing + + if velocity: + position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * + np.dot(dir_ball_to_target.array, + self.game_state.ball.velocity.array))) / velocity_offset + + return position_behind + + def is_ball_going_to_collide(self, threshold=0.95): + + return np.dot(normalize(self.player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array) > threshold From 041655e967d77eb161d2e01a0792b087683c871b Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Mon, 18 Jun 2018 10:55:11 -0400 Subject: [PATCH 21/58] Fix some bugs --- Engine/robot.py | 2 +- ai/STA/Strategy/defense_wall.py | 11 +++++++---- config/montreal_div_b_comp.cfg | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Engine/robot.py b/Engine/robot.py index ab94bd8b..10ee5fc9 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -5,7 +5,7 @@ MAX_LINEAR_SPEED = 4000 # mm/s MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 -MAX_ANGULAR_SPEED = 100 # rad/s +MAX_ANGULAR_SPEED = 20 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/ai/STA/Strategy/defense_wall.py b/ai/STA/Strategy/defense_wall.py index 0aeb5d86..9c41218f 100644 --- a/ai/STA/Strategy/defense_wall.py +++ b/ai/STA/Strategy/defense_wall.py @@ -153,10 +153,13 @@ def _dispatch_player(self): def _generate_cover_to_coveree_mapping(self): # We want to assign a coveree(enemy) to every cover(ally) # We also want to know for each cover(ally), the other covers that share the same target(enemy) - closest_enemy_to_ball = closest_players_to_point(self.game_state.ball_position, our_team=False)[0].player - - closest_enemies_to_our_goal = closest_players_to_point(self.game_state.field.our_goal, our_team=False) - enemy_not_with_ball = [enemy.player for enemy in closest_enemies_to_our_goal if enemy.player is not closest_enemy_to_ball] + closest_enemies_to_ball = closest_players_to_point(self.game_state.ball_position, our_team=False) + if len(closest_enemies_to_ball) > 0: + closest_enemy_to_ball = closest_enemies_to_ball[0].player + closest_enemies_to_our_goal = closest_players_to_point(self.game_state.field.our_goal, our_team=False) + enemy_not_with_ball = [enemy.player for enemy in closest_enemies_to_our_goal if enemy.player is not closest_enemy_to_ball] + else: + enemy_not_with_ball = [] # If we don't have enough player we cover the ball if len(enemy_not_with_ball) == 0: diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index b371552c..321edfd3 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[] +disabled_camera_id=[1,2] From 8864e75b806881f2c4336d522bbb528714df12b6 Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 12:47:21 -0400 Subject: [PATCH 22/58] game remove rotate arround --- ai/STA/Strategy/free_kick.py | 8 ++++---- config/field/montreal_div_b_comp.cfg | 2 +- config/montreal_div_b_comp.cfg | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ai/STA/Strategy/free_kick.py b/ai/STA/Strategy/free_kick.py index 493a3e62..2509883b 100644 --- a/ai/STA/Strategy/free_kick.py +++ b/ai/STA/Strategy/free_kick.py @@ -40,17 +40,17 @@ def __init__(self, p_game_state, can_kick_in_goal): auto_update_target=True, can_kick_in_goal=can_kick_in_goal)) - node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, p_game_state.field.their_goal_pose)) + #node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, p_game_state.field.their_goal_pose)) player_is_closest = partial(self.is_closest_not_goalkeeper, player) player_is_not_closest = partial(self.is_not_closest, player) player_has_kicked = partial(self.has_kicked, player) player_is_ready_to_kick = partial(self.is_ready_to_kick, player) - node_pass.connect_to(node_rotate_around_ball, when=player_is_closest) - node_rotate_around_ball.connect_to(node_pass, when=player_is_not_closest) + node_pass.connect_to(node_go_kick, when=player_is_closest) + #node_rotate_around_ball.connect_to(node_pass, when=player_is_not_closest) node_go_kick.connect_to(node_pass, when=player_is_not_closest) - node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) + #node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) node_go_kick.connect_to(node_go_kick, when=player_has_kicked) # Find position for ball player closest to ball diff --git a/config/field/montreal_div_b_comp.cfg b/config/field/montreal_div_b_comp.cfg index 669735ad..aca803cc 100644 --- a/config/field/montreal_div_b_comp.cfg +++ b/config/field/montreal_div_b_comp.cfg @@ -1,5 +1,5 @@ [COMMUNICATION] referee_address = 224.5.23.1 -referee_port=10023 +referee_port=10003 vision_address = 224.5.23.2 vision_port=10006 \ No newline at end of file diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index 321edfd3..b371552c 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[1,2] +disabled_camera_id=[] From 69225e2a4cdf74e3d92c9e8d77b72e08d56da54f Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Mon, 18 Jun 2018 13:04:42 -0400 Subject: [PATCH 23/58] dont know what im doing take 2 --- .../receiver/receiver_base_class.py | 1 - .../Communication/sender/sender_base_class.py | 1 - Engine/Framework.py | 11 ++++++++- Engine/engine.py | 10 +------- ai/coach.py | 5 +--- config/config.py | 11 --------- main.py | 23 ++++++++++++++----- 7 files changed, 29 insertions(+), 33 deletions(-) diff --git a/Engine/Communication/receiver/receiver_base_class.py b/Engine/Communication/receiver/receiver_base_class.py index 394df227..de499aeb 100644 --- a/Engine/Communication/receiver/receiver_base_class.py +++ b/Engine/Communication/receiver/receiver_base_class.py @@ -46,7 +46,6 @@ def run(self): pass except: self.logger.exception('An error occurred.') - raise finally: self.connection.close() self.logger.debug('Terminated') diff --git a/Engine/Communication/sender/sender_base_class.py b/Engine/Communication/sender/sender_base_class.py index 54374a1b..a4cdb4f4 100644 --- a/Engine/Communication/sender/sender_base_class.py +++ b/Engine/Communication/sender/sender_base_class.py @@ -43,7 +43,6 @@ def run(self): pass except: self.logger.exception('An error occurred.') - raise finally: self.connection.close() self.logger.debug('Terminated') diff --git a/Engine/Framework.py b/Engine/Framework.py index c6c836f4..46965b83 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -57,6 +57,15 @@ def start(self): def stop_game(self): self.logger.debug('Game stopped.') + self.coach.join() + self.coach_watchdog.close() + self.engine.vision_state.close() self.engine.join(timeout=1) - self.coach.join(timeout=1) + self.engine.ui_sender.join(timeout=1) + self.engine.ui_recver.join(timeout=1) + self.engine.referee_recver.join(timeout=1) + self.game_state.close() + self.field.close() + self.engine_watchdog.close() + #self.engine.join(timeout=1) sys.exit() diff --git a/Engine/engine.py b/Engine/engine.py index cf28d737..3a0ac51f 100644 --- a/Engine/engine.py +++ b/Engine/engine.py @@ -116,6 +116,7 @@ def run(self): self.logger.exception('An error occurred.') finally: self.dump_profiling_stats() + self.logger.debug('Terminated') def wait_for_vision(self): self.logger.debug('Waiting for vision frame from the VisionReceiver...') @@ -130,7 +131,6 @@ def update_time(self): def main_loop(self): engine_cmds = self.get_engine_commands() - sleep(5) game_state = self.tracker.update() self.game_state.update(game_state) @@ -171,11 +171,3 @@ def is_alive(self): self.ui_recver.is_alive(), self.referee_recver.is_alive())) return borked_process_not_found and super().is_alive() - - def join(self, timeout=None): - self.vision_receiver.connection.close() - self.ui_sender.connection.close() - self.ui_recver.connection.close() - self.referee_recver.connection.close() - super().join(timeout=timeout) - self.logger.debug('Terminated') diff --git a/ai/coach.py b/ai/coach.py index baca779d..a395d3d9 100644 --- a/ai/coach.py +++ b/ai/coach.py @@ -111,6 +111,7 @@ def run(self): self.logger.exception('An error occurred.') finally: self.dump_profiling_stats() + self.logger.info('Terminated') def main_loop(self): self.game_state.update(self.engine_game_state) @@ -137,7 +138,3 @@ def is_alive(self): self.logger.critical('Process is hanging. Shutting down.') return False return super().is_alive() - - def join(self, timeout=None): - super().join(timeout=timeout) - self.logger.info('Terminated') diff --git a/config/config.py b/config/config.py index 3c78fec5..3d2fc340 100644 --- a/config/config.py +++ b/config/config.py @@ -165,17 +165,6 @@ def load_parameters(self, cli_args): if cli_args.competition_mode: self._config['GAME']['is_autonomous_play_at_startup'] = True - file_formatter = logging.Formatter('(%(asctime)s) - [%(levelname)-5.5s] %(name)-22.22s: %(message)s') - file_handler = logging.FileHandler('./Logs/log_' + str(datetime.date.today()) + '_at_' - + str(datetime.datetime.now().hour) + 'h.log', 'a') - file_handler.setFormatter(file_formatter) - - console_formatter = logging.Formatter('[%(levelname)-5.5s] - %(name)-22.22s: %(message)s') - console_handler = logging.StreamHandler(stream=stdout) - console_handler.setFormatter(console_formatter) - - logging.basicConfig(level=logging.NOTSET, handlers=[file_handler, console_handler]) - self._config_was_set = False self.update_ports() self._config_was_set = True diff --git a/main.py b/main.py index 8c2f0096..92c97984 100644 --- a/main.py +++ b/main.py @@ -5,6 +5,8 @@ from time import sleep from sys import stdout +import datetime + from Engine.Framework import Framework from config.config import Config from Util.sysinfo import git_version @@ -64,6 +66,20 @@ def set_arg_parser(): logging.basicConfig(level=logging.NOTSET, handlers=[consoleHandler]) cli_args = set_arg_parser().parse_args() + + if not cli_args.competition_mode: + + file_formatter = logging.Formatter('(%(asctime)s) - [%(levelname)-5.5s] %(name)-22.22s: %(message)s') + file_handler = logging.FileHandler('./Logs/log_' + str(datetime.date.today()) + '_at_' + + str(datetime.datetime.now().hour) + 'h.log', 'a') + file_handler.setFormatter(file_formatter) + + console_formatter = logging.Formatter('[%(levelname)-5.5s] - %(name)-22.22s: %(message)s') + console_handler = logging.StreamHandler(stream=stdout) + console_handler.setFormatter(console_formatter) + + logging.basicConfig(level=logging.NOTSET, handlers=[file_handler]) + Config().load_file(cli_args.config_file) Config().load_parameters(cli_args) @@ -78,17 +94,12 @@ def set_arg_parser(): stop_framework = False while not stop_framework: try: - framework = Framework(profiling=cli_args.enable_profiling) - framework.start() - sleep(1) - framework.stop_game() + Framework(profiling=cli_args.enable_profiling).start() except SystemExit: logger.debug('Framework stopped.') except: logger.exception('An error occurred.') finally: - framework.stop_game() - if not cli_args.competition_mode: stop_framework = True else: From 79283e47c5f8298dced45023f3a712fab9124482 Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 13:28:35 -0400 Subject: [PATCH 24/58] ready to rock --- ai/STA/Strategy/test_passing.py | 2 +- ai/STA/Tactic/go_kick.py | 4 ++-- ai/STA/Tactic/reveive_pass.py | 18 +++++++++++------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index ce157a33..fd9703c7 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -114,7 +114,7 @@ def is_ready_to_kick(self, player): def ball_going_toward_player(self, player): role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'PositionForPass': + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': if self.game_state.ball.velocity.norm > 50: return np.dot(normalize(player.position - self.game_state.ball.position).array, normalize(self.game_state.ball.velocity).array) > 0.9 diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index d24693a5..ce28f857 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -59,7 +59,7 @@ def initialize(self): dist_from_ball = (self.player.position - self.game_state.ball_position).norm if self.is_able_to_grab_ball_directly(0.5) \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/100)): + and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.grab_ball if self._get_distance_from_ball() < KICK_DISTANCE: self.next_state = self.kick @@ -188,7 +188,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offs position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing - if velocity: + if velocity and self.game_state.ball.velocity.norm > 20: position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * np.dot(dir_ball_to_target.array, self.game_state.ball.velocity.array))) / velocity_offset diff --git a/ai/STA/Tactic/reveive_pass.py b/ai/STA/Tactic/reveive_pass.py index a8e565df..f87f18bf 100644 --- a/ai/STA/Tactic/reveive_pass.py +++ b/ai/STA/Tactic/reveive_pass.py @@ -15,7 +15,7 @@ from ai.STA.Tactic.tactic import Tactic from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState - +from Util.geometry import perpendicular GO_BEHIND_SPACING = 250 GRAB_BALL_SPACING = 100 @@ -34,7 +34,7 @@ def __init__(self, game_state: GameState, player: Player): def initialize(self): self.status_flag = Flags.WIP if self.is_ball_going_to_collide(): - if self.game_state.ball.velocity.norm < 100: + if self.game_state.ball.velocity.norm < 100 and False: self.next_state = self.grab_ball else: self.next_state = self.wait_for_ball @@ -54,7 +54,7 @@ def go_behind_ball(self): if self.is_ball_going_to_collide(threshold=0.95) \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/100)): - self.next_state = self.grab_ball + self.next_state = self.wait_for_ball else: self.next_state = self.go_behind_ball return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), @@ -75,20 +75,24 @@ def grab_ball(self): return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, end_speed=0, - ball_collision=False).addForceDribbler().build() + ball_collision=False).addChargeKicker().build() def wait_for_ball(self): + perp_vec = perpendicular(self.player.position - self.game_state.ball.position) + component_lateral = perp_vec * np.dot(perp_vec.array, normalize(self.game_state.ball.velocity).array) + small_segment_len = np.sqrt(1 - component_lateral.norm**2) + latteral_move = component_lateral * (self.player.position - self.game_state.ball.position).norm / small_segment_len if self._get_distance_from_ball() < HAS_BALL_DISTANCE: self.next_state = self.halt return self.halt() if not self.is_ball_going_to_collide(threshold=0.95): - self.next_state = self.go_behind_ball + self.next_state = self.wait_for_ball return CmdBuilder().build() orientation = (self.game_state.ball_position - self.player.position).angle - return CmdBuilder().addMoveTo(Pose(self.player.position, orientation), + return CmdBuilder().addMoveTo(Pose(self.player.position + latteral_move, orientation), cruise_speed=3, end_speed=0, - ball_collision=False).addForceDribbler().build() + ball_collision=False).addChargeKicker().build() def halt(self): if self.status_flag == Flags.INIT: From 29c15f8cef14c72a0bed27d6f9e0af6da6ca7345 Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 15:37:45 -0400 Subject: [PATCH 25/58] add receiver to other strategies --- ai/STA/Strategy/defense_wall.py | 59 ++++++++++++++++++++++++++++++++- ai/STA/Strategy/free_kick.py | 45 +++++++++++++++++++------ ai/STA/Strategy/offense.py | 32 +++++++++++++++++- 3 files changed, 123 insertions(+), 13 deletions(-) diff --git a/ai/STA/Strategy/defense_wall.py b/ai/STA/Strategy/defense_wall.py index 9c41218f..699655e6 100644 --- a/ai/STA/Strategy/defense_wall.py +++ b/ai/STA/Strategy/defense_wall.py @@ -2,10 +2,11 @@ from functools import partial from itertools import zip_longest, cycle +from Util.geometry import normalize from Util.role import Role from Util.position import Position from Util.pose import Pose - +import numpy as np from ai.Algorithm.evaluation_module import closest_players_to_point from ai.STA.Strategy.strategy import Strategy @@ -14,6 +15,7 @@ from ai.STA.Tactic.go_to_position import GoToPosition from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass +from ai.STA.Tactic.reveive_pass import ReceivePass from ai.STA.Tactic.stop import Stop from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState @@ -54,12 +56,19 @@ def __init__(self, game_state: GameState, can_kick=True, multiple_cover=True, st robots_in_formation=self.attackers, auto_position=True)) node_go_kick = self.create_node(role, GoKick(self.game_state, player, target=their_goal)) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) attacker_should_go_kick = partial(self.should_go_kick, player) attacker_should_not_go_kick = partial(self.should_not_go_kick, player) attacker_has_kicked = partial(self.has_kicked, role) + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) node_position_pass.connect_to(node_go_kick, when=attacker_should_go_kick) + node_position_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_wait_for_pass.connect_to(node_position_pass, when=player_is_not_receiving_pass) node_go_kick.connect_to(node_position_pass, when=attacker_should_not_go_kick) node_go_kick.connect_to(node_go_kick, when=attacker_has_kicked) elif role in self.cover_role: @@ -75,10 +84,25 @@ def __init__(self, game_state: GameState, can_kick=True, multiple_cover=True, st player, robots_in_formation=self.robots_in_cover_formation, auto_position=True)) + + node_go_kick = self.create_node(role, GoKick(self.game_state, player, target=their_goal)) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) + + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) + player_has_kicked = partial(self.has_kicked, role) + + + node_align_to_covered_object.connect_to(node_position_pass, when=self.game_state.field.is_ball_in_our_goal_area) node_position_pass.connect_to(node_align_to_covered_object, when=self.game_state.field.is_ball_outside_our_goal_area) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_wait_for_pass.connect_to(node_align_to_covered_object, when=player_is_not_receiving_pass) + node_position_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_go_kick.connect_to(node_align_to_covered_object, when=player_has_kicked) else: node_align_to_defense_wall = \ self.create_node(role, AlignToDefenseWall(self.game_state, @@ -91,9 +115,23 @@ def __init__(self, game_state: GameState, can_kick=True, multiple_cover=True, st robots_in_formation=self.robots_in_wall_formation, auto_position=True)) + node_go_kick = self.create_node(role, GoKick(self.game_state, player, target=their_goal)) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) + + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) + player_has_kicked = partial(self.has_kicked, role) + node_align_to_defense_wall.connect_to(node_position_pass, when=self.game_state.field.is_ball_in_our_goal_area) node_position_pass.connect_to(node_align_to_defense_wall, when=self.game_state.field.is_ball_outside_our_goal_area) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_go_kick.connect_to(node_align_to_defense_wall, when=player_has_kicked) + node_position_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_position_pass.connect_to(node_align_to_defense_wall, when=player_is_not_receiving_pass) + + @classmethod def required_roles(cls): return [Role.GOALKEEPER, @@ -177,3 +215,22 @@ def _generate_cover_to_coveree_mapping(self): cover_to_formation = {cover: [cover] for cover in self.robots_in_cover_formation} return cover_to_coveree, cover_to_formation + + + def ball_going_toward_player(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.velocity.norm > 50: + return np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array) > 0.9 + return False + + def ball_not_going_toward_player(self, player): + return not self.ball_going_toward_player(player) + + def has_received(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'ReceivePass': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False \ No newline at end of file diff --git a/ai/STA/Strategy/free_kick.py b/ai/STA/Strategy/free_kick.py index 493a3e62..3de8add0 100644 --- a/ai/STA/Strategy/free_kick.py +++ b/ai/STA/Strategy/free_kick.py @@ -1,18 +1,20 @@ # Under MIT License, see LICENSE.txt from functools import partial +from math import acos -from Util.pose import Position, Pose +from Util.geometry import normalize from Util.role import Role -from ai.Algorithm.evaluation_module import closest_player_to_point, closest_players_to_point +from ai.Algorithm.evaluation_module import closest_players_to_point from ai.STA.Strategy.strategy import Strategy from ai.STA.Tactic.go_kick import GoKick from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.rotate_around_ball import RotateAroundBall +from ai.STA.Tactic.reveive_pass import ReceivePass from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState +import numpy as np # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic @@ -34,23 +36,25 @@ def __init__(self, p_game_state, can_kick_in_goal): auto_position=True, forbidden_areas=[self.game_state.field.free_kick_avoid_area, self.game_state.field.our_goal_forbidden_area])) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) initial_position_for_pass_center[role] = node_pass.tactic.area.center # Hack node_go_kick = self.create_node(role, GoKick(self.game_state, player, auto_update_target=True, can_kick_in_goal=can_kick_in_goal)) - node_rotate_around_ball = self.create_node(role, RotateAroundBall(self.game_state, player, p_game_state.field.their_goal_pose)) - - player_is_closest = partial(self.is_closest_not_goalkeeper, player) player_is_not_closest = partial(self.is_not_closest, player) player_has_kicked = partial(self.has_kicked, player) - player_is_ready_to_kick = partial(self.is_ready_to_kick, player) + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) + player_is_closest = partial(self.is_closest_not_goalkeeper, player) - node_pass.connect_to(node_rotate_around_ball, when=player_is_closest) - node_rotate_around_ball.connect_to(node_pass, when=player_is_not_closest) + node_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_pass.connect_to(node_go_kick, when=player_is_closest) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_wait_for_pass.connect_to(node_pass, when=player_is_not_receiving_pass) node_go_kick.connect_to(node_pass, when=player_is_not_closest) - node_rotate_around_ball.connect_to(node_go_kick, when=player_is_ready_to_kick) node_go_kick.connect_to(node_go_kick, when=player_has_kicked) # Find position for ball player closest to ball @@ -58,7 +62,8 @@ def __init__(self, p_game_state, can_kick_in_goal): ball_position = self.game_state.ball_position for r, position in initial_position_for_pass_center.items(): if self.closest_role is None \ - or (initial_position_for_pass_center[self.closest_role] - ball_position).norm > (position - ball_position).norm: + or (initial_position_for_pass_center[self.closest_role] - ball_position).norm > \ + (position - ball_position).norm: self.closest_role = r self.has_ball_move = False @@ -106,3 +111,21 @@ def is_ready_to_kick(self, player): return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS else: return False + + def ball_going_toward_player(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.velocity.norm > 50: + return np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array) > 0.9 + return False + + def ball_not_going_toward_player(self, player): + return not self.ball_going_toward_player(player) + + def has_received(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'ReceivePass': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False \ No newline at end of file diff --git a/ai/STA/Strategy/offense.py b/ai/STA/Strategy/offense.py index bffa5a2c..246d393d 100644 --- a/ai/STA/Strategy/offense.py +++ b/ai/STA/Strategy/offense.py @@ -2,7 +2,7 @@ from functools import partial from Util.constant import KEEPOUT_DISTANCE_FROM_GOAL -from Util.geometry import Area +from Util.geometry import Area, normalize from Util.role import Role from ai.Algorithm.evaluation_module import closest_player_to_point, closest_players_to_point @@ -10,10 +10,15 @@ from ai.STA.Tactic.go_kick import GoKick from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass +from ai.STA.Tactic.reveive_pass import ReceivePass from ai.STA.Tactic.tactic_constants import Flags +import numpy as np # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic +from ai.states.game_state import GameState + + class Offense(Strategy): def __init__(self, p_game_state): super().__init__(p_game_state) @@ -31,15 +36,23 @@ def __init__(self, p_game_state): node_go_kick = self.create_node(role, GoKick(self.game_state, player, auto_update_target=True)) + node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) player_is_closest = partial(self.is_closest_not_goalkeeper, player) player_is_not_closest = partial(self.is_not_closest, player) player_has_kicked = partial(self.has_kicked, player) + player_is_receiving_pass = partial(self.ball_going_toward_player, player) + player_is_not_receiving_pass = partial(self.ball_not_going_toward_player, player) + player_has_received_ball = partial(self.has_received, player) node_pass.connect_to(node_go_kick, when=player_is_closest) + node_pass.connect_to(node_wait_for_pass, when=player_is_receiving_pass) + node_wait_for_pass.connect_to(node_go_kick, when=player_has_received_ball) + node_wait_for_pass.connect_to(node_pass, when=player_is_not_receiving_pass) node_go_kick.connect_to(node_pass, when=player_is_not_closest) node_go_kick.connect_to(node_go_kick, when=player_has_kicked) + @classmethod def required_roles(cls): return [Role.GOALKEEPER, @@ -69,3 +82,20 @@ def has_kicked(self, player): else: return False + def ball_going_toward_player(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.velocity.norm > 50: + return np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array) > 0.9 + return False + + def ball_not_going_toward_player(self, player): + return not self.ball_going_toward_player(player) + + def has_received(self, player): + role = GameState().get_role_by_player_id(player.id) + if self.roles_graph[role].current_tactic_name == 'ReceivePass': + return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS + else: + return False \ No newline at end of file From bf226e57a0c25f3b4e67fe15545f45cdfe98af59 Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Mon, 18 Jun 2018 16:14:00 -0400 Subject: [PATCH 26/58] I thibk I know what im doing? --- .../receiver/receiver_base_class.py | 2 +- .../receiver/uidebug_command_receiver.py | 5 ++- .../Communication/sender/sender_base_class.py | 2 +- Engine/Framework.py | 35 +++++++++---------- Engine/engine.py | 31 +++++++++------- ai/coach.py | 22 +++++++----- main.py | 6 ++-- 7 files changed, 58 insertions(+), 45 deletions(-) diff --git a/Engine/Communication/receiver/receiver_base_class.py b/Engine/Communication/receiver/receiver_base_class.py index de499aeb..8ebf416e 100644 --- a/Engine/Communication/receiver/receiver_base_class.py +++ b/Engine/Communication/receiver/receiver_base_class.py @@ -48,4 +48,4 @@ def run(self): self.logger.exception('An error occurred.') finally: self.connection.close() - self.logger.debug('Terminated') + self.logger.debug('Closed.') diff --git a/Engine/Communication/receiver/uidebug_command_receiver.py b/Engine/Communication/receiver/uidebug_command_receiver.py index de696301..e0c142f8 100644 --- a/Engine/Communication/receiver/uidebug_command_receiver.py +++ b/Engine/Communication/receiver/uidebug_command_receiver.py @@ -4,7 +4,8 @@ from pickle import loads from queue import Full -from socket import socket, AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_ADD_MEMBERSHIP, inet_aton, INADDR_ANY +from socket import socket, AF_INET, SOCK_DGRAM, IPPROTO_IP, IP_ADD_MEMBERSHIP, inet_aton, INADDR_ANY, SOL_SOCKET, \ + SO_REUSEADDR from struct import pack from Engine.Communication.receiver.receiver_base_class import ReceiverProcess @@ -16,12 +17,14 @@ class UIDebugCommandReceiver(ReceiverProcess): def connect(self, connection_info): connection = socket(AF_INET, SOCK_DGRAM) + connection.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) connection.bind(connection_info) if ip_address(connection_info[0]).is_multicast: connection.setsockopt(IPPROTO_IP, IP_ADD_MEMBERSHIP, pack("=4sl", inet_aton(connection_info[0]), INADDR_ANY)) + return connection def receive_packet(self): diff --git a/Engine/Communication/sender/sender_base_class.py b/Engine/Communication/sender/sender_base_class.py index a4cdb4f4..6445aff4 100644 --- a/Engine/Communication/sender/sender_base_class.py +++ b/Engine/Communication/sender/sender_base_class.py @@ -45,4 +45,4 @@ def run(self): self.logger.exception('An error occurred.') finally: self.connection.close() - self.logger.debug('Terminated') + self.logger.debug('Closed.') diff --git a/Engine/Framework.py b/Engine/Framework.py index 46965b83..c117c7cc 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -1,9 +1,11 @@ # Under MIT License, see LICENSE.txt import logging +import os +import signal from multiprocessing import Queue, Manager import sys -from time import time +import time from Engine.engine import Engine from ai.coach import Coach @@ -29,10 +31,9 @@ def __init__(self, profiling=False): self.ui_send_queue = Queue(maxsize=Framework.QUEUE_SIZE) self.ui_recv_queue = Queue(maxsize=Framework.QUEUE_SIZE) - self.engine_watchdog = Manager().Value('f', time()) + self.engine_watchdog = Manager().Value('f', time.time()) self.engine = Engine(self) - - self.coach_watchdog = Manager().Value('f', time()) + self.coach_watchdog = Manager().Value('f', time.time()) self.coach = Coach(self) def start(self): @@ -47,25 +48,23 @@ def start(self): sleep() except SystemExit: - self.logger.debug('Terminated') + pass except KeyboardInterrupt: self.logger.debug('A keyboard interrupt was raise.') except BrokenPipeError: - self.logger.info('A connection was broken.') + self.logger.debug('A connection was broken.') except: self.logger.exception('An error occurred.') + finally: + self.stop_game() + def stop_game(self): - self.logger.debug('Game stopped.') - self.coach.join() - self.coach_watchdog.close() - self.engine.vision_state.close() - self.engine.join(timeout=1) - self.engine.ui_sender.join(timeout=1) - self.engine.ui_recver.join(timeout=1) - self.engine.referee_recver.join(timeout=1) - self.game_state.close() - self.field.close() - self.engine_watchdog.close() - #self.engine.join(timeout=1) + self.logger.critical('Framework stopped.') + + try: + os.kill(self.engine.pid, signal.SIGINT) # This will interrupt the coach as well. + except ProcessLookupError: + pass + sys.exit() diff --git a/Engine/engine.py b/Engine/engine.py index 3a0ac51f..5a3403e5 100644 --- a/Engine/engine.py +++ b/Engine/engine.py @@ -86,19 +86,21 @@ def start(self): def run(self): - logged_string = 'Running with process ID {}'.format(os.getpid()) - if self.is_fps_locked: - logged_string += ' at {} fps.'.format(self.fps) - else: - logged_string += ' without fps limitation.' + try: - self.logger.debug(logged_string) + logged_string = 'Running with process ID {}'.format(os.getpid()) + if self.is_fps_locked: + logged_string += ' at {} fps.'.format(self.fps) + else: + logged_string += ' without fps limitation.' + + self.logger.debug(logged_string) + + self.profiler = cProfile.Profile() + if self.framework.profiling: + self.profiler.enable() - self.profiler = cProfile.Profile() - if self.framework.profiling: - self.profiler.enable() - try: self.wait_for_vision() self.last_time = time() while True: @@ -109,14 +111,13 @@ def run(self): self.framework.engine_watchdog.value = time() except KeyboardInterrupt: - pass + self.logger.debug('Interrupted.') except BrokenPipeError: self.logger.exception('A connection was broken.') except: self.logger.exception('An error occurred.') finally: - self.dump_profiling_stats() - self.logger.debug('Terminated') + self.stop() def wait_for_vision(self): self.logger.debug('Waiting for vision frame from the VisionReceiver...') @@ -171,3 +172,7 @@ def is_alive(self): self.ui_recver.is_alive(), self.referee_recver.is_alive())) return borked_process_not_found and super().is_alive() + + def stop(self): + self.dump_profiling_stats() + self.logger.debug('Stopped.') diff --git a/ai/coach.py b/ai/coach.py index a395d3d9..43cdca63 100644 --- a/ai/coach.py +++ b/ai/coach.py @@ -86,14 +86,15 @@ def wait_for_referee(self): def run(self): - self.logger.debug('Running with process ID {} at {} fps.'.format(os.getpid(), self.fps)) + try: - # profiling - self.profiler = cProfile.Profile() - if self.framework.profiling: - self.profiler.enable() + self.logger.debug('Running with process ID {} at {} fps.'.format(os.getpid(), self.fps)) + + # profiling + self.profiler = cProfile.Profile() + if self.framework.profiling: + self.profiler.enable() - try: self.wait_for_geometry() self.wait_for_referee() while True: @@ -104,14 +105,13 @@ def run(self): self.framework.coach_watchdog.value = time() except KeyboardInterrupt: - pass + self.logger.debug('Interrupted.') except BrokenPipeError: self.logger.exception('A connection was broken.') except: self.logger.exception('An error occurred.') finally: - self.dump_profiling_stats() - self.logger.info('Terminated') + self.stop() def main_loop(self): self.game_state.update(self.engine_game_state) @@ -138,3 +138,7 @@ def is_alive(self): self.logger.critical('Process is hanging. Shutting down.') return False return super().is_alive() + + def stop(self): + self.dump_profiling_stats() + self.logger.info('Stopped.') diff --git a/main.py b/main.py index 92c97984..73cffb8c 100644 --- a/main.py +++ b/main.py @@ -67,7 +67,7 @@ def set_arg_parser(): cli_args = set_arg_parser().parse_args() - if not cli_args.competition_mode: + if cli_args.competition_mode: file_formatter = logging.Formatter('(%(asctime)s) - [%(levelname)-5.5s] %(name)-22.22s: %(message)s') file_handler = logging.FileHandler('./Logs/log_' + str(datetime.date.today()) + '_at_' @@ -78,7 +78,7 @@ def set_arg_parser(): console_handler = logging.StreamHandler(stream=stdout) console_handler.setFormatter(console_formatter) - logging.basicConfig(level=logging.NOTSET, handlers=[file_handler]) + logging.basicConfig(level=logging.NOTSET, handlers=[console_handler, file_handler]) Config().load_file(cli_args.config_file) Config().load_parameters(cli_args) @@ -97,6 +97,8 @@ def set_arg_parser(): Framework(profiling=cli_args.enable_profiling).start() except SystemExit: logger.debug('Framework stopped.') + except KeyboardInterrupt: + logger.debug('Interrupted.') except: logger.exception('An error occurred.') finally: From b0a6790e3c8ba5599ce13dcf88c93438888181e1 Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Mon, 18 Jun 2018 16:43:58 -0400 Subject: [PATCH 27/58] fix the log in file --- Engine/Framework.py | 4 ++-- Logs/dummy_file | 0 main.py | 38 +++++++++++++++++++------------------- 3 files changed, 21 insertions(+), 21 deletions(-) create mode 100644 Logs/dummy_file diff --git a/Engine/Framework.py b/Engine/Framework.py index c117c7cc..b9f2cdf2 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -50,9 +50,9 @@ def start(self): except SystemExit: pass except KeyboardInterrupt: - self.logger.debug('A keyboard interrupt was raise.') + self.logger.debug('Interrupted.') except BrokenPipeError: - self.logger.debug('A connection was broken.') + self.logger.exception('A connection was broken.') except: self.logger.exception('An error occurred.') finally: diff --git a/Logs/dummy_file b/Logs/dummy_file new file mode 100644 index 00000000..e69de29b diff --git a/main.py b/main.py index 73cffb8c..346c6324 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,22 @@ from Util.sysinfo import git_version +def set_logging_config(competition_mode): + console_formatter = logging.Formatter('[%(levelname)-5.5s] - %(name)-22.22s: %(message)s') + console_handler = logging.StreamHandler(stream=stdout) + console_handler.setFormatter(console_formatter) + handlers = [console_handler] + + if competition_mode: + file_formatter = logging.Formatter('(%(asctime)s) - [%(levelname)-5.5s] %(name)-22.22s: %(message)s') + file_handler = logging.FileHandler('./Logs/log_' + str(datetime.date.today()) + '_at_' + + str(datetime.datetime.now().hour) + 'h.log', 'a') + file_handler.setFormatter(file_formatter) + handlers.append(file_handler) + + logging.basicConfig(level=logging.NOTSET, handlers=handlers) + + def set_arg_parser(): prog_desc = 'Artificial intelligent and Engine software for the ULtron team in the RoboCup SSL.' arg_parser = argparse.ArgumentParser(prog='ULtron\'s AI of the RoboCup ULaval group.', description=prog_desc) @@ -59,32 +75,16 @@ def set_arg_parser(): if __name__ == '__main__': - consoleFormatter = logging.Formatter('[%(levelname)-5.5s] - %(name)-22.22s: %(message)s') - consoleHandler = logging.StreamHandler(stream=stdout) - consoleHandler.setFormatter(consoleFormatter) - - logging.basicConfig(level=logging.NOTSET, handlers=[consoleHandler]) cli_args = set_arg_parser().parse_args() - if cli_args.competition_mode: + set_logging_config(cli_args.competition_mode) - file_formatter = logging.Formatter('(%(asctime)s) - [%(levelname)-5.5s] %(name)-22.22s: %(message)s') - file_handler = logging.FileHandler('./Logs/log_' + str(datetime.date.today()) + '_at_' - + str(datetime.datetime.now().hour) + 'h.log', 'a') - file_handler.setFormatter(file_formatter) - - console_formatter = logging.Formatter('[%(levelname)-5.5s] - %(name)-22.22s: %(message)s') - console_handler = logging.StreamHandler(stream=stdout) - console_handler.setFormatter(console_formatter) - - logging.basicConfig(level=logging.NOTSET, handlers=[console_handler, file_handler]) + logger = logging.getLogger('Main') Config().load_file(cli_args.config_file) Config().load_parameters(cli_args) - logger = logging.getLogger('Main') - logger.info('Color: {}, Field side: {}, Mode: {}'.format(Config()['GAME']['our_color'].upper(), 'NEGATIVE' if Config()['GAME']['on_negative_side'] else 'POSITIVE', 'COMPETITION' if cli_args.competition_mode else 'NORMAL')) @@ -106,4 +106,4 @@ def set_arg_parser(): stop_framework = True else: logger.debug('Restarting Framework.') - sleep(1) + sleep(1) From f977580e6e971841e48eb866d6afa8ffedb9e402 Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 17:23:29 -0400 Subject: [PATCH 28/58] Update field limit in free kick --- ai/GameDomainObjects/field.py | 22 ++++++++++++++++++++++ ai/STA/Strategy/defense_wall.py | 2 +- ai/STA/Strategy/free_kick.py | 23 +++++++++++++++-------- ai/STA/Strategy/offense.py | 2 +- ai/STA/Strategy/test_passing.py | 2 +- ai/STA/Tactic/tactic.py | 23 ++--------------------- 6 files changed, 42 insertions(+), 32 deletions(-) diff --git a/ai/GameDomainObjects/field.py b/ai/GameDomainObjects/field.py index 64c96491..86667b23 100644 --- a/ai/GameDomainObjects/field.py +++ b/ai/GameDomainObjects/field.py @@ -214,6 +214,28 @@ def __contains__(self, item: Union[Pose, Position]): return self.left <= item.x <= self.right and \ self.bottom <= item.y <= self.top + # FIXME MONTREAL + @property + def border_limits(self): + + top_area = Area.from_limits(self.top + 100 * self.boundary_width, + self.top + self.boundary_width, + self.right + 100 * self.boundary_width, + self.left - 100 * self.boundary_width) + bottom_area = Area.from_limits(self.bottom - self.boundary_width, + self.bottom - 100 * self.boundary_width, + self.right + 100 * self.boundary_width, + self.left - 100 * self.boundary_width) + right_area = Area.from_limits(self.top + 100 * self.boundary_width, + self.bottom - 100 * self.boundary_width, + self.right + 100 * self.boundary_width, + self.right + self.boundary_width) + left_area = Area.from_limits(self.top + 100 * self.boundary_width, + self.bottom - 100 * self.boundary_width, + self.left - self.boundary_width, + self.left - 100 * self.boundary_width) + return [top_area, bottom_area, right_area, left_area] + @property def top(self): return self.field_width / 2 diff --git a/ai/STA/Strategy/defense_wall.py b/ai/STA/Strategy/defense_wall.py index 699655e6..44f620d9 100644 --- a/ai/STA/Strategy/defense_wall.py +++ b/ai/STA/Strategy/defense_wall.py @@ -15,7 +15,7 @@ from ai.STA.Tactic.go_to_position import GoToPosition from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.reveive_pass import ReceivePass +from ai.STA.Tactic.receive_pass import ReceivePass from ai.STA.Tactic.stop import Stop from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState diff --git a/ai/STA/Strategy/free_kick.py b/ai/STA/Strategy/free_kick.py index a173661c..01a18411 100644 --- a/ai/STA/Strategy/free_kick.py +++ b/ai/STA/Strategy/free_kick.py @@ -11,7 +11,7 @@ from ai.STA.Tactic.go_kick import GoKick from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.reveive_pass import ReceivePass +from ai.STA.Tactic.receive_pass import ReceivePass from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState import numpy as np @@ -25,23 +25,30 @@ def __init__(self, p_game_state, can_kick_in_goal): formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] + forbidden_areas = [self.game_state.field.free_kick_avoid_area, + self.game_state.field.our_goal_forbidden_area] + initial_position_for_pass_center = {} for role, player in self.assigned_roles.items(): if role == Role.GOALKEEPER: self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) else: - node_pass = self.create_node(role, PositionForPass(self.game_state, - player, - robots_in_formation=formation, - auto_position=True, - forbidden_areas=[self.game_state.field.free_kick_avoid_area, - self.game_state.field.our_goal_forbidden_area])) + node_pass = self.create_node(role, + PositionForPass(self.game_state, + player, + robots_in_formation=formation, + auto_position=True, + forbidden_areas=self.game_state.field.border_limits + + forbidden_areas)) node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) initial_position_for_pass_center[role] = node_pass.tactic.area.center # Hack node_go_kick = self.create_node(role, GoKick(self.game_state, player, auto_update_target=True, - can_kick_in_goal=can_kick_in_goal)) + can_kick_in_goal=can_kick_in_goal, + forbidden_areas=self.game_state.field.border_limits + + forbidden_areas + )) player_is_not_closest = partial(self.is_not_closest, player) player_has_kicked = partial(self.has_kicked, player) diff --git a/ai/STA/Strategy/offense.py b/ai/STA/Strategy/offense.py index 246d393d..b542d39d 100644 --- a/ai/STA/Strategy/offense.py +++ b/ai/STA/Strategy/offense.py @@ -10,7 +10,7 @@ from ai.STA.Tactic.go_kick import GoKick from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.reveive_pass import ReceivePass +from ai.STA.Tactic.receive_pass import ReceivePass from ai.STA.Tactic.tactic_constants import Flags import numpy as np diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index fd9703c7..fe9aedb9 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -11,7 +11,7 @@ from ai.STA.Tactic.go_kick import GoKick from ai.STA.Tactic.goalkeeper import GoalKeeper from ai.STA.Tactic.position_for_pass import PositionForPass -from ai.STA.Tactic.reveive_pass import ReceivePass +from ai.STA.Tactic.receive_pass import ReceivePass from ai.STA.Tactic.tactic_constants import Flags from ai.states.game_state import GameState import numpy as np diff --git a/ai/STA/Tactic/tactic.py b/ai/STA/Tactic/tactic.py index 55f08def..e529c770 100644 --- a/ai/STA/Tactic/tactic.py +++ b/ai/STA/Tactic/tactic.py @@ -40,28 +40,9 @@ def __init__(self, game_state: GameState, player: Player, target: Optional[Pose] if forbidden_areas is None: field = self.game_state.field - top_area = Area.from_limits(field.top + 100 * field.boundary_width, - field.top + field.boundary_width, - field.right, - field.left) - bottom_area = Area.from_limits(field.bottom - field.boundary_width, - field.bottom - 100 * field.boundary_width, - field.right, - field.left) - right_area = Area.from_limits(field.top, - field.bottom, - field.right + 100 * field.boundary_width, - field.right + field.boundary_width) - left_area = Area.from_limits(field.top, - field.bottom, - field.left - field.boundary_width, - field.left - 100 * field.boundary_width) # Those limits are for ulaval local only - areas = [ - top_area, - bottom_area, - right_area, - left_area, + areas = field.border_limits + areas += [ self.field.behind_our_goal_line, self.field.behind_their_goal_line] #areas = [] From ec8c141f77039de07a67924669e1ba4a55efcab5 Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 17:29:52 -0400 Subject: [PATCH 29/58] fix ports --- config/field/sim.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/field/sim.cfg b/config/field/sim.cfg index 346da38c..254f0cc1 100644 --- a/config/field/sim.cfg +++ b/config/field/sim.cfg @@ -1,5 +1,5 @@ [COMMUNICATION] referee_address = 224.5.23.1 -referee_port=10003 +referee_port=10023 vision_address = 224.5.23.2 -vision_port=10228 \ No newline at end of file +vision_port=10227 \ No newline at end of file From 55e095f0be945f690d59fde5a8becec0e0c72ada Mon Sep 17 00:00:00 2001 From: philippe Date: Mon, 18 Jun 2018 18:02:28 -0400 Subject: [PATCH 30/58] Before game against RoboJacket --- Engine/regulators/velocity_regulators.py | 2 +- ai/STA/Tactic/go_kick.py | 5 ++--- config/field/montreal_div_b_comp.cfg | 4 ++-- config/montreal_div_b_comp.cfg | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index ef32eee4..a76238e7 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -13,7 +13,7 @@ class RealVelocityController(RegulatorBaseClass): settings = {'kp': 10, 'ki': 0, 'kd': 1} - v_d = 10 # lower = bigger path correction + v_d = 100 # lower = bigger path correction emergency_break_constant = 0.4 # Higher = higher correction of trajectory emergency_break_safety_factor = 1 # lower = bigger break distance diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index ce28f857..88c65611 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -32,7 +32,7 @@ class GoKick(Tactic): def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), args: List[str]=None, - kick_force: KickForce=KickForce.MEDIUM, + kick_force: KickForce=KickForce.HIGH, auto_update_target=False, go_behind_distance=GRAB_BALL_SPACING*3, forbidden_areas=None, @@ -108,7 +108,6 @@ def grab_ball(self): end_speed=0, ball_collision=False)\ .addForceDribbler()\ - .addChargeKicker()\ .addKick(self.kick_force)\ .build() @@ -188,7 +187,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offs position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing - if velocity and self.game_state.ball.velocity.norm > 20: + if velocity and self.game_state.ball.velocity.norm > 20 and False: position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * np.dot(dir_ball_to_target.array, self.game_state.ball.velocity.array))) / velocity_offset diff --git a/config/field/montreal_div_b_comp.cfg b/config/field/montreal_div_b_comp.cfg index aca803cc..27447b4f 100644 --- a/config/field/montreal_div_b_comp.cfg +++ b/config/field/montreal_div_b_comp.cfg @@ -1,5 +1,5 @@ [COMMUNICATION] referee_address = 224.5.23.1 -referee_port=10003 +referee_port=10023 vision_address = 224.5.23.2 -vision_port=10006 \ No newline at end of file +vision_port=10003 \ No newline at end of file diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index b371552c..f6391bb1 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[] +disabled_camera_id=[1, 2] From 155f4126b61c52fdd3debe043dc9b829241228bf Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Tue, 19 Jun 2018 12:39:16 -0400 Subject: [PATCH 31/58] Fix tests --- ai/STA/Tactic/receive_pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index f87f18bf..8172e48f 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -25,7 +25,7 @@ # noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class ReceivePass(Tactic): - def __init__(self, game_state: GameState, player: Player): + def __init__(self, game_state: GameState, player: Player, target): super().__init__(game_state, player) self.current_state = self.initialize From 650b7370e8bb74818976f6ffb89be2502444c1e2 Mon Sep 17 00:00:00 2001 From: philippe Date: Tue, 19 Jun 2018 13:39:13 -0400 Subject: [PATCH 32/58] more robust --- Engine/robot.py | 4 ++-- ai/STA/Tactic/go_kick.py | 31 ++++++++++++++++++++-------- ai/STA/Tactic/receive_pass.py | 2 +- ai/STA/Tactic/tactic_book.py | 4 +++- ai/executors/pathfinder_module.py | 2 +- config/field/montreal_div_b_comp.cfg | 2 +- config/montreal_div_b_comp.cfg | 2 +- 7 files changed, 31 insertions(+), 16 deletions(-) diff --git a/Engine/robot.py b/Engine/robot.py index 10ee5fc9..9cbab9f5 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -4,8 +4,8 @@ from Util.geometry import wrap_to_pi MAX_LINEAR_SPEED = 4000 # mm/s -MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 -MAX_ANGULAR_SPEED = 20 # rad/s +MAX_LINEAR_ACCELERATION = 4000 # mm/s^2 +MAX_ANGULAR_SPEED = 70 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 88c65611..502a813e 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -20,7 +20,7 @@ TARGET_ASSIGNATION_DELAY = 1.0 GO_BEHIND_SPACING = 250 -GRAB_BALL_SPACING = 100 +GRAB_BALL_SPACING = 120 APPROACH_SPEED = 100 KICK_DISTANCE = 130 KICK_SUCCEED_THRESHOLD = 300 @@ -38,7 +38,7 @@ def __init__(self, game_state: GameState, player: Player, forbidden_areas=None, can_kick_in_goal=True): - super().__init__(game_state, player, target, args=args, forbidden_areas=forbidden_areas) + super().__init__(game_state, player, target, args=args, forbidden_areas=[]) self.current_state = self.initialize self.next_state = self.initialize self.kick_last_time = time.time() @@ -76,19 +76,25 @@ def go_behind_ball(self): orientation = (self.target.position - self.game_state.ball_position).angle ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) - effective_ball_spacing = GRAB_BALL_SPACING * 3 * ball_speed_modifier + angle_behind =self.get_alligment_with_ball_and_target() + if angle_behind > 30: + effective_ball_spacing = GRAB_BALL_SPACING * min(2, abs(angle_behind/30)) * ball_speed_modifier + collision_ball = True + else: + effective_ball_spacing = GRAB_BALL_SPACING + collision_ball = False distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm if self.is_able_to_grab_ball_directly(0.95) \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/100)): + and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.grab_ball else: self.next_state = self.go_behind_ball return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, end_speed=0, - ball_collision=True)\ + ball_collision=collision_ball)\ .addChargeKicker().build() def grab_ball(self): @@ -101,7 +107,7 @@ def grab_ball(self): self.next_state = self.kick self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm - orientation = (self.game_state.ball_position - self.player.position).angle + orientation = (self.target.position - self.game_state.ball_position).angle distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), cruise_speed=3, @@ -114,7 +120,7 @@ def grab_ball(self): def kick(self): if self.auto_update_target: self._find_best_passing_option() - if not self.is_able_to_grab_ball_directly(0.95): + if not self.is_able_to_grab_ball_directly(0.7): self.next_state = self.go_behind_ball return self.go_behind_ball() self.next_state = self.validate_kick @@ -178,7 +184,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=25) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=15) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ @@ -187,7 +193,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offs position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing - if velocity and self.game_state.ball.velocity.norm > 20 and False: + if velocity and self.game_state.ball.velocity.norm > 20: position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * np.dot(dir_ball_to_target.array, self.game_state.ball.velocity.array))) / velocity_offset @@ -200,3 +206,10 @@ def is_able_to_grab_ball_directly(self, threshold): alignement_behind = np.dot(vec_target_to_ball.array, (normalize(self.player.position - self.game_state.ball_position)).array) return threshold < alignement_behind + + def get_alligment_with_ball_and_target(self): + + vec_target_to_ball = normalize(self.game_state.ball.position - self.target.position) + alignement_behind = np.dot(vec_target_to_ball.array, + (normalize(self.player.position - self.game_state.ball_position)).array) + return np.arccos(alignement_behind) * 180 / np.pi \ No newline at end of file diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index f87f18bf..aa003c69 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -25,7 +25,7 @@ # noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class ReceivePass(Tactic): - def __init__(self, game_state: GameState, player: Player): + def __init__(self, game_state: GameState, player: Player, target=None, args=None, fu=None): super().__init__(game_state, player) self.current_state = self.initialize diff --git a/ai/STA/Tactic/tactic_book.py b/ai/STA/Tactic/tactic_book.py index 9ba63332..0943ed99 100644 --- a/ai/STA/Tactic/tactic_book.py +++ b/ai/STA/Tactic/tactic_book.py @@ -11,6 +11,7 @@ from ai.STA.Tactic.face_target import FaceTarget from ai.STA.Tactic.pass_to_player import PassToPlayer from ai.STA.Tactic.demo_follow_robot import DemoFollowRobot +from ai.STA.Tactic.receive_pass import ReceivePass from ai.STA.Tactic.rotate_around_ball import RotateAroundBall from ai.STA.Tactic.stress_test_robot import StressTestRobotWaypoint, StressTestRobot from ai.STA.Tactic.tactic import Tactic @@ -33,7 +34,8 @@ def __init__(self): defaults_tactics = [GoToPosition, GoKick] - tactics = {PlaceBall, + tactics = {ReceivePass, + PlaceBall, FaceTarget, DemoFollowBall, DemoFollowRobot, diff --git a/ai/executors/pathfinder_module.py b/ai/executors/pathfinder_module.py index 3a3ef967..25e646fa 100644 --- a/ai/executors/pathfinder_module.py +++ b/ai/executors/pathfinder_module.py @@ -60,7 +60,7 @@ def player_optional_obstacles(self, ball_collision: bool) -> List[Obstacle]: if ball_collision and self.game_state.is_ball_on_field: path_obstacles.append(Obstacle(self.game_state.ball_position.array, - avoid_distance=MIN_DISTANCE_FROM_OBSTACLE)) + avoid_distance=100)) return path_obstacles diff --git a/config/field/montreal_div_b_comp.cfg b/config/field/montreal_div_b_comp.cfg index 27447b4f..669735ad 100644 --- a/config/field/montreal_div_b_comp.cfg +++ b/config/field/montreal_div_b_comp.cfg @@ -2,4 +2,4 @@ referee_address = 224.5.23.1 referee_port=10023 vision_address = 224.5.23.2 -vision_port=10003 \ No newline at end of file +vision_port=10006 \ No newline at end of file diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index f6391bb1..ab359e04 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[1, 2] +disabled_camera_id=[0, 3] From 45908573400e4d4392cfc80fe32f5e1f7f600f47 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Tue, 19 Jun 2018 13:41:44 -0400 Subject: [PATCH 33/58] Add visualization --- ai/STA/Tactic/go_kick.py | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 88c65611..2b6f3992 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -6,6 +6,7 @@ import numpy as np +from Debug.debug_command_factory import DebugCommandFactory, CYAN, RED from Util.constant import ROBOT_CENTER_TO_KICKER, BALL_RADIUS, KickForce from Util import Pose, Position from Util.ai_command import CmdBuilder, Idle @@ -27,7 +28,6 @@ COMMAND_DELAY = 0.5 -# noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class GoKick(Tactic): def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), @@ -200,3 +200,31 @@ def is_able_to_grab_ball_directly(self, threshold): alignement_behind = np.dot(vec_target_to_ball.array, (normalize(self.player.position - self.game_state.ball_position)).array) return threshold < alignement_behind + + def debug_cmd(self): + angle = None + additional_dbg = [] + if self.current_state == self.go_behind_ball: + angle = np.arccos(0.95) + elif self.current_state == self.grab_ball: + angle = np.arccos(0.95) + elif self.current_state == self.kick: + angle = np.arccos(0.95) + additional_dbg = [DebugCommandFactory.circle(self.game_state.ball_position, KICK_DISTANCE, color=RED)] + + if angle is not None: + base_angle = (self.game_state.ball.position - self.target.position).angle + magnitude = 3000 + ori = self.game_state.ball.position + upper = ori + Position.from_angle(base_angle + angle, magnitude) + lower = ori + Position.from_angle(base_angle - angle, magnitude) + upper_back = ori + Position.from_angle(base_angle + angle + np.pi, magnitude) + lower_back = ori + Position.from_angle(base_angle - angle + np.pi, magnitude) + ball_to_player = self.player.position - self.game_state.ball_position + behind_player = (ball_to_player.norm + 1000) * normalize(ball_to_player) + self.game_state.ball_position + return [DebugCommandFactory.line(ori, upper), + DebugCommandFactory.line(ori, lower), + DebugCommandFactory.line(ori, upper_back), + DebugCommandFactory.line(ori, lower_back), + DebugCommandFactory.line(self.game_state.ball_position, behind_player, color=CYAN)] + additional_dbg + return [] From dfcfacf9b6fefbc06ddfb72a0a3f4fe9160c7c96 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Tue, 19 Jun 2018 14:45:30 -0400 Subject: [PATCH 34/58] Rename --- ai/STA/Tactic/go_kick.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 610b74ea..7bb0c23d 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -76,7 +76,7 @@ def go_behind_ball(self): orientation = (self.target.position - self.game_state.ball_position).angle ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) - angle_behind =self.get_alligment_with_ball_and_target() + angle_behind = self.get_alignment_with_ball_and_target() if angle_behind > 30: effective_ball_spacing = GRAB_BALL_SPACING * min(2, abs(angle_behind/30)) * ball_speed_modifier collision_ball = True @@ -86,7 +86,7 @@ def go_behind_ball(self): distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.get_alligment_with_ball_and_target() < 18 \ + if self.get_alignment_with_ball_and_target() < 18 \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.grab_ball else: @@ -100,7 +100,7 @@ def go_behind_ball(self): def grab_ball(self): if self.auto_update_target: self._find_best_passing_option() - if self.get_alligment_with_ball_and_target() > 25: + if self.get_alignment_with_ball_and_target() > 25: self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: @@ -120,7 +120,7 @@ def grab_ball(self): def kick(self): if self.auto_update_target: self._find_best_passing_option() - if not self.get_alligment_with_ball_and_target() > 45: + if not self.get_alignment_with_ball_and_target() > 45: self.next_state = self.go_behind_ball return self.go_behind_ball() self.next_state = self.validate_kick @@ -207,7 +207,7 @@ def is_able_to_grab_ball_directly(self, threshold): (normalize(self.player.position - self.game_state.ball_position)).array) return threshold < alignement_behind - def get_alligment_with_ball_and_target(self): + def get_alignment_with_ball_and_target(self): vec_target_to_ball = normalize(self.game_state.ball.position - self.target.position) alignement_behind = np.dot(vec_target_to_ball.array, @@ -218,13 +218,14 @@ def debug_cmd(self): angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: - angle = np.arccos(0.95) + angle = 18 elif self.current_state == self.grab_ball: - angle = np.arccos(0.95) + angle = 25 elif self.current_state == self.kick: - angle = np.arccos(0.70) + angle = 45 additional_dbg = [DebugCommandFactory.circle(self.game_state.ball_position, KICK_DISTANCE, color=RED)] if angle is not None: + angle *= np.pi/180.0 base_angle = (self.game_state.ball.position - self.target.position).angle magnitude = 3000 ori = self.game_state.ball.position From 5e401c201d370c47d3990ee166170a6a4a5ba4b5 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Tue, 19 Jun 2018 15:00:01 -0400 Subject: [PATCH 35/58] WIP --- Engine/regulators/velocity_regulators.py | 2 +- Engine/robot.py | 2 +- ai/STA/Tactic/go_kick.py | 10 +++------- ai/STA/Tactic/receive_pass.py | 2 +- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index a76238e7..659ff5f9 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -78,7 +78,7 @@ class GrSimVelocityController(RealVelocityController): settings = {'kp': 2, 'ki': 0.3, 'kd': 0} v_d = 15 emergency_break_constant = 0 - emergency_break_safety_factor = 1 + emergency_break_safety_factor = 1 # lower = bigger break distance def is_time_to_break(robot, destination, cruise_speed, acceleration, target_speed): diff --git a/Engine/robot.py b/Engine/robot.py index 9cbab9f5..7f3a8158 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -4,7 +4,7 @@ from Util.geometry import wrap_to_pi MAX_LINEAR_SPEED = 4000 # mm/s -MAX_LINEAR_ACCELERATION = 4000 # mm/s^2 +MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 MAX_ANGULAR_SPEED = 70 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 7bb0c23d..baadf5c3 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -58,9 +58,9 @@ def initialize(self): dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.is_able_to_grab_ball_directly(0.5) \ + if self.get_alignment_with_ball_and_target() < 60 \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): - self.next_state = self.grab_ball + self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: self.next_state = self.kick @@ -120,7 +120,7 @@ def grab_ball(self): def kick(self): if self.auto_update_target: self._find_best_passing_option() - if not self.get_alignment_with_ball_and_target() > 45: + if self.get_alignment_with_ball_and_target() > 45: self.next_state = self.go_behind_ball return self.go_behind_ball() self.next_state = self.validate_kick @@ -231,13 +231,9 @@ def debug_cmd(self): ori = self.game_state.ball.position upper = ori + Position.from_angle(base_angle + angle, magnitude) lower = ori + Position.from_angle(base_angle - angle, magnitude) - upper_back = ori + Position.from_angle(base_angle + angle + np.pi, magnitude) - lower_back = ori + Position.from_angle(base_angle - angle + np.pi, magnitude) ball_to_player = self.player.position - self.game_state.ball_position behind_player = (ball_to_player.norm + 1000) * normalize(ball_to_player) + self.game_state.ball_position return [DebugCommandFactory.line(ori, upper), DebugCommandFactory.line(ori, lower), - DebugCommandFactory.line(ori, upper_back), - DebugCommandFactory.line(ori, lower_back), DebugCommandFactory.line(self.game_state.ball_position, behind_player, color=CYAN)] + additional_dbg return [] diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index 8172e48f..8a491a08 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -25,7 +25,7 @@ # noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class ReceivePass(Tactic): - def __init__(self, game_state: GameState, player: Player, target): + def __init__(self, game_state: GameState, player: Player, target=Position(0, 0)): super().__init__(game_state, player) self.current_state = self.initialize From 0cb5b65ccb56c5e1f43f588f9023ef9ab8e85763 Mon Sep 17 00:00:00 2001 From: philippe Date: Tue, 19 Jun 2018 16:02:36 -0400 Subject: [PATCH 36/58] before ais --- Engine/robot.py | 2 +- ai/STA/Tactic/go_kick.py | 19 +++++++++---------- config/montreal_div_b_comp.cfg | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/Engine/robot.py b/Engine/robot.py index 7f3a8158..9cbab9f5 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -4,7 +4,7 @@ from Util.geometry import wrap_to_pi MAX_LINEAR_SPEED = 4000 # mm/s -MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 +MAX_LINEAR_ACCELERATION = 4000 # mm/s^2 MAX_ANGULAR_SPEED = 70 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index baadf5c3..dfcb14a5 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -20,8 +20,8 @@ VALIDATE_KICK_DELAY = 0.5 TARGET_ASSIGNATION_DELAY = 1.0 -GO_BEHIND_SPACING = 250 -GRAB_BALL_SPACING = 120 +GO_BEHIND_SPACING = 180 +GRAB_BALL_SPACING = 100 APPROACH_SPEED = 100 KICK_DISTANCE = 130 KICK_SUCCEED_THRESHOLD = 300 @@ -77,16 +77,15 @@ def go_behind_ball(self): ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) angle_behind = self.get_alignment_with_ball_and_target() - if angle_behind > 30: - effective_ball_spacing = GRAB_BALL_SPACING * min(2, abs(angle_behind/30)) * ball_speed_modifier + if angle_behind > 35: + effective_ball_spacing = GO_BEHIND_SPACING * min(3, abs(angle_behind/30)) * ball_speed_modifier collision_ball = True else: - effective_ball_spacing = GRAB_BALL_SPACING + effective_ball_spacing = GO_BEHIND_SPACING collision_ball = False distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - - if self.get_alignment_with_ball_and_target() < 18 \ + if self.get_alignment_with_ball_and_target() < 25 \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.grab_ball else: @@ -100,7 +99,7 @@ def go_behind_ball(self): def grab_ball(self): if self.auto_update_target: self._find_best_passing_option() - if self.get_alignment_with_ball_and_target() > 25: + if self.get_alignment_with_ball_and_target() > 45: self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: @@ -184,7 +183,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=15) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=4) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ @@ -214,7 +213,7 @@ def get_alignment_with_ball_and_target(self): (normalize(self.player.position - self.game_state.ball_position)).array) return np.arccos(alignement_behind) * 180 / np.pi - def debug_cmd(self): + def debug_cmd_fuck(self): angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: diff --git a/config/montreal_div_b_comp.cfg b/config/montreal_div_b_comp.cfg index ab359e04..b371552c 100644 --- a/config/montreal_div_b_comp.cfg +++ b/config/montreal_div_b_comp.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[0, 3] +disabled_camera_id=[] From da8a466ced158701005bb36f072f4c1eaefe2292 Mon Sep 17 00:00:00 2001 From: philippe Date: Tue, 19 Jun 2018 19:29:43 -0400 Subject: [PATCH 37/58] Before Islander --- Engine/regulators/velocity_regulators.py | 2 +- Engine/tracker.py | 2 +- ai/STA/Strategy/test_passing.py | 6 +++--- ai/STA/Tactic/go_kick.py | 13 +++++++------ ai/executors/pathfinder_module.py | 2 +- config/field/montreal_div_b_comp.cfg | 2 +- 6 files changed, 14 insertions(+), 13 deletions(-) diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index 659ff5f9..c9eec879 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -13,7 +13,7 @@ class RealVelocityController(RegulatorBaseClass): settings = {'kp': 10, 'ki': 0, 'kd': 1} - v_d = 100 # lower = bigger path correction + v_d = 4 # lower = bigger path correction emergency_break_constant = 0.4 # Higher = higher correction of trajectory emergency_break_safety_factor = 1 # lower = bigger break distance diff --git a/Engine/tracker.py b/Engine/tracker.py index 661a1ac9..de624e3d 100644 --- a/Engine/tracker.py +++ b/Engine/tracker.py @@ -21,7 +21,7 @@ class Tracker: - MAX_BALLS_SEPARATION = 2000 + MAX_BALLS_SEPARATION = 1000 def __init__(self, vision_state: DictProxy, ui_send_queue: Queue): self.logger = logging.getLogger(self.__class__.__name__) diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index fe9aedb9..f277f14c 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -20,7 +20,7 @@ # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class TestPassing(Strategy): - def __init__(self, p_game_state, can_kick_in_goal=False): + def __init__(self, p_game_state, can_kick_in_goal=True): super().__init__(p_game_state) formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] @@ -71,13 +71,13 @@ def __init__(self, p_game_state, can_kick_in_goal=False): @classmethod def required_roles(cls): return [Role.GOALKEEPER, - Role.FIRST_ATTACK, + Role.FIRST_DEFENCE, Role.MIDDLE] @classmethod def optional_roles(cls): return [Role.SECOND_ATTACK, - Role.FIRST_DEFENCE, + Role.FIRST_ATTACK, Role.SECOND_DEFENCE] def is_closest_not_goalkeeper(self, player): diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index dfcb14a5..5b5721a3 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -21,9 +21,9 @@ TARGET_ASSIGNATION_DELAY = 1.0 GO_BEHIND_SPACING = 180 -GRAB_BALL_SPACING = 100 +GRAB_BALL_SPACING = 90 APPROACH_SPEED = 100 -KICK_DISTANCE = 130 +KICK_DISTANCE = 90 KICK_SUCCEED_THRESHOLD = 300 COMMAND_DELAY = 0.5 @@ -78,7 +78,7 @@ def go_behind_ball(self): ball_speed_modifier = (ball_speed/1000 + 1) angle_behind = self.get_alignment_with_ball_and_target() if angle_behind > 35: - effective_ball_spacing = GO_BEHIND_SPACING * min(3, abs(angle_behind/30)) * ball_speed_modifier + effective_ball_spacing = GO_BEHIND_SPACING * min(3, abs(angle_behind/45)) * ball_speed_modifier collision_ball = True else: effective_ball_spacing = GO_BEHIND_SPACING @@ -86,7 +86,7 @@ def go_behind_ball(self): distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm if self.get_alignment_with_ball_and_target() < 25 \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): + and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): self.next_state = self.grab_ball else: self.next_state = self.go_behind_ball @@ -94,7 +94,7 @@ def go_behind_ball(self): cruise_speed=3, end_speed=0, ball_collision=collision_ball)\ - .addChargeKicker().build() + .addChargeKicker().addKick(self.kick_force).build() def grab_ball(self): if self.auto_update_target: @@ -107,9 +107,10 @@ def grab_ball(self): self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm orientation = (self.target.position - self.game_state.ball_position).angle + spacing_offset = abs(1 - np.dot((self.player.position-self.target.position).array, (self.player.position-self.game_state.ball.position).array)) distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), - cruise_speed=3, + cruise_speed=1, end_speed=0, ball_collision=False)\ .addForceDribbler()\ diff --git a/ai/executors/pathfinder_module.py b/ai/executors/pathfinder_module.py index 25e646fa..4e5dfbfe 100644 --- a/ai/executors/pathfinder_module.py +++ b/ai/executors/pathfinder_module.py @@ -60,7 +60,7 @@ def player_optional_obstacles(self, ball_collision: bool) -> List[Obstacle]: if ball_collision and self.game_state.is_ball_on_field: path_obstacles.append(Obstacle(self.game_state.ball_position.array, - avoid_distance=100)) + avoid_distance=150)) return path_obstacles diff --git a/config/field/montreal_div_b_comp.cfg b/config/field/montreal_div_b_comp.cfg index 669735ad..aca803cc 100644 --- a/config/field/montreal_div_b_comp.cfg +++ b/config/field/montreal_div_b_comp.cfg @@ -1,5 +1,5 @@ [COMMUNICATION] referee_address = 224.5.23.1 -referee_port=10023 +referee_port=10003 vision_address = 224.5.23.2 vision_port=10006 \ No newline at end of file From d3f37143d50978a9b400f0764dee54f55d2325a6 Mon Sep 17 00:00:00 2001 From: philippe Date: Wed, 20 Jun 2018 05:20:51 -0400 Subject: [PATCH 38/58] Force kill engine --- Engine/Framework.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Engine/Framework.py b/Engine/Framework.py index b9f2cdf2..e11f66f5 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -58,13 +58,17 @@ def start(self): finally: self.stop_game() - def stop_game(self): self.logger.critical('Framework stopped.') try: - os.kill(self.engine.pid, signal.SIGINT) # This will interrupt the coach as well. + os.kill(self.engine.pid, signal.SIGINT) except ProcessLookupError: pass + try: + os.kill(self.coach.pid, signal.SIGINT) + except ProcessLookupError: + pass + sys.exit() From 58ee6e67b90d837fa06656aa6011da2ab1c45c68 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 20 Jun 2018 09:58:05 -0400 Subject: [PATCH 39/58] Make everything more a bit faster --- ai/STA/Strategy/smart_stop.py | 3 ++- ai/STA/Tactic/align_to_defense_wall.py | 6 ++++-- ai/STA/Tactic/leeroy_jenkins.py | 6 +++--- ai/STA/Tactic/position_for_pass.py | 6 ++++-- dual_launch.sh | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/ai/STA/Strategy/smart_stop.py b/ai/STA/Strategy/smart_stop.py index 5d348917..e601b27d 100644 --- a/ai/STA/Strategy/smart_stop.py +++ b/ai/STA/Strategy/smart_stop.py @@ -35,7 +35,8 @@ def __init__(self, p_game_state): player, robots_in_formation=formation_defender, object_to_block=self.game_state.ball, - stay_away_from_ball=True)) + stay_away_from_ball=True, + cruise_speed=1)) else: self.create_node(role, AlignAroundTheBall(self.game_state, player, diff --git a/ai/STA/Tactic/align_to_defense_wall.py b/ai/STA/Tactic/align_to_defense_wall.py index d1551507..3749408c 100644 --- a/ai/STA/Tactic/align_to_defense_wall.py +++ b/ai/STA/Tactic/align_to_defense_wall.py @@ -34,7 +34,8 @@ def __init__(self, game_state: GameState, args: Optional[List[str]]=None, robots_in_formation: Optional[List[Player]]=None, object_to_block=None, - stay_away_from_ball=False): + stay_away_from_ball=False, + cruise_speed=3): super().__init__(game_state, player, args=args) if object_to_block is None: object_to_block = GameState().ball @@ -45,6 +46,7 @@ def __init__(self, game_state: GameState, self.robots_in_formation = robots_in_formation assert isinstance(self.robots_in_formation[0], Player) + self.cruise_speed = cruise_speed self.stay_away_from_ball = stay_away_from_ball self.go_kick_tactic = None self.player_number_in_formation = None @@ -129,7 +131,7 @@ def main_state(self): dest = self.position_on_wall_segment() dest_orientation = (self.object_to_block.position - dest).angle return MoveTo(Pose(dest, - dest_orientation)) + dest_orientation), cruise_speed=self.cruise_speed) def go_kick(self): self.compute_wall_segment() diff --git a/ai/STA/Tactic/leeroy_jenkins.py b/ai/STA/Tactic/leeroy_jenkins.py index 14bba186..825a54a7 100644 --- a/ai/STA/Tactic/leeroy_jenkins.py +++ b/ai/STA/Tactic/leeroy_jenkins.py @@ -27,7 +27,7 @@ def go_kick_low(self): self.next_state = self.go_kick_high return Idle if self.go_kick_tactic is None: - self.go_kick_tactic = GoKickExperimental(self.game_state, self.player, kick_force=KickForce.LOW, + self.go_kick_tactic = GoKick(self.game_state, self.player, kick_force=KickForce.LOW, target=self.game_state.field.their_goal_pose) if self.go_kick_tactic.status_flag == Flags.SUCCESS: self.go_kick_tactic.status_flag = Flags.INIT @@ -39,8 +39,8 @@ def go_kick_high(self): self.next_state = self.go_kick_low return Idle if self.go_kick_tactic is None: - self.go_kick_tactic = GoKickExperimental(self.game_state, self.player, kick_force=KickForce.HIGH, - target=self.game_state.field.their_goal_pose) + self.go_kick_tactic = GoKick(self.game_state, self.player, kick_force=KickForce.HIGH, + auto_update_target=True) if self.go_kick_tactic.status_flag == Flags.SUCCESS: self.go_kick_tactic.status_flag = Flags.INIT return self.go_kick_tactic.exec() diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 4e895c7b..563181ce 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -52,7 +52,7 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a def is_player_offense(self, player): role = self.game_state.get_role_by_player_id(player.id) - return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK] + return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK, Role.MIDDLE] def move_to_pass_position(self): destination_orientation = (self.game_state.ball_position - self.player.pose.position).angle @@ -60,7 +60,9 @@ def move_to_pass_position(self): if (time.time() - self.last_evaluation) > EVALUATION_INTERVAL: self.best_position = self._find_best_player_position() if self.auto_position else self.target self.last_evaluation = time.time() - return MoveTo(Pose(self.best_position, destination_orientation), ball_collision=False) + return MoveTo(Pose(self.best_position, destination_orientation), + ball_collision=False, + cruise_speed=2) def _find_best_player_position(self): if not self.auto_position: diff --git a/dual_launch.sh b/dual_launch.sh index c95a1b92..dd6dfee9 100755 --- a/dual_launch.sh +++ b/dual_launch.sh @@ -2,5 +2,5 @@ # Start two AI: yellow one in auto mode, blue in manual with a UI-debug. python ../UI-Debug/main.py config/field/sim.cfg blue \ -| python main.py config/sim.cfg yellow negative --start_in_auto \ -| python main.py config/sim.cfg blue positive +| python main.py config/sim.cfg yellow negative --start_in_auto --engine_fps 30\ +| python main.py config/sim.cfg blue positive --engine_fps 30 From ea8df15ee8c476a7029c52218692994543f3103e Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 20 Jun 2018 10:07:18 -0400 Subject: [PATCH 40/58] Fix goalkeeper hitting the sides --- ai/STA/Tactic/goalkeeper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/STA/Tactic/goalkeeper.py b/ai/STA/Tactic/goalkeeper.py index d12adedd..2ac6fc1b 100644 --- a/ai/STA/Tactic/goalkeeper.py +++ b/ai/STA/Tactic/goalkeeper.py @@ -61,7 +61,7 @@ def defense(self): self.next_state = self.intercept return self.intercept() # no time to loose - circle_radius = self.game_state.field.goal_width / 2 + circle_radius = self.game_state.field.goal_width / 2 - ROBOT_RADIUS circle_center = self.game_state.field.our_goal - self.OFFSET_FROM_GOAL_LINE solutions = intersection_line_and_circle(circle_center, circle_radius, From 6e83fdb6324cd2072ed28a7360854fa518bc017c Mon Sep 17 00:00:00 2001 From: philippe Date: Wed, 20 Jun 2018 12:14:38 -0400 Subject: [PATCH 41/58] destruction arrises --- Engine/regulators/velocity_regulators.py | 2 +- ai/Algorithm/path_partitionner.py | 12 ++++++------ ai/executors/pathfinder_module.py | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index c9eec879..601755b5 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -46,7 +46,7 @@ def following_path_vector(self, robot): return direction_error def get_next_speed(self, robot, acc=MAX_LINEAR_ACCELERATION): - acceleration_offset = 1.5 # on veut que le robot soit plus aggressif en début de trajet + acceleration_offset = 1 # on veut que le robot soit plus aggressif en début de trajet emergency_break_offset = self.emergency_break_constant / self.dt * (robot.current_speed / 1000) # on veut que le robot break le plus qu'il peut si on s'approche trop vite de la target emergency_break_offset = max(1.0, emergency_break_offset) diff --git a/ai/Algorithm/path_partitionner.py b/ai/Algorithm/path_partitionner.py index 21cce71d..50f34d17 100644 --- a/ai/Algorithm/path_partitionner.py +++ b/ai/Algorithm/path_partitionner.py @@ -31,7 +31,7 @@ class PathPartitionner: def __init__(self): self.obstacles = [] self.old_path = None - self.velocity = None + self.player_velocity = None @property def obstacles_position(self): @@ -39,7 +39,7 @@ def obstacles_position(self): @property def obstacles_avoid_distance(self): - return np.array([obs.avoid_distance for obs in self.obstacles]) + return np.array([obs.avoid_distance * 0.5*(1/(1+np.exp(-0.004 * np.linalg.norm(self.player_velocity) + 7)) + 1) for obs in self.obstacles]) def filter_obstacles(self, start, target): obstacles = np.array(self.obstacles) @@ -49,8 +49,8 @@ def filter_obstacles(self, start, target): is_not_self = start_to_obs > 0 # remove self if present self.obstacles = obstacles[is_inside_ellipse & is_not_self].tolist() - def get_path(self, start: Position, target: Position, obstacles: List[Obstacle], velocity: Position, last_path: Optional[Path]=None): - self.velocity = velocity.array + def get_path(self, start: Position, target: Position, obstacles: List[Obstacle], player_velocity: Position, last_path: Optional[Path]=None): + self.player_velocity = player_velocity.array self.obstacles = obstacles self.old_path = last_path self.filter_obstacles(start.array, target.array) @@ -121,8 +121,8 @@ def next_sub_target(self, start, target): while not self.is_valid_sub_target(sub_target_2, self.obstacles_position): sub_target_2 -= avoid_dir * resolution_sub_target #on maximise l'angle entre les segments pour avoir un path plus rectiligne - val_1 = np.dot((sub_target_1-start)/np.linalg.norm(sub_target_1-start), self.velocity) - val_2 = np.dot((sub_target_2 - start) / np.linalg.norm(sub_target_2 - start), self.velocity) + val_1 = np.dot((sub_target_1-start) / np.linalg.norm(sub_target_1-start), self.player_velocity) + val_2 = np.dot((sub_target_2 - start) / np.linalg.norm(sub_target_2 - start), self.player_velocity) if val_1 > val_2: #le segment 1 est plus aligne avec le path precedant que le segment2 sub_target = sub_target_1.copy() sub_target_potential = sub_target_1.copy() diff --git a/ai/executors/pathfinder_module.py b/ai/executors/pathfinder_module.py index 4e5dfbfe..3c95f4f2 100644 --- a/ai/executors/pathfinder_module.py +++ b/ai/executors/pathfinder_module.py @@ -118,7 +118,7 @@ def generate_simple_path(self, start: Position, way_point: WayPoint, velocity: P path = PathPartitionner().get_path(start=start, target=way_point.position, obstacles=player_obstacles, - velocity=velocity, + player_velocity=velocity, last_path=last_path) return path From 00ffb45ce3b178521def639605fc1a2256a362ee Mon Sep 17 00:00:00 2001 From: philippe Date: Wed, 20 Jun 2018 16:20:32 -0400 Subject: [PATCH 42/58] before AMC --- ai/STA/Tactic/go_kick.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 5b5721a3..3430bc3c 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -21,7 +21,7 @@ TARGET_ASSIGNATION_DELAY = 1.0 GO_BEHIND_SPACING = 180 -GRAB_BALL_SPACING = 90 +GRAB_BALL_SPACING = 80 APPROACH_SPEED = 100 KICK_DISTANCE = 90 KICK_SUCCEED_THRESHOLD = 300 @@ -85,7 +85,7 @@ def go_behind_ball(self): collision_ball = False distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.get_alignment_with_ball_and_target() < 25 \ + if self.get_alignment_with_ball_and_target() < 35 \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): self.next_state = self.grab_ball else: @@ -184,7 +184,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=4) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=200) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ From 7d6d71bf088219cb5271cae15192224ae51f3278 Mon Sep 17 00:00:00 2001 From: philippe Date: Thu, 21 Jun 2018 10:29:49 -0400 Subject: [PATCH 43/58] after amc --- ai/Algorithm/auto_play.py | 4 +++- ai/Algorithm/path_partitionner.py | 2 +- ai/STA/Tactic/position_for_pass.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ai/Algorithm/auto_play.py b/ai/Algorithm/auto_play.py index 2695d720..aaf5d3c9 100644 --- a/ai/Algorithm/auto_play.py +++ b/ai/Algorithm/auto_play.py @@ -233,7 +233,9 @@ def _exec_state(self): return self._decide_between_normal_play() elif self.current_state in self.FREE_KICK_STATE and GameState().ball.is_mobile(): return self._decide_between_normal_play() - elif self.current_state in self.KICKOFF_STATE and GameState().ball.is_mobile(): + elif self.current_state in self.KICKOFF_STATE and \ + (GameState().ball.is_mobile() or + (GameState().ball.position - Position(0, 0)).norm > self.game_state.field.center_circle_radius): return self._decide_between_normal_play() return self.current_state \ No newline at end of file diff --git a/ai/Algorithm/path_partitionner.py b/ai/Algorithm/path_partitionner.py index 50f34d17..4890078d 100644 --- a/ai/Algorithm/path_partitionner.py +++ b/ai/Algorithm/path_partitionner.py @@ -39,7 +39,7 @@ def obstacles_position(self): @property def obstacles_avoid_distance(self): - return np.array([obs.avoid_distance * 0.5*(1/(1+np.exp(-0.004 * np.linalg.norm(self.player_velocity) + 7)) + 1) for obs in self.obstacles]) + return np.array([obs.avoid_distance for obs in self.obstacles]) def filter_obstacles(self, start, target): obstacles = np.array(self.obstacles) diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 563181ce..59d31cce 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -52,7 +52,7 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a def is_player_offense(self, player): role = self.game_state.get_role_by_player_id(player.id) - return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK, Role.MIDDLE] + return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK] def move_to_pass_position(self): destination_orientation = (self.game_state.ball_position - self.player.pose.position).angle From 64a625644d386401d003c53b145cc14579bdbdfb Mon Sep 17 00:00:00 2001 From: philippe Date: Thu, 21 Jun 2018 11:07:07 -0400 Subject: [PATCH 44/58] During RoboFEI sadf --- ai/Algorithm/auto_play.py | 2 +- ai/STA/Strategy/test_passing.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ai/Algorithm/auto_play.py b/ai/Algorithm/auto_play.py index aaf5d3c9..abede4cd 100644 --- a/ai/Algorithm/auto_play.py +++ b/ai/Algorithm/auto_play.py @@ -235,7 +235,7 @@ def _exec_state(self): return self._decide_between_normal_play() elif self.current_state in self.KICKOFF_STATE and \ (GameState().ball.is_mobile() or - (GameState().ball.position - Position(0, 0)).norm > self.game_state.field.center_circle_radius): + (GameState().ball.position - Position(0, 0)).norm > GameState().field.center_circle_radius): return self._decide_between_normal_play() return self.current_state \ No newline at end of file diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index f277f14c..961c61b7 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -20,7 +20,7 @@ # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class TestPassing(Strategy): - def __init__(self, p_game_state, can_kick_in_goal=True): + def __init__(self, p_game_state, can_kick_in_goal=False): super().__init__(p_game_state) formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] From 85a507a530a9213765208f0ed97329e8ca852c3a Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 11 Jul 2018 17:30:56 -0400 Subject: [PATCH 45/58] WTF is this --- ai/STA/Tactic/go_kick.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 5b5721a3..baadf5c3 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -20,10 +20,10 @@ VALIDATE_KICK_DELAY = 0.5 TARGET_ASSIGNATION_DELAY = 1.0 -GO_BEHIND_SPACING = 180 -GRAB_BALL_SPACING = 90 +GO_BEHIND_SPACING = 250 +GRAB_BALL_SPACING = 120 APPROACH_SPEED = 100 -KICK_DISTANCE = 90 +KICK_DISTANCE = 130 KICK_SUCCEED_THRESHOLD = 300 COMMAND_DELAY = 0.5 @@ -77,16 +77,17 @@ def go_behind_ball(self): ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) angle_behind = self.get_alignment_with_ball_and_target() - if angle_behind > 35: - effective_ball_spacing = GO_BEHIND_SPACING * min(3, abs(angle_behind/45)) * ball_speed_modifier + if angle_behind > 30: + effective_ball_spacing = GRAB_BALL_SPACING * min(2, abs(angle_behind/30)) * ball_speed_modifier collision_ball = True else: - effective_ball_spacing = GO_BEHIND_SPACING + effective_ball_spacing = GRAB_BALL_SPACING collision_ball = False distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.get_alignment_with_ball_and_target() < 25 \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): + + if self.get_alignment_with_ball_and_target() < 18 \ + and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.grab_ball else: self.next_state = self.go_behind_ball @@ -94,12 +95,12 @@ def go_behind_ball(self): cruise_speed=3, end_speed=0, ball_collision=collision_ball)\ - .addChargeKicker().addKick(self.kick_force).build() + .addChargeKicker().build() def grab_ball(self): if self.auto_update_target: self._find_best_passing_option() - if self.get_alignment_with_ball_and_target() > 45: + if self.get_alignment_with_ball_and_target() > 25: self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: @@ -107,10 +108,9 @@ def grab_ball(self): self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm orientation = (self.target.position - self.game_state.ball_position).angle - spacing_offset = abs(1 - np.dot((self.player.position-self.target.position).array, (self.player.position-self.game_state.ball.position).array)) distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), - cruise_speed=1, + cruise_speed=3, end_speed=0, ball_collision=False)\ .addForceDribbler()\ @@ -184,7 +184,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=4) -> Position: + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=15) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ @@ -214,7 +214,7 @@ def get_alignment_with_ball_and_target(self): (normalize(self.player.position - self.game_state.ball_position)).array) return np.arccos(alignement_behind) * 180 / np.pi - def debug_cmd_fuck(self): + def debug_cmd(self): angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: From 46d58e4bef864b0acfb4b579df63bb3cdd0dfb77 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 11 Jul 2018 18:14:48 -0400 Subject: [PATCH 46/58] Fix test --- tests/STA/Tactic/go_kick_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/STA/Tactic/go_kick_test.py b/tests/STA/Tactic/go_kick_test.py index 906ac5ec..48b408b6 100644 --- a/tests/STA/Tactic/go_kick_test.py +++ b/tests/STA/Tactic/go_kick_test.py @@ -27,8 +27,7 @@ def test_givenARobotAndABall_thenKickTheBall(self): for _ in range(0, MAX_TICK_UNTIL_KICK): self.sim.tick() - if self.sim.has_kick(): - assert self.sim.has_hit_ball + if self.sim.has_kick() and self.sim.has_hit_ball: return assert False, "Reach max number of tick and no kick" From f9c3a25427b17a3173c9dc42fc302804d93c7832 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 11 Jul 2018 18:23:03 -0400 Subject: [PATCH 47/58] Revert two stupid commit --- ai/Algorithm/auto_play.py | 4 +--- ai/Algorithm/path_partitionner.py | 2 +- ai/STA/Strategy/test_passing.py | 2 +- ai/STA/Tactic/go_kick.py | 38 ++++++++++-------------------- ai/STA/Tactic/position_for_pass.py | 2 +- 5 files changed, 16 insertions(+), 32 deletions(-) diff --git a/ai/Algorithm/auto_play.py b/ai/Algorithm/auto_play.py index abede4cd..2695d720 100644 --- a/ai/Algorithm/auto_play.py +++ b/ai/Algorithm/auto_play.py @@ -233,9 +233,7 @@ def _exec_state(self): return self._decide_between_normal_play() elif self.current_state in self.FREE_KICK_STATE and GameState().ball.is_mobile(): return self._decide_between_normal_play() - elif self.current_state in self.KICKOFF_STATE and \ - (GameState().ball.is_mobile() or - (GameState().ball.position - Position(0, 0)).norm > GameState().field.center_circle_radius): + elif self.current_state in self.KICKOFF_STATE and GameState().ball.is_mobile(): return self._decide_between_normal_play() return self.current_state \ No newline at end of file diff --git a/ai/Algorithm/path_partitionner.py b/ai/Algorithm/path_partitionner.py index 4890078d..50f34d17 100644 --- a/ai/Algorithm/path_partitionner.py +++ b/ai/Algorithm/path_partitionner.py @@ -39,7 +39,7 @@ def obstacles_position(self): @property def obstacles_avoid_distance(self): - return np.array([obs.avoid_distance for obs in self.obstacles]) + return np.array([obs.avoid_distance * 0.5*(1/(1+np.exp(-0.004 * np.linalg.norm(self.player_velocity) + 7)) + 1) for obs in self.obstacles]) def filter_obstacles(self, start, target): obstacles = np.array(self.obstacles) diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index 961c61b7..f277f14c 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -20,7 +20,7 @@ # noinspection PyMethodMayBeStatic,PyMethodMayBeStatic class TestPassing(Strategy): - def __init__(self, p_game_state, can_kick_in_goal=False): + def __init__(self, p_game_state, can_kick_in_goal=True): super().__init__(p_game_state) formation = [p for r, p in self.assigned_roles.items() if r != Role.GOALKEEPER] diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 73c687e3..5b5721a3 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -20,15 +20,10 @@ VALIDATE_KICK_DELAY = 0.5 TARGET_ASSIGNATION_DELAY = 1.0 -<<<<<<< HEAD -GO_BEHIND_SPACING = 250 -GRAB_BALL_SPACING = 120 -======= GO_BEHIND_SPACING = 180 -GRAB_BALL_SPACING = 80 ->>>>>>> 64a625644d386401d003c53b145cc14579bdbdfb +GRAB_BALL_SPACING = 90 APPROACH_SPEED = 100 -KICK_DISTANCE = 130 +KICK_DISTANCE = 90 KICK_SUCCEED_THRESHOLD = 300 COMMAND_DELAY = 0.5 @@ -82,22 +77,16 @@ def go_behind_ball(self): ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) angle_behind = self.get_alignment_with_ball_and_target() - if angle_behind > 30: - effective_ball_spacing = GRAB_BALL_SPACING * min(2, abs(angle_behind/30)) * ball_speed_modifier + if angle_behind > 35: + effective_ball_spacing = GO_BEHIND_SPACING * min(3, abs(angle_behind/45)) * ball_speed_modifier collision_ball = True else: - effective_ball_spacing = GRAB_BALL_SPACING + effective_ball_spacing = GO_BEHIND_SPACING collision_ball = False distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm -<<<<<<< HEAD - - if self.get_alignment_with_ball_and_target() < 18 \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): -======= - if self.get_alignment_with_ball_and_target() < 35 \ + if self.get_alignment_with_ball_and_target() < 25 \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): ->>>>>>> 64a625644d386401d003c53b145cc14579bdbdfb self.next_state = self.grab_ball else: self.next_state = self.go_behind_ball @@ -105,12 +94,12 @@ def go_behind_ball(self): cruise_speed=3, end_speed=0, ball_collision=collision_ball)\ - .addChargeKicker().build() + .addChargeKicker().addKick(self.kick_force).build() def grab_ball(self): if self.auto_update_target: self._find_best_passing_option() - if self.get_alignment_with_ball_and_target() > 25: + if self.get_alignment_with_ball_and_target() > 45: self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: @@ -118,9 +107,10 @@ def grab_ball(self): self.kick_last_time = time.time() ball_speed = self.game_state.ball.velocity.norm orientation = (self.target.position - self.game_state.ball_position).angle + spacing_offset = abs(1 - np.dot((self.player.position-self.target.position).array, (self.player.position-self.game_state.ball.position).array)) distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), - cruise_speed=3, + cruise_speed=1, end_speed=0, ball_collision=False)\ .addForceDribbler()\ @@ -194,11 +184,7 @@ def _find_best_passing_option(self): self.target_assignation_last_time = time.time() -<<<<<<< HEAD - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=15) -> Position: -======= - def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=200) -> Position: ->>>>>>> 64a625644d386401d003c53b145cc14579bdbdfb + def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offset=4) -> Position: """ Compute the point which is at ball_spacing mm behind the ball from the target. """ @@ -228,7 +214,7 @@ def get_alignment_with_ball_and_target(self): (normalize(self.player.position - self.game_state.ball_position)).array) return np.arccos(alignement_behind) * 180 / np.pi - def debug_cmd(self): + def debug_cmd_fuck(self): angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 59d31cce..563181ce 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -52,7 +52,7 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a def is_player_offense(self, player): role = self.game_state.get_role_by_player_id(player.id) - return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK] + return role in [Role.FIRST_ATTACK, Role.SECOND_ATTACK, Role.MIDDLE] def move_to_pass_position(self): destination_orientation = (self.game_state.ball_position - self.player.pose.position).angle From 17c06042810c6d87a45ac801feffeab850c318a4 Mon Sep 17 00:00:00 2001 From: Philippe Babin Date: Wed, 11 Jul 2018 18:28:11 -0400 Subject: [PATCH 48/58] Naming --- ai/STA/Tactic/go_kick.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 5b5721a3..d6911622 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -214,7 +214,7 @@ def get_alignment_with_ball_and_target(self): (normalize(self.player.position - self.game_state.ball_position)).array) return np.arccos(alignement_behind) * 180 / np.pi - def debug_cmd_fuck(self): + def debug_cmd_disable(self): angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: From e8826aad4fa48cd05dce43e694feffab98c36d90 Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 14:24:22 -0400 Subject: [PATCH 49/58] add file to merge --- Engine/Framework.py | 8 ++++++-- Engine/regulators/velocity_regulators.py | 6 +++--- Engine/robot.py | 4 ++-- Engine/tracker.py | 2 +- dual_launch.sh | 4 ++-- 5 files changed, 14 insertions(+), 10 deletions(-) diff --git a/Engine/Framework.py b/Engine/Framework.py index b9f2cdf2..e11f66f5 100644 --- a/Engine/Framework.py +++ b/Engine/Framework.py @@ -58,13 +58,17 @@ def start(self): finally: self.stop_game() - def stop_game(self): self.logger.critical('Framework stopped.') try: - os.kill(self.engine.pid, signal.SIGINT) # This will interrupt the coach as well. + os.kill(self.engine.pid, signal.SIGINT) except ProcessLookupError: pass + try: + os.kill(self.coach.pid, signal.SIGINT) + except ProcessLookupError: + pass + sys.exit() diff --git a/Engine/regulators/velocity_regulators.py b/Engine/regulators/velocity_regulators.py index a76238e7..601755b5 100644 --- a/Engine/regulators/velocity_regulators.py +++ b/Engine/regulators/velocity_regulators.py @@ -13,7 +13,7 @@ class RealVelocityController(RegulatorBaseClass): settings = {'kp': 10, 'ki': 0, 'kd': 1} - v_d = 100 # lower = bigger path correction + v_d = 4 # lower = bigger path correction emergency_break_constant = 0.4 # Higher = higher correction of trajectory emergency_break_safety_factor = 1 # lower = bigger break distance @@ -46,7 +46,7 @@ def following_path_vector(self, robot): return direction_error def get_next_speed(self, robot, acc=MAX_LINEAR_ACCELERATION): - acceleration_offset = 1.5 # on veut que le robot soit plus aggressif en début de trajet + acceleration_offset = 1 # on veut que le robot soit plus aggressif en début de trajet emergency_break_offset = self.emergency_break_constant / self.dt * (robot.current_speed / 1000) # on veut que le robot break le plus qu'il peut si on s'approche trop vite de la target emergency_break_offset = max(1.0, emergency_break_offset) @@ -78,7 +78,7 @@ class GrSimVelocityController(RealVelocityController): settings = {'kp': 2, 'ki': 0.3, 'kd': 0} v_d = 15 emergency_break_constant = 0 - emergency_break_safety_factor = 1 + emergency_break_safety_factor = 1 # lower = bigger break distance def is_time_to_break(robot, destination, cruise_speed, acceleration, target_speed): diff --git a/Engine/robot.py b/Engine/robot.py index 10ee5fc9..9cbab9f5 100644 --- a/Engine/robot.py +++ b/Engine/robot.py @@ -4,8 +4,8 @@ from Util.geometry import wrap_to_pi MAX_LINEAR_SPEED = 4000 # mm/s -MAX_LINEAR_ACCELERATION = 3000 # mm/s^2 -MAX_ANGULAR_SPEED = 20 # rad/s +MAX_LINEAR_ACCELERATION = 4000 # mm/s^2 +MAX_ANGULAR_SPEED = 70 # rad/s MAX_ANGULAR_ACC = 3 # rad/s^2 MIN_LINEAR_SPEED = 200 # mm/s Speed near zero, but still move the robot diff --git a/Engine/tracker.py b/Engine/tracker.py index 661a1ac9..de624e3d 100644 --- a/Engine/tracker.py +++ b/Engine/tracker.py @@ -21,7 +21,7 @@ class Tracker: - MAX_BALLS_SEPARATION = 2000 + MAX_BALLS_SEPARATION = 1000 def __init__(self, vision_state: DictProxy, ui_send_queue: Queue): self.logger = logging.getLogger(self.__class__.__name__) diff --git a/dual_launch.sh b/dual_launch.sh index c95a1b92..dd6dfee9 100755 --- a/dual_launch.sh +++ b/dual_launch.sh @@ -2,5 +2,5 @@ # Start two AI: yellow one in auto mode, blue in manual with a UI-debug. python ../UI-Debug/main.py config/field/sim.cfg blue \ -| python main.py config/sim.cfg yellow negative --start_in_auto \ -| python main.py config/sim.cfg blue positive +| python main.py config/sim.cfg yellow negative --start_in_auto --engine_fps 30\ +| python main.py config/sim.cfg blue positive --engine_fps 30 From bd5226cd84d947ec4945839b9f8665bc6b57041a Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 14:48:53 -0400 Subject: [PATCH 50/58] fix received_pass tactic --- ai/STA/Tactic/receive_pass.py | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index 8a491a08..020ce7e3 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -1,21 +1,16 @@ # Under MIT licence, see LICENCE.txt -import math as m -import time -from typing import List, Union - import numpy as np -from Util.constant import ROBOT_CENTER_TO_KICKER, BALL_RADIUS, KickForce from Util import Pose, Position from Util.ai_command import CmdBuilder, Idle -from Util.geometry import compare_angle, normalize -from ai.Algorithm.evaluation_module import best_passing_option, player_covered_from_goal -from ai.GameDomainObjects import Player +from Util.geometry import compare_angle, normalize, perpendicular + from ai.STA.Tactic.tactic import Tactic from ai.STA.Tactic.tactic_constants import Flags + +from ai.GameDomainObjects import Player from ai.states.game_state import GameState -from Util.geometry import perpendicular GO_BEHIND_SPACING = 250 GRAB_BALL_SPACING = 100 @@ -25,7 +20,7 @@ # noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class ReceivePass(Tactic): - def __init__(self, game_state: GameState, player: Player, target=Position(0, 0)): + def __init__(self, game_state: GameState, player: Player): super().__init__(game_state, player) self.current_state = self.initialize @@ -81,7 +76,7 @@ def wait_for_ball(self): perp_vec = perpendicular(self.player.position - self.game_state.ball.position) component_lateral = perp_vec * np.dot(perp_vec.array, normalize(self.game_state.ball.velocity).array) small_segment_len = np.sqrt(1 - component_lateral.norm**2) - latteral_move = component_lateral * (self.player.position - self.game_state.ball.position).norm / small_segment_len + latteral_move = component_lateral / small_segment_len * (self.player.position - self.game_state.ball.position).norm if self._get_distance_from_ball() < HAS_BALL_DISTANCE: self.next_state = self.halt return self.halt() @@ -89,7 +84,7 @@ def wait_for_ball(self): self.next_state = self.wait_for_ball return CmdBuilder().build() orientation = (self.game_state.ball_position - self.player.position).angle - return CmdBuilder().addMoveTo(Pose(self.player.position + latteral_move, orientation), + return CmdBuilder().addMoveTo(Pose(self.player.position + latteral_move.view(Position), orientation), cruise_speed=3, end_speed=0, ball_collision=False).addChargeKicker().build() From 77324ba4b71ea2500a917a6bd49015fcf036812a Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 14:52:53 -0400 Subject: [PATCH 51/58] clean go_kick --- ai/STA/Tactic/go_kick.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 5b5721a3..09bbb9d2 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -2,12 +2,12 @@ import math as m import time -from typing import List, Union +from typing import List import numpy as np from Debug.debug_command_factory import DebugCommandFactory, CYAN, RED -from Util.constant import ROBOT_CENTER_TO_KICKER, BALL_RADIUS, KickForce +from Util.constant import ROBOT_CENTER_TO_KICKER, KickForce from Util import Pose, Position from Util.ai_command import CmdBuilder, Idle from Util.geometry import compare_angle, normalize @@ -51,6 +51,8 @@ def __init__(self, game_state: GameState, player: Player, self.kick_force = kick_force self.go_behind_distance = go_behind_distance + self.is_debug = False + def initialize(self): if self.auto_update_target: self._find_best_passing_option() @@ -105,14 +107,10 @@ def grab_ball(self): if self._get_distance_from_ball() < KICK_DISTANCE: self.next_state = self.kick self.kick_last_time = time.time() - ball_speed = self.game_state.ball.velocity.norm + orientation = (self.target.position - self.game_state.ball_position).angle - spacing_offset = abs(1 - np.dot((self.player.position-self.target.position).array, (self.player.position-self.game_state.ball.position).array)) distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) - return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), - cruise_speed=1, - end_speed=0, - ball_collision=False)\ + return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), ball_collision=False)\ .addForceDribbler()\ .addKick(self.kick_force)\ .build() @@ -129,9 +127,7 @@ def kick(self): behind_ball = self.game_state.ball_position + normalize(player_to_target) * (ROBOT_CENTER_TO_KICKER) orientation = (self.target.position - self.game_state.ball_position).angle - return CmdBuilder().addMoveTo(Pose(behind_ball, orientation), - ball_collision=False, - end_speed=0)\ + return CmdBuilder().addMoveTo(Pose(behind_ball, orientation), ball_collision=False)\ .addKick(self.kick_force)\ .addForceDribbler().build() @@ -214,7 +210,11 @@ def get_alignment_with_ball_and_target(self): (normalize(self.player.position - self.game_state.ball_position)).array) return np.arccos(alignement_behind) * 180 / np.pi - def debug_cmd_fuck(self): + def debug_cmd(self): + + if not self.is_debug: + return + angle = None additional_dbg = [] if self.current_state == self.go_behind_ball: From c50b3f3725e2a331d40826bc3a707bfeb2b2da8d Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 15:09:29 -0400 Subject: [PATCH 52/58] fix unittest --- Util/constant.py | 2 +- ai/STA/Tactic/receive_pass.py | 5 +++-- tests/STA/Tactic/go_kick_test.py | 3 +-- tests/STA/perfect_sim.py | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Util/constant.py b/Util/constant.py index d8bb68a7..3aac34a1 100644 --- a/Util/constant.py +++ b/Util/constant.py @@ -6,7 +6,7 @@ ROBOT_RADIUS = 90 ROBOT_DIAMETER = ROBOT_RADIUS * 2 -ROBOT_CENTER_TO_KICKER = 50 +ROBOT_CENTER_TO_KICKER = 60 BALL_RADIUS = 21 MAX_PLAYER_ON_FIELD_PER_TEAM = 6 BALL_OUTSIDE_FIELD_BUFFER = 200 diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index 020ce7e3..57f5b8af 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -1,6 +1,7 @@ # Under MIT licence, see LICENCE.txt import numpy as np +from typing import Optional from Util import Pose, Position from Util.ai_command import CmdBuilder, Idle @@ -20,9 +21,9 @@ # noinspection PyArgumentList,PyUnresolvedReferences,PyUnresolvedReferences class ReceivePass(Tactic): - def __init__(self, game_state: GameState, player: Player): + def __init__(self, game_state: GameState, player: Player, target: Optional[Pose]=None): - super().__init__(game_state, player) + super().__init__(game_state, player, target) self.current_state = self.initialize self.next_state = self.initialize diff --git a/tests/STA/Tactic/go_kick_test.py b/tests/STA/Tactic/go_kick_test.py index 906ac5ec..48b408b6 100644 --- a/tests/STA/Tactic/go_kick_test.py +++ b/tests/STA/Tactic/go_kick_test.py @@ -27,8 +27,7 @@ def test_givenARobotAndABall_thenKickTheBall(self): for _ in range(0, MAX_TICK_UNTIL_KICK): self.sim.tick() - if self.sim.has_kick(): - assert self.sim.has_hit_ball + if self.sim.has_kick() and self.sim.has_hit_ball: return assert False, "Reach max number of tick and no kick" diff --git a/tests/STA/perfect_sim.py b/tests/STA/perfect_sim.py index 5678779d..0e0b69fc 100644 --- a/tests/STA/perfect_sim.py +++ b/tests/STA/perfect_sim.py @@ -78,6 +78,7 @@ def _robot_can_hit_ball(self, robot): ball_position = self.game_state.ball.position robot_to_ball = robot.pose.position - ball_position + print(robot_to_ball.norm, KICK_DISTANCE_MIN, KICK_DISTANCE_MAX) return KICK_DISTANCE_MIN < robot_to_ball.norm < KICK_DISTANCE_MAX \ and compare_angle(robot.pose.orientation, robot_to_ball.angle, abs_tol=MAX_ANGLE_FOR_KICK) From 9f0ee25b0e545d045fc292b8e2855880ad1ab6b4 Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 15:11:42 -0400 Subject: [PATCH 53/58] remove print --- tests/STA/perfect_sim.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/STA/perfect_sim.py b/tests/STA/perfect_sim.py index 0e0b69fc..5678779d 100644 --- a/tests/STA/perfect_sim.py +++ b/tests/STA/perfect_sim.py @@ -78,7 +78,6 @@ def _robot_can_hit_ball(self, robot): ball_position = self.game_state.ball.position robot_to_ball = robot.pose.position - ball_position - print(robot_to_ball.norm, KICK_DISTANCE_MIN, KICK_DISTANCE_MAX) return KICK_DISTANCE_MIN < robot_to_ball.norm < KICK_DISTANCE_MAX \ and compare_angle(robot.pose.orientation, robot_to_ball.angle, abs_tol=MAX_ANGLE_FOR_KICK) From 6ace814bab877d621c6cc3fe80695ae4fd48802f Mon Sep 17 00:00:00 2001 From: Simon Bouchard Date: Fri, 13 Jul 2018 15:40:37 -0400 Subject: [PATCH 54/58] fix change --- ai/Algorithm/path_partitionner.py | 2 +- ai/STA/Tactic/go_kick.py | 2 +- ai/STA/Tactic/goalkeeper.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ai/Algorithm/path_partitionner.py b/ai/Algorithm/path_partitionner.py index 50f34d17..4890078d 100644 --- a/ai/Algorithm/path_partitionner.py +++ b/ai/Algorithm/path_partitionner.py @@ -39,7 +39,7 @@ def obstacles_position(self): @property def obstacles_avoid_distance(self): - return np.array([obs.avoid_distance * 0.5*(1/(1+np.exp(-0.004 * np.linalg.norm(self.player_velocity) + 7)) + 1) for obs in self.obstacles]) + return np.array([obs.avoid_distance for obs in self.obstacles]) def filter_obstacles(self, start, target): obstacles = np.array(self.obstacles) diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 78fad731..69dac91e 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -7,7 +7,7 @@ import numpy as np from Debug.debug_command_factory import DebugCommandFactory, CYAN, RED -from Util.constant import ROBOT_CENTER_TO_KICKER, BALL_RADIUS, KickForce +from Util.constant import ROBOT_CENTER_TO_KICKER, KickForce from Util import Pose, Position from Util.ai_command import CmdBuilder, Idle from Util.geometry import compare_angle, normalize diff --git a/ai/STA/Tactic/goalkeeper.py b/ai/STA/Tactic/goalkeeper.py index 2ac6fc1b..d12adedd 100644 --- a/ai/STA/Tactic/goalkeeper.py +++ b/ai/STA/Tactic/goalkeeper.py @@ -61,7 +61,7 @@ def defense(self): self.next_state = self.intercept return self.intercept() # no time to loose - circle_radius = self.game_state.field.goal_width / 2 - ROBOT_RADIUS + circle_radius = self.game_state.field.goal_width / 2 circle_center = self.game_state.field.our_goal - self.OFFSET_FROM_GOAL_LINE solutions = intersection_line_and_circle(circle_center, circle_radius, From 1b0f17986e5c76c877875de140d81bbe9247243d Mon Sep 17 00:00:00 2001 From: wonwon0 Date: Thu, 19 Jul 2018 08:52:30 -0400 Subject: [PATCH 55/58] changements pour enlever les produits scalaires et refactor de noms de variables --- ai/GameDomainObjects/ball.py | 10 ++--- ai/STA/Strategy/defense_wall.py | 7 ++-- ai/STA/Strategy/free_kick.py | 13 +++--- ai/STA/Strategy/offense.py | 10 +++-- ai/STA/Strategy/passes_with_decisions.py | 4 +- ai/STA/Strategy/test_passing.py | 32 ++++++--------- ai/STA/Tactic/go_kick.py | 50 ++++++++++-------------- ai/STA/Tactic/position_for_pass.py | 5 ++- ai/STA/Tactic/receive_pass.py | 14 +++---- ai/STA/Tactic/rotate_around_ball.py | 9 +++-- 10 files changed, 74 insertions(+), 80 deletions(-) diff --git a/ai/GameDomainObjects/ball.py b/ai/GameDomainObjects/ball.py index e9d68499..60125dcd 100644 --- a/ai/GameDomainObjects/ball.py +++ b/ai/GameDomainObjects/ball.py @@ -15,13 +15,11 @@ def update(self, new_dict: Dict): self.position = new_dict['position'] self.velocity = new_dict['velocity'] - def is_moving_fast(self): - FAST_SPEED = 600.0 # mm/s - return FAST_SPEED < self.velocity.norm + def is_moving_fast(self, fast_speed = 600.0): # mm/s + return fast_speed < self.velocity.norm - def is_mobile(self): - IMMOBILE_SPEED = 300.0 # mm/s - return IMMOBILE_SPEED < self.velocity.norm + def is_mobile(self, immobile_speed = 300.0): # mm/s + return immobile_speed < self.velocity.norm def is_immobile(self): return not self.is_mobile() diff --git a/ai/STA/Strategy/defense_wall.py b/ai/STA/Strategy/defense_wall.py index 44f620d9..f88f06c2 100644 --- a/ai/STA/Strategy/defense_wall.py +++ b/ai/STA/Strategy/defense_wall.py @@ -220,9 +220,10 @@ def _generate_cover_to_coveree_mapping(self): def ball_going_toward_player(self, player): role = GameState().get_role_by_player_id(player.id) if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': - if self.game_state.ball.velocity.norm > 50: - return np.dot(normalize(player.position - self.game_state.ball.position).array, - normalize(self.game_state.ball.velocity).array) > 0.9 + if self.game_state.ball.is_mobile(50): # to avoid division by zero and unstable ball_directions + ball_approach_angle = np.arccos(np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array)) * 180 / np.pi + return ball_approach_angle > 25 return False def ball_not_going_toward_player(self, player): diff --git a/ai/STA/Strategy/free_kick.py b/ai/STA/Strategy/free_kick.py index 01a18411..0bccf74b 100644 --- a/ai/STA/Strategy/free_kick.py +++ b/ai/STA/Strategy/free_kick.py @@ -69,7 +69,8 @@ def __init__(self, p_game_state, can_kick_in_goal): ball_position = self.game_state.ball_position for r, position in initial_position_for_pass_center.items(): if self.closest_role is None \ - or (initial_position_for_pass_center[self.closest_role] - ball_position).norm > (position - ball_position).norm: + or (initial_position_for_pass_center[self.closest_role] - + ball_position).norm > (position - ball_position).norm: self.closest_role = r self.has_ball_move = False @@ -120,10 +121,12 @@ def is_ready_to_kick(self, player): def ball_going_toward_player(self, player): role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': - if self.game_state.ball.velocity.norm > 50: - return np.dot(normalize(player.position - self.game_state.ball.position).array, - normalize(self.game_state.ball.velocity).array) > 0.9 + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or \ + self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.is_mobile(50): # to avoid division by zero and unstable ball_directions + ball_approach_angle = np.arccos(np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array)) * 180 / np.pi + return ball_approach_angle > 25 return False def ball_not_going_toward_player(self, player): diff --git a/ai/STA/Strategy/offense.py b/ai/STA/Strategy/offense.py index b542d39d..59476676 100644 --- a/ai/STA/Strategy/offense.py +++ b/ai/STA/Strategy/offense.py @@ -84,10 +84,12 @@ def has_kicked(self, player): def ball_going_toward_player(self, player): role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': - if self.game_state.ball.velocity.norm > 50: - return np.dot(normalize(player.position - self.game_state.ball.position).array, - normalize(self.game_state.ball.velocity).array) > 0.9 + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or \ + self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.is_mobile(50): # to avoid division by zero and unstable ball_directions + ball_approach_angle = np.arccos(np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array)) * 180 / np.pi + return ball_approach_angle > 25 return False def ball_not_going_toward_player(self, player): diff --git a/ai/STA/Strategy/passes_with_decisions.py b/ai/STA/Strategy/passes_with_decisions.py index 4d94a6bd..697cf02c 100644 --- a/ai/STA/Strategy/passes_with_decisions.py +++ b/ai/STA/Strategy/passes_with_decisions.py @@ -32,7 +32,9 @@ def __init__(self, p_game_state): self.assigned_roles[Role.FIRST_ATTACK], args=[self.assigned_roles[Role.MIDDLE].id])) - node_go_kick = self.create_node(Role.FIRST_ATTACK, GoKick(self.game_state, self.assigned_roles[Role.FIRST_ATTACK], their_goal)) + node_go_kick = self.create_node(Role.FIRST_ATTACK, GoKick(self.game_state, + self.assigned_roles[Role.FIRST_ATTACK], + their_goal)) second_attack_is_best_receiver = partial(self.is_best_receiver, Role.SECOND_ATTACK) middle_is_best_receiver = partial(self.is_best_receiver, Role.MIDDLE) diff --git a/ai/STA/Strategy/test_passing.py b/ai/STA/Strategy/test_passing.py index f277f14c..3e548a17 100644 --- a/ai/STA/Strategy/test_passing.py +++ b/ai/STA/Strategy/test_passing.py @@ -30,12 +30,13 @@ def __init__(self, p_game_state, can_kick_in_goal=True): if role == Role.GOALKEEPER: self.create_node(Role.GOALKEEPER, GoalKeeper(self.game_state, player)) else: - node_pass = self.create_node(role, PositionForPass(self.game_state, - player, - robots_in_formation=formation, - auto_position=True, - forbidden_areas=[self.game_state.field.free_kick_avoid_area, - self.game_state.field.our_goal_forbidden_area])) + node_pass = self.create_node(role, + PositionForPass(self.game_state, + player, + robots_in_formation=formation, + auto_position=True, + forbidden_areas=[self.game_state.field.free_kick_avoid_area, + self.game_state.field.our_goal_forbidden_area])) node_wait_for_pass = self.create_node(role, ReceivePass(self.game_state, player)) initial_position_for_pass_center[role] = node_pass.tactic.area.center # Hack node_go_kick = self.create_node(role, GoKick(self.game_state, @@ -103,21 +104,14 @@ def has_kicked(self, player): else: return False - def is_ready_to_kick(self, player): - if self.has_ball_move: - return True # FIXME: Test irl, might Cause a lot of problem - role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'RotateAroundBall': - return self.roles_graph[role].current_tactic.status_flag == Flags.SUCCESS - else: - return False - def ball_going_toward_player(self, player): role = GameState().get_role_by_player_id(player.id) - if self.roles_graph[role].current_tactic_name == 'PositionForPass' or self.roles_graph[role].current_tactic_name == 'ReceivePass': - if self.game_state.ball.velocity.norm > 50: - return np.dot(normalize(player.position - self.game_state.ball.position).array, - normalize(self.game_state.ball.velocity).array) > 0.9 + if self.roles_graph[role].current_tactic_name == 'PositionForPass' or \ + self.roles_graph[role].current_tactic_name == 'ReceivePass': + if self.game_state.ball.is_mobile(50): # to avoid division by zero and unstable ball_directions + ball_approach_angle = np.arccos(np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array)) * 180 / np.pi + return ball_approach_angle > 25 return False def ball_not_going_toward_player(self, player): diff --git a/ai/STA/Tactic/go_kick.py b/ai/STA/Tactic/go_kick.py index 69dac91e..7ab8196c 100644 --- a/ai/STA/Tactic/go_kick.py +++ b/ai/STA/Tactic/go_kick.py @@ -56,12 +56,14 @@ def __init__(self, game_state: GameState, player: Player, def initialize(self): if self.auto_update_target: self._find_best_passing_option() - orientation = (self.target.position - self.game_state.ball_position).angle + required_orientation = (self.target.position - self.game_state.ball_position).angle dist_from_ball = (self.player.position - self.game_state.ball_position).norm if self.get_alignment_with_ball_and_target() < 60 \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): + and compare_angle(self.player.pose.orientation, + required_orientation, + abs_tol=max(0.1, 0.1 * dist_from_ball/1000)): self.next_state = self.go_behind_ball if self._get_distance_from_ball() < KICK_DISTANCE: self.next_state = self.kick @@ -75,7 +77,7 @@ def go_behind_ball(self): if self.auto_update_target: self._find_best_passing_option() self.status_flag = Flags.WIP - orientation = (self.target.position - self.game_state.ball_position).angle + required_orientation = (self.target.position - self.game_state.ball_position).angle ball_speed = self.game_state.ball.velocity.norm ball_speed_modifier = (ball_speed/1000 + 1) angle_behind = self.get_alignment_with_ball_and_target() @@ -85,14 +87,16 @@ def go_behind_ball(self): else: effective_ball_spacing = GO_BEHIND_SPACING collision_ball = False - distance_behind = self.get_destination_behind_ball(effective_ball_spacing) + position_behind_ball = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm if self.get_alignment_with_ball_and_target() < 25 \ - and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): + and compare_angle(self.player.pose.orientation, + required_orientation, + abs_tol=max(0.05, 0.05 * dist_from_ball/1000)): self.next_state = self.grab_ball else: self.next_state = self.go_behind_ball - return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), + return CmdBuilder().addMoveTo(Pose(position_behind_ball, required_orientation), cruise_speed=3, end_speed=0, ball_collision=collision_ball)\ @@ -108,11 +112,9 @@ def grab_ball(self): self.next_state = self.kick self.kick_last_time = time.time() - ball_speed = self.game_state.ball.velocity.norm - orientation = (self.target.position - self.game_state.ball_position).angle - spacing_offset = abs(1 - np.dot((self.player.position-self.target.position).array, (self.player.position-self.game_state.ball.position).array)) - distance_behind = self.get_destination_behind_ball(GRAB_BALL_SPACING) - return CmdBuilder().addMoveTo(Pose(distance_behind, orientation), ball_collision=False)\ + required_orientation = (self.target.position - self.game_state.ball_position).angle + position_behind_ball = self.get_destination_behind_ball(GRAB_BALL_SPACING) + return CmdBuilder().addMoveTo(Pose(position_behind_ball, required_orientation), ball_collision=False)\ .addForceDribbler()\ .addKick(self.kick_force)\ .build() @@ -126,10 +128,10 @@ def kick(self): self.next_state = self.validate_kick player_to_target = (self.target.position - self.player.pose.position) - behind_ball = self.game_state.ball_position + normalize(player_to_target) * (ROBOT_CENTER_TO_KICKER) - orientation = (self.target.position - self.game_state.ball_position).angle + position_behind_ball = self.game_state.ball_position + normalize(player_to_target) * ROBOT_CENTER_TO_KICKER + required_orientation = (self.target.position - self.game_state.ball_position).angle - return CmdBuilder().addMoveTo(Pose(behind_ball, orientation), ball_collision=False)\ + return CmdBuilder().addMoveTo(Pose(position_behind_ball, required_orientation), ball_collision=False)\ .addKick(self.kick_force)\ .addForceDribbler().build() @@ -154,12 +156,6 @@ def halt(self): def _get_distance_from_ball(self): return (self.player.pose.position - self.game_state.ball_position).norm - def _is_player_towards_ball_and_target(self, abs_tol=m.pi/30): - ball_position = self.game_state.ball_position - target_to_ball = ball_position - self.target.position - ball_to_player = self.player.pose.position - ball_position - return compare_angle(target_to_ball.angle, ball_to_player.angle, abs_tol=abs_tol) - def _find_best_passing_option(self): assignation_delay = (time.time() - self.target_assignation_last_time) if assignation_delay > TARGET_ASSIGNATION_DELAY: @@ -192,19 +188,13 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offs position_behind = self.game_state.ball.position - dir_ball_to_target * ball_spacing if velocity and self.game_state.ball.velocity.norm > 20: - position_behind += (self.game_state.ball.velocity - (normalize(self.game_state.ball.velocity) * - np.dot(dir_ball_to_target.array, - self.game_state.ball.velocity.array))) / velocity_offset + position_behind += (self.game_state.ball.velocity - + (normalize(self.game_state.ball.velocity) * + np.dot(dir_ball_to_target.array, + self.game_state.ball.velocity.array))) / velocity_offset return position_behind - def is_able_to_grab_ball_directly(self, threshold): - # plus que le threshold est gors (1 max), plus qu'on veut que le robot soit direct deriere la balle. - vec_target_to_ball = normalize(self.game_state.ball.position - self.target.position) - alignement_behind = np.dot(vec_target_to_ball.array, - (normalize(self.player.position - self.game_state.ball_position)).array) - return threshold < alignement_behind - def get_alignment_with_ball_and_target(self): vec_target_to_ball = normalize(self.game_state.ball.position - self.target.position) diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 563181ce..388d7746 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -40,7 +40,8 @@ def __init__(self, game_state: GameState, player: Player, target: Pose=Pose(), a self.robots_in_formation = robots_in_formation self.is_offense = self.is_player_offense(player) - self.robots_in_formation = [player for player in self.robots_in_formation if self.is_offense == self.is_player_offense(player)] + self.robots_in_formation = [player for player in self.robots_in_formation + if self.is_offense == self.is_player_offense(player)] self.idx_in_formation = self.robots_in_formation.index(player) self.area = None @@ -95,7 +96,7 @@ def _find_best_player_position(self): d = enemy.position - center # Clamp distance norm d = MIN_DIST_FROM_CENTER * normalize(d) if d.norm < MIN_DIST_FROM_CENTER else d - # Square of the inverse of the distance, a bit like Newton's law of universal gravitation + # Cube of the inverse of the distance as magnets repulsing each other. v -= ATTENUATION * d / (d.norm ** 3) if self.area.point_inside(center + v): diff --git a/ai/STA/Tactic/receive_pass.py b/ai/STA/Tactic/receive_pass.py index 52af8565..e3f3f317 100644 --- a/ai/STA/Tactic/receive_pass.py +++ b/ai/STA/Tactic/receive_pass.py @@ -48,7 +48,7 @@ def go_behind_ball(self): distance_behind = self.get_destination_behind_ball(effective_ball_spacing) dist_from_ball = (self.player.position - self.game_state.ball_position).norm - if self.is_ball_going_to_collide(threshold=0.95) \ + if self.is_ball_going_to_collide(threshold=18) \ and compare_angle(self.player.pose.orientation, orientation, abs_tol=max(0.1, 0.1 * dist_from_ball/100)): self.next_state = self.wait_for_ball @@ -61,7 +61,7 @@ def go_behind_ball(self): .addChargeKicker().build() def grab_ball(self): - if not self.is_ball_going_to_collide(threshold=0.95): + if not self.is_ball_going_to_collide(threshold=18): self.next_state = self.go_behind_ball if self._get_distance_from_ball() < HAS_BALL_DISTANCE: @@ -82,7 +82,7 @@ def wait_for_ball(self): if self._get_distance_from_ball() < HAS_BALL_DISTANCE: self.next_state = self.halt return self.halt() - if not self.is_ball_going_to_collide(threshold=0.95): + if not self.is_ball_going_to_collide(threshold=18): self.next_state = self.wait_for_ball return CmdBuilder().build() orientation = (self.game_state.ball_position - self.player.position).angle @@ -117,7 +117,7 @@ def get_destination_behind_ball(self, ball_spacing, velocity=True, velocity_offs return position_behind - def is_ball_going_to_collide(self, threshold=0.95): - - return np.dot(normalize(self.player.position - self.game_state.ball.position).array, - normalize(self.game_state.ball.velocity).array) > threshold + def is_ball_going_to_collide(self, threshold=18): # threshold in degrees + ball_approach_angle = np.arccos(np.dot(normalize(player.position - self.game_state.ball.position).array, + normalize(self.game_state.ball.velocity).array)) * 180 / np.pi + return ball_approach_angle > threshold diff --git a/ai/STA/Tactic/rotate_around_ball.py b/ai/STA/Tactic/rotate_around_ball.py index d6c71f43..a0ceef4f 100644 --- a/ai/STA/Tactic/rotate_around_ball.py +++ b/ai/STA/Tactic/rotate_around_ball.py @@ -46,7 +46,8 @@ def next_position(self): if self.start_time is not None: if time.time() - self.start_time >= self.rotate_time: self.rotation_sign = self._get_direction() - if compare_angle(self.target_orientation, (self.game_state.ball_position - self.player.position).angle, VALID_DIFF_ANGLE): + if compare_angle(self.target_orientation, (self.game_state.ball_position - self.player.position).angle, + VALID_DIFF_ANGLE): self.next_state = self.halt return self._go_to_final_position() elif time.time() - self.iter_time >= self.switch_time: @@ -60,10 +61,12 @@ def next_position(self): self.ball_collision = True self.speed = 1 self.offset_orientation += DIFF_ANGLE * self.rotation_sign - self.position = (self.game_state.ball_position - Position.from_angle(self.offset_orientation) * DISTANCE_FROM_BALL) + self.position = (self.game_state.ball_position - + Position.from_angle(self.offset_orientation) * DISTANCE_FROM_BALL) if self.start_time is not None: - orientation = self.offset_orientation if time.time() - self.start_time < self.rotate_time else self.target_orientation + orientation = self.offset_orientation if time.time() - self.start_time < \ + self.rotate_time else self.target_orientation else: orientation = self.target_orientation return CmdBuilder().addMoveTo(Pose(self.position, orientation), From fdd035b23e39d7c15958e79eedfe09e8d1b7ed14 Mon Sep 17 00:00:00 2001 From: wonwon0 Date: Thu, 19 Jul 2018 08:54:02 -0400 Subject: [PATCH 56/58] fixed config file --- config/real.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/real.cfg b/config/real.cfg index 5133eccd..333ba799 100644 --- a/config/real.cfg +++ b/config/real.cfg @@ -8,5 +8,5 @@ ui_debug_address=127.0.0.1 [ENGINE] number_of_camera=4 -disabled_camera_id=[1, 2] +disabled_camera_id=[] From 01da510ad60342ac7d30e3d7f06c4da24ec4b3b7 Mon Sep 17 00:00:00 2001 From: wonwon0 Date: Thu, 19 Jul 2018 09:01:14 -0400 Subject: [PATCH 57/58] fetch_ball condition fix --- ai/STA/Tactic/place_ball.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ai/STA/Tactic/place_ball.py b/ai/STA/Tactic/place_ball.py index 78fdb3fd..f08ad8fb 100644 --- a/ai/STA/Tactic/place_ball.py +++ b/ai/STA/Tactic/place_ball.py @@ -44,9 +44,8 @@ def __init__(self, game_state: GameState, player: Player, self.steady_orientation = None def _fetch_ball(self): - #if self.game_state.field.is_outside_wall_limit(self.game_state.ball_position) or \ - # self._check_success(): - if self._check_success(): + if self.game_state.field.is_outside_wall_limit(self.game_state.ball_position) or \ + self._check_success(): self.next_state = self.halt else: self.next_state = self.go_behind_ball From 3abd00224838681b15bc94460fc5e52722d82fe4 Mon Sep 17 00:00:00 2001 From: philippe Date: Sat, 21 Jul 2018 09:28:38 -0400 Subject: [PATCH 58/58] k --- ai/STA/Tactic/position_for_pass.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ai/STA/Tactic/position_for_pass.py b/ai/STA/Tactic/position_for_pass.py index 388d7746..e85d88ee 100644 --- a/ai/STA/Tactic/position_for_pass.py +++ b/ai/STA/Tactic/position_for_pass.py @@ -96,7 +96,7 @@ def _find_best_player_position(self): d = enemy.position - center # Clamp distance norm d = MIN_DIST_FROM_CENTER * normalize(d) if d.norm < MIN_DIST_FROM_CENTER else d - # Cube of the inverse of the distance as magnets repulsing each other. + # Square of the inverse of the distance, a bit like Newton's law of universal gravitation v -= ATTENUATION * d / (d.norm ** 3) if self.area.point_inside(center + v):