Isaac Lab 操作空间控制器(OSC)实战:同时控制机械臂末端位姿与接触力
2026/9/17 12:11:43 网站建设 项目流程

Isaac Lab 操作空间控制器(OSC)实战:同时控制机械臂末端位姿与接触力

【免费下载链接】IsaacLabUnified framework for robot learning with multi-physics/renderer support项目地址: https://gitcode.com/GitHub_Trending/is/IsaacLab

本篇教程基于 Isaac Lab 的run_osc.py示例,讲解如何利用OperationalSpaceController(操作空间控制器)驱动机械臂,在跟踪期望末端位姿的同时,对倾斜墙面施加恒定接触力(模拟擦桌子等接触作业)。读完本文,你将掌握 OSC 的核心原理、OperationalSpaceControllerCfg全量配置参数、与差分 IK 控制器的区别,以及如何在 Isaac Lab 仿真环境中完成"力/位混合控制"的完整闭环。

为什么需要操作空间控制器

在 Isaac Lab 中,差分 IK 控制器教程 通过运动学求解将末端位姿映射为关节位置指令,适用于纯轨迹跟踪场景。但以下任务场景中差分 IK 并不够用:

  • 需要强制指定任务空间的位姿跟踪误差动力学(如保证末端以指定刚度、阻尼特性逼近目标);
  • 需要用关节力矩/力(effort/torque)指令直接驱动机器人;
  • 需要在一个方向上控制运动、同时在其他方向施加接触力(例如用抹布擦桌面、墙面抛光等接触作业)。

此时就需要操作空间控制器(Operational Space Controller,OSC)。OSC 的理论基础是 Khatib 于 1987 年提出的操作空间公式(Operational Space Formulation),它把任务空间(笛卡尔空间)的期望动力学映射到关节空间力矩。控制器实现及配置定义于:

  • 控制器实现
  • 控制器配置

本教程将复用OperationalSpaceController,让 Franka Panda 机械臂对一面红色倾斜墙持续施加垂直于墙面(沿任务帧 z 轴)的恒定力,同时在其他五个方向跟踪期望末端位姿。

运行示例:搭建场景并驱动 128 台机器人

示例脚本位于 scripts/tutorials/05_controllers/run_osc.py,通过仓库根目录下的启动脚本运行:

./isaaclab.sh -p scripts/tutorials/05_controllers/run_osc.py --num_envs 128

脚本将启动包含 128 台机器人的并行仿真环境。场景构成(SceneCfg)包括:

  • 地面平面(GroundPlaneCfg)与半球光(DomeLightCfg);
  • 一面半透明红色倾斜墙(CuboidCfg),尺寸为 2.0 × 1.5 × 0.01 m,启用碰撞与接触传感器,姿态四元数(0, -0.3827, 0, 0.9239)(绕 y 轴旋转约 45°),位置(0.685, 0, 0.3)
  • 一个ContactSensorCfgprim_path="/World/envs/env_.*/TiltedWall"history_length=2)用于读取接触力;
  • Franka Panda 机械臂:关键设定是把panda_shoulderpanda_forearm驱动器的刚度与阻尼清零(力矩控制模式),并关闭重力(disable_gravity=True),使关节完全由 OSC 输出的力矩指令驱动。

仿真循环中,机械臂将在三组目标(三个不同的末端位姿,均对应墙面上不同的接触点)之间循环切换。运行结果中,当前与目标末端位姿通过帧标记(frame marker)显示,你将看到机械臂到达目标位姿的同时保持垂直于墙面施加恒定力。运行效果如下:

停止仿真只需关闭窗口或在终端按下Ctrl+C

创建操作空间控制器:OperationalSpaceControllerCfg 全参数解析

