def test_detect_hit(self): arena = composer.Arena() ball = soccer_ball.SoccerBall(radius=0.35, mass=0.045, name='test_ball') player = team.Player( team=team.Team.HOME, walker=props.Primitive(geom_type='sphere', size=(0.1,), name='home')) arena.add_free_entity(player.walker) ball.register_player(player) arena.add_free_entity(ball) random_state = np.random.RandomState(42) physics = mjcf.Physics.from_mjcf_model(arena.mjcf_model) physics.step() ball.initialize_episode(physics, random_state) ball.before_step(physics, random_state) self.assertEqual(ball.hit, False) self.assertEqual(ball.repossessed, False) self.assertEqual(ball.intercepted, False) self.assertIsNone(ball.last_hit) self.assertIsNone(ball.dist_between_last_hits) ball.after_substep(physics, random_state) ball.after_step(physics, random_state) self.assertEqual(ball.hit, True) self.assertEqual(ball.repossessed, True) self.assertEqual(ball.intercepted, True) self.assertEqual(ball.last_hit, player) # Only one hit registered. self.assertIsNone(ball.dist_between_last_hits)
def test_has_tracking_cameras(self): ball = soccer_ball.SoccerBall(radius=0.35, mass=0.045, name='test_ball') expected_camera_names = ['ball_cam_near', 'ball_cam', 'ball_cam_far'] camera_names = [cam.name for cam in ball.mjcf_model.find_all('camera')] self.assertCountEqual(expected_camera_names, camera_names)
def __init__(self, players, arena, ball=None, initializer=None, observables=None, disable_walker_contacts=False, nconmax_per_player=200, njmax_per_player=200, control_timestep=0.025): """Construct an instance of soccer.Task. This task implements the high-level game logic of multi-agent MuJoCo soccer. Args: players: a sequence of `soccer.Player` instances, representing participants to the game from both teams. arena: an instance of `soccer.Pitch`, implementing the physical geoms and the sensors associated with the pitch. ball: optional instance of `soccer.SoccerBall`, implementing the physical geoms and sensors associated with the soccer ball. If None, defaults to using `soccer_ball.SoccerBall()`. initializer: optional instance of `soccer.Initializer` that initializes the task at the start of each episode. If None, defaults to `initializers.UniformInitializer()`. observables: optional instance of `soccer.Observables` that adds observables for each player. If None, defaults to `observables.CoreObservables()`. disable_walker_contacts: if `True`, disable physical contacts between players. nconmax_per_player: allocated maximum number of contacts per player. It may be necessary to increase this value if you encounter errors due to `mjWARN_CONTACTFULL`. njmax_per_player: allocated maximum number of scalar constraints per player. It may be necessary to increase this value if you encounter errors due to `mjWARN_CNSTRFULL`. control_timestep: control timestep of the agent. """ self.arena = arena self.players = players self._initializer = initializer or initializers.UniformInitializer() self._observables = observables or observables_lib.CoreObservables() if disable_walker_contacts: _disable_geom_contacts([p.walker for p in self.players]) # Create ball and attach ball to arena. self.ball = ball or soccer_ball.SoccerBall() self.arena.add_free_entity(self.ball) self.arena.register_ball(self.ball) # Register soccer ball contact tracking for players. for player in self.players: player.walker.create_root_joints(self.arena.attach(player.walker)) self.ball.register_player(player) # Add per-walkers observables. self._observables(self, player) self.set_timesteps(physics_timestep=0.005, control_timestep=control_timestep) self.root_entity.mjcf_model.size.nconmax = nconmax_per_player * len( players) self.root_entity.mjcf_model.size.njmax = njmax_per_player * len( players)
def test_damp_ratio_is_valid(self): with self.assertRaisesRegex(ValueError, 'Invalid `damp_ratio`.*'): soccer_ball.SoccerBall(damp_ratio=-0.5)