Priceless
[Isaac Sim] OmniGibson에서 ROS2 Bridge 설정, ROS2 camera topic , TF topic추가 본문
[Isaac Sim] OmniGibson에서 ROS2 Bridge 설정, ROS2 camera topic , TF topic추가
Hyun__ 2025. 2. 7. 13:45OmniGibson에서 ROS2를 사용하기
OmniGibson에서 rosbag 등을 사용하여 ROS를 통해 카메라 데이터를 받아오려고 한다
그렇게 하기 위해 Isaac Sim과 ROS2 를 연결할 Bridge를 설정해야 한다
유의 사항
OmniGibson에서 사용하는 Isaac Sim은
엔비디아에서 계속 지원해주는 버전이 아닌
4.1.0 버전을 포팅해서 사용한다
그러므로 공식적으로 ROS와 Isaac Sim의 모든 기능을 지원하지 않기 때문에
OmniGibson의 구성 환경에 맞게 실행해야 한다
환경
Ubuntu 22.04
ROS2 Humble
RTX 4070
OmniGibson 1.1.1
ROS2 설치 및 설정
아래 사이트를 참고한다
ROS2 설치
ROS2가 설치되어 있지 않다면
ROS2를 본인 환경에 맞게 설치한다
외부 자료 참고 권장
(필요한 경우 아래도 설치)
카메라 토픽을 추가해야 하니
아래도 설치해본다
sudo apt install ros-humble-vision-msgs
sudo apt install ros-humble-ackermann-msgs
Isaac Sim에 ROS Bridge 설정
Isaac Sim ROS 2 Workspace를 사용하지 않는다면
~/.ros/fastdds.xml 경로에 아래와 같은 파일을 추가한다
<?xml version="1.0" encoding="UTF-8" ?>
<license>Copyright (c) 2022-2024, NVIDIA CORPORATION. All rights reserved.
NVIDIA CORPORATION and its licensors retain all intellectual property
and proprietary rights in and to this software, related documentation
and any modifications thereto. Any use, reproduction, disclosure or
distribution of this software and related documentation without an express
license agreement from NVIDIA CORPORATION is strictly prohibited.</license>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles" >
<transport_descriptors>
<transport_descriptor>
<transport_id>UdpTransport</transport_id>
<type>UDPv4</type>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="udp_transport_profile" is_default_profile="true">
<rtps>
<userTransports>
<transport_id>UdpTransport</transport_id>
</userTransports>
<useBuiltinTransports>false</useBuiltinTransports>
</rtps>
</participant>
</profiles>
Cyclone DDS를 사용하여 ROS2 Bridge 실행 (필요 없음)
ROS2는 Fast DDS를 지원하지만 Isaac Sim은 Linux 환경에서 Cyclone DDS 도 지원한다
ROS2에서 Cyclone DDS를 사용하기 위해 세팅한다
https://docs.ros.org/en/humble/Installation/DDS-Implementations/Working-with-Eclipse-CycloneDDS.html
Eclipse Cyclone DDS — ROS 2 Documentation: Humble documentation
You're reading the documentation for an older, but still supported, version of ROS 2. For information on the latest version, please have a look at Jazzy. Eclipse Cyclone DDS Eclipse Cyclone DDS is a very performant and robust open-source DDS implementation
docs.ros.org
# install packages
sudo apt install ros-humble-rmw-cyclonedds-cpp
# switch to rmw_cyclonedds
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
Workspace 설정
여기서부터는 OmniGibson에서 수행할 것이기 때문에
공식 docs에서 조금 수정한다
# For rosdep install command
sudo apt install python3-rosdep python3-rosinstall python3-rosinstall-generator python3-wstool build-essential
# For colcon build command
sudo apt install python3-colcon-common-extensions
Omnigibson 디렉토리를 빌드한다
cd ~/Omnigibson
catkin build
source install/local_setup.bash
build 과정에서 패키지 버전 관련 오류가 종종 나타났는데
아래와 같이 해결 한다
pip install --upgrade <package name and version>
이후 build하면 정상적으로 빌드가 성공되고
build, install, log 디렉토리가 생성된다
이렇게 마무리 할 수 있다
ROS2 Bridge 설정
이제 다시 OmniGibson example을 실행하여
$ python -m omnigibson.examples.robots.robot_control_example --quickstartxamples.robots.robot_control_exampl
windows > extensions 창에서 ROS2 BRIDGE를 실행한다

