AEGLOSLAB ROS 2 Jazzy 대전

제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 계층적 기록

모든 것을 항상 기록할 수는 없다. 계층으로 나눈다.

기록 계층 ① 상시 작은 토픽 · 며칠 ② 순환 버퍼 대용량 · 최근 N초 ③ 이벤트 문제 발생 시 저장 ④ 세션 디버깅· 개발 시 전체
계층대상기간용량
① 상시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에서 언급한 패턴이다. "사건이 일어난 직전"을 검출하는 유일한 방법이다.

덮어씀 센서 데이터 메모리 순환 버퍼 최근 60초
이벤트 발생 충돌 · 실패 · 사람 요청 버퍼를 디스크로 저장 사건 전 60초 + 후 30초

왜 필요한가: 문제가 발생한 뒤에 기록을 시작하면 원인이 담기지 않는다. 원인은 결과보다 먼저 일어난다.

구현 방법:

방법설명
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, 결과 JSON early_sub_result.json·late_sub_result.json·after_finish_result.json).

11.3.5 시뮬 시간과 재생

--clock이 무엇을 하는가.

ros2 bag play --clock /clock 토픽 발행 bag의 시각 use_sim_time: true 인 노드 bag 시각으로 동작
설정결과
--clock + use_sim_time: truebag 시각으로 일관
--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_time 3자 관계를 실측으로 확인했다. --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초간 재생하며 /clock 343개를 기록했다. 역방향 점프가 정확히 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을 자산으로"의 실체다.

예 현장 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 현장 데이터 흐름

로봇에서 분석까지의 경로를 설계한다.

예 아니오 로봇: 계층적 기록 11.3.2 로컬 보존 · 정리 이벤트? 즉시 표시·우선 업로드 도킹 시 업로드 중앙 저장소 분석 · 지표 추출 회귀 데이터셋 편입 문제 티켓

운영 절차에 넣을 것:

항목이유
기록이 진행되고 있는지 감시진단으로(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와 플러그인 작성을 다룬다.