Skip to content

Move parameters and update load_params - #119

Open
ratheron wants to merge 1 commit into
mainfrom
fix.rearranging_parameters
Open

ratheron wants to merge 1 commit into
mainfrom
fix.rearranging_parameters

Conversation

@ratheron

Copy link
Copy Markdown
Collaborator

crazyflow/drones/params.toml now only holds the core parameters every drone needs: gravity_vec, mass, J, thrust_min, thrust_max. Everything else moves to the params.toml of the dynamics that uses it, i.e. the first principles coefficients and the platform data now live in crazyflow/dynamics/first_principles/params.toml. Values are unchanged. A commented example at the top of the core file documents the required keys.

This move broke crazyflow.drones.load_params, which used to be the only way to get hardware constants like pwm_max unfiltered. Since those now live in a dynamics file, that loader is removed and crazyflow.dynamics.load_params takes over: given a function it filters to its signature as before, given a Dynamics mode it returns every parameter of the drone for that dynamics.

Why

It was unclear which parameters a new drone actually needs. Now a drone that only runs the fitted models needs five keys, and the first principles section carries real content instead of being an empty marker. This prepares the availability methods PR, which derives available_drones and the supported drone/dynamics pairs from these files, and the X500 PR, the first drone without first principles parameters.

@ratheron
ratheron requested a review from amacati as a code owner September 17, 2026 22:56

@amacati amacati left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for splitting the PRs, this is really helpful.

There are two issues with this PR: First, it is not clear to me why we place some parameters into the first principles model files. Even our docstrings are inconsistent in this regard.

This inconsistency later appears in the second point, the API around load_params. I suspect the current design is forced by the requirement to get some physical parameters that are not in the function signature of the dynamics function. But getting different results for load_params(first_principles_dynamics) and load_params(Dynamics.first_principles) screams "something is off here".

We should come up with a better, more consistent solution.

Comment thread SKILL.md
`crazyflow.drones.load_params`.
- Two `load_params` exist, in `dynamics.core` and `control.core`. Given a function, both filter to
its signature and silently drop the rest. The dynamics one also takes a `Dynamics` mode and then
returns every parameter of the drone, which is how to get hardware constants like `pwm_max`.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
returns every parameter of the drone, which is how to get hardware constants like `pwm_max`.
returns every parameter of the drone.

I know we had this in before, but it should not have been there in the first place.

Comment thread crazyflow/sim/sim.py
params = load_drone_params(drone)
thrust_min, thrust_max = params["thrust_min"], params["thrust_max"]
params = load_dynamics_params(dynamics, drone)
thrust_min, thrust_max = float(params["thrust_min"]), float(params["thrust_max"])

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the float conversion? That seems odd.

Comment on lines +230 to +233
rpm2thrust = drone_params["rpm2thrust"]
hover_thrust_value = np.asarray(drone_params["mass"] * 9.81, dtype=np.float32)
hover_rotor_vel = motor_force2rotor_vel(
np.full(4, hover_thrust_value / 4.0, dtype=np.float32), drone_params["rpm2thrust"]
np.full(4, hover_thrust_value / 4.0, dtype=np.float32), rpm2thrust

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this changed?

Comment on lines +124 to +125
name = fn.__module__.split(".")[-2] if fn is not None else str(dynamics)
if name not in tuple(Dynamics):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
name = fn.__module__.split(".")[-2] if fn is not None else str(dynamics)
if name not in tuple(Dynamics):
name = fn.__module__.split(".")[-2] if fn is not None else dynamics
if name not in Dynamics:

Comment on lines +139 to +141
if fn is not None:
params = filter_to_signature(params, fn)
return to_xp(params, xp=xp, device=device)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not at all intuitive. Why do we not filter when we are given the enum over its function, which are supposed to be 1:1 correspondences? I suspect this is because you need some convenient way to get parameters like the pwms, but I am absolutely against introducing this kind of shortcut for it.

Comment on lines +106 to +107
dynamics: A dynamics function, or a dynamics mode. For a function, the result only contains
the parameters in its signature. For a mode, all parameters of both files are returned.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See below

Comment on lines +1 to +2
# Parameters of the first principles dynamics, and platform data that no dynamics uses but other tools
# (sim, estimators, firmware, examples) may need. The core physical parameters shared by all dynamics

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If no dynamics use the params, they should not be in first principles, should they?

#
# [my_drone]
# gravity_vec = [0.0, 0.0, -9.81] # m/s^2
# mass = 0.1 # kg

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how mass, something that we can measure, is distinct from, e.g., L, which is also something we can easily measure. The main argument is that mass is used across models, whereas L is only used in one. In turn, that means the location of a parameter is determined by the sum of signatures of our dynamics models, which doesn't make much sense. It should be immediately clear by looking at a parameter where it belongs, and the rule "mass and J are in drones, L is not, but thrust_min is" seems arbitrary.

are independent of the dynamics formulation used to simulate it (see [crazyflow.dynamics][]).
files, their referenced meshes (``assets/``), and the core physical parameters shared across all
dynamics (``params.toml`` with mass, inertia, thrust limits, and the gravity vector). These describe
the *hardware* and are independent of the dynamics formulation used to simulate it

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

E.g. L, which describes the hardware?

Comment on lines +26 to +28
filtered, unfiltered = load_params(dynamics, drone), load_params(Dynamics(dynamics_name), drone)
assert filtered.keys() <= unfiltered.keys()
assert {"thrust_min", "thrust_max"} <= unfiltered.keys()

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not a good API. The test result looks more surprising than something I want my function to guarantee.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants