Orbit 使用指南 03 | 与刚体交互 | Isaac Sim | Omniverse

如是我闻: “在之前的指南中,我们讨论了独立脚本( standalone script)的基本工作原理以及如何在模拟器中生成不同的对象(prims)。在指南03中,我们将展示如何创建并与刚体进行交互。为此,我们使用Orbit中提供的assets.RigidObject类。”

指南03 对应于orbit/source/standalone/tutorials/01_assets目录下的run_rigid_object.py 脚本,让我们先搂一眼完整的代码

# Copyright (c) 2022-2024, The ORBIT Project Developers.
# All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause

"""
This script demonstrates how to create a rigid object and interact with it.

.. code-block:: bash

    # Usage
    ./orbit.sh -p source/standalone/tutorials/01_assets/run_rigid_object.py

"""

from __future__ import annotations

"""Launch Isaac Sim Simulator first."""


import argparse

from omni.isaac.orbit.app import AppLauncher

# add argparse arguments
parser = argparse.ArgumentParser(description="Tutorial on spawning and interacting with a rigid object.")
# append AppLauncher cli args
AppLauncher.add_app_launcher_args(parser)
# parse the arguments
args_cli = parser.parse_args()

# launch omniverse app
app_launcher = AppLauncher(args_cli)
simulation_app = app_launcher.app

"""Rest everything follows."""

import torch

import omni.isaac.core.utils.prims as prim_utils

import omni.isaac.orbit.sim as sim_utils
import omni.isaac.orbit.utils.math as math_utils
from omni.isaac.orbit.assets import RigidObject, RigidObjectCfg
from omni.isaac.orbit.sim import SimulationContext


def design_scene():
    """Designs the scene."""
    # Ground-plane
    cfg = sim_utils.GroundPlaneCfg()
    cfg.func("/World/defaultGroundPlane", cfg)
    # Lights
    cfg = sim_utils.DomeLightCfg(intensity=2000.0, color=(0.8, 0.8, 0.8))
    cfg.func("/World/Light", cfg)

    # Create separate groups called "Origin1", "Origin2", "Origin3"
    # Each group will have a robot in it
    origins = [[0.25, 0.25, 0.0], [-0.25, 0.25, 0.0], [0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]]
    for i, origin in enumerate(origins):
        prim_utils.create_prim(f"/World/Origin{i}", "Xform", translation=origin)

    # Rigid Object
    cone_cfg = RigidObjectCfg(
        prim_path="/World/Origin.*/Cone",
        spawn=sim_utils.ConeCfg(
            radius=0.1,
            height=0.2,
            rigid_props=sim_utils.RigidBodyPropertiesCfg(),
            mass_props=sim_utils.MassPropertiesCfg(mass=1.0),
            collision_props=sim_utils.CollisionPropertiesCfg(),
            visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0), metallic=0.2),
        ),
        init_state=RigidObjectCfg.InitialStateCfg(),
    )
    cone_object = RigidObject(cfg=cone_cfg)

    # return the scene information
    scene_entities = {"cone": cone_object}
    return scene_entities, origins


def run_simulator(sim: sim_utils.SimulationContext, entities: dict[str, RigidObject], origins: torch.Tensor):
    """Runs the simulation loop."""
    # Extract scene entities
    # note: we only do this here for readability. In general, it is better to access the entities directly from
    #   the dictionary. This dictionary is replaced by the InteractiveScene class in the next tutorial.
    cone_object = entities["cone"]
    # Define simulation stepping
    sim_dt = sim.get_physics_dt()
    sim_time = 0.0
    count = 0
    # Simulate physics
    while simulation_app.is_running():
        # reset
        if count % 250 == 0:
            # reset counters
            sim_time = 0.0
            count = 0
            # reset root state
            root_state = cone_object.data.default_root_state.clone()
            # sample a random position on a cylinder around the origins
            root_state[:, :3] += origins
            root_state[:, :3] += math_utils.sample_cylinder(
                radius=0.1, h_range=(0.25, 0.5), size=cone_object.num_instances, device=cone_object.device
            )
            # write root state to simulation
            cone_object.write_root_state_to_sim(root_state)
            # reset buffers
            cone_object.reset()
            print("----------------------------------------")
            print("[INFO]: Resetting object state...")
        # apply sim data
        cone_object.write_data_to_sim()
        # perform step
        sim.step()
        # update sim-time
        sim_time += sim_dt
        count += 1
        # update buffers
        cone_object.update(sim_dt)
        # print the root position
        if count % 50 == 0:
            print(f"Root position (in world): {cone_object.data.root_state_w[:, :3]}")


