제11부 도구·관측성
11.3 기록·재생 전략
11.3.1 이 장에서 배우는 것 / 선수 지식
11.2가 도구였다면 이 장은 운용이다. 무엇을 기록할 것인가, 언제 기록할 것인가, 데이터를 어떻게 관리할 것인가, 재생을 어떻게 활용할 것인가.
이 결정들이 중요한 이유는 기록의 가치가 시점에 달렸기 때문이다. 문제가 발생한 뒤에 기록을 시작하면 늦고, 모든 것을 항상 기록하면 디스크가 감당하지 못한다. 적은 비용으로 필요한 순간을 포착하는 전략이 필요하다.
배우는 것:
- 계층적 기록 — 무엇을 항상, 무엇을 가끔.
- 순환 버퍼와 이벤트 기록 — 과거를 기록하는 법.
- 재생 옵션 — 속도·반복·구간·리매핑.
- 시뮬 시간과 재생 —
--clock의 의미. - 재생 시 충돌 — tf·중복 발행.
- 저장 관리 — 회전·업로드·보존.
- 회귀 데이터셋 — bag을 자산으로.
- 개인정보·보안 — 기록의 위험.
선수 지식: 11.2(rosbag2), 1.10(시간·use_sim_time), 5.1.4(tf 단일 부모), 8.8.6(항법 디버깅 기록), 10.6.6(bag 재생 활용), 6.9(진단).
정직: 재생 옵션·플래그는 배포판에 따라 다르다
(확인 필요)(→ 163차 정정: Jazzy에서는ros2 bag record --help/ros2 bag play --help로 이 장에 언급된 플래그가 모두 실재함을 확인했다 — 11.3.3·11.3.4 실행 확인(163차) 참고. 저장 관리·업로드는 여전히 검증하지 않았다). 저장 관리·업로드는 조직 인프라에 의존하므로 개념과 판단 기준만 다룬다. 이 환경에서 검증하지 않았다(목차 3).
11.3.2 계층적 기록
모든 것을 항상 기록할 수는 없다. 계층으로 나눈다.
| 계층 | 대상 | 기간 | 용량 |
|---|---|---|---|
| ① 상시 | tf·odom·/cmd_vel·진단·/rosout | 며칠~몇 주 | 작음 |
| ② 순환 | 스캔·압축 이미지 | 최근 30~120초 | 중간 |
| ③ 이벤트 | ②의 버퍼를 디스크로 | 사건마다 | 중간 |
| ④ 세션 | 전체(코스트맵·원본 이미지) | 디버깅 중 | 큼 |
①에 넣을 토픽:
ros2 bag record \
/tf /tf_static /odom /cmd_vel \
/diagnostics /diagnostics_agg /rosout \
/amcl_pose /scan \
--max-bag-duration 600 -o /var/log/robot/always
견해:
/diagnostics와/rosout을 상시 기록에 반드시 넣으라(1.11.9·6.9.8의 반복). 작고, 사후 분석에서 "그 시점에 시스템이 무슨 상태였나"를 알려주는 유일한 단서인 경우가 많다.
견해:
/tf와/odom도 작으면서 가치가 크다. 로봇이 어디에 있었고 어떻게 움직였는지가 대부분의 분석의 출발점이다./scan은 크기에 따라 판단하되, 2D 라이다는 작아서(7.8.2) 대개 포함할 만하다.
④에서만 기록할 것:
| 토픽 | 이유 |
|---|---|
| 원본 이미지·포인트클라우드 | 대역 폭증(11.2.6) |
| 코스트맵 | 큼(8.8.6) |
| 디버그 시각화 | 불필요 |
11.3.3 순환 버퍼와 이벤트 기록
7.8.6에서 언급한 패턴이다. "사건이 일어난 직전"을 검출하는 유일한 방법이다.
왜 필요한가: 문제가 발생한 뒤에 기록을 시작하면 원인이 담기지 않는다. 원인은 결과보다 먼저 일어난다.
구현 방법:
| 방법 | 설명 |
|---|---|
| snapshot 서비스 | rosbag2가 제공하는 스냅숏 모드(확인 필요: Jazzy 지원)(→ 163차 정정: Jazzy에서 실재하고 실제로 동작함을 기동 테스트로 확인했다 — 아래 실행 확인(163차) 참고) |
| 자체 구현 | 순환 버퍼 노드 + 저장 트리거 |
| 짧은 분할 + 보존 | 분할된 파일 중 사건 시점 것만 남김 |
# 스냅숏 모드 (확인 필요: 옵션·서비스 이름)(→ 163차 정정: 옵션·서비스 이름 모두 아래 그대로 동작함을 확인했다)
ros2 bag record -a --snapshot-mode -o /var/log/robot/snapshots
# 트리거
ros2 service call /rosbag2_recorder/snapshot rosbag2_interfaces/srv/Snapshot "{}"
세 번째 방법이 단순하고 견고하다:
# 30초 단위로 분할해 계속 기록
ros2 bag record -a --max-bag-duration 30 -o /var/log/robot/rolling
# 별도 스크립트가 오래된 파일 삭제 (예: 최근 20개만)
# 사건 발생 시 그 시점 파일들을 별도 디렉터리로 복사
견해: "짧은 분할 + 외부 정리"가 구현이 단순하고 도구 버전에 덜 의존한다. 스냅숏 기능이 있으면 쓰되, 없거나 동작이 불확실하면 이 방법이 확실하다.
이벤트 트리거:
| 트리거 | 예 |
|---|---|
| 충돌·비상정지 | 안전 이벤트(8.7) |
| 항법 실패 | ABORTED(8.7.6) |
| 진단 ERROR | 임계 초과(6.9.7) |
| 파지 실패 | 반복 실패(9.5.8) |
| 사람 요청 | 버튼·명령 |
견해: 진단 시스템(6.9)과 기록 트리거를 연결하면 강력하다. ERROR가 출력되면 자동으로 스냅숏을 저장하게 하면, 문제가 재현되기를 기다리지 않아도 데이터가 모인다.
실행 확인(163차, Jazzy) —
--snapshot-mode를 실제로 기동해 트리거 전/후 동작, 트리거 없이 종료한 경우, 종료 신뢰성을 확인했다.
- 트리거 전에는 디스크에 0바이트.
ros2 bag record --topics /counter --snapshot-mode -o snapshot_bag로 기동한 뒤/counter를 5Hz로 계속 발행해도, 서비스를 호출하기 전에는.mcap파일이 0바이트로 그대로였다.ros2 service call /rosbag2_recorder/snapshot rosbag2_interfaces/srv/Snapshot "{}"를 호출하자(response: success=True) 그 즉시 파일이 67105바이트로 늘었다 — 문서 설명("서비스가 호출되기 전에는 메시지가 bag 파일에 쓰이지 않는다")과 정확히 일치한다.- 스냅숏을 한 번도 트리거하지 않고 정상 종료(SIGINT)하면 bag이 비어 있다. 독립된 2회 시도 모두
ros2 bag info결과Messages: 0이었다 —metadata.yaml과duration·토픽 목록은 정상 기록되는데도 실제 메시지는 하나도 없다. 이때 퍼블리셔가ros2 topic hz /counter로 5.001Hz 실발행 중임을 별도로 확인했으므로 퍼블리셔 부재가 아니라 스냅숏 모드 자체의 동작이다. "종료하면 남은 캐시를 자동으로 저장해 준다"는 기대는 틀렸다 — 최소 한 번은 서비스를 호출해야 한다.- 트리거 후 종료하면 그 사이 데이터가 저장되지만, 발행량 대비 절반가량만 기록됐다. 트리거 1회 후 SIGINT로 종료한 시도에서
ros2 bag info는Messages: 22(9.6초 구간)를 보고했는데, 이 구간에 5Hz로 발행됐다면 이론상 ~48개가 나와야 한다.--max-cache-size(기본 104857600바이트=100MiB, 더블 버퍼링) 문서를 확인했지만 카운터 메시지 수십 개는 이 한도에 전혀 못 미치므로 크기 초과로 인한 손실은 아니다. 이 절반 손실의 정확한 메커니즘은 규명하지 못했다 — 원인 불명의 부분 손실 현상으로만 정직하게 남긴다.- SIGINT 종료 자체가 비결정적이었다. 최초 시도(수동
kill -INT $PID)는 "Writing remaining messages from cache to the bag" 로그 이후 15초 넘게 멈춰kill -9로 강제 종료해야 했다(metadata.yaml미생성). 이후timeout --signal=INT N <command>패턴으로 격리해 재시도한 2회는 모두 정상 종료됐다. 3회 중 1회의 행(hang)은 재현 조건을 좁히지 못해 "결정적 버그"로 단정하지 않고 "비결정적으로 관찰된 원인 미상의 종료 지연 1건"으로 기록한다.컨테이너
gap163j(ros:jazzy-ros-base+ros-jazzy-rosbag2+ros-jazzy-rosbag2-storage-mcap), ROS_DOMAIN_ID=64. 원본 로그·JSON:tools/gap_harness/gap163/raw_bag_test/(record_snapshot.log~record_snapshot4.log,snapshot_bag~snapshot_bag4).실행 확인(164차, Jazzy) — 방법론 보강:
ros2 bag info의 출력을 파일로 남기며 "트리거 없이 종료" 사례를 다시 재현했다. 163차는ros2 bag info를 화면으로만 확인해 "Messages: 0" 텍스트가 원시 로그 파일에 남지 않았다(코디네이터 지적, 133차 UBSAN 텍스트 누락과 같은 유형). 이번엔 그 출력을 그대로baginfo_snap0.log에 리다이렉트해 재확인했다 — 결과는 동일하게Messages: 0이었고, 이번엔 그 근거가 파일에 그대로 남았다. 163차 2회 + 164차 1회, 3회 연속 재현. 원본:tools/gap_harness/gap164/raw_bag_test/baginfo_snap0.log.
11.3.4 재생
# 기본
ros2 bag play my_bag
# 속도 조절
ros2 bag play my_bag --rate 0.5 # 절반 속도
ros2 bag play my_bag --rate 2.0 # 2배
# 반복
ros2 bag play my_bag --loop
# 구간
ros2 bag play my_bag --start-offset 30 # 30초 지점부터
ros2 bag play my_bag --playback-duration 60 # 60초만
# 토픽 선택
ros2 bag play my_bag --topics /scan /tf /tf_static
# 리매핑 (1.1.5)
ros2 bag play my_bag --remap /scan:=/scan_replay
# 일시정지·단계 실행
ros2 bag play my_bag --start-paused
# (스페이스로 재생·일시정지, 특정 키로 단계 진행 — 확인 필요)
# 시뮬 시간 발행
ros2 bag play my_bag --clock
정직: 옵션 이름·동작은 배포판 의존이다
(확인 필요)(→ 163차 정정: Jazzy에서--rate·--start-offset·--playback-duration·--clock을 실측으로 확인했다 — 아래 실행 확인(163차) 참고).ros2 bag play --help가 정본이다.
QoS 오버라이드:
ros2 bag play my_bag --qos-profile-overrides-path qos_override.yaml
기록된 QoS(11.2.7의 offered_qos_profiles)가 기본으로 쓰이지만, 필요하면 바꾼다.
함정:
TRANSIENT_LOCAL토픽(/map·/tf_static— 1.6.3.3)의 재생 동작을 확인하라. 재생 시작 시 한 번만 나오므로, 늦게 기동된 구독자가 못 받을 수 있다. 재생을 먼저 시작하고 노드를 실행하면 놓친다 — 순서에 유의한다.(→ 163차 정정: 실측해 보니 트리거는 "재생이 구독자보다 먼저 시작됨"이 아니라 "재생 프로세스 자체가 이미 종료됨"이다 — 아래 실행 확인(163차) 참고.ros2 bag play프로세스가 실행 중인 동안은 그 자신의 퍼블리셔가 TRANSIENT_LOCAL 캐시를 계속 유지하므로, 프로세스 생존 중에 뒤늦게 합류하는 구독자도 QoS만 맞으면 여전히 받는다.)
실행 확인(163차, Jazzy) —
--rate·--start-offset+--playback-duration·TRANSIENT_LOCAL 함정을 실측했다.
--rate타이밍 정밀도. 9.6초(48개 메시지, 5Hz) bag 기준:--rate 2.0재생 5.206초(기대 ~4.8초),--rate 0.5재생 19.611초(기대 ~19.2초) — 두 배·절반 속도 모두 기대치에 근접했다.--start-offset 5 --playback-duration 2정밀도. 정확히 10개 연속 메시지(카운터 값 31~40)가 0.2초 간격(5Hz)으로 수신됐다 — 문서 그대로 정확했다.- TRANSIENT_LOCAL 지각 구독자 함정 — 정교화됨. 9.6초 길이의
/counter스트림과 1회성 TRANSIENT_LOCAL/latched_topic메시지를 섞은 bag으로 3가지 조건을 비교했다. ① 재생 시작 전부터 구독: t=2.094초에 수신(대조군). ② 재생 시작 5초 후(재생 프로세스는 아직 실행 중)에 구독: 그래도 수신함. ③ 재생 프로세스가 완전히 종료된 후에 구독: 수신 없음([]). ②가 원래 문언("재생을 먼저 시작하면 놓친다")과 어긋난다 — 실제로 잃는 조건은 재생 프로세스의 종료이지, 구독 시점이 재생 시작보다 늦다는 사실 자체가 아니다.컨테이너
gap163j, ROS_DOMAIN_ID=64. 원본 로그:tools/gap_harness/gap163/raw_bag_test/(play_rate2.log·play_rate05.log·play_offset.log·play_combined_early.log·play_combined_late.log·play_combined_finished.log, 결과 JSONearly_sub_result.json·late_sub_result.json·after_finish_result.json).
11.3.5 시뮬 시간과 재생
--clock이 무엇을 하는가.
| 설정 | 결과 |
|---|---|
--clock + use_sim_time: true | bag 시각으로 일관 |
--clock 없음 + use_sim_time: true | 시간이 0에 멈춤(1.10.9의 1번) |
--clock + use_sim_time: false | 노드는 벽시계 — 스탬프 불일치 |
견해: bag 재생 분석에는
--clock+use_sim_time: true가 기본이다. 그래야 tf 조회·시간 정합이 bag 시각 기준으로 맞는다(5.2). 일부 노드만use_sim_time이면 대량 외삽 오류가 난다(5.2.4).
함정:
--loop로 재생하면 시간이 뒤로 점프한다(1.10.4). tf 버퍼·필터 상태가 오염되므로, 시간 점프 콜백으로 대응해야 한다(5.2.2.2). 5.2에서 "bag 루프 개발 환경이면 사실상 필수"라고 한 것이 이것이다.
함정:
--rate를 바꾸면 실시간성이 달라진다. 0.5배로 재생하면 노드가 처리할 시간이 두 배 생겨, 실제로는 못 따라가던 것이 따라간다. 성능 평가에는--rate 1.0을 쓰라.
실행 확인(163차, Jazzy) —
--clock/use_sim_time3자 관계를 실측으로 확인했다.--clock사용 시/clock이 384개 메시지 발행됐고 그 sim_time 구간(9.575초)이 원본 bag의 녹화 구간(9.6초)과 일치했다.--clock미사용 시/clock메시지는 0개였다 — 표의 세 행이 모두 실측과 맞았다. (테스트 하네스 쪽 참고: rosbag2_player의/clock퍼블리셔는 BEST_EFFORT QoS를 쓴다 — 기본 RELIABLE 구독으로 만들면 QoS 불일치 경고와 함께 0개 수신되어 "동작 안 함"으로 오판하기 쉽다. 이는 책의 오류가 아니라 이번 회차 테스트 스크립트 자체의 QoS 설정 실수였다.) 원본:tools/gap_harness/gap163/raw_bag_test/play_with_clock2.log,clock_test_result2.json,no_clock_result.json.실행 확인(164차, Jazzy) —
--loop의 시간 역행을 정량으로 확인했다. 3.2초(17개 메시지, 5Hz) bag을--clock --loop로 9초간 재생하며/clock343개를 기록했다. 역방향 점프가 정확히 2회 발견됐다(3회 반복 재생의 경계 2곳과 일치) — 각각 sim_time이 약 3.275초 뒤로 점프했고, 이는 bag의 녹화 구간(3.2015초)과 근사적으로 맞는다. 같은 창에서/counter값을 따로 기록하니[6..22, 6..22, 6..15]로 정확히 같은 시퀀스가 반복됐다 —--loop가 시간만 되감는 것이 아니라 실제로 같은 메시지 시퀀스를 되풀이 재생한다는 것도 함께 확인했다. 원본:tools/gap_harness/gap164/raw_bag_test/loop_clock_analysis.txt,loop_clock_result.json,loop_counter_result.json.
11.3.6 재생 시 충돌
재생 데이터와 실행 중인 노드가 충돌할 수 있다.
| 충돌 | 원인 | 대처 |
|---|---|---|
/tf 중복 | bag과 노드가 같은 변환 발행(5.1.4) | 노드 끄기·리매핑 |
/joint_states 중복 | bag과 RSP·드라이버 | 동일 |
/clock 중복 | 시뮬과 bag | 하나만 |
/map 중복 | bag과 map_server | 동일 |
| 명령 토픽 | bag의 옛 명령이 로봇에 | 재생 시 로봇 분리 |
# tf를 비교용으로만 보고 싶을 때
ros2 bag play my_bag --remap /tf:=/tf_replay /tf_static:=/tf_static_replay
함정: 재생 중인 bag의
/cmd_vel이 실제 로봇에 전달되면 위험하다. 실기와 연결된 상태에서 bag을 재생하면 로봇이 옛 명령대로 움직인다. 재생은 로봇과 분리된 환경에서 하거나, 명령 토픽을 리매핑해 차단한다.
견해: 재생 전용 launch를 만들어 두는 것이 안전하다. 어떤 노드를 실행하고 어떤 토픽을 리매핑할지 고정해 두면, 매번 판단하지 않아도 되고 사고를 막는다.
전형적 재생 구성(10.6.6의 "인지는 bag"):
# SLAM을 bag으로 검증 — 센서·tf_static은 bag에서, SLAM은 실행
def generate_launch_description():
return LaunchDescription([
SetParameter(name='use_sim_time', value=True), # 전체 적용
ExecuteProcess(cmd=['ros2', 'bag', 'play', bag_path, '--clock',
'--topics', '/scan', '/tf_static', '/odom']),
# /tf 는 SLAM이 발행하므로 bag에서 제외
Node(package='slam_toolbox', executable='async_slam_toolbox_node',
parameters=[slam_params]),
])
--topics로 필요한 것만 재생하는 것이 충돌 회피의 핵심이다.
실행 확인(164차, Jazzy) —
--topics필터링을 실측했다./counter·/other_counter두 토픽을 동시에 5Hz로 발행해 녹화하고,ros2 bag info로 두 토픽 모두 실제로 23개씩 녹화됐음을 먼저 확인했다(재생 시 필터링이 "애초에 없어서 안 나오는" 착시가 아님을 보장하기 위함).ros2 bag play --topics /counter로 재생하며 두 토픽을 독립 구독자로 동시 감시하니,/counter는 23개(값 6~28) 전부 수신,/other_counter는 0개였다 — 위 문장이 실측으로 확인됐다. 원본:tools/gap_harness/gap164/raw_bag_test/baginfo_topicsbag.log,topics_counter_result.json,topics_other_result.json.
11.3.7 저장 관리
장기 운영에서 데이터가 쌓인다.
| 정책 항목 | 결정할 것 |
|---|---|
| 로컬 보존 기간 | 디스크 용량에 맞춰 |
| 업로드 조건 | 전부·이벤트만·요청 시 |
| 업로드 시점 | 실시간·유휴 시·도킹 시 |
| 중앙 보존 기간 | 규정·용량 |
| 압축 | 업로드 전·후 |
| 익명화 | 개인정보(11.3.9) |
자동 정리:
# 오래된 bag 삭제 (개념)
find /var/log/robot/rolling -name "*.mcap" -mtime +7 -delete
# 디스크 여유 감시 → 진단으로(6.9)
df --output=pcent /var/log/robot | tail -1
함정: 디스크가 가득 차면 기록만 멈추는 것이 아니라 시스템 전체가 비정상이 된다(1.11.3의 로그 디스크 문제와 같다). 여유 공간을 진단으로 감시하고 임계에서 경보하라(6.9.7).
견해: 업로드를 무선으로 상시 하면 대역을 잠식한다(3.9.3). 도킹 스테이션에서 유선·강한 Wi-Fi로 업로드하는 것이 흔한 설계다. 급한 것(사고 데이터)만 즉시 업로드한다.
견해: "무엇을 남길 것인가"를 미리 정하라. 전부 남기면 저장 비용이 감당 안 되고, 다 지우면 나중에 필요할 때 없다. 이벤트 데이터와 대표 샘플은 오래, 일상 데이터는 짧게가 흔한 절충이다.
11.3.8 회귀 데이터셋
10.6.6에서 말한 "bag을 자산으로"의 실체다.
데이터셋 구성:
| 범주 | 내용 |
|---|---|
| 정상 케이스 | 대표적 일상 동작 |
| 어려운 케이스 | 실패했던 상황 |
| 다양한 조건 | 조명·환경·시간대 |
| 경계 케이스 | 극단적 상황 |
메타데이터를 함께 관리한다:
# dataset/index.yaml (개념)
- bag: 2026-03-15_corridor_glass.mcap
description: "유리벽 복도 — 라이다 통과 문제"
expected: "코스트맵에 유리벽이 안 잡힘 (알려진 한계)"
tags: [glass, corridor, known-limitation]
- bag: 2026-04-02_crowded_lobby.mcap
description: "사람 다수 — 동적 장애물"
expected: "성공률 > 80%"
tags: [dynamic, people]
견해: "기대 결과"를 함께 적는 것이 핵심이다. 그것이 없으면 회귀 시험이 "실행해 보고 눈으로 확인"이 되어 자동화되지 않는다. 정량적 기준(성공률·오차 임계)을 정해야 CI에 넣을 수 있다(4.10).
견해: 실패했던 bag이 가장 가치 있다. 문제를 고쳤을 때 그 bag으로 검증하고, 이후 회귀를 막는다. 현장에서 문제가 생기면 반드시 bag을 남기고 데이터셋에 추가하는 절차를 두라.
CI 통합(4.10.5):
# 개념: 데이터셋 전체에 대해 알고리즘 실행·평가
for bag in dataset/*.mcap; do
ros2 launch my_pkg replay_eval.launch.py bag:=$bag
# 지표를 수집해 기준과 비교
done
함정: bag 기반 회귀 시험도 느릴 수 있다. 데이터셋이 크면 야간 실행이 필요하다(4.10.2). 대표 소수를 PR 검증에, 전체를 야간에 두는 분업이 실용적이다.
11.3.9 개인정보와 보안
기록은 위험을 동반한다.
| 위험 | 설명 |
|---|---|
| 얼굴·개인 식별 | 카메라 기록 |
| 음성 | 마이크 |
| 위치·동선 | 사람의 이동 추적 |
| 사업 정보 | 시설 내부·재고 |
| 자격 증명 | 로그에 실수로 기록(1.11.8) |
견해: 카메라를 기록하는 로봇이 사람이 있는 공간에서 운영된다면, 개인정보 처리에 관한 규정을 반드시 확인하라. 이 책은 법적 조언을 제공하지 않으며, 적용 법규·조직 정책과 전문가 판단을 따라야 한다.
기술적 완화:
| 방법 | 설명 |
|---|---|
| 기록 대상 제한 | 카메라를 상시 기록하지 않음 |
| 익명화 | 얼굴 블러 후처리 |
| 접근 통제 | 저장소 권한 |
| 암호화 | 전송·저장 |
| 보존 기간 제한 | 자동 삭제 |
/rosout 검토 | 비밀 값 로깅 방지(1.11.10의 11번) |
함정:
/rosout을 기록하면 로그에 담긴 모든 것이 남는다. 로그에 자격 증명·개인정보를 남기지 말라는 원칙(1.11.8)이 여기서 더 중요해진다.
견해: "필요한 것만 기록"이 보안과 성능 양쪽에서 옳다(11.3.2의 계층). 원본 이미지를 상시 기록할 이유가 대개 없고, 안 하면 위험도 줄어든다.
11.3.10 현장 데이터 흐름
로봇에서 분석까지의 경로를 설계한다.
운영 절차에 넣을 것:
| 항목 | 이유 |
|---|---|
| 기록이 진행되고 있는지 감시 | 진단으로(6.9) |
| 디스크 여유 감시 | 중단 방지 |
| 이벤트 시 자동 보존 | 기회 상실 방지 |
| 업로드 성공 확인 | 유실 방지 |
| 정기 데이터셋 갱신 | 자산화 |
견해: "기록이 진행되고 있는가"를 진단 항목에 넣으라. 기록 노드가 종료됐는데 아무도 모르면, 정작 필요할 때 데이터가 없다. 기록 프로세스 생존과 최근 파일 갱신 시각을 감시하면 된다(6.9.2의
STALE개념과 같은 발상).
11.3.11 함정 카탈로그
| # | 함정 | 증상 | 대처 |
|---|---|---|---|
| 1 | 문제 후에 기록 시작 | 원인이 안 담김 | 순환 버퍼·이벤트 기록 |
| 2 | 전부 상시 기록 | 디스크 용량 급증 | 계층적 기록 |
| 3 | /diagnostics·/rosout 미기록 | 사후 분석 불가 | 상시에 포함 |
| 4 | --clock 없이 use_sim_time | 시간 0에 멈춤 | 함께 사용 |
| 5 | 일부 노드만 use_sim_time | 외삽 오류(5.2.4) | 전체 적용 |
| 6 | --loop에서 점프 미처리 | 상태 오염 | 점프 콜백(5.2) |
| 7 | 재생 시 /tf 충돌 | 비정상적인 결과 | --topics·리매핑 |
| 8 | 실기 연결 상태로 재생 | 로봇이 옛 명령대로 움직임 | 분리·차단 |
| 9 | --rate 변경 후 성능 평가 | 잘못된 결론 | 1.0으로 |
| 10 | 디스크 여유 미감시 | 시스템 이상 | 진단 감시 |
| 11 | 무선 상시 업로드 | 대역 잠식 | 도킹 시 업로드 |
| 12 | 기대 결과 없는 데이터셋 | 자동화 불가 | 정량 기준 |
| 13 | 개인정보 무제한 기록 | 규정·위험 | 제한·익명화·규정 확인 |
| 14 | 기록 생존 미감시 | 필요할 때 데이터 없음 | 진단 항목 |
11.3.12 체크포인트
- 기록 계층 네 가지와 각각의 대상·기간을 말할 수 있는가. 상시에 반드시 넣어야 할 것은?
- 순환 버퍼가 필요한 이유를 한 문장으로 말할 수 있는가. 구현 세 방법 중 견고한 것은?
- 이벤트 트리거 다섯 가지와, 진단 시스템과 연결하면 무엇이 좋아지는가.
- 주요 재생 옵션 여섯 가지를 말할 수 있는가.
--clock과use_sim_time의 세 조합과 각각의 결과는?--loop와--rate각각의 주의점은?- 재생 시 충돌 다섯 가지와, 가장 위험한 것은?
- 재생 전용 launch를 만들라는 조언의 근거는?
- 저장 관리 정책에서 결정할 여섯 항목과, 업로드 시점을 도킹으로 두는 이유는?
- 회귀 데이터셋에 "기대 결과"를 적어야 하는 이유와, 가장 가치 있는 bag은?
- 기록의 개인정보·보안 위험 다섯 가지와 기술적 완화 여섯 가지를 들 수 있는가.
- "기록이 진행되고 있는가"를 감시해야 하는 이유는?
다음 장 11.4은 이 데이터를 눈으로 보는 도구 — RViz2와 플러그인 작성을 다룬다.