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

Code enhancement and closed loop hand cycling with external forces example #8

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c8a45d4
feat(external forces): implementing external forces into msk model
Oct 9, 2024
63df875
feat(external forces) last node control fix and functional external F
Oct 10, 2024
5d927a6
feat(pedal): trying to implement a pedal with 2 additional dof
Oct 15, 2024
558e68c
Merge remote-tracking branch 'pyomeca/main' into external_forces
Nov 22, 2024
ee59847
feat(external_force): example with external torque for a biceps curl
Nov 22, 2024
a37b367
feat(external_force): cycling example (optimal solution found but wrong)
Nov 22, 2024
fb2b95d
feat(external_force): added example of cycling with ext_f and contact
Nov 26, 2024
1708b6e
feat (nmpc fes): some developpement for fes nmpc
Dec 3, 2024
d1f2422
feat (nmpc with fes): additionnal files to work on examples
Dec 4, 2024
211544f
feat (stimulation in model) : enabled the stimulation time in the model
Dec 5, 2024
19b1cfe
feat (stimulation in model): now available for nmpc
Dec 5, 2024
7ae30a5
feat (stimulation in model) : update stimulation time and width in nmpc
Dec 6, 2024
e02522a
temp
Dec 17, 2024
d2acab7
fix(integration): identified bug for integrators using rk4
Jan 7, 2025
248597f
working on convergence
Jan 14, 2025
205ab66
.
Jan 14, 2025
75d0f7d
example regrouping torque/muscle/fes driven
Jan 17, 2025
da85724
correct pedal inertial for model
Jan 17, 2025
7f298b0
Making truncation possible again
Jan 17, 2025
227b327
Reducing node shooting to increase optimization time
Jan 17, 2025
005f439
FIX: now all parameters sent are associated to the good muscle
Jan 31, 2025
f065f85
example cleaning
Jan 31, 2025
62974a5
truncation adjustment
Jan 31, 2025
deba936
fes_ocp cleaning
Jan 31, 2025
64c5cd6
removed the for_cycling argument
Jan 31, 2025
00546eb
Custom rk4 integrator to enable rk4 calculation w/ out calcium error
Jan 31, 2025
cf79af2
nmpc example
Feb 4, 2025
2b073e0
Cleaning cycling examples
Feb 4, 2025
c75b304
cleaning
Feb 4, 2025
f979b92
get pulse width
Feb 4, 2025
851a5d3
Passive force implementation
Feb 5, 2025
c428a69
working on nmpc
AnaisFarr Feb 5, 2025
8535d1e
Passive force
Feb 5, 2025
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
29 changes: 20 additions & 9 deletions cocofest/dynamics/inverse_kinematics_and_dynamics.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import math
import numpy as np
from scipy.interpolate import interp1d

import biorbd

Expand Down Expand Up @@ -50,6 +51,7 @@ def inverse_kinematics_cycling(
y_center: int | float,
radius: int | float,
ik_method: str = "trf",
cycling_number: int = 1,
) -> tuple:
"""
Perform the inverse kinematics of a cycling movement
Expand Down Expand Up @@ -80,6 +82,8 @@ def inverse_kinematics_cycling(
-‘lm’ : Levenberg-Marquardt algorithm as implemented in MINPACK.
Does not handle bounds and sparse Jacobians.
Usually the most efficient method for small unconstrained problems.
cycling_number: int
The number of cycle performed in a single problem

Returns
----------
Expand All @@ -88,20 +92,27 @@ def inverse_kinematics_cycling(
"""

model = biorbd.Model(model_path)
if 0 <= model.nbMarkers() > 1:
raise ValueError("The model must have only one markers to perform the inverse kinematics")

z = model.markers(np.array([0, 0]))[0].to_array()[2]
if z != model.markers(np.array([np.pi / 2, np.pi / 2]))[0].to_array()[2]:
z = model.markers(np.array([0]*model.nbQ()))[0].to_array()[2]
if z != model.markers(np.array([np.pi / 2]*model.nbQ()))[0].to_array()[2]:
print("The model not strictly 2d. Warm start not optimal.")

f = interp1d(np.linspace(0, -360 * cycling_number, 360 * cycling_number + 1),
np.linspace(0, -360 * cycling_number, 360 * cycling_number + 1), kind="linear")
x_new = f(np.linspace(0, -360 * cycling_number, n_shooting+1))
x_new_rad = np.deg2rad(x_new)

x_y_z_coord = np.array(
[
get_circle_coord(theta, x_center, y_center, radius, z=z)
for theta in np.linspace(0, -2 * np.pi + (-2 * np.pi / n_shooting), n_shooting + 1)
get_circle_coord(theta, x_center, y_center, radius)
for theta in x_new_rad
]
).T
target_q = x_y_z_coord.reshape((3, 1, n_shooting + 1))

