TT Lab
Blog

한국어 English 中文

Get started
Blog

Blog

Until a Table Tennis Robot Returns a Ball: Calculations Seen Through a Step-by-Step Simulation Video

Status: Draft (2026-10-18), measured. All numbers in the screen and text are values from within the simulator, and camera period, delay, and noise are assumed values. Recording and rendering were performed on 2026-10-18 as a temporary pod on a single mini PC node of the home lab Kubernetes cluster. The pod limits were 6 CPU cores and 3 GiB of memory (peak usage 1.5 GiB), and no GPU was used. The environment consists of MuJoCo 3.16.0, Python 3.11, numpy 2.3.4, Mesa 23.2.1 (llvmpipe, OSMesa), and ffmpeg 4.4.2 (libx264). Physics and control are the same as in Part 7 (time step 0.5 ms, control 1 kHz, learned hybrid policy seed 0). Evaluation ball #201 was run in four variations (learned hybrid delay 30 ms and 100 ms, classical baseline 30 ms, learned-free nominal planner 30 ms). Because it is a deterministic run, each was executed once, and all four results matched the results (result type and landing point) of the same ball and conditions in the Part 7 evaluation file. Raw data (recording out/rec/ball201.json, numbers in the text out/facts.json, and recording, rendering, and plotting scripts) are located in the working directory measure/sim-tt-video/ .

Table of Contents

1. Intuition: Seven Calculations Happening Over 1.3 Seconds

Parts 5 and 7 discussed success rates across 500 balls. While the numbers are accurate, what the robot calculates and when it calculates it while receiving a single ball is not clearly visible. This time, we follow a single ball from beginning to end and expose the values inside the robot's mind at every moment onto the screen. what and when it calculatesis not readily apparent. This time, we follow a single ball from start to finish, bringing the values inside the robot's mind at every moment onto the screen.

