技巧和故障排除#

备注

以下列出了我们在日常工作流程中使用的一些常见技巧和故障排除方法。请同时查看 Omniverse 上的故障排除页面 以获取更多帮助。

从模拟器的内部日志中检查#

在从独立脚本运行模拟器时,它会将警告和错误记录到终端。同时,它还会将内部消息记录到文件中。这些对于调试和了解模拟器的内部状态很有帮助。根据您的系统,日志文件可以在列出的位置找到 这里

要获取日志文件的确切位置,您需要检查运行独立脚本时终端输出的前几行。日志文件位置会在终端输出开始时打印出来。例如:

[INFO] Using python from: /home/${USER}/git/IsaacLab/_isaac_sim/python.sh
...
Passing the following args to the base kit application:  []
Loading user config located at: '.../data/Kit/Isaac-Sim/2023.1/user.config.json'
[Info] [carb] Logging to file: '.../logs/Kit/Isaac-Sim/2023.1/kit_20240328_183346.log'

在上面的示例中,日志文件位于 .../logs/Kit/Isaac-Sim/2023.1/kit_20240328_183346.log... 是用户日志目录的路径。日志文件名为 kit_20240328_183346.log

您可以打开此文件以查看模拟器的内部日志。此外,在报告问题时,请包括此日志文件以帮助我们调试问题。

更改模拟器的日志记录通道级别#

默认情况下,模拟器在终端上记录 WARN 级别及以上的消息。您可以更改日志通道级别以获得更详细的日志。日志通道级别可以通过 Omniverse 的日志系统进行设置。

要获取更详细的日志,您可以使用以下标志运行应用程序:

  • --info: 此标志记录 INFO 级别及以上的消息。

  • --verbose: 此标志记录 VERBOSE 级别及以上的消息。

例如,要以详细记录方式运行独立脚本,可以使用以下命令:

# Run the standalone script with info logging
./isaaclab.sh -p source/standalone/tutorials/00_sim/create_empty.py --headless --info

要进行更精细的控制,您可以通过 omni.log 模块修改日志通道。有关更多信息,请参阅其 文档

使用 CPU 缩放调度程序以获取性能#

默认情况下,在许多系统上,CPU 频率调度程序设置为“省电”模式,它将 CPU 设置为最低静态频率。为了提高最大性能,我们建议将 CPU 频率调度程序设置为“性能”模式。有关更多详细信息,请查看这个链接 这里

警告

我们建议不要在散热不佳的系统上(如笔记本电脑)将调度程序设置为“性能”模式,因为这可能会导致系统过热。

  • 查看每个 CPU 的现有 scaling_governor 值:

    cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
    
  • 将每个 CPU 的调度程序更改为“性能”模式:

    echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
    

观察模拟开始时的长加载时间#

第一次运行模拟器时,启动需要很长时间。这是因为模拟器正在编译着色器和加载资源。后续运行应该会更快启动,但可能仍需要一些时间。

请注意,一旦 Isaac Sim 应用加载,环境创建时间可能会随着环境数量线性增加。如果运行数千个环境或每个环境包含较多资产,则请期待更长的加载时间。我们一直在努力改进所需的时间。

当一个 Isaac Sim 实例已经在运行时,在不同进程中启动另一个 Isaac Sim 实例可能会在首次启动时出现挂起的情况。请耐心等待一段时间,因为第二个进程启动时间会较长,由于着色器编译较慢。

在 GPU 上运行模拟时收到 “PhysX error”#

使用 GPU pipeline 时,用于物理模拟的缓冲区仅在模拟开始时在 GPU 上分配一次。这意味着它们在场景中的碰撞或对象数量发生变化时不会动态增长。如果场景中的碰撞或对象数量超过缓冲区的大小,模拟将失败,并显示如下错误:

PhysX error: the application need to increase the PxgDynamicsMemoryConfig::foundLostPairsCapacity
parameter to 3072, otherwise the simulation will miss interactions

在这种情况下,您需要增加传递给 SimulationContext 类的缓冲区大小。可以通过设置 PhysxCfg 类中的 gpu_found_lost_pairs_capacity 参数来增加缓冲区的大小。例如,为了将缓冲区的大小增加到 4096,您可以使用以下代码:

import omni.isaac.lab.sim as sim_utils

sim_cfg = sim_utils.SimulationConfig()
sim_cfg.physx.gpu_found_lost_pairs_capacity = 4096
sim = SimulationContext(sim_params=sim_cfg)

请查看 SimulationCfg 的文档,了解可用于配置模拟的参数的更多详细信息。

预防模拟器中的内存泄漏#

当在 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 对象可以被正确地垃圾回收。

通过遵循这种模式,您可以防止内存泄漏,并保持更高效和稳定的模拟。

理解崩溃产生的错误日志#

许多情况下,模拟器由于实现中的错误而崩溃。这会导致终端输出异常,其中一些异常来自 Python 解释器调用 __del__() 析构函数模拟应用程序。通常看起来如下:

...

[INFO]: Completed setting up the environment...

Traceback (most recent call last):
File "source/standalone/workflows/robomimic/collect_demonstrations.py", line 166, in <module>
    main()
File "source/standalone/workflows/robomimic/collect_demonstrations.py", line 126, in main
    actions = pre_process_actions(delta_pose, gripper_command)
File "source/standalone/workflows/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 "../IsaacLab/_isaac_sim/kit/extscore/omni.kit.viewport.registry/omni/kit/viewport/registry/registry.py", line 103, in __del__
File "../IsaacLab/_isaac_sim/kit/extscore/omni.kit.viewport.registry/omni/kit/viewport/registry/registry.py", line 98, in destroy
TypeError: 'NoneType' object is not callable
Exception ignored in: <function _make_registry.<locals>._Registry.__del__ at 0x7f94ac097f80>
Traceback (most recent call last):
File "../IsaacLab/_isaac_sim/kit/extscore/omni.kit.viewport.registry/omni/kit/viewport/registry/registry.py", line 103, in __del__
File "../IsaacLab/_isaac_sim/kit/extscore/omni.kit.viewport.registry/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 "../IsaacLab/_isaac_sim/kit/kernel/py/omni/kit/app/_impl/__init__.py", line 114, in __del__
AttributeError: 'NoneType' object has no attribute 'get_settings'
Exception ignored in: <function RegisteredActions.__del__ at 0x7f935f5cae60>
Traceback (most recent call last):
File "../IsaacLab/_isaac_sim/extscache/omni.kit.viewport.menubar.lighting-104.0.7/omni/kit/viewport/menubar/lighting/actions.py", line 345, in __del__
File "../IsaacLab/_isaac_sim/extscache/omni.kit.viewport.menubar.lighting-104.0.7/omni/kit/viewport/menubar/lighting/actions.py", line 350, in destroy
TypeError: 'NoneType' object is not callable
2022-12-02 15:41:54 [18,514ms] [Warning] [carb.audio.context] 1 contexts were leaked
../IsaacLab/_isaac_sim/python.sh: line 41: 414372 Segmentation fault      (core dumped) $python_exe "$@" $args
There was an error running python

这是使用 Isaac Sim 模拟器运行独立脚本时出现的已知错误。请向上滚动异常抛出的 registry 以查看实际错误日志。

在上述情况中,实际错误是:

Traceback (most recent call last):
File "source/standalone/workflows/robomimic/tools/collect_demonstrations.py", line 166, in <module>
    main()
File "source/standalone/workflows/robomimic/tools/collect_demonstrations.py", line 126, in main
    actions = pre_process_actions(delta_pose, gripper_command)
File "source/standalone/workflows/robomimic/tools/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