Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RTR] Torque driven free floating base dynamics #803

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from 17 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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2090,7 +2090,7 @@ Let us take a look at the structure of the code. First, tau_min, tau_max, and ta
to -1, 1 and 0 if the integer `actuator_type` (a parameter of the `prepare_ocp` function) equals 1.
In this case, the dynamics function used is `DynamicsFcn.TORQUE_ACTIVATIONS_DRIVEN`.

### The [trampo_quaternions.py](./bioptim/examples/torque_driven_ocp/trampo_quaternions.py) file
### The [example_quaternions.py](./bioptim/examples/torque_driven_ocp/example_quaternions.py) file
This example uses a representation of a human body by a trunk_leg segment and two arms.
It is designed to show how to use a model that has quaternions in their degrees of freedom.

Expand Down
140 changes: 140 additions & 0 deletions bioptim/dynamics/configure_problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,145 @@ def torque_driven(
phase=nlp.phase_idx,
)

@staticmethod
def torque_driven_free_floating_base(
ocp,
nlp,
with_contact: bool = False,
with_passive_torque: bool = False,
with_ligament: bool = False,
with_friction: bool = False,
external_forces: list = None,
):
"""
Configure the dynamics for a torque driven program with a free floating base.
This version of the torque driven dynamics avoids defining a mapping to force the root to generate null forces and torques.
(states are q_root, q_joints, qdot_root, and qdot_joints, controls are tau_joints)
Please note that it was not meant to be used with quaternions yet.

Parameters
----------
ocp: OptimalControlProgram
A reference to the ocp
nlp: NonLinearProgram
A reference to the phase
with_contact: bool
If the dynamic with contact should be used
with_passive_torque: bool
If the dynamic with passive torque should be used
with_ligament: bool
If the dynamic with ligament should be used
with_friction: bool
If the dynamic with joint friction should be used (friction = coefficients * qdot)
external_forces: list[Any]
A list of external forces
"""

_check_contacts_in_biorbd_model(with_contact, nlp.model.nb_contacts, nlp.phase_idx)
_check_external_forces_format(external_forces, nlp.ns, nlp.phase_idx)
_check_external_forces_and_phase_dynamics(external_forces, nlp.phase_dynamics, nlp.phase_idx)

nb_q = nlp.model.nb_q
nb_qdot = nlp.model.nb_qdot
nb_root = nlp.model.nb_root

# Declared rigidbody states and controls
name_q_roots = [str(i) for i in range(nb_root)]
ConfigureProblem.configure_new_variable(
"q_roots",
name_q_roots,
ocp,
nlp,
as_states=True,
as_controls=False,
as_states_dot=False,
)

name_q_joints = [str(i) for i in range(nb_root, nb_q)]
ConfigureProblem.configure_new_variable(
"q_joints",
name_q_joints,
ocp,
nlp,
as_states=True,
as_controls=False,
as_states_dot=False,
)

ConfigureProblem.configure_new_variable(
"qdot_roots",
name_q_roots,
ocp,
nlp,
as_states=True,
as_controls=False,
as_states_dot=True,
)

name_qdot_joints = [str(i) for i in range(nb_root, nb_qdot)]
ConfigureProblem.configure_new_variable(
"qdot_joints",
name_qdot_joints,
ocp,
nlp,
as_states=True,
as_controls=False,
as_states_dot=True,
)

ConfigureProblem.configure_new_variable(
"qddot_roots",
name_q_roots,
ocp,
nlp,
as_states=False,
as_controls=False,
as_states_dot=True,
)

ConfigureProblem.configure_new_variable(
"qddot_joints",
name_qdot_joints,
ocp,
nlp,
as_states=False,
as_controls=False,
as_states_dot=True,
)

ConfigureProblem.configure_new_variable(
"tau_joints",
name_qdot_joints,
ocp,
nlp,
as_states=False,
as_controls=True,
as_states_dot=False,
)

# TODO: add implicit constraints + soft contacts + fatigue

# Configure the actual ODE of the dynamics
if nlp.dynamics_type.dynamic_function:
ConfigureProblem.configure_dynamics_function(ocp, nlp, DynamicsFunctions.custom)
else:
ConfigureProblem.configure_dynamics_function(
ocp,
nlp,
DynamicsFunctions.torque_driven_free_floating_base,
with_contact=with_contact,
with_passive_torque=with_passive_torque,
with_ligament=with_ligament,
with_friction=with_friction,
external_forces=external_forces,
)

# Configure the contact forces
if with_contact:
ConfigureProblem.configure_contact_function(
ocp, nlp, DynamicsFunctions.forces_from_torque_driven, external_forces=external_forces
)

@staticmethod
def stochastic_torque_driven(
ocp,
Expand Down Expand Up @@ -1576,6 +1715,7 @@ class DynamicsFcn(FcnEnum):
"""

TORQUE_DRIVEN = (ConfigureProblem.torque_driven,)
TORQUE_DRIVEN_FREE_FLOATING_BASE = (ConfigureProblem.torque_driven_free_floating_base,)
STOCHASTIC_TORQUE_DRIVEN = (ConfigureProblem.stochastic_torque_driven,)
TORQUE_DERIVATIVE_DRIVEN = (ConfigureProblem.torque_derivative_driven,)
TORQUE_ACTIVATIONS_DRIVEN = (ConfigureProblem.torque_activations_driven,)
Expand Down
Loading