testing.sim =========== .. py:module:: testing.sim .. autoapi-nested-parse:: High-level Python API for the libstp simulator. This module wraps :mod:`raccoon.sim` (the pybind11 bindings) with ergonomic helpers so a team's pytest can do:: from raccoon.testing.sim import use_scene with use_scene("empty_table.ftmap", robot=my_robot_config, start=(50, 50, 0)): await drive_forward(cm=30).run_step(robot) assert pose().x == pytest.approx(80.0, abs=2.0) The context manager configures the process-wide ``MockPlatform`` singleton to talk to a fresh ``SimWorld`` for the duration of the block, then detaches on exit so subsequent code paths see the stock mock HAL. Only available when the wheel is built with ``DRIVER_BUNDLE=mock`` — the ``raccoon.sim.mock`` submodule must be present. Importing this module on a wombat-bundle wheel raises ``RuntimeError``. This module lives under :mod:`raccoon.testing` because it is exclusively a test-harness concern; the actual C++ sim bindings still live at ``raccoon.sim``. Historically this API was at ``raccoon.step.sim`` — that path remains as a deprecation shim and will be removed in a future release. Classes ------- .. autoapisummary:: testing.sim.LineSensorMount testing.sim.DistanceSensorMount testing.sim.SimRobotConfig Functions --------- .. autoapisummary:: testing.sim.configure testing.sim.detach testing.sim.pose testing.sim.yaw_rate testing.sim.tick testing.sim.use_scene Module Contents --------------- .. py:class:: LineSensorMount .. py:attribute:: analog_port :type: int .. py:attribute:: forward_cm :type: float .. py:attribute:: strafe_cm :type: float .. py:attribute:: name :type: str :value: '' .. py:class:: DistanceSensorMount .. py:attribute:: analog_port :type: int .. py:attribute:: forward_cm :type: float .. py:attribute:: strafe_cm :type: float .. py:attribute:: mount_angle_rad :type: float :value: 0.0 .. py:attribute:: max_range_cm :type: float :value: 100.0 .. py:attribute:: name :type: str :value: '' .. py:class:: SimRobotConfig Sim-side counterpart to the team's GenericRobot geometry/kinematics. Defaults match a typical Botball wombat. Override fields that differ on your robot — they must agree with whatever the real ``Drive`` / ``DifferentialKinematics`` were constructed with so the sim physics matches what the motion controllers expect. .. py:attribute:: width_cm :type: float :value: 18.0 .. py:attribute:: length_cm :type: float :value: 18.0 .. py:attribute:: rotation_center_forward_cm :type: float :value: 0.0 .. py:attribute:: rotation_center_strafe_cm :type: float :value: 0.0 .. py:attribute:: wheel_radius_m :type: float :value: 0.03 .. py:attribute:: track_width_m :type: float :value: 0.15 .. py:attribute:: wheelbase_m :type: float :value: 0.15 .. py:attribute:: left_motor_port :type: int :value: 0 .. py:attribute:: right_motor_port :type: int :value: 1 .. py:attribute:: left_motor_inverted :type: bool :value: False .. py:attribute:: right_motor_inverted :type: bool :value: False .. py:attribute:: max_wheel_velocity_rad_s :type: float :value: 30.0 .. py:attribute:: motor_time_constant_sec :type: float :value: 0.05 .. py:attribute:: ticks_to_rad :type: float :value: 0.0043633231299858195 .. py:attribute:: viscous_drag_coeff :type: float :value: 0.0 .. py:attribute:: coulomb_friction_rad_s2 :type: float :value: 0.0 .. py:attribute:: bemf_noise_stddev :type: float :value: 0.0 .. py:attribute:: line_sensors :type: List[LineSensorMount] :value: [] .. py:attribute:: distance_sensors :type: List[DistanceSensorMount] :value: [] .. py:function:: configure(scene: Union[str, pathlib.Path], *, robot: Optional[SimRobotConfig] = None, start: PoseLike = (0.0, 0.0, 0.0), auto_tick: bool = True, auto_tick_max_step_sec: float = 0.05) -> None Attach a fresh sim to the MockPlatform singleton. After this returns, motor commands written through any HAL ``Motor`` drive the simulated chassis, and ``OdometryBridge::readOdometry`` reports its pose. Auto-tick is enabled by default so a real motion loop reading odometry on its own schedule will see the sim advance with wall time. .. py:function:: detach() -> None Disconnect any attached sim. The mock HAL goes back to zero odometry. .. py:function:: pose() -> raccoon.sim.Pose2D Return the sim's current ground-truth pose (cm, cm, rad). .. py:function:: yaw_rate() -> float Return the sim's current yaw rate in rad/s. .. py:function:: tick(dt_seconds: float) -> None Manually advance the sim. Use this for fully deterministic tests. .. py:function:: use_scene(scene: Union[str, pathlib.Path], *, robot: Optional[SimRobotConfig] = None, start: PoseLike = (0.0, 0.0, 0.0), auto_tick: bool = True, auto_tick_max_step_sec: float = 0.05) -> Iterator[None] Context manager: attach the sim for the duration of a ``with`` block. Example:: with use_scene("empty_table.ftmap", start=(20, 50, 0)): await drive_forward(cm=30).run_step(my_robot) x, y, _ = pose() assert x == pytest.approx(50, abs=2)