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.py | LIBERO-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, "../"))
🔑 核心逻辑
- 获取当前脚本所在目录的绝对路径
- 将上级目录添加到
sys.path最前面 - 确保可以导入LIBERO包
💡 使用场景
# 在其他脚本开头导入
import init_path # 必须在导入libero之前
from libero.libero import benchmark
from libero.libero.envs import *
⚠️ 注意事项
- 必须在所有LIBERO导入之前执行
- 适用于在
scripts/目录下运行脚本的情况 - 如果已经正确安装LIBERO包,可以不需要这个脚本
2️⃣ check_dataset_integrity.py - 数据集完整性检查
📖 功能说明
自动扫描并验证LIBERO数据集的完整性,检查每个数据集是否包含正确数量的演示轨迹。
🔑 核心功能
检查项目:
- ✅ 每个数据集是否有50个演示轨迹
- ✅ 轨迹长度统计(均值和标准差)
- ✅ 动作范围检查
- ✅ 数据集版本标签验证
💻 核心代码逻辑
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数据集的统计信息、元数据和结构,是数据集分析的利器。
🔑 主要功能
报告内容:
- 📊 轨迹统计(总数、长度分布)
- 🎯 动作范围(最大/最小值)
- 🗣️ 语言指令
- 🔖 过滤键(Filter Keys)
- 🌍 环境元数据
- 📦 数据结构详情
💻 核心代码解析
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基类
包含三个方法:
__init__: 声明场景中的对象define_regions: 定义对象放置区域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文件会生成在默认位置
# 可以在脚本中指定输出目录
🎯 学习要点
- 场景定义: 装置vs对象的区别
- 区域设置: 坐标系统和尺寸
- 状态约束: 谓词的使用方法
- 任务目标: 组合多个条件
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_class | Python类文件 | 自定义任务逻辑 |
| scene | XML场景文件 | 定义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. 完成后关闭环境
⚠️ 注意事项
- 任务成功判定:需要连续10步保持成功状态
- 取消演示:按ESC取消,该轨迹不会保存
- 设备连接:确保SpaceMouse正确连接和配置
- 存储空间:50个演示约需要500MB-1GB空间
- 手腕疲劳:收集50个演示需要30-60分钟
🎯 最佳实践
- 先用几个演示熟悉操作
- 保持操作平滑自然
- 任务完成后保持姿势1-2秒
- 失败的尝试及时按ESC取消
- 定期休息避免疲劳
9️⃣ libero_100_collect_demonstrations.py - LIBERO-100批量收集
📖 功能说明
专门用于LIBERO-100数据集收集的脚本,带有彩色提示和批量处理功能。
🔑 与collect_demonstration.py的区别
| 特性 | collect_demonstration.py | libero_100_collect_demonstrations.py |
|---|---|---|
| 用途 | 单任务数据收集 | 批量任务数据收集 |
| 界面 | 基础 | 彩色终端提示 |
| 任务标识 | 无 | 支持task-id参数 |
| 交互性 | 直接开始 | 等待用户确认 |
| 灵敏度默认值 | 1.5/1.0 | 1.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,可以修改
⚠️ 注意事项
- 内存使用:处理图像时需要大量内存
- 处理时间:50个演示约需5-10分钟
- 磁盘空间:
- 无图像:~100MB
- 有图像:~1-2GB
- 有深度:~2-3GB
- 回放误差:少量误差(<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 |
🚀 性能优化建议
- 并行处理:多个任务可以并行收集
- 批处理:使用脚本批量处理多个数据集
- 预检查:收集前验证BDDL文件
- 增量保存:大数据集分批保存
- 定期备份:避免数据丢失
📚 相关资源
- LIBERO官方文档: https://lifelong-robot-learning.github.io/LIBERO/
- Robosuite文档: https://robosuite.ai/
- HDF5格式: https://www.hdfgroup.org/
LIBERO 脚本快速参考卡片
📋 一分钟速览
┌─────────────────────────────────────────────────────────────┐
│ LIBERO 10个工具脚本 - 从数据收集到训练的完整工具链 │
└─────────────────────────────────────────────────────────────┘
🎯 按功能分类
📦 基础设施 (2个)
| 脚本 | 命令 | 用途 |
|---|---|---|
init_path.py | import init_path | 路径初始化(导入LIBERO前必须) |
config_copy.py | python config_copy.py | 复制配置文件到项目目录 |
🔍 信息查询 (3个)
| 脚本 | 命令 | 用途 |
|---|---|---|
get_dataset_info.py | python get_dataset_info.py --dataset xxx.hdf5 | 查看数据集统计信息 |
check_dataset_integrity.py | python check_dataset_integrity.py | 检查数据集完整性(50个演示) |
get_affordance_info.py | python get_affordance_info.py | 查看对象可交互区域 |
🛠️ 任务创建 (2个)
| 脚本 | 命令 | 用途 |
|---|---|---|
create_libero_task_example.py | python create_libero_task_example.py | 学习任务创建(示例) |
create_template.py | python 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.bddl | LIBERO-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-obs 和 has_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
💡 专业提示
- 数据收集: 任务成功需要连续10步,保持姿势1-2秒
- 失败重来: 按ESC取消演示,不会计入演示数量
- 批量处理: 用bash循环脚本批量处理多个任务
- 定期休息: 收集50个演示约需45分钟,注意休息
- 版本控制: 将生成的BDDL文件加入Git管理
- 备份数据: 演示数据珍贵,及时备份
📚 深入学习
- 完整文档:
libero_scripts_guide.md(本目录) - 代码示例:
LIBERO/notebooks/目录 - 官方文档: https://lifelong-robot-learning.github.io/LIBERO/
442

被折叠的 条评论
为什么被折叠?



