통신 설정·큐와 진단 순서
210분 안팎
학습 목표
노드 미실행·이름 오타·타입 불일치·큐 손실을 각각 주입해 원인을 기록합니다.
개념
무수신을 하나의 원인으로 단정하지 않습니다
화면이 갱신되지 않는다는 신고만으로 큐를 늘리면 이름 오타와 노드 중단은 해결되지 않습니다. 먼저 실패를 주입한 조건과 관찰한 증거를 연결해야 합니다. 이번 레슨은 중단, 이름 오타, 타입 불일치, 큐 넘침을 각각 실행하고 다른 진단 사유를 반환합니다. 그 다음 실제 ROS에서 확인할 끝점 설정을 문서로 분리합니다. 진단 결과는 한 번의 관찰에서 확인한 범위이며 다른 층의 원인까지 없다고 보증하지 않습니다.
실습의 diagnose는 alive, 발행·구독 이름, 발행·구독 타입, dropped, received를 받습니다. 중단, 이름, 타입, 큐 손실 순으로 첫 확인된 원인을 반환합니다. 그중 아무 원인도 없으면 received가 양수일 때 OK, 0일 때 NO_DATA입니다. NO_DATA는 아직 설명되지 않은 무수신입니다. 살아 있다는 플래그만으로 실제 발행 호출이 있었다거나 네트워크 연결이 완료되었다고 판단하지 않습니다.
생존과 발행을 먼저 관찰합니다
stopped fixture는 센서 역할을 실행하지 않아 publish를 호출하지 않습니다. NODE_STOPPED는 실습이 입력으로 주입한 중단 상태에 근거합니다. 실제 프로세스를 강제로 종료하는 실습이 아닙니다. 실제 환경에서는 실행 로그와 노드 목록, 발행 카운터 등을 확인해야 합니다. Python alive가 참이라는 사실을 ROS liveliness 정책과 같은 것으로 설명하지 않습니다. 두 개념은 검증 방법이 다릅니다.
정상 fixture에서는 세 행이 전달되어 received=3, dropped=0입니다. stopped에서는 received=0입니다. 이 두 수만으로 이름 문제와 중단을 구분할 수 없어 별도 상태와 설정을 함께 기록합니다. 장애 보고서에 “안 됩니다” 대신 실행한 fixture, 기대 수신, 실제 수신, 설정 비교, 진단 사유를 씁니다. 다음 담당자가 같은 조건을 실행해 같은 결과를 얻을 수 있어야 진단 자료로 쓸 수 있습니다.
이름 오타와 타입 불일치를 따로 고칩니다
name fixture는 발행 이름에 /robot/rnage_status를 사용합니다. 구독 이름 /robot/range_status와 다르므로 NAME_MISMATCH입니다. 발행 호출은 일어나도 큐에 들어가는 항목은 없습니다. 증거는 생산자 호출 횟수와 서로 다른 문자열입니다. 깊이와 소비 속도를 바꾸기 전에 해석된 이름을 맞추는 것이 이 fixture의 수정입니다. 다른 로봇의 토픽과 혼동하지 않도록 전체 이름을 기록합니다.
타입 fixture는 이름을 유지하고 발행 라벨만 String으로 바꿉니다. 결과는 TYPE_MISMATCH입니다. 이름을 고친 뒤에도 수신이 없다면 다음 경계를 확인하는 사례입니다. 실제 ROS에서는 인터페이스 정의와 양쪽 패키지 빌드 상태를 확인합니다. 이 모델은 문자열만 비교하므로 생성된 타입 지원이나 직렬화 호환 검증까지 수행하지 않습니다. 메시지를 임의 문자열로 뭉쳐 해결하기보다 약속한 필드 의미를 유지합니다.
일부 수신도 손실의 증거가 될 수 있습니다
burst fixture는 여섯 행을 먼저 발행하고 나중에 drain합니다. 깊이 4라 최신 네 건이 전달되고 dropped=2가 남아 QUEUE_LOSS입니다. received가 4이므로 정상이라고 먼저 반환하면 일부 성공 뒤의 손실을 숨깁니다. starter의 TODO는 바로 이 잘못된 판단을 고치게 합니다. 검사 우선순위에서 dropped를 수신 성공보다 먼저 확인해야 이 조건을 표현할 수 있습니다.
발행 번호가 건너뛰면 손실이나 필터링, 중간 재시작 등을 의심할 수 있지만 번호 간격만으로 원인을 단정하지는 않습니다. 이번 fixture에서는 큐 제거 카운터가 있어 용량 손실을 직접 확인합니다. 실제 환경에서 모든 항목을 기록해야 한다면 기록 처리량, 버퍼 한도, 저장 실패 정책을 함께 검토합니다. 큐를 크게 잡아 화면을 오래된 데이터로 채우는 것과 최신성 요구를 만족하는 것은 다른 목표입니다.
큐 깊이와 신뢰성 정책을 구별합니다
깊이는 보관할 항목 수이며 신뢰성은 전달 조건과 관련됩니다. 실제 ROS 2에서는 발행자의 제공 정책이 구독자의 요구를 만족하는지 비교합니다. 신뢰성에서 BEST_EFFORT 발행자와 RELIABLE 구독자는 호환되지 않습니다. RELIABLE 발행자는 BEST_EFFORT 요구를 만족할 수 있지만 다른 정책도 호환되어야 합니다. 모든 설정이 같은지만 확인하는 규칙보다 요구와 제공의 방향을 이해하는 편이 정확합니다.
깊이 4를 40으로 늘려도 신뢰성 불일치가 해결되지는 않습니다. RELIABLE이라고 설정해도 응용 콜백이 모든 발행을 처리했다는 증거는 별도로 필요합니다. 이력 한도와 자원 제한, 노드 종료, 처리 지연도 관찰 결과에 영향을 줄 수 있습니다. Python 버스에는 신뢰성 설정에 따른 재전송이나 연결 협상이 없습니다. 이번 결과로 실제 QoS 호환을 통과했다고 표시하지 않습니다. 상세 정책 조합은 더 읽기의 QoS 장에서 확인합니다.
실제 환경 확인은 실행 결과와 분리합니다
미션 DIAGNOSIS.md에는 실제 Linux와 ROS 2의 후속 체크리스트가 있습니다. 노드 실행 확인, 최종 이름과 타입 확인, 끝점별 QoS 비교, 값과 관찰 주기 확인 순서입니다. ros2 topic info의 상세 끝점 정보로 제공·요구를 비교하고 echo와 hz를 사용할 때도 관찰 도구의 설정을 확인합니다. 여기서는 ROS 명령을 실행하지 않아 고정 출력이나 실제 수신 주파수를 넣지 않습니다.
설정이 맞아도 발견 지연과 네트워크, 서로 다른 통신 도메인, 콜백 예외가 남을 수 있습니다. 후속 인계에는 운영체제와 배포판, 실행 명령, 해석된 토픽, 끝점 설정, 관찰 기간을 함께 남깁니다. 상태 메시지가 반복되어도 새 센서 측정이 아닐 수 있어 발행 주파수와 측정 갱신률을 구분합니다. 명령 하나의 성공을 전체 통신 계층의 성공으로 확대하지 않습니다.
직전 프로젝트의 결과를 유지합니다
모듈 미션 starter는 앞 모듈 solution을 이어받습니다. C HAL과 좌표 변환, 기존 테스트를 고치지 않고 topic_project.py의 시각 TODO를 완성합니다. resample은 각 발행 tick에서 그 시각 이하의 가장 최근 HAL 행을 선택합니다. stamp_s와 seq는 원본에 남겨 두고 pub_s와 pub_seq만 새로 부여합니다. 최근 상태 유지 정책을 함수 한 곳에 모아 앞 기능의 의미를 보존합니다.
20건 정상 수신의 “정상”은 통신 경로가 설정대로 처리된 상태입니다. 그중 0.2초 이후 메시지는 센서 결함입니다. 따라서 수신은 20건이어도 새 정상 map 점은 앞 모듈과 같은 두 개입니다. 마지막 화면은 seq=2, stamp=0.200, range=INVALID, status=2이며 발행 정보는 pub_seq=19, pub_s=0.950입니다. 수신 건수와 센서 관측 유효 건수를 혼동하지 않고 각각 증거를 남깁니다.
오류 메시지는 첫 깨진 계약을 가리킵니다
진단 실습의 test_stopped가 NO_DATA와 NODE_STOPPED를 비교하며 실패하면 실행된 중단 조건을 일반 무수신으로 합친 분기를 찾습니다. test_queue가 OK와 QUEUE_LOSS를 비교하면 수신 성공보다 손실 검사가 앞서는지 봅니다. 미션의 test_sample_clock_preserved가 실패하면 stamp_s를 pub_s로 덮어썼는지 확인합니다. 테스트 파일을 지우거나 기대값을 발행 시각으로 바꾸지 않습니다.
완료 증거는 20개 레슨 검사와 미션의 C 44개·Python 61개 검사, 실제 C 로그 연결 출력, 결함별 진단입니다. 보고서에는 한 줄 사유와 해당 설정·카운터를 함께 기록합니다. 여러 오류를 동시에 넣었을 때 첫 사유만 나온다는 우선순위도 적습니다. 모든 원인이 제거됐다는 뜻으로 읽지 않도록 이후 경계를 재검사할 순서를 남기면 다음 담당자의 재현과 수정 판단이 쉬워집니다.
사실 확인 자료: ROS 2 Jazzy 공식 문서 원본 — QoS 제공·요구와 호환성 표에서 해당 기준을 확인할 수 있습니다.
따라하기
진단 TODO의 실패를 확인합니다
robotics-m04-diagnosis starter에서 bash check.sh를 실행합니다. 기존 버스 검사는 통과하고 test_stopped·test_queue 등의 진단 검사가 실패하는지 확인합니다. AssertionError의 실제 사유와 기대 사유를 기록합니다.
확인된 원인을 먼저 반환합니다
topic_runtime.py의 diagnose에서 중단 분기는 NODE_STOPPED, dropped가 있는 분기는 QUEUE_LOSS를 반환하도록 TODO 두 줄을 고칩니다. 순서는 중단→이름→타입→손실→수신입니다. 아래 조각은 함수 내부 분기입니다.
if not alive:
return "NODE_STOPPED"
# 이름과 타입 검사 뒤
if dropped:
return "QUEUE_LOSS"결함을 하나씩 주입합니다
같은 폴더에서 bash check.sh로 20개 검사 OK를 확인하고 python3 demo.py를 실행합니다. 아래는 solution 실행 결과입니다. 각 행의 원인과 근거 카운터를 보고서에 적습니다.
실행 결과
normal: OK received=3 dropped=0 stopped: NODE_STOPPED received=0 dropped=0 name: NAME_MISMATCH received=0 dropped=0 type: TYPE_MISMATCH received=0 dropped=0 burst: QUEUE_LOSS received=4 dropped=2
미션을 연결하고 시각을 보존합니다
robotics-m04-topic-contract starter의 topic_project.py에서 TODO인 item["stamp_s"]=pub_s 대입을 제거합니다. 원본 stamp_s와 seq를 보존하고 pub_s·pub_seq를 별도로 둡니다. bash check.sh로 C 44개와 Python 61개 검사, 실제 로그 연결을 확인합니다. DIAGNOSIS.md에 실습 증거와 후속 환경에서 확인할 내용을 보완합니다.
확인 문제
실습
diagnose의 TODO 두 곳을 완성합니다. 중단·이름·타입·큐 손실·빈 수신을 구분하고 일부 수신에서도 손실을 보고합니다. 버스 12개와 진단 8개 검사를 통과하고 결함별 사유·설정·received·dropped를 제출합니다. 모듈 미션에서는 직전 HAL을 이어받아 20Hz 발행과 측정 시각 보존을 확인하고 실제 ROS QoS·Linux 확인을 DIAGNOSIS.md의 후속 체크리스트로 남깁니다.
실행 명령
bash check.sh
기대 결과
unittest 20개 검사 OK
모범 답안
모범 답안 내려받기더 읽기
면접 질문
- 센서 토픽에 데이터가 보이지 않을 때 확인할 순서를 설명해 주시면 됩니다.
- ROS 2 토픽과 서비스, 액션의 선택 기준을 설명해 주시면 됩니다.