Skip to content

Commit 1659f57

Browse files
committed
changed agile x inequalities to use interior point method
1 parent b54ed03 commit 1659f57

2 files changed

Lines changed: 78 additions & 25 deletions

File tree

mpx/config/config_piper.py

Lines changed: 77 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
from mujoco.mjx._src import smooth
1010

1111
from mpx.jax_ocp_solvers.jax_ocp_solvers import optimizers
12-
from mpx.utils.objectives import penalty
1312

1413

1514
dir_path = os.path.dirname(os.path.realpath(__file__))
@@ -22,7 +21,7 @@
2221
N = 50
2322
mpc_frequency = 50.0
2423
solver_mode = "equality"
25-
equality_num_alpha = 16
24+
equality_num_alpha = 8
2625

2726
regularization = jnp.array(1e-6,dtype=jnp.float32)
2827
merit_penalty = jnp.array(1e-6,dtype=jnp.float32)
@@ -39,6 +38,7 @@
3938
n = nq + nv
4039
m = nv + n_joints
4140
equality_dim = nv
41+
inequality_dim = 2 * n_joints
4242

4343
qacc_slice = slice(0, nv)
4444
tau_slice = slice(nv, nv + n_joints)
@@ -68,8 +68,8 @@
6868
raise ValueError("All controlled Piper joints must define position limits")
6969
joint_position_min = jnp.asarray(_MODEL.jnt_range[:n_joints, 0])
7070
joint_position_max = jnp.asarray(_MODEL.jnt_range[:n_joints, 1])
71-
joint_limit_barrier_weight = 0.01
72-
joint_limit_barrier_relaxation = 0.05
71+
barrier_parameter = jnp.array(1.0, dtype=jnp.float32)
72+
multiplier_regularization = jnp.array(1e-8, dtype=jnp.float32)
7373
_INITIAL_DATA = mujoco.MjData(_MODEL)
7474
_INITIAL_DATA.qpos[:] = q0
7575
mujoco.mj_forward(_MODEL, _INITIAL_DATA)
@@ -130,6 +130,18 @@ def _equilibrium_control(qpos, qvel):
130130
tau = data.qfrc_bias - data.qfrc_passive
131131
return jnp.concatenate([qacc, tau])
132132

133+
134+
def inequality(x, u, t, parameter):
135+
"""Joint position bounds, feasible when values are <= 0."""
136+
del u, t, parameter
137+
qpos, _ = _state_parts(x)
138+
return jnp.concatenate(
139+
[
140+
joint_position_min - qpos,
141+
qpos - joint_position_max,
142+
]
143+
)
144+
133145
def cost(W, reference, x, u, t):
134146
qpos, qvel = _state_parts(x)
135147
q = qpos
@@ -148,32 +160,18 @@ def cost(W, reference, x, u, t):
148160
end_effector_position = data.geom_xpos[_CONTACT_ID[0]]
149161
end_effector_error = end_effector_position - p_ref
150162
joint_error = q - q_ref
151-
joint_limit_cost = jnp.sum(
152-
penalty(
153-
q - joint_position_min,
154-
alpha=joint_limit_barrier_weight,
155-
sigma=joint_limit_barrier_relaxation,
156-
)
157-
+ penalty(
158-
joint_position_max - q,
159-
alpha=joint_limit_barrier_weight,
160-
sigma=joint_limit_barrier_relaxation,
161-
)
162-
)
163163

164164
stage_cost = (
165165
joint_error.T @ W["Qq"] @ joint_error
166166
+ (dq - dq_ref).T @ W["Qdq"] @ (dq - dq_ref)
167167
+ acc.T @ W["Qacc"] @ acc
168168
+ tau.T @ W["Qtau"] @ tau
169169
+ end_effector_error.T @ W["Qee"] @ end_effector_error
170-
+ joint_limit_cost
171170
)
172171
terminal_cost = (
173172
joint_error.T @ W["Qq"] @ joint_error
174173
+ (dq - dq_ref).T @ W["Qdq"] @ (dq - dq_ref)
175174
+ end_effector_error.T @ W["Qee_final"] @ end_effector_error
176-
+ joint_limit_cost
177175
)
178176
return jnp.where(t == N, 0.5 * terminal_cost, 0.5 * stage_cost)
179177