버튼을 누르면 터미널에서 아래와 같은 에러 문구가 뜰 수 있는데
본인은 아래와 같이 gcc를 새로 설치하여 해결했다
[48.680s] [ext: omni.isaac.ros2_bridge-2.31.4] startup
[48.707s] Attempting to load system rclpy
[48.719s] Could not import system rclpy: /home/user/anaconda3/envs/omnigibson/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so)
The C extension '/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so' failed to be imported while being present on the system. Please refer to 'https://docs.ros.org/en/{distro}/Guides/Installation-Troubleshooting.html#import-failing-even-with-library-present-on-the-system' for possible solutions
[48.719s] Attempting to load internal rclpy
[48.722s] Could not import internal rclpy: /home/user/anaconda3/envs/omnigibson/bin/../lib/libstdc++.so.6: version `GLIBCXX_3.4.30' not found (required by /opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so)
The C extension '/opt/ros/humble/local/lib/python3.10/dist-packages/rclpy/_rclpy_pybind11.cpython-310-x86_64-linux-gnu.so' failed to be imported while being present on the system. Please refer to 'https://docs.ros.org/en/{distro}/Guides/Installation-Troubleshooting.html#import-failing-even-with-library-present-on-the-system' for possible solutions
[48.722s] To use the internal libraries included with the extension please set the following environment variables to use with FastDDS (default) or CycloneDDS (ROS2 Humble only):
RMW_IMPLEMENTATION=rmw_fastrtps_cpp
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/humble/lib
OR
RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/humble/lib
Before starting Isaac Sim
>>>
conda install -c conda-forge gcc=12.1.0
다시 OmniGibson 환경을 실행한 후
ROS2 bridge를 작동한다

다행히 rclpy 다음 오류 없이 진행되었다
Running demo.
Press ESC to quit
Pressed None. Action: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
Pressed None. Action: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
[39.920s] [ext: omni.isaac.ros2_bridge-2.31.4] startup
[39.942s] Attempting to load system rclpy
Pressed None. Action: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]
이 과정을 매번 하기 귀찮다면
OmniGibson/omnigibson/omnigibson_4_1_0.kit 파일에
아래를 추가하면 자동으로 ROS2 Bridge가 켜진 상태로 실행된다
"omni.isaac.ros2_bridge" = {} # it works
ROS2 Camera Topic Tutorial
아래의 튜토리얼을 수행하여 정상적으로 작동하는지 확인한다
https://docs.omniverse.nvidia.com/isaacsim/latest/ros2_tutorials/index.html
windows > visual scripting > action graph 에서
공식 문서의 action graph는 아래와 같다

하지만 정상적으로 실행되지 않았고
디버깅한 결과 Isaac Sim One Simulation Frame 노드에서
다음 모듈로 데이터가 넘어가지 않았다
Isaac Sim One Simulation Frame 노드를 제거하여 그래프를 구성하고
Isaac Create Render Product 노드에서 로봇의 camera prim을 설정하면

ros2에서 /rgb 토픽으로 정상적으로 발행된다

depth와 segmentation 도 출력해본다
아래와 같이 action graph를 구성한다

depth 이미지도 잘 출력된다
semantic segmentation 이미지는
ROS2 에서 image를 출력하는 데이터 타입을 맞춰야 되는 듯 하다

ROS2 Bridge를 통해 Segmentation 이미지 출력하기
Semantic Segmentation 노드까지 설정한 후
발행되는 토픽을 확인하면
image와 label에 대한 정보가 따로 발행되는 것을 확인할 수 있다
$ ros2 topic echo /segment --once header: stamp: sec: 700 nanosec: 8369841 frame_id: sim_camera height: 720 width: 1280 encoding: 32SC1 is_bigendian: 0 step: 5120
data: - 13 - 0 - 0 - '...'
(label class가 출력됨)
$ ros2 topic echo /semantic_labels --once
data: '{"0":{"class":"BACKGROUND"},"1":{"class":"UNLABELLED"},"10":{"class":"carpet"},"13":{"class":"ottoman"},"14":{"class":"coffee_ta...'
(class에 대한 정보가 출력됨)
데이터 타입이 rgb와 같은 이미지가 아니기 때문에
ROS2에서 바로 image로 출력할 수 없다
Viewport에서 제공하는 segmentation 이미지는
자체적으로 색을 입히는 듯하다
매번 실행할 때마다 label의 색이 조금씩 달라진다


그렇기에 간단하게 segmentation 이미지를 출력할 수 있는 파이썬 코드를 작성한다
아래 코드는 발행된 토픽을 받아서 컬러링한 후
다시 발행하므로 실시간으로 데이터를 사용하기에는 무리가 있다
테스트 및 시각화용이다
아래 파이썬 파일을 실행하면 rqt에서도 확인할 수 있다
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from std_msgs.msg import String
import numpy as np
import json
import cv2 # OpenCV 추가
class SemanticLabelMapper(Node):
def __init__(self):
super().__init__('semantic_label_mapper')
# 구독할 토픽
self.segment_sub = self.create_subscription(
Image, '/semantic_segmentation', self.segment_callback, 10)
self.labels_sub = self.create_subscription(
String, '/semantic_labels', self.labels_callback, 10)
# 변환된 Semantic Label Map을 발행할 토픽
self.label_map_pub = self.create_publisher(Image, '/semantic_label_map', 10)
self.colored_map_pub = self.create_publisher(Image, '/colored_semantic_map', 10) # 컬러 맵을 위한 퍼블리셔 추가
# Label ID -> Class Name 매핑을 저장할 변수
self.label_dict = {}
# 색상 맵 생성
self.color_map = self.generate_color_map()
def generate_color_map(self, num_classes=256):
"""고유한 RGB 색상을 생성하는 함수"""
color_map = np.zeros((num_classes, 3), dtype=np.uint8)
for i in range(num_classes):
color_map[i] = [
(i * 50) % 255, # R
(i * 70) % 255, # G
(i * 90) % 255 # B
]
# 배경(0)은 검정색으로 설정
color_map[0] = [0, 0, 0]
return color_map
def labels_callback(self, msg):
"""'/semantic_labels' 토픽을 받아서 JSON 형식으로 변환"""
try:
self.label_dict = json.loads(msg.data)
self.get_logger().info("Received label mapping data")
except json.JSONDecodeError as e:
self.get_logger().error(f"Failed to decode label data: {e}")
def segment_callback(self, msg):
"""'/segment' 이미지 데이터를 변환하여 '/semantic_label_map'으로 발행"""
if not self.label_dict:
self.get_logger().warn("Label dictionary is empty. Waiting for semantic_labels topic.")
return
# 이미지 데이터를 NumPy 배열로 변환
segment_array = np.frombuffer(msg.data, dtype=np.int32).reshape((msg.height, msg.width))
# Label ID -> Class Name 변환
label_map = np.zeros(segment_array.shape, dtype=np.uint8)
for label_id, info in self.label_dict.items():
try:
label_id_int = int(label_id)
label_map[segment_array == label_id_int] = label_id_int
except ValueError:
continue
# 컬러 맵 생성
colored_map = np.zeros((msg.height, msg.width, 3), dtype=np.uint8)
for i in range(len(self.color_map)):
mask = (label_map == i)
colored_map[mask] = self.color_map[i]
# 원본 라벨 맵 발행
output_msg = Image()
output_msg.header = msg.header
output_msg.height = msg.height
output_msg.width = msg.width
output_msg.encoding = "mono8"
output_msg.is_bigendian = False
output_msg.step = msg.width
output_msg.data = label_map.tobytes()
self.label_map_pub.publish(output_msg)
# 컬러 맵 발행
color_msg = Image()
color_msg.header = msg.header
color_msg.height = msg.height
color_msg.width = msg.width
color_msg.encoding = "rgb8" # RGB 형식으로 변경
color_msg.is_bigendian = False
color_msg.step = msg.width * 3 # RGB는 픽셀당 3바이트
color_msg.data = colored_map.tobytes()
self.colored_map_pub.publish(color_msg)
self.get_logger().info("Published semantic label map and colored map")
def main(args=None):
rclpy.init(args=args)
node = SemanticLabelMapper()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()

실시간으로 사용하려면 어떻게 해야 할까?
'Robotics > NVIDIA' 카테고리의 다른 글
[NVIDIA Omniverse] OmniGibson 설치 (0) | 2025.01.16 |
---|