使用 Docker 运行示例#
从 Isaac Lab 仓库的根目录开始, docker
目录包含所有与 Docker 相关的文件。这些文件包括三个文件( Dockerfile , docker-compose.yaml , .env ),这些文件由 Docker 使用,以及我们用来与它们交互的附加脚本, container.sh 。
在本教程中,我们将学习如何使用 Isaac Lab Docker 容器进行开发。有关 Docker 设置的详细说明,包括安装和获取对 Isaac Sim 图像的访问权限,请参考 Docker 指南 。有关 Docker 的一般说明,请参阅 官方文档 。
构建容器#
从 Isaac Lab 仓库的根目录构建 Isaac Lab 容器,我们将运行以下命令:
python docker/container.py start
终端将首先拉取基础 IsaacSim 镜像,在其上构建 Isaac Lab 镜像的附加层,然后运行 Isaac Lab 容器。首次构建可能需要几分钟,但后续运行时间会更短,因为 Docker 的缓存可防止重复工作。如果在终端上运行命令 docker container ls
,输出将列出当前系统上运行的容器。如果一切设置正确,将会出现一个名为 NAME
isaac-lab-base 的容器,类似于下面的内容:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
483d1d5e2def isaac-lab-base "bash" 30 seconds ago Up 30 seconds isaac-lab-base
容器启动后,我们可以从终端进入其中。
python docker/container.py enter
进入 Isaac Lab 容器后,我们以超级用户 root
的身份在终端中。这个环境包含一个 Isaac Lab 仓库的副本,但也可以访问 Isaac Sim 的目录和库。我们可以使用一些很方便的别名在这个环境中运行实验,这些别名已经放入了超级用户 root
的 .bashrc 中。例如,我们可以通过输入别名 isaaclab
来任意地从任何地方使用 isaaclab.sh 脚本。
除了在容器中,我们还将 IsaacLab/source
目录从主机机器进行了 绑定挂载 。这意味着,如果我们在主机机器上的编辑器中修改了该目录下的文件,不需要重新构建 Docker 镜像,容器中的更改会立即反映出来。
现在,我们将在容器中运行一个示例脚本,以演示如何从 Isaac Lab Docker 容器中提取输出。
代码#
该教程对应的是 IsaacLab/source/standalone/tutorials/00_sim
目录中的 log_time.py
脚本。
log_time.py 的代码
1# Copyright (c) 2022-2024, The Isaac Lab Project Developers.
2# All rights reserved.
3#
4# SPDX-License-Identifier: BSD-3-Clause
5
6"""
7This script demonstrates how to generate log outputs while the simulation plays.
8It accompanies the tutorial on docker usage.
9
10.. code-block:: bash
11
12 # Usage
13 ./isaaclab.sh -p source/standalone/tutorials/00_sim/log_time.py
14
15"""
16
17"""Launch Isaac Sim Simulator first."""
18
19
20import argparse
21import os
22
23from omni.isaac.lab.app import AppLauncher
24
25# create argparser
26parser = argparse.ArgumentParser(description="Tutorial on creating logs from within the docker container.")
27# append AppLauncher cli args
28AppLauncher.add_app_launcher_args(parser)
29# parse the arguments
30args_cli = parser.parse_args()
31# launch omniverse app
32app_launcher = AppLauncher(args_cli)
33simulation_app = app_launcher.app
34
35"""Rest everything follows."""
36
37from omni.isaac.lab.sim import SimulationCfg, SimulationContext
38
39
40def main():
41 """Main function."""
42 # Specify that the logs must be in logs/docker_tutorial
43 log_dir_path = os.path.join("logs")
44 if not os.path.isdir(log_dir_path):
45 os.mkdir(log_dir_path)
46 # In the container, the absolute path will be
47 # /workspace/isaaclab/logs/docker_tutorial, because
48 # all python execution is done through /workspace/isaaclab/isaaclab.sh
49 # and the calling process' path will be /workspace/isaaclab
50 log_dir_path = os.path.abspath(os.path.join(log_dir_path, "docker_tutorial"))
51 if not os.path.isdir(log_dir_path):
52 os.mkdir(log_dir_path)
53 print(f"[INFO] Logging experiment to directory: {log_dir_path}")
54
55 # Initialize the simulation context
56 sim_cfg = SimulationCfg(dt=0.01)
57 sim = SimulationContext(sim_cfg)
58 # Set main camera
59 sim.set_camera_view([2.5, 2.5, 2.5], [0.0, 0.0, 0.0])
60
61 # Play the simulator
62 sim.reset()
63 # Now we are ready!
64 print("[INFO]: Setup complete...")
65
66 # Prepare to count sim_time
67 sim_dt = sim.get_physics_dt()
68 sim_time = 0.0
69
70 # Open logging file
71 with open(os.path.join(log_dir_path, "log.txt"), "w") as log_file:
72 # Simulate physics
73 while simulation_app.is_running():
74 log_file.write(f"{sim_time}" + "\n")
75 # perform step
76 sim.step()
77 sim_time += sim_dt
78
79
80if __name__ == "__main__":
81 # run the main function
82 main()
83 # close sim app
84 simulation_app.close()
代码说明#
Isaac Lab Docker 容器具有几个 数据卷 ,以便在主机计算机和容器之间实现持久存储。其中一个数据卷是 /workspace/isaaclab/logs
目录。 log_time.py
脚本指定该目录作为应该写入 log.txt
的位置:
# Specify that the logs must be in logs/docker_tutorial
log_dir_path = os.path.join("logs")
if not os.path.isdir(log_dir_path):
os.mkdir(log_dir_path)
# In the container, the absolute path will be
# /workspace/isaaclab/logs/docker_tutorial, because
# all python execution is done through /workspace/isaaclab/isaaclab.sh
# and the calling process' path will be /workspace/isaaclab
log_dir_path = os.path.abspath(os.path.join(log_dir_path, "docker_tutorial"))
if not os.path.isdir(log_dir_path):
os.mkdir(log_dir_path)
print(f"[INFO] Logging experiment to directory: {log_dir_path}")
正如注释中所述, os.path.abspath()
将在前面添加 /workspace/isaaclab
,因为在 Docker 容器中,所有的 Python 执行都是通过 /workspace/isaaclab/isaaclab.sh
进行的。结果将是一个名为 log.txt
的文件,在每个模拟步骤上, sim_time
将被写入一行:
# Prepare to count sim_time
sim_dt = sim.get_physics_dt()
sim_time = 0.0
# Open logging file
with open(os.path.join(log_dir_path, "log.txt"), "w") as log_file:
# Simulate physics
while simulation_app.is_running():
log_file.write(f"{sim_time}" + "\n")
# perform step
sim.step()
sim_time += sim_dt
执行脚本#
我们将执行脚本以生成一个日志,在我们的执行中添加 --headless
标志以防止 GUI:
isaaclab -p source/standalone/tutorials/00_sim/log_time.py --headless
现在, log.txt
将在 /workspace/isaaclab/logs/docker_tutorial
中生成。如果我们在容器中输入 exit
以退出,我们将返回到主机终端环境中的 IsaacLab/docker
中。然后,我们可以输入以下命令,从 Docker 容器中检索日志并将它们放在主机上:
./container.py copy
我们将看到一个终端输出报告,报告了我们从容器中检索出的输出物。如果我们转到 /isaaclab/docker/artifacts/logs/docker_tutorial
,我们将看到上面由脚本生成的 log.txt
文件的副本。
artifacts
下的每个目录对应于容器中与 数据卷 映射的 Docker 目录, container.sh copy
命令将它们从这些 `数据卷`_ 中复制到这些目录中。
我们可以再次运行 container.sh enter
来返回 Isaac Lab Docker 终端环境,但是我们已经检索到了日志并希望去检查它们。我们可以使用以下命令停止 Isaac Lab Docker 容器:
./container.py stop
这将关闭 Docker Isaac Lab 容器。镜像将保留并保持可用供进一步使用, 数据卷 的内容也将保留。如果我们希望释放镜像占用的磁盘空间,(~20.1GB),并且不介意下次运行 ./container.sh start
时重复构建过程,我们可以输入以下命令来删除 isaac-lab-base 镜像:
docker image rm isaac-lab-base
随后运行 docker image ls
将会显示标记为 isaac-lab-base 的镜像已经不存在。如果我们希望释放更多空间,我们可以对底层 NVIDIA 容器重复该过程。如果需要更强大的从 Docker 释放资源的方法,请查阅 `docker prune`_命令的文档。