RViz
lastmod 2026-04-02created 2026-02-123 edits
rViz is the main visualization tool used in ROS, and can visualize a robot's sensor data, coordinate frames, path planning, and more in a 3D environment. rViz is a powerful tool for checking the data and information generated during robot development in real time, and provides the following features: - Sensor data visualization: visualizes sensor data from lidar, cameras, IMUs, etc. in 3D. - Robot state display: shows the robot's position, orientation, joint states, etc. in real time. - URDF model visualization: loads a model from the robot's URDF (Universal Robot Description Format) file and checks its state in simulation. - Coordinate transforms (tf): lets you visually check transforms between the robot's various coordinate frames.
RViz2
The rviz of ros2.
How to view PLY
It cannot open PLY files directly, but it can visualize them if you publish them as a sensor_msgs/PointCloud2 topic. The approach is to convert PLY → PointCloud2 with the pcl_ros package or a simple Python node and then publish it.
pcl_ros / point_cloud_viewer
pcl_ros has a utility that loads PLY and publishes it as a topic, which you can check right away in RViz2.
# pcl_ros 설치 (Install pcl_ros)
sudo apt install ros-${ROS_DISTRO}-pcl-ros ros-${ROS_DISTRO}-pcl-conversions
Simple publisher node example
| WARNING |
| This code needs to be verified to work. |
Reading the PLY yourself and viewing it in RViz2 is the most practical:
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