Skip to content

RViz

rViz는 ROS에서 사용되는 주요 시각화 도구로, 로봇의 센서 데이터, 좌표계, 경로 계획 등을 3D 환경에서 시각화할 수 있습니다. rViz는 로봇 개발 중 발생하는 데이터와 정보를 실시간으로 확인할 수 있는 강력한 툴로, 다음과 같은 기능을 제공합니다: - 센서 데이터 시각화: 라이다, 카메라, IMU 등의 센서 데이터를 3D로 시각화. - 로봇의 상태 표시: 로봇의 위치, 방향, 관절 상태 등을 실시간으로 보여줌. - URDF 모델 시각화: 로봇의 URDF(Universal Robot Description Format) 파일로 모델을 로드하고, 시뮬레이션에서의 상태를 확인. - 좌표 변환(tf): 로봇의 여러 좌표계 간 변환을 시각적으로 확인 가능.

RViz2

ros2rviz.

PLY 보는 방법

PLY 파일을 직접 열지는 못하지만, sensor_msgs/PointCloud2 토픽으로 퍼블리시하면 시각화할 수 있습니다. pcl_ros 패키지나 간단한 Python 노드로 PLYPointCloud2 변환 후 퍼블리시하는 방식입니다.

pcl_ros / point_cloud_viewer

pcl_ros에 PLY를 로드해서 토픽으로 뿌려주는 유틸이 있고, RViz2에서 바로 확인 가능합니다.

# pcl_ros 설치 (Install pcl_ros)
sudo apt install ros-${ROS_DISTRO}-pcl-ros ros-${ROS_DISTRO}-pcl-conversions

간단한 퍼블리셔 노드 예시

WARNING

잘 되는지 검증이 필요한 코드 이다.

직접 PLY를 읽어서 RViz2로 보는 게 가장 실용적입니다:

import rclpy
from rclpy.node import Node
from sensor_msgs.msg import PointCloud2, PointField
import numpy as np
import open3d as o3d  # PLY 로딩용 (for loading PLY files)
import struct

class PlyPublisher(Node):
    def __init__(self, ply_path: str):
        super().__init__('ply_publisher')
        self.publisher_ = self.create_publisher(PointCloud2, 'point_cloud', 10)

        # PLY 파일 로드 (Load PLY file)
        pcd = o3d.io.read_point_cloud(ply_path)
        points = np.asarray(pcd.points, dtype=np.float32)

        # PointCloud2 메시지 생성 (Create PointCloud2 message)
        self.msg = self._create_pc2(points)

        # 1Hz로 퍼블리시 (Publish at 1Hz)
        self.timer = self.create_timer(1.0, self.publish)

    def publish(self):
        self.msg.header.stamp = self.get_clock().now().to_msg()
        self.publisher_.publish(self.msg)

    def _create_pc2(self, points):
        msg = PointCloud2()
        msg.header.frame_id = 'map'
        msg.height = 1
        msg.width = len(points)
        msg.fields = [
            PointField(name='x', offset=0, datatype=PointField.FLOAT32, count=1),
            PointField(name='y', offset=4, datatype=PointField.FLOAT32, count=1),
            PointField(name='z', offset=8, datatype=PointField.FLOAT32, count=1),
        ]
        msg.point_step = 12
        msg.row_step = 12 * len(points)
        msg.is_dense = True
        msg.data = points.tobytes()
        return msg

See also