hello, robot

문법 드릴만으로는 실제 데이터의 형태를 알기 어려워서, 뒤 커리큘럼에서 다룰 로봇 시연 데이터를 미리 열어 검증 드릴 12문제를 만들었어요. 그 과정에서 교과서 예제로는 안 드러나는 두 지점, 부동소수점 비교와 파이썬 import의 실행 모델을 정리하게 됐어요.

데이터셋lerobot/pusht · 모방학습용 시연 규모에피소드 206 · 프레임 25,650 · 10 fps 형식수치 Parquet · 영상 MP4 · 메타 JSON 재현리비전 고정 + 문제마다 assert

데이터 구조는 실물로 확인해요

HuggingFace에 공개된 lerobot/pusht를 썼어요. 로봇이 T자 블록을 미는 시연(demonstration)을 모은 데이터셋이고, 각 프레임은 관측(observation)과 행동(action)의 쌍이에요. 모방학습은 이 쌍에서 “이 관측이면 이 행동”을 지도학습으로 배워요.

참고 자료는 에피소드마다 Parquet 파일이 하나씩 있는 구조라고 했는데, 실제 데이터셋은 v3.0으로 개편되면서 청크 파일 하나에 206개가 통합돼 있었어요. 오픈소스 로보틱스 스택은 개정이 잦아 몇 달 전 자료도 어긋나기 쉬우니, 구조는 문서로 익히되 최종 확인은 실물을 열어서 해요. 문서와 데이터가 다르면 데이터가 맞으니까요.

float32 타임스탬프의 == 비교 오류

10 fps 데이터니까 인접 프레임의 타임스탬프 간격은 0.1초여야 하는데, 간격 == 0.1로 검증했더니 전부 실패했어요.

같은 0.1인데 값이 달라요
근사에 쓰는 비트 수가 타입마다 달라서, 같은 십진수도 서로 다른 2진 근사값이 돼요.
0.1은 2진수로 유한하게 안 떨어져요 — 0.0001100110011… 무한 반복수직선을 크게 확대한 구간이에요0.099999990.10000001파이썬 리터럴 0.10.1000000000000000055…float64 · 가수 52비트데이터셋 timestamp 간격0.10000000149…float32 · 가수 23비트두 값이 달라서 == 가 깨져요그래서 정확히 같은지가 아니라 허용 오차 안에서 같은지로 비교해요 — math.isclose(gap, 0.1, abs_tol=1e-6)

timestamp는 float32(가수 23비트)라 0.1이 0.10000000149…가 됐고, 파이썬 리터럴 0.1은 float64(가수 52비트)라 더 촘촘한 다른 근사값이에요. 두 값이 다르니 ==가 깨져요.

import math
gap == 0.1                            # 실패: 정확 비교
math.isclose(gap, 0.1, abs_tol=1e-6)  # 수정: 허용 오차

abs_tol은 절대 허용 오차예요. isclose는 기본적으로 상대 오차(rel_tol)로 비교하는데, 0에 가까운 값에서는 그것만으로 부족해서 절대 오차를 함께 줘요.

import는 모듈의 최상위 코드를 실행해요

모듈을 하나 만들고 아래쪽에 테스트용 print를 뒀는데, 다른 파일에서 import하는 순간 그 print가 실행됐어요.

import가 실제로 하는 일
최상위에 부작용(side effect) 코드를 두면 import만 해도 돌아가요.
mymodule.pyimport numpy as np실행됨def load(): ...정의 실행됨class Robot: ...정의 실행됨print('여기도 돕니다')실행됨 ← 부작용if __name__ == '__main__': run_tests()건너뜀import mymodule 하면· 최상위 코드를 위에서 아래로 한 번 실행· 함수·클래스 정의문도 그때 실행· 그 사이 일반 문장도 똑같이 실행· __main__ 가드 안쪽만 건너뜀· 한 번 실행되면 sys.modules에 캐시돼 재실행 안 됨

__name__은 파일을 python x.py로 직접 실행하면 '__main__', 다른 파일이 import x로 부르면 모듈 이름 'x'가 돼요. 그래서 가드 안의 코드는 직접 실행에서만 돌고 import에서는 건너뛰어요.

if __name__ == '__main__':
    # 파일을 직접 실행할 때만 도는 코드

조용한 실패는 한 얼굴이에요

드릴에서 반복해 걸린 실수들의 원인이 하나로 모여요. 파이썬은 오류로 멈추지 않고 조용히 다른 값을 돌려준다는 점이에요.

쓴 것기대한 결과실제 결과
return print(...)값이 반환됨print는 값을 반환하지 않아 None
min(xs, ys)각 리스트의 최솟값두 시퀀스를 사전순 비교한 결과
컴프리헨션에 append 혼용리스트가 채워짐세 자리를 지키면 append가 아예 불필요
gap == 0.1타임스탬프 검증 통과float32/float64 근사가 달라 전부 실패
모듈 최상위 print직접 실행할 때만 출력import만 해도 실행

정적 타입 언어라면 컴파일 단계에서 걸렸을 것들이 파이썬에서는 런타임에 조용히 통과하니, __main__ 가드나 assert 셀프체크 같은 방어 관용구가 자주 쓰여요.

드릴 구성과 재현 장치

데이터 검증(관측 키 추출, 프레임 수 집계, 타임스탬프 간격 검증, 좌표 범위 확인)과 문법 연습(컴프리헨션·Counter·deque)을 합쳐 12문제를 만들었어요. 재현을 위해 데이터셋 리비전(커밋 해시)을 고정했고, 문제마다 붙인 assert가 실행 즉시 통과·실패를 찍어요. 전체 드릴(58문제 + 답안)은 robotics-python-drills에 공개해 뒀어요.

전날 로봇의 몸(모터·실시간 신호)을 배운 기록은 1kHz 제어 주기와 지터 — 로봇 제어가 1ms를 다투는 이유에 있어요.