def main():
    """Main function."""
    # Load kit helper
    sim_cfg = sim_utils.SimulationCfg()
    sim = SimulationContext(sim_cfg)
    # Set main camera
    sim.set_camera_view(eye=[1.5, 0.0, 1.0], target=[0.0, 0.0, 0.0])
    # Design scene
    scene_entities, scene_origins = design_scene()
    scene_origins = torch.tensor(scene_origins, device=sim.device)
    # Play the simulator
    sim.reset()
    # Now we are ready!
    print("[INFO]: Setup complete...")
    # Run the simulator
    run_simulator(sim, scene_entities, scene_origins)


if __name__ == "__main__":
    # run the main function
    main()
    # close sim app
    simulation_app.close()
    

代码解析

在这个脚本中,我们将主函数main分割成两个独立的函数,这两个函数是在模拟器中设置任何模拟的两个主要步骤:

  1. 场景设计:顾名思义,这部分负责将所有图元( prims)添加到场景中。

  2. 模拟运行:这部分负责步进模拟器,与场景中的原始物体进行互动,例如,改变它们的姿态,并对它们应用指令。

区别这两个步骤是必要的,因为第二步只有在第一步完成并且模拟器被重置后才会发生。一旦模拟器被重置(自动播放模拟),新的(启用物理的)原始物体(prims)不应该被添加到场景中,因为这可能会导致意外的行为。然而,可以通过它们各自的句柄(respective handles)与原始物体(prims)进行互动。

场景设计

与前一个指南类似,我们使用地面平面和光源填充场景。此外,我们使用assets.RigidObject类将一个刚体添加到场景中。这个类负责在输入路径处生成原始物体,并初始化它们对应的刚体物理句柄。

在本指南中,我们使用与“生成对象指南”中的刚体圆锥相似的生成配置,创建一个圆锥形的刚体对象。唯一的区别是,现在我们将生成配置包装进assets.RigidObjectCfg类中。这个类包含有关资产生成策略、默认初始状态和其他元信息的信息。当这个类传递给assets.RigidObject类时,它会在播放模拟时生成对象并初始化相应的物理句柄。

作为例子,关于多次生成刚体原始物体,我们创建了它们的父Xform原始物体,/World/Origin{i},这对应于不同的生成位置。当正则表达式/World/Origin*/Cone传递给assets.RigidObject类时,它会在每个/World/Origin{i}位置生成刚体原始物体。例如,如果场景中存在/World/Origin1/World/Origin2,则刚体原始物体分别在位置/World/Origin1/Cone/World/Origin2/Cone处生成。

    # Create separate groups called "Origin1", "Origin2", "Origin3"
    # Each group will have a robot in it
    origins = [[0.25, 0.25, 0.0], [-0.25, 0.25, 0.0], [0.25, -0.25, 0.0], [-0.25, -0.25, 0.0]]
    for i, origin in enumerate(origins):
        prim_utils.create_prim(f"/World/Origin{i}", "Xform", translation=origin)

    # Rigid Object
    cone_cfg = RigidObjectCfg(
        prim_path="/World/Origin.*/Cone",
        spawn=sim_utils.ConeCfg(
            radius=0.1,
            height=0.2,
            rigid_props=sim_utils.RigidBodyPropertiesCfg(),
            mass_props=sim_utils.MassPropertiesCfg(mass=1.0),
            collision_props=sim_utils.CollisionPropertiesCfg(),
            visual_material=sim_utils.PreviewSurfaceCfg(diffuse_color=(0.0, 1.0, 0.0), metallic=0.2),
        ),
        init_state=RigidObjectCfg.InitialStateCfg(),
    )
    cone_object = RigidObject(cfg=cone_cfg)

由于我们是想与刚体进行互动,我们将这个实体返回给主函数。然后在模拟循环中使用这个实体与刚体进行互动。在后续的指南中,我们将看到使用scene.InteractiveScene类处理多个场景实体的更便捷方式。

    # return the scene information
    scene_entities = {"cone": cone_object}
    return scene_entities, origins

运行模拟循环

我们修改模拟循环已进行与刚体的互动,包括三个步骤

  1. 在固定时间间隔重置模拟状态、
  2. 步进模拟
  3. 以及更新刚体的内部缓冲区。

为了简便一些,我们从场景的字典中提取出刚体的实体,并将其存储在一个变量中。

在固定时间间隔重置模拟状态

为了重置生成的刚体原始物体的模拟状态,我们需要设置它们的姿态和速度。这两者共同定义了生成的刚体对象的根状态。重要的是要注意,这个状态是在模拟世界框架中定义的,而不是它们的父Xform原始物体的框架。这是因为物理引擎只理解世界框架,而不理解父Xform原始物体的框架。因此,在设置之前,我们需要将刚体原始物体的期望状态转换到世界框架中。

