Skip to content

Commit b451fd1

Browse files
committed
Add multi drone env
1 parent 0822050 commit b451fd1

File tree

9 files changed

+1018
-136
lines changed

9 files changed

+1018
-136
lines changed

benchmarks/config/test.toml

-100
This file was deleted.

benchmarks/main.py

+15-9
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from __future__ import annotations
22

3+
import fire
34
import numpy as np
4-
from sim import time_sim_attitude_step, time_sim_reset, time_sim_step
5+
from sim import time_multi_drone_reset, time_multi_drone_step, time_sim_reset, time_sim_step
56

67

78
def print_benchmark_results(name: str, timings: list[float]):
@@ -12,16 +13,21 @@ def print_benchmark_results(name: str, timings: list[float]):
1213
print(f"FPS: {1 / np.mean(timings):.2f}")
1314

1415

15-
if __name__ == "__main__":
16-
n_tests = 10
17-
sim_steps = 10
18-
timings = time_sim_reset(n_tests=n_tests)
16+
def main(n_tests: int = 10, sim_steps: int = 10, multi_drone: bool = False):
17+
reset_fn, step_fn = time_sim_reset, time_sim_step
18+
if multi_drone:
19+
reset_fn, step_fn = time_multi_drone_reset, time_multi_drone_step
20+
timings = reset_fn(n_tests=n_tests)
1921
print_benchmark_results(name="Sim reset", timings=timings)
20-
timings = time_sim_step(n_tests=n_tests, sim_steps=sim_steps)
22+
timings = step_fn(n_tests=n_tests, sim_steps=sim_steps)
2123
print_benchmark_results(name="Sim steps", timings=timings / sim_steps)
22-
timings = time_sim_step(n_tests=n_tests, sim_steps=sim_steps, physics_mode="sys_id")
24+
timings = step_fn(n_tests=n_tests, sim_steps=sim_steps, physics_mode="sys_id")
2325
print_benchmark_results(name="Sim steps (sys_id backend)", timings=timings / sim_steps)
24-
timings = time_sim_step(n_tests=n_tests, sim_steps=sim_steps, physics_mode="mujoco")
26+
timings = step_fn(n_tests=n_tests, sim_steps=sim_steps, physics_mode="mujoco")
2527
print_benchmark_results(name="Sim steps (mujoco backend)", timings=timings / sim_steps)
26-
timings = time_sim_attitude_step(n_tests=n_tests, sim_steps=sim_steps)
28+
timings = step_fn(n_tests=n_tests, sim_steps=sim_steps, physics_mode="sys_id")
2729
print_benchmark_results(name="Sim steps (sys_id backend)", timings=timings / sim_steps)
30+
31+
32+
if __name__ == "__main__":
33+
fire.Fire(main)

benchmarks/sim.py