target_q_hand = x_y_z_coord.reshape((3, 1, n_shooting+1)) # Hand marker_target
wheel_center_x_y_z_coord = np.array([x_center, y_center, z])
target_q_wheel_center = np.tile(wheel_center_x_y_z_coord[:, np.newaxis, np.newaxis], (1, 1, n_shooting+1)) # Wheel marker_target
target_q = np.concatenate((target_q_hand, target_q_wheel_center), axis=1)
ik = biorbd.InverseKinematics(model, target_q)
ik_q = ik.solve(method=ik_method)
ik_qdot = np.array([np.gradient(ik_q[i], (1 / n_shooting)) for i in range(ik_q.shape[0])])
Expand Down Expand Up @@ -136,9 +147,9 @@ def inverse_dynamics_cycling(
joints torques
"""
model = biorbd.Model(model_path)
tau_shape = (model.nbQ(), q.shape[1] - 1)
tau_shape = (model.nbQ(), q.shape[1])
tau = np.zeros(tau_shape)
for i in range(tau.shape[1]):
tau_i = model.InverseDynamics(q[:, i], qdot[:, i], qddot[:, i])
tau[:, i] = tau_i.to_array()
return tau
return tau[:, :-1]
71 changes: 0 additions & 71 deletions cocofest/examples/dynamics/cycling/cycling_fes_driven.py

This file was deleted.

91 changes: 91 additions & 0 deletions cocofest/examples/dynamics/cycling/cycling_inverse_kinematics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"""
This example will do an inverse kinematics and dynamics of a 100 steps hand cycling motion.
"""

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import interp1d

import biorbd
from pyorerun import BiorbdModel, PhaseRerun

from cocofest import get_circle_coord


def main(show_plot=True, animate=True):
n_shooting = 1000
cycling_number = 1

# Define the circle parameters
x_center = 0.35
y_center = 0
radius = 0.1

# Load a predefined model
model = biorbd.Model("../../msk_models/simplified_UL_Seth_pedal_aligned_for_inverse_kinematics.bioMod")

# Define the marker target to match
z = model.markers(np.array([0] * model.nbQ()))[0].to_array()[2]
if z != model.markers(np.array([np.pi / 2] * model.nbQ()))[0].to_array()[2]:
print("The model not strictly 2d. Warm start not optimal.")

f = interp1d(np.linspace(0, -360 * cycling_number, 360 * cycling_number + 1),
np.linspace(0, -360 * cycling_number, 360 * cycling_number + 1), kind="linear")
x_new = f(np.linspace(0, -360 * cycling_number, n_shooting + 1))
x_new_rad = np.deg2rad(x_new)

x_y_z_coord = np.array(
[
get_circle_coord(theta, x_center, y_center, radius)
for theta in x_new_rad
]
).T

target_q_hand = x_y_z_coord.reshape((3, 1, n_shooting + 1)) # Hand marker_target
wheel_center_x_y_z_coord = np.array([x_center, y_center, z])
target_q_wheel_center = np.tile(wheel_center_x_y_z_coord[:, np.newaxis, np.newaxis],
(1, 1, n_shooting + 1)) # Wheel marker_target
target_q = np.concatenate((target_q_hand, target_q_wheel_center), axis=1)

# Perform the inverse kinematics
ik = biorbd.InverseKinematics(model, target_q)
ik_q = ik.solve(method="lm")
ik_qdot = np.array([np.gradient(ik_q[i], (1 / n_shooting)) for i in range(ik_q.shape[0])])
ik_qddot = np.array([np.gradient(ik_qdot[i], (1 / n_shooting)) for i in range(ik_qdot.shape[0])])

# Perform the inverse dynamics
tau_shape = (model.nbQ(), ik_q.shape[1] - 1)
tau = np.zeros(tau_shape)
for i in range(tau.shape[1]):
tau_i = model.InverseDynamics(ik_q[:, i], ik_qdot[:, i], ik_qddot[:, i])
tau[:, i] = tau_i.to_array()

# Plot the results
if show_plot:
fig, (ax1, ax2) = plt.subplots(1, 2)
ax1.set_title("Q")
ax1.plot(np.linspace(0, 1, n_shooting + 1), ik_q[0], color="orange", label="shoulder")
ax1.plot(np.linspace(0, 1, n_shooting + 1), ik_q[1], color="blue", label="elbow")
ax1.set(xlabel="Time (s)", ylabel="Angle (rad)")
ax2.set_title("Tau")
ax2.plot(np.linspace(0, 1, n_shooting)[2:-1], tau[0][2:-1], color="orange", label="shoulder")
ax2.plot(np.linspace(0, 1, n_shooting)[2:-1], tau[1][2:-1], color="blue", label="elbow")
ax2.set(xlabel="Time (s)", ylabel="Torque (N.m)")
plt.legend()
plt.show()

# pyorerun animation
if animate:
biorbd_model = biorbd.Model("../../msk_models/simplified_UL_Seth_pedal_aligned.bioMod")
prr_model = BiorbdModel.from_biorbd_object(biorbd_model)

nb_seconds = 1
t_span = np.linspace(0, nb_seconds, n_shooting+1)

viz = PhaseRerun(t_span)
viz.add_animated_model(prr_model, ik_q)
viz.rerun("msk_model")


if __name__ == "__main__":
main(show_plot=True, animate=True)
124 changes: 0 additions & 124 deletions cocofest/examples/dynamics/cycling/cycling_muscle_driven.py

This file was deleted.

Loading
Loading