It takes 1.307 s from the initial state in the public data (a ball above the opponent's baseline, flying toward our side) until it passes through our robot and lands on the opponent's court. There are seven stages in between.

  1. Observation. The camera captures the ball's position, and those points arrive late.
  2. Prediction. The arrived points are used to fit the ball state and project the future path.
  3. Strike Decision. Working backward from the target landing point, it determines when, where, with what face orientation, and how hard to hit.
  4. Inverse Kinematics. That racket posture is translated into four joint values.
  5. Trajectory and Swing. Fifth-order polynomials are connected for each joint from the current posture to the target posture, and followed.
  6. Contact. The ball hits the racket, and its velocity and spin change.
  7. Landing. The ball lands on the opponent's court.

The robot uses the same real-scale 2-axis gantry (x for side, z for height) + 2-axis wrist (yaw, pitch) as in Part 5, and control is the learned hybrid from Part 7. The policy corrects only 6 strike parameters, while all others are handled by the classical calculations shown below.

2. How the Video and Figures Were Created

2.1 Overall Process

공 하나를 넘기기까지: 옆에서 본 전체 과정 평가 공 201번, 120 Hz·지연 30 ms(가정), 학습한 하이브리드. 녹화 궤적(1 ms)을 5배 느리게. 가로축은 탁자 길이 방향(오른쪽이 상대), 세로축은 높이. ▶ 누르면 재생 타격면 목표 0.75 m 1 관측 2–4 예측·결정·역기구학 5 스윙(1차 계획) 5 다시 계획 6 접촉 7 착지 0.200 s 첫 결정 · 0.497 s 다시 계획 · 0.543 s 접촉 · 1.307 s 착지(오차 3.7 cm) 하늘색 점 0.2 s 에 도착한 관측, 올리브 점선 1차 예측, 보라 원 칠 위치(1차·2차), 빨간 선분 라켓 면.
Figure: Overall process viewed from the side until a single ball is returned. Click to play at 5x slower speed.
Stage Simulator View What is Visible in the Video Playback Speed
1 Observation 0–0.200 s Captured points (gray) and arrived points (sky blue) 1/20
2 Prediction Paused at 0.200 s Quadratic fit, predicted path, estimated spin vs. true spin Paused
3 Strike Decision Paused at 0.200 s Hit position, racket target, face normal, targeted path and landing point Paused
4 Inverse Kinematics Paused at 0.200 s Current posture and target posture, four joint values Paused
5 Trajectory and Swing 0.200–0.539 s Planned racket path vs. actual, joint reference vs. actual graphs, re-planning at 0.497 s 1/10
6 Contact 0.513–0.583 s Incoming and outgoing velocity arrows, speed and spin 1/10
7 Landing 0.543–1.307 s Actual path vs. planned path, landing error 1/4
Comparison 0–0.700 s Baseline vs. hybrid for the same ball, 30 ms delay vs. 100 ms delay 1/4

The video is 1280×720, 30 fps, 65.6 s (1,967 frames), H.264 2.6 MB. Since videos embedded in a single article are limited to 30 s, stage-specific clips (4.7–8.1 s) were placed in each section, with a still image of the exact moment placed right below each.

2.2 Recording: Extracting Calculations Without Changing Them

The recorded trajectory from Part 7 (rec_*.json) contains only ball and racket positions at 5 ms intervals. To show the step-by-step calculations, we needed observation points, fitted quadratics, prediction paths, plans per decision, and joint reference values, so the same environment was re-run with the same seed (777000 + ball number). The environment code was left unchanged and read from a subclass. States are transcribed at every 1 ms control step, and estimated values and plans are transcribed at every decision.

class RecEnv(ttenv.TTEnv):
    def _tick(self, qr, vr, ar):
        done = super()._tick(qr, vr, ar)          # 물리·제어는 원래 코드 그대로
        d = self.d
        v, w = ball_world(self)                   # 세계 좌표 속도·각속도
        self.ticks.append([round(self.t, 6), *d.qpos[:11].tolist(), *d.qvel[6:10].tolist(),
                           *np.asarray(qr).tolist(), *v.tolist(), *w.tolist(), ...])
        return done

Source: TT Lab experiment code sim-tt-video/src/vid_record.py(contact indicator column omitted).

Recording results (result type, landing point) were checked against the values for the same ball and conditions in the Part 7 evaluation file, matching across all four cases. This confirms that the exact same calculations were re-executed.

2.3 Rendering: Numbers from the Recording, Figures Using a Visualization-Only Model

The robot in the physics model has no geometry other than the racket, so rendering it directly leaves only the racket floating in mid-air. Therefore, a separate visualization-only modelwith identical joint layouts (qpos order, positions, axes, racket size) was created by attaching rails, carriages, wrists, and handles, and the recorded qpos values were fed directly into it to render using MuJoCo's off-screen renderer. This model does not calculate contacts. Indicators such as observation points, prediction paths, and strike points were added to the MuJoCo scene as geometries, and subtitles and numbers were rendered on top of the frames using NanumGothic. All numbers on the screen were read from the recording file, with only direct transformations applied, such as speed (vector magnitude), angles, and cm conversions. Frames between 1 ms records (1.67 ms intervals at 1/20 playback speed) were rendered by linearly interpolating ball and joint positions.

3. Stage 1 Observation: Captured Points Arrive Late

Video: Video Stage 1 Observation (1/20x Speed)
1단계 관측: 찍은 점과 로봇에 도착한 점 0.2 s 까지 찍은 24개 중 지연 30 ms 를 지나 도착한 것은 21개. 높이를 5배 늘려 그림. t = 0 t = 0.2 s 0.00 s 0.05 s 0.10 s 0.15 s 0.20 s 지연 30 ms: 아직 도착 전 도착한 관측 찍었지만 도착 전 공의 실제 경로 찍는 간격은 약 8.3 ms(1 ms 제어 주기에 맞춰 찍음), 위치 잡음 σ 3 mm. 공의 처음 속력 7.78 m/s.
Figure: Stage 1 Observation: Captured and arrived points up to 0.2 s, delay 30 ms

General principles for estimating ball states from observations (such as Kalman filters) can be found in "Basics of Table Tennis Robot Arms", Chapter 6, Ball Flight Equations.

4. Stage 2 Prediction: Quadratic Fitting and RK4/Bounce Models

Video: Video Stage 2 Flight Prediction
2단계 예측: 2차식 맞춤과 RK4·바운드 모델 0.2 s 의 예측(올리브 점선)과 실제 경로(주황). 0.497 s 에 바운드 뒤 관측으로 다시 맞춘다. 맞춘 2차식 1차 예측 2차 예측 실제 로봇의 추정참값(시뮬레이터) 0.2 s 속도 (m/s)(-1.23, -6.29, -0.39)(-1.14, -6.20, -0.74) 0.2 s 회전 ω (rad/s)(82, -16, 4)(55, 3, 15) 0.497 s 회전 ω (rad/s)(131, -25, 4)(98, -7, 15) 바운드 시각0.415 s0.429 s 바운드 (x, y) m(-0.47, -1.16)(-0.47, -1.26) 예측 바운드와 실제 바운드의 거리 10.3 cm. 회전은 가속도의 작은 차이로만 보여 크게 어긋난다.
Figure: Stage 2 Prediction: Fitted quadratic, predictions at 0.2 s and 0.497 s, actual path

Calculation. A quadratic equation of position with respect to time is fitted via least squares to arrived points (up to the latest 36), yielding the position, velocity, and acceleration at the last observation time. The fit at 0.2 s used 21 observations, with an acceleration of (1.56, 6.90, −13.49) m/s². Subtracting gravity and drag from the acceleration, the remaining share is treated as the Magnus force (k_M/m) ω×v to solve for ω. Since spin only appears as slight differences in acceleration, a prior term pulling toward 0 (standard deviation 300 rad/s) is applied. With this state, the planner's physics (drag coefficient 0.471, Magnus coefficient, table restitution 0.975, friction 0.10) are simulated using RK4 at 4 ms intervals, bouncing using an impulse model when contacting the table.

Values at 0.2 s Robot's Estimate True Value (Simulator)
Velocity (m/s) (−1.23, −6.29, −0.39) (−1.14, −6.20, −0.74)
Spin ω (rad/s) (82, −16, 4) (55, 3, 15)
Bounce Time 0.415 s 0.429 s
Bounce Position (x, y) m (−0.47, −1.16) (−0.47, −1.26)

The predicted bounce was 14 ms faster and 10.3 cm ahead of the actual. Spin estimation shows the largest discrepancy (as seen in Chapter 6, position alone provides only weak visibility into spin).

Re-fitting After Bounce. The robot detects a bounce when the height of arrived points reaches a minimum and rises again by more than 1 cm. For this ball, 0.425 s was identified as the bounce, and the second decision was made at 0.497 s , after 4 subsequent observations arrived. If fewer than 6 observations are available, acceleration is set to gravity, only a straight line is fitted, and spin directly uses the value passing the first estimate through the bounce model, (131, −25, 4) rad/s (true value: (98, −7, 15)). The equations for this calculation are found in the Gravity, Drag, Magnus, and Bounce Model section of "Basics of Table Tennis Robot Arms", Chapter 6.

5. Stage 3 Strike Decision: Working Backwards from the Landing Point

Video: Video Stage 3 Strike Decision
3단계 타격 결정: 위에서 본 칠 위치·면 방향·노린 경로 0.2 s 의 1차 결정. 착지점에서 거꾸로 나가는 속도를 풀고, 면 법선과 면 속도를 정한다. 갠트리 x ±0.9 m 노리는 착지점 (0, 0.75) 칠 위치 실제 공 예측 법선(정책 보정 후) 명목 법선 노린 경로 칠 시각0.556 s (결정에서 356 ms 뒤) 칠 위치 b (m)(-0.59, -1.75, 0.32) 면 yaw / pitch-7.7° / 0.4° (명목 -12.3° / 4.7°) 면 속도(법선 방향)1.10 m/s (명목 0.48 m/s) 원하는 나가는 속도(1.02, 4.38, 2.27) m/s, 5.04 m/s 정책 출력(보정)yaw +4.7°, pitch -4.0°, 면 속도 +0.63 m/s, 시각 +7.0 ms, 중심 x -0.6 cm, z -2.7 cm
Figure: Stage 3 Strike Decision: Hit position, face orientation, and targeted path viewed from above

Calculation. Three items are solved sequentially.

  1. Outgoing Velocity. The target landing point is the center of the opponent's court at (0, 0.75) m. Setting the horizontal velocity to 4.5 m/s and determining the flight time T = distance / 4.5, v_z is chosen such that a parabola with only gravity reaches table height.
  2. Face Normal and Face Velocity. The direction of the difference between outgoing and incoming velocities is taken as the normal vector n, and the normal component of face velocity v_pn = v_in·n + (Δv·n)/(1+e) is determined using the restitution coefficient e. Expected outcomes are recalculated three times using an impulse model incorporating friction.
  3. Hit Time. Since the gantry lacks a depth (y) axis, the y coordinate reachable by the racket is determined solely by the wrist angles. The time when the predicted path intersects that y coordinate is the hit time.
def _v_des(self, b):
    dx, dy = TARGET[0] - b[0], TARGET[1] - b[1]
    dist = math.hypot(dx, dy)
    vh = 4.5
    Tf = dist / vh
    vz = (T.BALL_R - b[2] + 0.5 * G * Tf * Tf) / Tf
    return np.array([dx / dist * vh, dy / dist * vh, vz])

Source: TT Lab experiment code rl/src/ttenv.py(same file as Part 7).

The learned policy adds six corrections to these nominal values (within the ranges of ±20° for face yaw and pitch, ±1.5 m/s for face velocity, ±20 ms for hit time, and ±6 cm for racket center x and z).

First decision at 0.2 s Nominal (no learning) After policy correction
Hit time 0.552 s 0.556 s (356 ms after decision)
Hit position b (m) (−0.58, −1.74, 0.32) (−0.59, −1.75, 0.32)
Face yaw / pitch −12.3° / 4.7° −7.7° / 0.4°
Face velocity (normal direction) 0.48 m/s 1.10 m/s
Desired outgoing velocity (1.03, 4.38, 2.26) m/s (1.02, 4.38, 2.27) m/s, 5.04 m/s

Converting the policy output into units gives yaw +4.7°, pitch −4.0°, face velocity +0.63 m/s, hit time +7.0 ms, center x −0.6 cm, and z −2.7 cm. The equations for inversely calculating the racket velocity and normal at the desired landing point are found in Part 7, Hitting Equations, of "Fundamentals of Table Tennis Robot Arms".

6. Step 4 Inverse Kinematics: Four Lines of Closed-Form Equations

Video: Video of Step 4 Inverse Kinematics
4단계 역기구학: 상대 쪽에서 본 갠트리와 손목 닫힌 해: 손목 두 각은 법선에서, 갠트리 두 축은 라켓 중심에서 손목 오프셋을 빼서. x 레일(±0.9 m, 오른쪽이 -x) 탁자 윗면 높이 지금(0.2 s) 목표 공(칠 위치) 관절값식 (L = 0.15 m) 갠트리 x-0.595 mc_x − L·sin(pitch)·sin(yaw) 갠트리 z+0.144 mc_z − L·cos(pitch) 손목 yaw-7.7°atan2(−n_x, n_y) 손목 pitch+0.4°asin(n_z) c = b − n·(공 반지름 + 라켓 두께/2) + 정책의 중심 보정. 네 값 모두 한계 안(잘라 낸 값 없음).
Figure: Step 4 Inverse Kinematics: Current and Target Poses of the Gantry Viewed from the Opponent's Side

Because the gantry uses Cartesian coordinates, inverse kinematics finishes without iterative calculations. The two wrist angles come directly from the desired normal, and the two gantry axes are obtained by subtracting the wrist offset from the racket center.

def ik(c, n, rb: Robot):
    n = np.asarray(n, float) / np.linalg.norm(n)
    th = math.asin(max(-1.0, min(1.0, n[2])))
    psi = math.atan2(-n[0], n[1])
    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))
    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

