LIBERO Benchmark自定义BDDL任务-模块化实践指南(1)

张开发
2026/4/21 7:25:05 15 分钟阅读

分享文章

LIBERO Benchmark自定义BDDL任务-模块化实践指南(1)
1. 从Jupyter Notebook到模块化工程为什么需要重构第一次接触LIBERO Benchmark的开发者大概率会从官方提供的Jupyter Notebook示例开始。那个名为custom_object_example.ipynb的笔记本文件确实能快速演示如何生成自定义BDDL文件。但当你真正要把这个功能集成到自己的项目中时问题就来了——所有代码都挤在一个文件里资产注册、场景定义、任务生成三个核心逻辑混杂在一起就像把衣柜、书桌和床全都塞进了一个房间。我在实际项目中遇到过这种情况当需要新增5个自定义物体时发现要修改的代码分散在同一个文件的三个不同段落当团队其他成员想复用某个场景模板时不得不复制粘贴大段代码。这种集中式的代码结构在工程化开发中至少会带来三个痛点维护成本高任何修改都需要在同一个文件中反复横跳容易遗漏关联改动复用性差无法单独引用某个物体的定义或某个场景的配置协作困难多人同时修改一个文件时Git冲突几乎不可避免LIBERO本身采用的是标准的模块化架构比如libero/ ├── envs/ │ ├── objects/ # 物体定义 │ └── problems/ # 场景定义 └── benchmark/ ├── tasks/ # 任务配置 └── mu_creation.py # 场景模板我们需要做的就是把Notebook里的三段式代码A/B/C段按照这个规范拆解到对应的模块中。这就像把杂乱的物品分类收纳——衣柜只放衣服书桌只放文具找东西时直奔主题不用再翻箱倒柜。2. 资产注册模块化让自定义物体安家落户2.1 资产文件的正确存放位置官方Notebook示例中自定义资产如libero_mug.xml默认放在notebooks/custom_assets/目录下。这在开发初期没问题但正式项目中会破坏代码的自包含性——其他模块引用这些资产时不得不使用../notebooks/这种脆弱的相对路径。正确的做法是将资产迁移到项目标准目录# 创建自定义资产目录 mkdir -p libero/assets/custom_assets/libero_mug # 移动资产文件 mv notebooks/custom_assets/libero_mug.xml libero/assets/custom_assets/libero_mug/2.2 创建专属的物体注册文件在libero/envs/objects/下新建custom_objects.py将Notebook的代码段A迁移过来。关键修改点是路径处理import os import pathlib from robosuite.models.objects import MujocoXMLObject from libero.libero.envs.base_object import register_object # 获取项目根目录绝对路径 absolute_path pathlib.Path(__file__).parent.parent.parent.absolute() register_object class LiberoMug(CustomObjects): def __init__(self, namelibero_mug, obj_namelibero_mug): # 使用标准路径格式 custom_path os.path.join( absolute_path, fassets/custom_assets/{obj_name}/{obj_name}.xml ) super().__init__(custom_pathcustom_path, namename, obj_nameobj_name) self.rotation {x: (-np.pi/2, -np.pi/2), y: (-np.pi, -np.pi), z: (np.pi, np.pi)}这个改造带来了三个好处路径安全使用绝对路径避免运行时路径错误集中管理所有自定义物体都在同一个文件中定义自动注册register_object装饰器会将类自动加入全局对象字典2.3 让模块生效的最后一步在libero/envs/objects/__init__.py中添加from .custom_objects import *这样其他模块就能通过from libero.libero.envs.objects import LiberoMug直接引用你的自定义物体了。3. 场景定义模块化打造可复用的场景模板3.1 理解场景模板的运作机制LIBERO通过mu_creation.py中的场景模板系统来管理各类场景。每个模板需要定义固定装置fixtures如桌子、柜子等不可移动物体可动物体objects如杯子、碗等可操作对象区域定义regions物体的初始位置和操作区域初始状态init_states场景启动时的物体布局Notebook中的代码段B就是一个典型的厨房场景模板我们需要将其整合到标准模板系统中。3.2 将场景添加到官方模板打开libero/benchmark/mu_creation.py在文件末尾添加register_mu(scene_typekitchen) class KitchenDemoScene(InitialSceneTemplates): def __init__(self): fixture_num_info {kitchen_table: 1, wooden_cabinet: 1} object_num_info {libero_mug: 1, libero_mug_yellow: 1} super().__init__( workspace_namekitchen_table, fixture_num_infofixture_num_info, object_num_infoobject_num_info ) def define_regions(self): self.regions.update( self.get_region_dict( region_centroid_xy[0.0, -0.30], region_namewooden_cabinet_init_region, target_nameself.workspace_name, region_half_len0.01, yaw_rotation(np.pi, np.pi), ) ) # 其他区域定义... property def init_states(self): return [ (On, libero_mug_1, kitchen_table_libero_mug_init_region), # 其他初始状态... ]3.3 场景模板的扩展技巧实际开发中可以通过继承快速创建相似场景。比如要创建一个带两个杯子的厨房场景register_mu(scene_typekitchen) class KitchenTwoMugsScene(KitchenDemoScene): def __init__(self): super().__init__() self.object_num_info[libero_mug] 2 # 将杯子数量改为2 def define_regions(self): super().define_regions() # 继承父类区域定义 # 为第二个杯子添加区域 self.regions.update( self.get_region_dict( region_centroid_xy[0.1, 0.0], region_namelibero_mug_2_init_region, target_nameself.workspace_name, region_half_len0.025, ) ) property def init_states(self): states super().init_states states.append( (On, libero_mug_2, kitchen_table_libero_mug_2_init_region) ) return states这种模块化设计让场景配置像搭积木一样简单既保证了统一性又支持灵活扩展。4. 任务生成入口简洁的主程序完成前两步的模块化后原本复杂的Notebook代码现在只需要保留最核心的任务生成逻辑代码段C。创建一个新的generate_task.py作为程序入口from libero.libero.utils.task_generation_utils import ( register_task_info, generate_bddl_from_task_info ) from libero.libero.envs import OffScreenRenderEnv from PIL import Image import os # 任务配置 scene_name kitchen_demo_scene language Put the yellow mug into the cabinet bddl_output_dir ./generated_bddl # 生成BDDL文件 register_task_info( language, scene_namescene_name, objects_of_interest[], goal_states[ (Open, wooden_cabinet_1_top_region), (In, libero_mug_yellow_1, wooden_cabinet_1_top_region), ], ) bddl_files, _ generate_bddl_from_task_info(folderbddl_output_dir) # 场景可视化 env OffScreenRenderEnv(bddl_file_namebddl_files[0]) obs env.reset() Image.fromarray(obs[agentview_image][::-1]).save( os.path.join(bddl_output_dir, preview.png) )这个主程序现在只做三件事设置任务的自然语言描述和目标状态调用LIBERO核心API生成BDDL文件输出场景预览图所有底层实现细节都被封装在前面的模块中符合高内聚低耦合的工程原则。当需要修改物体属性或场景布局时完全不需要动这个主程序。5. 模块化后的BDDL定制指南5.1 修改物体属性现在要调整杯子的旋转属性只需要打开custom_objects.py修改对应类register_object class LiberoMug(CustomObjects): def __init__(self, namelibero_mug, obj_namelibero_mug): super().__init__(custom_pathcustom_path, namename, obj_nameobj_name) # 调整X轴旋转范围 self.rotation {x: (-np.pi/4, np.pi/4), y: (-np.pi, -np.pi), z: (np.pi, np.pi)}5.2 新增场景物体假设要添加一个盘子物体流程变得非常清晰将plate.xml放入assets/custom_assets/plate/在custom_objects.py中添加Plate类在mu_creation.py的对应场景模板中在object_num_info中添加plate: 1在define_regions中添加盘子区域在init_states中添加初始状态5.3 切换基础场景LIBERO内置了多个基础场景厨房、书房等切换时只需修改场景模板的装饰器和workspace名称register_mu(scene_typestudy) # 改为study场景 class StudyScene(InitialSceneTemplates): def __init__(self): super().__init__( workspace_namestudy_table, # 改为study_table fixture_num_info{study_table: 1}, object_num_info{notebook: 1} )这种模块化结构让BDDL定制变得像填写配置表一样简单每个修改都有明确的位置和规范。

更多文章