Skip to content

Commit 33cfae0

Browse files
committed
Start controller refactor. Add scipy broadcast dependency
1 parent 2c8eb0f commit 33cfae0

4 files changed

Lines changed: 73 additions & 29 deletions

File tree

drone_models/controller/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111
from drone_models.controller.mellinger import (
1212
attitude2force_torque as mellinger_attitude2force_torque,
1313
)
14-
from drone_models.controller.mellinger import pos2attitude as mellinger_pos2attitude
14+
from drone_models.controller.mellinger import state2attitude as mellinger_state2attitude
1515

1616
available_controller: dict[str, Callable] = {
17-
"mellinger_pos2attitude": mellinger_pos2attitude,
17+
"mellinger_state2attitude": mellinger_state2attitude,
1818
"mellinger_attitude2force_torque": mellinger_attitude2force_torque,
1919
}

drone_models/controller/mellinger.py

Lines changed: 61 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
from __future__ import annotations
44

5-
from typing import TYPE_CHECKING
5+
from typing import TYPE_CHECKING, NamedTuple
66

7+
import numpy as np
78
from array_api_compat import array_namespace
89
from scipy.spatial.transform import Rotation as R
910

@@ -15,16 +16,26 @@
1516
from drone_models.utils.constants import Constants
1617

1718

18-
def pos2attitude(
19+
def state2attitude(
1920
pos: Array,
2021
quat: Array,
2122
vel: Array,
2223
ang_vel: Array,
2324
cmd: Array,
24-
constants: Constants,
25-
parameters: dict[str, Array | float],
26-
dt: float = 1 / 500,
27-
i_error: Array | None = None,
25+
ctrl_freq: float = 100,
26+
ctrl_errors: tuple[Array, ...] = (),
27+
ctrl_info: tuple[Array, ...] = (),
28+
*,
29+
mass: float,
30+
kp: Array,
31+
kd: Array,
32+
ki: Array,
33+
gravity_vec: Array,
34+
mass_thrust: float,
35+
i_range: Array,
36+
thrust_min: float,
37+
thrust_max: float,
38+
pwm_max: float,
2839
) -> tuple[Array, Array]:
2940
"""Compute the positional part of the mellinger controller.
3041
@@ -56,23 +67,19 @@ def pos2attitude(
5667
setpoint_vel = cmd[..., 3:6]
5768
setpoint_acc = cmd[..., 6:9]
5869
setpoint_yaw = cmd[..., 9]
70+
dt = 1 / ctrl_freq
5971
# setpointRPY_rates = cmd[..., 10:13]
6072
# From firmware controller_mellinger
6173
r_error = setpoint_pos - pos # l. 145 Position Error (ep)
6274
v_error = setpoint_vel - vel # l. 148 Velocity Error (ev)
6375
# l.151 ff Integral Error
64-
if i_error is None:
65-
i_error = xp.zeros_like(pos)
66-
i_error = xp.clip(i_error + r_error * dt, -parameters["i_range"], parameters["i_range"])
76+
i_error = xp.zeros_like(pos) if ctrl_errors == () else ctrl_errors[0]
77+
i_error = xp.clip(i_error + r_error * dt, -i_range, i_range)
6778
# l. 161 Desired thrust [F_des]
6879
# => only one case here, since setpoint is always in absolute mode
6980
# Note: since we've defined the gravity in z direction, a "-" needs to be added
70-
target_thrust = (
71-
parameters["mass"] * (setpoint_acc - constants.GRAVITY_VEC)
72-
+ parameters["kp"] * r_error
73-
+ parameters["kd"] * v_error
74-
+ parameters["ki"] * i_error
75-
)
81+
target_thrust = mass * (setpoint_acc - gravity_vec) + kp * r_error + kd * v_error + ki * i_error
82+
target_thrust = xp.clip(target_thrust, thrust_min * 4, thrust_max * 4)
7683
# l. 178 Rate-controlled YAW is moving YAW angle setpoint
7784
# => only one case here, since the setpoint is always in absolute mode
7885
desiredYaw = setpoint_yaw
@@ -102,9 +109,8 @@ def pos2attitude(
102109
matrix = xp.stack((x_axis_desired, y_axis_desired, z_axis_desired), axis=-1)
103110
command_RPY = R.from_matrix(matrix).as_euler("xyz", degrees=False)
104111
# l. 283
105-
thrust = parameters["massThrust"] * current_thrust
106112
# Transform thrust into N to keep uniform interface
107-
thrust = pwm2force(thrust, constants.THRUST_MAX, constants.PWM_MAX) * 4
113+
thrust = pwm2force(mass_thrust * current_thrust, thrust_max, pwm_max) * 4
108114
command_rpyt = xp.concat((command_RPY, thrust[..., None]), axis=-1)
109115
return command_rpyt, i_error
110116

@@ -264,3 +270,41 @@ def pwm_clip(motor_pwm: Array, constants: Constants) -> Constants:
264270
return xp.where(
265271
xp.all(motor_pwm == 0), 0.0, xp.clip(motor_pwm, constants.PWM_MIN, constants.PWM_MAX)
266272
)
273+
274+
275+
class MellingerStateParams(NamedTuple):
276+
"""Parameters for the Mellinger state controller."""
277+
278+
mass: float
279+
kp: Array
280+
kd: Array
281+
ki: Array
282+
gravity_vec: Array
283+
mass_thrust: float
284+
i_range: Array
285+
thrust_min: float
286+
thrust_max: float
287+
pwm_max: float
288+
289+
@staticmethod
290+
def load(drone_model: str) -> MellingerStateParams:
291+
"""Load the parameters from the config file."""
292+
params = MellingerStateParams._load_fake_model()
293+
return MellingerStateParams(**params)
294+
295+
@staticmethod
296+
def _load_fake_model() -> dict[str, Array | float]:
297+
"""Load the parameters from the config file."""
298+
# TODO: Remove this once we can load proper params
299+
return {
300+
"mass": 0.034,
301+
"mass_thrust": 132000 * 0.034 / 0.027,
302+
"kp": np.array([0.4, 0.4, 1.25]),
303+
"kd": np.array([0.2, 0.2, 0.4]),
304+
"ki": np.array([0.05, 0.05, 0.05]),
305+
"i_range": np.array([2.0, 2.0, 0.4]),
306+
"gravity_vec": np.array([0.0, 0.0, -9.81]), # TODO: Double-check if we want this
307+
"thrust_min": 0.02,
308+
"thrust_max": 0.1125,
309+
"pwm_max": 65535.0,
310+
}

pixi.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ classifiers = [
1616
dependencies = [
1717
"numpy>=2.0.0",
1818
"array-api-compat",
19-
"scipy @ git+https://github.com/scipy/scipy.git@0f2342f", # TODO: Replace with scipy 1.17 once released
19+
"scipy @ git+https://github.com/amacati/scipy.git@broadcasting", # TODO: Replace with scipy 1.17 once released
2020
"array-api-typing @ git+https://github.com/data-apis/array-api-typing", # TODO: Replace with array-api-typing from pip once released
2121
"array-api-extra",
2222
]

0 commit comments

Comments
 (0)