LIBERO 工具脚本完全讲解

LIBERO 工具脚本完全讲解

这是对LIBERO项目中10个核心工具脚本的详细讲解文档。


📋 脚本总览

脚本名称功能使用场景难度
init_path.py路径初始化所有脚本的前置依赖
check_dataset_integrity.py数据集完整性检查验证数据集质量
get_dataset_info.py数据集信息查看分析数据集统计
get_affordance_info.py可交互区域信息查看对象交互能力
config_copy.py配置文件复制初始化项目配置
create_libero_task_example.py任务创建示例学习任务创建⭐⭐
create_template.py模板生成工具快速创建新组件⭐⭐
collect_demonstration.py人类演示收集收集单个任务数据⭐⭐⭐
libero_100_collect_demonstrations.pyLIBERO-100数据收集批量收集数据⭐⭐⭐
create_dataset.py数据集生成转换演示为训练数据⭐⭐⭐

1️⃣ init_path.py - 路径初始化

📖 功能说明

这是一个简单但关键的初始化脚本,用于将LIBERO包路径添加到Python搜索路径中。

💻 完整代码

import sys
import os

path = os.path.dirname(os.path.realpath(__file__))
sys.path.insert(0, os.path.join(path, "../"))

🔑 核心逻辑

  1. 获取当前脚本所在目录的绝对路径
  2. 将上级目录添加到sys.path最前面
  3. 确保可以导入LIBERO包

💡 使用场景

# 在其他脚本开头导入
import init_path  # 必须在导入libero之前

from libero.libero import benchmark
from libero.libero.envs import *

⚠️ 注意事项

  • 必须在所有LIBERO导入之前执行
  • 适用于在scripts/目录下运行脚本的情况
  • 如果已经正确安装LIBERO包,可以不需要这个脚本

2️⃣ check_dataset_integrity.py - 数据集完整性检查

📖 功能说明

自动扫描并验证LIBERO数据集的完整性,检查每个数据集是否包含正确数量的演示轨迹。

🔑 核心功能

检查项目:
  1. ✅ 每个数据集是否有50个演示轨迹
  2. ✅ 轨迹长度统计(均值和标准差)
  3. ✅ 动作范围检查
  4. ✅ 数据集版本标签验证

💻 核心代码逻辑

from pathlib import Path
import h5py
import numpy as np
from libero.libero import get_libero_path

error_datasets = []

# 递归查找所有HDF5文件
for demo_file_name in Path(get_libero_path("datasets")).rglob("*hdf5"):
    demo_file = h5py.File(demo_file_name)
    
    # 统计演示数量
    count = 0
    for key in demo_file["data"].keys():
        if "demo" in key:
            count += 1
    
    if count == 50:  # LIBERO标准:每任务50个演示
        # 统计轨迹长度
        traj_lengths = []
        for demo_name in demo_file["data"].keys():
            traj_lengths.append(
                demo_file["data/{}/actions".format(demo_name)].shape[0]
            )
        
        traj_lengths = np.array(traj_lengths)
        print(f"✔ dataset {demo_file_name} is intact")
        print(f"Mean length: {np.mean(traj_lengths)} ± {np.std(traj_lengths)}")
        
        # 检查版本
        if demo_file["data"].attrs["tag"] == "libero-v1":
            print("Version correct")
    else:
        print(f"❌ Error: {demo_file_name} has {count} demos (expected 50)")
        error_datasets.append(demo_file_name)

# 报告错误
if len(error_datasets) > 0:
    print("\n[error] The following datasets are corrupted:")
    for dataset in error_datasets:
        print(dataset)

📊 输出示例

[info] dataset libero_spatial/demo_0.hdf5 is intact, test passed ✔
124.5  +-  15.3
Version correct
=========================================
[info] dataset libero_object/demo_1.hdf5 is intact, test passed ✔
156.2  +-  22.7
Version correct
=========================================

💡 使用方法

# 检查所有数据集
python check_dataset_integrity.py

# 自动扫描 ~/.libero/datasets/ 目录下的所有HDF5文件

🎯 应用场景

  • 下载数据集后验证完整性
  • 数据收集后的质量检查
  • 定期验证数据集状态
  • 诊断数据集问题

3️⃣ get_dataset_info.py - 数据集信息查看

📖 功能说明

详细报告HDF5数据集的统计信息、元数据和结构,是数据集分析的利器。

🔑 主要功能

报告内容:
  1. 📊 轨迹统计(总数、长度分布)
  2. 🎯 动作范围(最大/最小值)
  3. 🗣️ 语言指令
  4. 🔖 过滤键(Filter Keys)
  5. 🌍 环境元数据
  6. 📦 数据结构详情

💻 核心代码解析

import h5py
import json
import argparse
import numpy as np

parser = argparse.ArgumentParser()
parser.add_argument("--dataset", type=str, help="path to hdf5 dataset")
parser.add_argument("--filter_key", type=str, default=None)
parser.add_argument("--verbose", action="store_true")
args = parser.parse_args()

f = h5py.File(args.dataset, "r")

# 获取演示列表
if args.filter_key is not None:
    demos = sorted([elem.decode("utf-8") 
                   for elem in np.array(f["mask/{}".format(args.filter_key)])])
else:
    demos = sorted(list(f["data"].keys()))

# 统计轨迹长度和动作范围
traj_lengths = []
action_min = np.inf
action_max = -np.inf

for ep in demos:
    traj_lengths.append(f["data/{}/actions".format(ep)].shape[0])
    action_min = min(action_min, np.min(f["data/{}/actions".format(ep)][()]))
    action_max = max(action_max, np.max(f["data/{}/actions".format(ep)][()]))

traj_lengths = np.array(traj_lengths)

# 报告统计信息
print("")
print(f"total transitions: {np.sum(traj_lengths)}")
print(f"total trajectories: {traj_lengths.shape[0]}")
print(f"traj length mean: {np.mean(traj_lengths)}")
print(f"traj length std: {np.std(traj_lengths)}")
print(f"traj length min: {np.min(traj_lengths)}")
print(f"traj length max: {np.max(traj_lengths)}")
print(f"action min: {action_min}")
print(f"action max: {action_max}")

# 获取语言指令
problem_info = json.loads(f["data"].attrs["problem_info"])
language_instruction = problem_info["language_instruction"]
print(f"language instruction: {language_instruction.strip('\"')}")

# 报告数据结构
print("\n==== Dataset Structure ====")
for ep in demos:
    print(f"episode {ep} with {f['data/{}'.format(ep)].attrs['num_samples']} transitions")
    for k in f["data/{}".format(ep)]:
        if k in ["obs", "next_obs"]:
            print(f"    key: {k}")
            for obs_k in f["data/{}/{}".format(ep, k)]:
                shape = f["data/{}/{}/{}".format(ep, k, obs_k)].shape
                print(f"        observation key {obs_k} with shape {shape}")
        elif isinstance(f["data/{}/{}".format(ep, k)], h5py.Dataset):
            key_shape = f["data/{}/{}".format(ep, k)].shape
            print(f"    key: {k} with shape {key_shape}")
    
    if not args.verbose:
        break  # 只显示第一个演示的结构

f.close()

