Skip to content

Commit 788dc3f

Browse files
committed
change arm config to add end effector refernce + tuning
1 parent 13a65c2 commit 788dc3f

1 file changed

Lines changed: 72 additions & 58 deletions

File tree

mpx/config/config_spot_arm.py

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import os
22
from functools import partial
3+
import time
34

45
import jax
56
import jax.numpy as jnp
67

8+
from mpx.utils import mpc_utils
79
import mpx.utils.models as mpc_dyn_model
810
import mpx.utils.objectives as mpc_objectives
911

@@ -12,10 +14,8 @@
1214
model_path = os.path.abspath(os.path.join(dir_path, "..")) + "/data/boston_dynamics_spot/scene_arm.xml"
1315

1416
# Contact frame names and body names for the Spot feet / lower legs.
15-
contact_frame = ["FL", "FR", "HL", "HR"]
16-
body_name = ["fl_lleg", "fr_lleg", "hl_lleg", "hr_lleg"]
17-
# contact_frame = ["FL", "FR", "RL", "RR"]
18-
# body_name = ["FL_calf", "FR_calf", "RL_calf", "RR_calf"]
17+
contact_frame = ["FL", "FR", "HL", "HR","arm"]
18+
body_name = ["fl_lleg", "fr_lleg", "hl_lleg", "hr_lleg","arm_link_fngr"]
1919

2020
# Time and stage parameters.
2121
dt = 0.02
@@ -31,6 +31,7 @@
3131
# robot_height = 0.40
3232
initial_height = 0.46
3333
robot_height = 0.46
34+
clearance_speed = 0.2
3435

3536
# Initial base state and nominal joint posture.
3637
p0 = jnp.array([0.0, 0.0, initial_height])
@@ -45,56 +46,43 @@
4546
-0.34, 0.175, 0.0,
4647
-0.34, -0.175, 0.0,
4748
])
48-
# p_legs0 = jnp.array([
49-
# 0.26635823, 0.1658, 0.03254209,
50-
# 0.26635823, -0.1658, 0.03254209,
51-
# -0.32934177, 0.1658, 0.03254209,
52-
# -0.32934177, -0.1658, 0.03254209])
5349

5450
# Dimensions.
5551
n_joints = 12 + 7
56-
n_contact = len(contact_frame)
57-
n = 13 + 2 * n_joints + 6 * n_contact
52+
n_leg = len(contact_frame)
53+
n_contact = n_leg - 1 # Exclude the arm contact from the contact cost.
54+
n = 13 + 2 * n_joints + 3 * n_contact + 3 * n_leg
5855
m = n_joints
59-
grf_as_state = True
6056

57+
foot_slice = slice(13 + 2 * n_joints, 13 + 2 * n_joints + 3 * (n_contact))
58+
leg_slice = slice(13 + 2 * n_joints, 13 + 2 * n_joints + 3 * (n_leg))
6159
# Reference controls.
6260
u_ref = jnp.zeros(m)
6361

64-
# Cost weights.
65-
# Qp = jnp.diag(jnp.array([0.0, 0.0, 1e4]))
66-
# Qrot = jnp.diag(jnp.array([1000.0, 1000.0, 0.0])) * 10
67-
# # Qq = jnp.diag(jnp.ones(n_joints)) * 1e0
68-
# Qq = jnp.diag(jnp.concatenate([jnp.ones(7) * 1e3, jnp.ones(12) * 1e-1]))
69-
# Qdp = jnp.diag(jnp.array([1.0, 1.0, 1.0])) * 1e3
70-
# Qomega = jnp.diag(jnp.array([1.0, 1.0, 10.0])) * 1e2
71-
# Qdq = jnp.diag(jnp.ones(n_joints)) * 1e-1
72-
# Qtau = jnp.diag(jnp.ones(n_joints)) * 1e-2
73-
# Q_grf = jnp.diag(jnp.ones(3 * n_contact)) * 1e-2
74-
# Qleg = jnp.diag(jnp.tile(jnp.array([1e4, 1e4, 1e5]), n_contact))
75-
76-
# Values for go2
62+
# Values for spot
7763
Qp = jnp.diag(jnp.array([0, 0, 1e4])) # Cost matrix for position
78-
Qrot = jnp.diag(jnp.array([1000, 1000, 0])) # Cost matrix for rotation
79-
Qq = jnp.diag(jnp.concatenate([jnp.ones(7) * 5e2, jnp.ones(12) * 1e-1])) # Cost matrix for joint angles
80-
Qdp = jnp.diag(jnp.array([1, 1, 1])) * 5e3 # Cost matrix for position derivatives
81-
Qomega= jnp.diag(jnp.array([1, 1, 1])) * 1e2 # Cost matrix for angular velocity
82-
Qdq = jnp.diag(jnp.ones(n_joints)) * 1e-1 # Cost matrix for joint angle derivatives
64+
Qrot = jnp.diag(jnp.array([100, 100, 0])) # Cost matrix for rotation
65+
Qq = jnp.diag(jnp.concatenate([jnp.ones(7) * 5e0, jnp.ones(12) * 1e-1])) # Cost matrix for joint angles
66+
Qdp = jnp.diag(jnp.array([5, 5, 1])) * 1e1 # Cost matrix for position derivatives
67+
Qomega= jnp.diag(jnp.array([1, 1, 1])) * 1e1 # Cost matrix for angular velocity
68+
Qdq = jnp.diag(jnp.ones(n_joints)) * 1e0 # Cost matrix for joint angle derivatives
8369
Qtau = jnp.diag(jnp.ones(n_joints)) * 1e-2 # Cost matrix for torques
8470
Q_grf = jnp.diag(jnp.ones(3*n_contact)) * 1e-3 # Cost matrix for ground reaction forces
8571

