-
Notifications
You must be signed in to change notification settings - Fork 47
/
example_joints_acceleration_driven.py
133 lines (109 loc) · 3.8 KB
/
example_joints_acceleration_driven.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
"""
A simple optimal control program consisting of a double pendulum starting downward and ending upward while requiring the
minimum of generalized forces. The solver is only allowed to apply an angular acceleration the joint linking the second
pendulum to the first one.
During the optimization process, the graphs are updated real-time (even though it is a bit too fast and short to really
appreciate it). Finally, once it finished optimizing, it animates the model using the optimal solution
"""
import platform
from bioptim import (
BiorbdModel,
OptimalControlProgram,
DynamicsFcn,
Dynamics,
BoundsList,
InitialGuessList,
ObjectiveFcn,
Objective,
OdeSolver,
OdeSolverBase,
CostType,
Solver,
)
def prepare_ocp(
biorbd_model_path: str,
final_time: float,
n_shooting: int,
ode_solver: OdeSolverBase = OdeSolver.RK4(),
use_sx: bool = True,
n_threads: int = 1,
) -> OptimalControlProgram:
"""
The initialization of an ocp
Parameters
----------
biorbd_model_path: str
The path to the biorbd model
final_time: float
The time in second required to perform the task
n_shooting: int
The number of shooting points to define int the direct multiple shooting program
ode_solver: OdeSolverBase = OdeSolver.RK4()
Which type of OdeSolver to use
use_sx: bool
If the SX variable should be used instead of MX (can be extensive on RAM)
n_threads: int
The number of threads to use in the paralleling (1 = no parallel computing)
Returns
-------
The OptimalControlProgram ready to be solved
"""
bio_model = BiorbdModel(biorbd_model_path)
# Add objective functions
objective_functions = Objective(ObjectiveFcn.Lagrange.MINIMIZE_CONTROL, key="qddot_joints")
# Dynamics
dynamics = Dynamics(DynamicsFcn.JOINTS_ACCELERATION_DRIVEN)
# Path constraint
x_bounds = BoundsList()
x_bounds["q"] = bio_model.bounds_from_ranges("q")
x_bounds["qdot"] = bio_model.bounds_from_ranges("qdot")
x_bounds["q"][:, [0, -1]] = 0
x_bounds["q"][0, -1] = 3.14
x_bounds["q"][1, -1] = 0
# Initial guess
n_q = bio_model.nb_q
n_qdot = bio_model.nb_qdot
x_init = InitialGuessList()
x_init.add("q", initial_guess=[0] * n_q)
x_init.add("qdot", initial_guess=[0] * n_qdot)
# Define control path constraint
n_qddot_joints = bio_model.nb_qddot - bio_model.nb_root # 2 - 1 = 1 in this example
qddot_joints_min, qddot_joints_max, qddot_joints_init = -100, 100, 0
u_bounds = BoundsList()
u_bounds.add(
"qddot_joints", min_bound=[qddot_joints_min] * n_qddot_joints, max_bound=[qddot_joints_max] * n_qddot_joints
)
u_init = InitialGuessList()
u_init.add("qddot_joints", initial_guess=[qddot_joints_init] * n_qddot_joints)
return OptimalControlProgram(
bio_model,
dynamics,
n_shooting,
final_time,
x_init=x_init,
u_init=u_init,
x_bounds=x_bounds,
u_bounds=u_bounds,
objective_functions=objective_functions,
ode_solver=ode_solver,
use_sx=use_sx,
n_threads=n_threads,
)
def main():
"""
If pendulum is run as a script, it will perform the optimization and animates it
"""
# --- Prepare the ocp --- #
ocp = prepare_ocp(biorbd_model_path="models/double_pendulum.bioMod", final_time=10, n_shooting=100)
# Custom plots
ocp.add_plot_penalty(CostType.ALL)
# --- Print ocp structure --- #
ocp.print(to_console=False, to_graph=False)
# --- Solve the ocp --- #
sol = ocp.solve(Solver.IPOPT(show_online_optim=platform.system() == "Linux"))
# sol.graphs()
# --- Show the results in a bioviz animation --- #
sol.print_cost()
sol.animate(n_frames=100)
if __name__ == "__main__":
main()