제11부 도구·관측성
11.4 RViz2와 플러그인 작성
11.4.1 이 장에서 배우는 것 / 선수 지식
RViz2는 ROS에서 가장 많이 쓰이는 도구이자 가장 자주 오해되는 도구다. 오해의 핵심은 이것이다 — RViz2는 "로봇의 상태"를 보여주지 않는다. "발행된 메시지"를 보여준다. 그 둘은 같지 않다.
이 구분이 진단에서 결정적이다. RViz2에 뭔가 안 보일 때, 원인은 ① 발행이 없음 ② QoS 불일치 ③ tf가 없음 ④ 설정 문제 중 하나이고, 각각 조치가 다르다(11.4.9).
배우는 것:
- 구조 — 디스플레이·패널·툴·뷰 컨트롤러.
- 고정 프레임 — 가장 자주 잘못 설정되는 것.
- 성능 — 무엇이 비용이 큰가.
- 설정 관리 —
.rviz파일. - 마커 — 코드에서 그리는 간단한 방법.
- 인터랙티브 마커 — 조작 가능한 시각화.
- 플러그인 작성 — 디스플레이·패널.
- 진단 — "안 보인다"의 체계적 해결.
선수 지식: 1.6(QoS), 5.1·5.2(tf), 1.1.4(토픽), 4.5(빌드), 4.2.6(pluginlib).
정직: RViz2 플러그인 API(클래스명·시그니처)는 버전 의존이며
(확인 필요), Qt·Ogre 지식을 요구한다. 이 장은 구조와 판단에 집중하고, 완전한 플러그인 코드는 골격만 제시한다. 이 환경에서 실행 검증하지 않았다(목차 3).(→ 188차 확인: RViz2 자체를 헤드리스로 실제 실행했고(Xvfb 필요, 아래 실행 확인(188차) 참고), 11.4.4의 RobotModel·Image 디스플레이 두 마커를 실물 소스(rviz-default-plugins14.1.22)로 확인·정정했다. 플러그인 API 버전 의존성 자체(클래스명·시그니처가 배포판마다 어떻게 다른가)는 이번에도 시도하지 않았다. → 189차 확인: 이 버전 의존성도 Jazzy·Humble 헤더 전수 대조로 확인했다 —rviz_common20%·rviz_default_plugins39%의 공개 헤더가 실제로 달랐고, 시그니처가 완전히 바뀐 항목도 있었다. 아래 실행 확인(189차) 참고.)
실행 확인(189차) — "RViz2 플러그인 API는 버전 의존"이라는 서술을 Jazzy(
rviz_common·rviz_default_plugins14.1.22)와 Humble(11.2.28) 두 배포판의 실물 헤더를 전수 대조해 정량 확인했다. 83·84차의 API-diff 방식(그때는rclcpp)을 재사용했다.rviz_common은 공통 헤더 84개 중 17개(20.2%)가 서로 달랐고(Jazzy 전용 신규 파일 1개,regex_filter_property.hpp),rviz_default_plugins는 공통 헤더 97개 중 38개(39.2%)가 달라 변화율이 두 배 가까이 높았다(Jazzy 전용 신규 파일 3개 —camera_info_display.hpp는 완전히 새로운 디스플레이 타입,get_transport_from_topic.hpp·point_cloud_transport_display.hpp는 PointCloud2도 Image처럼(11.4.4, 188차)image_transport형 전송 지원을 얻었음을 시사). 가장 크게 바뀐 파일 하나를 분석해 보니 실제로 시그니처가 깨지는 변경이었다 —ROSImageTexture의ImageData생성자가 Humble의(std::string encoding, const uint8_t*, size_t size)(3개 인자)에서 Jazzy의(Ogre::PixelFormat pixformat, const uint8_t*, size_t data_size_in_bytes, bool take_ownership)(4개 인자, 두 번째 인자 타입 자체가 문자열→열거형으로 교체)로 완전히 바뀌었고,getName()·getWidth()등 접근자 메서드도 비-const(Humble, 헤더에 인라인 정의)에서const(Jazzy,.cpp로 분리)로 바뀌었다 — Humble용으로 작성한 플러그인 코드는 이 API를 그대로 쓰면 Jazzy에서 컴파일이 안 된다. 반면 가장 기본이 되는Display기반 클래스 자체는 종료된 ROS1 시절 코드(#if 0) 제거뿐, 사실상 안정적이었다 — 최소한의 디스플레이 플러그인(속성 몇 개 붙인 정도)은 버전 간 이식성이 상대적으로 높지만, 이미지 텍스처·인터랙티브 마커·TF·맵 디스플레이처럼 세부 내장 기능을 변경하는 플러그인일수록 깨질 위험이 크다는 뜻이다. 정직한 한계: 헤더(.hpp)만 전수 대조했고.cpp구현부는 보지 않았다 — 헤더가 그대로인데 구현만 바뀐 경우는 이 방법으로 검출하지 못한다. 실제로 플러그인을 두 버전에 컴파일해 실패를 재현하지는 않았다(헤더 대조만으로 시그니처 불일치를 판단). 원본:tools/gap_harness/gap189/rviz_api_diff/(diff_summary.txt·ros_image_texture_diff.txt·frame_manager_iface_diff.txt·findings_summary.txt).
11.4.2 구조
| 구성 | 역할 | 예 |
|---|---|---|
| 디스플레이 | 토픽·tf를 3D로 그림 | LaserScan·PointCloud2·RobotModel·Map |
| 패널 | 부가 UI | Displays·Views·Tool Properties·Nav2 Goal |
| 툴 | 마우스 조작 | 2D Goal Pose·Publish Point·Select |
| 뷰 컨트롤러 | 카메라 모드 | Orbit·TopDownOrtho·FPS |
모두 pluginlib 기반이라 확장 가능하다(11.4.7).
렌더링은 Ogre가 한다:
| 결과 | 설명 |
|---|---|
| GPU 사용 | 드라이버 문제가 RViz2 문제로 나타남 |
| 원격 실행 어려움 | X 포워딩이 느림(11.4.6)(→ 188차 확인: 원격이 느린 이유이자 동시에 헤드리스가 완전히 불가능하지는 않은 이유를 실측으로 밝혔다 — Xvfb로 가상 디스플레이를 주면 GPU·원격 접속 없이도 완전히 동작한다. 아래 실행 확인(188차) 참고.) |
| 3D 성능 특성 | 점 개수가 직접 영향 |
실행 확인(188차) — RViz2가 정말 디스플레이 없이는 기동되지 않는지, Gazebo Harmonic의 카메라 센서(162차)처럼 자동으로 헤드리스 전환이 되는지 직접 실행으로 확인했다. 결론: 안 된다 — 하지만 Xvfb를 주면 완전히 동작한다. 세 조건을 순서대로 시험했다. ①
DISPLAY자체를 안 준 채rviz2를 그대로 실행 — Qt가 전혀 시작하지 못하고 즉시 코어 덤프로 종료된다("qt.qpa.xcb: could not connect to display","Could not load the Qt platform plugin \"xcb\"") — Ogre 이전에 Qt 레이어에서부터 실패한다. ②QT_QPA_PLATFORM=offscreen으로 Qt의 자체 헤드리스 플랫폼을 명시 지정 — Qt 단계는 통과하지만, 이번엔 더 안쪽의 Ogre 1.x(GLX 기반,rviz-ogre-vendor) 렌더링 엔진이 명시적으로 예외를 던지며 종료된다("Ogre::RenderingAPIException: Couldn't open X display") — Gazebo Harmonic의 Ogre2(162차)와 달리, RViz2의 Ogre 1.x/GLX 렌더러는 디스플레이 부재를 스스로 감지해 소프트웨어 렌더링으로 자동 전환하는 기능이 없다. ③Xvfb :99 -screen 0 1280x1024x24를 실행하고DISPLAY=:99로rviz2실행 — 완전히 정상 기동했다: 로그에"OpenGl version: 4.5 (GLSL 4.5)"가 출력되고(Xvfb+Mesa 소프트웨어 렌더링으로 실제 OpenGL 컨텍스트를 얻음),timeout으로 강제 종료할 때까지 안정적으로 계속 실행됐다(크래시 아님).xwd+ImageMagick으로 화면을 실제로 캡처하니(rviz2_screen.png) 메뉴바·전체 툴바(Interact·Move Camera·Select·Focus Camera·Measure·2D Pose Estimate·2D Goal Pose·Publish Point)·Displays 패널(Fixed Frame=map, Grid가 3D 뷰포트에 실제로 격자를 그리고 있음)·Views 패널(Orbit 뷰 컨트롤러 속성 전체)·상태 바("RViz is ready", ROS/Wall Time 둘 다 흐름, 31 fps)까지 완전하고 실제로 작동하는 GUI임을 시각적으로 확인했다(단순히 "종료되지 않았다"가 아니라 실제 인터랙티브 수준 렌더링). 정직한 결론: "헤드리스에서 GPU·디스플레이 없이 렌더링이 된다"(162차, 카메라)는 RViz2에는 그대로 적용되지 않는다 — RViz2는 Xvfb(또는 다른 가상 X 서버)가 반드시 있어야 하며, 그것만 있으면 GPU 없이도 완전히 동작한다. 이는 11.4.6의 "X 포워딩이 느리다"는 서술과 정합적이다 — RViz2가 정말로 X 서버(실물·포워딩·가상 불문)를 필요로 한다는 것을 실측으로 확인한 것이다. 원본:tools/gap_harness/gap188/rviz_test/(rviz2_screen.png·findings_summary.txt).
11.4.3 고정 프레임
RViz2 설정에서 가장 자주 잘못되는 항목이다.
고정 프레임(Fixed Frame)은 "세계가 정지해 있다고 볼 기준"이다.
| 고정 프레임 | 보이는 것 | 용도 |
|---|---|---|
| map | 로봇이 지도 위를 움직임 | 측위·항법 확인 |
| odom | 로봇이 부드럽게 움직임, 지도는 튐 | 오도메트리 확인(5.1.7) |
| base_link | 로봇이 정지, 세계가 움직임 | 센서 배치 확인 |
견해: 고정 프레임을 바꿔 보는 것이 강력한 진단 기법이다.
odom기준에서 스캔이 잘 겹치면 오도메트리가 좋은 것이고,map기준에서 스캔이 급변하면 측위가 흔들리는 것이다(5.1.7의 "odom은 연속·map은 점프"가 눈에 보인다).
함정: 고정 프레임으로 가는 tf가 없으면 아무것도 안 보인다. "Global Status: Error — Fixed Frame [map] does not exist"가 출력된다.
map이 없으면(측위 미실행)odom이나base_link로 바꾼다.
Global Options:
| 옵션 | 의미 |
|---|---|
| Fixed Frame | 위 |
| Background Color | 배경 |
| Frame Rate | 렌더 목표 — 낮추면 CPU 절약 |
11.4.4 주요 디스플레이
| 디스플레이 | 토픽 | 주의 |
|---|---|---|
| TF | /tf·/tf_static | 프레임 다수면 부하가 큼 — 필요한 것만 표시 |
| RobotModel | robot_description(5.3.8) | 토픽·파라미터 방식 확인(확인 필요)(→ 188차 확인: 토픽이 기본, 파일도 가능 — 파라미터는 아니다. 아래 실행 확인(188차) 참고) |
| LaserScan | sensor_msgs/LaserScan | QoS를 BEST_EFFORT로(1.6) |
| PointCloud2 | sensor_msgs/PointCloud2 | 가장 부하가 큼 — Decay Time·크기 |
| Image | sensor_msgs/Image | image_transport 미지원(확인 필요)(→ 188차 정정: 이 서술이 틀렸다 — 실제로는 지원한다. 아래 실행 확인(188차) 참고) |
| Map | nav_msgs/OccupancyGrid | TRANSIENT_LOCAL 필요(1.6.3.3) |
| Path | nav_msgs/Path | 경로 시각화 |
| Marker·MarkerArray | visualization_msgs | 커스텀 시각화(11.4.6) |
| Costmap | Map 또는 전용 | Nav2(8.4) |
| PoseWithCovariance | 측위 | 공분산 타원 |
함정: 디스플레이마다 QoS를 설정해야 한다. RViz2 기본이
RELIABLE인 디스플레이에BEST_EFFORT센서를 연결하면 아무것도 안 보인다(1.6.3.1의 최다 사고가 여기서도). 디스플레이 속성의 "Reliability Policy"를 확인한다.
함정:
/map이 안 보이면 Durability를Transient Local로 바꾸라.map_server가TRANSIENT_LOCAL로 한 번만 발행하므로(1.6.3.3),VOLATILE구독자는 못 받는다.
실행 확인(188차) — RobotModel·Image 두 디스플레이의 마커를
apt-get source ros-jazzy-rviz-default-plugins(14.1.22)로 받은 실물 소스로 직접 확인·정정했다. ① RobotModel — "토픽·파라미터 방식"의 정답은 "토픽(기본)·파일, 파라미터는 아님"이다.RobotModelDisplay클래스 자체가rviz_common::RosTopicDisplay<std_msgs::msg::String>를 상속하고,description_source_property_라는EnumProperty(기본값"Topic")에 등록된 옵션은"Topic"과"File"단 둘뿐이다 —"Parameter"옵션은 코드 어디에도 없다. 토픽 모드의 QoS는rclcpp::QoS(rclcpp::KeepLast(1)).transient_local()로 명시돼 있어,/map(1.6.3.3, 바로 위 함정)과 같은 "한 번 발행, 늦게 온 구독자도 받아야 함" 패턴과 정확히 일치한다(관례상robot_state_publisher가 발행하는/robot_description토픽). 정직한 단서: 설치된 헤더의load_urdf()주석은 여전히 "Loads a URDF from the ros-param named by our ... property"라고 적혀 있어 파라미터 시절의 흔적이 남아 있지만, 실제 동작하는 코드는 이미 토픽/파일 드롭다운으로 바뀌어 있다 — 주석이 낡았을 뿐 실제 동작과는 다르다. ② Image — "image_transport미지원"은 틀린 서술이다, 실제로는 지원한다.ImageDisplay클래스는ImageTransportDisplay<sensor_msgs::msg::Image>를 상속하며, 이 기반 클래스가image_transport/image_transport.hpp·image_transport/subscriber_filter.hpp를 실제로 포함하고image_transport::SubscriberFilter를 실제로 사용한다 —getTransportFromTopic()으로 입력한 토픽 이름 자체에서 전송 방식(예:.../compressed)을 읽어 해당 트랜스포트 플러그인을 로드하는, 일반 노드에서 쓰는image_transport::Subscriber와 동일한 방식이다(image_transport::TransportLoadException까지 실제로 처리). 책의 이 항목은 단순히 "확인 안 됨"이 아니라 실제로 틀린 서술이었다. 원본:tools/gap_harness/gap188/rviz_test/source_evidence/(robot_model_display_full.hpp·robot_model_display_source_excerpt.cpp·image_transport_display_source_excerpt.hpp).
11.4.5 성능
RViz2가 느려지는 원인은 대부분 몇 가지로 좁혀진다.
| 원인 | 영향 | 대처 |
|---|---|---|
| PointCloud2 점 개수 | 가장 큼 | 다운샘플·Decay Time 0·Size 축소 |
| Decay Time | 누적 렌더 | 0 또는 짧게 |
| TF 프레임 다수 | 선·이름 렌더 | 필요한 프레임만·이름 끄기 |
| 이미지 다수 | 대역·디코딩 | 필요한 것만 |
| 원격 X 포워딩 | 매우 느림 | 11.4.6 |
| Marker 다수 | 개수에 비례 | 집계·수명 |
| 코스트맵 갱신 | 큰 그리드 | 갱신 빈도 |
견해: "하나씩 끄며 원인을 찾는" 절차가 확실하다. 추측으로 조정하기보다 5초면 원인을 특정할 수 있다.
견해: RViz2가 느려서 시스템이 느린 것으로 오해하는 경우가 흔하다. RViz2는 자원 소모가 큰 GUI이며, RViz2를 끄면 로봇이 정상 동작하는지 반드시 확인하라. 특히 개발 PC가 로봇 온보드일 때 RViz2가 CPU를 잠식해 제어 주기를 깨뜨릴 수 있다(6.6.6).
11.4.6 설정과 원격
.rviz 설정 파일:
# 저장: File → Save Config As
# 실행 시 지정
rviz2 -d $(ros2 pkg prefix my_robot_bringup)/share/my_robot_bringup/rviz/nav.rviz
# launch에서
Node(package='rviz2', executable='rviz2',
arguments=['-d', os.path.join(pkg_share, 'rviz', 'nav.rviz')],
parameters=[{'use_sim_time': use_sim_time}]) # ★ 재생·시뮬 시 필수
견해: 목적별
.rviz를 만들어 패키지에 두라.nav.rviz(항법)·slam.rviz(매핑)·manip.rviz(조작)·debug.rviz(전체). 매번 디스플레이를 추가하는 시간이 사라지고, 팀이 같은 화면을 본다.
함정:
.rviz를 버전 관리에 넣되, 자동 저장되는 변경에 주의하라. RViz2가 종료 시 설정을 덮어쓸 수 있어 의도치 않은 diff가 생긴다(확인 필요: 동작).
함정:
use_sim_time을 RViz2에도 줘야 한다. bag 재생·시뮬에서 이것을 빼면 RViz2가 벽시계로 tf를 조회해 "변환이 미래/과거"라며 아무것도 안 그린다(5.2.4·1.10.9).
원격 실행:
| 방법 | 특성 |
|---|---|
| 개발 PC에서 실행 + 네트워크로 토픽 | 권장 — 로봇 CPU 부담 없음 |
| X 포워딩 | 매우 느림 — 3D 렌더를 네트워크로 |
| VNC·원격 데스크톱 | X보다 나음 |
| 웹 기반 도구 | 대안(확인 필요) |
견해: "개발 PC에서 RViz2를 실행하고 로봇 토픽을 구독"이 기본이다. 다만 대용량 토픽이 무선을 잠식하므로(3.9.3·7.8), 포인트클라우드·원본 이미지는 필요할 때만 켜고
image_transport의 압축을 쓴다(7.2.7).
함정: RViz2가 구독하는 순간 대역이 발생한다. 디스플레이를 켜 둔 채 로봇을 운영하면 무선이 포화될 수 있다. 운영 중에는 끄라.
11.4.7 마커 — 코드에서 그리기
플러그인을 만들지 않고 커스텀 시각화를 하는 가장 쉬운 방법이다.
#include <visualization_msgs/msg/marker_array.hpp>
visualization_msgs::msg::Marker m;
m.header.frame_id = "map";
m.header.stamp = now();
m.ns = "detections"; // 네임스페이스
m.id = 0; // ns 안에서 고유
m.type = visualization_msgs::msg::Marker::SPHERE;
m.action = visualization_msgs::msg::Marker::ADD;
m.pose.position.x = 1.0;
m.pose.orientation.w = 1.0; // ★ 0이면 경고·미표시
m.scale.x = m.scale.y = m.scale.z = 0.2;
m.color.r = 1.0; m.color.a = 1.0; // ★ a=0이면 투명 — 안 보임
m.lifetime = rclcpp::Duration::from_seconds(1.0); // 자동 소멸
| 타입 | 용도 |
|---|---|
| ARROW·SPHERE·CUBE·CYLINDER | 기본 도형 |
| LINE_STRIP·LINE_LIST | 경로·연결 |
| POINTS | 다수 점 — 효율적 |
| TEXT_VIEW_FACING | 라벨 |
| MESH_RESOURCE | 3D 모델 |
| TRIANGLE_LIST | 임의 표면 |
함정: 가장 흔한 두 실수 —
orientation.w = 0(쿼터니언이 무효)과color.a = 0(완전 투명). 둘 다 "마커가 안 보인다"의 대표적 원인이다.w = 1.0과a = 1.0을 기본으로 두라.
함정:
lifetime을 0(무한)으로 두고 매 프레임 새id를 쓰면 마커가 무한 누적된다. RViz2가 느려지고 메모리를 소모한다. 같은id를 재사용하거나lifetime을 설정한다.
견해:
MarkerArray로 묶어 한 번에 보내라. 개별Marker를 다수 발행하는 것보다 효율적이고, 원자적으로 갱신된다.
삭제:
m.action = visualization_msgs::msg::Marker::DELETE; // 하나
m.action = visualization_msgs::msg::Marker::DELETEALL; // 전체
인터랙티브 마커:
| 용도 | 예 |
|---|---|
| 목표 자세 지정 | 드래그로 위치 설정 |
| 캘리브레이션 조정 | 프레임 미세 조정 |
| 교시 | 로봇 자세 지정(9.4) |
| 파라미터 조정 | 3D로 |
견해: 인터랙티브 마커는 만들 가치가 있는 경우가 분명하다 — 3D 공간에서 값을 지정해야 하는 작업. 숫자를 입력하는 것보다 훨씬 빠르다. 다만 구현 비용이 있으므로, 반복적으로 하는 작업에만 만든다.
11.4.8 플러그인 작성
마커로 안 되는 것이 있을 때 플러그인을 만든다.
| 마커로 충분 | 플러그인이 필요 |
|---|---|
| 도형·선·점·텍스트 | 커스텀 메시지 타입 직접 표시 |
| 정적 시각화 | 대량 데이터 효율적 렌더 |
| 단순 표시 | 속성 UI로 제어 |
| — | 패널 UI(버튼·입력) |
견해: 대부분의 경우 마커로 충분하다. 플러그인은 Qt·Ogre·pluginlib 지식이 필요하고 버전 의존성이 있다. "커스텀 메시지를 RViz2에서 직접 보고 싶다"거나 "조작 패널이 필요하다" 같은 명확한 이유가 있을 때만 만든다.
디스플레이 플러그인 골격:
// my_display.hpp
#include <rviz_common/message_filter_display.hpp>
#include <rviz_common/properties/color_property.hpp>
namespace my_rviz_plugins
{
class MyDisplay
: public rviz_common::MessageFilterDisplay<my_msgs::msg::MyThing>
{
Q_OBJECT
public:
MyDisplay();
void onInitialize() override;
void reset() override;
private Q_SLOTS:
void updateColor();
private:
void processMessage(my_msgs::msg::MyThing::ConstSharedPtr msg) override;
rviz_common::properties::ColorProperty * color_property_;
// Ogre 씬 노드·비주얼 객체
};
} // namespace my_rviz_plugins
// my_display.cpp
#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS(my_rviz_plugins::MyDisplay, rviz_common::Display)
<!-- plugins_description.xml -->
<library path="my_rviz_plugins">
<class name="my_rviz_plugins/MyDisplay"
type="my_rviz_plugins::MyDisplay"
base_class_type="rviz_common::Display">
<description>내 커스텀 메시지 표시</description>
<message_type>my_msgs/msg/MyThing</message_type>
</class>
</library>
# CMakeLists.txt
set(CMAKE_AUTOMOC ON) # ★ Qt MOC
find_package(rviz_common REQUIRED)
find_package(Qt5 REQUIRED COMPONENTS Widgets)
add_library(my_rviz_plugins SHARED src/my_display.cpp)
target_link_libraries(my_rviz_plugins Qt5::Widgets)
ament_target_dependencies(my_rviz_plugins rviz_common rviz_rendering my_msgs)
pluginlib_export_plugin_description_file(rviz_common plugins_description.xml)
정직: 클래스 계층·헤더 이름·필수 매크로는 버전 의존이다
(확인 필요). RViz2 소스의 기존 플러그인(예:rviz_default_plugins)을 참조해 현재 API를 확인하는 것이 가장 확실하다.
패널 플러그인:
#include <rviz_common/panel.hpp>
class MyPanel : public rviz_common::Panel
{
Q_OBJECT
public:
explicit MyPanel(QWidget * parent = nullptr);
void onInitialize() override; // 노드 접근
void save(rviz_common::Config config) const override; // 설정 저장
void load(const rviz_common::Config & config) override;
};
| 패널 용도 | 예 |
|---|---|
| 운영 버튼 | 시작·정지·복귀 |
| 상태 표시 | 배터리·모드·진단 |
| 파라미터 조정 | 슬라이더 |
| 작업 트리거 | 미션 실행 |
견해: 운영자용 패널은 투자 가치가 높다. 현장에서 터미널로 서비스를 호출하게 하는 것보다, 버튼 몇 개가 있는 패널이 훨씬 안전하고 빠르다. 다만 운영 UI를 RViz2에 의존하는 것이 옳은지는 별개 판단이다 — 전용 UI가 나을 수 있다.
함정:
Q_OBJECT를 쓰면CMAKE_AUTOMOC ON이 필요하다. 빠뜨리면 링크 오류(vtable 없음)가 난다.
11.4.9 "안 보인다" 진단
RViz2 진단의 표준 절차다.
| 증상 | 확인 | 원인 |
|---|---|---|
| Fixed Frame does not exist | ros2 run tf2_tools view_frames | tf 없음(5.2.5) |
| No messages received | ros2 topic hz | 미발행 |
| 발행되는데 안 옴 | ros2 topic info -v | QoS 불일치(1.5.4) |
| 상태 OK인데 안 보임 | 설정 | alpha 0·크기 0·색 배경과 동일 |
| 비정상적인 위치 | tf | 프레임 오설정(5.1.8) |
| 깜빡임 | 두 발행자 | tf 중복(5.1.4) |
| 뒤집힘 | optical frame | REP 105·103(7.1.4) |
견해: "Display Status를 먼저 보라"가 첫 단계다. RViz2가 이미 원인을 말해 주는 경우가 많은데, 상태 창을 펼치지 않아 놓친다. 각 디스플레이를 확장하면 Topic·Status가 나온다.
견해: RViz2에서 보이는 것과 알고리즘이 받는 것이 다를 수 있다(11.4.1의 반복). RViz2 디스플레이의 QoS는 별도 설정이라, RViz2에는 보이는데 노드는 못 받거나 그 반대일 수 있다.
ros2 topic info -v로 실제 연결을 확인하는 것이 확실하다(1.5.6).
11.4.10 함정 카탈로그
| # | 함정 | 증상 | 대처 |
|---|---|---|---|
| 1 | QoS 불일치 | 아무것도 안 보임 | 디스플레이 QoS 설정 |
| 2 | /map Durability | 지도 안 보임 | Transient Local |
| 3 | Fixed Frame 부재 | Global Status Error | 프레임 변경·tf 확인 |
| 4 | use_sim_time 누락 | 재생 시 안 보임 | RViz2에도 설정 |
| 5 | orientation.w = 0 | 마커 안 보임·경고 | w = 1.0 |
| 6 | color.a = 0 | 투명 | a = 1.0 |
| 7 | 마커 무한 누적 | 느려짐·메모리 | id 재사용·lifetime |
| 8 | PointCloud2 과다 | 매우 느림 | 다운샘플·Decay 0 |
| 9 | X 포워딩 | 매우 느림 | 로컬 실행 |
| 10 | 운영 중 RViz2 구독 | 무선 포화 | 끄기 |
| 11 | 온보드 RViz2 | 제어 주기 방해 | 원격 실행 |
| 12 | Display Status 미확인 | 시행착오 | 먼저 확인 |
| 13 | CMAKE_AUTOMOC 누락 | 링크 오류 | 설정 |
| 14 | RViz2 표시를 알고리즘 입력으로 오해 | 잘못된 진단 | topic info -v |
11.4.11 체크포인트
- "RViz2는 로봇 상태가 아니라 발행된 메시지를 보여준다"는 말의 진단적 함의는?
- RViz2의 네 구성 요소와 각각의 예를 들 수 있는가.
- 고정 프레임 셋과 각각이 보여주는 것을 말할 수 있는가. 진단 기법으로 어떻게 쓰는가.
- 주요 디스플레이의 QoS 함정 둘은 무엇인가.
- RViz2 성능 저하 원인 일곱 가지와, 원인을 찾는 절차는?
- RViz2가 로봇 성능에 미치는 영향과, 온보드 실행의 위험은?
- 목적별
.rviz를 만들라는 조언의 근거는? - 원격 실행 네 방법과 권장안, 그리고 그 대가는?
- 마커의 두 가지 최다 실수와 누적 문제의 원인·대처는?
- 마커로 충분한 경우와 플러그인이 필요한 경우를 구분할 수 있는가.
- 패널 플러그인의 용도와, "운영 UI를 RViz2에 두는 것"에 대한 판단은?
- "안 보인다" 진단의 첫 단계와, 증상별 원인 일곱 가지를 말할 수 있는가.
다음 장 11.5은 rqt·PlotJuggler — 그래프·시계열·로그를 다루는 분석 도구들이다.