# 로봇 비주얼라이제이션(RViz2) 설정

#### RViz2의 기본 개념

ROS2 환경에서 로봇 상태를 직관적으로 확인하기 위해 가장 많이 활용되는 도구 중 하나가 RViz2이다. URDF로 정의된 로봇 모델을 시각화하고, 다양한 센서 데이터나 좌표계(tf)를 모니터링할 수 있다. RViz2는 하드웨어 없이도 ‘가상 환경에서 로봇의 동작’을 미리 살펴보고, 로봇 센서나 동작에 대한 여러 가지 시뮬레이션을 할 수 있다는 장점이 있다.

ROS2 Humble 버전에서 URDF를 활용해 RViz2에서 로봇을 표시하려면 다음과 같은 개념 및 과정을 이해하고 설정해야 한다.

1. URDF를 통한 로봇 모델 표현
2. ROS2 Parameter Server 또는 XACRO 등을 통한 로봇 설명 파라미터화
3. RViz2에서 RobotModel, TF, LaserScan, Odometry 등 필요한 Display 유형 설정
4. URDF에서 정의된 링크, 조인트, 그리고 센서들의 상태를 Topic 구독 또는 TF를 통해 업데이트

이를 위해서 먼저 URDF, XACRO, TF 등에 대한 지식이 필요하다. 이후, URDF로 만들어 놓은 로봇 모델을 Parameter Server에 로드하고, RViz2에서 그것을 로드해 시각화하기 위해 Display 설정을 수행한다.

#### URDF 로드 과정

RViz2에서 로봇 모델을 표시하기 위해서는 robot\_description 이라는 ROS2 파라미터가 주로 사용된다. 이는 URDF 파일 혹은 URDF를 포함한 XACRO 파일에서 생성한 문자열을 파라미터 서버에 로딩하여, 로봇 모델에 대한 정보를 ROS2 전체에서 사용할 수 있도록 하는 기법이다.

대표적인 로딩 순서는 다음과 같다.

1. URDF/XACRO 파일 작성
2. 로봇 모델 파일을 robot\_description 파라미터로 세팅
3. RViz2 실행
4. RViz2의 ‘RobotModel’ Display에서 Parameter 명을 robot\_description 으로 설정
5. 로봇 모델이 정상적으로 시각화되는지 확인

예시로, URDF 파일이 `my_robot.urdf`라는 이름으로 존재한다고 가정해 보자. 이를 ROS2 파라미터에 로딩하기 위한 launch 파일에서 다음과 같이 설정할 수 있다.

```python
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument, ExecuteProcess
from launch.substitutions import ThisLaunchFileDir, LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        DeclareLaunchArgument(
            'use_sim_time',
            default_value='false',
            description='Use sim time if true'),
        ExecuteProcess(
            cmd=[
                'ros2', 'param', 'set',
                '/robot_state_publisher',
                'robot_description',
                open('my_robot.urdf', 'r').read()
            ],
            output='screen'
        ),
        Node(
            package='robot_state_publisher',
            executable='robot_state_publisher',
            name='robot_state_publisher',
            parameters=[{'use_sim_time': LaunchConfiguration('use_sim_time')}]
        )
    ])
```

위 코드에서는 `robot_state_publisher` 노드를 통해 URDF가 ROS2 환경의 파라미터로 등록되며, 로봇 상태를 publish 해준다. 이후 RViz2에서 `robot_description` 파라미터를 기반으로 로봇을 시각화할 수 있다.

#### Display 패널 구성

RViz2를 실행하면, 좌측에 ‘Displays’ 패널이 나타난다. 여기서 우리가 원하는 데이터를 시각화하기 위해 각종 유형(Display)을 추가할 수 있다. 로봇을 모델로 표시하기 위해서는 주로 다음 두 가지 Display를 사용한다.