+76-4
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,75 @@
1414
1515
from lsy_drone_racing.utils import load_config
1616
17-
config = load_config(Path('{Path(__file__).parents[1] / "config/level0.toml"}'))
18-
17+
config = load_config(Path('{Path(__file__).parents[1] / "config/level3.toml"}'))
1918
"""
19+
2020
env_setup_code = """
2121
import gymnasium
2222
2323
import lsy_drone_racing
2424
25-
env = gymnasium.make('DroneRacing-v0', config=config)
25+
env = gymnasium.make(
26+
config.env.id,
27+
freq=config.env.freq,
28+
sim_config=config.sim,
29+
sensor_range=config.env.sensor_range,
30+
track=config.env.track,
31+
disturbances=config.env.get("disturbances"),
32+
randomizations=config.env.get("randomizations"),
33+
random_resets=config.env.random_resets,
34+
seed=config.env.seed,
35+
)
2636
env.reset()
2737
env.step(env.action_space.sample()) # JIT compile
2838
env.reset()
2939
"""
40+
3041
attitude_env_setup_code = """
3142
import gymnasium
3243
3344
import lsy_drone_racing
3445
35-
env = gymnasium.make('DroneRacingAttitude-v0', config=config)
46+
env = gymnasium.make('DroneRacingAttitude-v0',
47+
config.env.id,
48+
freq=config.env.freq,
49+
sim_config=config.sim,
50+
sensor_range=config.env.sensor_range,
51+
track=config.env.track,
52+
disturbances=config.env.get("disturbances"),
53+
randomizations=config.env.get("randomizations"),
54+
random_resets=config.env.random_resets,
55+
seed=config.env.seed,
56+
)
57+
env.reset()
58+
env.step(env.action_space.sample()) # JIT compile
59+
env.reset()
60+
"""
61+
62+
load_multi_drone_config_code = f"""
63+
from pathlib import Path
64+
65+
from lsy_drone_racing.utils import load_config
66+
67+
config = load_config(Path('{Path(__file__).parents[1] / "config/multi_level0.toml"}'))
68+
"""
69+
70+
multi_drone_env_setup_code = """
71+
import gymnasium
72+
73+
import lsy_drone_racing
74+
75+
env = gymnasium.make('MultiDroneRacing-v0',
76+
n_drones=config.env.n_drones,
77+
freq=config.env.freq,
78+
sim_config=config.sim,
79+
sensor_range=config.env.sensor_range,
80+
track=config.env.track,
81+
disturbances=config.env.get("disturbances"),
82+
randomizations=config.env.get("randomizations"),
83+
random_resets=config.env.random_resets,
84+
seed=config.env.seed,
85+
)
3686
env.reset()
3787
env.step(env.action_space.sample()) # JIT compile
3888
env.reset()
@@ -62,3 +112,25 @@ def time_sim_attitude_step(n_tests: int = 10, sim_steps: int = 100) -> NDArray[n
62112
for _ in range({sim_steps}):
63113
env.step(env.action_space.sample())"""
64114
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))
115+
116+
117+
def time_multi_drone_reset(n_tests: int = 10) -> NDArray[np.floating]:
118+
setup = load_multi_drone_config_code + multi_drone_env_setup_code + "\nenv.reset()"
119+
stmt = """env.reset()"""
120+
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))
121+
122+
123+
def time_multi_drone_step(
124+
n_tests: int = 10, sim_steps: int = 100, physics_mode: str = "analytical"
125+
) -> NDArray[np.floating]:
126+
modify_config_code = f"""config.sim.physics = '{physics_mode}'\n"""
127+
setup = (
128+
load_multi_drone_config_code
129+
+ modify_config_code
130+
+ multi_drone_env_setup_code
131+
+ "\nenv.reset()"
132+
)
133+
stmt = f"""
134+
for _ in range({sim_steps}):
135+
env.step(env.action_space.sample())"""
136+
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))

config/multi_level0.toml

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Level 0
2+
3+
# | Evaluation Scenario | Rand. Inertial Properties | Randomized Obstacles, Gates | Rand. Between Episodes | Notes |
4+
# | :-----------------: | :-----------------------: | :-------------------------: | :--------------------: | :---------------: |
5+
# | `level0.toml` | *No* | *No* | *No* | Perfect knowledge |
6+
[controller]
7+
file = "trajectory_controller.py" # Put your controller file name here. Specifying a controller as argument to scripts will override this setting. Controllers are located in `lsy_drone_racing/control/`
8+
9+
[deploy]
10+
### Settings only relevant for deployment
11+
# Whether to check if gate and obstacle positions observed by vicon are within the limits defined down below.
12+
check_race_track = true
13+
# Whether to check if the drone start position is within the limits specified down below.
14+
check_drone_start_pos = true
15+
# Lets you practice your controller without putting up gates & obstacles, assumes nominal positions given below.
16+
practice_without_track_objects = false
17+
18+
[sim]
19+
# Physics options:
20+
# "analytical": Analytical, simplified dynamics model
21+
# "mujoco": Mujoco dynamics. May take longer to compile at startup.
22+
# "sys_id": System identification model.
23+
physics = "analytical"
24+
25+
camera_view = [5.0, -40.0, -40.0, 0.5, -1.0, 0.5]
26+
freq = 500 # Simulation frequency, in Hz
27+
attitude_freq = 500 # Controller frequency, in Hz. This frequency is used to simulate the onboard controller, NOT for the environment's step function
28+
gui = false # Enable/disable PyBullet's GUI
29+
30+
[sim.disturbances.action]
31+
type = "GaussianNoise"
32+
std = 0.001
33+
34+
[sim.disturbances.dynamics]
35+
type = "UniformNoise"
36+
low = [-0.1, -0.1, -0.1]
37+
high = [0.1, 0.1, 0.1]
38+
39+
[env]
40+
id = "MultiDroneRacing-v0" # Either "MultiDroneRacingEnv-v0" or "MultiDroneRacingAttitude-v0". If using "MultiDroneRacingAttitude-v0", the drone will use the attitude controller instead of the position controller.
41+
n_drones = 2 # Number of drones has to match the track configuration for drones
42+
random_resets = false # Whether to re-seed the random number generator between episodes
43+
seed = 1337 # Random seed
44+
freq = 50 # Frequency of the environment's step function, in Hz
45+
symbolic = false # Whether to include symbolic expressions in the info dict. Note: This can interfere with multiprocessing! If you want to parallelize your training, set this to false.
46+
sensor_range = 0.45 # Range at which the exact location of gates and obstacles become visible to the drone. Objects that are not in the drone's sensor range report their nominal position.
47+
48+
[env.track]
49+
# Tall gates: 1.0m height. Short gates: 0.525m height. Height is measured from the ground to the
50+
# center of the gate.
51+
[[env.track.gates]]
52+
pos = [0.45, -1.0, 0.56]
53+
rpy = [0.0, 0.0, 2.35]
54+
[[env.track.gates]]
55+
pos = [1.0, -1.55, 1.11]
56+
rpy = [0.0, 0.0, -0.78]
57+
[[env.track.gates]]
58+
pos = [0.0, 0.5, 0.56]
59+
rpy = [0.0, 0.0, 0.0]
60+
[[env.track.gates]]
61+
pos = [-0.5, -0.5, 1.11]
62+
rpy = [0.0, 0.0, 3.14]
63+
64+
# Obstacle height: 1.4m. Height is measured from the ground to the top of the obstacle.
65+
[[env.track.obstacles]]
66+
pos = [1.0, -0.5, 1.4]
67+
[[env.track.obstacles]]
68+
pos = [0.5, -1.5, 1.4]
69+
[[env.track.obstacles]]
70+
pos = [-0.5, 0.0, 1.4]
71+
[[env.track.obstacles]]
72+
pos = [0.0, 1.0, 1.4]
73+
74+
[env.track.drone]
75+
pos = [[1.0, 1.0, 0.05], [1.2, 1.0, 0.05]]
76+
rpy = [[0, 0, 0], [0, 0, 0]]
77+
vel = [[0, 0, 0], [0, 0, 0]]
78+
rpy_rates = [[0, 0, 0], [0, 0, 0]]

lsy_drone_racing/envs/__init__.py

+9
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,12 @@
4646
max_episode_steps=1800,
4747
disable_env_checker=True,
4848
)
49+
50+
# region MultiEnvs
51+
52+
register(
53+
id="MultiDroneRacing-v0",
54+
entry_point="lsy_drone_racing.envs.multi_drone_race:MultiDroneRacingEnv",
55+
max_episode_steps=1800,
56+
disable_env_checker=True,
57+
)

0 commit comments

Comments
 (0)