Surface, samples and capture formats¶
The ROS 2 stack (ros/), the simulator, the offline samples planner and the
wrist-camera tools read or write the files below. Every file has a schema value; readers refuse
an unknown schema, and a preflight failure refuses a path rather than silently
clamping it.
Frames¶
A surface is stored in the configured robot-root frame. Samples are stored in the configured arm-base frame. The profile, URDF and tool datasheet supply the conversion between them, the tool-tip transform, the tool axis, the camera extrinsics, the workspace and the joint limits. A consumer never substitutes values copied from another rig.
rotation is always the commanded rotation of the final arm link. The tool-tip
point and the tool axis come from the selected tool configuration.
Samples files: orbit.csv and path.csv¶
A samples file starts with key,value header lines, then a columns,...
declaration, then one row per control tick:
schema,tatbot.draw-samples/1
kind,orbit | path
frame,arm/base_link
period_s,0.0025
constants_sha,<config/motion_constants.json short SHA>
sample_count,N
capture_count,K
start_tolerance_m,<profile-derived tolerance>
columns,t_s,px,py,pz,vx,vy,vz,r00,r01,r02,r10,r11,r12,r20,r21,r22,pen,capture,dip
...
pis the tool-tip position andvthe feedforward velocity.ris the row-major target rotation of the final link.penis zero for retracted travel and one for a drawing segment.captureis zero except at an orbit sample that requests a numbered capture.dipis zero except on the row where dipkbottoms out in a cap.The first sample must agree with the arm’s current pose within the declared start tolerance.
Dips are path rows like any other. Each is pen-up travel from the standoff to
the cap’s transit point, a descent to the hover above the rim, the plunge, a
dwell, the retract, and the travel back. Pen-down rows are checked against
planner.max_joint_velocity_rad_s. Pen-up rows are checked against
planner.max_joint_velocity_pen_up_rad_s, with the looser model-error cap
max_model_error_pen_up_m.
The parser ignores unknown header keys. It refuses:
a malformed schema, or a missing or mismatched
constants_sha;non-finite values or discontinuities;
profile-limit violations or excessive model error;
an invalid starting pose.
cpp/teleop/build/path_plan_check <samples.csv> <period> <joint values...>
runs that parser and planner offline. The ROS CLIK parity test
(ros/tatbot_motion/test/test_clik_parity.py) compares the ROS planner
against it.
Wrist captures: capture-<k>.npz¶
tatbot vision capture (scripts/vision_capture.py) writes one
capture-<k>.npz per capture and then capture-<k>.done. A reader waits for
the .done marker before opening the archive.
A capture holds, for each configured camera role:
the depth image, its validity counts and its depth units;
the depth intrinsics;
one color frame, when the camera provides one.
It also holds the observed joints, the carriage position, the capture index and the wall time. Readers use the stored depth units and intrinsics; they never infer them from a camera model name.
surface.npz¶
surface.npz uses schema tatbot.surface/1. It stores:
a plane or cylinder chart and the chart frame;
the canvas dimensions;
a displacement grid with per-cell sample counts and residuals;
the contact anchor.
Grid rows index v and columns index u. The chart rotation columns are
(e_u, e_v, n).
A mapped chart puts (0, 0) at the touched reference’s projection, and the
height anchoring places the surface through that reference. Reparameterizing
a cylinder keeps its fitted radius and axis. A plane’s u direction follows
the projected robot-root X hint, or Y when that is degenerate. A cylinder’s
u follows its fitted axis. These coordinate conventions do not establish
physical registration.
An optional surface.json sidecar records provenance and fit statistics
without changing the numeric contract. The NumPy reader
(scripts/lib/surface_model.py) and the simulator’s loader
(python/tatbot_sim/src/tatbot_sim/surface_io.py) read the same
representation, and parity tests pin their frame points and normals.