Source: TT Lab Experiment Code sim/ttsim.py(explanatory comments omitted).

Joint Current (0.2 s) First Target Limit
Gantry x 0.000 m −0.595 m ±0.9 m
Gantry z 0.150 m 0.144 m −0.15–0.7 m
Wrist yaw 0.0° −7.7° ±80°
Wrist pitch 0.0° 0.4° ±80°

The racket center is c = b − n·(ball radius + racket thickness/2) plus the policy's center correction. All four values were within limits, so no clipping occurred. y_res is the depth-direction difference that the gantry cannot match; it was 0 in the nominal plan and −2.9 cm in the first target incorporating policy correction. General arm topics such as dual solutions, singularities, and no-solution cases are covered in Part 4, Inverse Kinematics, of "Fundamentals of Table Tennis Robot Arms".

7. Step 5 Trajectory and Swing: Redrawing the Path in 39 ms

Video: Video of Step 5 Trajectory Generation and Swing (1/10 speed)
5단계 궤적과 추종: 5차 다항식 기준과 실제 관절 점선은 제어기가 받은 기준(1차 계획, 0.497 s 부터 2차 계획), 실선은 실제 관절. 갠트리 x (m) -0.58 0.00 다시 계획 손목 pitch (°) 0 30 접촉 0.2 s 0.3 s 0.4 s 0.5 s 2차 계획은 접촉까지 39 ms: x 가속도 323 m/s², z 98 m/s² 를 요구(한계 40·30). 한계에서 잘려 접촉 순간 x 가 기준과 6.6 cm 어긋났다(1차 계획 동안 x 오차 최대 0.3 cm).
Figure: Step 5 Trajectory and Tracking: Quintic Polynomial References and Actuals for Gantry x and Wrist Pitch

