alpaqa 0.0.1
Nonconvex constrained optimization
hanging_chain_dynamics.py
Go to the documentation of this file.
1from typing import Union
2import casadi as cs
3import numpy as np
4from casadi import vertcat as vc
5
6
8 def __init__(self, N: int, dim: int):
9 self.NN = N
10 self.dimdim = dim
11
12 self.y1y1 = cs.SX.sym("y1", dim * N, 1) # state: balls 1→N positions
13 self.y2y2 = cs.SX.sym("y2", dim * N, 1) # state: balls 1→N velocities
14 self.y3y3 = cs.SX.sym("y3", dim, 1) # state: ball 1+N position
15 self.uu = cs.SX.sym("u", dim, 1) # input: ball 1+N velocity
16 self.yy = vc(self.y1y1, self.y2y2, self.y3y3) # full state vector
17
18 self.mm = cs.SX.sym("m") # mass
19 self.DD = cs.SX.sym("D") # spring constant
20 self.LL = cs.SX.sym("L") # spring length
21
22 self.paramsparams = vc(self.mm, self.DD, self.LL)
23
24 self.gg = np.array([0, 0, -9.81] if dim == 3 else [0, -9.81]) # gravity
25 self.x0x0 = np.zeros((dim, )) # ball 0 position
26 self.x_endx_end = np.eye(1, dim, 0).ravel() # ball N+1 reference position
27
28 def dynamics(self, Ts=0.05):
29 y, y1, y2, y3, u = self.yy, self.y1y1, self.y2y2, self.y3y3, self.uu
30 dist = lambda xa, xb: cs.norm_2(xa - xb)
31 N, d = self.NN, self.dimdim
32 p = self.paramsparams
33
34 # Continuous-time dynamics y' = f(y, u; p)
35
36 f1 = [y2]
37 f2 = []
38 for i in range(N):
39 xi = y1[d * i:d * i + d]
40 xip1 = y1[d * i + d:d * i + d * 2] if i < N - 1 else y3
41 Fiip1 = self.DD * (1 - self.LL / dist(xip1, xi)) * (xip1 - xi)
42 xim1 = y1[d * i - d:d * i] if i > 0 else self.x0x0
43 Fim1i = self.DD * (1 - self.LL / dist(xi, xim1)) * (xi - xim1)
44 fi = (Fiip1 - Fim1i) / self.mm + self.gg
45 f2 += [fi]
46 f3 = [u]
47
48 f_expr = vc(*f1, *f2, *f3)
49 self.ff = cs.Function("f", [y, u, p], [f_expr], ["y", "u", "p"], ["y'"])
50
51 # Discretize dynamics y[k+1] = f_d(y[k], u[k]; p)
52
53 opt = {"tf": Ts, "simplify": True, "number_of_finite_elements": 4}
54 intg = cs.integrator("intg", "rk", {
55 "x": y,
56 "p": vc(u, p),
57 "ode": f_expr
58 }, opt)
59
60 f_d_expr = intg(x0=y, p=vc(u, p))["xf"]
61 self.f_df_d = cs.Function("f_d", [y, u, p], [f_d_expr], ["y", "u", "p"],
62 ["y+"])
63
64 return self.f_df_d
65
66 def state_to_pos(self, y):
67 N, d = self.NN, self.dimdim
68 rav = lambda x: np.array(x).ravel()
69 xdim = lambda y, i: np.concatenate(
70 ([0], rav(y[i:d * N:d]), rav(y[-d + i])))
71 if d == 3:
72 return (xdim(y, 0), xdim(y, 1), xdim(y, 2))
73 else:
74 return (xdim(y, 0), xdim(y, 1), np.zeros((N + 1, )))
75
76 def input_to_matrix(self, u):
77 """
78 Reshape the input signal from a vector into a dim × N_horiz matrix (note
79 that CasADi matrices are stored column-wise and NumPy arrays row-wise)
80 """
81 if isinstance(u, np.ndarray):
82 return u.reshape((self.dimdim, u.shape[0] // self.dimdim), order='F')
83 else:
84 return u.reshape((self.dimdim, u.shape[0] // self.dimdim))
85
86 def simulate(self, N_sim: int, y_0: np.ndarray, u: Union[np.ndarray, list,
87 cs.SX.sym],
88 p: Union[np.ndarray, list, cs.SX.sym]):
89 if isinstance(u, list):
90 u = np.array(u)
91 if isinstance(u, np.ndarray):
92 if u.ndim == 1 or (u.ndim == 2 and u.shape[1] == 1):
93 if u.shape[0] == self.dimdim:
94 u = np.tile(u, (N_sim, 1)).T
95 return self.f_df_d.mapaccum(N_sim)(y_0, u, p)
96
97 def initial_state(self):
98 N, d = self.NN, self.dimdim
99 y1_0 = np.zeros((d * N))
100 y1_0[0::d] = np.arange(1, N + 1) / (N + 1)
101 y2_0 = np.zeros((d * N))
102 y3_0 = np.zeros((d, ))
103 y3_0[0] = 1
104
105 y_null = np.concatenate((y1_0, y2_0, y3_0))
106 u_null = np.zeros((d, ))
107
108 return y_null, u_null
109
110 def generate_cost_fun(self, α=25, β=1, γ=0.01):
111 N, d = self.NN, self.dimdim
112 y1t = cs.SX.sym("y1t", d * N, 1)
113 y2t = cs.SX.sym("y2t", d * N, 1)
114 y3t = cs.SX.sym("y3t", d, 1)
115 ut = cs.SX.sym("ut", d, 1)
116 yt = cs.vertcat(y1t, y2t, y3t)
117
118 L_cost = α * cs.sumsqr(y3t - self.x_endx_end) + γ * cs.sumsqr(ut)
119 for i in range(N):
120 xdi = y2t[d * i:d * i + d]
121 L_cost += β * cs.sumsqr(xdi)
122 return cs.Function("L_cost", [yt, ut], [L_cost])
def generate_cost_fun(self, α=25, β=1, γ=0.01)
def simulate(self, int N_sim, np.ndarray y_0, Union[np.ndarray, list, cs.SX.sym] u, Union[np.ndarray, list, cs.SX.sym] p)