TT Lab
요금제

한국어

시작하기
블로그

블로그

탁구공 물리를 MuJoCo 로 재기: 반발, 항력, 회전이 시뮬레이터 설정 한 줄에 달려 있다

상태: 초안 (2026-10-18), 실측. 공 물리 1단계(A–E) 완료. 이 모델 위에서 돌린 고전 제어 기준선은 5편에, 강화학습은 이후 편에 적습니다. 측정은 2026-10-18 에 홈랩 쿠버네티스의 임시 파드 하나에서 했습니다. 노드는 미니 PC 한 대(Intel Core Ultra 9 185H)이고, 파드 상한은 CPU 3코어·메모리 3 GiB, GPU 없음, 오프스크린 렌더링 끔(MUJOCO_GL=disable)입니다. 이미지는 python:3.12 에 pip 로 mujoco 3.16.0, numpy 2.5.4, scipy 1.18.1 을 더했습니다(설치 11.6 s). 파드 메모리 최고치는 725 MB 였습니다. MuJoCo 는 같은 입력에 같은 결과를 내므로 표의 값은 한 번 돌린 값이고, 흩어짐은 접촉 위상(A4, 50가지)과 공 표본(D, 500개)으로 따로 냈습니다. 원자료는 작업 디렉터리 tt-robot/out/(표와 그림)과 tt-robot/logs/(실행 로그)에 있습니다.

목차

1. 직관: 2.7 g 짜리 공은 설정에 민감하다

탁구공은 지름 40 mm, 무게 2.7 g 입니다. 7 m/s 로 날아가는 공에 걸리는 공기 힘은 무게와 비슷한 크기이고, 회전이 크면 무게보다 커집니다. 탁자에 닿는 시간은 1 ms 남짓입니다. 그래서 시뮬레이터의 시간 간격, 접촉의 단단함, 유체 계수 같은 설정 몇 개가 공의 길을 크게 바꿉니다.

로봇에게 탁구를 가르치려면 먼저 「시뮬레이터 안의 공이 진짜 공처럼 나는가」를 알아야 합니다. 이 글은 진짜 공의 궤적이 아직 없는 상태에서 할 수 있는 일, 곧 공개된 설정을 그대로 넣고, 문헌의 값과 나란히 놓고, 어느 설정이 결과를 가장 크게 흔드는지 재는 일을 합니다.

2. 모델: DeepMind 공개 MJCF 의 값 그대로

DeepMind 는 ICRA 2025 탁구 논문과 함께 공의 초기 상태 15,792개(랠리 13,088개, 서브 2,704개)와 MuJoCo 노트북을 공개했습니다. 노트북의 값을 그대로 옮겼습니다.

항목 값
시간 간격, 적분기 1 ms, implicitfast
공 질량 2.7 g, 반지름 0.02 m, 얇은 껍질 구
유체 계수(fluidcoef) 0.235 0.25 0.0 1.0 1.0
공과 탁자 접촉 solref -1000000 -17(강성 1e6, 감쇠 17), friction 0.1
좌표 원점은 탁자 윗면 가운데, x 폭 1.525 m, y 길이 2.74 m, z 위. 로봇 쪽은 y < 0

유체 힘은 MuJoCo 가 qfrc_fluid 에 따로 담아 줍니다. 중력을 끄고 속도와 회전만 준 뒤 이 값을 읽으면 항력과 마그누스 힘을 직접 잴 수 있습니다.

s = Sim(base.with_(gravity=False))
for v in [2, 5, 10, 15, 20, 25, 30]:
    s.reset([0, 0, 1], [0, v, 0], [0, 0, 0])
    fd = -s.d.qfrc_fluid[1]                    # 진행 방향 반대 힘 = 항력
    cd = fd / (Q * v * v)                      # Q = ½ρA
    for S in [0.0, 0.1, 0.2, 0.4, 0.6, 1.0]:   # 회전비 S = rω / v
        w = S * v / BALL_R
        s.reset([0, 0, 1], [0, v, 0], [-w, 0, 0])   # 탑스핀
        fm = -s.d.qfrc_fluid[2]                # 아래로 누르는 힘 = 마그누스
        km = fm / (w * v) if w > 0 else float("nan")

(TT Lab 실험 코드 exp_b_magnus.py 에서 발췌. Sim 은 MJCF 를 만들고 mj_forward 까지 부르는 작은 감싸개입니다.)

3. 30 cm 낙하: 공이 너무 잘 튄다