OperationalSpaceController的任务是在任务空间内同时进行运动控制与力控制,输出关节力矩。任务空间参考系(task frame)可以是欧氏空间中的任意坐标系,默认取机器人基座坐标系。当目标坐标相对其他坐标系更容易定义时(例如本教程中墙面平行坐标系),应在set_commandcurrent_task_frame_pose_b参数中提供该任务参考系相对基座的位姿。本教程中,目标位姿与墙面同姿态,将其作为任务帧后,力控制方向恰好只落在任务帧的 z 轴,全部配置参数都围绕这一任务参考系展开。

控制器在 operational_space.py 中以批处理 + PyTorch 运算实现,天然支持并行环境(num_envs)。

target_types:任务空间目标类型

指定任务空间目标的类型与参考系,由"类型 + 参考"两个子串用下划线拼接:

取值含义命令维度
"pose_abs"绝对位姿(相对机器人基座),含位置 + 四元数7
"pose_rel"相对末端当前位姿的位姿增量,旋转用轴角表示6
"wrench_abs"绝对力/力矩(相对机器人基座)6

若需同时做位姿与力控制,将target_types设为列表,如["pose_abs", "wrench_abs"]["pose_rel", "wrench_abs"]。各目标的命令向量按target_types顺序拼接,action_dim为各目标维度之和(见下节)。

本教程使用target_types=["pose_abs", "wrench_abs"]:除 z 轴外的五个方向做绝对位姿控制,z 轴做绝对力控制。

控制轴选择:motion_control_axes_task 与 contact_wrench_control_axes_task

用 0/1 长度为 6 的列表分别指定运动控制与力控制作用的轴(顺序为 x、y、z 平动 + 绕 x、y、z 转动)。两列表应互补:例如 x 轴若motion_control_axes_task为 0,则contact_wrench_control_axes_task应为 1。

本教程中:

motion_control_axes_task=[1, 1, 0, 1, 1, 1], # 除 z 平动外的所有轴做运动控制 contact_wrench_control_axes_task=[0, 0, 1, 0, 0, 0], # 仅在 z 平动方向做力控制

注意:源码中会将增益矩阵与选择矩阵相乘,把非运动控制轴的增益清零(operational_space.py第 95-97 行),避免因轴间耦合导致未控制轴产生意外力矩。

运动控制:刚度、阻尼比与阻抗模式

运动控制轴上的期望刚度(stiffness)与阻尼比(damping ratio)通过以下参数设置:

  • motion_stiffness_task:位置增益(N/m 或 N·m/rad),可为标量(所有轴相同)或 6 元素列表,默认100.0 × 6
  • motion_damping_ratio_task:阻尼比,配合位置增益计算速度增益:d_gains = 2 * sqrt(p_gains) * damping_ratio,默认1.0 × 6

若希望刚度/阻尼比作为命令参数动态改变(例如用 RL 学习阻抗或运行中在线调整),设置impedance_mode