1. **RobotModel**
   * `robot_description` 파라미터를 읽어서 로봇의 링크와 조인트 정보를 시각화한다.
   * TF 정보가 존재하면 조인트의 움직임도 실시간으로 반영된다.
2. **TF**
   * 다양한 좌표계를 시각적으로 확인할 수 있도록 돕는다.
   * 링크나 센서, 조인트가 서로 어떻게 연결되어 있는지 파악하기 위해 활용된다.

아래는 RViz2에서 RobotModel Display를 설정하는 기본적인 순서이다.

```bash
ros2 run rviz2 rviz2
```

RViz2가 실행된 뒤, 좌측 하단 “Add” 버튼을 눌러 “Displays”에 RobotModel을 추가한다. 그리고 “Description Source”를 “Parameter”로 설정하고, “Parameter Name”에 `robot_description`을 입력한다. 이때 로봇 모델이 시각화되어야 정상 작동 중임을 알 수 있다.

#### 기본적인 TF 구조

RViz2에서 로봇 모델이 정상적으로 표시되기 위해서는 TF 트리 역시 적절하게 브로드캐스팅되어야 한다. ROS2에서 TF를 활용할 때, $^{(A)}\mathbf{T}\_{(B)}$와 같은 표기로 좌표계 변환을 표현한다면, 이는 ‘A 좌표계에서 B 좌표계로 가는 변환(Transformation)’을 의미한다.

각 변환은 4×4 변환 행렬로 나타낼 수 있다:

$$
\mathbf{T} = \begin{pmatrix} \mathbf{R} & \mathbf{p} \ 0 & 1 \end{pmatrix}
$$

여기서 $\mathbf{R}$은 3×3 회전행렬, $\mathbf{p}$는 3×1 변위 벡터이다. 로봇 URDF에서 링크가 조인트로 연결될 때, 이 변환 정보가 내부적으로 TF로 전달되어 RViz2 상에서 각 링크가 올바른 위치 및 자세에 위치하도록 한다.

#### 좌표계 트리 예시 (mermaid 활용)

URDF의 링크와 조인트로부터 생성된 TF 트리를 예시로 그려보면 다음과 같다.