@@ -184,13 +182,18 @@ class InverseDynamicsMPCData(PyTreeNode):
184182
U0: jnp.ndarray
185183
V0: jnp.ndarray
186184
Veq0: jnp.ndarray
185+
Vineq0: jnp.ndarray
186+
slack0: jnp.ndarray
187187
W: jnp.ndarray
188188
regularization: jnp.ndarray
189189
merit_penalty: jnp.ndarray
190+
barrier_parameter: jnp.ndarray
190191

191192

192193
@partial(jax.jit, static_argnums=(0, 1))
193-
def _update_warm_start(horizon, shift, u_ref, x0, X_prev, U_prev, X, U, V, Veq):
194+
def _update_warm_start(
195+
horizon, shift, u_ref, x0, X_prev, U_prev, X, U, V, Veq, Vineq, slack
196+
):
194197
q_slice = slice(0, n_joints)
195198
dq_slice = slice(nq, nq + n_joints)
196199
u_fallback_idx = 1 if horizon > 1 else 0
@@ -205,6 +208,8 @@ def safe_update():
205208
shift_trajectory(X),
206209
shift_trajectory(V),
207210
shift_trajectory(Veq),
211+
shift_trajectory(Vineq),
212+
shift_trajectory(slack),
208213
X[1, q_slice],
209214
X[1, dq_slice],
210215
)
@@ -215,6 +220,8 @@ def unsafe_update():
215220
jnp.tile(x0, (horizon + 1, 1)),
216221
jnp.zeros_like(X_prev),
217222
jnp.zeros((horizon, equality_dim), dtype=X_prev.dtype),
223+
shift_trajectory(Vineq),
224+
shift_trajectory(slack),
218225
X_prev[1, q_slice],
219226
X_prev[1, dq_slice],
220227
)
@@ -239,15 +246,24 @@ def __init__(self, config, limited_memory=False):
239246
self.initial_U0 = jnp.tile(config.u_ref, (config.N, 1))
240247
self.initial_V0 = jnp.zeros((config.N + 1, config.n))
241248
self.initial_Veq0 = jnp.zeros((config.N, config.equality_dim))
249+
initial_g = jax.vmap(config.inequality)(
250+
self.initial_X0[:-1],
251+
self.initial_U0,
252+
jnp.arange(config.N),
253+
jnp.zeros((config.N, 1)),
254+
)
255+
self.initial_slack0 = jnp.maximum(-initial_g, 1e-2)
256+
self.initial_Vineq0 = config.barrier_parameter / self.initial_slack0
242257

243258
self.dynamics = config.dynamics
244259
solver = partial(
245-
optimizers.mpc_equality,
260+
optimizers.ip_mpc,
246261
config.cost,
247262
self.dynamics,
248263
None,
249264
limited_memory,
250265
equality=config.equality,
266+
inequality=config.inequality,
251267
num_alpha=config.equality_num_alpha,
252268
)
253269

@@ -260,7 +276,10 @@ def solve(
260276
U0,
261277
V0,
262278
Veq0,
279+
Vineq0,
280+
slack0,
263281
regularization,
282+
current_barrier_parameter,
264283
):
265284
return solver(
266285
reference,
@@ -271,7 +290,11 @@ def solve(
271290
U0,
272291
V0,
273292
Veq_in=Veq0,
293+
Vineq_in=Vineq0,
294+
slack_in=slack0,
274295
regularization=regularization,
296+
barrier_parameter=current_barrier_parameter,
297+
multiplier_regularization=config.multiplier_regularization,
275298
)
276299

277300
self._solve = solve
@@ -289,9 +312,12 @@ def make_data(self):
289312
U0=self.initial_U0,
290313
V0=self.initial_V0,
291314
Veq0=self.initial_Veq0,
315+
Vineq0=self.initial_Vineq0,
316+
slack0=self.initial_slack0,
292317
W=W,
293318
regularization=regularization,
294319
merit_penalty=merit_penalty,
320+
barrier_parameter=barrier_parameter,
295321
)
296322