Calculation. Every time a decision is made, a quintic polynomial is connected for each joint from the current joint position, velocity, and acceleration to the target at the moment of impact (position q, velocity (0, 0, 0, −v_pn/L), acceleration 0). After the swing, pitch stops over 0.12 s. 1 kHz computed torque control (PD + feedforward, natural frequency 50 rad/s) follows this reference, and accelerations and velocities are clipped at axis limits.

The principle of quintic polynomials matching positions, velocities, and accelerations at both ends and minimum-time trajectories within limits are covered in Part 8, Trajectory Generation, and computed torque control in Part 9, Control, of "Fundamentals of Table Tennis Robot Arms".

8. Step 6 Contact: Events Within 1 ms

Video: Video of Step 6 Contact (1/10 speed)
6단계 접촉: 옆에서 본 라켓 면과 공 점은 공(4 ms 간격), 화살표는 속도(1 m/s 당 3 cm, 겹치지 않게 위아래로 비켜 그림). 라켓 면 상대 쪽 → 속력 회전 진행 방향 기준 들어온 공 4.51 m/s 98.9 rad/s 탑스핀 97.6 rad/s 나간 공 4.89 m/s 98.7 rad/s 백스핀 95.8 rad/s 회전 벡터는 거의 그대로(1.5 rad/s 변화)인데 공의 방향이 뒤집혀 탑스핀이 백스핀이 된다. 계획이 원한 나가는 속력 5.06 m/s, 접촉 0.543 s(계획 0.536 s), 라켓 면 중심 0.69 m/s.
Figure: Step 6 Contact: Side View of Racket Face and Ball, Incoming and Outgoing Velocities