我们使用assets.RigidObject.data.default_root_state属性来获取生成的刚体原始物体的默认根状态。这个默认状态可以从assets.RigidObjectCfg.init_state属性配置,我们在这个指南中将其保留为身份。然后,我们随机化根状态的平移,并使用assets.RigidObject.write_root_state_to_sim()方法设置刚体原始物体的期望状态。正如名称所示,这个方法将刚体原始物体的根状态写入到模拟缓冲区中。

            # reset root state
            root_state = cone_object.data.default_root_state.clone()
            # sample a random position on a cylinder around the origins
            root_state[:, :3] += origins
            root_state[:, :3] += math_utils.sample_cylinder(
                radius=0.1, h_range=(0.25, 0.5), size=cone_object.num_instances, device=cone_object.device
            )
            # write root state to simulation
            cone_object.write_root_state_to_sim(root_state)
            # reset buffers
            cone_object.reset()

PS:我这段真看了半天,就只能直译了,我现在的理解是,我们要是想刷新这个圆锥的状态,就必须找出他的根状态,在根状态上做改变,当然如果是单纯的图形的话,在上一级Xform上改动也就可以了,也就是这一段代码,对orbit同样绝望还必须得用的可以私信我,我们一起研究一下

 root_state = cone_object.data.default_root_state.clone()

步进模拟

在步进模拟之前,我们执行assets.RigidObject.write_data_to_sim()方法。这个方法将其他数据,比如外部力,写入模拟缓冲区。在本指南中,我们没有对刚体施加任何外部力,所以这个方法不是必需的。然而,为了完整性,我们将他写在这里。

        # apply sim data
        cone_object.write_data_to_sim()

更新状态

在步进模拟之后,我们更新刚体原始物体的内部缓冲区,以便在assets.RigidObject.data属性内反映它们的新状态。这是通过使用assets.RigidObject.update()方法完成的。

        # update buffers
        cone_object.update(sim_dt)

代码执行

现在我们已经讲解了代码,让我们运行脚本并查看结果:

./orbit.sh -p source/standalone/tutorials/01_assets/run_rigid_object.py

这应该会打开一个带有地面平面、灯光和几个绿色圆锥的舞台。圆锥必须从随机高度落下并落在地面上。

在这里插入图片描述

要停止模拟,可以关闭窗口,或在UI中按停止按钮,或在终端中按Ctrl+C。

本指南展示了如何生成刚体对象,并将它们包装在RigidObject类中以初始化它们的物理句柄,这允许设置和获取它们的状态。在下一个指南中,我们将看到如何与由关节连接的刚体对象集合即关节物体进行互动。

愿本文渡一切机器人模拟器苦

以上

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/464667.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习周记(第三十周:文献阅读-SageFormer)2024.3.11~2024.3.17

目录 摘要 ABSTRACT 1 论文信息 1.1 论文标题 1.2 论文摘要 1.3 论文背景 2 论文模型 2.1 问题描述 2.2 模型信息 2.2.1 Series-aware Global Tokens(序列感知全局标记) 2.2.2 Graph Structure Learning(图结构学习) …

大数据面试题之SQL题

