forked from pyomeca/bioptim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pendulum.py
119 lines (98 loc) · 3.47 KB
/
pendulum.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
"""
TODO: Please confirm this example
A very simple yet meaningful optimal control program consisting in a pendulum starting downward and ending upward
while requiring the minimum of generalized forces. The solver is only allowed to move the pendulum sideways.
This simple example is a good place to start investigating bioptim using ACADOS as it describes the most common
dynamics out there (the joint torque driven), it defines an objective function and some boundaries and initial guesses
"""
import numpy as np
from bioptim import (
BiorbdModel,
OptimalControlProgram,
ObjectiveList,
ObjectiveFcn,
DynamicsList,
DynamicsFcn,
BoundsList,
Solver,
)
def prepare_ocp(
biorbd_model_path: str,
final_time: float,
n_shooting: int,
use_sx: bool = True,
expand_dynamics: bool = True,
) -> 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
use_sx: bool
If the ocp should be built with SX. Please note that ACADOS requires SX
Returns
-------
The OptimalControlProgram ready to be solved
"""
bio_model = BiorbdModel(biorbd_model_path)
nq = bio_model.nb_q
nqdot = bio_model.nb_qdot
target = np.zeros((nq + nqdot, 1))
target[1, 0] = 3.14
# Add objective functions
objective_functions = ObjectiveList()
objective_functions.add(ObjectiveFcn.Lagrange.MINIMIZE_CONTROL, key="tau", weight=100.0, multi_thread=False)
objective_functions.add(ObjectiveFcn.Lagrange.MINIMIZE_STATE, key="q", weight=10.0, multi_thread=False)
objective_functions.add(ObjectiveFcn.Lagrange.MINIMIZE_STATE, key="qdot", weight=1.0, multi_thread=False)
objective_functions.add(
ObjectiveFcn.Mayer.MINIMIZE_STATE, weight=5000000, key="q", target=target[:nq, :], multi_thread=False
)
objective_functions.add(
ObjectiveFcn.Mayer.MINIMIZE_STATE, weight=500, key="qdot", target=target[nq:, :], multi_thread=False
)
# Dynamics
dynamics = DynamicsList()
dynamics.add(DynamicsFcn.TORQUE_DRIVEN, expand_dynamics=expand_dynamics)
# Path constraint
x_bounds = BoundsList()
x_bounds["q"] = bio_model.bounds_from_ranges("q")
x_bounds["q"][:, 0] = 0
x_bounds["qdot"] = bio_model.bounds_from_ranges("qdot")
x_bounds["qdot"][:, 0] = 0
# Define control path constraint
n_tau = bio_model.nb_tau
torque_min, torque_max = -300, 300
u_bounds = BoundsList()
u_bounds["tau"] = [torque_min] * n_tau, [torque_max] * n_tau
u_bounds["tau"][-1, :] = 0
# ------------- #
return OptimalControlProgram(
bio_model,
dynamics,
n_shooting,
final_time,
x_bounds=x_bounds,
u_bounds=u_bounds,
objective_functions=objective_functions,
use_sx=use_sx,
)
def main():
"""
If pendulum is run as a script, it will perform the optimization using ACADOS and animates it
"""
ocp = prepare_ocp(biorbd_model_path="models/pendulum.bioMod", final_time=1, n_shooting=100)
# --- Solve the program --- #
solver = Solver.ACADOS()
solver.set_maximum_iterations(500)
sol = ocp.solve(solver=solver)
# --- Show results --- #
sol.print_cost()
sol.graphs()
sol.animate()
if __name__ == "__main__":
main()