The video shows this scene at 1/10 speed. Contact between the ball and the racket was recorded for 1 ms, which is one log slot (two physics steps).

Speed Spin Magnitude Relative to Travel Direction
Incoming ball (0.542 s) 4.51 m/s 98.9 rad/s Topspin 97.6 rad/s
Outgoing ball (0.544 s) 4.89 m/s 98.7 rad/s Backspin 95.8 rad/s

9. Step 7 Landing: 3.7 cm from Target

Video: Video of Step 7 Landing (1/4 speed)
7단계 착지: 계획한 경로와 실제 경로, 착지 오차 위: 옆에서 본 나가는 공. 아래: 위에서 본 상대 코트(목표 주변 확대). 꼭대기 0.68 m 실제(학습한 정책) 계획이 노린 경로(중력만) 명목(학습 없음) 목표 학습한 정책 3.7 cm 명목 22.1 cm y 0.35 m1.05 m 착지점 (-0.004, 0.713) m, 네트 위 여유 36.7 cm, 타격에서 착지까지 0.764 s. 실제 경로는 백스핀의 마그누스 힘과 항력 때문에 중력만 둔 계획보다 높이 떴다.
Figure: Step 7 Landing: Planned vs. Actual Trajectory and Landing Error
Metric Learned Hybrid Nominal (no learning)
Landing point (x, y) m (−0.004, 0.713) (−0.007, 0.529)
From target (0, 0.75) 3.7 cm 22.1 cm
Peak height 0.68 m 0.47 m
Result Return successful Return successful

