Skip to content

Commit 493e8f0

Browse files
committed
Implement vectorized, multi-drone core race env.
Add specialized environments based off of RaceCoreEnv. Switch from rpy_rates to ang_vel
1 parent 20cbbce commit 493e8f0

15 files changed

+368
-1466
lines changed

benchmarks/sim.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@
7676
import jax
7777
7878
import lsy_drone_racing
79+
from lsy_drone_racing.envs.multi_drone_race import MultiDroneRaceEnv
7980
8081
env = gymnasium.make('MultiDroneRacing-v0',
81-
n_envs=1, # TODO: Remove this for single-world envs
8282
n_drones=config.env.n_drones,
8383
freq=config.env.freq,
8484
sim_config=config.sim,
@@ -98,7 +98,7 @@
9898
# JIT masked reset (used in autoreset)
9999
mask = env.unwrapped.data.marked_for_reset
100100
mask = mask.at[0].set(True)
101-
env.unwrapped.reset(mask=mask)
101+
super(MultiDroneRaceEnv, env.unwrapped).reset(mask=mask) # enforce masked reset compile
102102
jax.block_until_ready(env.unwrapped.data)
103103
env.action_space.seed(2)
104104
"""

config/level0.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ pos = [0.0, 1.0, 1.4]
7474
pos = [1.0, 1.0, 0.05]
7575
rpy = [0, 0, 0]
7676
vel = [0, 0, 0]
77-
rpy_rates = [0, 0, 0]
77+
ang_vel = [0, 0, 0]

config/level1.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pos = [0.0, 1.0, 1.4]
6161
pos = [1.0, 1.0, 0.05]
6262
rpy = [0, 0, 0]
6363
vel = [0, 0, 0]
64-
rpy_rates = [0, 0, 0]
64+
ang_vel = [0, 0, 0]
6565

6666
[env.disturbances.action]
6767
fn = "normal"

config/level2.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pos = [0.0, 1.0, 1.4]
6161
pos = [1.0, 1.0, 0.05]
6262
rpy = [0, 0, 0]
6363
vel = [0, 0, 0]
64-
rpy_rates = [0, 0, 0]
64+
ang_vel = [0, 0, 0]
6565

6666
[env.disturbances.action]
6767
fn = "normal"

config/level3.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ pos = [-0.5, 0.0, 1.4]
6161
pos = [1.0, 1.0, 0.07]
6262
rpy = [0, 0, 0]
6363
vel = [0, 0, 0]
64-
rpy_rates = [0, 0, 0]
64+
ang_vel = [0, 0, 0]
6565

6666
[env.disturbances.action]
6767
fn = "normal"

config/multi_level0.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,4 @@ pos = [0.0, 1.0, 1.4]
6666
pos = [[1.0, 1.0, 0.05], [1.2, 1.0, 0.05]]
6767
rpy = [[0, 0, 0], [0, 0, 0]]
6868
vel = [[0, 0, 0], [0, 0, 0]]
69-
rpy_rates = [[0, 0, 0], [0, 0, 0]]
69+
ang_vel = [[0, 0, 0], [0, 0, 0]]

config/multi_level3.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ pos = [0.0, 1.0, 1.4]
6666
pos = [[1.0, 1.0, 0.05], [1.2, 1.0, 0.05]]
6767
rpy = [[0, 0, 0], [0, 0, 0]]
6868
vel = [[0, 0, 0], [0, 0, 0]]
69-
rpy_rates = [[0, 0, 0], [0, 0, 0]]
69+
ang_vel = [[0, 0, 0], [0, 0, 0]]
7070

7171
[env.disturbances.action]
7272
fn = "normal"

lsy_drone_racing/envs/__init__.py

+16-14
Original file line numberDiff line numberDiff line change
@@ -15,44 +15,46 @@
1515

1616
from gymnasium import register
1717

18-
from lsy_drone_racing.envs.drone_racing_env import DroneRacingEnv
19-
20-
__all__ = ["DroneRacingEnv"]
18+
# region SingleDroneEnvs
2119

2220
register(
2321
id="DroneRacing-v0",
24-
entry_point="lsy_drone_racing.envs.drone_racing_env:DroneRacingEnv",
22+
entry_point="lsy_drone_racing.envs.drone_race:DroneRaceEnv",
23+
vector_entry_point="lsy_drone_racing.envs.drone_race:VecDroneRaceEnv",
2524
max_episode_steps=1800, # 30 seconds * 60 Hz,
2625
disable_env_checker=True, # Remove warnings about 2D observations
2726
)
2827

2928
register(
3029
id="DroneRacingAttitude-v0",
31-
entry_point="lsy_drone_racing.envs.drone_racing_env:DroneRacingAttitudeEnv",
30+
entry_point="lsy_drone_racing.envs.drone_race:DroneRaceAttitudeEnv",
31+
vector_entry_point="lsy_drone_racing.envs.drone_race:VecDroneRaceAttitudeEnv",
3232
max_episode_steps=1800,
3333
disable_env_checker=True,
3434
)
3535

36+
# region MultiDroneEnvs
37+
3638
register(
37-
id="DroneRacingDeploy-v0",
38-
entry_point="lsy_drone_racing.envs.drone_racing_deploy_env:DroneRacingDeployEnv",
39+
id="MultiDroneRacing-v0",
40+
entry_point="lsy_drone_racing.envs.multi_drone_race:MultiDroneRaceEnv",
41+
vector_entry_point="lsy_drone_racing.envs.multi_drone_race:VecMultiDroneRaceEnv",
3942
max_episode_steps=1800,
4043
disable_env_checker=True,
4144
)
4245

46+
# region DeployEnvs
47+
4348
register(
44-
id="DroneRacingAttitudeDeploy-v0",
45-
entry_point="lsy_drone_racing.envs.drone_racing_deploy_env:DroneRacingAttitudeDeployEnv",
49+
id="DroneRacingDeploy-v0",
50+
entry_point="lsy_drone_racing.envs.drone_racing_deploy_env:DroneRacingDeployEnv",
4651
max_episode_steps=1800,
4752
disable_env_checker=True,
4853
)
4954

50-
# region MultiEnvs
51-
52-
# TODO: Register specialized, non-vectorized envs for single worlds
5355
register(
54-
id="MultiDroneRacing-v0",
55-
entry_point="lsy_drone_racing.envs.vec_drone_race:VectorMultiDroneRaceEnv",
56+
id="DroneRacingAttitudeDeploy-v0",
57+
entry_point="lsy_drone_racing.envs.drone_racing_deploy_env:DroneRacingAttitudeDeployEnv",
5658
max_episode_steps=1800,
5759
disable_env_checker=True,
5860
)

lsy_drone_racing/envs/drone_race.py

+110
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
"""Single drone racing environments."""
2+
3+
from __future__ import annotations
4+
5+
from typing import TYPE_CHECKING, Literal
6+
7+
from gymnasium import Env
8+
from gymnasium.vector import VectorEnv
9+
from gymnasium.vector.utils import batch_space
10+
11+
from lsy_drone_racing.envs.race_core import RaceCoreEnv, action_space, observation_space
12+
13+
if TYPE_CHECKING:
14+
import numpy as np
15+
from ml_collections import ConfigDict
16+
from numpy.typing import NDArray
17+
18+
19+
class DroneRaceEnv(RaceCoreEnv, Env):
20+
def __init__(
21+
self,
22+
freq: int,
23+
sim_config: ConfigDict,
24+
sensor_range: float,
25+
track: ConfigDict | None = None,
26+
disturbances: ConfigDict | None = None,
27+
randomizations: ConfigDict | None = None,
28+
random_resets: bool = False,
29+
seed: int = 1337,
30+
max_episode_steps: int = 1500,
31+
device: Literal["cpu", "gpu"] = "cpu",
32+
):
33+
super().__init__(
34+
n_envs=1,
35+
n_drones=1,
36+
freq=freq,
37+
sim_config=sim_config,
38+
sensor_range=sensor_range,
39+
track=track,
40+
disturbances=disturbances,
41+
randomizations=randomizations,
42+
random_resets=random_resets,
43+
seed=seed,
44+
max_episode_steps=max_episode_steps,
45+
device=device,
46+
)
47+
self.action_space = action_space("state")
48+
n_gates, n_obstacles = len(track.gates), len(track.obstacles)
49+
self.observation_space = observation_space(n_gates, n_obstacles)
50+
self.autoreset = False
51+
52+
def reset(self, seed: int | None = None, options: dict | None = None) -> tuple[dict, dict]:
53+
obs, info = super().reset(seed=seed, options=options)
54+
obs = {k: v[0, 0] for k, v in obs.items()}
55+
info = {k: v[0, 0] for k, v in info.items()}
56+
return obs, info
57+
58+
def step(self, action: NDArray[np.floating]) -> tuple[dict, float, bool, bool, dict]:
59+
obs, reward, terminated, truncated, info = super().step(action)
60+
obs = {k: v[0, 0] for k, v in obs.items()}
61+
info = {k: v[0, 0] for k, v in info.items()}
62+
return obs, reward[0, 0], terminated[0, 0], truncated[0, 0], info
63+
64+
65+
class VecDroneRaceEnv(RaceCoreEnv, VectorEnv):
66+
def __init__(
67+
self,
68+
num_envs: int,
69+
freq: int,
70+
sim_config: ConfigDict,
71+
sensor_range: float,
72+
track: ConfigDict | None = None,
73+
disturbances: ConfigDict | None = None,
74+
randomizations: ConfigDict | None = None,
75+
random_resets: bool = False,
76+
seed: int = 1337,
77+
max_episode_steps: int = 1500,
78+
device: Literal["cpu", "gpu"] = "cpu",
79+
):
80+
super().__init__(
81+
n_envs=num_envs,
82+
n_drones=1,
83+
freq=freq,
84+
sim_config=sim_config,
85+
sensor_range=sensor_range,
86+
track=track,
87+
disturbances=disturbances,
88+
randomizations=randomizations,
89+
random_resets=random_resets,
90+
seed=seed,
91+
max_episode_steps=max_episode_steps,
92+
device=device,
93+
)
94+
self.single_action_space = action_space("state")
95+
self.action_space = batch_space(self.single_action_space, num_envs)
96+
n_gates, n_obstacles = len(track.gates), len(track.obstacles)
97+
self.single_observation_space = observation_space(n_gates, n_obstacles)
98+
self.observation_space = batch_space(self.single_observation_space, num_envs)
99+
100+
def reset(self, seed: int | None = None, options: dict | None = None) -> tuple[dict, dict]:
101+
obs, info = super().reset(seed=seed, options=options)
102+
obs = {k: v[:, 0] for k, v in obs.items()}
103+
info = {k: v[:, 0] for k, v in info.items()}
104+
return obs, info
105+
106+
def step(self, action: NDArray[np.floating]) -> tuple[dict, float, bool, bool, dict]:
107+
obs, reward, terminated, truncated, info = super().step(action)
108+
obs = {k: v[:, 0] for k, v in obs.items()}
109+
info = {k: v[:, 0] for k, v in info.items()}
110+
return obs, reward[:, 0], terminated[:, 0], truncated[:, 0], info

0 commit comments

Comments
 (0)