Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
matrix:
os: [ubuntu-latest]
# TODO: add Python 3.11 to test matrix
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
fail-fast: false
timeout-minutes: 60
steps:
Expand Down
11 changes: 6 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ classifiers = [
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Intended Audience :: Science/Research",
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"Topic :: Software Development :: Libraries :: Python Modules",
]
dependencies = [
"gymnasium == 0.28.1",
"gymnasium-robotics == 1.2.2",
"pygame == 2.1.0",
"mujoco == 2.3.3",
"gymnasium >= 0.28.1",
"gymnasium-robotics >= 1.2.2",
"pygame >= 2.1.0",
"mujoco >= 2.3.3",
"xmltodict >= 0.13.0",
"pyyaml >= 6.0",
"imageio >= 2.27.0",
Expand Down Expand Up @@ -74,7 +75,7 @@ safe = true
line-length = 100
skip-string-normalization = true
# Sync with requires-python
target-version = ["py38", "py39", "py310", "py311"]
target-version = ["py38", "py39", "py310", "py311", "py312"]

[tool.isort]
atomic = true
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/free_geoms/push_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PushBox(FreeGeom): # pylint: disable=too-many-instance-attributes
reward_box_dist: float = 1.0 # Dense reward for moving the agent towards the box
reward_box_goal: float = 1.0 # Reward for moving the box towards the goal

color: np.array = COLOR['push_box']
color: np.array = field(default_factory=lambda: COLOR['push_box'])
alpha: float = 0.25
group: np.array = GROUP['push_box']
is_lidar_observed: bool = True
Expand Down
4 changes: 2 additions & 2 deletions safety_gymnasium/assets/free_geoms/vases.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class Vases(FreeGeom): # pylint: disable=too-many-instance-attributes
placements: list = None # Vases placements list (defaults to full extents)
locations: list = field(default_factory=list) # Fixed locations to override placements
keepout: float = 0.15 # Radius of vases keepout for placement
alpha: float = COLOR['vase'][-1]
alpha: float = field(default_factory=lambda: COLOR['vase'][-1])
sink: float = 4e-5 # Experimentally measured, based on size and density,
# how far vases "sink" into the floor.
# Mujoco has soft contacts, so vases slightly sink into the floor,
Expand All @@ -48,7 +48,7 @@ class Vases(FreeGeom): # pylint: disable=too-many-instance-attributes
velocity_cost: float = 1.0 # Cost (per step) per m/s of velocity for a vase
velocity_threshold: float = 1e-4 # Ignore very small velocities

color: np.array = COLOR['vase']
color: np.array = field(default_factory=lambda: COLOR['vase'])
group: np.array = GROUP['vase']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/apples.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Apples(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['apple']
color: np.array = field(default_factory=lambda: COLOR['apple'])
alpha: float = 0.25
group: np.array = GROUP['apple']
is_lidar_observed: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Buttons(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['button']
color: np.array = field(default_factory=lambda: COLOR['button'])
group: np.array = GROUP['button']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
4 changes: 2 additions & 2 deletions safety_gymnasium/assets/geoms/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# ==============================================================================
"""Circle."""

from dataclasses import dataclass
from dataclasses import dataclass, field

import numpy as np

Expand All @@ -33,7 +33,7 @@ class Circle(Geom): # pylint: disable=too-many-instance-attributes
locations: tuple = ((0, 0),)
keepout: float = 0.0

color: np.array = COLOR['circle']
color: np.array = field(default_factory=lambda: COLOR['circle'])
alpha: float = 0.1
group: np.array = GROUP['circle']
is_lidar_observed: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/goal.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Goal(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.ndarray = COLOR['goal']
color: np.ndarray = field(default_factory=lambda: COLOR['goal'])
alpha: float = 0.25
group: np.ndarray = GROUP['goal']
is_lidar_observed: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/hazards.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Hazards(Geom): # pylint: disable=too-many-instance-attributes
alpha: float = 0.25
cost: float = 1.0 # Cost (per step) for violating the constraint

color: np.array = COLOR['hazard']
color: np.array = field(default_factory=lambda: COLOR['hazard'])
group: np.array = GROUP['hazard']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/oranges.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Oranges(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['orange']
color: np.array = field(default_factory=lambda: COLOR['orange'])
alpha: float = 0.25
group: np.array = GROUP['orange']
is_lidar_observed: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/pillars.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Pillars(Geom): # pylint: disable=too-many-instance-attributes
keepout: float = 0.3 # Radius for placement of pillars
cost: float = 1.0 # Cost (per step) for being in contact with a pillar

color: np.array = COLOR['pillar']
color: np.array = field(default_factory=lambda: COLOR['pillar'])
alpha: float = 1.0
group: np.array = GROUP['pillar']
is_lidar_observed: bool = True
Expand Down
4 changes: 2 additions & 2 deletions safety_gymnasium/assets/geoms/sigwalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# ==============================================================================
"""Hazard."""

from dataclasses import dataclass
from dataclasses import dataclass, field

import numpy as np

Expand All @@ -37,7 +37,7 @@ class Sigwalls(Geom): # pylint: disable=too-many-instance-attributes
placements: list = None
keepout: float = 0.0

color: np.array = COLOR['sigwall']
color: np.array = field(default_factory=lambda: COLOR['sigwall'])
alpha: float = 0.1
group: np.array = GROUP['sigwall']
is_lidar_observed: bool = False
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/geoms/walls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Walls(Geom): # pylint: disable=too-many-instance-attributes
locations: list = field(default_factory=list) # This should be used and length == walls_num
keepout: float = 0.0 # This should not be used

color: np.array = COLOR['wall']
color: np.array = field(default_factory=lambda: COLOR['wall'])
group: np.array = GROUP['wall']
is_lidar_observed: bool = True
is_constrained: bool = False
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/mocaps/gremlins.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Gremlins(Mocap): # pylint: disable=too-many-instance-attributes
dist_cost: float = 1.0 # Cost for being within distance threshold
density: float = 0.001

color: np.array = COLOR['gremlin']
color: np.array = field(default_factory=lambda: COLOR['gremlin'])
alpha: float = 1
group: np.array = GROUP['gremlin']
is_lidar_observed: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/assets/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Robot: # pylint: disable=too-many-instance-attributes
placements: list = None # Robot placements list (defaults to full extents)
locations: list = field(default_factory=list) # Explicitly place robot XY coordinate
keepout: float = 0.4 # Needs to be set to match the robot XML used
base: str = 'assets/xmls/car.xml' # Which robot XML to use as the base
base: str = os.path.join('assets', 'xmls', 'car.xml') # Which robot XML to use as the base
rot: float = None # Override robot starting angle

def __post_init__(self, path) -> None:
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/bases/base_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def __init__( # pylint: disable=too-many-arguments
keepout (float): Needs to be set to match the agent XML used.
rot (float): Override agent starting angle.
"""
self.base: str = f'assets/xmls/{name.lower()}.xml'
self.base: str = os.path.join('assets', 'xmls', f'{name.lower()}.xml')
self.random_generator: RandomGenerator = random_generator
self.placements: list = placements
self.locations: list = [] if locations is None else locations
Expand Down
8 changes: 5 additions & 3 deletions safety_gymnasium/bases/underlying.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class RenderConf:
r"""Render options.

Attributes:
libels (bool): Whether to render labels.
labels (bool): Whether to render labels.
lidar_markers (bool): Whether to render lidar markers.
lidar_radius (float): Radius of the lidar markers.
lidar_size (float): Size of the lidar markers.
Expand Down Expand Up @@ -482,7 +482,7 @@ def _render_sphere(
def render(
self,
width: int,
height: int,
height: int,
mode: str,
camera_id: int | None = None,
camera_name: str | None = None,
Expand Down Expand Up @@ -577,7 +577,9 @@ def _get_viewer(
self.agent.keyboard_control_callback,
)
elif mode in {'rgb_array', 'depth_array'}:
self.viewer = OffScreenViewer(self.model, self.data)
self.viewer = OffScreenViewer(self.model, self.data,
self.model.vis.global_.offwidth,
self.model.vis.global_.offheight)
else:
raise AttributeError(f'Unexpected mode: {mode}')

Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class PushBox(FreeGeom): # pylint: disable=too-many-instance-attributes
reward_box_dist: float = 1.0 # Dense reward for moving the agent towards the box
reward_box_goal: float = 1.0 # Reward for moving the box towards the goal

color: np.array = COLOR['push_box']
color: np.array = field(default_factory=lambda: COLOR['push_box'])
group: np.array = GROUP['push_box']
is_lidar_observed: bool = True
is_comp_observed: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class Vases(FreeGeom): # pylint: disable=too-many-instance-attributes
velocity_threshold: float = 1e-4 # Ignore very small velocities
last_contact: dict = field(default_factory=lambda: {f'vase{i}': 0 for i in range(20)})

color: np.array = COLOR['vase']
color: np.array = field(default_factory=lambda: COLOR['vase'])
group: np.array = GROUP['vase']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import numpy as np


from safety_gymnasium.tasks.safe_multi_agent.assets.color import COLOR
from safety_gymnasium.tasks.safe_multi_agent.assets.group import GROUP
from safety_gymnasium.tasks.safe_multi_agent.bases.base_object import Geom
Expand All @@ -44,7 +45,7 @@ class Apples(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['apple']
color: np.array = field(default_factory=lambda: COLOR['apple'])
group: np.array = GROUP['apple']
is_lidar_observed: bool = True
is_constrained: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class Buttons(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['button']
color: np.array = field(default_factory=lambda: COLOR['button'])
group: np.array = GROUP['button']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# ==============================================================================
"""Circle."""

from dataclasses import dataclass
from dataclasses import dataclass, field

import numpy as np

Expand All @@ -33,7 +33,7 @@ class Circle(Geom): # pylint: disable=too-many-instance-attributes
locations: tuple = ((0, 0),)
keepout: float = 0.0

color: np.array = COLOR['circle']
color: np.array = field(default_factory=lambda: COLOR['circle'])
group: np.array = GROUP['circle']
is_lidar_observed: bool = True
is_constrained: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class Goal(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['goal']
color: np.array = field(default_factory=lambda: COLOR['goal'])
group: np.array = GROUP['goal']
is_lidar_observed: bool = True
is_comp_observed: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Hazards(Geom): # pylint: disable=too-many-instance-attributes
alpha: float = COLOR['hazard'][-1]
cost: float = 1.0 # Cost (per step) for violating the constraint

color: np.array = COLOR['hazard']
color: np.array = field(default_factory=lambda: COLOR['hazard'])
group: np.array = GROUP['hazard']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Oranges(Geom): # pylint: disable=too-many-instance-attributes
# if reward_distance is 0, then the reward function is sparse
reward_distance: float = 1.0 # Dense reward multiplied by the distance moved to the goal

color: np.array = COLOR['orange']
color: np.array = field(default_factory=lambda: COLOR['orange'])
group: np.array = GROUP['orange']
is_lidar_observed: bool = True
is_constrained: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Pillars(Geom): # pylint: disable=too-many-instance-attributes
keepout: float = 0.3 # Radius for placement of pillars
cost: float = 1.0 # Cost (per step) for being in contact with a pillar

color: np.array = COLOR['pillar']
color: np.array = field(default_factory=lambda: COLOR['pillar'])
group: np.array = GROUP['pillar']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# ==============================================================================
"""Hazard."""

from dataclasses import dataclass
from dataclasses import dataclass, field

import numpy as np

Expand All @@ -34,7 +34,7 @@ class Sigwalls(Geom): # pylint: disable=too-many-instance-attributes
placements: list = None
keepout: float = 0.0

color: np.array = COLOR['sigwall']
color: np.array = field(default_factory=lambda: COLOR['sigwall'])
group: np.array = GROUP['sigwall']
is_lidar_observed: bool = False
is_constrained: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class Walls(Geom): # pylint: disable=too-many-instance-attributes
locations: list = field(default_factory=list) # This should be used and length == walls_num
keepout: float = 0.0 # This should not be used

color: np.array = COLOR['wall']
color: np.array = field(default_factory=lambda: COLOR['wall'])
group: np.array = GROUP['wall']
is_lidar_observed: bool = True
is_constrained: bool = False
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class Gremlins(Mocap): # pylint: disable=too-many-instance-attributes
dist_cost: float = 1.0 # Cost for being within distance threshold
density: float = 0.001

color: np.array = COLOR['gremlin']
color: np.array = field(default_factory=lambda: COLOR['gremlin'])
group: np.array = GROUP['gremlin']
is_lidar_observed: bool = True
is_constrained: bool = True
Expand Down
2 changes: 1 addition & 1 deletion safety_gymnasium/tasks/safe_multi_agent/assets/robot.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class Robot: # pylint: disable=too-many-instance-attributes
placements: list = None # Robot placements list (defaults to full extents)
locations: list = field(default_factory=list) # Explicitly place robot XY coordinate
keepout: float = 0.4 # Needs to be set to match the robot XML used
base: str = 'assets/xmls/car.xml' # Which robot XML to use as the base
base: str = os.path.join('assets', 'xmls', 'car.xml') # Which robot XML to use as the base
rot: float = None # Override robot starting angle

def __post_init__(self, path) -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def __init__( # pylint: disable=too-many-arguments
keepout (float): Needs to be set to match the agent XML used.
rot (float): Override agent starting angle.
"""
self.base: str = f'assets/xmls/multi_{name.lower()}.xml'
self.base: str = os.path.join('assets', 'xmls', f'multi_{name.lower()}.xml')
self.random_generator: RandomGenerator = random_generator
self.placements: list = placements
self.locations: list = [] if locations is None else locations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def __init__( # pylint: disable=too-many-arguments
render_mode,
**kwargs,
)
self.env.single_agent_env.model.light(0).castshadow = False
self.env.single_agent_env.unwrapped.model.light(0).castshadow = False

def __getattr__(self, name: str) -> Any:
"""Returns an attribute with ``name``, unless ``name`` starts with an underscore."""
Expand All @@ -97,7 +97,7 @@ def step(self, action):
for agents in self.env.possible_agents:
costs[agents] = cost_n

viewer = self.env.single_agent_env.mujoco_renderer.viewer
viewer = self.env.single_agent_env.unwrapped.mujoco_renderer.viewer
if viewer:
clear_viewer(viewer)
add_velocity_marker(
Expand Down
Loading