Isaac Sim知识小解(6):Robot
1. 机器人就是 Articulation
在 Isaac Sim 中,机器人本质上就是一个 Articulation,也就是一组通过关节(Joint)连接起来的刚体(Rigid Body),把这些东西按照一个特定的拓扑结构组织起来,并且每一个可动的关节都带有一个 Drive,可以接受位置或者速度的控制指令。
Robot (Articulation) = Rigid Body 刚体集合
+ Joint 关节(连接刚体)
+ Drive 驱动器(接受控制指令)
Isaac Sim 提供了 omni.isaac.core.robots.robot.Robot 这个类来对 Articulation 进行上层封装,它本质上是 Articulation 的一个子类,提供了诸如 get_joint_positions()、set_joint_positions()等方法。一般来说我们会直接把一个机器人的 USD 加载进来,然后用 Robot 类去包裹对应的 prim。
类继承关系:
ArticulationView (底层,PhysX 直接交互)
└── Articulation (中间层,封装了物理视图操作)
└── Robot (上层,提供友好的 Python API)
├── get_joint_positions()
├── set_joint_positions()
├── apply_action()
├── dof_names
├── num_dof
└── ...
这里给出一个demo:
from omni.isaac.core.robots.robot import Robot
from omni.isaac.core.utils.prims import create_prim
# 把机器人 USD 加载到指定的 prim path 下
create_prim(
prim_path="/World/robot",
prim_type="Xform",
usd_path="/path/to/your/robot.usd",
)
robot = Robot(prim_path="/World/robot", name="my_robot")
# 一些求解器相关的参数,影响物理仿真的稳定性
robot.set_solver_position_iteration_count(124)
robot.set_solver_velocity_iteration_count(4)
robot.set_stabilization_threshold(0.005)
# 设置机器人在世界中的位置和姿态
robot.set_world_pose(position, orientation)
需要注意的是:先创建好所有 prim,把 robot 加入 world.scene,调用 world.reset(),然后再 robot.initialize()
原因:initialize() 内部需要创建 ArticulationView ,而 ArticulationView 依赖 PhysX 的物理场景。 world.reset() 才会真正初始化 PhysX 物理世界。如果跳过 reset 直接调用 initialize,底层的 View 会找不到对应的物理句柄
world.scene.add(robot)
world.reset()
robot.initialize()时间线:
创建 Prim ———→ 加入 Scene ———→ reset() ———→ initialize()
✅ ✅ ✅ ✅此时只是USD场景 注册到场景 物理引擎初始化 创建PhysX View
树中的一个节点, ArticulationView
没有任何物理属性
initialize() 之后,机器人就成功激活了
print(robot.dof_names) # 每个关节的名字,顺序很重要
print(robot.num_dof) # 总自由度数
print(robot.get_joint_positions()) # 当前每个关节的角度/位置
有一个非常关键、并且在后面运动规划环节会反复用到的点:dof_names 的顺序就是关节状态向量的顺序。Isaac Sim 内部的关节顺序是按照 USD 的拓扑解析出来的,它和你脑子里想的「关节 1 到关节 7」的顺序不一定一致,更不一定和 cuRobo 期望的顺序一致。
2. 控制机器人
控制机器人最直接的方式有两种:直接设置和力控
set_joint_positions()
它会直接把关节设置到指定的位置,绕过物理引擎,相当于瞬移。这在初始化机器人姿态、或者重置场景的时候非常有用,但是它不符合物理,不应该在正常的控制循环中使用:
# 直接把 Franka 摆到一个默认的初始姿态(7 个臂关节 + 若干夹爪关节)
robot.set_joint_positions(
[0.0, -0.785, 0.0, -2.356, 0.0, 1.57079, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
)
值得一提的是,对于我们使用的 Franka RoboTiq 资产来说,其包含一个 RoboTiq 夹爪,包含了六个自由度,当然,实际上这个夹爪的不同自由度之间存在约束,如 Mimic Joint 等,因此实际上在控制一个 Joint 的时候其他的都会随之运动。
- Drive 控制关节-----set_joint_position_targets
让物理引擎在每一步仿真中根据 stiffness 和 damping 把关节朝着目标驱动过去。在 Isaac Sim 中,这一般通过 ArticulationView 来做
# robot_view 即 robot._articulation_view
robot_view = robot._articulation_view
# 给指定的关节设置位置目标,物理引擎会逐步驱动过去
robot_view.set_joint_position_targets(
target_joint_positions,
joint_indices=[0, 1, 2, 3, 4, 5, 6], # 只控制 7 个臂关节
)
world.step(render=False) # 推进物理;
Drive 类型:
├── Position Drive (位置驱动) → 给目标角度,关节自动运动过去
│ stiffness 高 → 像弹簧,紧紧拉向目标位置
│ damping 高 → 像阻尼器,减少振荡
│
├── Velocity Drive (速度驱动) → 给目标速度,关节以此速度运动
│
└── Effort Drive (力矩驱动) → 直接给力/力矩
joint_indices 这个参数用来指定我们要控制哪些关节,这一点非常实用,因为一个机器人往往把「手臂」和「夹爪」放在同一个 Articulation 里,但是它们的控制逻辑是分开的:手臂用curobo运动规划给出的轨迹来驱动,而夹爪只需要在「张开」和「闭合」两个状态之间切换
以 Franka + Robotiq 夹爪为例,臂有 7 个自由度,夹爪有 6 个自由度(Robotiq 2F-85 是个多连杆的结构),我们可以这样定义张开和闭合:
arm_dof_num = 7
gripper_open = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
gripper_close = [0.7853, 0.7853, -0.7853, -0.7853, -0.7853, -0.7853]
# 把规划得到的臂部轨迹和夹爪状态拼成一个完整的 action
def make_action(arm_joints, grasp: bool):
return np.concatenate([
arm_joints[:arm_dof_num],
gripper_close if grasp else gripper_open,
])
3. Mimic 关节
Robotiq 夹爪(以及很多真实夹爪)的机械结构中, 多个关节之间存在运动耦合关系。
Mimic 关节 ,即从动关节,其运动是主动关节运动的 固定比例函数 ,不需要独立驱动。
Robotiq 2F-85 夹爪结构:
主动关节 (finger_joint) 从动关节 (mimic joints)
┌──────────────┐ ┌───────────────────-──┐
│ 电机驱动 │ ──约束关系──→ │ inner_finger_joint │
│ │ │ outer_knuckle_joint │
│ 你控制的这个 │ │ ... (3-4个从动关节) │
└──────────────┘ └────────────────────-─┘
当 finger_joint 转动 θ 度时
→ inner_finger 自动转动 f(θ) 度
→ outer_knuckle 自动转动 g(θ) 度
(由机械连杆结构决定的比例关系)
如何控制Mimic 关节?
-
驱动关节设置较小的 stiffness 和 damping,并且从动关节的 max force 直接设为 0
from genmanip.utils.usd_utils import (
set_drive_damping_and_stiffness,
set_drive_max_force,
)
# 1. # 主动关节:给一个比较软的驱动,通过调节 damping 和 stiffness 可以改变夹爪的闭合速度等
for joint in active_joints:
set_drive_damping_and_stiffness(joint_path, damping=0.01, stiffness=0.1)
set_drive_max_force(joint_path, 10000.0)
# 2. 从动关节:max force 设为 0,纯粹被带动
for joint in passive_joints:
set_drive_max_force(joint_path, 0.0) # max_force=0 = 不产生任何驱动力!
- 只控制第一个 驱动关节即可,但要求 USD 中 Mimic 约束已经正确配置好
# 其余关节完全由 mimic 约束自动跟随
gripper_dof_num = 1 # 只需要控制1个DOF
gripper_open = [0.0]
gripper_close = [1]
# 控制时只需要设置1个值:
robot.set_joint_positions(arm_positions + [gripper_value])
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)