# 验证动作范围
if (action_min < -1.0) or (action_max > 1.0):
    raise Exception(f"Actions should be in [-1., 1.] but got [{action_min}, {action_max}]")

📊 输出示例

total transitions: 6247
total trajectories: 50
traj length mean: 124.94
traj length std: 15.32
traj length min: 95
traj length max: 168
action min: -0.9876
action max: 0.9912
language instruction: put the black bowl on the plate

==== Filter Keys ====
filter key train with 45 demos
filter key valid with 5 demos

==== Env Meta ====
{
    "type": 1,
    "env_name": "KITCHEN_SCENE1_put_the_black_bowl_on_the_plate",
    "problem_name": "KITCHEN_SCENE1_put_the_black_bowl_on_the_plate",
    "bddl_file": "libero/bddl_files/kitchen_scene1/...",
    "env_kwargs": {...}
}

==== Dataset Structure ====
episode demo_0 with 124 transitions
    key: obs
        observation key agentview_rgb with shape (124, 128, 128, 3)
        observation key eye_in_hand_rgb with shape (124, 128, 128, 3)
        observation key gripper_states with shape (124, 2)
        observation key joint_states with shape (124, 7)
    key: actions with shape (124, 7)
    key: rewards with shape (124,)
    key: dones with shape (124,)

💡 使用方法

# 查看基本信息
python get_dataset_info.py --dataset path/to/demo.hdf5

# 查看训练集子集
python get_dataset_info.py --dataset demo.hdf5 --filter_key train

# 详细模式(显示所有演示结构)
python get_dataset_info.py --dataset demo.hdf5 --verbose

🎯 应用场景

  • 分析数据集特性
  • 验证数据格式
  • 调试数据加载问题
  • 评估数据质量

4️⃣ get_affordance_info.py - 可交互区域信息

📖 功能说明

提取所有对象的可交互区域(affordance regions)信息,显示对象支持哪些交互操作。

💻 完整代码

import init_path
from libero.libero.envs.objects import OBJECTS_DICT
from libero.libero.utils.object_utils import get_affordance_regions

# 获取所有对象的可交互区域
affordances = get_affordance_regions(OBJECTS_DICT)

print(affordances)

📊 输出示例

{
    'microwave': {
        'regions': ['inside', 'top'],
        'actions': ['open', 'close', 'put_in']
    },
    'wooden_cabinet': {
        'regions': ['top_region', 'bottom_region', 'door'],
        'actions': ['open', 'close', 'put_on', 'put_in']
    },
    'plate': {
        'regions': ['surface'],
        'actions': ['put_on']
    },
    'basket': {
        'regions': ['inside'],
        'actions': ['put_in']
    },
    'flat_stove': {
        'regions': ['burner_1', 'burner_2', 'burner_3', 'burner_4'],
        'actions': ['turnon', 'turnoff', 'put_on']
    }
}

🔑 关键概念

