kendama_combo_simulate — DRIVE kendama op

• Data kinds: table → table

• Call: import fullseye as fs; fs.ledger.kendama_combo_simulate(kp: 'dict', sequence=('ozara', 'chuzara'), *, n_catch: 'int' = 10, hand0=(0.0, 0.0, 1.0), hand_v0=(0.0, 0.0, 0.0), z_home: 'float' = None, apex_above_cup: 'float' = 0.2, k_match: 'float' = 0.8, v_max: 'float' = 2.5, a_max: 'float' = 20.0, a_toss: 'float' = 20.0, omega_max: 'float' = 30.0, rot_clear: 'float' = 0.15, v_rel_max: 'float' = 1.0, dt: 'float' = 0.001, perceive=None, contact=None, contact_tol: 'float' = 0.0005, controller: 'str' = 'pos_vel', t_max: 'float' = None, g: 'float' = None) -> 'dict' (to call the implementation directly, import kendama; kendama.kendama_combo_simulate(kp: 'dict', sequence=('ozara', 'chuzara'), *, n_catch: 'int' = 10, hand0=(0.0, 0.0, 1.0), hand_v0=(0.0, 0.0, 0.0), z_home: 'float' = None, apex_above_cup: 'float' = 0.2, k_match: 'float' = 0.8, v_max: 'float' = 2.5, a_max: 'float' = 20.0, a_toss: 'float' = 20.0, omega_max: 'float' = 30.0, rot_clear: 'float' = 0.15, v_rel_max: 'float' = 1.0, dt: 'float' = 0.001, perceive=None, contact=None, contact_tol: 'float' = 0.0005, controller: 'str' = 'pos_vel', t_max: 'float' = None, g: 'float' = None) -> 'dict'; from the registry, opsdrive.get("kendama_combo_simulate"))

Usage

Combo: starting with the ball resting on the cup sequence[0], repeats "release → switch grip while it flies → carry the next cup directly under the landing point and catch it with matched speed" n_catch times or until the first failure (moshikame = ("ozara", "chuzara"), 3 cups = ("ozara", "kozara", "chuzara")). Hand hand0 = center of the cross-piece (switching grip only turns the wrist; no regrip: assumption). The first cup is caught via the swing-up of kendama_simulate, and that hand's position and velocity are passed as hand0 / hand_v0.

Stages (each cycle): absorb (stop the cup that caught, within limits: the ball moves with the cup) → toss (accelerate the cup upward at a_toss, and when the speed reaches v_toss stop it at a_max (> g): at the step where stopping begins the cup's normal force turns negative and the ball leaves. The ball's velocity at the moment of release = the cup's velocity → apex = release height + v²/2g) → flight (from the perceived parabola obtain the landing time τ and point, and carry the hand to "position = directly below the landing point (height z_home), velocity = k_match × the ball's landing velocity" with _move_pos_vel. The change of grip starts only after the ball is at least rot_clear (0.15 m: 0.12 m from the sarado centre to the base cup's rim + the ball radius) away from the sarado centre (by perception; if the last moment that still allows reaching the landing arrives without that separation, it starts then = the 180° big cup → small cup turn of the 3-cup trick may fall into this case), and rotates to the next pose with a triangular angular-velocity profile capped at omega_max. No catch before the rotation finishes) → after a catch, back to absorb.

Physics: on the cup, the ball moves with the cup (while the cup's normal force ∝ (a_cup + g ẑ)·axis ≥ 0; it leaves when this turns negative); in flight, only gravity (+ drag) and the string tension (unilateral constraint, the same projection method as kendama_simulate). The ken does not push the ball (when contact(hand, p, R) → 隙間 falls below −contact_tol → "hit_ken": R_ken of kendamaworld.kendama_clearance). The catch test is kendama_catch_check (landing window kp["catch_window"], relative speed ≤ v_rel_max: assumed 1 m/s). If it enters the window but is too fast → "too_fast". At the moment of the catch, the ball is placed at the position resting on the rim and its velocity is set to the cup's velocity (inelastic, no bounce: an assumption. Re-placement distance ≤ the 3 mm of the window).

Release height (closed form): put the apex apex_above_cup above the height z_r at which the ball's centre rests at the next landing. Accelerating at a_toss from the current ball height z₀, the release height is z₀ + v²/(2 a_toss), so v_toss² = 2g (z_r + A − z₀) / (1 + g / a_toss) (drag not included). controller="position": a control case that carries the hand during flight with the legacy _move_bounded (stops with only the position as the target). Perception perceive: None = ground truth. With kendamaworld.camera_perceiver (flight_from="cup"), every step perceive(t, p, v, scene) is called (scene = quantities known from the hand's proprioception + the pose R_ken for rendering), receiving (p̂, v̂) or None. Since the catch is known from the feel of the hand (assumption: touch), perceive.reset() is called at the catch step if it exists (discarding the previous flight's parabola).

Assumptions (no published values): wrist angular velocity ≤ 30 rad/s, hand speed ≤ 2.5 m/s, acceleration ≤ 20 m/s², k_match = 0.8 (the degree to which a person "matches the speed with the knees"). Return value {"count" (最初の失敗までに受けた回数), "catches" [{"t", "trick", "rel_speed", "lateral", "apex", "z_catch" (受けた瞬間の玉の中心の高さ), "z_release", "v_release", "apex_closed", "rose_then_fell", "energy_drift"}], "end_reason" ("done" | "too_fast" | "hit_ken" | "missed" | "timeout"), "t", "p", "v", "hand", "hand_v", "hand_a", "R", "on_cup", "taut", "stage", "min_gap", "grade" (もしかめの級相当), "max_omega"}.

Empty input (kp is an empty dict) raises ValueError.

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

• The canonical algorithm (author, year) and its uses are named in the family usage guide above.

Runnable examples (verified samples that actually call this op)

• poc_kendama — py -3.11 examples/poc_kendama.py

Ops the type connects to (they accept table as input)

course_layout · course_occupancy · course_contains · world_build · world_camera · world_move · lidar_scan · rss_longitudinal_same

Same category (kendama)

kendama_params · elliptic_k_agm · pendulum_period_exact · pendulum_launch_speed · pendulum_rod_simulate · tether_tension_fixed · tether_slack_angle · swing_up_plan


*Provenance: kendama.py — DRIVE operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.