技巧和故障排除#
以下提供安装、启动、仿真和训练问题的解决方法。Kit 专用问题见 Omniverse 故障排查指南。
安装与导入#
无法导入 Isaac Lab 包#
如果 ModuleNotFoundError 指向某个 Isaac Lab 包,几乎总是因为命令没有在 Isaac Lab 环境中运行,而非安装时漏装了该包。大多数包在安装时根本无法排除。
缺失的模块 |
含义 |
|---|---|
|
核心包由 |
|
可选集成。根据工作流选择 |
|
|
|
Isaac Sim 本身,它从不会被隐式安装。参阅 未安装 Isaac Sim 。 |
先在仓库根目录检查 uv 管理的环境能否找到该包:
uv run python -c "import isaaclab_tasks; print('ok')"
如果检查成功,但您自己的命令仍失败,说明该命令使用了其他解释器。请从仓库根目录通过 uv run 重新运行:
uv run python scripts/environments/random_agent.py --task Isaac-Cartpole --num_envs 4
如果通过 uv run 也无法导入,请按对应工作流的源代码安装文档重新创建环境。
备注
ovrtx、rlinf 和 tetrahedralization 等可选依赖需显式选择 extra,例如 uv run --extra ovrtx isaaclab train ...。
未安装 Isaac Sim#
ModuleNotFoundError: No module named 'isaacsim' 表示启动了需要 Isaac Sim 的脚本,但环境中没有安装它。可以安装 Isaac Sim:
uv sync --extra isaacsim
也可以运行基于 Newton 的任务,这类任务不需要 Kit:
uv run isaaclab train --task Isaac-Cartpole physics=newton_mjwarp --visualizer newton_gl
全部 physics= 和 renderer= 选择器,以及各自所需 extra,见 快速入门。
安装时出现依赖版本冲突#
使用 pip 或 uv 安装时,包管理器可能显示类似 <package> requires <version>, but <other-package> requires <version> 的依赖警告,表示某个 Isaac Lab 包、Isaac Sim 包或第三方包声明了不兼容的版本约束。常见例子是 isaaclab 、 isaacsim-kernel 、 isaacsim-core 、 nvidia-srl-usd 和 moviepy 之间报告的 coverage 、 packaging 、 numpy 或 Pillow 版本约束。
如果安装命令成功完成,这些提示通常不会造成问题。它们往往说明包元数据中的约束比 Isaac Sim 附带并经过测试的版本更严格或更陈旧。建议从全新的虚拟环境开始,并使用 Isaac Lab 文档中的安装命令。如果依赖解析器以 No solution found 中止,或安装后运行时仍有模块缺失,请重新创建环境,并先安装文档指定版本的 Isaac Sim,再安装 Isaac Lab。
GLIBC 版本过旧#
Isaac Sim 的 pip 包要求 GLIBC 2.35 或更新版本。使用 ldd --version 检查版本。Ubuntu 22.04 及更新版本满足要求。较旧的发行版应改用 Isaac Sim 的 二进制安装 方式。
PhysX 后端#
以下条目适用于 physics=isaacsim_physx 和 physics=ovphysx 后端。
新导入的机器人仿真不稳定#
当将新机器人导入到 Isaac Lab 或设置新环境时,如果资产没有通过合理的仿真参数进行调优,仿真不稳定性往往会出现。在强化学习场景中,这通常会导致由于仿真中的无效状态,NaN 在学习流程中传播。
如果发生这种情况,我们建议参考 关节和机器人仿真稳定性指南 ,该指南推荐了各种仿真参数和最佳实践,以实现机器人仿真中的更好稳定性。
使用 OmniPVD 录制仿真#
Omniverse PhysX 可视化调试器 可以录制 PhysX 仿真数据,通常有助于诊断仿真问题和调试。
要在 Isaac Lab 中启用 OmniPVD 捕获,请在启动 Isaac Lab 进程的命令行中添加相应的 Kit 参数:
uv run --extra isaacsim isaaclab demo zoo --physics isaacsim_physx --viz kit --kit_args "--/persistent/physics/omniPvdOvdRecordingDirectory=/tmp/ --/physics/omniPvdOutputEnabled=true"
GPU 缓冲区容量错误#
使用 GPU 流水线时,物理仿真的缓冲区只在仿真开始时于 GPU 上分配一次,不会随着场景中的碰撞或对象数量变化而动态扩容。如果场景超出某个缓冲区的容量,仿真就会失败,并报告如下错误:
PhysX error: the application need to increase the PxgDynamicsMemoryConfig::foundLostPairsCapacity
parameter to 3072, otherwise the simulation will miss interactions
请增大当前后端物理配置中对应字段的值。字段名与 PhysX 参数一致;对于上述错误,对应的是 gpu_found_lost_pairs_capacity :
import isaaclab.sim as sim_utils
from isaaclab.sim import SimulationContext
from isaaclab_physx.physics import PhysxCfg
sim_cfg = sim_utils.SimulationCfg(physics=PhysxCfg(gpu_found_lost_pairs_capacity=2**22))
sim = SimulationContext(sim_cfg)
ovphysx 后端的 OvPhysxCfg 中也有同名字段。在任务中,应通过任务的预设进行设置,让两个 PhysX 后端保持一致:
from isaaclab.physics import PhysxAutoCfg
from isaaclab.utils import configclass
from isaaclab_ov.physics import OvPhysxCfg
from isaaclab_physx.physics import PhysxCfg
from isaaclab_tasks.utils import PresetCfg
@configclass
class MyPhysicsCfg(PresetCfg):
isaacsim_physx = PhysxCfg(gpu_found_lost_pairs_capacity=2**22)
ovphysx = OvPhysxCfg(gpu_found_lost_pairs_capacity=2**22)
physx = PhysxAutoCfg(isaacsim_physx=isaacsim_physx, ovphysx=ovphysx)
默认容量已经较大,因此只有在 PhysX 明确要求时才应增大。其他仿真配置参数见 SimulationCfg 。
Newton 后端#
以下条目适用于 physics=newton_mjwarp 和 physics=newton_kamino 后端。
仿真或训练速度低于预期#
调整物理或渲染设置之前,先对有代表性的运行过程进行性能分析。 Nsight Systems 性能分析指南 可以帮助区分物理计算、渲染、环境代码和策略推理各自的耗时。
对于 PhysX 工作负载,请检查以下常见原因:
不必要的可视化: 命令未通过
--viz选择可视化器时,不启动查看器,即使配置的SimulationCfg.visualizer_cfgs列出了可视化器。因此可去掉--viz。过多的碰撞计算: 避免重复或重叠的碰撞几何体,在满足所需精度的前提下使用最简单的碰撞体。
GPU 碰撞体回退: 如果警告提示凸网格无法预处理为 GPU 兼容形式,它的碰撞计算会回退到 CPU。尽可能用基本几何体或包围盒近似替代该碰撞体。静态三角网格也是一种选择,但仅适用于不属于动态刚体的几何体。
更全面的调优建议,包括 CPU/GPU 选择、求解器设置、渲染、传感器及 CPU 配置,见持续维护的上游指南:
Newton 专用的性能设置与求解器参数,见 Newton 物理文档 。
关节在 PhysX 中能被驱动,在基于 Newton 的后端中却不能#
Newton 会在构造求解器之前,为 Isaac Lab 执行器配置所覆盖的关节确定目标模式。对于 ImplicitActuatorCfg ,仅有刚度、仅有阻尼、两种增益均有以及两种增益均为零的配置,分别对应位置、速度、位置与速度组合、驱动力模式。 None 表示保留从 USD 导入的对应增益。显式执行器配置采用驱动力模式,因为 Isaac Lab 会直接计算其驱动力。
未配置 Isaac Lab 执行器的关节保留导入的 USD 目标模式。因此,零增益 USD 驱动不再需要仅为让已配置关节在 Newton 中动作而设置 ensure_drives_exist。对于需要独立于 Isaac Lab 执行器配置创建占位驱动的工作流,该选项仍可使用。详情见 各物理后端的关节驱动。
渲染器与可视化器#
OVRTX 的 libusd_tf 崩溃或 USD 符号冲突#
如果崩溃涉及 libusd_tf-*.so ,并出现 USD 版本冲突(例如 pxrInternal_v0_25_5 与 pxrInternal_v0_25_11 ):
确认
LD_PRELOAD指向 ovrtx 的libcarb.so,并通过uv sync --extra ovrtx安装 OVRTX 运行时,见 模块化安装。确保同一环境中 没有 安装
isaacsim/omniverse-kit,它们附带的 USD 库会与 ovrtx 的库冲突。
Newton 可视化窗口没有出现#
Newton 交互式查看器需要 imgui-bundle ,它是 Isaac Lab 的基本依赖。在 uv 管理的环境中,该包始终存在,因此窗口没有出现通常是显示环境有问题,而非缺少软件包。如果运行环境并非按 Isaac Lab 的依赖集创建,请显式安装:
uv pip install imgui-bundle
viser 可视化器提供 Web 界面,不会打开窗口#
--visualizer viser 不会打开原生窗口。请在终端中查看服务地址;默认端口为 8080 ,可通过 port 配置。 viser 包包含在 viser 额外依赖中。
直播与 WebRTC#
设置 LIVESTREAM=1 或 LIVESTREAM=2 时出现 NVST_R_BUSY / NVST_R_INTERNAL_ERROR#
设置 LIVESTREAM=1 (公网)或 LIVESTREAM=2 (私网)时, KitLauncher 会固定使用 TCP 端口 49100 进行 WebRTC 信令通信。如果之前的直播进程仍占用该端口,新会话就无法启动,并报错:
[Error] [omni.kit.livestream.webrtc.plugin] NVST Error: NVST_R_BUSY
也可能在绑定信令套接字时出现较少见的 NVST_R_INTERNAL_ERROR 。找到占用端口 49100 的进程,确认可以安全停止后,终止它并重新启动:
ss -tlnp | grep 49100 # or: lsof -i :49100
kill $(lsof -ti tcp:49100) # SIGTERM first
kill -9 $(lsof -ti tcp:49100) # only if it is still running
netstat -ano | findstr ":49100"
taskkill /PID <pid> /F
在 Windows 上, netstat 会在匹配行的最后一列显示占用端口的 PID;用它替换 <pid> 。
分布式训练#
多 GPU 训练中的 NCCL 错误#
在某些 Linux 多 GPU 系统上,分布式训练可能会失败,并由 ProcessGroupNCCL 报出 CUDA error: an illegal memory access was encountered 。有关已记录的 NCCL 变通方法,请参见 NCCL 挂起和错误 。
调试与诊断#
从仿真器的内部日志中检查#
通过独立脚本运行基于 Kit 的工作流时,仿真器会把警告和错误输出到终端,同时将内部消息写入日志文件。这些信息有助于调试和了解仿真器的内部状态。日志位置因系统而异,详见 常用路径 。
要确定日志文件的具体位置,请查看运行独立脚本时终端输出的前几行。日志路径会在输出开头以如下形式显示:
[Info] [carb] Logging to file: '.../logs/Kit/Isaac-Sim/<version>/kit_<timestamp>.log'
可以打开该文件查看仿真器的内部日志。报告问题时,请附上日志文件,以帮助我们排查。
更改仿真器的日志记录通道级别#
默认情况下,仿真器在终端上记录 WARN 级别及以上的消息。您可以更改日志通道级别以获得更详细的日志。日志通道级别可以通过 Omniverse 的日志系统进行设置。
要获取更详细的日志,您可以使用以下标志运行应用程序:
--info: 此标志记录INFO级别及以上的消息。--verbose: 此标志记录VERBOSE级别及以上的消息。
例如,要以详细记录方式运行独立脚本,可以使用以下命令:
# Run the standalone script with info logging
uv run python scripts/tutorials/00_sim/create_empty.py --info
要进行更精细的控制,您可以通过 logger 模块修改日志通道。有关更多信息,请参阅其 文档 。
理解崩溃产生的错误日志#
基于 Kit 的脚本崩溃时,终端往往会出现大量异常,其中许多来自仿真应用退出时 Python 解释器调用的 __del__() 析构函数,例如:
...
[INFO]: Completed setting up the environment...
Traceback (most recent call last):
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 166, in <module>
main()
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 126, in main
actions = pre_process_actions(delta_pose, gripper_command)
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 57, in pre_process_actions
return torch.concat([delta_pose, gripper_vel], dim=1)
TypeError: expected Tensor as element 1 in argument 0, but got int
Exception ignored in: <function _make_registry.<locals>._Registry.__del__ at 0x7f94ac097f80>
Traceback (most recent call last):
File ".../omni/kit/viewport/registry/registry.py", line 103, in __del__
File ".../omni/kit/viewport/registry/registry.py", line 98, in destroy
TypeError: 'NoneType' object is not callable
Exception ignored in: <function SettingChangeSubscription.__del__ at 0x7fa2ea173e60>
Traceback (most recent call last):
File ".../omni/kit/app/_impl/__init__.py", line 114, in __del__
AttributeError: 'NoneType' object has no attribute 'get_settings'
[Warning] [carb.audio.context] 1 contexts were leaked
Segmentation fault (core dumped)
There was an error running python
退出过程中的这些异常并非真正的故障原因。请向上查看,找到 registry 和 Exception ignored in 代码块 之前 的实际错误;在上面的示例中是:
Traceback (most recent call last):
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 166, in <module>
main()
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 126, in main
actions = pre_process_actions(delta_pose, gripper_command)
File "scripts/imitation_learning/robomimic/collect_demonstrations.py", line 57, in pre_process_actions
return torch.concat([delta_pose, gripper_vel], dim=1)
TypeError: expected Tensor as element 1 in argument 0, but got int
观察仿真开始时的长加载时间#
第一次运行仿真器时,启动需要很长时间。这是因为仿真器正在编译着色器和加载资源。后续运行应该会更快启动,但可能仍需要一些时间。
请注意,一旦 Isaac Sim 应用加载,环境创建时间可能会随着环境数量线性增加。如果运行数千个环境或每个环境包含较多资产,则请期待更长的加载时间。我们一直在努力改进所需的时间。
当一个 Isaac Sim 实例已经在运行时,在不同进程中启动另一个 Isaac Sim 实例可能会在首次启动时出现挂起的情况。请耐心等待一段时间,因为第二个进程启动时间会较长,由于着色器编译较慢。
预防仿真器中的内存泄漏#
当在 Python 对象中注册 C++ 回调时,Isaac Sim 仿真器中可能会发生内存泄漏。当类中的回调函数与其关联的 Python 对象保持引用时会发生这种情况。结果是,Python 的垃圾回收无法回收与这些对象相关联的内存,从而阻止了相应的 C++ 对象被销毁。随着时间的推移,这可能导致内存泄漏和资源使用量增加。
为了防止 Isaac Sim 仿真器中的内存泄漏,务必在向仿真器注册回调时使用弱引用。这可以确保在不再需要时可以对 Python 对象进行垃圾回收,从而避免内存泄漏。Python 标准库中的 weakref 模块可用于此目的。
例如,考虑一个具有需要向仿真器注册的回调函数 on_event_callback 的类。如果在传递回调时对 MyClass 对象使用强引用,则会增加 MyClass 对象的引用计数。这会防止在不再需要时对 MyClass 对象进行垃圾回收,即不会调用 __del__ 析构函数。
import omni.kit
class MyClass:
def __init__(self):
app_interface = omni.kit.app.get_app_interface()
self._handle = app_interface.get_post_update_event_stream().create_subscription_to_pop(
self.on_event_callback
)
def __del__(self):
self._handle.unsubscribe()
self._handle = None
def on_event_callback(self, event):
# do something with the message
要解决此问题,关键是在注册回调时使用弱引用。虽然这种方法会使代码变得冗长,但它确保在不再使用时可以对 MyClass 对象进行垃圾回收。以下是修改后的代码:
import omni.kit
import weakref
class MyClass:
def __init__(self):
app_interface = omni.kit.app.get_app_interface()
self._handle = app_interface.get_post_update_event_stream().create_subscription_to_pop(
lambda event, obj=weakref.proxy(self): obj.on_event_callback(event)
)
def __del__(self):
self._handle.unsubscribe()
self._handle = None
def on_event_callback(self, event):
# do something with the message
在这个修改后的代码中,当注册回调时使用弱引用 weakref.proxy(self) ,使得 MyClass 对象可以被正确地垃圾回收。
通过遵循这种模式,您可以防止内存泄漏,并保持更高效和稳定的仿真。