取值含义
"fixed"增益固定,命令只含任务空间目标
"variable_kp"命令额外包含 6 个刚度值(action_dim = target_dim + 6
"variable"命令额外包含刚度与阻尼比(action_dim = target_dim + 6 + 6

使用"variable_kp"/"variable"时必须同时设置:

  • motion_stiffness_limits_task:刚度上下限,默认(0, 1000)
  • motion_damping_ratio_limits_task:阻尼比上下限,默认(0, 100)(仅"variable"使用)。

命令中的刚度/阻尼比会被裁剪到上述范围内(见operational_space.py第 224-227、243-248 行)。

本教程设置impedance_mode="variable_kp"motion_damping_ratio_task=1.0(阻尼比固定为 1,kd 随 kp 自适应,维持临界阻尼响应),并在命令中动态传入三组 kp:360、420、320(每个目标一组)。

力控制:开环与闭环

  • 开环力控制:不设置contact_wrench_stiffness_task(保持None),直接输出期望力;
  • 闭环力控制:设置contact_wrench_stiffness_task(标量或 6 元素列表),在期望力上叠加刚度 × 期望力与实测力之差(含前馈项),形成反馈修正。

由于目前接触传感器只能测量线性力、无法测量力矩,闭环控制仅使用contact_wrench_stiffness_task的前三个元素(线性部分),力矩方向保持开环(见operational_space.py第 459-472 行)。

本教程设置contact_wrench_stiffness_task=[0.0, 0.0, 0.1, 0.0, 0.0, 0.0]:仅对 z 轴力做闭环反馈(增益 0.1),期望力为任务帧 z 轴方向 10 N。

惯性动力学解耦(inverse dynamics)

  • inertial_dynamics_decoupling=True:利用机器人的质量/惯性矩阵解耦任务空间的期望加速度(逆动力学),计算操作空间质量矩阵M_task = (J M⁻¹ Jᵀ)⁻¹,再得到F = M_task · ẍ_des。这对快速运动下的控制精度至关重要,解耦覆盖全部六个运动轴之间的耦合;
  • partial_inertial_dynamics_decoupling=True:忽略平动与转动之间的惯性耦合,分别计算平移与旋转部分(如 测试用例 test_franka_pose_abs_with_partial_inertial_decoupling 所示)。

若为False,则退化为不包含惯性项的任务空间阻抗控制(命令力直接等于期望加速度)。本教程使用inertial_dynamics_decoupling=Truepartial_inertial_dynamics_decoupling=False,做完整惯性解耦。

重力补偿

gravity_compensation=True时,将重力补偿向量gravity叠加到关节力矩中。本教程中机器人的重力已在场景配置中关闭(disable_gravity=True),因此不启用。

冗余机械臂的零空间控制

零空间(null-space)是关节空间中不影响任务空间坐标的子空间。若不加以控制,冗余关节会"飘浮"(甚至逼近关节限位)。有两种选择:

  • nullspace_control="none"(默认):不施加零空间控制;
  • nullspace_control="position":集成零空间 PD 控制器,把关节吸引到期望位置而不影响任务空间。

零空间行为由nullspace_stiffness(默认 10.0)与nullspace_damping_ratio(默认 1.0)定义。理论上的零空间与任务空间完全解耦,仅在inertial_dynamics_decoupling=Truepartial_inertial_dynamics_decoupling=False时成立(此时使用动力学一致的伪逆,否则退化为 Moore-Penrose 伪逆,见operational_space.py第 498-505 行)。

本教程设置nullspace_control="position",将关节目标设为关节限位中心

joint_centers = torch.mean(robot.data.soft_joint_pos_limits.torch[:, arm_joint_ids, :], dim=-1)

本教程的完整配置

osc_cfg = OperationalSpaceControllerCfg( target_types=["pose_abs", "wrench_abs"], impedance_mode="variable_kp", inertial_dynamics_decoupling=True, partial_inertial_dynamics_decoupling=False, gravity_compensation=False, motion_damping_ratio_task=1.0, contact_wrench_stiffness_task=[0.0, 0.0, 0.1, 0.0, 0.0, 0.0], motion_control_axes_task=[1, 1, 0, 1, 1, 1], contact_wrench_control_axes_task=[0, 0, 1, 0, 0, 0], nullspace_control="position", ) osc = OperationalSpaceController(osc_cfg, num_envs=scene.num_envs, device=sim.device)

控制器实例化需要三个参数:配置、环境数num_envs与计算设备device。所有配置字段的完整说明见 operational_space_cfg.py。

更新机器人状态:向控制器喂入动力学量

OperationalSpaceController纯计算类,不持有机器人内部状态,需要调用方在每个控制周期提供(全部在机器人基座/root 坐标系下):

  • 末端雅可比矩阵jacobian_b(root 系,形状num_envs × 6 × num_DoF);
  • 关节空间质量/惯性矩阵mass_matrixnum_envs × num_DoF × num_DoF);
  • 重力补偿向量gravitynum_envs × num_DoF);
  • 末端位姿current_ee_pose_bnum_envs × 7,位置 + 四元数);
  • 末端速度current_ee_vel_bnum_envs × 6,线速度 + 角速度);
  • 末端接触力current_ee_force_bnum_envs × 3);
  • 关节位置/速度current_joint_poscurrent_joint_vel
  • (可选)零空间关节目标位置nullspace_joint_pos_target与重力向量。