{% @mermaid/diagram content="graph LR;
base\_link --> link1;
link1 --> link2;
link1 --> sensor\_frame;
link2 --> end\_effector;" %}

* **base\_link**: 로봇의 기본 좌표계(차체 등)
* **link1**: base\_link에서 첫 번째 조인트로 이어진 링크
* **sensor\_frame**: 링크1에 장착된 센서 좌표계
* **link2**: 이어지는 두 번째 조인트의 링크
* **end\_effector**: 로봇 말단 장치(End Effector)

이렇게 TF 트리가 명확하게 잡혀 있어야, RViz2가 로봇 각 부분의 링크를 올바른 위치에 배치할 수 있다.

#### 추가적인 Display 옵션

RViz2에서 로봇 모델뿐 아니라 센서 데이터 등을 함께 시각화하면, 로봇의 전체 상태나 환경 정보를 보다 직관적으로 확인할 수 있다. 이를 위해 다음과 같은 Display 유형을 추가로 활용할 수 있다.

1. **LaserScan**
   * 라이다(LiDAR)나 초음파 센서 등에서 출력된 스캔 데이터를 시각화한다.
   * 일반적으로 `sensor_msgs/msg/LaserScan` 형식의 Topic을 구독한다.
   * RViz2 상에서 포인트 구름 혹은 레이 형태로 나타나며, 장애물이나 벽, 사람 등을 확인할 수 있다.
2. **PointCloud2**
   * 3D 센서(예: RGB-D 카메라, 3D LiDAR)에서 획득한 포인트 클라우드를 표시한다.
   * `sensor_msgs/msg/PointCloud2` 형식의 Topic을 구독한다.
   * 밀도, 색상, 높이, 강도 등을 이용해 다양한 방법으로 표시할 수 있다.
3. **Marker / MarkerArray**
   * 노드에서 임의로 생성한 시각화 마커(Marker)를 표시한다.
   * 주로 `visualization_msgs/msg/Marker` 혹은 `visualization_msgs/msg/MarkerArray`를 사용한다.
   * 점, 선, 화살표, 메시, 텍스트 등을 자유롭게 배치하거나 애니메이션을 줄 수 있어, 디버깅이나 상태 표시용으로 많이 사용된다.
4. **Odometry**
   * 로봇의 위치/자세 추정 정보를 나타내는 `nav_msgs/msg/Odometry` Topic을 구독한다.
   * 로봇의 진행 궤적 등을 확인할 때 유용하다.

이러한 Display들을 “Add” 버튼을 눌러 필요한 만큼 추가하고, Topic이나 Parameter 이름, 표현 방식 등을 설정해 주면, URDF의 로봇 모델과 함께 각종 센서/마커 정보를 시각화할 수 있다.

#### RobotModel Display 상세 설정

RViz2에서 RobotModel Display를 선택하면, 다음과 같은 파라미터들을 확인할 수 있다.

* Description Source

  : URDF 데이터를 가져오는 방법

  * 일반적으로 “Parameter”를 선택하고, 그 아래의 “Parameter Name”을 `robot_description`으로 설정한다.
* **Robot Description**: 실제 URDF나 XACRO 데이터가 들어 있는 문자열(파라미터 값)
* **TF Prefix**: 로봇 모델의 모든 링크가 사용하는 TF 이름에 접두어(prefix)를 붙일 수 있다(여러 로봇 시뮬레이션 시 유용).
* **Alpha**: 로봇 모델의 투명도 설정
* **Update Rate**: 모델 업데이트 주기(초당 몇 번 업데이트할지)
* **Enable Visuals**: 링크의 시각적 요소(Visual) 표시 여부
* **Enable Collisions**: 링크의 충돌 요소(Collision) 표시 여부

**Collision 표시**

개발 및 디버깅 단계에서 로봇의 물리 충돌 모델을 확인해야 할 때가 있다. 이때 “Enable Collisions” 옵션을 활성화하면, RViz2 상에서 로봇의 충돌 메시에 해당하는 형태가 렌더링된다. URDF 안에서 `<collision>` 태그로 정의된 형상이 시각화되므로, 물리 시뮬레이션에서 어떤 형상으로 충돌을 감지하는지 빠르게 확인 가능하다.

#### Tools 패널 활용

RViz2 화면 상단에는 다음과 같은 “Tools” 아이콘들이 있다.

* **Interact**: 마우스로 RViz 내의 인터랙티브 마커(Interactive Marker)를 조작할 때 사용
* **Move Camera**: 시점을 평행 이동하거나 회전시킬 때 사용
* **Select**: 화면 내 특정 오브젝트(링크, 마커 등)를 선택했을 때 세부 정보를 확인할 수 있음
* **Measure**: 클릭-드래그로 두 점 사이의 거리를 재는 기능
* **Publish Point**: 선택한 점의 좌표를 Topic으로 보내는 기능

특히 “Interact” 기능은, URDF 모델 상에 Interactive Marker가 띄워져 있을 경우, 로봇 조인트를 직접 드래그하면서 동작 확인을 해볼 수 있다. 단, 이를 위해서는 별도의 노드에서 Interactive Marker를 생성하고 있어야 한다.

#### RViz2 Config 파일 구성

RViz2에서 로봇 모델의 시각화와 각종 Display들을 세팅한 뒤, 해당 설정값들을 하나의 파일로 저장할 수 있다. 일반적으로 `.rviz2` 확장자를 사용하며, 아래와 같이 구성된다.

* **Displays**: 현재 RViz2에 추가된 Display 목록 및 각각의 파라미터 설정
* **ViewControllers**: 카메라 시점이나 관찰 모드(Orbit, FPS, XY Orbit 등) 설정
* **Tools**: Measure, Interact 등 툴바에서 활성화된 상태나 파라미터
* **Global Options**: Fixed Frame, 배경색 등 전역 옵션

**예시: 구성 파일 저장**

RViz2에서 로봇을 불러와 Display들을 원하는 대로 추가 및 설정했다면, 상단의 “File” 메뉴 → “Save Config As…”를 선택해서 원하는 경로에 `.rviz2` 파일로 저장한다.

**예시: 구성 파일 로딩**

RViz2를 실행하면서 미리 저장해 둔 구성 파일을 불러오려면, 다음과 같이 `-d` 옵션을 활용할 수 있다.

```bash
ros2 run rviz2 rviz2 -d path/to/my_config.rviz2
```

이렇게 하면, 저장된 설정대로 모든 Display, View, Tool 등이 자동으로 로드되어 시간을 절약할 수 있다.

#### 시점(View) 설정

RViz2에서는 카메라 시점을 다양하게 제어할 수 있다. 대표적으로 다음과 같은 View Controller 유형이 존재한다.

1. **Orbit**: 마우스 드래그를 통해 로봇을 중심으로 회전하며 볼 수 있는 일반적인 3D 뷰
2. **XY Orbit**: XY 평면 위에서 회전하는 뷰로, 2D 지도(OccupancyGrid) 시각화 시 주로 사용
3. **TopDownOrtho**: 위에서 아래로 내려다보는 직교투영(Orthographic) 뷰
4. **FPS**: 1인칭 시점(First Person Shooter) 스타일로, WASD 키와 마우스 이동을 통해 카메라를 조작

**카메라 위치 및 초점 변경**

* **Shift + 마우스 가운데 드래그**: 카메라 평행 이동
* **Ctrl + 마우스 왼쪽 드래그**: 카메라 줌(또는 마우스 휠로도 조정 가능)

원하는 시점을 맞춘 상태에서 “Views” 탭을 열고 “Save Current to View” 기능 등을 이용해 특정 시점을 즐겨찾기처럼 저장할 수 있다.

#### RViz2에서 다중 로봇 시각화

하나의 RViz2 인스턴스에서 여러 로봇을 시각화해야 할 때가 있다. 예를 들어, 서로 다른 URDF를 가진 로봇 두 대가 각각 독립된 TF 트리를 가지고 있으며, 토픽 이름도 다를 수 있다.

1. **TF Prefix 활용**:
   * RobotModel Display마다 “TF Prefix”를 달리 설정하거나, 로봇 URDF에서 미리 접두어를 지정한다.
   * 예: 첫 번째 로봇의 base\_link → `robot1/base_link`, 두 번째 로봇 → `robot2/base_link`
2. **다중 Display**:
   * ‘RobotModel’ Display를 여러 개 추가한다.
   * 각각 “Description Source”를 “Parameter”로 설정하되, 파라미터 이름도 다르게(예: `robot_description_1`, `robot_description_2`) 구성한다.
3. **Topic 네임스페이스(namespace)**
   * 각 로봇이 토픽을 발행할 때 namespace를 다르게 설정하면, LaserScan, Odometry 등도 구분해서 Display를 추가로 구성 가능하다.

이러한 방식으로 단일 RViz2 창 안에서 여러 로봇을 동시에 모니터링하거나 시뮬레이션할 수 있다.

#### 로봇 애니메이션(조인트 움직임) 확인

ROS2에서 조인트 상태 정보를 확인할 때, 주로 `JointState` 메시지를 사용한다. 이를 `robot_state_publisher` 노드와 함께 사용하면, 로봇의 조인트 값이 실시간으로 TF 트리에 반영되고, RViz2 상의 로봇 모델도 애니메이션처럼 움직인다.

1. **JointStatePublisher GUI**
   * ROS1에서 사용하던 `joint_state_publisher_gui` 패키지가 ROS2용으로도 제공된다.
   * 해당 GUI에서 각 조인트를 슬라이더로 조절하면, `joint_states` 토픽이 발행되어 실시간으로 RViz2에서 로봇이 움직인다.
2. **직접 JointState 발행**
   * 센서나 제어 모듈 등에서 계산된 조인트 값($\theta$ 등)을 `sensor_msgs/msg/JointState` 형식으로 발행한다.
   * 메시지 내부에는 `name`(조인트 이름 목록), `position`(각 조인트의 위치, 일반적으로 라디안), `velocity`, `effort` 등이 담긴다.

이렇게 발행된 조인트 정보는 `robot_state_publisher`가 수신하여 TF 트리를 업데이트하고, RViz2가 그 TF 정보를 구독해 실시간으로 조인트 변화를 표현한다.

#### RViz2 플러그인(Plugin) 활용

ROS2 생태계에는 다양한 RViz2 플러그인이 존재한다. 예를 들어, 이미지 데이터를 표시하는 Image Display, AR(증강현실) 시각화 기능을 더해주는 플러그인 등이 있다. 프로젝트 요구사항에 따라 플러그인을 설치하고 활용하면, URDF로 정의된 로봇 모델 외에도 복합적인 시뮬레이션 환경을 구성할 수 있다.

* **rviz\_visual\_tools**:
  * Marker, Interactive Marker, RobotState, 경로(Path) 등 다양한 RViz2 시각화 기능을 제공하는 라이브러리
  * 복잡한 디버깅 과정을 간단히 시각화하고, 조작하는 데 도움을 준다.
* **interactive\_markers**:
  * RViz2에서 3D 공간상에 마커를 띄워 놓고, 사용자가 마우스로 조작해 명령을 내리는 데 활용
  * 예: 로봇의 End Effector를 잡아당겨서 목표 좌표를 설정하고, 그 결과를 즉시 확인

플러그인마다 설치 및 사용 방법이 조금씩 다르므로, ROS2 패키지 관리자를 통해 패키지를 설치하고, RViz2 실행 시 해당 플러그인을 로드하면 된다.

#### RViz2에서 발생할 수 있는 문제 해결(디버깅) 팁

**1. 로봇 모델이 보이지 않음**

1. **Fixed Frame 설정 확인**
   * RViz2 좌측 상단 “Global Options”에서 “Fixed Frame”을 올바른 링크(보통 `base_link` 또는 `world`)로 설정했는지 확인한다.
   * `robot_state_publisher`가 TF를 정상적으로 퍼블리시하고 있는지도 체크한다.
2. **URDF 파라미터 로딩 여부**
   * `robot_description` 파라미터가 비어 있거나, 오탈자로 다른 이름이 되어 있으면 로봇 모델이 표시되지 않는다.
   * 로봇 모델(XACRO→URDF 변환)이 정상적으로 변환되었는지, `<material>` 등에서 리소스 파일의 경로(예: `.dae`, `.stl`)가 잘못되지 않았는지 확인한다.

**2. 링크 색상이 검정색/회색으로만 보임**

1. 재질(Material) 파일 경로 오류
   * URDF에서 `<mesh filename="package://..."/>` 경로를 사용할 때, 재질이나 텍스처 파일(.png 등)이 누락되거나 경로가 잘못되면 색상이 적용되지 않을 수 있다.
2. COLLADA(.dae) 혹은 STL 파일의 UV 맵/텍스처 문제
   * 일부 3D 모델링 툴에서 내보낸 `.dae`, `.stl` 파일에 텍스처 정보가 제대로 들어있지 않은 경우가 있다.
   * 텍스처 없이 기본 색만 적용하려면 `<color>` 태그나 `<material>` 태그를 URDF에 직접 정의해볼 수 있다.

**3. TF 프레임 겹침(Warning)**

* RViz2 창 하단에 “No transform from X to Y” 경고가 뜬다면, TF 트리가 끊겼거나, 퍼블리시가 늦게 시작되는 상황일 수 있다.
* `tf2_tools` 등의 패키지를 사용해 현재 TF 트리를 그려보거나, `ros2 run tf2_tools view_frames` 명령어 등을 통해 TF를 확인한다.
* 조인트 이름이 중복되거나, 하나의 링크가 서로 다른 부모를 갖도록 정의된 경우도 주의해야 한다.

**4. Interactive Marker가 반응하지 않음**

* RViz2에서 “Interact” 툴이 활성화되어 있는지 확인한다.
* Interactive Marker를 퍼블리시하는 노드가 제대로 동작하는지, 해당 마커 토픽을 RViz2가 구독 중인지 체크한다.
* TF Prefix나 네임스페이스가 달라서 인식 못 하는 경우도 있다. 토픽 이름이 일치하는지 살펴본다.

**5. URDF에서 조인트 움직임 반영이 안 됨**

1. JointState 메시지 불일치
   * URDF의 `<joint name="joint1">`와 `JointState` 메시지의 `name` 필드(예: `["joint1"]`)가 정확히 일치하는지 확인한다.
2. robot\_state\_publisher 노드 누락
   * 단순히 URDF만 파라미터에 올려놓고 `robot_state_publisher`를 실행하지 않으면 TF가 갱신되지 않는다.
3. JointStatePublisher GUI
   * `ros2 run joint_state_publisher_gui joint_state_publisher_gui` 등을 실행했을 때 조인트 슬라이더가 표시되는지, RViz2에서 움직임이 반영되는지 확인한다.

#### RViz2 성능 최적화

**1. Mesh Simplification**

* 복잡한 3D 메시는 렌더링에 많은 자원을 사용하므로, STL/DAE 파일을 3D 모델링 소프트웨어에서 간소화(Decimation/Simplify) 처리할 수 있다.
* RViz2 상에서 FPS가 떨어진다면, 메시 파일의 폴리곤 수를 줄여보거나 충돌 모델과 시각화 모델을 분리해 가볍게 만든다.

**2. Display Update Rate**

* 각 Display 항목마다 Update Rate(초당 업데이트 횟수)를 조정할 수 있다.
* 조인트 움직임 테스트 등 필요 시에만 높은 업데이트 주기를 사용하고, 불필요한 경우 낮춰주면 CPU 사용량을 줄일 수 있다.

**3. 불필요한 Display 비활성화**

* LaserScan, PointCloud2 등 방대한 양의 센서 데이터를 시각화할 때는 성능 저하가 심할 수 있다.
* 디버깅에 필요 없는 Display는 끄거나 제거해, 더 나은 프레임레이트를 확보한다.

#### RViz2와 시뮬레이터 연동

Gazebo나 Ignition, Webots 등과 같은 시뮬레이터에서 동작 중인 로봇을 RViz2에서 모니터링할 수도 있다. 이 경우 시뮬레이터가 로봇의 URDF를 로드하고, `/joint_states`, TF, 센서 데이터 등을 ROS2 Topic으로 퍼블리시한다. 사용자는 다음과 같은 절차로 RViz2 시각화를 세팅한다.

1. 시뮬레이터에서 로봇 구동 (예: Gazebo)
2. 시뮬레이터가 퍼블리시하는 `/joint_states`, `/tf`, 센서 토픽(예: `/scan`, `/camera/points`) 확인
3. RViz2 실행 후 로봇 모델(URDF) 로딩
4. LaserScan, TF, RobotModel, PointCloud2 등을 적절히 연결하여 시각화

시뮬레이터와 RViz2가 모두 움직이는 환경에서는, 로봇 모델 상태와 시뮬레이터 환경 간 TF 트리가 제대로 연결되어 있는지(예: `world` → `robot_base_link`) 반드시 확인한다.
