机器人有助于为制造业、物流业、医疗保健业和服务业等行业创造新效率并提升人们的生活质量, NVIDIA Isaac 凭借改进的机器人开发、模拟和部署功能,可加速这一进程。
对于机器人领域的开发者而言,“Isaac 就是 Omniverse 平台里面,一个完全在 GPU 上实现,很好地将机器人相关的一些深度学习、强化学习、SLAM、图像处理等等的算法,融合在一个 GEMs 的高性能软件包中的炫酷仿真引擎。” 这是知乎大咖稚辉(知乎坐拥 130 多万粉丝的知名 KOL、AI 工程师)对于 Isaac 的评价。本期文章我们将分享稚辉 Isaac 仿真平台搭建以及 ROS 试用教程。
Isaac 仿真平台搭建以及 ROS 试用教程
最近在搞一个机器人项目嘛,所以借着机会了解了一下之前 NVIDIA 大力推广的 Omniverse 平台,Omniverse 是 NVIDIA 推出的一个元宇宙模拟平台,而 Isaac 是其中专门用于机器人环境模拟的一个引擎,试了一下还挺有意思的。
其实最早 Omniverse 设计的初衷是提供一个能让工程师们协作创作的虚拟工具,毕竟号称元宇宙引擎嘛,在数字世界里做基建必然是一个需要大量不同场景的工程师们配合实现的工作,后来该项目逐渐演变成了一个更加宏大的全行业框架。
发布会上提到会通过一种 USD(Universal Scene Description,这个缩写我直呼内行)的基础数据格式来打通各种不同的软件之间的配合。USD 不仅仅只是导入和导出的一种格式而已, USD 之于 Omniverse 就像 HTML(一种标记语言,可以将网络上的文档格式统一)之于网站。
而 Isaac 就是 Omniverse 平台里面,一个完全在 GPU 上实现,很好地将机器人相关的一些深度学习、强化学习、SLAM、图像处理等等的算法,融合在一个 GEMs 的高性能软件包中的炫酷仿真引擎。之前做机器人仿真的时候,最常用的是 VREP(现在叫 CoppeliaSim 了)、ROS 里面的 Gazebo、WeBot 等,这些仿真器用到的主要物理引擎都是开源的 Bullet 和 ODE。
与上面提到的这些仿真器相比,Isaac 的优势在于:
- 超逼真的光照渲染效果:一个字,以假乱真。NVIDIA 做啥起家的大家都知道了,RTX ON 之后这渲染效果相比于前面提到的开源引擎有质的飞跃,直接来到照片级的逼真度。
- 性能的提升:实时的光照渲染和物理引擎的算力需求都是很高的,Isaac 针对 NVIDIA 硬件(GPU)进行了优化,可以生成高效的平台优化的交叉编译应用程序。
- 生态支持度好:Isaac 集成了其中许多 CUDA 加速的开源库,例如 NPP、OpenCV、ROS、PCL (wip)、Eigen 等。
- 自带常用的算法库:Isaac SDK 附带了一系列高性能算法,这些算法被称为 GEM,此外除了机器人控制类的算法,Issac 还为主业打游戏副业炼丹的同学们准备了深度神经网络模块的集成,例如立体声深度估计、目标检测、 Tracking 算法等等。
当然了对我这种颜值狗来说,渲染效果美丽 + Modern UI 的软件界面就足够让我对其他软件 Say No 了。下图展示了 Isaac 的生态系统:
那么接下来本文简单介绍一下 Issac 的安装流程以及使用记录。
准备的环境
使用的是我自己的台式机,硬件配置如下:
项目 | 概述 |
OS | Ubuntu 20.04 LTS |
kernel | 5.13.0-35-generic |
CPU | 英特尔 i7-12700F |
MEM | 64GB |
GPU | GeForce RTX 3080 |
Driver Ver | 470.103.01 |
CUDA Ver | 11.4 |
按照 NVIDIA 官方 Omniverse 安装指南(链接如下):
首先,下载 Omniverse 的启动器程序(需要注册一下,链接如下):
操作系统可以选择 Windows 或 Linux,这里我用的是 Ubuntu 所以选 Linux 版本,可以得到名为 omniver 的文件,下载好之后需要授予它执行权限,并将其放在主页目录下,命令:
chmod +x omniver ./omniver
运行此启动器程序将启动 Omniverse 窗口,但需要 NVIDIA 帐户登录才能使用,没有的话注册一下就行个人使用是免费的。
首次启动时,系统会提示是否要安装名为 “Cache” 的软件,这个是用于提供一种软件缓存机制,用于管理网络通信加载内容的,建议安装它。
启动器的软件界面
顺便说一下,Omniverse会开启一个后台服务,你可以从浏览器访问 http://localhost:3080 来打开后台管理页面查看每个服务的操作状态。
然后需要在启动器软件中安装 Nucleus 服务:
Nucleus 就是个数据服务器,用于连接其他软件,同时在当多个人进行项目时,通过连接到此服务器进行协作开发。软件中也有很多有意思的 Tutorial 可以自己尝试学习:
安装完成后用之前注册的账号登录即可,登录后将看到一个文件管理器,可以在其中管理项目内容。
接下来,我们添加机器人模拟器环境 Isaac Sim。Isaac Sim 是一个机器人仿真工具包,在 Omniverse 上运行,Isaac Sim 具有构建虚拟机器人世界和实验的基本功能,还能通过渲染能力提供进行数据集合成的工具和工作流程。Isaac Sim 通过 ROS/ROS2 支持导航和操作应用程序。
Isaac 的架构图如下:
由于渲染能力过猛,Isaac 对于硬件的配置要求有一丢丢高,推荐的配置为- RTX2070 及以上的显卡,内存至少 32GB,NVIDIA 的驱动程序版本需要 470.57.02 或更高版本。
参考以下安装指南安装 Isaac Sim:
从 EXCHANGE 选项卡中选择并安装:
根据教程,Isaac Sim 应该有一个按钮来下载 Isaac Sim Assets(示例数据等)后启动,但可能是网络问题我这边无法下载,所以通过手动添加方式解决,参考:
具体解决方案是从主窗口的 mount 选项卡右键单击导航器的 localhost,创建具有以下参数的文件夹:
项目 | 内容 |
Name | Isaac |
Type | Amazon S3 |
Host | |
Service | s3 |
Redirection |
下面的命令安装:
sudo apt install . sudo apt install -y apt-transport-https sudo apt update
然后我们安装一下 VS Code 来代替自带的编辑器,在官网下载 deb 安装包
此外,从 Isaac Sim 打开 VSCode 时的配置文件(如 )使用的是 .vscode,该文件位于 Isaac Sim 的安装根目录~/.local/share/ov/pkg/isaac_simxxx 中。
安装 ROS 和 ROS2
在 Ubuntu 上安装要与配合的 ROS 和 ROS2,只需按照官方安装指南进行安装即可:
然后,在 Isaac Sim 端启用 ROS Bridge 扩展,在窗口状态量菜单中 Window->Extensions 中搜索 “ROS”:
启用 “ROS Bridge” 和 “ROS UI” :
如果使用 ROS2,那就启用 ROS2 Bridge 而不是 ROS Bridge。
现在 ROS 就可以和 Isaac Sim 通信啦,接下来我们编写一个简单的程序进行测试。
Python代码测试
Isaac Sim 可以从官方自带的一些 python 脚本独立启动, 启动脚本位于 Omniverse 中的 Isaac Sim 目录中,例如,启动作为示例提供的名为 “franka” 的制造机器人演示的命令如下所示:
cd ~/.local/share/ov/pkg . standalone_examples/api
打开的时间可能比较久需要有点耐心...
当然还有其他很多别的脚本可以供参考,接下来我们将自己编写 Python 脚本实现以下内容:
1、在场景中放置对象
2、在场景中放置一个机器人并用键盘控制运动
放置对象
我们可以使用 omni.i 对象模块放置对象,包含以下函数:
- DynamicCuboid
- DynamicCapsule
- DynamicCone
- DynamicCylinder
- DynamicSphere
- VisualCuboid
- VisualCapsule
- VisualCone
- VisualCylinder
- VisualSphere
- FixedCuboid
这些函数允许我们在场景中放置立方体、胶囊、圆锥体、圆柱体和球体,Dynamic 开头的对象受到物理引擎的作用,比如重力,当把它们放置在空中时,它会直接掉落。Visual 开头的对象则只会用于外观,不会受到力的作用,也不会进行碰撞检测,因此其他对象可以直接穿过它。例如以下代码:
from omni.i import SimulationApp import numpy as np simulation_app = SimulationApp({"headless": False}) from omni.i import World from omni.i.objects import DynamicCuboid, DynamicCapsule, DynamicCone from omni.i.objects import DynamicCylinder, DynamicSphere, FixedCuboid my_world = World(stage_units_in_meters=0.01) d_cube = my_world.( DynamicCuboid( prim_path="/dynamic_cube", name="dynamic_cube", position=np.array([0, 0, 0.5]) * 100, size=np.array([0.1, 0.1, 0.1]) * 100, color=np.array([255, 255, 255]), ) ) d_cap = my_world.( DynamicCapsule( prim_path="/dynamic_capsule", name="dynamic_capsule", position=np.array([0.5, 0, 0.5]) * 100, radius=0.05 * 100, height=0.05 * 100, color=np.array([255, 0, 0]), ) ) d_cone = my_world.( DynamicCone( prim_path="/dynamic_cone", name="dynamic_cone", position=np.array([-0.5, 0, 0.5]) * 100, radius=0.05 * 100, height=0.05 * 100, color=np.array([0, 0, 255]), ) ) d_cyl = my_world.( DynamicCylinder( prim_path="/dynamic_cylinder", name="dynamic_cylinder", position=np.array([0, 0.5, 0.5]) * 100, radius=0.05 * 100, height=0.05 * 100, color=np.array([0, 255, 0]), ) ) d_sph = my_world.( DynamicSphere( prim_path="/dynamic_sphere", name="dynamic_sphere", position=np.array([0.5, 0.5, 0.5]) * 100, radius=0.05 * 100, color=np.array([255, 0, 255]), ) ) f_cube = my_world.( FixedCuboid( prim_path="/fixed_cube", name="fixed_cube", position=np.array([-0.5, 0.5, 0.5]) * 100, size=np.array([0.1, 0.1, 0.1]) * 100, color=np.array([255, 255, 255]), ) ) my_world._default_ground_plane() my_world.reset() while (): my_world.step(render=True) ()
效果是这样的:
稍微修改一下,加入一些互动,比如用键盘控制一个小车:
from omni.i import SimulationApp import numpy as np import carb import omni.appwindow simulation_app = SimulationApp({"headless": False}) from omni.i import Jetbot from omni.i.controllers import DifferentialController from omni.i import World my_world = World(stage_units_in_meters=0.01) my_jetbot = my_world.( Jetbot( prim_path="/World/Jetbot", name="my_jetbot", position=np.array([0, 0.0, 2.0]) ) ) my_controller = DifferentialController(name="simple_control") my_world._default_ground_plane() command_ = [0.0, 0.0] def sub_keyboard_event(event, *Args, **kwargs): """Handle keyboard events w,s,a,d as arrow keys for jetbot movement Args: event (int): keyboard event type """ global command_ if( event.type == carb.in or event.type == carb.in ): if event.input == carb.in: command_ = [20, 0.0] if event.input == carb.in: command_ = [-20, 0.0] if event.input == carb.in: command_ = [0.0, np.pi / 5] if event.input == carb.in: command_ = [0.0, -np.pi / 5] i == carb.in): command_ = [0.0, 0.0] return True appwindow_ = omni.a() input_ = carb.in() keyboard_ = a() sub_keyboard_ = in(keyboard_,sub_keyboard_event) my_world.reset() while (): my_world.step(render=True) if my_world.is_playing(): my_je(command=command_)) ()
效果如下,用键盘的 WASD 可以控制小车运动:
更多的 API 可以参考官方的文档,后续再补充更多内容。
*本文转载自 NVIDIA英伟达
*与 NVIDIA 产品相关的图片或视频(完整或部分)的版权均归 NVIDIA Corporation 所有。