示例脚本中的update_states()函数负责从 Isaac Lab 的ArticulationContactSensor提取这些量,关键步骤包括:

  1. Jacobian 提取与坐标系转换:取body_link_jacobian_w中末端连杆对应的块(注意固定基座机器人的基座自由度偏移num_base_dofs),再用matrix_from_quat(quat_inv(root_quat_w))将旋转部分与世界坐标下的 Jacobian 从世界系旋转到 root 系;
  2. 质量矩阵与重力向量:从robot.data.mass_matrixrobot.data.gravity_compensation_forces中按臂关节索引切片;
  3. 末端位姿/速度:用subtract_frame_transforms将世界系末端位姿转换到 root 系;速度用quat_apply_inverse把"末端相对 root 的相对速度"从世界系旋转到 root 系;
  4. 接触力:更新接触传感器后,对历史窗口(history_length=2)内的净接触力取平均再取三面最大值,得到平滑的末端接触力(脚本注释说明这是为了测试所做的简化处理)。

设置命令与计算关节力矩:控制循环三要素

OSC 将"设置期望命令"与"计算关节指令"分离,这是使用该控制器的关键编程约定。

1. 组装并转换目标命令

命令向量是一个形状为(num_envs, action_dim)的张量,内容按target_types顺序拼接。本教程的impedance_mode="variable_kp",因此命令为pose_abs(7) + wrench_abs(6) + kp(6) = 19维。每组目标定义为:

ee_target_set = torch.cat([ee_goal_pose_set_tilted_b, ee_goal_wrench_set_tilted_task, kp_set_task], dim=-1)

期望力已在任务帧中定义(ee_goal_wrench_set_tilted_task,仅 z 轴为 10 N),而期望位姿定义在基座系。convert_to_task_frame()subtract_frame_transforms把位姿目标从基座系转换到任务帧(即目标位姿本身作为任务参考系),命令全部统一到任务帧:

command, task_frame_pose_b = convert_to_task_frame(osc, command=command, ee_target_pose_b=ee_target_pose_b)

2. 设置 OSC 命令

将任务帧下的命令向量、末端当前位姿(基座系)与任务参考系位姿(基座系)一起交给set_command。内部计算在基座系完成,因此需要任务帧相对基座的位姿用于坐标变换(包括增益矩阵、选择矩阵的旋转变换与期望力/力矩的传递,见operational_space.py第 293-345 行):

osc.set_command(command=command, current_ee_pose_b=ee_pose_b, current_task_frame_pose_b=task_frame_pose_b)

3. 计算关节力矩并施加

compute()在内部依次完成:运动控制(末端位姿误差 + 弹簧阻尼动力学 → 惯性解耦 → 经选择矩阵与 Jacobian 转置映射到关节力矩)、力控制(开环或带前馈的闭环力修正同样映射到关节力矩)、重力补偿叠加、零空间控制叠加,最终返回(num_envs, num_DoF)的关节力矩:

joint_efforts = osc.compute( jacobian_b=jacobian_b, current_ee_pose_b=ee_pose_b, current_ee_vel_b=ee_vel_b, current_ee_force_b=ee_force_b, mass_matrix=mass_matrix, gravity=gravity, current_joint_pos=joint_pos, current_joint_vel=joint_vel, nullspace_joint_pos_target=joint_centers, ) # 施加关节力矩(仅作用于臂关节),并写回仿真 robot.set_joint_effort_target_index(target=joint_efforts, joint_ids=arm_joint_ids) robot.write_data_to_sim()

重置与目标切换

仿真每 500 步重置一次:将关节状态恢复默认值、力矩清零、重置接触传感器,随后重新计算目标命令并调用osc.reset()清空内部目标缓存,再重新set_command。目标索引通过current_goal_idx在三个目标间循环(next_goal_idx = (current_goal_idx + 1) % len(ee_target_set))。