ITTF 규정은 30 cm 에서 떨어뜨린 공이 약 23 cm 튀어야 한다고 정합니다. 공기저항을 무시하면 반발 계수 e ≈ √(23/30) = 0.876 입니다.

30 cm 에서 떨어뜨린 공, 같은 탁자 값 시뮬레이션 시간 간격(dt)만 1 ms 와 2 ms 로 다릅니다. 5배 느리게. ▶ 누르면 재생 탁자면 놓은 높이 30 cm ITTF 규정 약 23 cm dt 1 ms, e 0.978 꼭대기 26.4 cm dt 2 ms, e 3.004 ↑ 꼭대기 1.96 m (화면 밖) 높이는 A1 실측(반발 속도·꼭대기)과 같은 공기저항으로 다시 그린 움직임입니다. dt 2 ms 는 접촉 강성에 비해 간격이 커서 에너지가 생겨 3배로 튕깁니다.
그림: 30 cm 에서 떨어뜨린 공의 반발, 시간 간격 1 ms 와 2 ms
모델 입사 속도 반발 속도 e 꼭대기 규정 23 cm 대비
MuJoCo, dt 0.25 ms −2.375 m/s 2.299 m/s 0.968 26.0 cm +3.0 cm
MuJoCo, dt 0.5 ms −2.373 m/s 2.308 m/s 0.973 26.2 cm +3.2 cm
MuJoCo, dt 1 ms −2.368 m/s 2.317 m/s 0.978 26.4 cm +3.4 cm
MuJoCo, dt 2 ms −2.368 m/s 7.114 m/s 3.004 196.4 cm 발산
TT3D 의 e 0.85(같은 입사 속도·같은 저항으로 계산) 0.850 20.2 cm −2.8 cm
Sony AI 2026 의 e 식(같은 방법으로 계산) 0.932 24.2 cm +1.2 cm

(그림의 움직임은 표의 반발 속도로, 실측과 같은 공기저항 C_D 0.471 을 넣어 다시 그렸습니다. 다시 그린 꼭대기는 26.4 cm 와 195.9 cm 로 표와 맞습니다.)

충돌 속도를 1–8 m/s 로 바꿔 보면 차이가 더 분명합니다. MuJoCo 의 e 는 0.96–0.99 로 거의 평평한데, Sony AI 2026 의 식(e = 0.98 − 0.02·입사 속도)은 속도가 빠를수록 e 가 내려갑니다.

충돌 속도별 탁자 반발 계수 e 0.80 0.85 0.90 0.95 1.00 0 2 4 6 8 입사 속도 |v_z| (m/s) MuJoCo dt 1 ms MuJoCo dt 0.5 ms Sony 2026 식 ITTF 30 cm→23 cm 는 e ≈ 0.876 입니다. ITTF 0.876
그림: 충돌 속도별 탁자 반발 계수, MuJoCo 대 Sony 2026 식

4. 공기: 마그누스 힘이 문헌보다 4.2배 세다

출처 C_D 마그누스 계수 k_M (N·s²/rad/m) MuJoCo 대비
MuJoCo, DeepMind 값(실측) 0.471 2.053e-5 1.00
TT3D 2025 0.494 4.860e-6 0.237
Tebbe 외 2020(C_D 0.4, C_M 0.6, 힘의 꼴은 추정) 0.400 9.236e-6 0.450
Sony AI 2026 저속 0.55, 17.5 m/s 에서 0.37–0.51 회전비의 함수(이 글에서는 수치를 쓰지 않음)

같은 타구(로봇 쪽 끝선 뒤 y = −1.6 m, 높이 0.2 m 에서 속도 (0, 7, 1.6) m/s)에 회전만 바꿔 넣으면 차이가 착지점으로 드러납니다.

같은 타구, 회전만 바꿨을 때 첫 착지 위치 로봇 쪽 끝선 뒤에서 7 m/s 로 친 공. 가로축은 탁자 길이 방향 y(m). 네트 상대 코트 친 쪽 -1 0 1 2 3 4 5 탑스핀 300 탑스핀 150 무회전 백스핀 150 백스핀 300 속이 빈 표시는 네트에 걸린 공입니다(문헌 식은 네트 높이 아래로 지나가면 걸림으로 판정). MuJoCo(DeepMind 값) TT3D 식 Tebbe 식(힘의 꼴 추정)
그림: 같은 타구에서 회전만 바꿨을 때 모델별 첫 착지 위치
회전 MuJoCo 착지 y TT3D 식 착지 y 비고
탑스핀 300 rad/s −0.315 m(친 쪽 코트) 0.355 m TT3D 는 네트 높이보다 1.2 cm 낮게 지나 네트로 판정
무회전 0.812 m 0.789 m 두 모델이 2.3 cm 안에서 같음
백스핀 150 rad/s 3.684 m(밖), 꼭대기 51.3 cm 1.093 m
백스핀 300 rad/s 5.378 m(밖), 꼭대기 139.6 cm 1.482 m(밖)

