# Robot Configuration Before EMOS can drive your robot, it needs to understand its physical constraints. You define this "Digital Twin" using the `RobotConfig` object, which aggregates the Motion Model, Geometry, and Control Limits. ```python import numpy as np from kompass_core.models import RobotConfig, RobotType, RobotGeometry # Example: Defining a simple box-shaped Ackermann robot robot_config = RobotConfig( model_type=RobotType.ACKERMANN, geometry_type=RobotGeometry.Type.BOX, geometry_params=np.array([1.0, 1.0, 1.0]) # x, y, z ) ``` ## Motion Models EMOS supports three distinct kinematic models. Choose the one that matches your robot's drivetrain. - {material-regular}`directions_car;1.2em;sd-text-primary` Ackermann — Car-Like Vehicles. Non-holonomic constraints (bicycle model). The robot has a limited steering angle and cannot rotate in place. - {material-regular}`swap_horiz;1.2em;sd-text-primary` Differential — Two-Wheeled Robots. Capable of forward/backward motion and zero-radius rotation (spinning in place). - {material-regular}`open_with;1.2em;sd-text-primary` Omni — Holonomic Robots. Mecanum-wheel platforms or quadrupeds. Capable of instantaneous motion in any direction (x, y) and rotation. ## Robot Geometry The geometry defines the collision volume of the robot, used by the local planner for obstacle avoidance. The `geometry_params` argument expects a **NumPy array** containing specific dimensions based on the selected type: ```{list-table} :widths: 15 25 60 :header-rows: 1 * - Type - Parameters (np.array) - Description * - **BOX** - `[length, width, height]` - Axis-aligned box. * - **CYLINDER** - `[radius, length_z]` - Vertical cylinder. * - **SPHERE** - `[radius]` - Perfect sphere. * - **ELLIPSOID** - `[axis_x, axis_y, axis_z]` - Axis-aligned ellipsoid. * - **CAPSULE** - `[radius, length_z]` - Cylinder with hemispherical ends. * - **CONE** - `[radius, length_z]` - Vertical cone. ``` ```python import numpy as np from kompass_core.models import RobotConfig, RobotType, RobotGeometry # A cylinder robot (Radius=0.5m, Height=1.0m) cylinder_robot_config = RobotConfig( model_type=RobotType.DIFFERENTIAL_DRIVE, geometry_type=RobotGeometry.Type.CYLINDER, geometry_params=np.array([0.5, 1.0]) ) ``` ## Control Limits Safety is paramount. You must explicitly define the kinematic limits for linear and angular velocities. For both linear and angular control limits we need to set: - Maximum velocity (m/s) or (rad/s) - Maximum acceleration (m/s^2) or (rad/s^2) - Maximum deceleration (m/s^2) or (rad/s^2) Additionally, for angular control limits we can set the maximum steering angle (rad). EMOS separates **Acceleration** limits from **Deceleration** limits. This allows you to configure a "gentle" acceleration for smooth motion, but a "hard" deceleration for emergency braking. ```python from kompass_core.models import LinearCtrlLimits, AngularCtrlLimits, RobotConfig, RobotType, RobotGeometry import numpy as np # 1. Linear Limits (Forward/Backward) ctrl_vx = LinearCtrlLimits(max_vel=1.0, max_acc=1.5, max_decel=2.5) # 2. Linear Limits (Lateral — for Omni robots) ctrl_vy = LinearCtrlLimits(max_vel=0.5, max_acc=0.7, max_decel=3.5) # 3. Angular Limits (Rotation) # max_steer is only used for Ackermann robots ctrl_omega = AngularCtrlLimits( max_vel=1.0, max_acc=2.0, max_decel=2.0, max_steer=np.pi / 3 ) # Setup your robot configuration my_robot = RobotConfig( model_type=RobotType.DIFFERENTIAL_DRIVE, geometry_type=RobotGeometry.Type.CYLINDER, geometry_params=np.array([0.1, 0.3]), ctrl_vx_limits=ctrl_vx, ctrl_omega_limits=ctrl_omega, ) ``` :::{tip} Deceleration limit is separated from the acceleration limit to allow the robot to decelerate faster thus ensuring safety. ::: :::{tip} For Ackermann robots, `ctrl_omega_limits.max_steer` defines the maximum physical steering angle of the wheels in radians. ::: ## Coordinate Frames EMOS needs to know the names of your TF frames to perform lookups. You configure this using the `RobotFrames` object. The components will automatically subscribe to `/tf` and `/tf_static` to track these frames. ```python from kompass.config import RobotFrames frames = RobotFrames( world='map', # The fixed global reference frame odom='odom', # The drift-prone odometry frame robot_base='base_link', # The center of the robot scan='scan', # Lidar frame rgb='camera/rgb', # RGB Camera frame depth='camera/depth' # Depth Camera frame ) ``` ```{list-table} :widths: 20 70 :header-rows: 1 * - Frame - Description * - **world** - The global reference for path planning (usually `map`). * - **odom** - The continuous reference for local control loops. * - **robot_base** - The physical center of the robot. All geometry is relative to this. * - **scan** - Laserscan sensor frame. * - **rgb** - RGB camera sensor frame. * - **depth** - Depth camera sensor frame. ``` ```{note} It is important to configure your coordinate frames names correctly and pass them to Kompass. Components in Kompass will subscribe automatically to the relevant `/tf` and `/tf_static` topics in ROS2 to get the necessary transformations. ```