Skip to content

Commit

Permalink
Merge dev into main branch
Browse files Browse the repository at this point in the history
  • Loading branch information
amacati committed Jul 25, 2024
2 parents ab59746 + ba11b17 commit 4c1c23a
Show file tree
Hide file tree
Showing 66 changed files with 6,380 additions and 1,116 deletions.
16 changes: 6 additions & 10 deletions .github/workflows/test_solution.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
branches:
- master
- main
workflow_dispatch:


jobs:
Expand All @@ -25,22 +26,17 @@ jobs:
bash
cache-environment: true
post-cleanup: 'all'
# - run: |
# pip install setuptools==65.5.0 pip==21
# pip install wheel==0.38.0
- name: Install safe-control-gym
run: |
git clone -b beta-iros-competition https://github.com/utiasDSL/safe-control-gym.git
cd safe-control-gym
pip install . --no-deps
cd ..
shell: bash -el {0}
- name: Install cffirmware
run: |
git clone https://github.com/utiasDSL/pycffirmware.git
cd pycffirmware
git submodule update --init --recursive
./wrapper/build_linux.sh
- name: Install stable baselines
run: pip install stable-baselines3
shell: bash -el {0}
- name: Install stable baselines
run: pip install stable-baselines3
shell: bash -el {0}
- run: pip install .
shell: bash -el {0}
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@
**.egg-info/
**/__pycache__/
submission.csv
logs
logs
secrets
**/*.secret
saves
.pytest_cache
18 changes: 18 additions & 0 deletions .readthedocs.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# .readthedocs.yaml
# Read the Docs configuration file
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details

# Required
version: 2

build:
os: ubuntu-20.04
tools:
python: "3.8"

sphinx:
configuration: docs/conf.py

python:
install:
- requirements: docs/requirements.txt
60 changes: 37 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
- [Setting up your GitHub repo for the competition](#setting-up-your-github-repo-for-the-competition)
- [Submitting your latest iteration](#submitting-your-latest-iteration)
- [Creating your own controller](#creating-your-own-controller)
- [Common errors](#common-errors)
- [Deployment (**NOT IMPORTANT FOR STUDENTS FOR NOW**)](#deployment-not-important-for-students-for-now)
- [Hardware setup](#hardware-setup)
- [Common errors](#common-errors)
Expand All @@ -26,10 +27,9 @@

## Installation

To run the LSY Autonomous Drone Racing project, you will need 3 main repositories:
- [safe-control-gym](https://github.com/utiasDSL/safe-control-gym/tree/beta-iros-competition) - `beta-iros-competition` branch: The drone simulator and gym environments
To run the LSY Autonomous Drone Racing project, you will need 2 repositories:
- [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
- [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
- [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

### Fork lsy_drone_racing

Expand All @@ -51,21 +51,14 @@ conda activate drone
```

> **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.
Next, download the `safe-control-gym` and `pycffirmware` repositories and install them. Make sure you have your conda/mamba environment active!
Now you can install the lsy_drone_racing package in editable mode from the repository root

```bash
cd ~/repos
git clone -b beta-iros-competition https://github.com/utiasDSL/safe-control-gym.git
cd safe-control-gym
pip install .
cd ~/repos/lsy_drone_racing
pip install --upgrade pip
pip install -e .
```

> **Note:** If you receive an error installing safe-control-gym related to gym==0.21.0, run
> ```bash
> pip install setuptools==65.5.0 pip==21 wheel==0.38.4
> ```
> first
In addition, you also need to install the pycffirmware package from source with

```bash
cd ~/repos
Expand All @@ -78,14 +71,6 @@ conda install swig
./wrapper/build_linux.sh
```

Now you can install the lsy_drone_racing package in editable mode from the repository root

```bash
cd ~/repos/lsy_drone_racing
pip install --upgrade pip
pip install -e .
```

Finally, you can test if the installation was successful by running

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

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.

## Common errors

### GLIBCXX
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

```bash
LIBGL_DEBUG=verbose python scripts/sim.py
```

Next, you should check if your system has the required library installed

```bash
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX_3.4.30
```

or if it is installed in your conda environment

```bash
strings /path-to-your-conda/envs/your-env-name/lib/libstdc++.so.6 | grep GLIBCXX_3.4.30
```

If neither of those yield any results, you are missing this library and can install it with

```bash
conda install -c conda-forge gcc=12.1.0
```

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.

## Deployment (**NOT IMPORTANT FOR STUDENTS FOR NOW**)

### Hardware setup
Expand Down
8 changes: 8 additions & 0 deletions benchmarks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Benchmarks

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!

## Profiling
To profile the simulation, use [pyinstrument](https://github.com/joerick/pyinstrument) and run

>: pyinstrument -r html profile.py
99 changes: 99 additions & 0 deletions benchmarks/config/test.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
[sim]
physics = "pyb" # pyb: PyBullet, dyn: Mathematical dynamics model, TODO: Complete the list
camera_view = [5.0, -40.0, -40.0, 0.5, -1.0, 0.5]
sim_freq = 500 # Simulation frequency, in Hz
ctrl_freq = 500 # Controller frequency, in Hz. This frequency is used to simulate the onboard controller, NOT for the environment's step function
gui = false # Enable/disable PyBullet's GUI

[sim.disturbances.action]
type = "GaussianNoise"
std = 0.001

[sim.disturbances.dynamics]
type = "UniformNoise"
low = [-0.1, -0.1, -0.1]
high = [0.1, 0.1, 0.1]

[env]
reseed = false # Whether to re-seed the random number generator between episodes
seed = 1337 # Random seed
freq = 30 # Frequency of the environment's step function, in Hz
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.

[env.track]
# Tall gates: 1.0m height. Short gates: 0.525m height. Height is measured from the ground to the
# center of the gate.
[[env.track.gates]]
pos = [0.45, -1.0, 0.525]
rpy = [0.0, 0.0, 2.35]
[[env.track.gates]]
pos = [1.0, -1.55, 1.0]
rpy = [0.0, 0.0, -0.78]
[[env.track.gates]]
pos = [0.0, 0.5, 0.525]
rpy = [0.0, 0.0, 0.0]
[[env.track.gates]]
pos = [-0.5, -0.5, 1.0]
rpy = [0.0, 0.0, 3.14]

# Obstacle height: 1.05m. Height is measured from the ground to the top of the obstacle.
[[env.track.obstacles]]
pos = [1.0, -0.5, 1.05]
[[env.track.obstacles]]
pos = [0.5, -1.5, 1.05]
[[env.track.obstacles]]
pos = [-0.5, 0.0, 1.05]
[[env.track.obstacles]]
pos = [0.0, 1.0, 1.05]

[env.track.drone]
pos = [1.0, 1.0, 0.05]
rpy = [0, 0, 0]
vel = [0, 0, 0]
ang_vel = [0, 0, 0]

[env.randomization.drone_pos]
type = "uniform" # Everything that can be used as a distribution in numpy.random
# Kwargs that are permissable in the np random function
low = [-0.1, -0.1, 0.0]
high = [0.1, 0.1, 0.02]

[env.randomization.drone_rpy]
type = "uniform"
low = [-0.1, -0.1, -0.1]
high = [0.1, 0.1, 0.1]

[env.randomization.drone_mass]
type = "uniform"
low = -0.01
high = 0.01

[env.randomization.drone_inertia]
type = "uniform"
low = [-0.000001, -0.000001, -0.000001]
high = [0.000001, 0.000001, 0.000001]

[env.randomization.gate_pos]
type = "uniform"
low = [-0.1, -0.1, 0.0]
high = [0.1, 0.1, 0.0]

[env.randomization.gate_rpy]
type = "uniform"
low = [0.0, 0.0, -0.1]
high = [0.0, 0.0, 0.1]

[env.randomization.obstacle_pos]
type = "uniform"
low = [-0.1, -0.1, 0.0]
high = [0.1, 0.1, 0.0]

[[env.constraints]]
type = "DefaultConstraint"
ctype = "input"
[[env.constraints]]
type = "BoundedConstraint"
ctype = "state"
active_dims = [0, 2, 4]
upper_bounds = [3, 3, 2]
lower_bounds = [-3.0, -3.0, -0.1]
29 changes: 29 additions & 0 deletions benchmarks/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from __future__ import annotations

import numpy as np
from sim import time_sim_reset, time_sim_step


def print_benchmark_results(name: str, timings: list[float]):
print(f"\nResults for {name}:")
print(f"Mean/std: {np.mean(timings):.2e}s +- {np.std(timings):.2e}s")
print(f"Min time: {np.min(timings):.2e}s")
print(f"Max time: {np.max(timings):.2e}s")


if __name__ == "__main__":
timings = time_sim_reset(n_tests=10)
print_benchmark_results(name="Sim reset", timings=timings)
sim_steps = 10
timings = time_sim_step(n_tests=10, sim_steps=sim_steps)
print_benchmark_results(name="Sim steps", timings=timings / sim_steps)
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="dyn")
print_benchmark_results(name="Sim steps (dyn backend)", timings=timings / sim_steps)
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_gnd")
print_benchmark_results(name="Sim steps (pyb_gnd backend)", timings=timings / sim_steps)
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_drag")
print_benchmark_results(name="Sim steps (pyb_drag backend)", timings=timings / sim_steps)
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_dw")
print_benchmark_results(name="Sim steps (pyb_dw backend)", timings=timings / sim_steps)
timings = time_sim_step(n_tests=10, sim_steps=sim_steps, physics_mode="pyb_gnd_drag_dw")
print_benchmark_results(name="Sim steps (pyb_gnd_drag_dw backend)", timings=timings / sim_steps)
19 changes: 19 additions & 0 deletions benchmarks/profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from pathlib import Path

import gymnasium

import lsy_drone_racing # noqa: F401, required for gymnasium.make
from lsy_drone_racing.utils import load_config


def main():
config = load_config(Path(__file__).parent / "config/test.toml")
env = gymnasium.make("DroneRacing-v0", config=config)
env.reset()
for _ in range(1000):
env.step(env.action_space.sample())
# 0.455


if __name__ == "__main__":
main()
44 changes: 44 additions & 0 deletions benchmarks/sim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
from __future__ import annotations

import timeit
from pathlib import Path
from typing import TYPE_CHECKING

import numpy as np

if TYPE_CHECKING:
import numpy.typing as npt

load_config_code = f"""
from pathlib import Path
from lsy_drone_racing.utils import load_config
config = load_config(Path('{Path(__file__).parent / "config/test.toml"}'))
"""
env_setup_code = """
import gymnasium
import lsy_drone_racing
env = gymnasium.make('DroneRacing-v0', config=config)
"""


def time_sim_reset(n_tests: int = 10) -> npt.NDArray[np.floating]:
setup = load_config_code + env_setup_code
stmt = """env.reset()"""
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))


def time_sim_step(
n_tests: int = 10, sim_steps: int = 100, physics_mode: str = "pyb"
) -> npt.NDArray[np.floating]:
modify_config_code = f"""config.sim.physics = '{physics_mode}'\n"""
setup = load_config_code + modify_config_code + env_setup_code + "\nenv.reset()"
stmt = f"""
for _ in range({sim_steps}):
env.step(env.action_space.sample())"""
return np.array(timeit.repeat(stmt=stmt, setup=setup, number=1, repeat=n_tests))
Loading

0 comments on commit 4c1c23a

Please sign in to comment.