무회전 공은 두 모델이 거의 같고, 회전이 들어가면 MuJoCo 쪽이 크게 휩니다. 문제는 공개 데이터의 회전 값이 바로 이 MJCF 와 함께 쓰이도록 만들어졌을 수 있다는 점입니다(추정). 그렇다면 회전 값과 마그누스 계수는 짝으로만 써야 하고, 한쪽만 문헌 값으로 바꾸면 안 됩니다. 6절의 민감도가 그 근거입니다.

5. 비스듬한 바운드: 탁자가 미끄럽다

탁자 바로 위에서 수평 속도 3, 6, 9 m/s, 수직 속도 2, 4 m/s, 회전 −300, 0, +300 rad/s 를 조합해 바운드 직전과 직후의 상태를 비교했습니다.

6. 공개 초기 상태 500개: 무엇이 가장 크게 흔드나

랠리 13,088개 가운데 로봇 쪽으로 오는 공 11,999개에서 500개를 무작위로(seed 0) 뽑아 DeepMind 값의 MuJoCo(dt 1 ms)로 날렸습니다. 공개 데이터에는 궤적이 없고 초기 상태만 있습니다. 그래서 아래는 실제 공과의 비교가 아니라 「같은 초기 상태에서 시뮬레이터가 내놓는 값」과 그 민감도입니다.

지표 5% / 50% / 95%
초기 속력 3.80 / 5.49 / 7.89 m/s
초기 회전 12.21 / 57.55 / 101.60 rad/s
로봇 쪽 탁자 착지 100.0%(네트 접촉 0.6%)
첫 바운드까지 0.30 / 0.42 / 0.60 s
바운드 직후 속력 3.82 / 4.50 / 5.61 m/s
타격면(y = −1.6 m) 도달 0.51 / 0.71 / 1.06 s
타격면 높이 0.01 / 0.31 / 0.47 m

같은 500개를 설정만 바꿔 다시 날리고, 짝지어 타격면에서의 위치 차이를 보았습니다. 라켓 판의 반폭이 약 7.5 cm 이므로, 차이가 수 cm 를 넘으면 정책이 헛칩니다.

계수를 바꾸면 타격면에서 공이 얼마나 비켜 가나 공개 초기 상태 500개를 짝지어 비교. 막대 진한 부분 중앙값, 옅은 부분 95%. 라켓 반폭 7.5 cm dt 0.5 ms 1 / 3.8 C_D 0.40 2.5 / 12.5 C_D 0.55 2.7 / 13.2 탁자 μ 0.3 0.7 / 6 e ITTF ×1.08 4.7 / 10.1 탁자 e = ITTF 6.9 / 15.2 마그누스 ×0.5 12.4 / 37.6 마그누스 ×0.24 17.7 / 57.3 마그누스 0 23.2 / 78.9 문헌 값 조합 17.4 / 57.3 0 20 40 60 80 타격면(y = −1.6 m) 위치 차이 (cm) 기준: DeepMind 공개 MJCF 값, dt 1 ms. 「e ITTF ×1.08」 만 ITTF e 를 기준으로 비교.
그림: 계수를 바꿨을 때 타격면 위치 차이의 중앙값과 95%
바꾼 것 타격면 위치 차이 중앙값 / 95% 로봇 쪽 착지율 변화
dt 0.5 ms / 0.25 ms 1.0 / 3.8 cm, 0.7 / 3.2 cm 0
C_D 0.40 / 0.55 2.5 / 12.5 cm, 2.7 / 13.2 cm −1.4 / 0 %p
탁자 μ 0.25 / 0.3 0.6 / 5.1 cm, 0.7 / 6.0 cm 0
탁자 e 를 규정 값 0.876 으로 6.9 / 15.2 cm 0
규정 e 에서 ±8% 4.7 / 10.1 cm, 4.6 / 9.8 cm 0
마그누스 ×0.5 12.4 / 37.6 cm −11.0 %p
마그누스 ×0.24(TT3D 세기) 17.7 / 57.3 cm −23.0 %p
마그누스 0 23.2 / 78.9 cm −32.2 %p
문헌 값 조합(C_D 0.49, 마그누스 ×0.24, 규정 e, μ 0.3) 17.4 / 57.3 cm −21.2 %p

