{"id":2068,"date":"2020-08-03T15:00:18","date_gmt":"2020-08-03T15:00:18","guid":{"rendered":"https:\/\/roboticsbackend.com\/?p=2068"},"modified":"2023-02-01T10:53:28","modified_gmt":"2023-02-01T10:53:28","slug":"create-a-ros2-python-package","status":"publish","type":"post","link":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/","title":{"rendered":"Create a ROS2 Python package"},"content":{"rendered":"<p>In this tutorial you&#8217;ll learn how to create and setup a ROS2 Python package.<\/p>\n<p>I&#8217;ll show you every step, and explain the relation between files, where to write your nodes, how to add launch files, etc.<\/p>\n<p>&gt;&gt; Here&#8217;s a video tutorial that recaps the first part of this article. Watch it as an additional resource:<\/p>\n<p><iframe loading=\"lazy\" title=\"Create a ROS2 Python Package - ROS2 Tutorial 4\" width=\"1200\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/iBGZ8LEvkCY?feature=oembed&#038;rel=0\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/p>\n<p>After watching the video,\u00a0<a href=\"https:\/\/www.youtube.com\/c\/RoboticsBackEnd?sub_confirmation=1\">subscribe to the Robotics Back-End Youtube channel<\/a>\u00a0so you don\u2019t miss the next tutorials!<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_81 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-69fcb0a48023c\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-69fcb0a48023c\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Setup_your_ROS2_Python_package\" >Setup your ROS2 Python package<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Explanation_of_files_inside_a_ROS2_Python_package\" >Explanation of files inside a ROS2 Python package<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#packagexml\" >package.xml<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#setuppy\" >setup.py<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#setupcfg\" >setup.cfg<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#_folder\" >&lt;package_name&gt;\/ folder<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#resource_file\" >resource\/&lt;package_name&gt; file<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#test_folder\" >test\/ folder<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Compile_your_package\" >Compile your package<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Build_a_Python_node_inside_a_ROS2_Python_package\" >Build a Python node inside a ROS2 Python package<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Install_other_files_in_a_ROS2_Python_package\" >Install other files in a ROS2 Python package<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#Launch_files\" >Launch files<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#YAML_config_files\" >YAML config files<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#ROS2_Python_package_going_further\" >ROS2 Python package: going further<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"Setup_your_ROS2_Python_package\"><\/span>Setup your ROS2 Python package<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Before you can create a ROS2 Python package, make sure you have :<\/p>\n<ul>\n<li>correctly installed ROS2,<\/li>\n<li>setup your environment (add <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">source \/opt\/ros\/ROS_VERSION\/setup.bash<\/code> in your .bashrc &#8211; don&#8217;t forget to replace &#8220;ROS_VERSION&#8221;),<\/li>\n<li>and created a ROS2 workspace (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">$ mkdir -p ~\/ros2_ws\/src &amp;&amp; cd ros2_ws\/ &amp;&amp; colcon build<\/code>).<\/li>\n<\/ul>\n<p>Now, to create a Python package:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ cd ~\/ros2_ws\/src\/\n$ ros2 pkg create my_python_pkg --build-type ament_python \ngoing to create a new package\npackage name: my_python_pkg\ndestination directory: \/home\/user\/ros2_ws\/src\npackage format: 3\nversion: 0.0.0\ndescription: TODO: Package description\nmaintainer: ['Name &lt;your@email.com&gt;']\nlicenses: ['TODO: License declaration']\nbuild type: ament_python\ndependencies: []\ncreating folder .\/my_python_pkg\ncreating .\/my_python_pkg\/package.xml\ncreating source folder\ncreating folder .\/my_python_pkg\/my_python_pkg\ncreating .\/my_python_pkg\/setup.py\ncreating .\/my_python_pkg\/setup.cfg\ncreating folder .\/my_python_pkg\/resource\ncreating .\/my_python_pkg\/resource\/my_python_pkg\ncreating .\/my_python_pkg\/my_python_pkg\/__init__.py\ncreating folder .\/my_python_pkg\/test\ncreating .\/my_python_pkg\/test\/test_copyright.py\ncreating .\/my_python_pkg\/test\/test_flake8.py\ncreating .\/my_python_pkg\/test\/test_pep257.py<\/pre>\n<p>Use <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">ros2 pkg create<\/code> followed by the name of your package. Then add the option <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">--build-type ament_python<\/code> to precise that you&#8217;re building a package specifically for Python.<\/p>\n<p>A bunch of files will be created inside the new package.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-linenumbers=\"false\">my_python_pkg\/\n\u251c\u2500\u2500 my_python_pkg\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 __init__.py\n\u251c\u2500\u2500 package.xml\n\u251c\u2500\u2500 resource\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 my_python_pkg\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 setup.py\n\u2514\u2500\u2500 test\n    \u251c\u2500\u2500 test_copyright.py\n    \u251c\u2500\u2500 test_flake8.py\n    \u2514\u2500\u2500 test_pep257.py<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Explanation_of_files_inside_a_ROS2_Python_package\"><\/span>Explanation of files inside a ROS2 Python package<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Here&#8217;s a quick explanation for each file, and what you have to do to set them up.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"packagexml\"><\/span>package.xml<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This file provides some information and required dependencies for the package.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-highlight=\"5-8\">&lt;?xml version=\"1.0\"?&gt;\n&lt;?xml-model href=\"http:\/\/download.ros.org\/schema\/package_format3.xsd\" schematypens=\"http:\/\/www.w3.org\/2001\/XMLSchema\"?&gt;\n&lt;package format=\"3\"&gt;\n  &lt;name&gt;my_python_pkg&lt;\/name&gt;\n  &lt;version&gt;0.0.0&lt;\/version&gt;\n  &lt;description&gt;TODO: Package description&lt;\/description&gt;\n  &lt;maintainer email=\"your@email.com\"&gt;Name&lt;\/maintainer&gt;\n  &lt;license&gt;TODO: License declaration&lt;\/license&gt;\n\n  &lt;buildtool_depend&gt;ament_python&lt;\/buildtool_depend&gt;\n\n  &lt;test_depend&gt;ament_copyright&lt;\/test_depend&gt;\n  &lt;test_depend&gt;ament_flake8&lt;\/test_depend&gt;\n  &lt;test_depend&gt;ament_pep257&lt;\/test_depend&gt;\n  &lt;test_depend&gt;python3-pytest&lt;\/test_depend&gt;\n\n  &lt;export&gt;\n    &lt;build_type&gt;ament_python&lt;\/build_type&gt;\n  &lt;\/export&gt;\n&lt;\/package&gt;\n<\/pre>\n<p>You need to manually edit lines 5-8. Everything will work if you don&#8217;t do it, but if you decide to share or publish your package, then those info are mandatory.<\/p>\n<ul>\n<li>version.<\/li>\n<li>description: a brief description of what your package does.<\/li>\n<li>maintainer: name and email of current maintainer. You can add multiple maintainer tags. Also, you can add some author tags (with name and email) if you want to make the distinction between authors and maintainers.<\/li>\n<li>license: if you ever want to publish your package you&#8217;ll need a license (for example BSD, MIT, GPLv3).<\/li>\n<\/ul>\n<h3><span class=\"ez-toc-section\" id=\"setuppy\"><\/span>setup.py<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>If you know what a CMakeLists.txt file is, well the setup.py is basically the same but for Python. When you compile your package it will tell what to install, where to install it, how to link dependencies, etc.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"7,16-18\">from setuptools import setup\n\npackage_name = 'my_python_pkg'\n\nsetup(\n    name=package_name,\n    version='0.0.0',\n    packages=[package_name],\n    data_files=[\n        ('share\/ament_index\/resource_index\/packages',\n            ['resource\/' + package_name]),\n        ('share\/' + package_name, ['package.xml']),\n    ],\n    install_requires=['setuptools'],\n    zip_safe=True,\n    maintainer='Name',\n    maintainer_email='your@email.com',\n    description='TODO: Package description',\n    license='TODO: License declaration',\n    tests_require=['pytest'],\n    entry_points={\n        'console_scripts': [\n        ],\n    },\n)\n<\/pre>\n<p>We&#8217;ll come back to this file later in this tutorial. For now you can see that the 4 lines we had to setup in the package.xml are also here. Modify those lines if you intent to share or publish the package.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"setupcfg\"><\/span>setup.cfg<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This file will tell where the scripts will be installed. Right now you have nothing to change.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">[develop]\nscript-dir=$base\/lib\/my_python_pkg\n[install]\ninstall-scripts=$base\/lib\/my_python_pkg\n<\/pre>\n<h3><span class=\"ez-toc-section\" id=\"_folder\"><\/span>&lt;package_name&gt;\/ folder<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This folder will be different every time, because it will always have the same name as your package. In this case the name of the package is &#8220;my_python_pkg&#8221;, so the name of the folder is also &#8220;my_python_pkg&#8221;.<\/p>\n<p>You will create all your ROS2 Python nodes in this folder. Note that it already contains an empty __init__.py file.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"resource_file\"><\/span>resource\/&lt;package_name&gt; file<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This is needed for ROS2 to find your package. For our example the file name is &#8220;resource\/my_python_pkg&#8221;.<\/p>\n<p>Nothing to change here for now.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"test_folder\"><\/span>test\/ folder<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>This folder, as its name suggests, is for testing. When you create a package it already contains 3 Python files.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Compile_your_package\"><\/span>Compile your package<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>To compile your package, go into your workspace directory and execute <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">colcon build<\/code>. We&#8217;ll tell ROS2 to only build our Python package with the option <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">--packages-select<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ cd ~\/ros2_ws\n$ colcon build --packages-select my_python_pkg \nStarting &gt;&gt;&gt; my_python_pkg\nFinished &lt;&lt;&lt; my_python_pkg [0.52s]          \n\nSummary: 1 package finished [0.65s]<\/pre>\n<p>Note: When working with Python, you may think that you don&#8217;t need to compile anything. That&#8217;s true, you can directly execute the Python files that you create without <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">colcon build<\/code>. But compiling a package is much more than that: it will install the scripts in a place where they can find other modules from other packages, where they can be found by other scripts. It will also allow you to start a node with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">ros2 run<\/code>, add it in a launch file, pass parameters to it, etc.<\/p>\n<p>Now that you know how to create and compile a package, let&#8217;s make a few examples to see what you can do with this package.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"Build_a_Python_node_inside_a_ROS2_Python_package\"><\/span>Build a Python node inside a ROS2 Python package<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Let&#8217;s see how to build, install, and use a Python node, with our freshly created ROS2 Python package.<\/p>\n<p>Create a file named my_python_node.py in the my_python_pkg\/ folder.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ cd ~\/ros2_ws\/src\/my_python_pkg\/my_python_pkg\/\n$ touch my_python_node.py<\/pre>\n<p>Here&#8217;s a simple Python code you can use for testing purposes.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">import rclpy\nfrom rclpy.node import Node\n\nclass MyPythonNode(Node):\n    def __init__(self):\n        super().__init__(\"my_node_name\")\n        self.get_logger().info(\"This node just says 'Hello'\")\n\ndef main(args=None):\n    rclpy.init(args=args)\n    node = MyPythonNode()\n    rclpy.spin(node)\n    node.destroy_node()\n    rclpy.shutdown()\n\nif __name__ == \"__main__\":\n    main()<\/pre>\n<p>The node will just print a message on startup, and then it will spin indefinitely until you kill the node. If you want to know more about the code, check out how to <a href=\"https:\/\/roboticsbackend.com\/write-minimal-ros2-python-node\/\">write a ROS2 Python node<\/a>.<\/p>\n<p>Now that we have a Python file, we need to add an entry point in the setup.py file.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\">...\nentry_points={\n    'console_scripts': [\n        'test = my_python_pkg.my_python_node:main'\n    ],\n...<\/pre>\n<p>Find the &#8220;entry_points&#8221; dictionary and add one line in the &#8220;console_scripts&#8221; array.<\/p>\n<p>Some explanations:<\/p>\n<ul>\n<li>&#8220;test&#8221; will be the name of the executable after the script is installed.<\/li>\n<li>&#8220;my_python_pkg.my_python_node:main&#8221; means: execute the main() function inside the my_python_node.py file, inside the my_python_pkg. So, the entry point is the main(). If you want to start your node with a different function, make sure to set the function name accordingly in setup.py.<\/li>\n<li>Don&#8217;t mix everything: executable name != file name != node name. Those are 3 different things. In our example: &#8220;test&#8221; is the executable, &#8220;my_python_node&#8221; is the file, and &#8220;my_node_name&#8221; is the node name. Note that you can also choose to use the same name for all 3.<\/li>\n<li>The executable script will be installed in ~\/ros2_ws\/install\/my_python_pkg\/lib\/my_python_pkg\/. This is the folder specified in the setup.cfg file.<\/li>\n<\/ul>\n<p>One more thing you need to do: add a <code class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">&lt;depend&gt;rclpy&lt;\/depend&gt;<\/code> tag in package.xml, because we use a dependency to rclpy in our code.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\">...\n&lt;buildtool_depend&gt;ament_python&lt;\/buildtool_depend&gt;\n\n&lt;depend&gt;rclpy&lt;\/depend&gt;\n...<\/pre>\n<p>You only need to do this once per dependency for the whole package. If you create another node you&#8217;ll need to update setup.py, but not package.xml if you don&#8217;t have any new dependency.<\/p>\n<p>And now you can compile your package with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">colcon build --packages-select my_python_pkg<\/code>. Then, open a new terminal, source your ROS2 workspace and execute the node with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">ros2 run<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ ros2 run my_python_pkg test \n[INFO] [my_node_name]: This node just says 'Hello'<\/pre>\n<h2><span class=\"ez-toc-section\" id=\"Install_other_files_in_a_ROS2_Python_package\"><\/span>Install other files in a ROS2 Python package<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>You can virtually put everything you want in a ROS2 package. There is no hard rule about what to do, but some conventions make it easier for you. Let&#8217;s see how to install launch files and YAML config files. Those are among the most common things you&#8217;ll add to packages when you develop your ROS2 application.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"Launch_files\"><\/span>Launch files<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Create a launch\/ folder at the root of your package. You&#8217;ll put all your <a href=\"https:\/\/roboticsbackend.com\/ros2-launch-file-example\/\">launch files<\/a> inside this folder.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ cd ~\/ros2_ws\/src\/my_python_pkg\/ \n$ mkdir launch<\/pre>\n<p>Now, to install those launch files, you need to modify setup.py.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"1,2,9\">import os\nfrom glob import glob\nfrom setuptools import setup\n...\ndata_files=[\n    ('share\/ament_index\/resource_index\/packages',\n        ['resource\/' + package_name]),\n    ('share\/' + package_name, ['package.xml']),\n    (os.path.join('share', package_name, 'launch'), glob('launch\/*.launch.py')),\n],\n...<\/pre>\n<p>For our example, with package name &#8220;my_python_pkg&#8221;, this will install all launch files from the launch\/ folder, into ~\/ros2_ws\/install\/my_python_pkg\/share\/my_python_pkg\/launch\/.<\/p>\n<p>Note: you only need to modify setup.py once. After that, every time you add a launch file you&#8217;ll just need to compile your package so that the file is installed, that&#8217;s it.<\/p>\n<p>Then, to start a launch file: <code class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\">ros2 launch package_name launch_file_name<\/code>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"YAML_config_files\"><\/span>YAML config files<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>You can follow the same technique to install <a href=\"https:\/\/roboticsbackend.com\/ros2-yaml-params\/\">YAML config files<\/a>.<\/p>\n<p>Create a config\/ folder at the root of your package. You&#8217;ll put all your YAML files here.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ cd ~\/ros2_ws\/src\/my_python_pkg\/\n$ mkdir config<\/pre>\n<p>To install YAML files, again, modify setup.py. Add a new line in the &#8220;data_files&#8221; array:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"python\" data-enlighter-highlight=\"7\">...\ndata_files=[\n    ('share\/ament_index\/resource_index\/packages',\n        ['resource\/' + package_name]),\n    ('share\/' + package_name, ['package.xml']),\n    (os.path.join('share', package_name, 'launch'), glob('launch\/*.launch.py')),\n    (os.path.join('share', package_name, 'config'), glob('config\/*.yaml')),\n],\n...<\/pre>\n<p>Still with the &#8220;my_python_pkg&#8221; example, the YAML files will be installed into ~\/ros2_ws\/install\/my_python_pkg\/share\/my_python_pkg\/config\/.<\/p>\n<p>You can follow this technique to add any other folder into the install\/ folder of your ROS2 workspace.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"ROS2_Python_package_going_further\"><\/span>ROS2 Python package: going further<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>In this tutorial you have seen how to setup a ROS2 Python package, and how to make it grow with nodes, launch files, YAML files.<\/p>\n<p>Here&#8217;s the final package architecture after all the additions we made:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"raw\" data-enlighter-linenumbers=\"false\">my_python_pkg\/\n\u251c\u2500\u2500 config\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 some_params.yaml\n\u251c\u2500\u2500 launch\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 my_application.launch.py\n\u251c\u2500\u2500 my_python_pkg\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 __init__.py\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 my_python_node.py\n\u251c\u2500\u2500 package.xml\n\u251c\u2500\u2500 resource\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 my_python_pkg\n\u251c\u2500\u2500 setup.cfg\n\u251c\u2500\u2500 setup.py\n\u2514\u2500\u2500 test\n    \u251c\u2500\u2500 test_copyright.py\n    \u251c\u2500\u2500 test_flake8.py\n    \u2514\u2500\u2500 test_pep257.py<\/pre>\n<p>Understanding how to work with ROS2 packages is important so that you&#8217;re not stuck whenever you want to add something to your application.<\/p>\n<p>To go further from here, check out how to:<\/p>\n<ul>\n<li><a href=\"https:\/\/roboticsbackend.com\/create-a-ros2-cpp-package\/\">Create a ROS2 Cpp package<\/a>.<\/li>\n<li><a href=\"https:\/\/roboticsbackend.com\/ros2-package-for-both-python-and-cpp-nodes\/\">Create a ROS2 package for both Python and Cpp<\/a>.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In this tutorial you&#8217;ll learn how to create and setup a ROS2 Python package. I&#8217;ll show you every step, and explain the relation between files, where to write your nodes, how to add launch files, etc. &gt;&gt; Here&#8217;s a video tutorial that recaps the first part of this article. Watch it as an additional resource: &#8230; <a title=\"Create a ROS2 Python package\" class=\"read-more\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\" aria-label=\"Read more about Create a ROS2 Python package\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-2068","post","type-post","status-publish","format-standard","hentry","category-ros2"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.1.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Create a ROS2 Python package - The Robotics Back-End<\/title>\n<meta name=\"description\" content=\"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Create a ROS2 Python package - The Robotics Back-End\" \/>\n<meta property=\"og:description\" content=\"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\" \/>\n<meta property=\"og:site_name\" content=\"The Robotics Back-End\" \/>\n<meta property=\"article:published_time\" content=\"2020-08-03T15:00:18+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-02-01T10:53:28+00:00\" \/>\n<meta name=\"author\" content=\"ed\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@RoboticsBackend\" \/>\n<meta name=\"twitter:site\" content=\"@RoboticsBackend\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"ed\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"7 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\"},\"author\":{\"name\":\"ed\",\"@id\":\"https:\/\/roboticsbackend.com\/#\/schema\/person\/a20832f15e39847d8eea5be981767353\"},\"headline\":\"Create a ROS2 Python package\",\"datePublished\":\"2020-08-03T15:00:18+00:00\",\"dateModified\":\"2023-02-01T10:53:28+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\"},\"wordCount\":1369,\"publisher\":{\"@id\":\"https:\/\/roboticsbackend.com\/#organization\"},\"articleSection\":[\"ROS2 Tutorials\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\",\"url\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\",\"name\":\"Create a ROS2 Python package - The Robotics Back-End\",\"isPartOf\":{\"@id\":\"https:\/\/roboticsbackend.com\/#website\"},\"datePublished\":\"2020-08-03T15:00:18+00:00\",\"dateModified\":\"2023-02-01T10:53:28+00:00\",\"description\":\"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.\",\"breadcrumb\":{\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/roboticsbackend.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Create a ROS2 Python package\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/roboticsbackend.com\/#website\",\"url\":\"https:\/\/roboticsbackend.com\/\",\"name\":\"The Robotics Back-End\",\"description\":\"Program Robots, Step by Step\",\"publisher\":{\"@id\":\"https:\/\/roboticsbackend.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/roboticsbackend.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/roboticsbackend.com\/#organization\",\"name\":\"Robotics Back-End\",\"url\":\"https:\/\/roboticsbackend.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/roboticsbackend.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/roboticsbackend.com\/wp-content\/uploads\/2020\/02\/logo_hd.png\",\"contentUrl\":\"https:\/\/roboticsbackend.com\/wp-content\/uploads\/2020\/02\/logo_hd.png\",\"width\":2500,\"height\":1875,\"caption\":\"Robotics Back-End\"},\"image\":{\"@id\":\"https:\/\/roboticsbackend.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/x.com\/RoboticsBackend\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/roboticsbackend.com\/#\/schema\/person\/a20832f15e39847d8eea5be981767353\",\"name\":\"ed\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/roboticsbackend.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7b666620f11fb12df5674e1e1ee525afe3d4ceecdaa57f8c60f6a937a33e3427?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/7b666620f11fb12df5674e1e1ee525afe3d4ceecdaa57f8c60f6a937a33e3427?s=96&d=identicon&r=g\",\"caption\":\"ed\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Create a ROS2 Python package - The Robotics Back-End","description":"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/","og_locale":"en_US","og_type":"article","og_title":"Create a ROS2 Python package - The Robotics Back-End","og_description":"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.","og_url":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/","og_site_name":"The Robotics Back-End","article_published_time":"2020-08-03T15:00:18+00:00","article_modified_time":"2023-02-01T10:53:28+00:00","author":"ed","twitter_card":"summary_large_image","twitter_creator":"@RoboticsBackend","twitter_site":"@RoboticsBackend","twitter_misc":{"Written by":"ed","Est. reading time":"7 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#article","isPartOf":{"@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/"},"author":{"name":"ed","@id":"https:\/\/roboticsbackend.com\/#\/schema\/person\/a20832f15e39847d8eea5be981767353"},"headline":"Create a ROS2 Python package","datePublished":"2020-08-03T15:00:18+00:00","dateModified":"2023-02-01T10:53:28+00:00","mainEntityOfPage":{"@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/"},"wordCount":1369,"publisher":{"@id":"https:\/\/roboticsbackend.com\/#organization"},"articleSection":["ROS2 Tutorials"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/","url":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/","name":"Create a ROS2 Python package - The Robotics Back-End","isPartOf":{"@id":"https:\/\/roboticsbackend.com\/#website"},"datePublished":"2020-08-03T15:00:18+00:00","dateModified":"2023-02-01T10:53:28+00:00","description":"Learn how to create a ROS2 Python package. Setup the package, add nodes, launch files, YAML files, and see how everything works together.","breadcrumb":{"@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/roboticsbackend.com\/create-a-ros2-python-package\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/roboticsbackend.com\/"},{"@type":"ListItem","position":2,"name":"Create a ROS2 Python package"}]},{"@type":"WebSite","@id":"https:\/\/roboticsbackend.com\/#website","url":"https:\/\/roboticsbackend.com\/","name":"The Robotics Back-End","description":"Program Robots, Step by Step","publisher":{"@id":"https:\/\/roboticsbackend.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/roboticsbackend.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/roboticsbackend.com\/#organization","name":"Robotics Back-End","url":"https:\/\/roboticsbackend.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/roboticsbackend.com\/#\/schema\/logo\/image\/","url":"https:\/\/roboticsbackend.com\/wp-content\/uploads\/2020\/02\/logo_hd.png","contentUrl":"https:\/\/roboticsbackend.com\/wp-content\/uploads\/2020\/02\/logo_hd.png","width":2500,"height":1875,"caption":"Robotics Back-End"},"image":{"@id":"https:\/\/roboticsbackend.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/x.com\/RoboticsBackend"]},{"@type":"Person","@id":"https:\/\/roboticsbackend.com\/#\/schema\/person\/a20832f15e39847d8eea5be981767353","name":"ed","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/roboticsbackend.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/7b666620f11fb12df5674e1e1ee525afe3d4ceecdaa57f8c60f6a937a33e3427?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7b666620f11fb12df5674e1e1ee525afe3d4ceecdaa57f8c60f6a937a33e3427?s=96&d=identicon&r=g","caption":"ed"}}]}},"_links":{"self":[{"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/posts\/2068","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/comments?post=2068"}],"version-history":[{"count":0,"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/posts\/2068\/revisions"}],"wp:attachment":[{"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/media?parent=2068"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/categories?post=2068"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/roboticsbackend.com\/wp-json\/wp\/v2\/tags?post=2068"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}