| |
| import argparse, sys, os |
| from isaaclab.app import AppLauncher |
| import cli_args |
|
|
| parser = argparse.ArgumentParser() |
| parser.add_argument("--task", type=str, default=None) |
| parser.add_argument("--agent", type=str, default="rsl_rl_cfg_entry_point") |
| parser.add_argument("--grid", type=int, default=16, help="每个轴的网格点数 (G×G 格)") |
| parser.add_argument("--repeats", type=int, default=4, help="每格重复次数 (物理随机性求平均)") |
| parser.add_argument("--out", type=str, default="eval_grid_out", help="输出目录") |
| cli_args.add_rsl_rl_args(parser) |
| AppLauncher.add_app_launcher_args(parser) |
| args_cli, hydra_args = parser.parse_known_args() |
| sys.argv = [sys.argv[0]] + hydra_args |
|
|
| app_launcher = AppLauncher(args_cli) |
| simulation_app = app_launcher.app |
|
|
| import gymnasium as gym |
| import torch |
| from rsl_rl.runners import OnPolicyRunner |
| from isaaclab.envs import ManagerBasedRLEnvCfg |
| from isaaclab.utils.assets import retrieve_file_path |
| from isaaclab_rl.rsl_rl import RslRlVecEnvWrapper |
| import isaaclab_tasks |
| import uwlab_tasks |
| from uwlab_tasks.utils.hydra import hydra_task_config |
|
|
| |
| X_MIN, X_MAX = 0.30, 0.55 |
| Y_MIN, Y_MAX = -0.10, 0.30 |
| Z_REST = 0.0065 |
| RECEPTIVE_LOCAL = (0.45, 0.10, 0.0070) |
| UPRIGHT = (1.0, 0.0, 0.0, 0.0) |
|
|
|
|
| @hydra_task_config(args_cli.task, args_cli.agent) |
| def main(env_cfg: ManagerBasedRLEnvCfg, agent_cfg): |
| G, R = args_cli.grid, args_cli.repeats |
| num_envs = G * G * R |
| env_cfg.scene.num_envs = num_envs |
| agent_cfg = cli_args.update_rsl_rl_cfg(agent_cfg, args_cli) |
| agent_cfg = cli_args.sanitize_rsl_rl_cfg(agent_cfg) |
| env_cfg.seed = agent_cfg.seed |
|
|
| env = gym.make(args_cli.task, cfg=env_cfg) |
| env = RslRlVecEnvWrapper(env, clip_actions=agent_cfg.clip_actions) |
| u = env.unwrapped |
| device = u.device |
|
|
| |
| resume = retrieve_file_path(args_cli.checkpoint) |
| runner = OnPolicyRunner(env, agent_cfg.to_dict(), log_dir=None, device=agent_cfg.device) |
| runner.load(resume) |
| policy = runner.get_inference_policy(device=device) |
| try: |
| policy_nn = runner.alg.policy |
| except AttributeError: |
| policy_nn = runner.alg.actor_critic |
|
|
| |
| xs = torch.linspace(X_MIN, X_MAX, G, device=device) |
| ys = torch.linspace(Y_MIN, Y_MAX, G, device=device) |
| cell = torch.arange(num_envs, device=device) % (G * G) |
| ix, iy = cell % G, cell // G |
| gx, gy = xs[ix], ys[iy] |
|
|
| origins = u.scene.env_origins |
| ins = u.scene["insertive_object"] |
| rec = u.scene["receptive_object"] |
| pc = u.reward_manager.get_term_cfg("progress_context").func |
|
|
| def quat_t(q): |
| return torch.tensor(q, device=device).repeat(num_envs, 1) |
|
|
| def override_poses(): |
| |
| ins_pose = torch.zeros((num_envs, 7), device=device) |
| ins_pose[:, 0] = origins[:, 0] + gx |
| ins_pose[:, 1] = origins[:, 1] + gy |
| ins_pose[:, 2] = origins[:, 2] + Z_REST |
| ins_pose[:, 3:7] = quat_t(UPRIGHT) |
| ins.write_root_pose_to_sim(ins_pose) |
| ins.write_root_velocity_to_sim(torch.zeros((num_envs, 6), device=device)) |
| |
| rec_pose = torch.zeros((num_envs, 7), device=device) |
| rec_pose[:, 0] = origins[:, 0] + RECEPTIVE_LOCAL[0] |
| rec_pose[:, 1] = origins[:, 1] + RECEPTIVE_LOCAL[1] |
| rec_pose[:, 2] = origins[:, 2] + RECEPTIVE_LOCAL[2] |
| rec_pose[:, 3:7] = quat_t(UPRIGHT) |
| rec.write_root_pose_to_sim(rec_pose) |
| rec.write_root_velocity_to_sim(torch.zeros((num_envs, 6), device=device)) |
|
|
| |
| obs = env.get_observations() |
| env.reset() |
| override_poses() |
| u.sim.forward() |
| obs = env.get_observations() |
|
|
| ever_succ = torch.zeros(num_envs, dtype=torch.bool, device=device) |
| frozen = torch.zeros(num_envs, dtype=torch.bool, device=device) |
| steps = int(u.max_episode_length) |
| print(f"[eval] num_envs={num_envs} (G={G}, R={R}), steps/episode={steps}") |
|
|
| for t in range(steps): |
| with torch.inference_mode(): |
| actions = policy(obs) |
| obs, _, dones, _ = env.step(actions) |
| policy_nn.reset(dones) |
| succ = pc.success.clone() |
| ever_succ |= (succ & ~frozen) |
| frozen |= dones.bool() |
|
|
| |
| succ_f = ever_succ.float().view(R, G * G).mean(dim=0) |
| rate = succ_f.view(G, G).cpu().numpy() |
| xs_np, ys_np = xs.cpu().numpy(), ys.cpu().numpy() |
|
|
| os.makedirs(args_cli.out, exist_ok=True) |
| import numpy as np |
| np.save(os.path.join(args_cli.out, "success_rate.npy"), rate) |
| with open(os.path.join(args_cli.out, "success_rate.csv"), "w") as f: |
| f.write("x,y,success_rate\n") |
| for j in range(G): |
| for i in range(G): |
| f.write(f"{xs_np[i]:.4f},{ys_np[j]:.4f},{rate[j,i]:.4f}\n") |
|
|
| try: |
| import matplotlib |
| matplotlib.use("Agg") |
| import matplotlib.pyplot as plt |
| plt.figure(figsize=(6, 5)) |
| plt.imshow(rate, origin="lower", aspect="auto", |
| extent=[X_MIN, X_MAX, Y_MIN, Y_MAX], vmin=0, vmax=1, cmap="RdYlGn") |
| plt.colorbar(label="success rate") |
| plt.xlabel("insertive cube x (local)"); plt.ylabel("insertive cube y (local)") |
| plt.title("Cube expert failure map") |
| plt.scatter([RECEPTIVE_LOCAL[0]], [RECEPTIVE_LOCAL[1]], c="blue", marker="*", s=120, label="receptive") |
| plt.legend() |
| plt.savefig(os.path.join(args_cli.out, "failure_map.png"), dpi=130, bbox_inches="tight") |
| print(f"[eval] saved heatmap -> {args_cli.out}/failure_map.png") |
| except Exception as e: |
| print(f"[eval] heatmap skipped: {e}") |
|
|
| print(f"[eval] overall success rate = {ever_succ.float().mean().item():.3f}") |
| env.close() |
|
|
|
|
| if __name__ == "__main__": |
| main() |
| simulation_app.close() |