144 lines
4.6 KiB
Python
144 lines
4.6 KiB
Python
import time
|
|
from copy import deepcopy
|
|
import matplotlib.pyplot as plt
|
|
import mujoco
|
|
import mujoco.viewer
|
|
import numpy as np
|
|
import pinocchio as pin
|
|
from pinocchio.robot_wrapper import RobotWrapper
|
|
from Go2Py import ASSETS_PATH
|
|
import os
|
|
|
|
class Go2Sim:
|
|
def __init__(self, render=True, dt=0.002):
|
|
|
|
self.model = mujoco.MjModel.from_xml_path(
|
|
os.path.join(ASSETS_PATH, 'mujoco/go2.xml')
|
|
)
|
|
self.data = mujoco.MjData(self.model)
|
|
self.dt = dt
|
|
_render_dt = 1/60
|
|
self.render_ds_ratio = max(1, _render_dt//dt)
|
|
|
|
if render:
|
|
self.viewer = mujoco.viewer.launch_passive(self.model, self.data)
|
|
self.render = True
|
|
self.viewer.cam.distance = 3.0
|
|
self.viewer.cam.azimuth = 90
|
|
self.viewer.cam.elevation = -45
|
|
self.viewer.cam.lookat[:] = np.array([0.0, -0.25, 0.824])
|
|
else:
|
|
self.render = False
|
|
|
|
self.model.opt.gravity[2] = -9.81
|
|
self.model.opt.timestep = dt
|
|
self.renderer = None
|
|
self.render = render
|
|
self.step_counter = 0
|
|
|
|
self.sitting_q = np.array([ 0.0, 1.26186061, -2.81310153,
|
|
0.0, 1.25883281, -2.78329301,
|
|
0.0, 1.27193761, -2.8052032 ,
|
|
0.0, 1.27148342, -2.81436563])
|
|
|
|
self.standing_q = np.array([ 0.0, 0.77832842, -1.56065452,
|
|
0.0, 0.76754963, -1.56634164,
|
|
0.0, 0.76681757, -1.53601146,
|
|
0.0, 0.75422204, -1.53229916])
|
|
|
|
self.q0 = self.sitting_q
|
|
self.pos0 = np.array([0., 0., 0.1])
|
|
self.rot0 = np.array([1., 0., 0., 0.])
|
|
self.reset()
|
|
mujoco.mj_step(self.model, self.data)
|
|
self.viewer.sync()
|
|
self.nv = self.model.nv
|
|
self.jacp = np.zeros((3, self.nv))
|
|
self.jacr = np.zeros((3, self.nv))
|
|
self.M = np.zeros((self.nv, self.nv))
|
|
|
|
self.q_des = np.zeros(12)
|
|
self.dq_des = np.zeros(12)
|
|
self.tau_ff = np.zeros(12)
|
|
self.kp = np.zeros(12)
|
|
self.kv = np.zeros(12)
|
|
self.latest_command_stamp = time.time()
|
|
|
|
def reset(self):
|
|
self.q_nominal = np.hstack(
|
|
[self.pos0.squeeze(), self.rot0.squeeze(), self.q0.squeeze()]
|
|
)
|
|
self.data.qpos = self.q_nominal
|
|
self.data.qvel = np.zeros(18)
|
|
|
|
def standUpReset(self):
|
|
self.q0 = self.standing_q
|
|
self.pos0 = np.array([0., 0., 0.33])
|
|
self.rot0 = np.array([1., 0., 0., 0.])
|
|
self.reset()
|
|
mujoco.mj_step(self.model, self.data)
|
|
self.viewer.sync()
|
|
|
|
def sitDownReset(self):
|
|
self.q0 = self.sitting_q
|
|
self.pos0 = np.array([0., 0., 0.1])
|
|
self.rot0 = np.array([1., 0., 0., 0.])
|
|
self.reset()
|
|
mujoco.mj_step(self.model, self.data)
|
|
self.viewer.sync()
|
|
|
|
def getJointStates(self):
|
|
return self.data.qpos[7:], self.data.qvel[6:]
|
|
|
|
def getPose(self):
|
|
return self.data.qpos[:3], self.data.qpos[3:7]
|
|
|
|
def getIMU(self):
|
|
return {
|
|
'accel':np.array(self.data.sensordata[0:3]),\
|
|
'gyro': np.array(self.data.sensordata[3:6])
|
|
}
|
|
|
|
def getFootContact(self):
|
|
return self.data.sensordata[6:10]
|
|
|
|
def setCommands(self, q_des, dq_des, kp, kv, tau_ff):
|
|
self.q_des = q_des
|
|
self.dq_des = dq_des
|
|
self.kp = kp
|
|
self.kv = kv
|
|
self.tau_ff = tau_ff
|
|
self.latest_command_stamp = time.time()
|
|
|
|
def step(self):
|
|
q, dq = self.getJointStates()
|
|
tau = np.diag(self.kp)@(self.q_des-q).reshape(12,1)+ \
|
|
np.diag(self.kv)@(self.dq_des-dq).reshape(12,1)+self.tau_ff.reshape(12,1)
|
|
self.data.ctrl[:] = tau.squeeze()
|
|
|
|
self.step_counter += 1
|
|
mujoco.mj_step(self.model, self.data)
|
|
# Render every render_ds_ratio steps (60Hz GUI update)
|
|
if self.render and (self.step_counter%self.render_ds_ratio)==0:
|
|
self.viewer.sync()
|
|
|
|
def getSiteJacobian(self, site_name):
|
|
id = mujoco.mj_name2id(self.model, mujoco.mjtObj.mjOBJ_SITE,site_name)
|
|
assert id>0, 'The requested site could not be found'
|
|
mujoco.mj_jacSite(self.model, self.data, self.jacp, self.jacr, id)
|
|
return self.jacp, self.jacr
|
|
|
|
def getDynamicsParams(self):
|
|
mujoco.mj_fullM(self.model, self.M, self.data.qM)
|
|
nle = self.data.qfrc_bias.reshape(self.nv,1)
|
|
return {
|
|
'M':self.M,
|
|
'nle':nle
|
|
}
|
|
|
|
def overheat(self):
|
|
return False
|
|
|
|
def close(self):
|
|
self.viewer.close()
|