7. 라켓: 공이 판을 뚫고 지나간다

라켓 판(15×16 cm, 두께 6 mm·14 mm)을 고정해 두고 공을 정면으로 쏘았습니다. 접촉이 시간 간격 사이 어디에서 시작하는지(위상)를 30–50가지로 흔들어, 되튀는지 뚫고 지나가는지 셌습니다.

라켓 접촉 강성과 시간 간격: 뚫리거나 튀거나 판 두께 14 mm, 공 속도 20·30·40 m/s 각 30회(접촉 위상을 흔듦). 칸마다 관통·불안정 횟수/90. 0.1 ms 0.25 ms 0.5 ms 1 ms 2 ms 1e6(DeepMind) 관통 60 관통 60 관통 60 관통 60 59/8 4e6(채택) 안정 안정 안정 11/51 56/26 1.6e+07 안정 안정 튐 60 13/74 43/47 6.4e+07 안정 튐 60 튐 81 11/74 39/51 2.56e+08 튐 41 튐 86 튐 89 13/77 41/49 √k·dt = 1 경계(왼쪽이 √k·dt ≤ 1) 「관통 a」 a 회 판을 뚫음, 「튐 b」 e > 1.05 로 튄 횟수, 「a/b」 둘 다. 굵은 테두리가 채택한 조합. 강성 k 의 단위는 1/s². 위의 dt 는 MuJoCo 의 timestep.
그림: 라켓 접촉 강성과 시간 간격 격자: 관통과 불안정 횟수

결정. 물리 시간 간격은 0.5 ms, 라켓 접촉은 solref (−4e6, −34)(감쇠비는 DeepMind 값과 같게)입니다. 14 mm 판, 40 m/s 에서 관통 0/30, 불안정 0/30 이었습니다. 이 설정에서 잰 라켓의 반발 계수는 4 m/s 에서 0.931, 8 m/s 에서 0.893 으로, Sony AI 2026 식(0.80, 0.72)보다 큽니다. 실제 러버가 파고드는 깊이와 접촉 시간에 맞춘 값은 아닙니다(미확인). 탁자는 DeepMind 강성 그대로 두었습니다. 탁자에 닿는 수직 속도는 8 m/s 를 넘지 않는다고 보았고(추정), 8 m/s 까지는 3절에서 안정이었습니다.

8. 계산은 싸다

공과 탁자만 있는 모델은 1코어로 초당 23만–36만 스텝을 돌았습니다. 같은 측정을 두 번 했는데 노드의 다른 부하에 따라 이만큼 달랐습니다(나중 측정: dt 0.25–1 ms 에서 229,806–239,229 스텝/s). dt 0.5 ms 면 실시간의 120–180배입니다. 스레드 3개로 공 512개를 한꺼번에 굴리면 초당 58만–122만 스텝이었습니다. 갠트리 2축과 손목 2축 로봇을 넣은 모델은 dt 0.5 ms 에서 1스레드 초당 152,611 스텝(실시간 76배)이었습니다. 이 단계에는 GPU 가 필요 없습니다. 실험 시간도 짧았습니다. 낙하 묶음(A)은 11.3 s, 공기역학 묶음(B)은 3.6 s, 바운드(C)는 0.5 s, 500개 민감도(D)는 28.7 s 였습니다.

9. 한계

10. 다음 편으로

이 공 모델 위에 로봇을 올려 「보고, 예측하고, 휘두르는」 고전 제어 기준선을 돌린 결과는 5편에 있습니다. 강화학습은 그 기준선을 넘는지로 평가합니다. 로봇의 몸을 어떻게 만들지는 바로 다음 3편에서 봅니다.

티티 한마디. 같은 공인데 시뮬레이터 설정 한 줄 바꿨다고 26 cm 튀던 공이 2 m 가까이 솟았어요. 탁구공이 가볍다고 우습게 보면 안 돼요. 계수는 데이터와 짝으로 다뤄 주세요!

참고

모든 링크는 2026-10-18 에 열람해 열리는 것을 확인했습니다.

로그인하면 좋아요를 누를 수 있습니다

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다