step.motion.path.ir

Intermediate representation for the motion path pipeline.

Compiler passes operate on list[PathNode]:

  • Segment — one motion primitive (linear / turn / arc / follow_line / spline).

  • SideAction — a non-motion step pinned to a transition point.

  • None — placeholder for a deferred step resolved at runtime.

These types are intentionally pure data — they hold no robot reference and no runtime state. Anything stateful (current motion, world tracker) lives in the executor / middleware layer.

Attributes

SENTINEL_DISTANCE_M

PathNode

Classes

Segment

One motion primitive extracted from a Step into the pipeline IR.

SideAction

A non-motion step pinned to a transition point in the path.

Module Contents

step.motion.path.ir.SENTINEL_DISTANCE_M: float = 100.0
class step.motion.path.ir.Segment

One motion primitive extracted from a Step into the pipeline IR.

Field semantics depend on kind:

  • "linear"axis, sign, distance_m, speed_scale,

    optional heading_deg and condition.

  • "turn"sign, angle_rad, speed_scale,

    optional condition.

  • "arc"radius_m, arc_angle_rad, speed_scale,

    lateral.

  • "crab_arc"radius_m, arc_angle_rad, speed_scale plus

    crab_from / crab_to (body-frame unit velocity directions at entry / exit). A constant-heading 90° corner blend for a holonomic base: the body velocity vector rotates from crab_from to crab_to over a quarter circle WITHOUT rotating the heading. Driven by a Python adapter (no warm-start unless profiled). Used by cut_corners for forward↔strafe corners.

  • "follow_line" — same shape as "linear" plus opaque_step

    (the original LineFollow step). Adapter delegates lifecycle to the step’s on_start/on_update.

  • "spline"opaque_step (the SplinePath step). No warm-start.

  • "diagonal"opaque_step (the DriveAngle step) plus the known

    body-frame displacement forward_m / left_m and distance_m. Same opaque shape as a step; the travel direction is decoupled from the held heading. No warm-start.

kind: str
axis: raccoon.motion.LinearAxis | None = None
sign: float = 1.0
distance_m: float | None = None
speed_scale: float = 1.0
heading_deg: float | None = None
target_heading_rad: float | None = None
angle_rad: float | None = None
radius_m: float | None = None
arc_angle_rad: float | None = None
lateral: bool = False
crab_from: tuple[float, float] | None = None
crab_to: tuple[float, float] | None = None
forward_m: float | None = None
left_m: float | None = None
condition: step.condition.StopCondition | None = None
has_known_endpoint: bool = True
entry_speed_mps: float | None = None
exit_speed_mps: float | None = None
opaque_step: step.Step | None = None
class step.motion.path.ir.SideAction

A non-motion step pinned to a transition point in the path.

is_background=True → fired as an asyncio task and not awaited inline. is_background=False → awaited inline before the next segment starts.

ephemeral=True marks a background task SCOPED to a parallel() spine — a non-spine branch of parallel(motion_spine, branch). It runs concurrently with the spine but is JOINED at the next transition point (when the spine ends), preserving parallel()’s await-all semantics instead of leaking past its scope (which would, e.g., hold a servo while a later step tries to use it). A plain background() step is non-ephemeral — it persists until the path ends. Only meaningful together with is_background.

step: step.Step
is_background: bool
ephemeral: bool = False
step.motion.path.ir.PathNode