PAI Physical AI Notebook 详解(5):基于 Isaac-Cortex 的软件在环验证

终于到了本系列的最后一期。在前4期详解系列中,我们体验了:

从技术选择角度,覆盖了从Isaac仿真到Cosmos世界模型的多种思路;

从使用流程角度,覆盖了从人工演示到模仿学习的多个环节;

从基础模型角度,覆盖了从动作模型、导航模型到VLA模型的多种类型;

从PAI的使用深度,经历了从DSW探索体验,到DLC、EAS大规模使用的过程。

在这些最佳实践中,不可避免的会用到可视化操作环境,通过在PAI-DSW里启动VNC进程,或者Livestream服务,可以很好的解决这个问题。

但是,手动启动VNC进程仍是比较繁琐的操作。在本期,我们隆重介绍DSW全新的noVNC功能 ,并结合Isaac Sim的协作机器人系统Cortex,搭建软件在环验证系统(Software-In-Loop System)。

在PAI的Notebook Gallery中,我们已经预置了一个最佳实践,就是这个过程的一个具体示例:

gallery.pai-ml.com/#/preview/d...

下面我们来详细解读这个示例。

环境准备

实例创建

由于SIL系统天然需要可视化体验,我们还是使用DSW作为搭建环境。

在DSW中,使用以下配置创建实例:

本最佳实践中,无需特殊的自定义数据集和公共数据集配置。

资源下载

在DSW中,使用如下脚本下载所需的数据、代码和模型:

python 复制代码
import os
from pathlib import Path

local_dir = Path("/mnt/data/notebook5/")  # 缓存目录
print(f"下载数据和代码到: {local_dir}")

print("开始下载数据和代码...")
package = "bin_picking_demo.tar"
download_from_oss('aigc-data/isaac/nb5/', package, str(local_dir))
print("下载完成")
print("开始解压数据和代码...")
zip_file = os.path.join(local_dir, package)
print(zip_file)
breakpoint()
!tar -xvf {zip_file} -C {local_dir}
!rm {zip_file}
print("解压完成")


import os
from pathlib import Path

local_dir = Path("/root/FoundationPose")  # 缓存目录
print(f"下载预训练模型参数到: {local_dir}")

print("开始下载预训练模型参数...")
package = "weights.tar"
download_from_oss('aigc-data/isaac/nb5/', package, str(local_dir))
print("下载完成")
print("开始解压预训练模型参数...")
zip_file = os.path.join(local_dir, package)
print(zip_file)
!tar -xvf {zip_file} -C {local_dir}
!rm {zip_file}
print("解压完成")

VNC启动

使用以下脚本,安装noVNC服务端,并启动VNC进程:

bash 复制代码
#安装python env
apt update
apt install python3-venv

#启动vncserver
/opt/TurboVNC/bin/vncserver :1 -geometry 3840x2160

#安装novnc
/etc/dsw/runtime/bin/pai-dsw runtime plugin install novnc

#启动novnc
/etc/dsw/runtime/bin/pai-dsw runtime plugin start-daemon novnc

在DSW的Terminal中输入:

arduino 复制代码
http://localhost:9803

跳转至DSW的gateway地址,在链接末尾添加vnc.html

从而打开noVNC界面:

运行验证

在noVNC界面中,运行以下指令:

bash 复制代码
cd /root/bin_picking_demo
/isaac-sim/python.sh sim_main.py --component "mustard_bottle"
## 可以尝试更改--component "cracker_box"

视频演示>>

可以看到,在Isaac Lab窗口中,机械臂按照FoundationPose模型的输出,执行了物料识别、抓取和转移的动作;在Terminal窗口中,FastSAM模型完成了物料位置的识别,并通过FoundationPose模型完成了机械臂动作的输出。

原理解析

系统主入口

此SIL系统的入口位于/mnt/workspace/notebook5/bin_picking_demo/sim_main.py路径下:

ini 复制代码
if __name__ == "__main__":
    # ------- parse configuration ------- #
    opt = tyro.cli(SimulationConfig)
    
    # Setup all configuration parameters
    opt, camera_pameters, weights_path, standard_mask_path = setup_configuration(opt)

    # ------- create a separate process for FoundationPose Infer ------- #
    ctx = mp.get_context('spawn')
    
    data_queue = ctx.Queue() ## image/depth from SIM
    hand_data_queue = ctx.Queue() ## image/depth from hand camera from SIM
    detect_queue = ctx.Queue() ## detections from FoundationPose
    hand_detect_queue = ctx.Queue() ## detections from FoundationPose

    debug = True
    process = ctx.Process(target=inference, args=(data_queue, detect_queue, hand_data_queue, hand_detect_queue, camera_pameters, opt.mesh_file, standard_mask_path, weights_path, debug))
    # Start the subprocess of FoundationPose Inference
    process.start()
    # Start main process of ISAAC Sim
    main(opt, data_queue, detect_queue, hand_data_queue, hand_detect_queue)
   
          
    process.terminate()
    process.join()
    print('## Sub process is terminated.')

这段代码中:

  1. 使用multiprocessing创建感知子进程;仿真在主进程

  2. 创建数据队列,进行仿真主进程和感知子进程之间的数据交换;仿真主进程从感知子进程中读取检测结果,感知子进程从仿真主进程中获取传感器数据

感知子进程

感知子进程位于 /mnt/workspace/notebook5/bin_picking_demo/foundationpose/multiprocess_foundationpose_infer_sim.py

