Architecture ============ The stack is 79 ROS 2 packages across 20 repositories. They form layers: each one depends on those below it and knows nothing about those above. .. code-block:: text application sorting_app <- what you write | framework core_pick_and_place <- move_arm, decision taking, CLI | core_supervisor <- lifecycle orchestration | services core_motion_planning <- plan, IK/FK, collision checking | core_motion_control <- execute on a real or simulated arm | core_modeling <- workcell description, joint states | contract core_interfaces <- 110 msg / srv / action definitions | foundation core_types core_utils core_logger core_tf | simulation core_plugins mesh_models <- Gazebo plugins, arm and EE models The layer that matters most when you start is **contract**. Packages do not link against each other's internals; they exchange the messages and services in :doc:`../reference/interfaces/index`. If you want to know what a subsystem can do, read its interfaces first. Which layer am I writing in? ---------------------------- .. list-table:: :header-rows: 1 :widths: 30 70 * - You are... - Work in * - building a new robot application - **application** — see :doc:`../tutorials/build_an_application` * - adding a behaviour every application should share - **framework** (``core_pick_and_place``) * - changing how motions are planned or executed - **services** * - adding a new arm or gripper - **simulation** (``mesh_models``) plus configuration Most work belongs in the application layer. Reaching into services usually means either the framework is missing something, or an interface needs extending. The request path ---------------- A pick-and-place cycle moves through the layers like this: .. code-block:: text CLI / UI -> supervisor activates the application's lifecycle nodes -> application decides what to do next (which destination) -> move_arm (framework) plans + sends the trajectory -> motion_planning /compute_motion_plan, /check_robot_collision -> motion_control queues the trajectory, drives the arm -> ArmPlugin (simulation only) applies joint commands in Gazebo -> end effector grasp / release Two properties of this path are worth internalising early. **The same driver runs against simulation and hardware.** ``motion_control_ros`` speaks the Motoman ``simple_message`` protocol over TCP. In simulation ``core_plugins``' ``ArmPlugin`` implements the other end of that protocol on ports 50240/50241, so nothing above the driver knows whether it is talking to a real robot. Code that works in simulation is the code that runs on hardware. **Planning and execution are separate.** ``motion_planning`` produces a time-parameterised trajectory; ``motion_control`` executes it. A trajectory that plans cleanly can still be executed badly — see :doc:`../howto/debug_a_collision`. Applications are a template, not a framework call ------------------------------------------------- There is no ``Application`` base class to inherit. An application is a set of packages that mirror ``core_pick_and_place`` one-for-one: .. list-table:: :header-rows: 1 :widths: 50 50 * - Framework package - Your application provides * - ``pick_and_place_controller`` - a controller (HTTP/UI entry point) * - ``core_decision_taking`` - decision taking (what to do next) * - ``pick_and_place_interfaces`` - your own msg/srv/action * - ``pick_and_place_cli`` - a CLI * - ``move_arm_app``, ``pre_planner_app`` - bringup and any custom plugins ``sorting_app`` is the reference implementation of that mapping. :doc:`../tutorials/build_an_application` walks through it. Configuration is part of the API -------------------------------- Behaviour that looks like code is often configuration, and getting it wrong produces symptoms that look like bugs: - ``parameterization_config.json`` — velocity and acceleration limits per speed profile. Too aggressive and the arm cannot track the trajectory it was given. - ``app_poses.json`` — base and pivot poses the application plans between. - the ``ArmPlugin`` block in the world SDF — how joint commands reach the simulated arm, including ``drive_mode``. See :doc:`../howto/index` for what each key does and what breaks when it is wrong.