大数据面试题之SQL题 1.有一个录取学生人数表,记录的是每年录取学生人数和入学学生的学制 以下是表结构: CREATE TABLE admit ( id int(11) NOT NULL AUTO_INCREMENT, year int(255) DEFAULT NULL COMMENT ‘入学年度’, num int(255) DEFAULT NULL COMM…

交流互动系统|基于springboot框架+ Mysql+Java+Tomcat的交流互动系统设计与实现(可运行源码+数据库+设计文档)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java,ssm,springboot的平台设计与实现项目系统开发资源(可…

【医学图像处理】ECAT和HRRT格式转nii格式【超简单】

之前从ADNI上下载PET数据的时候发现有许多数据的格式不是DICOM的而是ECAT或者是HRRT格式,这对原本就少的PET数据是血上加霜啊。 当然只使用DICOM格式的数据也会得到不少的数据,我一开始也是只使用DICOM格式的样本,后来为了得到更多的数据&a…

2024年值得创作者关注的十大AI动画创新平台

别提找大型工作室制作动画了。如今,AI平台让我们就可以轻松制作动画。从简单的文本生动画功能到复杂的角色动作,这些平台为各种类型的创作者提供了不同的功能。 AI已经有了长足的发展,现在它可以理解复杂的人类动作和艺术意图,将简单的输入转化成丰富而详细的动画。 下面…

RoketMQ主从搭建

vim /etc/hosts# IP与域名映射,端口看自己的#nameserver 192.168.126.132 rocketmq-nameserver1 192.168.126.133 rocketmq-nameserver2# 注意主从节点不在同一个主机上 #broker 192.168.126.132 rocketmq-master1 192.168.126.133 rocketmq-master2#broker 192.168…

HarmonyOS(鸿蒙)不再适合JS语言开发

ArkTS是鸿蒙生态的应用开发语言。它在保持TypeScript(简称TS)基本语法风格的基础上,对TS的动态类型特性施加更严格的约束,引入静态类型。同时,提供了声明式UI、状态管理等相应的能力,让开发者可以以更简洁、…

用Python 3 开发的摄像头拍照程序

在当今数字化的世界中,使用摄像头进行拍照已成为日常生活的重要组成部分。无论是用于个人用途还是专业用途,能够使用电脑摄像头轻松拍照都是一项有用的技能。本文将指导您使用 Python 3 编写一个简单的程序,让您能够使用电脑摄像头拍照并将其…

如果网络不好 如何下载huggingface上的模型

很多朋友网络不太好,有时候上不了huggingface这样的国外网站; 或者网络流量不太够,想要下载一些stable diffusion模型,或者其他人工智能的大模型的时候,看到动辄几个G的模型文件,不太舍得下载;…

9. 综合案例-ATM系统 (1~7节知识综合练习)

ATM系统_综合大练习 今天的任务是对之前所有的学习的知识, 进行一个综合性的大练习. 老师说的好, 键盘敲烂 这个项目我写了大量的注释给大家参考, 如果有同学是跟着我的系列学习的, 一定动手练一练. 下面的代码只要按着敲是可以直接运行起来的, 我也把完整代码上传到了CSDN上…

Fritzing 简单使用

文章目录 1 Fritzing 资源2 Fritzing 简单使用3 添加自已的元器件3.1 面包板3.1.1 新建面包板 svg 文件3.1.2 新建面包板 3.2 原理图3.3 PCB3.4 图标3.5 使用 1 Fritzing 资源 1)官网: 开源的电子设计和原型平台:https://fritzing.org/免费开…

机试:砍树修路

问题描述 代码示例: //一坐标轴表示某道路,从0开始 到L,整数位置上都种有一颗树。现在该路修建地铁,要砍掉铁路线路上的树木。例如:L等于10,铺设4条铁路,坐标是1到2,2到3,2到8,3到…

【SpringBoot】解决数据库时间和返回时间格式不一致的问题

先看问题: 类中的属性中有Date类型的属性 数据库表中的数据: 可以看到也没问题 但是在返回实体类对象时,数据类型是这样的: 虽然数据是成功返回了,但这显然不是我们想要的结果.也不符合我们的日常使用习惯. 这个问题虽然前端,后端都能处理,但最好还是后端来进行处理.前端主…

openEuler学习总结1(仅供学习参考)

华为的openEuler内核是源于Linux。 openEuler操作系统安装流程 第一步:开启虚拟化 第二步:安装一个虚拟化软件virtualbox 第三步:镜像 第四步:配置 设置虚拟机所在的目录 把网卡类型选择成桥接网卡 挂载镜像 设置完成&#xff0…

玩转键盘鼠标,自动化你的电脑操作 —— 定时执行专家

简介 “定时执行专家”是一款功能强大的定时任务执行软件,除了支持常见的定时关机、重启、执行程序等功能外,还拥有模拟键盘按键和模拟鼠标操作功能,可以让你轻松实现各种自动化操作。 模拟键盘按键功能可以模拟用户的键盘输入,让…

BufferedOutputStream类讲解

咦咦咦,各位小可爱,我是你们的好伙伴——bug菌,今天又来给大家普及Java IO相关知识点了,别躲起来啊,听我讲干货还不快点赞,赞多了我就有动力讲得更嗨啦!所以呀,养成先点赞后阅读的好…

GEE错误——Line 12: xxx.size is not a function(计算列表长度出现错误)

简介 这里我们再计算研究区面积的时候出现了一个错误,这里的问题是Line 12: points8.size is not a function 主要问题是xxx不是一个数组或者对象,无法调用size方法。这里的问题是我们要获取这个对象的时候出现了问题,也就说你给函数传输的并不是一个对象,而不知道是什么…

基于Springboot+Vue+Sercurity实现的大学生健康管理平台

1.项目介绍 大学生健康档案管理系统,通过电子健康档案管理系统这个平台,可以实现人员健康情况的信息化、网络化、系统化、规范化管理,从繁杂的数据查询和统计中解脱出来,更好的掌握人员健康状况。系统的主要功能包括:…

7.JavaWebHTML:构建数字世界的语言和结构

目录 导语: 第一部分:Web概念与作用 1.1 Web的定义 1.2 Web的作用 1.3 JavaWeb 第二部分:HTML概念与内容 2.1 HTML的定义 2.2 HTML的内容 第三部分:HTML的作用 3.1 HTML的作用 3.2 HTML在现代Web开发中的角色 …

2024.3.15

1.单向循环链表 代码: #include"loop.h" //创建单向循环链表 loop_p create_loop_list() {loop_p H (loop_p)malloc(sizeof(loop));if(HNULL){printf("空间申请失败\n");return NULL;}H->len0;H->nextH;return H; } //创建节点 loop_p…