8672
# For the leg contact cost, repeat the unit cost for each contact point.
87-
Qleg = jnp.diag(jnp.tile(jnp.array([1e4,1e4,1e5]),n_contact))
73+
weight_leg = jnp.tile(jnp.array([1e3,1e3,1e5]),n_contact)
74+
weight_arm = jnp.array([5e4,5e4,5e4])
75+
Qcontact = jnp.diag(jnp.concatenate([weight_leg, weight_arm]))
8876

89-
W = jax.scipy.linalg.block_diag(Qp, Qrot, Qq, Qdp, Qomega, Qdq, Qleg, Qtau, Q_grf)
77+
W = {"pos": Qp, "rot": Qrot, "q": Qq, "vel": Qdp, "omega": Qomega, "dq": Qdq, "tau": Qtau, "contact": Qcontact, "grf": Q_grf}
78+
# jax.scipy.linalg.block_diag(Qp, Qrot, Qq, Qdp, Qomega, Qdq, Qcontact, Qtau, Q_grf)
9079

9180
use_terrain_estimation = False
92-
_state_extra = n - (13 + 2 * n_joints + 3 * n_contact)
9381
initial_state = jnp.concatenate(
94-
[p0, quat0, q0, jnp.zeros(6 + n_joints), p_legs0, jnp.zeros(_state_extra)]
82+
[p0, quat0, q0, jnp.zeros(6 + n_joints), p_legs0, jnp.zeros(3 + 3 * n_contact)]
9583
)
9684

97-
cost = partial(mpc_objectives.quadruped_wb_obj, True, n_joints, n_contact, N)
85+
cost = partial(mpc_objectives.quadruped_wb_obj, True, n_joints, n_contact, n_leg, N)
9886
hessian_approx = None
9987

10088
def dynamics(model, mjx_model, contact_id, body_id):
@@ -109,32 +97,58 @@ def dynamics(model, mjx_model, contact_id, body_id):
10997
)
11098

11199
# Torque bounds used by the MPC cost / clipping.
112-
max_torque = 500
113-
min_torque = -500
100+
max_torque = 300
101+
min_torque = -300
114102
solver_mode = "primal_dual" # Solver mode for the optimization problem
115103

116-
extra_qref_data = {
117-
"amp": jnp.array([2.0, 0.5, 0.4, 0.6, 0.7, 0.8, 0.5]),
118-
"freq": jnp.array([0.2, 1.0, 1.2, 0.8, 0.9, 1.0, 0.5]),
119-
"joint_index": jnp.arange(7, dtype=jnp.int32),
120-
}
121-
122-
def extra_qref_fn(q_ref, current_time, data):
123-
if data is None:
124-
return q_ref
125-
126-
arm_amp_ref = data["amp"]
127-
arm_freq_ref = data["freq"]
128-
arm_joint_index = data["joint_index"]
104+
def extra_ref_fun(reference,current_time):
129105

130106
def arm_fn(t, carry):
131-
q_ref = carry
107+
arm_pos_ref = carry
132108
#
133109
time_n = t * dt + current_time
134-
arm_pos = arm_amp_ref * jnp.sin(2 * jnp.pi * arm_freq_ref * time_n) + q0[arm_joint_index]
135-
136-
q_ref = q_ref.at[t,arm_joint_index].set(arm_pos)
137-
return (q_ref)
138-
init_carry = q_ref
139-
q_ref = jax.lax.fori_loop(0, N+1, arm_fn, init_carry)
140-
return q_ref
110+
arm_pos = jnp.array([0.75 + 0.2*time_n,0.2 * jnp.sin(2 * jnp.pi * 0.25 * time_n), 0.5 + 0.2 * jnp.cos(2 * jnp.pi * 0.25 * time_n)])
111+
112+
arm_pos_ref = arm_pos_ref.at[t].set(arm_pos)
113+
return (arm_pos_ref)
114+
init_carry = jnp.zeros((N+1, 3))
115+
arm_pos_ref = jax.lax.fori_loop(0, N+1, arm_fn, init_carry)
116+
reference['foot'] = jnp.concatenate([reference['foot'], arm_pos_ref], axis=1)
117+
return reference
118+
119+
reference_generator = partial(
120+
mpc_utils.reference_generator,
121+
use_terrain_estimation,
122+
N,
123+
dt,
124+
n_joints,
125+
n_contact,
126+
foot0=p_legs0,
127+
q0=q0,
128+
clearence_speed=clearance_speed,
129+
extra_ref_fun=extra_ref_fun
130+
)
131+
132+
import mpx.utils.mpc_wrapper as mpc_wrapper
133+
134+
class MpcWrapper(mpc_wrapper.MPCWrapper):
135+
136+
def reset(self, data, qpos, qvel, foot):
137+
"""Reset the warm start around the provided measured state."""
138+
139+
# Start from the config initial_state so any extra state entries keep
140+
# their configured default value.
141+
initial_state = (
142+
self.initial_state
143+
.at[self.qpos_slice].set(jnp.ravel(qpos))
144+
.at[self.qvel_slice].set(jnp.ravel(qvel))
145+
.at[leg_slice].set(jnp.ravel(foot))
146+
)
147+
return data.replace(
148+
U0=self.initial_U0,
149+
X0=jnp.tile(initial_state, (self.config.N + 1, 1)),
150+
V0=self.initial_V0,
151+
time=jnp.asarray(0.0, dtype=jnp.float32),
152+
contact_time=self.config.timer_t,
153+
liftoff=jnp.ravel(foot[:12]),
154+
)

0 commit comments

Comments
 (0)