从控制器到动作项:OSC 在 RL 环境中的封装

除脚本级使用外,Isaac Lab 还将 OSC 封装为 Manager-based RL 环境的动作项(Action Term),配置类为 OperationalSpaceControllerActionCfg(实现位于task_space_actions.pyOperationalSpaceControllerAction)。其关键字段:

  • joint_names:动作映射到的关节列表(支持正则);
  • body_name:执行运动/力控制的末端连杆/坐标系名称;
  • body_offset:末端坐标系相对父刚体的偏移(很多机器人的末端是虚构坐标系,如 Franka 的末端相对panda_hand存在偏移);
  • task_frame_rel_path:指定任务参考系对应的RigidObject路径(如一面墙);
  • controller_cfg:内嵌的OperationalSpaceControllerCfg
  • position_scale/orientation_scale/wrench_scale/stiffness_scale/damping_ratio_scale:对各类命令的缩放因子;
  • nullspace_joint_pos_target:零空间关节目标策略,取"none"/"zero"/"default"/"center"(仅当nullspace_control="position"时生效)。

验证与测试:仓库中的 OSC 覆盖矩阵

仓库测试 test_operational_space.py 系统验证了 OSC 的各种组合模式,可作为理解各配置项行为的最佳参照:

  • test_franka_pose_abs_without_inertial_decoupling:固定阻抗 + 无惯性解耦的绝对位姿控制;
  • test_franka_pose_abs_with_partial_inertial_decoupling:部分惯性解耦;
  • test_franka_pose_abs_fixed_impedance_with_gravity_compensation:启用重力补偿(机器人不关闭重力);
  • test_franka_pose_abs/test_franka_pose_rel:绝对/相对位姿 + 完整惯性解耦;
  • test_franka_pose_abs_variable_impedancevariable阻抗模式(命令含 kp 与阻尼比);
  • test_franka_wrench_abs_open_loop/test_franka_wrench_abs_closed_loop:纯力控制的开环与闭环模式;
  • test_franka_hybrid_decoupled_motiontest_franka_hybrid_variable_kp_impedance:位姿 + 力混合控制(固定阻抗 / variable_kp);
  • test_franka_taskframe_pose_abstest_franka_taskframe_pose_reltest_franka_taskframe_hybrid:以任务参考系(非 root 系)定义目标的位姿控制与混合控制。

例如混合控制测试使用的配置与教程配置高度一致(target_types=["pose_abs", "wrench_abs"]contact_wrench_stiffness_task=[0.1, 0, 0, 0, 0, 0]、互补的控制轴),进一步印证了"运动轴与力轴互补 + 任务帧定义"这一 OSC 标准用法。

小结

本文围绕run_osc.py完整演示了 Isaac Lab 操作空间控制器的使用闭环:场景搭建 →OperationalSpaceControllerCfg配置(目标类型、控制轴、阻抗模式、惯性解耦、零空间控制)→ 机器人状态提取(Jacobian、质量矩阵、接触力)→ 任务帧命令转换 →set_command/compute力矩输出。关键要点可归纳为:

  1. 运动与力控制通过互补的motion_control_axes_taskcontact_wrench_control_axes_task划分任务空间六轴;
  2. 任务参考系可自由选择(默认基座系),配合current_task_frame_pose_b传入即可简化目标定义;
  3. 惯性解耦提升快速运动精度,且是零空间与任务空间理论解耦的前提;
  4. 接触力闭环只作用于线性力方向(传感器测不到接触力矩);
  5. 冗余机械臂务必规划零空间控制策略,避免关节失控飘移。

进一步阅读可参考仓库中的 差分 IK 控制器教程 对比两类任务空间控制器的差异,以及 任务空间动作项封装 了解如何将 OSC 接入端到端强化学习训练。

【免费下载链接】IsaacLabUnified framework for robot learning with multi-physics/renderer support项目地址: https://gitcode.com/GitHub_Trending/is/IsaacLab

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询