1. OmniGraph(视觉编程)
OmniGraph 是 Omniverse 的可视化编程框架。它提供了一个图状结构,将 Omniverse 内多个系统的功能节点串联起来;同时也是一个计算框架,允许你编写高度自定义的节点,将自己的功能无缝集成到 Omniverse 中,并自动利用其高效的计算后端。
在 Isaac Sim 中,OmniGraph 是:
-
Replicators(批量场景生成器)
-
ROS / ROS2 桥接
-
传感器访问
-
控制器
-
外部输入/输出设备
-
用户界面等功能的核心引擎
本教程将带你入门 OmniGraph 的世界。我们强烈建议你同时阅读《OmniGraph》官方文档,因为它是 Omniverse Kit 的关键组件。
学习目标
-
了解 OmniGraph 的基本概念
-
教你构建一个动作图(Action Graph),在 Isaac Sim 中控制 Jetbot 机器人
-
演示如何使用 OmniGraph 快捷生成功差控制器(differential controller)图
图编辑器(Graph Editors)
Isaac Sim 中有两种图编辑器:Action Graph(动作图)和 Generic Graph(通用图)。它们都在菜单 Window > Visual Scripting 下可见。在大多数 Isaac Sim 场景中,你会用到的是 Action Graph。
节点搜索(Node Search)
OmniGraph 中提供了丰富的节点库。打开图编辑器后,左侧面板会按类别列出所有节点。你也可以在面板顶部的搜索框中输入关键词,快速找到需要的节点。
基本概念
Action Graph(动作图) vs Push Graph(通用图)
-
Action Graph
-
需要有一个“执行”节点(Execution Node)作为触发器,才会在触发时运行。
-
常见触发器是 Tick 节点——它在仿真每帧开始时触发,这样当仿真未播放时图不会运行,播放后每渲染一帧就执行一次。
-
如果你把 Tick 节点从动作图中删掉,按下 Play 后动作图就不会运行了。
-
其它触发方式还包括键盘/鼠标输入或舞台事件,对应的节点可在 “Event” 节点分类中找到。
-
-
Push Graph
-
不需要执行节点,默认情况下每个渲染帧都会自动执行。
-
因为视口一直在渲染,即使仿真未播放,节点也会持续运行。
-
举例:在 Push Graph 中拖一个 “Print Text” 节点,打开控制台并允许显示 Info 级别日志,输入完文字后即刻会在控制台打印出来。
-
如果图中节点有连线依赖,它会按照连线顺序执行;若无连线,则各节点按无保证的顺序并行执行。
-
这样,你就对 OmniGraph 的基础概念和使用场景有了初步了解。接下来,我们将手把手创建一个控制 Jetbot 的动作图,让它在仿真中动起来!
2. 自建OmniGraph
build
-
在编辑器顶部菜单中依次选择 Window > Visual Scripting > Action Graph,此时图编辑器会在与内容浏览器相同的面板中打开。
-
点击 New Action Graph,创建一个空白动作图。
-
在图编辑器右上角的搜索栏中输入 controller。
-
将 Articulation Controller 和 Differential Controller 节点拖入画布。
Articulation Controller 会对任何带有关节根(articulation root)的 Prim,向指定关节施加力、位置或速度驱动命令。
-
配置要控制的机器人:
-
选中 Articulation Controller 节点,在属性面板中进行设置:
-
方案 A:点击 usePath,在 robotPath 字段中输入机器人路径
/World/jetbot
; -
方案 B:点击属性面板顶部的 Add Targets,在弹出的选择窗口中选中 JetBot。
-
-
Differential Controller 根据目标的线速度和角速度,为双轮机器人计算驱动命令。它同样需要配置关键参数。
-
配置 Differential Controller:
-
选中 Differential Controller 节点,在属性面板中设置:
-
wheelDistance(轮距)= 0.1125
-
wheelRadius(轮半径)= 0.03
-
maxAngularSpeed(最大角速度)= 0.2
-
-
配置 Articulation Controller 的关节列表
Articulation Controller 还需要知道要驱动哪些关节,以令其按指定方式运动。它期望接收一个 token 列表或索引值列表。JetBot 在其底盘下有两个旋转关节:left_wheel_joint
和 right_wheel_joint
。你可以在 Stage Context Tree 中的 /World/jetbot/chassis
下找到它们。
-
在图编辑器的搜索栏中输入 token。
-
将 Constant Token 节点拖入画布两次。
-
选中第一个 Constant Token,在属性面板中将其 value 设置为
left_wheel_joint
; -
选中第二个 Constant Token,将其 value 设置为
right_wheel_joint
。 -
在搜索栏中输入 make array(制作成数组),将 Make Array 节点拖入画布。
-
选中 Make Array 节点,点击属性面板中输入列表旁的 + 图标,添加第二个输入端口;
-
将 arraySize 设置为
2
; -
从 Array Type 的下拉菜单中,将输入类型(Input Type)设为
token[]
。
-
-
将两个 Constant Token 节点的输出,分别连接到 Make Array 的
input0
和input1
; -
再将 Make Array 的输出连接到 Articulation Controller 节点的 Joint Names 输入。
添加事件触发节点
最后,需要一个事件节点来驱动整个图表在仿真播放时持续执行。
-
在搜索栏中输入 playback,将 On Playback Tick 节点拖入画布。
-
该节点在仿真播放时,每帧都会发出一次执行事件。
-
-
将 On Playback Tick 的 Tick 输出,分别连接到 Articulation Controller 和 Differential Controller 节点的 Exec In 输入。
-
将 Differential Controller 的 Velocity Command 输出,连接到 Articulation Controller 的 Velocity Command 输入。
概括
下面用简洁的流程图和说明,概括一下上文中通过 OmniGraph 节点来控制 JetBot 小车的整体流程:
-
事件触发(On Playback Tick)
-
On Playback Tick 节点在仿真播放时,每一帧都会发出一次 “Tick” 执行信号。
-
“Tick” 信号分别输入到 Differential Controller 和 Articulation Controller 的 Exec In 端口,驱动后续计算。
-
-
差速控制(Differential Controller)
-
接收到 Tick 信号后,Differential Controller 根据设定的目标线速度(linear velocity)和角速度(angular velocity),结合轮距(
wheelDistance
)和轮半径(wheelRadius
),计算出左右两个车轮的驱动速度——即 Velocity Command。 -
此输出通过连线传给 Articulation Controller。
-
-
关节列表准备(Constant Token → Make Array)
-
两个 Constant Token 节点分别存储
left_wheel_joint
和right_wheel_joint
两个关节名称。 -
Make Array 节点将这两个 token 组合为一个
token[]
数组,作为 Articulation Controller 的 Joint Names 输入,告诉它要驱动哪两个关节。
-
-
关节驱动(Articulation Controller)
-
接收 Tick 执行信号(Exec In)、差速控制输出(Velocity Command)以及关节名称数组(Joint Names)后,Articulation Controller 将 Velocity Command 转换为对指定关节的速度驱动命令,并下发给物理模拟引擎。
-
从而实现两个轮子的协同运动,带动小车前进或转向。
-
-
仿真运行(Play)
-
按下 Play,以上节点开始按序运转:每个仿真帧触发一次 Differential → Articulation 的计算链,持续地通过物理引擎驱动小车运动。
-
可以通过修改角速度和线速度让小车移动。
使用键盘控制
探索可用的 OmniGraph 节点,并尝试搭建一个通过键盘控制 JetBot 的图。
目前我们只有:
我们需要键盘输入进行控制,所以需要键盘输入节点:
分别设置成WASD
这里的键盘输入之后输出的值是布尔值 IsPressed
。需要把布尔值(true
/false
)转成数值(1.0
/0.0
),方便后续运算。这里就要用到 To Double
这里是通过线速度和角速度控制小车移动和转向,那么这两个输入肯定要被键盘输入所控制,我们当前只是将bool值转化成了数值,并不是实际的速度值,所以需要进一步转化:
首先需要一个乘法,将按键状态值(0/1)承上我们设置的速度,就是最终速度值,用来存储这个速度常量的节点就是Constant Double。
我们有两种速度,角速度和线速度,所以需要两个速度常量节点。有4个键盘输入,每个都要和速度常量相乘,所以需要4个multiply,每个multiply都要接收速度常量值和键盘输入值,最终输出的就是实际的速度值。
在来看这里,w/s就是控制线速度,a/d就是控制角速度
前后、左右按键的速度分量合并成线速度和角速度。
-
Subtract
-
上半部分:线速度 = “前进(W)”分量 − “后退(S)”分量
-
下半部分:角速度 = “右转(D)”分量 − “左转(A)”分量
-
a/d乘出来的速度值相减就是实际的角速度,w/s乘出来的速度值相减就是实际的线速度:
记得修改一下差速控制中的最大角速度,之前设置的0.2太小了,我们这里5就差不多了。
3. OmniGraph 快捷方式
从头搭图可能很繁琐,尤其在你需要频繁迭代时。我们为常用的图提供了一些快捷生成方式 —— 只需几次点击,就能生成包含多个节点和连线的复杂图。它们位于菜单 Isaac Utils > Common Omnigraphs 下,对应的使用说明在 Commonly Used Omnigraph Shortcuts 文档中。
使用菜单快捷方式生成差速控制器图的步骤:
-
删除(或禁用,如果有此选项)之前任何用于控制 JetBot 的 Omnigraph。
-
在菜单栏点击 Isaac Utils > Common Omnigraphs > Differential Controller。
-
弹出参数填写对话框后,按提示输入必要参数:
-
Articulation Root:填入
/World/jetbot
-
Wheel Distance(轮距):
0.1125
-
Wheel Radius(轮半径):
0.03
-
JetBot 只有两个可控关节,其余字段可留空。
-
-
打开 Use Keyboard Control (WASD) 开关,以启用键盘控制。
-
点击 OK,OmniGraph 会在
/Graph/differential_controller
下自动生成完整的控制图。 -
按 Play 开始仿真。
-
验证可用键盘的 WASD 键控制 JetBot 前进、后退和转向。
4. OmniGraph:输入设备
本教程将带你使用 OmniGraph,将输入设备(如游戏手柄或键盘)连接到 Isaac Sim 仿真中,实现:
-
通过游戏手柄控制移动机器人
-
使用键盘操作舞台上的物体
我这没手柄,就先用键盘了,后续有了手柄在进行研究
运行示例
OmniGraph 的键盘示例展示了如何接收键盘输入并将它们连接到场景中。连接完成后,就可以用按键来修改舞台上物体的特定属性。
-
在菜单栏依次点击 Isaac Examples > Input Devices > Omniverse Keyboard,打开示例。
-
按 Play 开始仿真。
-
在舞台上的立方体,可通过按 A 键变大,按 D 键变小。
1. 读键盘状态
-
Read Keyboard State(两个节点)
-
第一个监听 A 键,第二个监听 D 键。
-
输出
IsPressed
布尔值。
-
-
To Double
-
将布尔值 (
true
/false
) 转为数值 (1.0
/0.0
),方便做算术运算。
-
2. 计算缩放增量
-
Constant Int
-
存储一个“单位增量”,比如
1
(你可以把它理解为“每按一下 A/D,就放大或缩小 1 单位”)。
-
-
Multiply(两个节点)
-
A_pressed * +1
→ 得到 “放大贡献” -
D_pressed * +1
→ 得到 “缩小贡献”
-
-
Add
-
将上面两者相加:
deltaRaw = (A?1:0) + (D?1:0)
-
由于按 D 时希望“缩小”,实际上你会把 D 那路乘以
-1
或在后面做一次相减,总之合成一个能表示“正向放大/负向缩小”的数值。
-
3. 考虑帧率(时间因子)
-
Constant Double
-
存一个小数(例如
0.1
),表示“每秒变化的比例”或用来和帧间隔相乘,保证不同帧率下效果一致。
-
-
Multiply
-
把上面算出的
deltaRaw
乘上这个0.1
,得到 deltaPerFrame。
-
4. 读取当前属性并累加
-
Read Prim Attribute
-
读出立方体当前的某个属性(比如
x
轴缩放值,Attribute Name 里填"xformOp:scale:1"
之类的路径,Prim Path 指你的/World/Cube
)。
-
-
Add
-
把当前值和 deltaPerFrame 相加,得到 newScale。
-
5. 每帧执行与写回
-
On Tick
-
每个渲染帧都会发出一次 Tick(仿真播放时才会触发),为所有带
Exec In
的节点提供执行脉冲。
-
-
Write Prim Attribute
-
接收
Exec In
、Prim Path
、Attribute Name
、以及新算好的Value
(即 newScale),把它写回到立方体上,实时更新尺寸。
-
5. 其他常用 OmniGraph 快捷方式
快捷方式列表
控制器图(Controller Graphs)
-
Articulation Position Controller
-
Articulation Velocity Controller
-
Differential Controller
-
Gripper Controller
ROS 图(ROS Graphs)
-
ROS2 Clock
-
ROS2 Camera
-
ROS2 RTX Lidar
-
ROS2 Joint State Publisher and Subscriber
-
ROS2 TF Publisher
-
ROS2 Odometry Publisher
-
ROS2 Generic Publisher
注意:
系统不会自动检测场景中是否已有功能重复或控制同一机器人的图;请务必保证各图在场景中的唯一性。
这只是生成图的快捷方式;生成后,你仍可根据需求自由编辑和扩展这些图。
带星号(*)的参数为必填
ROS图暂时不做学习,先看一下其他的控制图
用于驱动机器人的控制器快捷方式有:
-
Articulation 控制器(关节位置和速度)
-
差速驱动控制器(Differential Drive Controller)
-
夹爪控制器(Gripper Controller)
我们之前已经演示过了第二个差速控制,这里演示一下剩下两个。
Articulation Controllers
Articulation Position/Velocity Controllers 会直接向机器人的每个关节下发命令。
-
Robot Prim:机器人的父级 prim(根节点)。
-
Graph Path*:生成的图存放路径。默认会建在独立树下,比如
/Graph/position_controller
或/Graph/velocity_controller
。如果该路径已存在,系统会自动在末尾加数字寻找下一个可用路径。 -
Add to Existing Graph:默认为 False。不勾选时,生成新图;勾选后,会把节点添加到已有图里,并复用已有的 Tick 节点(如果有)。不管怎样,总会再添加新的控制器节点。
使用 Articulation Controller 驱动机器人
-
在新建的图里,选中 JointCommandArray 节点(属性面板中可修改)。
-
点击 Play,开始仿真。
-
在属性面板里调整 JointCommandArray 的值,机器人就会按你给的命令移动。
如果 USD 原始场景里已经保存了某些初始目标位置或速度,按下播放后,机器人会立刻往这些目标运动。
夹爪控制器(Gripper Controller)
夹爪控制器适用于每个手指只有一个自由度驱动的末端执行器,包括所有的平行 Jaw 夹爪,以及那些多指但每指单自由度的机械手。
快捷参数说明
-
Parent Robot*:包含夹爪的机器人 prim。可以直接选夹爪本身,或若夹爪是手臂一部分,则选整条机械臂的根 prim。
-
Graph Path*:生成的图存放路径,默认位置为
/Graph/{type}_controller
。如该路径已存在,会自动在末尾追加数字以寻找可用路径。 -
Gripper Root*:包含所有夹爪关节的 prim 根节点。
-
Gripper Speed*:夹爪开合速度,单位为米/秒(对棱柱关节)或弧度/秒(对旋转关节)。
-
Gripper Joint Names*:所有控制夹爪手指的关节名称,逗号分隔。
-
Open/Close Position Limit:认为“完全打开”或“完全闭合”时的关节位置值,单位同上。留空时默认读取 USD 文件里的关节极限。
-
Use Keyboard Control:默认不启用。勾选后,会自动在图里添加接收键盘 “O”(Open)、“C”(Close)、“N”(停止)三个输入的节点。
-
Add to Existing Graph:默认 False。勾选后,会把节点添加到已有图中,复用已有的 Tick 节点(若存在),但会无条件再添加新的控制器节点。
使用夹爪控制器
-
如果不指定 Open/Close Position Limit,控制器会使用 USD 里预设的关节极限。
-
如果你填反了“打开”和“闭合”数值,控制器会自动检测并纠正——它假设“打开”的关节极限值大于“闭合”的极限值。若你的夹爪定义相反,可自行交换这两个数值,或修改对应的 Python 脚本来适配。
如果你想用Articulation Controller 驱动机械臂,而用gripper控制夹爪,你可以:
在Articulation Controller 的图里把最后两个输入(左右夹爪关节)删除
这是就是两个图在同时工作,只不过他们控制的部位不同,仍然可以按CON控制夹爪