libstp.step.motion.characterize_drive ===================================== .. py:module:: libstp.step.motion.characterize_drive .. autoapi-nested-parse:: Characterize drive limits by commanding raw velocities and measuring response. Bypasses the profile/PID system to discover the robot's true physical limits: max velocity, acceleration, and deceleration for each axis. Runs multiple trials per axis for statistical robustness. Results are persisted to raccoon.project.yml under robot.motion_pid and applied in-memory. Classes ------- .. autoapisummary:: libstp.step.motion.characterize_drive.AxisResult libstp.step.motion.characterize_drive.CharacterizeDrive Functions --------- .. autoapisummary:: libstp.step.motion.characterize_drive.characterize_drive Module Contents --------------- .. py:class:: AxisResult Measured limits for a single axis. .. py:attribute:: max_velocity :type: float :value: 0.0 .. py:attribute:: acceleration :type: float :value: 0.0 .. py:attribute:: deceleration :type: float :value: 0.0 .. py:class:: CharacterizeDrive(axes: list[str], trials: int, command_speed: float, accel_timeout: float, decel_timeout: float, persist: bool) Bases: :py:obj:`libstp.step.Step` Characterize drive limits by commanding raw velocities. For each configured axis, runs multiple acceleration + deceleration trials. Acceleration phase records odometry at ~100 Hz until a velocity plateau is detected; deceleration phase ramps up then commands zero and records coast-down. Max velocity, acceleration, and deceleration are extracted via 10%/90% rise/fall-time analysis, and the median across trials is taken as the final result. Results are applied in-memory and optionally persisted to ``raccoon.project.yml``. .. py:attribute:: axes .. py:attribute:: trials .. py:attribute:: command_speed .. py:attribute:: accel_timeout .. py:attribute:: decel_timeout .. py:attribute:: persist .. py:attribute:: results :type: dict[str, AxisResult] .. py:function:: characterize_drive(axes: list[str] | None = None, trials: int = 3, command_speed: float = 1.0, accel_timeout: float = 3.0, decel_timeout: float = 3.0, persist: bool = True) -> CharacterizeDrive Characterize the robot's physical drive limits by commanding raw velocities. Bypasses the profile and PID systems entirely to discover the true hardware capabilities of each drive axis. For each axis, the step runs multiple independent trials consisting of two phases: 1. **Acceleration phase** -- commands the specified velocity and records odometry at ~100 Hz until a velocity plateau is detected or the timeout expires. From this data, max velocity and acceleration are extracted using 10%--90% rise-time analysis. 2. **Deceleration phase** -- ramps the robot back up to speed, then commands zero velocity and records the coast-down. Deceleration is computed from 90%--10% fall-time analysis. The median of all valid trials for each metric is taken as the final result. Measured values are applied to the in-memory ``motion_pid_config`` immediately and, if ``persist`` is enabled, written to the ``robot.motion_pid`` section of ``raccoon.project.yml`` so they survive restarts. This step is intended for initial robot setup and should be run on a flat surface with enough room for the robot to accelerate to full speed. It is typically the first phase of the full ``auto_tune()`` pipeline. :param axes: Which axes to characterize. Options are ``"forward"``, ``"lateral"``, and ``"angular"``. Default ``["forward"]``. :param trials: Number of trials per axis. The median is used for robustness against outliers. Default 3. :param command_speed: Raw velocity command magnitude sent to the motors. For forward/lateral this is in m/s; for angular it is in rad/s. Should be at or near the maximum the robot can sustain. Default 1.0. :param accel_timeout: Maximum time in seconds to wait for the acceleration phase before giving up. Default 3.0. :param decel_timeout: Maximum time in seconds to record the deceleration (coast-down) phase. Default 3.0. :param persist: If ``True``, write the measured limits to ``raccoon.project.yml`` under ``robot.motion_pid``. Default ``True``. :returns: A ``CharacterizeDrive`` step that measures and persists drive limits. Example:: from libstp.step.motion import characterize_drive # Characterize forward axis with default settings step = characterize_drive() # Characterize forward and angular axes with 5 trials each step = characterize_drive( axes=["forward", "angular"], trials=5, ) # Characterize without saving to disk (dry run) step = characterize_drive( axes=["forward", "lateral", "angular"], persist=False, )