ROS 2를 쓰다 막혔을 때 증상부터 찾아볼 수 있도록 HuntLab 글을 묶었습니다. 대부분의 글에는 ros:jazzy 컨테이너에서 직접 돌려 본 실측값이 들어 있고, 재현 코드는 GitHub에 공개돼 있습니다. 새 글이 공개되면 이 목록에 자동으로 추가됩니다.
설치·빌드
- ROS 2 Iron이냐 Humble이냐: 로봇 프로젝트 배포판을 EOL까지 남은 개월 수로 고르기 (English)
Iron이냐 Humble이냐는 2023년의 질문이다. 2026년 10월 기준 공식 날짜로 남은 개월을 계산하고 프로젝트 기간을 빼서, Humble·Jazzy·Lyrical 가운데 무엇이 프로젝트가 끝날 때까지 지원되는지 판정한다. - 새 터미널에서 local_setup.bash만 source해도 underlay 패키지가 보일까: setup.bash와 ros2 pkg list 개수로 직접 재 보기 (English)
local_setup.bash 한 줄로는 underlay 패키지도 ros2 명령도 들어오지 않는다. Jazzy 컨테이너의 깨끗한 셸 다섯 개에서 ros2 pkg list 개수를 재고, setup.bash가 빌드 때 적어 둔 경로로 underlay를 부르는 원리를 따라간다. - colcon build가 너무 느릴 때: overlay·COLCON_IGNORE·–symlink-install로 다시 빌드할 패키지를 줄이는 순서 계산하기 (English)
colcon은 선택된 패키지마다 빌드와 설치를 반복한다. 네 가지 수단이 덜어내는 몫을 가상 작업공간으로 계산하고, Jazzy 컨테이너 실측에서 플래그를 바꿔 다는 비용이 패키지를 줄여 얻는 시간보다 컸던 이유를 정리했다. - colcon build 스레드 수를 줄이고 싶을 때: 라즈베리 파이가 멈추면 –executor sequential로 동시 빌드 메모리와 시간 계산하기 (English)
sequential은 패키지 수만 1로 만든다. 패키지 안 make -j까지 곱해 동시 컴파일 수와 메모리를 계산하고, 줄였을 때 늘어나는 시간을 의존 관계로 가늠하는 법을 colcon 소스와 실측으로 확인한다.
토픽·QoS 통신
- Docker 컨테이너 경계를 넘으면 ROS 2 노드가 서로를 못 찾을 때: ROS_AUTOMATIC_DISCOVERY_RANGE와 ROS_STATIC_PEERS 36가지 조합 중 다른 호스트에서도 통하는 칸 세어 보기 (English)
같은 호스트에서 통하던 16칸 중 다른 호스트에서 빠지는 3칸에는 모두 정적 피어 없는 LOCALHOST가 끼어 있다. 공식 표와 Jazzy 컨테이너 실측으로 어느 노드에 무엇을 설정할지 판정한다. - ROS 2는 왜 ‘실시간’이라고 할까: real time factor 1.0과 마감을 지키는 실시간 컴퓨팅을 숫자로 구분하기 (English)
시뮬레이터의 RTF 1.0은 시뮬레이션 시계가 벽시계를 따라갔다는 뜻이지, 제어 콜백이 매 주기 마감을 지켰다는 증거가 아니다. 계산 예제와 ROS 2 Jazzy 컨테이너 실측으로 두 값을 따로 판정하는 방법을 정리했다. - ROS 2 센서 토픽이 멈춘 걸 liveliness로 알 수 있을까: 같은 노드의 다른 토픽이 lease를 갱신하는 문서 정의와 deadline으로 토픽 단위 감시하기 (English)
카메라 토픽만 멈추면 liveliness는 조용하고 deadline만 울린다. 문서마다 다르게 적힌 Automatic liveliness의 갱신 주체를 ROS 2 Jazzy 기본 RMW에서 직접 재고, 토픽 단위 감시를 고르는 기준을 정리했다. - ‘Message Filter dropping message: frame laser’ 로그가 뜰 때: 레이저 타임스탬프와 tf 시각이 다른 시계에서 왔는지 뺄셈으로 확인하기 (English)
같은 시계여도 tf2는 미래 외삽 오류를 낸다. 오류 문구 대신 레이저 스탬프 − tf 최신 스탬프의 크기와 부호를 보면 시계 혼동 여부와 원인 노드가 갈린다. 스탬프 0과 정적 변환만 있는 경로는 드롭 없이 지나간다는 점도 측정했다. - ROS 2 로봇 상태 토픽을 transient local로 남기면 늦게 켠 노드는 몇 초 전 데이터를 받을까: depth·발행 주기·lifespan으로 표본 나이 계산하기 (English)
10 Hz·keep last depth 10·transient local 토픽에 늦게 붙은 노드는 최대 10개, 약 0.9초 전 표본까지 받는다. 발행자에 lifespan 0.45초를 걸면 5개만 남고 depth를 100으로 늘려도 같다. 두 창의 계산식과 lifespan을 발행자에 걸어야 하는 이유를 정리했다. - ROS 2 센서 토픽에 deadline QoS를 걸 때: 구독자가 더 짧은 deadline을 요청하면 왜 연결이 끊길까
구독자 요청 50 ms, 발행자 제공 100 ms면 50 − 100 = −50으로 비호환이다. 연결 시점의 '요청 − 제공'과 연결 뒤의 '제공 − 실제 발행 간격'을 따로 계산해 어느 값을 고칠지 고른다. - ROS 2 토픽 이름이 같은데 메시지가 안 올 때: QoS 호환성을 먼저 계산하기
publisher가 제공하는 QoS와 subscription이 요청하는 QoS를 첫 번째 0이 나올 때까지 대조해, 연결 전 불일치와 연결 뒤 queue 문제를 구분한다.
시간·시뮬레이션
- rclpy에서 rate.sleep()이 멈추거나 주기가 안 맞을 때: Rate가 타이머 콜백의 이벤트를 기다린다는 점으로 executor 구성과 루프 주기 계산하기 (English)
rate.sleep()이 첫 반복 뒤 멈추는 이유와 루프가 목표 Hz보다 느려지는 이유는 다르다. Jazzy rclpy 소스, 8 Hz 계산 예제, 8가지 구성의 컨테이너 실측으로 둘을 구분하고 spin 스레드·MultiThreadedExecutor·create_timer 중 무엇을 쓸지 정한다. - ROS 2 use_sim_time 노드가 /clock을 받기 전 시각 0을 저장하면 첫 dt는 몇 초가 될까: 음수 검사를 통과하는 첫 주기 스파이크 계산하기
/clock을 받기 전 저장한 시각 0은 첫 dt를 첫 시뮬레이션 시각 전체로 만든다. 125초 예제로 적분·차분 속도·timeout이 틀어지는 크기와 dt < 0 검사가 이를 통과시키는 이유, 0 가드의 비용을 계산한다. - ROS 2 시뮬레이션을 10배속으로 돌리면 타임스탬프는 얼마나 어긋날까: 통신 지연과 real time factor 곱하기
배속 시뮬레이션의 타임스탬프 오차를 통신 지연 항(RTF×L)과 /clock 틱 항(RTF÷f)으로 나눠 계산한다. 발행 빈도는 틱 항만 줄이고, 지연 항은 배속을 낮춰야 준다. - ROS 2 시뮬레이션 시간이 뒤로 가면 로봇 타이머 계산은 어떻게 깨질까
ROS 시간이 12초에서 9초로 이동하면 경과시간은 -3초다. 이 값을 정상 주기로 처리하지 않고 시간 점프 사건으로 다루는 법을 익힌다. - 로봇 동역학 시뮬레이션의 에너지 드리프트는 어떻게 읽을까
총 기계에너지의 작은 변화가 수치 오류인지 판단하려면 보존 조건, 에너지 영점, 전체 시간 이력과 시간 간격 축소 결과를 함께 봐야 한다. - 로봇 시뮬레이션의 시간 간격을 줄이면 위치 계산은 왜 달라질까
전진 오일러법이 구간 시작 속도로 이동거리를 근사할 때 빠뜨리는 면적을 계산해, timestep을 줄이면 위치가 달라지는 이유를 알아본다.
좌표계·tf
- tf 프레임 원점이 base_link에서 어긋나 보일 때 변환 방향부터 의심해야 할까: 1 m 오프셋을 반대로 발행하면 2 m가 벌어지는지 계산하기 (English)
부모·자식을 바꾸거나 이동 부호를 뒤집으면 순수 이동 변환은 오프셋의 2배만큼 벌어진다. 하지만 회전이 섞이면 1배·0배도 나오고, odom 부모가 있는 base_link를 거꾸로 적으면 2배 대신 트리가 끊긴다. tf2 실측과 손계산으로 확인했다. - ROS 카메라 _optical 프레임으로 점을 옮길 때 축 부호가 맞는지 확인하기: 오른손 좌표계 행렬식과 기준점 하나로 매핑 검사
몸체 좌표 (x, y, z)는 _optical 좌표 (−y, −z, x)가 된다. 틀린 매핑 중에는 행렬식 +1과 거리 보존을 모두 통과하는 것이 있어, 기대 좌표를 적어 둔 기준점 테스트가 필요하다. - ROS 로봇 자세 공분산 36칸 중 yaw 분산은 몇 번째 칸일까: 6×6 행우선 인덱스와 rad² 단위 계산하기
yaw 표준편차 2°는 35번 칸에 약 0.00122 rad²로, x 표준편차 0.05 m는 0번 칸에 0.0025 m²로 넣는다. 행우선·열우선 혼동보다 변수 순서와 단위 실수가 값을 실제로 바꾼다. - 나침반 방위 30도를 ROS yaw에 그대로 넣으면 로봇은 어디를 볼까: 북쪽 기준 시계방향을 동쪽 기준 반시계방향으로 바꾸기
ROS의 지리 좌표 yaw는 동쪽이 0이고 반시계방향으로 커진다. 북쪽 0·시계방향인 나침반 방위를 그대로 넣으면 30도가 60도로 읽힌다. 변환식 yaw = 90 − 방위와, 45도 한 입력으로는 잡히지 않는 변환 실수를 드러내는 테스트 입력을 정리했다. - 피지컬 AI 좌표계: 같은 물체의 위치가 다르게 보이는 이유
로봇 앞 1m의 점에 원점만 더하면 왜 틀릴까. 같은 점을 다른 좌표계로 옮길 때 회전과 이동이 모두 필요한 이유를 2D 예제로 설명한다. - ROS 2와 tf2: 센서 데이터 전달과 좌표 변환을 구분하는 법
센서 값이 도착했다고 로봇이 그 위치를 이해한 것은 아니다. ROS 2의 통신과 tf2의 좌표·시각 처리를 분리해, 무엇을 연결하고 무엇을 직접 준비해야 하는지 알아본다.
제어·학습
- 로봇 관절 P 제어 게인을 올려도 왜 시간상수 1/Kp만큼 빨라지지 않을까: 속도 한계에서 선형 모델이 맞는 오차 범위 계산하기
명령 속도 Kp×오차가 관절 최대 속도를 넘는 동안에는 시간상수 1/Kp가 응답을 설명하지 못한다. 경계 오차 vmax/Kp를 구해 게인 비교를 어디까지 믿을지 판단하는 계산 예제다. - 로봇 관절 속도를 가우시안 정책으로 뽑으면 왜 행동 범위를 넘을까: 경계까지의 여유를 표준편차로 재기
평균 0.875 rad/s, 표준편차 0.25에서는 z=1만 뽑혀도 샘플이 1.125 rad/s로 상한을 넘는다. 경계까지 표준편차 몇 개가 남았는지 계산하는 법과, 넘은 행동을 환경과 학습 버퍼가 각각 어떻게 받는지 정리한다. - 로봇 강화학습 에피소드가 끝났을 때: 추락과 시간 제한의 목표값은 왜 다를까
추락은 다음 상태 가치를 끊지만 외부 시간 제한은 그렇지 않다. 두 종료 원인을 같은 숫자로 계산해 부트스트랩 마스크를 구분한다. - 움직이는 로봇 관절을 P 제어하면 왜 오차가 남을까
오차가 있어야 속도 명령이 생기는 P 제어의 구조를 따라가며, 일정 속도 목표에서 잔류 각도 오차가 c/Kp가 되는 이유를 계산한다. - ROS 로봇 속도 단위가 1000배 어긋나는 순간: mm/s를 m/s로 검증하기
250 mm/s와 0.25 m/s가 같은 이동거리로 수렴하는지 검사해 ROS 입력 경계의 단위 변환 누락과 중복을 구별한다. - 이동평균 필터 실습: 센서 노이즈를 줄이면 왜 반응이 늦어질까
값이 덜 흔들린다고 더 좋은 센서 입력일까? 고정 수치열과 별도 계단 입력으로 평균 창을 늘릴 때 얻는 것과 잃는 것을 확인한다.
기초 개념
- ROS 2에서 중첩 구조 메시지 Foo[]를 만들 때: 같은 값을 기본형 배열 두 개로 나누면 비기본형 요소 수가 얼마나 달라지는지 세고 publish() 비교 실험 설계하기 (English)
같은 값 1만 개를 Foo[]와 기본형 배열 두 개에 담으면 바이트 합은 같지만 비기본형 요소는 1만 대 0이다. 그 차이가 rclpy의 publish()와 수신 쪽에서 어떻게 드러나는지 ROS 2 Jazzy 컨테이너에서 쟀다. - Gymnasium 커스텀 로봇 환경에서 step()이 같은 관측 배열을 고쳐 돌려주면, 복사 없이 쌓는 리플레이 버퍼에는 무엇이 남을까: 관절각 4스텝으로 평균과 차분 속도 계산하기 (English)
관절각 4스텝 예제와 컨테이너 5회 실측으로, 관측 배열을 재사용하는 환경이 복사 없는 버퍼에 남기는 값과 그 버그를 잡는 테스트를 확인한다. - 피지컬 AI 작동 원리: 관측·행동·피드백을 숫자로 이해하기
목표에 도착했다고 읽었는데 실제로는 덜 움직였다면? 작은 수치 예제로 관측과 상태, 행동과 결과, 피드백과 학습을 구분한다.