상태: 초안 (2026-10-18), 실측. 카메라 주기·잡음·지연과 로봇의 속도·힘 한계는 모두 가정값입니다. 측정은 2026-10-18 에 2편과 같은 임시 파드(미니 PC 노드 Intel Core Ultra 9 185H, 상한 CPU 3코어·메모리 3 GiB, GPU 없음, mujoco 3.16.0)에서 했습니다. 물리 시간 간격 0.5 ms, 라켓 접촉 solref (−4e6, −34)(2편 7절에서 정한 값)입니다. 공은 DeepMind 공개 초기 상태에서 2편과 같은 500개 표본(seed 0)의 앞쪽 100개를 썼고, 지연 100 ms 와 30 Hz 조건은 시간 때문에 앞쪽 50개만 돌렸습니다. 조건마다 한 번 돌린 값입니다. 앞의 세 조건 300회에 1,573 s 가 걸렸습니다(프로세스 3개). 원자료는 작업 디렉터리
tt-robot/out/(F1 표 세 개와 회차별 원자료 JSON)과tt-robot/logs/에 있습니다.
목차
1. 직관: 강화학습이 넘어야 할 바닥
강화학습으로 탁구 로봇을 가르친다고 할 때, 「잘한다」의 기준이 먼저 있어야 합니다. 이 글의 기준선은 사람이 손으로 짠 고전 제어입니다. 공을 보고, 날아갈 길을 물리 식으로 예측하고, 칠 자리와 라켓 각도를 계산해 팔을 그 자리로 보냅니다. 학습은 하나도 없습니다. 이 기준선이 몇 개를 넘기는지, 그리고 어디서 실패하는지를 알아야 강화학습이 무엇을 줄였는지 말할 수 있습니다.
2. 로봇: 갠트리 2축 + 손목 2축
| 부분 | 값(모두 가정값) |
|---|---|
| 갠트리 | 로봇 쪽 끝선 38 cm 뒤(y = −1.75 m)의 평면에서 가로 x ±0.9 m, 높이 z −0.15–0.7 m |
| 손목 | yaw, pitch 두 축, ±1.4 rad. 라켓 면 중심은 pitch 축에서 0.15 m |
| 한계 | 갠트리 4 m/s, 40 m/s², 힘 400 N(가로)·300 N(높이). 손목 20·30 rad/s, 400·600 rad/s², 20 N·m |
3편의 하드웨어 계획에서 「레일 2축 + 손목 2축」(2·3단계)에 해당하는 모양입니다. 갠트리에는 깊이(y) 축이 없어서, 라켓이 닿을 수 있는 y 와 공의 길이 만나는 순간이 곧 타격 시각입니다.
3. 파이프라인: 단계마다 함수 하나
- 공 상태 추정. 카메라가 공의 위치만 본다고 두고(120 Hz, 잡음 σ 3 mm, 지연 30 ms), 최소제곱으로 위치·속도·회전을 맞춥니다. 회전은 궤적의 휨으로만 보이므로 사전값 쪽으로 당기는 항을 둡니다.
- 비행 예측. 중력, 항력, 마그누스 힘을 RK4 로 풀고, 탁자 바운드는 충격량 모델로 처리합니다. 계수는 2편에서 잰 시뮬레이터 값입니다.
- 타격 결정. 목표 착지점(상대 코트 가운데)으로 보낼 반사 속도를 사격법으로 구하고, 거울 법칙과 충격량 모델로 라켓 법선과 휘두를 속도를 정합니다.
- 역기구학. 손목 두 각은 법선에서 바로 나오고, 갠트리는 빼기 하나입니다(아래 코드).
- 관절 궤적. 현재 상태에서 타격 순간의 (위치, 속도, 가속도 0)까지 5차 다항식으로 잇습니다. pitch 의 타격 속도가 곧 휘두르기입니다.
- 관절 제어. 계산 토크(PD + 피드포워드)로 따라가고, 힘 한계에서 자릅니다.
- 다시 계획. 바운드 전 0.2 s 에 한 번 계획하고, 바운드 뒤에는 50 ms 마다 새 관측으로 다시 맞춰 궤적을 이어 붙입니다.
def ik(c, n, rb):
"""원하는 라켓 면 중심 c 와 법선 n → 관절 [x, z, yaw, pitch]."""
n = np.asarray(n, float) / np.linalg.norm(n)
th = math.asin(max(-1.0, min(1.0, n[2]))) # pitch
psi = math.atan2(-n[0], n[1]) # yaw
x = c[0] - rb.L * math.sin(th) * math.sin(psi) # 갠트리는 손목 오프셋을 빼면 끝
z = c[2] - rb.L * math.cos(th)
y_res = c[1] - (rb.y_g - rb.L * math.sin(th) * math.cos(psi)) # 0 이어야 닿는다
q = np.array([x, z, psi, th])
ok = bool(np.all(q >= np.array(rb.lo)) and np.all(q <= np.array(rb.hi)))
return q, y_res, ok
(TT Lab 실험 코드 ttsim.py 에서 발췌했고 독스트링과 주석은 줄였습니다.)
직교 갠트리는 두 축이 라켓 위치에 그대로 더해지므로 특이점, 다중해, 수치 역기구학이 없습니다. 6축 팔이라면 같은 일을 수치 최적화와 특이점 회피로 풀어야 합니다. pitch 를 돌리면 라켓 면 중심의 속도가 정확히 면의 법선 방향이 되어, 「어디로 향할지」(각도)와 「얼마나 세게 칠지」(pitch 속도)가 깔끔하게 갈립니다.
4. 결과
| 조건 | 카메라(주기·잡음·지연, 가정값) | 플래너의 물리 계수 | 공 | 반환 성공 | 맞혔으나 실패 | 못 맞힘 | 계획 실패 |
|---|---|---|---|---|---|---|---|
| 참 상태 | 참 상태를 바로 앎 | 시뮬레이터 실측값 | 100 | 62% | 16 | 2 | 20 |
| 120 Hz·지연 30 ms | 120 Hz, 3 mm, 30 ms | 시뮬레이터 실측값 | 100 | 60% | 8 | 9 | 23 |
| 플래너만 문헌 계수 | 120 Hz, 3 mm, 30 ms | 문헌(TT3D 항력·마그누스, 탁자 e 0.85·μ 0.3) | 100 | 48% | 11 | 11 | 30 |
| 120 Hz·지연 100 ms | 120 Hz, 3 mm, 100 ms | 시뮬레이터 실측값 | 50 | 26% | 4 | 17 | 16 |
| 30 Hz·지연 100 ms | 30 Hz, 10 mm, 100 ms | 시뮬레이터 실측값 | 50 | 2% | 0 | 17 | 32 |
「맞혔으나 실패」는 탁자 밖과 자기 코트를 합친 수입니다. 지연 100 ms 조건의 50개는 30 ms 조건 100개의 앞쪽 50개와 같은 공이고, 그 50개에서 30 ms 조건의 성공률도 60% 였습니다.
| 조건 | 타격 시각 오차 중앙값 | 타격 시각의 공 예측 오차 중앙값 | 라켓 추종 오차 중앙값 | 성공한 공의 착지 오차 중앙값 |
|---|---|---|---|---|
| 참 상태 | 1.6 ms | 1.9 cm | 0.08 cm | 21.3 cm |
| 120 Hz·지연 30 ms | 2.3 ms | 3.8 cm | 0.07 cm | 18.5 cm |
| 플래너만 문헌 계수 | 2.0 ms | 3.3 cm | 0.06 cm | 12.4 cm |
| 120 Hz·지연 100 ms | 2.2 ms | 9.7 cm | 0.07 cm | 21.0 cm |
| 30 Hz·지연 100 ms | 2.2 ms | 34.6 cm | 0.05 cm | 12.4 cm(1개) |
5. 무엇이 실패를 가르나
- 제어는 병목이 아닙니다. 라켓 추종 오차 중앙값은 0.05–0.08 cm, 타격 시각 오차는 2 ms 안팎이었습니다. 토크가 한계에 걸린 회차는 참 상태와 30 ms 조건에서 각각 2개뿐이었고, 5차 궤적이 속도·가속도 한계를 넘은 계획은 100개 중 0–6개로 모두 갠트리 축이었습니다.
- 가장 큰 실패는 작업 공간입니다(계획 실패 20–30%). 「관절 한계 밖」이 12–19건, 「라켓이 닿을 수 있는 y 에 공이 오지 않음」이 6–10건이었습니다. 끝선 38 cm 뒤에 고정된 평면으로는 짧은 공과 낮은 공을 받지 못합니다. 계획에 성공한 공만 보면 반환률은 참 상태 77.5%, 30 ms 조건 77.9%, 문헌 계수 68.6% 입니다. 3편이 2단계 축으로 깊이(y)를 먼저 보자고 한 근거와 같은 방향입니다.
- 카메라는 잡음보다 지연이 훨씬 큽니다. 120 Hz 에서 지연만 30 ms 에서 100 ms 로 늘리자 60% 가 26% 가 되었고, 타격 시각의 공 예측 오차 중앙값이 3.8 cm 에서 9.7 cm 로 커졌습니다. 30 Hz·100 ms(지금 쓰는 점수판 카메라 급이라고 가정한 값)로는 2% 였습니다. 이 실험은 계획 시각을 0.2 s 로 고정했으므로, 30 Hz 에 맞춰 관측을 더 기다리는 전략을 쓰면 조금 오를 수 있습니다(추정). 3편의 「카메라 지연을 줄이는 데 돈을 쓰는 편이 모터를 키우는 것보다 싸다」는 계산과 같은 결론입니다.
- 계수가 틀리면 12%p 떨어집니다. 시뮬레이터가 DeepMind 값일 때 플래너만 문헌 계수로 바꾸자 60% 가 48% 가 되었고, 자기 코트에 떨어뜨린 공이 2개에서 9개로 늘었습니다. 2편에서 본 마그누스 세기 차이(4.2배)가 그대로 타격 실패로 이어진 것입니다. 실제 로봇에서도 우리 카메라 궤적으로 계수를 맞추는 일이 성공률에 직접 걸립니다.
- 참 상태를 알아도 62% 입니다. 남는 실패는 플래너의 충격량 모델과 MuJoCo 접촉의 차이(그래서 참 상태에서도 예측 오차가 1.9 cm, 「맞혔으나 탁자 밖」이 16건)와 작업 공간입니다. 강화학습이 이길 수 있는 곳은 이 「모델 차이」라고 봅니다(추정). 해석 모델 대신 시뮬레이터 자체에서 배우기 때문입니다.
6. 한계
- 카메라 주기·잡음·지연과 로봇의 속도·힘 한계는 가정값입니다. 우리 카메라의 실제 지연 분포는 아직 재지 않았습니다(미확인).
- 공은 조건마다 50–100개이고 한 번씩 돌렸습니다. 성공률의 신뢰 구간을 말하기에는 표본이 작습니다.
- 라켓은 마찰을 준 상자이고, 이 설정에서 잰 실효 마찰은 45° 입사에서 0.047 이었습니다. 회전을 거는 능력이 거의 없어 조준·회전 반환은 다루지 않았습니다.
- 회차별 궤적(공과 라켓의 매 스텝 위치)을 저장하지 않아서, 성공한 공과 지연으로 놓친 공을 나란히 움직이는 그림은 이번에 만들지 못했습니다. 다음 측정에서 궤적을 함께 남깁니다.
7. 다음 편으로
다음은 같은 공 표본, 같은 카메라 가정, 같은 로봇 한계에서 강화학습 두 가지(타격 파라미터만 배우는 하이브리드, 관절 목표를 직접 내는 방식)를 이 기준선과 나란히 놓는 것입니다(7편, 준비 중). 그 전에 6편에서 DeepMind 로봇의 한계를 원문으로 읽고 회전 문제를 시뮬레이터로 따져 봅니다. 실패 이유별 개수를 함께 남겨, 강화학습이 어느 실패를 줄였는지 보이게 하겠습니다.
티티 한마디. 팔은 0.7 mm 오차로 정확히 움직였는데도 열 개 중 넷을 놓쳤어요. 팔이 아니라 자리(작업 공간)와 눈(지연)이 문제였어요. 빨리 보는 눈부터 챙겨 주세요!
참고
모든 링크는 2026-10-18 에 열람해 열리는 것을 확인했습니다.
- DeepMind, Achieving Human Level Competitive Robot Table Tennis(ICRA 2025): https://arxiv.org/abs/2408.03906
- 공개 초기 공 상태: https://github.com/google-deepmind/competitive_robot_table_tennis(© 2025 Google LLC, CC BY 4.0. 데이터는 다시 배포하지 않고 시뮬레이션 결과만 실었습니다.)
- TT3D: Table Tennis 3D Reconstruction(2025, 플래너의 문헌 계수): https://arxiv.org/abs/2504.10035
- Sony AI, Physics Models for Sim-to-Real Transfer in Professional-Level Robot Table Tennis(2026, 라켓 반발 식 비교): https://arxiv.org/abs/2606.28805
- MuJoCo: https://github.com/google-deepmind/mujoco
- 인용 코드는 TT Lab 실험 코드입니다.