297323
def _reference(self, x, command):
@@ -311,7 +337,18 @@ def run(self, data, x, command, contact=None):
311337
del contact
312338
reference = self._reference(x, command)
313339
parameter = jnp.zeros((N + 1, 1), dtype=x.dtype)
314-
X, U, V, Veq, regularization, alpha_best, any_accepted = self._solve(
340+
(
341+
X,
342+
U,
343+
V,
344+
Veq,
345+
Vineq,
346+
slack,
347+
regularization,
348+
next_barrier_parameter,
349+
alpha_best,
350+
any_accepted,
351+
) = self._solve(
315352
reference,
316353
parameter,
317354
data.W,
@@ -320,7 +357,10 @@ def run(self, data, x, command, contact=None):
320357
data.U0,
321358
data.V0,
322359
data.Veq0,
360+
data.Vineq0,
361+
data.slack0,
323362
data.regularization,
363+
data.barrier_parameter,
324364
)
325365
valid_solution = jnp.isfinite(U).all()
326366
tau = jax.lax.cond(
@@ -329,22 +369,27 @@ def run(self, data, x, command, contact=None):
329369
lambda _: self.control_output(x, data.X0, data.U0, reference, parameter),
330370
operand=None,
331371
)
332-
U0, X0, V0, Veq0, q, dq = self._update_warm_start(
372+
U0, X0, V0, Veq0, Vineq0, slack0, q, dq = self._update_warm_start(
333373
x,
334374
data.X0,
335375
data.U0,
336376
X,
337377
U,
338378
V,
339379
Veq,
380+
Vineq,
381+
slack,
340382
)
341383
# jax.debug.print("====================" )
342384
return data.replace(
343385
X0=X0,
344386
U0=U0,
345387
V0=V0,
346388
Veq0=Veq0,
389+
Vineq0=Vineq0,
390+
slack0=slack0,
347391
regularization=regularization,
392+
barrier_parameter=jnp.maximum(next_barrier_parameter, 1e-8),
348393
), tau, q, dq, alpha_best, any_accepted
349394

350395
def reset(self, data, qpos, qvel, foot=None):
@@ -356,13 +401,21 @@ def reset(self, data, qpos, qvel, foot=None):
356401
nominal_control = _equilibrium_control(
357402
x[self.qpos_slice], x[self.qvel_slice]
358403
)
404+
X0 = jnp.tile(x, (N + 1, 1))
405+
U0 = jnp.tile(nominal_control, (N, 1))
406+
parameters = jnp.zeros((N, 1), dtype=x.dtype)
407+
g = jax.vmap(inequality)(X0[:-1], U0, jnp.arange(N), parameters)
408+
slack0 = jnp.maximum(-g, 1e-2)
359409
return data.replace(
360-
X0=jnp.tile(x, (N + 1, 1)),
361-
U0=jnp.tile(nominal_control, (N, 1)),
410+
X0=X0,
411+
U0=U0,
362412
V0=self.initial_V0,
363413
Veq0=self.initial_Veq0,
414+
Vineq0=barrier_parameter / slack0,
415+
slack0=slack0,
364416
regularization=regularization,
365417
merit_penalty=merit_penalty,
418+
barrier_parameter=barrier_parameter,
366419
)
367420

368421

mpx/jax_ocp_solvers

0 commit comments

Comments
 (0)