Note
Go to the end to download the full example code
Ergo manipulation#
Visualize ergonomics and manipulability of a humanoid robot using Optitrack data and Jacobian matrix.
import isaacgym
from rofunc.utils.datalab.poselib.robot_utils.HOTU.optitrack_fbx_to_hotu_npy import *
from rofunc.config.utils import omegaconf_to_dict, get_config
from rofunc.learning.RofuncRL.tasks import Tasks
from rofunc.learning.RofuncRL.trainers import Trainers
from tqdm import tqdm
import argparse
import multiprocessing
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import csv
import os
def inference(custom_args):
task_name = "HumanoidASEViewMotion"
args_overrides = [
f"task={task_name}",
"train=HumanoidASEViewMotionASERofuncRL",
f"device_id=0",
f"rl_device=cuda:{gpu_id}",
"headless={}".format(True),
"num_envs={}".format(1),
]
cfg = get_config("./learning/rl", "config", args=args_overrides)
cfg.task.env.motion_file = custom_args.motion_file
cfg.task.env.asset.assetFileName = custom_args.humanoid_asset
cfg_dict = omegaconf_to_dict(cfg.task)
# Instantiate the Isaac Gym environment
infer_env = Tasks().task_map[task_name](cfg=cfg_dict,
rl_device=cfg.rl_device,
sim_device=f'cuda:{cfg.device_id}',
graphics_device_id=cfg.device_id,
headless=cfg.headless,
virtual_screen_capture=cfg.capture_video,
force_render=cfg.force_render,
csv_path=rf.oslab.get_rofunc_path(
f'../examples/data/hotu2/{input_file_name}.csv'))
# Instantiate the RL trainer
trainer = Trainers().trainer_map["ase"](cfg=cfg,
env=infer_env,
device=cfg.rl_device,
env_name=task_name,
hrl=False,
inference=True)
# Start inference
trainer.inference()
def update(frame):
ax.clear()
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
ax.set_zlim(0, 2)
ax.set_xlabel('X')
ax.set_ylabel('Y')
ax.set_zlabel('Z')
joint_rotations = skeleton_joint[frame]
global_positions, global_rotations = rf.maniplab.forward_kinematics(skeleton_joint_local_translation,
joint_rotations, skeleton_parent_indices)
rf.visualab.plot_skeleton(ax, global_positions, skeleton_parent_indices)
right_hand_index = 5
left_hand_index = 8
jacobian_right = np.squeeze(jacobians_right[frame])
eigenvalues_right, eigenvectors_right = rf.maniplab.calculate_manipulability(jacobian_right)
rf.visualab.plot_ellipsoid(ax, eigenvalues_right, eigenvectors_right, global_positions[right_hand_index], 'b')
jacobian_left = np.squeeze(jacobians_left[frame])
eigenvalues_left, eigenvectors_left = rf.maniplab.calculate_manipulability(jacobian_left)
rf.visualab.plot_ellipsoid(ax, eigenvalues_left, eigenvectors_left, global_positions[left_hand_index], 'r')
rf.visualab.plot_skeleton(ax, global_positions, skeleton_parent_indices)
# Define a structure to map joint types to their corresponding functions and indices
joint_analysis = {
'upper_arm': {
'indices': [skeleton_joint_name.index('right_upper_arm'), skeleton_joint_name.index('left_upper_arm')],
'degree_func': rf.robolab.ergonomics.UpperArmDegree(global_positions).upper_arm_degrees,
'reba_func': rf.robolab.ergonomics.UAREBA,
'score_func': lambda reba: reba.upper_arm_reba_score(),
'color_func': rf.visualab.ua_get_color
},
'lower_arm': {
'indices': [skeleton_joint_name.index('right_lower_arm'), skeleton_joint_name.index('left_lower_arm')],
'degree_func': rf.robolab.ergonomics.LADegrees(global_positions).lower_arm_degree,
'reba_func': rf.robolab.ergonomics.LAREBA,
'score_func': lambda reba: reba.lower_arm_score(),
'color_func': rf.visualab.la_get_color
},
'trunk': {
'indices': [skeleton_joint_name.index('pelvis')],
'degree_func': rf.robolab.ergonomics.TrunkDegree(global_positions, global_rotations).trunk_degrees,
'reba_func': rf.robolab.ergonomics.TrunkREBA,
'score_func': lambda reba: reba.trunk_reba_score(),
'color_func': rf.visualab.trunk_get_color
}
}
# Process each joint type with its corresponding REBA analysis and coloring
for joint_type, settings in joint_analysis.items():
degrees = settings['degree_func']()
reba = settings['reba_func'](degrees)
scores = settings['score_func'](reba)
for i, idx in enumerate(settings['indices']):
score = scores[i]
color = settings['color_func'](score)
ax.scatter(*global_positions[idx], color=color, s=100) # Use scatter for single points
if __name__ == "__main__":
gpu_id = 0
input_file_name = 'demo_3_andrew_only'
# # Calculate from optitrack data to HOTU joint information
parser = argparse.ArgumentParser()
parser.add_argument("--fbx_dir", type=str, default=None)
parser.add_argument("--fbx_file", type=str,
default=f"{rf.oslab.get_rofunc_path()}/../examples/data/hotu2/{input_file_name}_optitrack.fbx")
parser.add_argument("--parallel", action="store_true")
parser.add_argument("--humanoid_asset", type=str, default="mjcf/hotu/hotu_humanoid.xml")
parser.add_argument("--target_tpose", type=str,
default="utils/datalab/poselib/data/target_hotu_humanoid_tpose.npy")
args = parser.parse_args()
rofunc_path = rf.oslab.get_rofunc_path()
if args.fbx_dir is not None:
fbx_dir = args.fbx_dir
fbx_files = rf.oslab.list_absl_path(fbx_dir, suffix='.fbx')
elif args.fbx_file is not None:
fbx_files = [args.fbx_file]
else:
raise ValueError("Please provide a valid fbx_dir or fbx_file.")
if args.parallel:
pool = multiprocessing.Pool()
pool.map(npy_from_fbx, fbx_files)
else:
with tqdm(total=len(fbx_files)) as pbar:
for fbx_file in fbx_files:
npy_from_fbx(args, fbx_file)
pbar.update(1)
# # # Calculate joint angles
parser.add_argument("--motion_file", type=str, default=rf.oslab.get_rofunc_path(
f"../examples/data/hotu2/{input_file_name}_optitrack2hotu.npy"))
custom_args = parser.parse_args()
inference(custom_args)
# # Calculate Jacobian matrix
rf.logger.beauty_print("########## Jacobian from URDF or MuJoCo XML files with RobotModel class ##########")
model_path = "../../rofunc/simulator/assets/mjcf/hotu/hotu_humanoid.xml"
joint_value = [0.1 for _ in range(34)]
export_links = ["right_hand_2", "left_hand_2"]
robot = rf.robolab.RobotModel(model_path, solve_engine="pytorch_kinematics", verbose=True)
input_csv_path = rf.oslab.get_rofunc_path(
f'../examples/data/hotu2/{input_file_name}.csv')
save_directory = rf.oslab.get_rofunc_path('../examples/data/jacobian_data')
if not os.path.exists(save_directory):
os.makedirs(save_directory)
jacobians = {link: [] for link in export_links}
with open(input_csv_path, mode='r') as file:
reader = csv.reader(file)
joint_data = list(reader)
for joint_values in joint_data:
joint_values = list(map(float, joint_values))
for link in export_links:
J = robot.get_jacobian(joint_values, link)
jacobians[link].append(J)
for link in export_links:
filename = os.path.join(save_directory, f'jacobian_{input_file_name}_{link}.npy')
np.save(filename, np.array(jacobians[link]))
print(f"Saved all Jacobians for {link} to {filename}")
# # Calculate and draw skeleton model, ergonomics and manipulability
skeleton_joint_name, skeleton_joint, skeleton_parent_indices, skeleton_joint_local_translation = rf.maniplab.read_skeleton_motion(
rf.oslab.get_rofunc_path(f'../examples/data/hotu2/{input_file_name}_optitrack2hotu.npy'))
skeleton_joint = skeleton_joint[::40, :, :]
jacobians_left = np.array(jacobians["left_hand_2"])[
::10]
jacobians_right = np.array(jacobians["right_hand_2"])[::10]
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
ani = FuncAnimation(fig, update, frames=len(skeleton_joint), repeat=True)
# ani.save('/home/ubuntu/Ergo-Manip/data/gif/demo_2_andrew.gif', writer='imagemagick', fps=3)
plt.show()
Total running time of the script: (0 minutes 0.000 seconds)