ini 复制代码
def inference(data_queue, detect_queue, hand_data_queue, hand_detect_queue, camera_pameters, mesh_file, standard_mask_path, weights_path, debug):
    pose_estimator = FoundationPoseInfer(camera_pameters, mesh_file, standard_mask_path, weights_path, debug)
    pose_tuner = ICPByHandCamera(camera_pameters, mesh_file, weights_path)

    print(f"*** inference *** Initialized !! ") 
    last_data_time = time.time()
    timeout_duration = 300  # auto exit time: seconds

    while True:
        if not data_queue.empty():
            rgb_array, depth_array, failed_last, reset = data_queue.get()
            if reset:
                pose_estimator = FoundationPoseInfer(camera_pameters, mesh_file, standard_mask_path, weights_path, debug)
                print("reset: re-init foundation pose")
                continue
            pose_in_cam, mask = pose_estimator.detect(rgb_array, depth_array, failed_last)
            detect_queue.put([pose_in_cam, mask, pose_estimator.extent_bbox])
            print(f"*** inference *** Detect target and add to detect_queue !! ") 
            last_data_time = time.time()

        if not hand_data_queue.empty():
            rgb_array_hand, depth_array_hand, \
                pose_in_world, orient_in_world, pose_matrix_in_world, \
                    pose_matrix_in_hand_cam = hand_data_queue.get()
            print(f"[perception] [inference] hand camera received, processing")

            # get world position from head camera 
            pose_in_cam, mask = pose_tuner.run(rgb_array_hand, depth_array_hand, pose_matrix_in_hand_cam)

            # TODO: update boxes, use flag: head_camera or hand_camera; update or new
            print(f"[perception] [inference] hand camera processed, sending")
            hand_detect_queue.put([pose_in_cam, mask, pose_estimator.extent_bbox])
            last_data_time = time.time()
        else:
            if time.time() - last_data_time > timeout_duration:
                print(f"*** inference *** No data received for {timeout_duration} seconds. Exiting... ")
                break
            # print(f"*** inference *** No RGBD data received !! ") 
        time.sleep(0.01)  # avoid high frequency empty polling, reduce CPU consumption

在这段代码中:

  1. 使用FastSAM进行目标检测

  2. 使用FoundationPose进行姿态估计

  3. 使用ICP进行pose精调

仿真模块

仿真模块与主入口一起,位于/mnt/workspace/notebook5/bin_picking_demo/sim_main.py路径下:

ini 复制代码
def main(opt, data_queue, detect_queue, hand_data_queue, hand_detect_queue):
    ......
    world = CortexWorld()
    ......
    robot = world.add_robot(CortexUr10LongSuction(name="robot", prim_path="{}/ur10_long_suction".format(env_path), robot_type=opt.robot_type))
    ......
    camera_prim1 = world.stage.DefinePrim("/World/Camera1", "Camera")
    ......
    world.add_task(BinPickingStackedTask(opt, mechanical_part_usd, usd_scale, opt.num_object, rp_head))
    
    # Reset the world and task to add objects, surface gripper joints, and obstacles, etc.
    world.reset()
    world.add_decider_network(behavior.make_decider_network(data_queue, detect_queue, hand_data_queue, hand_detect_queue, robot, target_pose, opt, rp_head, rp_hand, camera_prim1, camera_prim_hand))

    world.run(simulation_app,render=True, loop_fast=False, play_on_entry=True)
    print('## Simulation_app is closed. ##')

在这段代码中:

  1. 使用Isaac Cortex创建仿真环境;并配置camera、robot、task等基础资源

  2. 添加decider_network

  3. 仿真启动,消费感知子进程数据,更新仿真环境和机械臂姿态,并产生新的传感器数据

总结

通过PAI-DSW和noVNC可视化环境,利用Isaac Sim提供的一系列工具链可以快速搭建复杂的机器人感知和交互系统,实现高效的机器人算法原型开发和验证,并以zero-shot的方式迁移到真机中进行部署验证,提升物理AI系统和算法的研发效率和研发质量。

从本期开始,PAI Physical AI Notebook系列将告一段落,希望大家已经体验到了在PAi平台中进行Physical AI的便捷与高效。阿里云PAI平台是全功能的Physical AI开发平台,可以覆盖仿真数据合成、模仿学习、强化学习、软件在环验证等各个环节。

欢迎访问:

gallery.pai-ml.com

并搜索"NVIDIA Physical AI",获取更多关于PAI Physical AI的最佳实践。

相关推荐
冴羽1 小时前
10 个 Nano Banana Pro 专业级生图技巧
前端·人工智能·aigc
晨非辰1 小时前
算法闯关日记 Episode :解锁链表「环形」迷局与「相交」奥秘
数据结构·c++·人工智能·后端·python·深度学习·神经网络
老蒋新思维1 小时前
创客匠人 2025 峰会深度解析:AI 赋能垂直领域,创始人 IP 变现的差异化路径
大数据·网络·人工智能·网络协议·tcp/ip·重构·知识付费
沛沛老爹1 小时前
AI入门之LangChain Agent工具链组合设计:从理论到产业落地的AI智能体架构指南
人工智能·架构·langchain·agent·ai入门
摘星编程1 小时前
解构CANN图编译技术:打造高吞吐、低延迟的实时AI质检系统
人工智能
8个贝壳2 小时前
开发者福音!一键聚合GPT-5.1、Claude 4.5:我的高性价比AI模型中转站实战分享
人工智能
liliangcsdn2 小时前
如何从二项分布中抽取样本 - binomial
大数据·人工智能
北京耐用通信2 小时前
耐达讯自动化Profibus光纤转换器为您的水处理系统装上“光纤高速路”,数据从此畅通无阻!
网络·人工智能·科技·网络协议·自动化·信息与通信
老蒋新思维2 小时前
创客匠人 2025 峰会深度解析:AI 激活创始人 IP 变现的核心价值
网络·人工智能·网络协议·tcp/ip·创始人ip·创客匠人·知识变现