Skip to content

Commit 4c1c23a

Browse files
committed
Merge dev into main branch
2 parents ab59746 + ba11b17 commit 4c1c23a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+6380
-1116
lines changed

.github/workflows/test_solution.yml

+6-10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches:
66
- master
77
- main
8+
workflow_dispatch:
89

910

1011
jobs:
@@ -25,22 +26,17 @@ jobs:
2526
bash
2627
cache-environment: true
2728
post-cleanup: 'all'
28-
# - run: |
29-
# pip install setuptools==65.5.0 pip==21
30-
# pip install wheel==0.38.0
31-
- name: Install safe-control-gym
32-
run: |
33-
git clone -b beta-iros-competition https://github.com/utiasDSL/safe-control-gym.git
34-
cd safe-control-gym
35-
pip install . --no-deps
36-
cd ..
37-
shell: bash -el {0}
3829
- name: Install cffirmware
3930
run: |
4031
git clone https://github.com/utiasDSL/pycffirmware.git
4132
cd pycffirmware
4233
git submodule update --init --recursive
4334
./wrapper/build_linux.sh
35+
- name: Install stable baselines
36+
run: pip install stable-baselines3
37+
shell: bash -el {0}
38+
- name: Install stable baselines
39+
run: pip install stable-baselines3
4440
shell: bash -el {0}
4541
- run: pip install .
4642
shell: bash -el {0}

