step.motion.path.motion_factory =============================== .. py:module:: step.motion.path.motion_factory .. autoapi-nested-parse:: Motion factory — constructs a controller for one ``Segment``. The executor calls ``create_motion(robot, seg, is_last)`` and gets back an object with the uniform motion-controller interface: motion.start() motion.start_warm(offset, velocity) motion.update(dt) motion.is_finished() motion.has_reached_distance() / .has_reached_angle() motion.get_filtered_velocity() motion.set_suppress_hard_stop(bool) For ``linear`` / ``turn`` / ``arc`` kinds, this is the corresponding C++ ``LinearMotion`` / ``TurnMotion`` / ``ArcMotion`` class directly. For ``follow_line`` / ``spline`` / ``diagonal`` kinds, the Python step is wrapped in an adapter that translates the ``MotionStep`` lifecycle (``on_start``, ``on_update(robot, dt)``) to the uniform interface. Attributes ---------- .. autoapisummary:: step.motion.path.motion_factory.OVERSHOOT_M step.motion.path.motion_factory.OVERSHOOT_RAD Classes ------- .. autoapisummary:: step.motion.path.motion_factory.LineFollowAdapter step.motion.path.motion_factory.TurnHeadingAdapter step.motion.path.motion_factory.DriveAngleAdapter step.motion.path.motion_factory.CrabArcAdapter step.motion.path.motion_factory.SplineAdapter Functions --------- .. autoapisummary:: step.motion.path.motion_factory.create_motion Module Contents --------------- .. py:data:: OVERSHOOT_M :value: 1.0 .. py:data:: OVERSHOOT_RAD :value: 3.0 .. py:class:: LineFollowAdapter(step, robot: raccoon.robot.api.GenericRobot) Adapts a LineFollow/SingleSensorLineFollow step to the C++ motion API. Delegates to the step's ``on_start``/``on_update`` lifecycle and forwards completion queries to the internal ``LinearMotion``. Supports warm-start for seamless velocity hand-off from a preceding forward linear segment. .. py:method:: start() -> None .. py:method:: start_warm(offset: float, velocity: float) -> None .. py:method:: update(dt: float) -> None .. py:method:: is_finished() -> bool .. py:method:: has_reached_distance() -> bool .. py:method:: get_filtered_velocity() -> float .. py:method:: set_suppress_hard_stop(val: bool) -> None .. py:class:: TurnHeadingAdapter(step, robot: raccoon.robot.api.GenericRobot) Adapts a :class:`TurnToHeading` step to the C++ motion API. Delegates to the step's ``on_start``/``on_update`` lifecycle. The step resolves its absolute target heading (via the HeadingReferenceService) and builds its own ``TurnMotion`` at ``on_start``, so this adapter only tracks completion. Turns never warm-start, so ``start_warm`` is a cold start. .. py:method:: start() -> None .. py:method:: start_warm(offset: float, velocity: float) -> None .. py:method:: update(dt: float) -> None .. py:method:: is_finished() -> bool .. py:method:: has_reached_angle() -> bool .. py:method:: get_filtered_velocity() -> float .. py:method:: set_suppress_hard_stop(val: bool) -> None .. py:class:: DriveAngleAdapter(step, robot: raccoon.robot.api.GenericRobot) Adapts a DriveAngle (true diagonal) step to the C++ motion API. Delegates to the step's ``on_start``/``on_update`` lifecycle. The underlying ``DiagonalMotion`` has no guaranteed warm-start, so every transition into a diagonal uses a cold start. .. py:method:: start() -> None .. py:method:: start_warm(offset: float, velocity: float) -> None .. py:method:: update(dt: float) -> None .. py:method:: is_finished() -> bool .. py:method:: has_reached_distance() -> bool .. py:method:: get_filtered_velocity() -> float .. py:method:: set_suppress_hard_stop(val: bool) -> None .. py:class:: CrabArcAdapter(seg: step.motion.path.ir.Segment, robot: raccoon.robot.api.GenericRobot) Drives a constant-heading 90° corner blend (``crab_arc``). A holonomic base can round a ``forward↔strafe`` corner without rotating: the body-frame velocity vector is swept from the entry leg's travel direction (``crab_from``) to the exit leg's (``crab_to``) along a quarter circle of radius ``R = seg.radius_m``, while a proportional controller holds the heading captured at start. Progress is the path length travelled (read from odometry); the arc angle is ``α = travelled / R`` and the blend completes at ``α = arc_angle_rad`` (π/2). No C++ motion backs this — like ``DriveAngle`` it commands chassis velocity directly. It never relies on a trapezoidal profile, so a cold ``start`` and a profiled ``start_warm`` both simply begin commanding the blend at cruise (or the carried) speed; ``inflate`` is irrelevant. .. py:method:: start() -> None .. py:method:: start_warm(offset: float, velocity: float) -> None .. py:method:: update(dt: float) -> None .. py:method:: is_finished() -> bool .. py:method:: has_reached_distance() -> bool .. py:method:: get_filtered_velocity() -> float .. py:method:: set_suppress_hard_stop(val: bool) -> None .. py:class:: SplineAdapter(step, robot: raccoon.robot.api.GenericRobot) Adapts a SplinePath step to the C++ motion API. SplineMotion does not support warm-start; cross-type transitions to/from spline segments always use a cold start. .. py:method:: start() -> None .. py:method:: start_warm(offset: float, velocity: float) -> None .. py:method:: update(dt: float) -> None .. py:method:: is_finished() -> bool .. py:method:: has_reached_distance() -> bool .. py:method:: get_filtered_velocity() -> float .. py:method:: set_suppress_hard_stop(val: bool) -> None .. py:function:: create_motion(robot: raccoon.robot.api.GenericRobot, seg: step.motion.path.ir.Segment, is_last: bool, current_world_heading_rad: float | None = None, inflate: bool | None = None) Construct a controller for the given segment kind. ``current_world_heading_rad`` is the absolute world heading at the moment the executor is about to start this segment, read from ``robot.localization.get_pose().heading``. Used by ``linear`` segments that have no user-specified ``heading_deg`` and by absolute ``turn`` segments bridged from the Phase-5 plan IR. Ignored by ``arc`` and by the opaque ``follow_line`` / ``spline`` adapters (those steps fetch the heading themselves). ``inflate`` controls profile-overshoot inflation: ``True`` cruises through the endpoint (only correct when the next segment warm-starts from this one), ``False`` decelerates to the real target (cross-type / blocked / last). Defaults (``None``) to ``not is_last`` for back-compat. The executor passes the look-ahead result so short moves before a direction change stop on target instead of overshooting.