.. redirect-from:: Tutorials/Creating-Your-First-ROS2-Package .. _CreatePkg: Creating a package ================== **Goal:** Create a new package using either CMake or Python, and run its executable. **Tutorial level:** Beginner **Time:** 15 minutes .. contents:: Contents :depth: 2 :local: Background ---------- 1 What is a ROS 2 package? ^^^^^^^^^^^^^^^^^^^^^^^^^^ A package is an organizational unit for your ROS 2 code. If you want to be able to install your code or share it with others, then you'll need it organized in a package. With packages, you can release your ROS 2 work and allow others to build and use it easily. Package creation in ROS 2 uses ament as its build system and colcon as its build tool. You can create a package using either CMake or Python, which are officially supported, though other build types do exist. 2 What makes up a ROS 2 package? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ROS 2 Python and CMake packages each have their own minimum required contents: .. tabs:: .. group-tab:: CMake * ``CMakeLists.txt`` file that describes how to build the code within the package * ``include/`` directory containing the public headers for the package * ``package.xml`` file containing meta information about the package * ``src`` directory containing the source code for the package .. group-tab:: Python * ``package.xml`` file containing meta information about the package * ``resource/`` marker file for the package * ``setup.cfg`` is required when a package has executables, so ``ros2 run`` can find them * ``setup.py`` containing instructions for how to install the package * ```` - a directory with the same name as your package, used by ROS 2 tools to find your package, contains ``__init__.py`` The simplest possible package may have a file structure that looks like: .. tabs:: .. group-tab:: CMake .. code-block:: console my_package/ CMakeLists.txt include/my_package/ package.xml src/ .. group-tab:: Python .. code-block:: console my_package/ package.xml resource/my_package setup.cfg setup.py my_package/ 3 Packages in a workspace ^^^^^^^^^^^^^^^^^^^^^^^^^ A single workspace can contain as many packages as you want, each in their own folder. You can also have packages of different build types in one workspace (CMake, Python, etc.). You cannot have nested packages. Best practice is to have a ``src`` folder within your workspace, and to create your packages in there. This keeps the top level of the workspace “clean”. A trivial workspace might look like: .. code-block:: console workspace_folder/ src/ cpp_package_1/ CMakeLists.txt include/cpp_package_1/ package.xml src/ py_package_1/ package.xml resource/py_package_1 setup.cfg setup.py py_package_1/ ... cpp_package_n/ CMakeLists.txt include/cpp_package_n/ package.xml src/ Prerequisites ------------- You should have a ROS 2 workspace after following the instructions in the :doc:`previous tutorial <./Creating-A-Workspace/Creating-A-Workspace>`. You will create your package in this workspace. Tasks ----- 1 Create a package ^^^^^^^^^^^^^^^^^^ First, :doc:`source your ROS 2 installation <../Beginner-CLI-Tools/Configuring-ROS2-Environment>`. Let's use the workspace you created in the :ref:`previous tutorial `, ``ros2_ws``, for your new package. Make sure you are in the ``src`` folder before running the package creation command. .. tabs:: .. group-tab:: Linux .. code-block:: console cd ~/ros2_ws/src .. group-tab:: macOS .. code-block:: console cd ~/ros2_ws/src .. group-tab:: Windows .. code-block:: console cd \ros2_ws\src The command syntax for creating a new package in ROS 2 is: .. tabs:: .. group-tab:: CMake .. code-block:: console ros2 pkg create --build-type ament_cmake --license Apache-2.0 .. group-tab:: Python .. code-block:: console ros2 pkg create --build-type ament_python --license Apache-2.0 For this tutorial, you will use the optional arguments ``--node-name`` and ``--license``. ``--node-name`` option creates a simple Hello World type executable in the package, and ``--license`` declares the license information for the package. Enter the following command in your terminal: .. tabs:: .. group-tab:: CMake .. code-block:: console ros2 pkg create --build-type ament_cmake --license Apache-2.0 --node-name my_node my_package .. group-tab:: Python .. code-block:: console ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name my_node my_package You will now have a new folder within your workspace's ``src`` directory called ``my_package``. After running the command, your terminal will return the message: .. tabs:: .. group-tab:: CMake .. code-block:: console going to create a new package package name: my_package destination directory: /home/user/ros2_ws/src package format: 3 version: 0.0.0 description: TODO: Package description maintainer: [' '] licenses: ['Apache-2.0'] build type: ament_cmake dependencies: [] node_name: my_node creating folder ./my_package creating ./my_package/package.xml creating source and include folder creating folder ./my_package/src creating folder ./my_package/include/my_package creating ./my_package/CMakeLists.txt creating ./my_package/src/my_node.cpp .. group-tab:: Python .. code-block:: console going to create a new package package name: my_package destination directory: /home/user/ros2_ws/src package format: 3 version: 0.0.0 description: TODO: Package description maintainer: [' '] licenses: ['Apache-2.0'] build type: ament_python dependencies: [] node_name: my_node creating folder ./my_package creating ./my_package/package.xml creating source folder creating folder ./my_package/my_package creating ./my_package/setup.py creating ./my_package/setup.cfg creating folder ./my_package/resource creating ./my_package/resource/my_package creating ./my_package/my_package/__init__.py creating folder ./my_package/test creating ./my_package/test/test_copyright.py creating ./my_package/test/test_flake8.py creating ./my_package/test/test_pep257.py creating ./my_package/my_package/my_node.py You can see the automatically generated files for the new package. 2 Build a package ^^^^^^^^^^^^^^^^^ Putting packages in a workspace is especially valuable because you can build many packages at once by running ``colcon build`` in the workspace root. Otherwise, you would have to build each package individually. Return to the root of your workspace: .. tabs:: .. group-tab:: Linux .. code-block:: console cd ~/ros2_ws .. group-tab:: macOS .. code-block:: console cd ~/ros2_ws .. group-tab:: Windows .. code-block:: console cd \ros2_ws Now you can build your packages: .. tabs:: .. group-tab:: Linux .. code-block:: console colcon build .. group-tab:: macOS .. code-block:: console colcon build .. group-tab:: Windows .. code-block:: console colcon build --merge-install Windows doesn't allow long paths, so ``merge-install`` will combine all the paths into the ``install`` directory. Recall from the last tutorial that you also have the ``ros_tutorials`` packages in your ``ros2_ws``. You might have noticed that running ``colcon build`` also built the ``turtlesim`` package. That's fine when you only have a few packages in your workspace, but when there are many packages, ``colcon build`` can take a long time. To build only the ``my_package`` package next time, you can run: .. code-block:: console colcon build --packages-select my_package 3 Source the setup file ^^^^^^^^^^^^^^^^^^^^^^^ To use your new package and executable, first open a new terminal and source your main ROS 2 installation. Then, from inside the ``ros2_ws`` directory, run the following command to source your workspace: .. tabs:: .. group-tab:: Linux .. code-block:: console source install/local_setup.bash .. group-tab:: macOS .. code-block:: console . install/local_setup.bash .. group-tab:: Windows .. code-block:: console call install/local_setup.bat Now that your workspace has been added to your path, you will be able to use your new package's executables. 4 Use the package ^^^^^^^^^^^^^^^^^ To run the executable you created using the ``--node-name`` argument during package creation, enter the command: .. code-block:: console ros2 run my_package my_node Which will return a message to your terminal: .. tabs:: .. group-tab:: CMake .. code-block:: console hello world my_package package .. group-tab:: Python .. code-block:: console Hi from my_package. 5 Examine package contents ^^^^^^^^^^^^^^^^^^^^^^^^^^ Inside ``ros2_ws/src/my_package``, you will see the files and folders that ``ros2 pkg create`` automatically generated: .. tabs:: .. group-tab:: CMake .. code-block:: console CMakeLists.txt include package.xml src ``my_node.cpp`` is inside the ``src`` directory. This is where all your custom C++ nodes will go in the future. .. group-tab:: Python .. code-block:: console my_package package.xml resource setup.cfg setup.py test ``my_node.py`` is inside the ``my_package`` directory. This is where all your custom Python nodes will go in the future. 6 Customize package.xml ^^^^^^^^^^^^^^^^^^^^^^^ You may have noticed in the return message after creating your package that the fields ``description`` and ``license`` contain ``TODO`` notes. That's because the package description and license declaration are not automatically set, but are required if you ever want to release your package. The ``maintainer`` field may also need to be filled in. From ``ros2_ws/src/my_package``, open ``package.xml`` using your preferred text editor: .. tabs:: .. group-tab:: CMake .. code-block:: xml my_package 0.0.0 TODO: Package description user TODO: License declaration ament_cmake ament_lint_auto ament_lint_common ament_cmake .. group-tab:: Python .. code-block:: xml my_package 0.0.0 TODO: Package description user TODO: License declaration ament_copyright ament_flake8 ament_pep257 python3-pytest ament_python Input your name and email on the ``maintainer`` line if it hasn't been automatically populated for you. Then, edit the ``description`` line to summarize the package: .. code-block:: xml Beginner client libraries tutorials practice package Then, update the ``license`` line. You can read more about open source licenses `here `__. Since this package is only for practice, it's safe to use any license. We'll use ``Apache License 2.0``: .. code-block:: xml Apache License 2.0 Don't forget to save once you're done editing. Below the license tag, you will see some tag names ending with ``_depend``. This is where your ``package.xml`` would list its dependencies on other packages, for colcon to search for. ``my_package`` is simple and doesn't have any dependencies, but you will see this space being utilized in upcoming tutorials. .. tabs:: .. group-tab:: CMake You're all done for now! .. group-tab:: Python The ``setup.py`` file contains the same description, maintainer and license fields as ``package.xml``, so you need to set those as well. They need to match exactly in both files. The version and name (``package_name``) also need to match exactly, and should be automatically populated in both files. Open ``setup.py`` with your preferred text editor. .. code-block:: python from setuptools import find_packages, setup package_name = 'my_py_pkg' setup( name=package_name, version='0.0.0', packages=find_packages(exclude=['test']), data_files=[ ('share/ament_index/resource_index/packages', ['resource/' + package_name]), ('share/' + package_name, ['package.xml']), ], install_requires=['setuptools'], zip_safe=True, maintainer='TODO', maintainer_email='TODO', description='TODO: Package description', license='TODO: License declaration', tests_require=['pytest'], entry_points={ 'console_scripts': [ 'my_node = my_py_pkg.my_node:main' ], }, ) Edit the ``maintainer``, ``maintainer_email``, and ``description`` lines to match ``package.xml``. Don't forget to save the file. Summary ------- You've created a package to organize your code and make it easy to use for others. Your package was automatically populated with the necessary files, and then you used colcon to build it so you can use its executables in your local environment. Next steps ---------- Next, let's add something meaningful to a package. You'll start with a simple publisher/subscriber system, which you can choose to write in either :doc:`C++ <./Writing-A-Simple-Cpp-Publisher-And-Subscriber>` or :doc:`Python <./Writing-A-Simple-Py-Publisher-And-Subscriber>`.