.gitignore

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,8 @@
22
**.egg-info/
33
**/__pycache__/
44
submission.csv
5-
logs
5+
logs
6+
secrets
7+
**/*.secret
8+
saves
9+
.pytest_cache

.readthedocs.yaml

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# .readthedocs.yaml
2+
# Read the Docs configuration file
3+
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
4+
5+
# Required
6+
version: 2
7+
8+
build:
9+
os: ubuntu-20.04
10+
tools:
11+
python: "3.8"
12+
13+
sphinx:
14+
configuration: docs/conf.py
15+
16+
python:
17+
install:
18+
- requirements: docs/requirements.txt

README.md

+37-23
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- [Setting up your GitHub repo for the competition](#setting-up-your-github-repo-for-the-competition)
1616
- [Submitting your latest iteration](#submitting-your-latest-iteration)
1717
- [Creating your own controller](#creating-your-own-controller)
18+
- [Common errors](#common-errors)
1819
- [Deployment (**NOT IMPORTANT FOR STUDENTS FOR NOW**)](#deployment-not-important-for-students-for-now)
1920
- [Hardware setup](#hardware-setup)
2021
- [Common errors](#common-errors)
@@ -26,10 +27,9 @@
2627

2728
## Installation
2829

29-
To run the LSY Autonomous Drone Racing project, you will need 3 main repositories:
30-
- [safe-control-gym](https://github.com/utiasDSL/safe-control-gym/tree/beta-iros-competition) - `beta-iros-competition` branch: The drone simulator and gym environments
30+
To run the LSY Autonomous Drone Racing project, you will need 2 repositories:
3131
- [pycffirmware](https://github.com/utiasDSL/pycffirmware) - `main` branch: A simulator for the on-board controller response of the drones we are using to accurately model their behavior
32-
- [lsy_drone_racing](https://github.com/utiasDSL/lsy_drone_racing) - `main` branch: This repository contains the scripts to simulate and deploy the drones in the racing challenge
32+
- [lsy_drone_racing](https://github.com/utiasDSL/lsy_drone_racing) - `main` branch: This repository contains the drone simulation, environments, and scripts to simulate and deploy the drones in the racing challenge
3333

3434
### Fork lsy_drone_racing
3535

@@ -51,21 +51,14 @@ conda activate drone
5151
```
5252

5353
> **Note:** It is important you stick with **Python 3.8**. Yes, it is outdated. Yes, we'd also like to upgrade. However, there are serious issues beyond our control when deploying the code on the real drones with any other version.
54-
55-
Next, download the `safe-control-gym` and `pycffirmware` repositories and install them. Make sure you have your conda/mamba environment active!
54+
Now you can install the lsy_drone_racing package in editable mode from the repository root
5655

5756
```bash
58-
cd ~/repos
59-
git clone -b beta-iros-competition https://github.com/utiasDSL/safe-control-gym.git
60-
cd safe-control-gym
61-
pip install .
57+
cd ~/repos/lsy_drone_racing
58+
pip install --upgrade pip
59+
pip install -e .
6260
```
63-
64-
> **Note:** If you receive an error installing safe-control-gym related to gym==0.21.0, run
65-
> ```bash
66-
> pip install setuptools==65.5.0 pip==21 wheel==0.38.4
67-
> ```
68-
> first
61+
In addition, you also need to install the pycffirmware package from source with
6962

7063
```bash
7164
cd ~/repos
@@ -78,14 +71,6 @@ conda install swig
7871
./wrapper/build_linux.sh
7972
```
8073

81-
Now you can install the lsy_drone_racing package in editable mode from the repository root
82-
83-
```bash
84-
cd ~/repos/lsy_drone_racing
85-
pip install --upgrade pip
86-
pip install -e .
87-
```
88-
8974
Finally, you can test if the installation was successful by running
9075

9176
```bash
@@ -153,6 +138,35 @@ Once you have pushed your latest iteration, a GitHub action runner will start te
153138

154139
To implement your own controller, have a look at the [example implementation](./examples/controller.py). We recommend altering the existing example controller instead of creating your own file to not break the testing pipeline. Please also read through the documentation of the controller. You **must not** alter its function signatures. If you encounter problems implementing something with the given interface, contact one of the lecturers.
155140

141+
## Common errors
142+
143+
### GLIBCXX
144+
If you were able to install everything without any issues, but the simulation crashes when running the sim script, you should check the error messages for any errors related to `LIBGL` and `GLIBCXX_3.4.30`. If you don't find any conclusive evidence about what has happened, you might also want to run the simulation in verbose mode for `LIBGL` with
145+
146+
```bash
147+
LIBGL_DEBUG=verbose python scripts/sim.py
148+
```
149+
150+
Next, you should check if your system has the required library installed
151+
152+
```bash
153+
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.30
154+
```
155+
156+
or if it is installed in your conda environment
157+
158+
```bash
159+
strings /path-to-your-conda/envs/your-env-name/lib/libstdc++.so.6 | grep GLIBCXX_3.4.30
160+
```
161+
162+
If neither of those yield any results, you are missing this library and can install it with
163+
164+
```bash
165+
conda install -c conda-forge gcc=12.1.0
166+
```
167+
168+
If the program still crashes and complains about not finding `GLIBCXX_3.4.30`, please update your `LD_LIBRARY_PATH` variable to point to your conda environment's lib folder.
169+
156170
## Deployment (**NOT IMPORTANT FOR STUDENTS FOR NOW**)
157171

158172
### Hardware setup

benchmarks/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Benchmarks
2+
3+
These benchmarks are intended to test the performance of the implementation, i.e. speed and memory consumption. They are not meant to benchmark different approaches, algorithms or agents in the race task!
4+
5+
## Profiling
6+
To profile the simulation, use [pyinstrument](https://github.com/joerick/pyinstrument) and run
7+
8+
>: pyinstrument -r html profile.py

benchmarks/config/test.toml

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
[sim]
2+
physics = "pyb" # pyb: PyBullet, dyn: Mathematical dynamics model, TODO: Complete the list
3+
camera_view = [5.0, -40.0, -40.0, 0.5, -1.0, 0.5]
4+
sim_freq = 500 # Simulation frequency, in Hz
5+
ctrl_freq = 500 # Controller frequency, in Hz. This frequency is used to simulate the onboard controller, NOT for the environment's step function
6+
gui = false # Enable/disable PyBullet's GUI
7+
8+
[sim.disturbances.action]
9+
type = "GaussianNoise"
10+
std = 0.001
11+
12+
[sim.disturbances.dynamics]
13+
type = "UniformNoise"
14+
low = [-0.1, -0.1, -0.1]
15+
high = [0.1, 0.1, 0.1]
16+
17+
[env]
18+
reseed = false # Whether to re-seed the random number generator between episodes
19+
seed = 1337 # Random seed
20+
freq = 30 # Frequency of the environment's step function, in Hz
21+
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.
22+
23+
[env.track]
24+
# Tall gates: 1.0m height. Short gates: 0.525m height. Height is measured from the ground to the
25+
# center of the gate.
26+
[[env.track.gates]]
27+
pos = [0.45, -1.0, 0.525]
28+
rpy = [0.0, 0.0, 2.35]
29+
[[env.track.gates]]
30+
pos = [1.0, -1.55, 1.0]
31+
rpy = [0.0, 0.0, -0.78]
32+
[[env.track.gates]]
33+
pos = [0.0, 0.5, 0.525]
34+
rpy = [0.0, 0.0, 0.0]
35+
[[env.track.gates]]
36+
pos = [-0.5, -0.5, 1.0]
37+
rpy = [0.0, 0.0, 3.14]
38+
39+
# Obstacle height: 1.05m. Height is measured from the ground to the top of the obstacle.
40+
[[env.track.obstacles]]
41+
pos = [1.0, -0.5, 1.05]
42+
[[env.track.obstacles]]
43+
pos = [0.5, -1.5, 1.05]
44+
[[env.track.obstacles]]
45+
pos = [-0.5, 0.0, 1.05]
46+
[[env.track.obstacles]]
47+
pos = [0.0, 1.0, 1.05]
48+
49+
[env.track.drone]
50+
pos = [1.0, 1.0, 0.05]
51+
rpy = [0, 0, 0]
52+
vel = [0, 0, 0]
53+
ang_vel = [0, 0, 0]
54+
55+
[env.randomization.drone_pos]
56+
type = "uniform" # Everything that can be used as a distribution in numpy.random
57+
# Kwargs that are permissable in the np random function
58+
low = [-0.1, -0.1, 0.0]
59+
high = [0.1, 0.1, 0.02]
60+
61+
[env.randomization.drone_rpy]
62+
type = "uniform"
63+
low = [-0.1, -0.1, -0.1]
64+
high = [0.1, 0.1, 0.1]
65+
66+
[env.randomization.drone_mass]
67+
type = "uniform"
68+
low = -0.01
69+
high = 0.01
70+
71+
[env.randomization.drone_inertia]
72+
type = "uniform"
73+
low = [-0.000001, -0.000001, -0.000001]
74+
high = [0.000001, 0.000001, 0.000001]
75+
76+
[env.randomization.gate_pos]
77+
type = "uniform"
78+
low = [-0.1, -0.1, 0.0]
79+
high = [0.1, 0.1, 0.0]
80+
81+
[env.randomization.gate_rpy]
82+
type = "uniform"
83+
low = [0.0, 0.0, -0.1]
84+
high = [0.0, 0.0, 0.1]
85+
86+
[env.randomization.obstacle_pos]
87+
type = "uniform"
88+
low = [-0.1, -0.1, 0.0]
89+
high = [0.1, 0.1, 0.0]
90+
91+
[[env.constraints]]
92+
type = "DefaultConstraint"
93+
ctype = "input"
94+
[[env.constraints]]
95+
type = "BoundedConstraint"
96+
ctype = "state"
97+
active_dims = [0, 2, 4]
98+
upper_bounds = [3, 3, 2]
99+
lower_bounds = [-3.0, -3.0, -0.1]

benchmarks/main.py

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
from __future__ import annotations
2+
3+
import numpy as np
4+
from sim import time_sim_reset, time_sim_step
5+
6+
7+
def print_benchmark_results(name: str, timings: list[float]):
8+
print(f"\nResults for {name}:")
9+
print(f"Mean/std: {np.mean(timings):.2e}s +- {np.std(timings):.2e}s")
10+
print(f"Min time: {np.min(timings):.2e}s")
11+
print(f"Max time: {np.max(timings):.2e}s")
12+
13+
14+
if __name__ == "__main__":
15+
timings = time_sim_reset(n_tests=10)
16+
print_benchmark_results(name="Sim reset", timings=timings)
17+
sim_steps = 10
18+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps)
19+
print_benchmark_results(name="Sim steps", timings=timings / sim_steps)
20+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="dyn")
21+
print_benchmark_results(name="Sim steps (dyn backend)", timings=timings / sim_steps)
22+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_gnd")
23+
print_benchmark_results(name="Sim steps (pyb_gnd backend)", timings=timings / sim_steps)
24+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_drag")
25+
print_benchmark_results(name="Sim steps (pyb_drag backend)", timings=timings / sim_steps)
26+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_dw")
27+
print_benchmark_results(name="Sim steps (pyb_dw backend)", timings=timings / sim_steps)
28+
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_gnd_drag_dw")
29+
print_benchmark_results(name="Sim steps (pyb_gnd_drag_dw backend)", timings=timings / sim_steps)

benchmarks/profile.py

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from pathlib import Path
2+
3+
import gymnasium
4+
5+
import lsy_drone_racing # noqa: F401, required for gymnasium.make
6+
from lsy_drone_racing.utils import load_config
7+
8+
9+
def main():
10+
config = load_config(Path(__file__).parent / "config/test.toml")
11+
env = gymnasium.make("DroneRacing-v0", config=config)
12+
env.reset()
13+
for _ in range(1000):
14+
env.step(env.action_space.sample())
15+
# 0.455
16+
17+
18+
if __name__ == "__main__":
19+
main()

benchmarks/sim.py

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from __future__ import annotations
2+
3+
import timeit
4+
from pathlib import Path
5+
from typing import TYPE_CHECKING
6+
7+
import numpy as np
8+
9+
if TYPE_CHECKING:
10+
import numpy.typing as npt
11+
12+
load_config_code = f"""
13+
from pathlib import Path
14+
15+
from lsy_drone_racing.utils import load_config
16+
17+
config = load_config(Path('{Path(__file__).parent / "config/test.toml"}'))
18+
19+
"""
20+
env_setup_code = """
21+
import gymnasium
22+
23+
import lsy_drone_racing
24+
25+
env = gymnasium.make('DroneRacing-v0', config=config)
26+
27+
"""
28+
29+
30+
def time_sim_reset(n_tests: int = 10) -> npt.NDArray[np.floating]:
31+
setup = load_config_code + env_setup_code
32+
stmt = """env.reset()"""
33+
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))
34+
35+
36+
def time_sim_step(
37+
n_tests: int = 10, sim_steps: int = 100, physics_mode: str = "pyb"
38+
) -> npt.NDArray[np.floating]:
39+
modify_config_code = f"""config.sim.physics = '{physics_mode}'\n"""
40+
setup = load_config_code + modify_config_code + env_setup_code + "\nenv.reset()"
41+
stmt = f"""
42+
for _ in range({sim_steps}):
43+
env.step(env.action_space.sample())"""
44+
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))

0 commit comments

Comments
 (0)