Skip to content
Closed
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
14 changes: 10 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ dependencies = [
'pandas',
'tqdm',
'gymnasium',
'roma', # For batched sim
'torch>=1.11.0', # For batched sim
'torchdiffeq', # For batched sim
'opt-einsum', # For batched sim
'timed_count', # Only for ardupilot sitl example
]

[project.optional-dependencies]
batched = [
'torch>=1.11.0',
'torchdiffeq',
'roma',
'opt-einsum',
]
learning = [
'stable_baselines3',
'tensorboard',
Expand All @@ -58,6 +60,10 @@ px4 = [
'pymavlink',
]
all = [
"torch>=1.11.0",
"torchdiffeq",
"roma",
"opt-einsum",
"stable_baselines3",
"tensorboard",
"pytest",
Expand Down
7 changes: 5 additions & 2 deletions rotorpy/controllers/quadrotor_control.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import numpy as np
import torch
import roma
try:
import torch
import roma
except ImportError:
pass
from scipy.spatial.transform import Rotation

class SE3Control(object):
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/sensors/imu.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import numpy as np
from scipy.spatial.transform import Rotation
import torch
try:
import torch
except ImportError:
pass
import copy

class Imu:
Expand Down
7 changes: 5 additions & 2 deletions rotorpy/simulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
from enum import Enum
import copy
import numpy as np
import roma
import torch
try:
import roma
import torch
except ImportError:
pass
from numpy.linalg import norm
from scipy.spatial.transform import Rotation
from time import perf_counter
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/trajectories/circular_traj.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import numpy as np
import torch
try:
import torch
except ImportError:
pass
import sys

class ThreeDCircularTraj(object):
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/trajectories/hover_traj.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import numpy as np
import torch
try:
import torch
except ImportError:
pass

class HoverTraj(object):
"""
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/trajectories/lissajous_traj.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import numpy as np
import torch
try:
import torch
except ImportError:
pass

"""
Lissajous curves are defined by trigonometric functions parameterized in time.
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/trajectories/minsnap.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import cvxopt
from scipy.linalg import block_diag
from typing import List
import torch
try:
import torch
except ImportError:
pass

def cvxopt_solve_qp(P, q, G=None, h=None, A=None, b=None):
"""
Expand Down
5 changes: 4 additions & 1 deletion rotorpy/trajectories/traj_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
Imports
"""
import numpy as np
import torch
try:
import torch
except ImportError:
pass

class TrajTemplate(object):
"""
Expand Down
50 changes: 35 additions & 15 deletions rotorpy/vehicles/multirotor.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
from scipy.spatial.transform import Rotation as R

# imports for Batched Dynamics
import torch
from torchdiffeq import odeint
import roma
try:
import torch
from torchdiffeq import odeint
import roma
except ImportError:
pass

import time

Expand Down Expand Up @@ -176,12 +179,15 @@ def __init__(self, quad_params, initial_state = {'x': np.array([0,0,0]),

self.aero = aero

# Integrator settings.
# Integrator settings.
if integrator_kwargs is None:
self.integrator_kwargs = {'method':'RK45'}
else:
self.integrator_kwargs = integrator_kwargs

# Fixed-step RK4 option (much faster than solve_ivp for small timesteps)
self.use_fixed_step = False

def extract_geometry(self):
"""
Extracts the geometry in self.rotors for efficient use later on in the computation of
Expand Down Expand Up @@ -230,19 +236,22 @@ def step(self, state, control, t_step):
# The true motor speeds can not fall below min and max speeds.
cmd_rotor_speeds = np.clip(cmd_rotor_speeds, self.rotor_speed_min, self.rotor_speed_max)

# Form autonomous ODE for constant inputs and integrate one time step.
def s_dot_fn(t, s):
return self._s_dot_fn(t, s, cmd_rotor_speeds)
s = Multirotor._pack_state(state)

# Integrate
sol = scipy.integrate.solve_ivp(
s_dot_fn,
(0.0, t_step),
s,
**self.integrator_kwargs
)
s = sol['y'][:, -1]
if self.use_fixed_step:
# Fixed-step RK4: 4 function evaluations, no adaptive overhead
s = self._rk4_step(s, cmd_rotor_speeds, t_step)
else:
# Adaptive RK45 via scipy
def s_dot_fn(t, s):
return self._s_dot_fn(t, s, cmd_rotor_speeds)
sol = scipy.integrate.solve_ivp(
s_dot_fn,
(0.0, t_step),
s,
**self.integrator_kwargs
)
s = sol['y'][:, -1]

# Unpack the state vector.
state = Multirotor._unpack_state(s)
Expand All @@ -260,6 +269,17 @@ def s_dot_fn(t, s):

return state

def _rk4_step(self, s, cmd_rotor_speeds, dt):
"""
Single fixed-step RK4 integration. 7x faster than solve_ivp for small
timesteps with identical accuracy at dt <= 4ms.
"""
k1 = self._s_dot_fn(0, s, cmd_rotor_speeds)
k2 = self._s_dot_fn(0, s + 0.5 * dt * k1, cmd_rotor_speeds)
k3 = self._s_dot_fn(0, s + 0.5 * dt * k2, cmd_rotor_speeds)
k4 = self._s_dot_fn(0, s + dt * k3, cmd_rotor_speeds)
return s + (dt / 6.0) * (k1 + 2*k2 + 2*k3 + k4)

def _s_dot_fn(self, t, s, cmd_rotor_speeds):
"""
Compute derivative of state for quadrotor given fixed control inputs as
Expand Down
Loading
Loading