kendama op• Data kinds: table → table
• Call: import fullseye as fs; fs.ledger.kendama_simulate(kp: 'dict', handle, *, p0, v0, t_end: 'float', dt: 'float' = 0.001, perceive=None, catch_plan=None, g: 'float' = None, v_max: 'float' = 2.0, a_max: 'float' = 20.0, v_rel_max: 'float' = 1.0, plan_from: 'float' = 0.0, stop_on_miss: 'bool' = True, contact=None, contact_tol: 'float' = 0.0005) -> 'dict' (to call the implementation directly, import kendama; kendama.kendama_simulate(kp: 'dict', handle, *, p0, v0, t_end: 'float', dt: 'float' = 0.001, perceive=None, catch_plan=None, g: 'float' = None, v_max: 'float' = 2.0, a_max: 'float' = 20.0, v_rel_max: 'float' = 1.0, plan_from: 'float' = 0.0, stop_on_miss: 'bool' = True, contact=None, contact_tol: 'float' = 0.0005) -> 'dict'; from the registry, opsdrive.get("kendama_simulate"))
2-phase kendama simulation: while the string is taut, the ball is tied to the pivot (the string hole of the cross-piece = hand + kp["tie_offset"]) (projection method, the same as ballistics.tether_simulate: with a fixed pivot in vacuum the trajectory is identical; string length = kp["pendulum_length"]); once slack, free fall (gravity + drag, kp["bp"]; rho = 0 for vacuum). Every step, kendama_catch_check (big cup = hand + kp["cup_offset"], axis kp["cup_axis"]) judges the catch, and the simulation ends once caught.
handle = the hand (sarado centre) as a fixed (3,) point or a function t → (3,) (open-loop swing-up). If catch_plan is given, then after the string goes slack (and t ≥ plan_from: the open loop takes priority until the swing-up is over), at every step the (p̂, v̂) perceived with perceive is passed to catch_plan(t, p̂, v̂, cup_state) → {"target": 大皿の縁の中心の目標 (3,), …}, and the hand is carried by bang-bang with speed ≤ v_max and acceleration ≤ a_max to "target − cup_offset" (when the hand moves the pivot moves too, so once the ball falls and |p − pivot| = L the string is taut again).
Perception perceive:
• None → ground truth (p, v).
• perceive(t, p, v) → (p̂, v̂) (e.g. noisy_perceiver) is called only at steps where the plan is active.
• A perceiver with the attribute observe_all = True (kendamaworld.camera_perceiver) is called every step as perceive(t, p, v, scene) (scene = {"t", "hand", "tie", "cup", "cup_axis", "taut"} = quantities known from the hand's proprioception + taut for rendering the world (rendering convention for the ball's pose: while taut the string hole faces the knot; when slack it keeps the last pose). p is likewise passed only for rendering the world). If it returns None the plan stays as is (it keeps carrying toward the last target, and stops the hand if there is no target).
The ball is moved only by gravity (+ drag, when rho > 0) and the string tension (unilateral constraint ≥ 0). The ken does not push the ball: passing contact(hand, p) → 隙間 [m] (e.g. kendamaworld.kendama_clearance) ends the run as "hit_ken" at the step where, before a catch, the gap < −contact_tol (the ball touched the ken tip, a cup rim or the sarado = failure). The catch is judged with kp["catch_window"] (the height at which the ball touches the rim).
Endings end_reason: "caught" (caught), "hit_ken" (touched the kendama), "missed" (after going slack, came 2 r_b or more below the big cup's plane while falling downward; with stop_on_miss=False it does not stop: used for the snap gate), "timeout" (t_end). Return value {"t", "p", "v", "hand", "anchor" (= 支点 = 糸穴), "cup", "cup_v", "taut", "tension", "energy", "snap_times", "snap_loss", "slack_t", "caught", "catch_t", "end_reason", "lateral", "plan_log", "n_estimates", "stage", "min_gap"} (arrays up to the step where it ended. stage = control stage at each step ("lift" swing-up / "wait" slack but before planning / the plan's "stage" (hold / carry / absorb) or "plan"). slack_t = the time the string first goes slack after having been taut, 0.0 if slack from the start, None if it never goes slack. energy = ½mv² + mgz. n_estimates = number of perceptions passed to the plan). An initial state with |p₀ − pivot(0)| > L, t_end < 0, dt ≤ 0, or a limit ≤ 0 raises ValueError.
Empty input (kp is an empty dict) raises ValueError.
• 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.
• poc_kendama — py -3.11 examples/poc_kendama.py
table as input)course_layout · course_occupancy · course_contains · world_build · world_camera · world_move · lidar_scan · rss_longitudinal_same
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.