10. Comparison: Same Ball, Different Methods and Latencies

Video: Video Comparison 1: Same Ball with Classical Baseline and Learned Hybrid (1/4 speed)
Video: Video Comparison 2: Same Policy, 30 ms and 100 ms Camera Latencies (1/4 speed)
같은 공, 세 조건: 위에서 본 로봇 쪽 평가 공 201번. 가로는 탁자 길이(오른쪽이 네트), 세로는 옆(x). 0.7 s 까지 6배 느리게. ▶ 누르면 재생 고전 기준선, 지연 30 ms 못 맞힘(가장 가까울 때 28.2 cm) 학습한 하이브리드, 지연 30 ms 반환 성공(착지 오차 3.7 cm) 학습한 하이브리드, 지연 100 ms 못 맞힘(가장 가까울 때 32.4 cm) 공 쓰인 계획의 예측 쓰인 계획의 칠 위치 라켓 면
Figure: Top-down view of the same ball under three conditions. Click to play at 6x slower speed

Classical baseline (30 ms latency): Missed, closest approach 28.2 cm. The baseline fitted position, velocity, and spin all at once using least squares from 21 observations at 0.2 s, reading the spin as (111, 279, −27) rad/s (true value: (55, 3, 15)). Based on that prediction, it set the hit position to x −0.83 m, while the actual ball was at x −0.54 m at that time. The baseline only replans from 80 ms after the predicted bounce until 80 ms before the hit time. Because the predicted bounce was at 0.440 s and the hit time at 0.545 s, that window was empty, leaving only the single plan from 0.2 s. The hybrid detected the bounce from observations and immediately replanned and corrected as soon as 4 observations were gathered.

Learned hybrid (100 ms latency): Missed, closest approach 32.4 cm. This is the same policy and the same ball. Because there were only 13 observations arrived at 0.2 s (compared to 21 for 30 ms latency), it read the spin as (67, −5, 87) rad/s. Due to a large sidespin component around the vertical axis (z), it set the hit position to x −0.19 m (actual ball at x −0.55 m at that time). Four observations after the bounce only arrived at 0.567 s, and by then the hit time of 0.545 s from that plan had already passed, rendering it unusable. At 100 ms latency, the return success rate of this policy is 58.2% based on 500 balls, whereas the baseline is 26.6% (Part 7).

11. Things Encountered During Development

12. Limitations and Unmeasured Factors

13. To the Next Part

Next, we will add low balls and a depth axis that expands the workspace to the robot model and run the same evaluation again (as previewed in Part 7). Using the same recording and rendering tools, we plan to show in the same seven steps how the definition of the "hitting time" changes when a depth axis is introduced.

A word from TT. Following the robot that we only saw as success rate tables with a single ball, there was a scene where it replanned in the final 39 ms and managed to hit the ball into the racket even when demanded 8 times its limit. Such a thrilling moment was hidden behind a single number!

Notes

External links share the same URL as Part 7 (confirmed to open on 2026-10-18 in Part 7).

Sign in to like

Comments

No comments yet.

Sign in to leave a comment