step.motion.at_heading ====================== .. py:module:: step.motion.at_heading .. autoapi-nested-parse:: Wait until the robot has turned a certain number of degrees. Designed to run inside a parallel() branch alongside a turn step: parallel( turn_left(90), seq([wait_until_degrees(45), servo_open()]), ) Multiple heading-triggered actions: parallel( turn_left(90), seq([wait_until_degrees(30), arm_lower()]), seq([wait_until_degrees(60), servo_open()]), seq([wait_until_degrees(85), servo_close()]), ) Polls odometry heading at 100 Hz. Three origin modes are available — see ``HeadingOrigin`` for details. Classes ------- .. autoapisummary:: step.motion.at_heading.HeadingOrigin step.motion.at_heading.WaitUntilDegrees Module Contents --------------- .. py:class:: HeadingOrigin(*args, **kwds) Bases: :py:obj:`enum.Enum` Reference point from which ``wait_until_degrees`` measures rotation. Choose the origin that matches where your degree target is counted from. All three modes use the same 100 Hz polling loop and stall detection — only the zero point differs. Members ------- STEP_START Degrees are counted from the heading at the moment ``wait_until_degrees`` *itself* starts executing. Use this when ``wait_until_degrees`` is the **first** step in its ``seq()`` branch, i.e. there are no prior steps that could consume time while the turn is already progressing. This is the default. Example — fires 45° after the step starts:: parallel([ turn_left(90), seq([wait_until_degrees(45), servo(claw, 90)]), ]) TURN_START Degrees are counted from the heading at the start of the concurrent turn step. ``TurnMotion.start()`` resets odometry to zero, so this origin is always zero regardless of when ``wait_until_degrees`` begins running. Use this when earlier steps in the same ``seq()`` branch may have taken time while the turn was already progressing, and you still want the threshold to be measured from the turn's own start, not from a later point in the branch. Example — fires when the turn has reached 45° from its own start, even though ``prepare_arm()`` ran first:: parallel([ turn_left(90), seq([prepare_arm(), wait_until_degrees(45, origin=HeadingOrigin.TURN_START), servo(claw, 90)]), ]) HEADING_REFERENCE Degrees are counted from the global heading reference set by ``mark_heading_reference()``. Uses the raw IMU heading (``get_absolute_heading()``), which is never reset by motion steps. Use this when you want to trigger an action at a board-absolute heading rather than at an angle relative to the current turn. Requires ``mark_heading_reference()`` to have been called earlier in the mission. Example — fires when the robot faces 45° from its mission-start heading, no matter how many turns have happened before:: mark_heading_reference() # ... other motion ... parallel([ turn_left(90), seq([wait_until_degrees(45, origin=HeadingOrigin.HEADING_REFERENCE), servo(claw, 90)]), ]) .. py:attribute:: STEP_START :value: 'step_start' .. py:attribute:: TURN_START :value: 'turn_start' .. py:attribute:: HEADING_REFERENCE :value: 'heading_reference' .. py:class:: WaitUntilDegrees(degrees: float, origin: HeadingOrigin = HeadingOrigin.STEP_START) Bases: :py:obj:`step.Step` Wait until the robot has turned at least the given number of degrees. Polls heading at 100 Hz and compares the angular distance from the chosen origin against the threshold. Designed to run inside a ``parallel()`` branch alongside a turn step, enabling actions to trigger at specific angles during a turn. The origin (zero point) is controlled by the ``origin`` parameter — see :class:`HeadingOrigin` for the three available modes. :param degrees: Heading-change threshold in degrees (always positive). :param origin: Which reference point to count degrees from. Defaults to ``HeadingOrigin.STEP_START``. Example:: from raccoon.step import parallel, seq from raccoon.step.motion import turn_left, wait_until_degrees, HeadingOrigin from raccoon.step.servo import servo # Default: fires 45° after this step starts executing parallel([ turn_left(90), seq([wait_until_degrees(45), servo(claw, 90)]), ]) # TURN_START: fires at 45° from the turn's own start parallel([ turn_left(90), seq([prepare_arm(), wait_until_degrees(45, origin=HeadingOrigin.TURN_START), servo(claw, 90)]), ]) # HEADING_REFERENCE: fires at 45° from the global reference parallel([ turn_left(90), seq([wait_until_degrees(45, origin=HeadingOrigin.HEADING_REFERENCE), servo(claw, 90)]), ])