**Affordance(可供性/可交互性)**指对象支持的交互能力:

  • 容器类(microwave, basket):可以放入物体(put_in
  • 表面类(plate, table):可以放置物体(put_on
  • 可开关类(cabinet, fridge):可以打开/关闭(open/close
  • 可控制类(stove, faucet):可以开启/关闭(turnon/turnoff

💡 使用方法

# 直接运行
python get_affordance_info.py

# 输出会显示所有对象及其可交互区域

🎯 应用场景

  • 任务设计:了解哪些对象支持哪些操作
  • BDDL文件编写:确定可用的谓词和区域
  • 调试任务:验证交互操作的可行性
  • 文档编写:生成对象能力清单

5️⃣ config_copy.py - 配置文件复制

📖 功能说明

将LIBERO的配置文件复制到当前项目目录,方便自定义和修改配置。

💻 完整代码

import os
import shutil
from libero.libero import get_libero_path

def main():
    target_path = os.path.abspath(os.path.join("./", "configs"))
    print(f"Copying configs to {target_path}")
    
    # 检查目标目录是否已存在
    if os.path.exists(target_path):
        response = input("The target directory already exists. Overwrite it? (y/n) ")
        if response.lower() != "y":
            return
        shutil.rmtree(target_path)
    
    # 复制配置文件
    shutil.copytree(
        os.path.join(get_libero_path("benchmark_root"), "../configs"),
        target_path
    )
    print("✔ Configs copied successfully!")

if __name__ == "__main__":
    main()

📁 复制的配置结构

configs/
├── config.yaml           # 主配置文件
├── data/
│   └── default.yaml      # 数据配置
├── eval/
│   └── default.yaml      # 评估配置
├── lifelong/
│   ├── base.yaml         # 基础算法配置
│   ├── er.yaml           # 经验回放配置
│   ├── ewc.yaml          # EWC配置
│   └── packnet.yaml      # PackNet配置
├── policy/
│   ├── bc_rnn_policy.yaml        # RNN策略配置
│   ├── bc_transformer_policy.yaml # Transformer策略配置
│   └── bc_vilt_policy.yaml       # ViLT策略配置
└── train/
    └── default.yaml      # 训练配置

🔑 配置文件说明

主配置文件 (config.yaml)
defaults:
  - data: default
  - eval: default
  - policy: bc_transformer_policy
  - lifelong: base
  - train: default

seed: 42
benchmark_name: libero_spatial
folder: ${libero.datasets}
策略配置示例 (bc_transformer_policy.yaml)
policy_type: BCTransformerPolicy
transformer_num_layers: 4
transformer_num_heads: 6
transformer_max_seq_len: 10
image_encoder:
  network: ResnetEncoder
  network_kwargs:
    language_fusion: film
    freeze: false

💡 使用方法

# 复制配置文件
python config_copy.py

# 之后可以修改 ./configs/ 目录下的配置

🎯 应用场景

  • 初始化新项目
  • 自定义实验配置
  • 创建不同的配置变体
  • 版本控制配置文件

6️⃣ create_libero_task_example.py - 任务创建示例

📖 功能说明

演示如何通过代码创建LIBERO任务,生成BDDL文件。这是学习任务创建的最佳起点。

💻 完整代码详解

import numpy as np
from libero.libero.utils.bddl_generation_utils import (
    get_xy_region_kwargs_list_from_regions_info,
)
from libero.libero.utils.mu_utils import register_mu, InitialSceneTemplates
from libero.libero.utils.task_generation_utils import (
    register_task_info,
    generate_bddl_from_task_info,
)

# ============= 第1步: 定义场景 =============
@register_mu(scene_type="kitchen")
class KitchenScene1(InitialSceneTemplates):
    """
    定义一个厨房场景,包含:
    - 1个厨房桌子(工作空间)
    - 1个木制橱柜
    - 1个黑碗
    - 1个盘子
    """
    def __init__(self):
        # 定义固定装置(fixtures)
        fixture_num_info = {
            "kitchen_table": 1,      # 桌子
            "wooden_cabinet": 1,     # 橱柜
        }
        
        # 定义可操作对象(objects)
        object_num_info = {
            "akita_black_bowl": 1,   # 黑碗
            "plate": 1,              # 盘子
        }
        
        super().__init__(
            workspace_name="kitchen_table",  # 工作空间名称
            fixture_num_info=fixture_num_info,
            object_num_info=object_num_info,
        )
    
    def define_regions(self):
        """定义对象的初始放置区域"""
        
        # 橱柜的放置区域(桌子后方)
        self.regions.update(
            self.get_region_dict(
                region_centroid_xy=[0.0, -0.30],  # 中心坐标 (x, y)
                region_name="wooden_cabinet_init_region",
                target_name=self.workspace_name,
                region_half_len=0.01,              # 区域半径(米)
                yaw_rotation=(np.pi, np.pi),       # 旋转角度
            )
        )
        
        # 黑碗的放置区域(桌子中央)
        self.regions.update(
            self.get_region_dict(
                region_centroid_xy=[0.0, 0.0],
                region_name="akita_black_bowl_init_region",
                target_name=self.workspace_name,
                region_half_len=0.025,
            )
        )
        
        # 盘子的放置区域(桌子前方)
        self.regions.update(
            self.get_region_dict(
                region_centroid_xy=[0.0, 0.25],
                region_name="plate_init_region",
                target_name=self.workspace_name,
                region_half_len=0.025,
            )
        )
        
        # 生成区域参数列表
        self.xy_region_kwargs_list = get_xy_region_kwargs_list_from_regions_info(
            self.regions
        )
    
    @property
    def init_states(self):
        """定义初始状态约束"""
        states = [
            ("On", "akita_black_bowl_1", "kitchen_table_akita_black_bowl_init_region"),
            ("On", "plate_1", "kitchen_table_plate_init_region"),
            ("On", "wooden_cabinet_1", "kitchen_table_wooden_cabinet_init_region"),
        ]
        return states


# ============= 第2步: 定义任务 =============
def main():
    # 任务1: 打开橱柜顶层并把碗放进去
    scene_name = "kitchen_scene1"
    language = "open the top cabinet and put the black bowl in it"
    register_task_info(
        language,
        scene_name=scene_name,
        objects_of_interest=["wooden_cabinet_1", "akita_black_bowl_1"],
        goal_states=[
            ("Open", "wooden_cabinet_1_top_region"),          # 打开顶层
            ("In", "akita_black_bowl_1", "wooden_cabinet_1_top_region"),  # 碗在里面
        ],
    )
    
    # 任务2: 打开橱柜底层并把碗放进去
    language = "open the bottom cabinet and put the black bowl in it"
    register_task_info(
        language,
        scene_name=scene_name,
        objects_of_interest=["wooden_cabinet_1", "akita_black_bowl_1"],
        goal_states=[
            ("Open", "wooden_cabinet_1_top_region"),          # 打开顶层(需要先开)
            ("In", "akita_black_bowl_1", "wooden_cabinet_1_bottom_region"),  # 碗在底层
        ],
    )
    
    # ============= 第3步: 生成BDDL文件 =============
    bddl_file_names, failures = generate_bddl_from_task_info()
    
    print("✔ Successfully generated BDDL files:")
    for file_name in bddl_file_names:
        print(f"  - {file_name}")
    
    if failures:
        print("\n❌ Failed to generate:")
        for failure in failures:
            print(f"  - {failure}")

if __name__ == "__main__":
    main()

🔑 关键步骤详解

Step 1: 场景定义
@register_mu(scene_type="kitchen")  # 注册为厨房场景
class KitchenScene1(InitialSceneTemplates):
    # 继承自InitialSceneTemplates基类

包含三个方法:

  1. __init__: 声明场景中的对象
  2. define_regions: 定义对象放置区域
  3. init_states: 定义初始状态约束
Step 2: 任务注册
register_task_info(
    language,                    # 自然语言指令
    scene_name=scene_name,      # 使用的场景
    objects_of_interest=[...],  # 关键对象
    goal_states=[...],          # 目标状态
)
Step 3: BDDL生成
bddl_file_names, failures = generate_bddl_from_task_info()

📊 生成的BDDL文件示例

(define (problem KITCHEN_SCENE1_open_the_top_cabinet_and_put_the_black_bowl_in_it)
  (:domain libero)
  (:language "open the top cabinet and put the black bowl in it")
  
  (:objects
    kitchen_table - kitchen_table
    wooden_cabinet_1 - wooden_cabinet
    akita_black_bowl_1 - akita_black_bowl
    plate_1 - plate
  )
  
  (:init
    (On akita_black_bowl_1 kitchen_table_akita_black_bowl_init_region)
    (On plate_1 kitchen_table_plate_init_region)
    (On wooden_cabinet_1 kitchen_table_wooden_cabinet_init_region)
  )
  
  (:goal
    (And
      (Open wooden_cabinet_1_top_region)
      (In akita_black_bowl_1 wooden_cabinet_1_top_region)
    )
  )
)

💡 使用方法

# 运行示例
python create_libero_task_example.py

# BDDL文件会生成在默认位置
# 可以在脚本中指定输出目录

🎯 学习要点

  1. 场景定义: 装置vs对象的区别
  2. 区域设置: 坐标系统和尺寸
  3. 状态约束: 谓词的使用方法
  4. 任务目标: 组合多个条件

7️⃣ create_template.py - 模板生成工具

📖 功能说明

交互式工具,用于快速生成LIBERO扩展组件的模板文件,大幅减少重复代码编写。

💻 核心功能

import os
import xml.etree.ElementTree as ET
from libero.libero import get_libero_path
from libero.libero.envs.textures import get_texture_file_list

def create_problem_class_from_file(class_name):
    """从模板创建问题类文件"""
    template_source_file = os.path.join(
        get_libero_path("benchmark_root"), 
        "../../templates/problem_class_template.py"
    )
    
    # 读取模板
    with open(template_source_file, "r") as f:
        lines = f.readlines()
    
    # 替换占位符
    new_lines = []
    for line in lines:
        if "YOUR_CLASS_NAME" in line:
            line = line.replace("YOUR_CLASS_NAME", class_name)
        new_lines.append(line)
    
    # 保存新文件
    output_file = f"{class_name.lower()}.py"
    with open(output_file, "w") as f:
        f.writelines(new_lines)
    
    print(f"✔ Created class {class_name} at: {output_file}")


def create_scene_xml_file(scene_name):
    """交互式创建场景XML文件"""
    template_source_file = os.path.join(
        get_libero_path("benchmark_root"),
        "../../templates/scene_template.xml"
    )
    
    # 解析XML模板
    parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True))
    tree = ET.parse(template_source_file, parser)
    root = tree.getroot()
    
    # 定义需要选择纹理的元素
    basic_elements = [
        ("Floor", "texplane"),
        ("Table", "tex-table"),
        ("Table legs", "tex-table-legs"),
        ("Walls", "tex-wall"),
    ]
    
    # 为每个元素选择纹理
    for (element_name, texture_name) in basic_elements:
        element = root.findall('.//texture[@name="{}"]'.format(texture_name))[0]
        
        # 确定纹理类型
        type = None
        if "floor" in element_name.lower():
            type = "floor"
        elif "table" in element_name.lower():
            type = "table"
        elif "wall" in element_name.lower():
            type = "wall"
        
        # 获取可用纹理列表
        texture_list = get_texture_file_list(type=type, texture_path="../")
        
        # 显示选项
        for i, (texture_name, texture_file_path) in enumerate(texture_list):
            print(f"[{i}]: {texture_name}")
        
        # 用户选择
        choice = int(input(f"Select texture for {element_name}: "))
        element.set("file", texture_list[choice][1])
    
    # 保存XML文件
    output_file = f"{scene_name}.xml"
    tree.write(output_file, encoding="utf-8")
    print(f"✔ Created scene {scene_name} at: {output_file}")
    print("\n[Notice] Texture paths assume the XML will be in libero/libero/assets/scenes/")


def main():
    # 显示选项
    choices = [
        "problem_class",  # 问题类Python文件
        "scene",          # 场景XML文件
        "object",         # 对象定义(保留)
        "arena",          # 竞技场定义(保留)
    ]
    
    print("=== LIBERO Template Generator ===")
    for i, choice in enumerate(choices):
        print(f"[{i}]: {choice}")
    
    choice = int(input("Select which file to create: "))
    
    if choices[choice] == "problem_class":
        class_name = input("Specify the class name: ")
        assert " " not in class_name, "Space not allowed in naming"
        
        # 标准化类名(首字母大写)
        parts = class_name.split("_")
        class_name = "_".join([part.lower().capitalize() for part in parts])
        
        create_problem_class_from_file(class_name)
        
    elif choices[choice] == "scene":
        scene_name = input("Specify the scene name: ")
        scene_name = scene_name.lower()
        assert " " not in scene_name, "Space not allowed in naming"
        
        create_scene_xml_file(scene_name)

🎬 使用示例

创建问题类
$ python create_template.py

=== LIBERO Template Generator ===
[0]: problem_class
[1]: scene
[2]: object
[3]: arena
Select which file to create: 0
Specify the class name: my_custom_task

✔ Created class My_Custom_Task at: my_custom_task.py

生成的模板内容:

from libero.libero.envs.base_env import LiberoBaseEnv
import numpy as np

class My_Custom_Task(LiberoBaseEnv):
    """
    YOUR TASK DESCRIPTION HERE
    """
    def __init__(self, bddl_file_name, **kwargs):
        super().__init__(bddl_file_name, **kwargs)
    
    def _check_success(self):
        """
        Check if the task is successfully completed.
        Returns:
            bool: True if task is complete
        """
        # TODO: Implement success condition
        return self._check_goal_satisfied()
    
    # TODO: Add custom methods if needed
创建场景XML
$ python create_template.py

Select which file to create: 1
Specify the scene name: my_kitchen

Select texture for Floor:
[0]: light_wood
[1]: dark_wood
[2]: tile_gray
[3]: tile_white
Select: 2

Select texture for Table:
[0]: wood_light
[1]: wood_dark
[2]: metal
Select: 0

Select texture for Walls:
[0]: white
[1]: beige
[2]: gray
Select: 1

✔ Created scene my_kitchen at: my_kitchen.xml

📋 模板类型说明

模板类型生成内容用途
problem_classPython类文件自定义任务逻辑
sceneXML场景文件定义3D环境
object对象定义新对象类型
arena竞技场自定义工作空间

🎯 应用场景

  • 快速原型开发
  • 减少样板代码
  • 标准化组件结构
  • 新手学习模板

8️⃣ collect_demonstration.py - 人类演示收集

📖 功能说明

使用SpaceMouse或键盘收集人类操作演示数据,是创建高质量训练数据的核心工具。

🔑 核心流程

初始化环境 → 人类操控 → 记录轨迹 → 检查成功 → 保存HDF5

💻 核心代码详解

1. 轨迹收集函数
def collect_human_trajectory(
    env, device, arm, env_configuration, problem_info, remove_directory=[]
):
    """
    使用输入设备收集演示轨迹
    
    Args:
        env: MuJoCo环境
        device: 输入设备(SpaceMouse或键盘)
        arm: 控制的机械臂('right' 或 'left')
        env_configuration: 环境配置
        problem_info: 任务信息
        remove_directory: 要移除的目录列表
    
    Returns:
        saving: 是否保存该轨迹
    """
    # 重置环境
    reset_success = False
    while not reset_success:
        try:
            env.reset()
            reset_success = True
        except:
            continue
    
    env.render()
    
    # 任务完成计数器
    task_completion_hold_count = -1
    device.start_control()
    
    saving = True
    count = 0
    
    while True:
        count += 1
        
        # 获取动作
        active_robot = env.robots[0] if env_configuration == "bimanual" else env.robots[arm == "left"]
        action, grasp = input2action(
            device=device,
            robot=active_robot,
            active_arm=arm,
            env_configuration=env_configuration,
        )
        
        # 按ESC退出不保存
        if action is None:
            print("Break - Not saving")
            saving = False
            break
        
        # 执行动作
        env.step(action)
        env.render()
        
        # 检查任务完成
        if task_completion_hold_count == 0:
            break
        
        # 状态机:检查连续10步成功
        if env._check_success():
            if task_completion_hold_count > 0:
                task_completion_hold_count -= 1
            else:
                task_completion_hold_count = 10  # 首次成功
        else:
            task_completion_hold_count = -1
    
    print(f"Episode length: {count}")
    
    if not saving:
        remove_directory.append(env.ep_directory.split("/")[-1])
    
    env.close()
    return saving
2. HDF5数据保存函数
def gather_demonstrations_as_hdf5(
    directory, out_dir, env_info, args, remove_directory=[]
):
    """
    将演示数据收集为HDF5格式
    
    HDF5结构:
    data/
        ├── [attributes] 元数据
        ├── demo_1/
        │   ├── [attribute] model_file
        │   ├── states (dataset)
        │   └── actions (dataset)
        ├── demo_2/
        └── ...
    """
    hdf5_path = os.path.join(out_dir, "demo.hdf5")
    f = h5py.File(hdf5_path, "w")
    grp = f.create_group("data")
    
    num_eps = 0
    env_name = None
    
    # 遍历所有轨迹文件
    for ep_directory in os.listdir(directory):
        if ep_directory in remove_directory:
            continue
        
        state_paths = os.path.join(directory, ep_directory, "state_*.npz")
        states = []
        actions = []
        
        # 加载状态和动作
        for state_file in sorted(glob(state_paths)):
            dic = np.load(state_file, allow_pickle=True)
            env_name = str(dic["env"])
            states.extend(dic["states"])
            for ai in dic["action_infos"]:
                actions.append(ai["actions"])
        
        if len(states) == 0:
            continue
        
        # 删除第一个动作和最后一个状态(数据收集机制导致)
        del states[-1]
        assert len(states) == len(actions)
        
        num_eps += 1
        ep_data_grp = grp.create_group(f"demo_{num_eps}")
        
        # 保存模型XML
        xml_path = os.path.join(directory, ep_directory, "model.xml")
        with open(xml_path, "r") as f:
            xml_str = f.read()
        ep_data_grp.attrs["model_file"] = xml_str
        
        # 保存数据集
        ep_data_grp.create_dataset("states", data=np.array(states))
        ep_data_grp.create_dataset("actions", data=np.array(actions))
    
    # 保存元数据
    now = datetime.datetime.now()
    grp.attrs["date"] = f"{now.month}-{now.day}-{now.year}"
    grp.attrs["time"] = f"{now.hour}:{now.minute}:{now.second}"
    grp.attrs["repository_version"] = suite.__version__
    grp.attrs["env"] = env_name
    grp.attrs["env_info"] = env_info
    grp.attrs["problem_info"] = json.dumps(problem_info)
    grp.attrs["bddl_file_name"] = args.bddl_file
    grp.attrs["bddl_file_content"] = str(open(args.bddl_file, "r", encoding="utf-8").read())
    
    f.close()
3. 主程序
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--directory", type=str, default="demonstration_data")
    parser.add_argument("--robots", nargs="+", type=str, default="Panda")
    parser.add_argument("--controller", type=str, default="OSC_POSE")
    parser.add_argument("--device", type=str, default="spacemouse")
    parser.add_argument("--pos-sensitivity", type=float, default=1.5)
    parser.add_argument("--rot-sensitivity", type=float, default=1.0)
    parser.add_argument("--num-demonstration", type=int, default=50)
    parser.add_argument("--bddl-file", type=str, required=True)
    parser.add_argument("--vendor-id", type=int, default=9583)
    parser.add_argument("--product-id", type=int, default=50734)
    args = parser.parse_args()
    
    # 加载控制器配置
    controller_config = load_controller_config(default_controller=args.controller)
    
    # 获取任务信息
    problem_info = BDDLUtils.get_problem_info(args.bddl_file)
    problem_name = problem_info["problem_name"]
    language_instruction = problem_info["language_instruction"]
    
    # 创建环境
    env = TASK_MAPPING[problem_name](
        bddl_file_name=args.bddl_file,
        robots=args.robots,
        controller_configs=controller_config,
        has_renderer=True,
        has_offscreen_renderer=False,
        ignore_done=True,
        use_camera_obs=False,
        control_freq=20,
    )
    
    # 包装环境
    env = VisualizationWrapper(env)
    tmp_directory = f"demonstration_data/tmp/{problem_name}/{time.time()}"
    env = DataCollectionWrapper(env, tmp_directory)
    
    # 初始化设备
    if args.device == "spacemouse":
        device = SpaceMouse(
            args.vendor_id,
            args.product_id,
            pos_sensitivity=args.pos_sensitivity,
            rot_sensitivity=args.rot_sensitivity,
        )
    elif args.device == "keyboard":
        device = Keyboard(
            pos_sensitivity=args.pos_sensitivity,
            rot_sensitivity=args.rot_sensitivity
        )
    
    # 创建输出目录
    new_dir = os.path.join(args.directory, f"{problem_name}_{time.time()}")
    os.makedirs(new_dir)
    
    # 收集演示
    remove_directory = []
    i = 0
    while i < args.num_demonstration:
        print(f"Collecting demonstration {i+1}/{args.num_demonstration}")
        saving = collect_human_trajectory(
            env, device, args.arm, args.config, problem_info, remove_directory
        )
        if saving:
            gather_demonstrations_as_hdf5(
                tmp_directory, new_dir, env_info, args, remove_directory
            )
            i += 1

🎮 设备控制说明

SpaceMouse 3D鼠标
移动鼠标:控制末端执行器位置 (x, y, z)
旋转鼠标:控制末端执行器姿态 (roll, pitch, yaw)
按钮:开关夹爪
按ESC:取消当前演示(不保存)
键盘控制
W/S: 前进/后退 (x方向)
A/D: 左移/右移 (y方向)
Q/E: 上升/下降 (z方向)
J/L: 旋转roll
I/K: 旋转pitch
U/O: 旋转yaw
Space: 切换夹爪
ESC: 取消当前演示

💡 使用方法

使用SpaceMouse收集
python collect_demonstration.py \
    --bddl-file path/to/task.bddl \
    --device spacemouse \
    --num-demonstration 50 \
    --pos-sensitivity 1.5 \
    --rot-sensitivity 1.0 \
    --vendor-id 9583 \
    --product-id 50734
使用键盘收集
python collect_demonstration.py \
    --bddl-file path/to/task.bddl \
    --device keyboard \
    --num-demonstration 50 \
    --pos-sensitivity 2.0 \
    --rot-sensitivity 1.5

📊 收集流程

1. 加载任务BDDL文件
2. 创建环境和输入设备
3. 循环收集N个演示:
   a. 重置环境
   b. 人类操控完成任务
   c. 检查任务成功(连续10步)
   d. 保存轨迹到HDF5
4. 完成后关闭环境

⚠️ 注意事项

  1. 任务成功判定:需要连续10步保持成功状态
  2. 取消演示:按ESC取消,该轨迹不会保存
  3. 设备连接:确保SpaceMouse正确连接和配置
  4. 存储空间:50个演示约需要500MB-1GB空间
  5. 手腕疲劳:收集50个演示需要30-60分钟

🎯 最佳实践

  • 先用几个演示熟悉操作
  • 保持操作平滑自然
  • 任务完成后保持姿势1-2秒
  • 失败的尝试及时按ESC取消
  • 定期休息避免疲劳

9️⃣ libero_100_collect_demonstrations.py - LIBERO-100批量收集

📖 功能说明

专门用于LIBERO-100数据集收集的脚本,带有彩色提示和批量处理功能。

🔑 与collect_demonstration.py的区别

特性collect_demonstration.pylibero_100_collect_demonstrations.py
用途单任务数据收集批量任务数据收集
界面基础彩色终端提示
任务标识支持task-id参数
交互性直接开始等待用户确认
灵敏度默认值1.5/1.01.5/1.5

💻 关键改进

from termcolor import colored

# 彩色任务提示
text = colored(language_instruction, "red", attrs=["bold"])
print("Goal of the following task: ", text)

instruction = colored(
    "Hit any key to proceed to data collection ...",
    "green",
    attrs=["reverse", "blink"]
)
print(instruction)
input()  # 等待用户准备

# 支持任务ID
parser.add_argument("--task-id", type=int)

💡 使用方法

批量收集LIBERO-100
# 创建批处理脚本
for task_id in {0..99}; do
    python libero_100_collect_demonstrations.py \
        --bddl-file libero/bddl_files/libero_90/task_${task_id}.bddl \
        --task-id $task_id \
        --device spacemouse \
        --num-demonstration 50
done
单个任务收集
python libero_100_collect_demonstrations.py \
    --bddl-file libero/bddl_files/libero_10/task_0.bddl \
    --task-id 0 \
    --device spacemouse \
    --num-demonstration 50 \
    --pos-sensitivity 1.5 \
    --rot-sensitivity 1.5

🎯 应用场景

  • LIBERO-100数据集创建
  • 批量任务数据收集
  • 需要任务标识的项目
  • 团队协作数据收集

🔟 create_dataset.py - 数据集生成

📖 功能说明

将收集的原始演示数据(demo.hdf5)转换为训练就绪的数据集,包括提取图像观察、状态信息和奖励信号。

🔑 核心功能

数据转换流程:
原始演示(demo.hdf5) → 回放验证 → 提取观察 → 添加奖励 → 训练数据集(_demo.hdf5)

💻 核心代码详解

import argparse
import h5py
import numpy as np
import json
from pathlib import Path
import robosuite.utils.transform_utils as T
from libero.libero.envs import *
from libero.libero import get_libero_path

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("--demo-file", default="demo.hdf5")
    parser.add_argument("--use-actions", action="store_true")
    parser.add_argument("--use-camera-obs", action="store_true")
    parser.add_argument("--dataset-path", type=str, default="datasets/")
    parser.add_argument("--dataset-name", type=str, default="training_set")
    parser.add_argument("--no-proprio", action="store_true")
    parser.add_argument("--use-depth", action="store_true")
    args = parser.parse_args()
    
    # ============= 第1步: 读取原始演示文件 =============
    f = h5py.File(args.demo_file, "r")
    env_name = f["data"].attrs["env"]
    env_kwargs = json.loads(f["data"].attrs["env_info"])
    problem_info = json.loads(f["data"].attrs["problem_info"])
    problem_name = problem_info["problem_name"]
    
    demos = list(f["data"].keys())
    bddl_file_name = f["data"].attrs["bddl_file_name"]
    
    # ============= 第2步: 确定输出路径 =============
    bddl_file_dir = os.path.dirname(bddl_file_name)
    hdf5_path = os.path.join(
        get_libero_path("datasets"),
        bddl_file_dir.split("bddl_files/")[-1].replace(".bddl", "_demo.hdf5")
    )
    
    output_parent_dir = Path(hdf5_path).parent
    output_parent_dir.mkdir(parents=True, exist_ok=True)
    
    # ============= 第3步: 创建输出HDF5文件 =============
    h5py_f = h5py.File(hdf5_path, "w")
    grp = h5py_f.create_group("data")
    
    # 保存元数据
    grp.attrs["env_name"] = env_name
    grp.attrs["problem_info"] = f["data"].attrs["problem_info"]
    grp.attrs["macros_image_convention"] = macros.IMAGE_CONVENTION
    
    # 更新环境配置
    libero_utils.update_env_kwargs(
        env_kwargs,
        bddl_file_name=bddl_file_name,
        has_renderer=not args.use_camera_obs,
        has_offscreen_renderer=args.use_camera_obs,
        ignore_done=True,
        use_camera_obs=args.use_camera_obs,
        camera_depths=args.use_depth,
        camera_names=["robot0_eye_in_hand", "agentview"],
        camera_heights=128,
        camera_widths=128,
        control_freq=20,
    )
    
    grp.attrs["bddl_file_name"] = bddl_file_name
    grp.attrs["bddl_file_content"] = open(bddl_file_name, "r").read()
    
    # ============= 第4步: 创建环境 =============
    env = TASK_MAPPING[problem_name](**env_kwargs)
    
    total_len = 0
    cap_index = 5  # 跳过前5帧(力传感器不稳定)
    
    # ============= 第5步: 处理每个演示 =============
    for (i, ep) in enumerate(demos):
        print(f"Processing episode {i+1}/{len(demos)}...")
        
        # 读取模型XML和状态
        model_xml = f["data/{}".format(ep)].attrs["model_file"]
        states = f["data/{}/states".format(ep)][()]
        actions = np.array(f["data/{}/actions".format(ep)][()])
        
        # 重置环境
        reset_success = False
        while not reset_success:
            try:
                env.reset()
                reset_success = True
            except:
                continue
        
        # 从XML和状态恢复环境
        env.reset_from_xml_string(model_xml)
        env.sim.reset()
        env.sim.set_state_from_flattened(states[0])
        env.sim.forward()
        
        # 初始化数据容器
        ee_states = []
        gripper_states = []
        joint_states = []
        robot_states = []
        agentview_images = []
        eye_in_hand_images = []
        agentview_depths = []
        eye_in_hand_depths = []
        valid_index = []
        
        # ============= 第6步: 回放并记录 =============
        for j, action in enumerate(actions):
            obs, reward, done, info = env.step(action)
            
            # 验证回放准确性
            if j < len(actions) - 1:
                state_playback = env.sim.get_state().flatten()
                err = np.linalg.norm(states[j + 1] - state_playback)
                if err > 0.01:
                    print(f"[warning] playback diverged by {err:.2f}")
            
            # 跳过前几帧(力传感器稳定期)
            if j < cap_index:
                continue
            
            valid_index.append(j)
            
            # 记录本体感觉信息
            if not args.no_proprio:
                if "robot0_gripper_qpos" in obs:
                    gripper_states.append(obs["robot0_gripper_qpos"])
                joint_states.append(obs["robot0_joint_pos"])
                ee_states.append(
                    np.hstack((
                        obs["robot0_eef_pos"],
                        T.quat2axisangle(obs["robot0_eef_quat"]),
                    ))
                )
            
            robot_states.append(env.get_robot_state_vector(obs))
            
            # 记录视觉观察
            if args.use_camera_obs:
                agentview_images.append(obs["agentview_image"])
                eye_in_hand_images.append(obs["robot0_eye_in_hand_image"])
                
                if args.use_depth:
                    agentview_depths.append(obs["agentview_depth"])
                    eye_in_hand_depths.append(obs["robot0_eye_in_hand_depth"])
            else:
                env.render()
        
        # ============= 第7步: 保存处理后的数据 =============
        states = states[valid_index]
        actions = actions[valid_index]
        
        # 创建奖励和完成标志
        dones = np.zeros(len(actions)).astype(np.uint8)
        dones[-1] = 1  # 最后一步标记为完成
        rewards = np.zeros(len(actions)).astype(np.uint8)
        rewards[-1] = 1  # 最后一步给予奖励
        
        # 创建演示组
        ep_data_grp = grp.create_group(f"demo_{i}")
        obs_grp = ep_data_grp.create_group("obs")
        
        # 保存本体感觉
        if not args.no_proprio:
            obs_grp.create_dataset("gripper_states", data=np.stack(gripper_states, axis=0))
            obs_grp.create_dataset("joint_states", data=np.stack(joint_states, axis=0))
            obs_grp.create_dataset("ee_states", data=np.stack(ee_states, axis=0))
            obs_grp.create_dataset("ee_pos", data=np.stack(ee_states, axis=0)[:, :3])
            obs_grp.create_dataset("ee_ori", data=np.stack(ee_states, axis=0)[:, 3:])
        
        # 保存图像
        obs_grp.create_dataset("agentview_rgb", data=np.stack(agentview_images, axis=0))
        obs_grp.create_dataset("eye_in_hand_rgb", data=np.stack(eye_in_hand_images, axis=0))
        
        if args.use_depth:
            obs_grp.create_dataset("agentview_depth", data=np.stack(agentview_depths, axis=0))
            obs_grp.create_dataset("eye_in_hand_depth", data=np.stack(eye_in_hand_depths, axis=0))
        
        # 保存其他数据
        ep_data_grp.create_dataset("actions", data=actions)
        ep_data_grp.create_dataset("states", data=states)
        ep_data_grp.create_dataset("robot_states", data=np.stack(robot_states, axis=0))
        ep_data_grp.create_dataset("rewards", data=rewards)
        ep_data_grp.create_dataset("dones", data=dones)
        ep_data_grp.attrs["num_samples"] = len(agentview_images)
        ep_data_grp.attrs["model_file"] = model_xml
        ep_data_grp.attrs["init_state"] = states[0]
        
        total_len += len(agentview_images)
    
    # ============= 第8步: 保存全局属性 =============
    grp.attrs["num_demos"] = len(demos)
    grp.attrs["total"] = total_len
    
    env.close()
    h5py_f.close()
    f.close()
    
    print("\n✔ Dataset created successfully!")
    print(f"Saved to: {hdf5_path}")

if __name__ == "__main__":
    main()

📊 数据集结构对比

输入:原始演示 (demo.hdf5)
data/
├── demo_1/
│   ├── states (array)      # MuJoCo状态
│   └── actions (array)     # 动作序列
└── demo_2/
    └── ...
输出:训练数据集 (*_demo.hdf5)
data/
├── demo_0/
│   ├── obs/
│   │   ├── agentview_rgb (128, 128, 3)      # 第三人称视角
│   │   ├── eye_in_hand_rgb (128, 128, 3)    # 手眼相机
│   │   ├── gripper_states (2,)              # 夹爪状态
│   │   ├── joint_states (7,)                # 关节角度
│   │   ├── ee_pos (3,)                      # 末端执行器位置
│   │   └── ee_ori (3,)                      # 末端执行器姿态
│   ├── actions (7,)                         # 动作
│   ├── rewards (1,)                         # 奖励(稀疏)
│   ├── dones (1,)                           # 完成标志
│   └── [attributes]
│       ├── num_samples
│       ├── model_file
│       └── init_state
└── demo_1/
    └── ...

💡 使用方法

基础使用(不带视觉)
python create_dataset.py \
    --demo-file path/to/demo.hdf5
包含视觉观察
python create_dataset.py \
    --demo-file path/to/demo.hdf5 \
    --use-camera-obs
包含深度图
python create_dataset.py \
    --demo-file path/to/demo.hdf5 \
    --use-camera-obs \
    --use-depth
无本体感觉(仅视觉)
python create_dataset.py \
    --demo-file path/to/demo.hdf5 \
    --use-camera-obs \
    --no-proprio

🔑 关键特性

1. 回放验证
# 确保回放准确性
state_playback = env.sim.get_state().flatten()
err = np.linalg.norm(states[j + 1] - state_playback)
if err > 0.01:
    print(f"[warning] playback diverged by {err:.2f}")
2. 跳过不稳定帧
cap_index = 5  # 跳过前5帧
# 力传感器在开始时不稳定
if j < cap_index:
    continue
3. 稀疏奖励
# LIBERO使用稀疏奖励
rewards = np.zeros(len(actions))
rewards[-1] = 1  # 只有完成时给奖励
4. 图像分辨率
camera_heights=128,
camera_widths=128,
# 默认128x128,可以修改

⚠️ 注意事项

  1. 内存使用:处理图像时需要大量内存
  2. 处理时间:50个演示约需5-10分钟
  3. 磁盘空间
    • 无图像:~100MB
    • 有图像:~1-2GB
    • 有深度:~2-3GB
  4. 回放误差:少量误差(<0.01)是正常的

🎯 典型工作流

# 1. 收集演示
python collect_demonstration.py --bddl-file task.bddl --num-demonstration 50

# 2. 转换为训练数据
python create_dataset.py --demo-file demo.hdf5 --use-camera-obs

# 3. 验证数据集
python check_dataset_integrity.py

# 4. 查看信息
python get_dataset_info.py --dataset path/to/task_demo.hdf5

# 5. 开始训练
python libero/lifelong/main.py ...

🎓 总结与最佳实践

📋 脚本使用建议

阶段推荐脚本目的
初始化config_copy.py, init_path.py设置项目环境
探索get_affordance_info.py了解对象能力
设计create_libero_task_example.py, create_template.py创建新任务
数据收集collect_demonstration.py收集训练数据
数据处理create_dataset.py生成训练集
验证check_dataset_integrity.py, get_dataset_info.py质量检查

🔧 常见工作流

工作流1:快速原型
# 1. 复制配置
python config_copy.py

# 2. 创建任务
python create_libero_task_example.py

# 3. 收集少量演示测试
python collect_demonstration.py --num-demonstration 5
工作流2:完整数据集创建
# 1. 收集50个演示
python collect_demonstration.py --num-demonstration 50

# 2. 转换为训练数据
python create_dataset.py --use-camera-obs

# 3. 检查完整性
python check_dataset_integrity.py

# 4. 查看统计
python get_dataset_info.py --dataset path/to/dataset.hdf5
工作流3:LIBERO-100扩展
# 批量创建100个任务的数据集
for i in {0..99}; do
    python libero_100_collect_demonstrations.py \
        --task-id $i \
        --bddl-file libero_90/task_$i.bddl \
        --num-demonstration 50
done

⚠️ 常见问题解决

问题可能原因解决方案
导入错误路径问题使用init_path.py
回放误差大随机性/物理不确定检查随机种子
图像倒置图像约定检查macros.IMAGE_CONVENTION
内存溢出处理大数据集分批处理或减少演示数
设备连接失败SpaceMouse配置检查vendor-id和product-id

🚀 性能优化建议

  1. 并行处理:多个任务可以并行收集
  2. 批处理:使用脚本批量处理多个数据集
  3. 预检查:收集前验证BDDL文件
  4. 增量保存:大数据集分批保存
  5. 定期备份:避免数据丢失

📚 相关资源

  • LIBERO官方文档: https://lifelong-robot-learning.github.io/LIBERO/
  • Robosuite文档: https://robosuite.ai/
  • HDF5格式: https://www.hdfgroup.org/

LIBERO 脚本快速参考卡片

📋 一分钟速览

┌─────────────────────────────────────────────────────────────┐
│  LIBERO 10个工具脚本 - 从数据收集到训练的完整工具链        │
└─────────────────────────────────────────────────────────────┘

🎯 按功能分类

📦 基础设施 (2个)

脚本命令用途
init_path.pyimport init_path路径初始化(导入LIBERO前必须)
config_copy.pypython config_copy.py复制配置文件到项目目录

🔍 信息查询 (3个)

脚本命令用途
get_dataset_info.pypython get_dataset_info.py --dataset xxx.hdf5查看数据集统计信息
check_dataset_integrity.pypython check_dataset_integrity.py检查数据集完整性(50个演示)
get_affordance_info.pypython get_affordance_info.py查看对象可交互区域

🛠️ 任务创建 (2个)

脚本命令用途
create_libero_task_example.pypython create_libero_task_example.py学习任务创建(示例)
create_template.pypython create_template.py生成模板(场景/类)

🎮 数据收集 (3个)

脚本命令用途
collect_demonstration.py--bddl-file task.bddl --num-demonstration 50人类演示收集(单任务)
libero_100_collect_demonstrations.py--task-id 0 --bddl-file task.bddlLIBERO-100批量收集
create_dataset.py--demo-file demo.hdf5 --use-camera-obs转换为训练数据集

⚡ 5秒钟命令速查

# 初始化项目
python config_copy.py

# 查看对象能力
python get_affordance_info.py

# 创建任务示例
python create_libero_task_example.py

# 收集数据(SpaceMouse)
python collect_demonstration.py --bddl-file task.bddl --device spacemouse --num-demonstration 50

# 转换数据集
python create_dataset.py --demo-file demo.hdf5 --use-camera-obs

# 检查数据集
python check_dataset_integrity.py

# 查看数据集信息
python get_dataset_info.py --dataset path/to/task_demo.hdf5

🔧 典型使用场景

场景1️⃣: 我是新手,想了解LIBERO

# Step 1: 初始化
python config_copy.py

# Step 2: 查看有哪些对象和交互
python get_affordance_info.py

# Step 3: 看看任务创建示例
python create_libero_task_example.py

# Step 4: 查看现有数据集
python get_dataset_info.py --dataset ~/.libero/datasets/libero_spatial/demo_0.hdf5

场景2️⃣: 我要创建新任务

# Step 1: 生成任务模板
python create_template.py
# 选择: [0] problem_class

# Step 2: 创建场景XML(可选)
python create_template.py  
# 选择: [1] scene

# Step 3: 参考示例编写任务
# 编辑: my_task.py (参考 create_libero_task_example.py)

# Step 4: 生成BDDL文件
python my_task.py  # 调用 generate_bddl_from_task_info()

场景3️⃣: 我要收集训练数据

# Step 1: 准备BDDL文件
# 假设: libero/bddl_files/my_task/task.bddl

# Step 2: 收集演示(需要SpaceMouse)
python collect_demonstration.py \
    --bddl-file libero/bddl_files/my_task/task.bddl \
    --device spacemouse \
    --num-demonstration 50 \
    --pos-sensitivity 1.5 \
    --rot-sensitivity 1.0

# Step 3: 转换为训练数据
python create_dataset.py \
    --demo-file demonstration_data/.../demo.hdf5 \
    --use-camera-obs

# Step 4: 验证数据集
python check_dataset_integrity.py
python get_dataset_info.py --dataset ~/.libero/datasets/my_task/task_demo.hdf5

场景4️⃣: 我要扩展LIBERO-100

# Step 1: 批量收集(创建bash脚本)
for i in {0..9}; do
    python libero_100_collect_demonstrations.py \
        --task-id $i \
        --bddl-file libero/bddl_files/libero_10/task_${i}.bddl \
        --device spacemouse \
        --num-demonstration 50
done

# Step 2: 批量转换
for demo_file in demonstration_data/*/demo.hdf5; do
    python create_dataset.py --demo-file $demo_file --use-camera-obs
done

# Step 3: 批量检查
python check_dataset_integrity.py

📊 数据流转图

┌──────────────────┐
│  BDDL定义文件     │ (create_libero_task_example.py)
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  人类演示收集     │ (collect_demonstration.py)
│  demo.hdf5       │ 
└────────┬─────────┘
         │ 原始状态+动作
         ▼
┌──────────────────┐
│  数据集转换       │ (create_dataset.py)
│  *_demo.hdf5     │ 
└────────┬─────────┘
         │ 图像+状态+动作+奖励
         ▼
┌──────────────────┐
│  数据验证         │ (check_dataset_integrity.py)
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│  训练模型         │ (libero/lifelong/main.py)
└──────────────────┘

🎮 SpaceMouse控制速查

┌─────────────────────────────────────────────────────┐
│  SpaceMouse 3D鼠标控制                               │
├─────────────────────────────────────────────────────┤
│  移动鼠标     → 控制末端执行器位置 (x, y, z)          │
│  旋转鼠标     → 控制末端执行器姿态 (roll, pitch, yaw) │
│  左键/右键    → 开关夹爪                              │
│  按 ESC      → 取消当前演示(不保存)                 │
└─────────────────────────────────────────────────────┘

⚙️ 灵敏度建议:
  - 位置: 1.0-2.0 (默认1.5)
  - 旋转: 0.8-1.5 (默认1.0)
  - 新手建议降低灵敏度: --pos-sensitivity 1.0 --rot-sensitivity 0.8

📦 HDF5文件结构速查

原始演示 (demo.hdf5)

data/
  ├── [attributes] metadata
  ├── demo_1/
  │   ├── states (array)
  │   └── actions (array)
  └── demo_2/ ...

训练数据集 (*_demo.hdf5)

data/
  ├── demo_0/
  │   ├── obs/
  │   │   ├── agentview_rgb (T, 128, 128, 3)
  │   │   ├── eye_in_hand_rgb (T, 128, 128, 3)
  │   │   ├── gripper_states (T, 2)
  │   │   ├── joint_states (T, 7)
  │   │   ├── ee_pos (T, 3)
  │   │   └── ee_ori (T, 3)
  │   ├── actions (T, 7)
  │   ├── rewards (T,)  # 稀疏: 只有最后一步=1
  │   ├── dones (T,)    # 只有最后一步=1
  │   └── states (T, 123)
  └── demo_1/ ...

⚠️ 常见问题一行解决

问题解决方案
ImportError: No module named libero在脚本开头添加 import init_path
SpaceMouse连接失败检查 --vendor-id 9583 --product-id 50734
回放误差过大 (>0.01)正常,少量误差可接受;如果>0.1检查物理参数
数据集不是50个演示检查收集时是否有失败的演示(按ESC取消的)
图像是黑屏确保使用 --use-camera-obshas_offscreen_renderer=True
内存溢出减少演示数量或分批处理
任务一直不成功检查BDDL目标状态定义是否合理

🎯 记忆口诀

路径初始化: init_path 
配置复制: config_copy
信息查询: get_*
任务创建: create_libero_task_example, create_template
数据收集: collect_demonstration (+ libero_100版本)
数据转换: create_dataset
质量检查: check_dataset_integrity

📝 参数速记表

collect_demonstration.py

--bddl-file         # BDDL文件路径 [必需]
--device            # spacemouse / keyboard
--num-demonstration # 演示数量 (默认50)
--pos-sensitivity   # 位置灵敏度 (默认1.5)
--rot-sensitivity   # 旋转灵敏度 (默认1.0)
--controller        # OSC_POSE / IK_POSE

create_dataset.py

--demo-file         # 输入demo.hdf5路径
--use-camera-obs    # 包含图像观察
--use-depth         # 包含深度图
--no-proprio        # 不包含本体感觉

get_dataset_info.py

--dataset           # 数据集HDF5路径 [必需]
--filter_key        # train / valid (可选)
--verbose           # 显示详细信息

🚀 快速上手3步走

# 1️⃣ 安装和初始化 (5分钟)
conda create -n libero python=3.8
conda activate libero
cd LIBERO
pip install -e .
python scripts/config_copy.py

# 2️⃣ 探索和学习 (10分钟)
python scripts/get_affordance_info.py
python scripts/create_libero_task_example.py
python scripts/get_dataset_info.py --dataset ~/.libero/datasets/libero_10/demo_0.hdf5

# 3️⃣ 收集数据 (30-60分钟)
python scripts/collect_demonstration.py \
    --bddl-file libero/bddl_files/libero_10/KITCHEN_SCENE1_put_the_black_bowl_on_the_plate.bddl \
    --device spacemouse \
    --num-demonstration 50

💡 专业提示

  1. 数据收集: 任务成功需要连续10步,保持姿势1-2秒
  2. 失败重来: 按ESC取消演示,不会计入演示数量
  3. 批量处理: 用bash循环脚本批量处理多个任务
  4. 定期休息: 收集50个演示约需45分钟,注意休息
  5. 版本控制: 将生成的BDDL文件加入Git管理
  6. 备份数据: 演示数据珍贵,及时备份

📚 深入学习

  • 完整文档: libero_scripts_guide.md (本目录)
  • 代码示例: LIBERO/notebooks/ 目录
  • 官方文档: https://lifelong-robot-learning.github.io/LIBERO/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值