From b4e5742ba98e683b662a519fe84a27cd29094d5f Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 30 Sep 2024 20:09:46 -0700 Subject: [PATCH 1/6] Add tutorial for migrating a Python package from ROS 1 to 2 Signed-off-by: Shane Loretz --- source/How-To-Guides/Migrating-from-ROS1.rst | 1 + .../Migrating-Python-Package-Tutorial.rst | 129 ++++++++++++++++++ .../Migrating-Python-Packages.rst | 4 +- 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst diff --git a/source/How-To-Guides/Migrating-from-ROS1.rst b/source/How-To-Guides/Migrating-from-ROS1.rst index 91e298d1af..d329b5f344 100644 --- a/source/How-To-Guides/Migrating-from-ROS1.rst +++ b/source/How-To-Guides/Migrating-from-ROS1.rst @@ -12,6 +12,7 @@ If you are new to porting between ROS 1 and ROS 2, it is recommended to read thr Migrating-from-ROS1/Migrating-Interfaces Migrating-from-ROS1/Migrating-CPP-Package-Example Migrating-from-ROS1/Migrating-CPP-Packages + Migrating-from-ROS1/Migrating-Python-Package-Tutorial Migrating-from-ROS1/Migrating-Python-Packages Migrating-from-ROS1/Migrating-Launch-Files Migrating-from-ROS1/Migrating-Parameters diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst new file mode 100644 index 0000000000..1282f59ac9 --- /dev/null +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst @@ -0,0 +1,129 @@ +Migrating a Python Package Tutorial +=================================== + +.. contents:: Table of Contents + :depth: 2 + :local: + +This tutorial shows how to migrate an example Python package from ROS 1 to ROS 2. + +Prerequisites +------------- + +You need a working ROS 2 installation, such as :doc:`ROS {DISTRO} <../../Installation>`. + +The ROS 1 code +-------------- + +Say you have a ROS 1 package called ``talker_py`` that uses ``rospy`` in one node, called ``talker_py_node``. +This package is in a catkin workspace, located at ``~/ros1_talker``. + +Your ROS 1 workspace has the following directory layout: + +.. code-block:: bash + + $ cd ~/ros1_talker + $ find . + . + src + src/talker_py + src/talker_py/package.xml + src/talker_py/CMakeLists.txt + src/talker_py/src + src/talker_py/src/talker_py + src/talker_py/src/talker_py/__init__.py + src/talker_py/scripts + src/talker_py/scripts/talker_py_node + src/talker_py/setup.py + +The files have the following content: + +``src/talker_py/package.xml``: + +.. code-block:: xml + + + + + talker_py + 1.0.0 + The talker_py package + Brian Gerkey + BSD + + catkin + + rospy + std_msgs + + +``src/talker_py/CMakeLists.txt``: + +.. code-block:: cmake + + cmake_minimum_required(VERSION 3.0.2) + project(talker_py) + + find_package(catkin REQUIRED) + + catkin_python_setup() + + catkin_package() + + catkin_install_python(PROGRAMS + scripts/talker_py_node + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} + ) + +``src/talker/src/talker_py/__init__.py``: + +.. code-block:: python + + import rospy + from std_msgs.msg import String + + def main(): + pub = rospy.Publisher('chatter', String, queue_size=10) + rospy.init_node('talker', anonymous=True) + rate = rospy.Rate(10) # 10hz + while not rospy.is_shutdown(): + hello_str = "hello world %s" % rospy.get_time() + rospy.loginfo(hello_str) + pub.publish(hello_str) + rate.sleep() + +``src/talker_py/scripts/talker_py_node``: + +.. code-block:: python + + #!/usr/bin/env python + + import talker_py + + if __name__ == '__main__': + talker_py.main() + +``src/talker_py/setup.py``: + +.. code-block:: python + + from setuptools import setup + from catkin_pkg.python_setup import generate_distutils_setup + + setup_args = generate_distutils_setup( + packages=['talker_py'], + package_dir={'': 'src'} + ) + + setup(**setup_args) + +Migrating to ROS 2 +------------------ + +TODO + +Conclusion +---------- + +You have learned how to migrate an example Python ROS 1 package to ROS 2. +Use the :doc:`Migrating Python Packages reference page <./Migrating-Python-Packages>` to help you migrate your own Python packages from ROS 1 to ROS 2. \ No newline at end of file diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Packages.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Packages.rst index 2c8d7ffa0d..b234a38bb7 100644 --- a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Packages.rst +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Packages.rst @@ -3,8 +3,8 @@ Migration-Guide-Python The-ROS2-Project/Contributing/Migration-Guide-Python -Migrating Python Packages -========================= +Migrating Python Packages Reference +=================================== .. contents:: Table of Contents :depth: 2 From 278bed203ca9470bfe83cd22b7d15711478a0b9b Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Mon, 30 Sep 2024 20:12:06 -0700 Subject: [PATCH 2/6] Newline at end of file Signed-off-by: Shane Loretz --- .../Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst index 1282f59ac9..7c9aeedebf 100644 --- a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst @@ -126,4 +126,4 @@ Conclusion ---------- You have learned how to migrate an example Python ROS 1 package to ROS 2. -Use the :doc:`Migrating Python Packages reference page <./Migrating-Python-Packages>` to help you migrate your own Python packages from ROS 1 to ROS 2. \ No newline at end of file +Use the :doc:`Migrating Python Packages reference page <./Migrating-Python-Packages>` to help you migrate your own Python packages from ROS 1 to ROS 2. From de72497f438e9460068a06544f37d024e840927a Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 1 Oct 2024 14:34:26 -0700 Subject: [PATCH 3/6] Tutorial -> Example Signed-off-by: Shane Loretz --- ...ge-Tutorial.rst => Migrating-Python-Package-Example.rst} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename source/How-To-Guides/Migrating-from-ROS1/{Migrating-Python-Package-Tutorial.rst => Migrating-Python-Package-Example.rst} (95%) diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst similarity index 95% rename from source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst rename to source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst index 7c9aeedebf..04d50a3ad9 100644 --- a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Tutorial.rst +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst @@ -1,11 +1,11 @@ -Migrating a Python Package Tutorial -=================================== +Migrating a Python Package Example +================================== .. contents:: Table of Contents :depth: 2 :local: -This tutorial shows how to migrate an example Python package from ROS 1 to ROS 2. +This guide shows how to migrate an example Python package from ROS 1 to ROS 2. Prerequisites ------------- From 338470d5205de94a26fd08bc8383e1c8911137eb Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 1 Oct 2024 14:34:54 -0700 Subject: [PATCH 4/6] Tutorial -> Example Signed-off-by: Shane Loretz --- source/How-To-Guides/Migrating-from-ROS1.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/How-To-Guides/Migrating-from-ROS1.rst b/source/How-To-Guides/Migrating-from-ROS1.rst index d329b5f344..6b095ca63f 100644 --- a/source/How-To-Guides/Migrating-from-ROS1.rst +++ b/source/How-To-Guides/Migrating-from-ROS1.rst @@ -12,7 +12,7 @@ If you are new to porting between ROS 1 and ROS 2, it is recommended to read thr Migrating-from-ROS1/Migrating-Interfaces Migrating-from-ROS1/Migrating-CPP-Package-Example Migrating-from-ROS1/Migrating-CPP-Packages - Migrating-from-ROS1/Migrating-Python-Package-Tutorial + Migrating-from-ROS1/Migrating-Python-Package-Example Migrating-from-ROS1/Migrating-Python-Packages Migrating-from-ROS1/Migrating-Launch-Files Migrating-from-ROS1/Migrating-Parameters From 4607856efe0cac9293f0fc420fc66913417a8f7f Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 8 Oct 2024 04:21:37 +0000 Subject: [PATCH 5/6] More progress on migration guide Signed-off-by: Shane Loretz --- .../Migrating-Python-Package-Example.rst | 209 ++++++++++++++++-- 1 file changed, 191 insertions(+), 18 deletions(-) diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst index 04d50a3ad9..985114172a 100644 --- a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst @@ -15,28 +15,27 @@ You need a working ROS 2 installation, such as :doc:`ROS {DISTRO} <../../Install The ROS 1 code -------------- -Say you have a ROS 1 package called ``talker_py`` that uses ``rospy`` in one node, called ``talker_py_node``. -This package is in a catkin workspace, located at ``~/ros1_talker``. +Create a colcon workspace at ``~/ros2_tallker_py``. -Your ROS 1 workspace has the following directory layout: +.. code-block:: bash + + mkdir -p ~/ros2_talker_py/src + +Next, create a ROS 1 package in the new workspace. +The ROS 1 package is called ``talker_py``, and it has one node called ``talker_py_node``. .. code-block:: bash - $ cd ~/ros1_talker - $ find . - . - src - src/talker_py - src/talker_py/package.xml - src/talker_py/CMakeLists.txt - src/talker_py/src - src/talker_py/src/talker_py - src/talker_py/src/talker_py/__init__.py - src/talker_py/scripts - src/talker_py/scripts/talker_py_node - src/talker_py/setup.py - -The files have the following content: + cd ~/ros2_talker_py + mkdir -p src/talker_py/src/talker_py + mkdir -p src/talker_py/scripts + touch src/talker_py/package.xml + touch src/talker_py/CMakeLists.txt + touch src/talker_py/src/talker_py/__init__.py + touch src/talker_py/scripts/talker_py_node + touch src/talker_py/setup.py + +Put the following content into each file ``src/talker_py/package.xml``: @@ -117,11 +116,185 @@ The files have the following content: setup(**setup_args) +You now have a ROS 1 package in a new workspace. + Migrating to ROS 2 ------------------ +When migrating large packages to ROS 2, it is helpful to build and run tests as you go. +Migrate the build system files first so that you can do this. +Always start with the ``package.xml``. + +Migrating the ``package.xml`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ROS 2 does not use ``catkin``. +Delete the ```` on it. + +.. code-block:: + + + catkin + + +ROS 2 uses ``rclpy`` instead of ``rospy``. +Delete the dependency on ``rospy``. + +.. code-block:: + + + rospy + + +Add a new dependency on ``rclpy``. + +.. code-block:: xml + + rclpy + +Add an ```` section to tell colcon the package is an ``ament_python`` package instead of a ``catkin`` package. + +.. code-block:: xml + + + ament_python + + + +Your ``package.xml`` is fully migrated. +It now looks like this: + +.. code-block:: xml + + + + + talker_py + 1.0.0 + The talker_py package + Brian Gerkey + BSD + + rclpy + std_msgs + + + ament_python + + + +Migrating to ``setup.py`` and ``setup.cfg`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Python packages in ROS 2 do not use CMake, so delete the ``CMakeLists.txt``. + +Create a new file called ``setup.cfg`` next to the ``package.xml``. +The ``setup.cfg`` needs two pieces of information with the package's name, ``talker_py``, in it. +Put the following content into ``setup.cfg`` + +.. code-block:: + + [develop] + script_dir=$base/lib/talker_py + [install] + install_scripts=$base/lib/talker_py + +The ``setup.py`` can no longer be automatically generated with ``catkin_pkg``. +Start by deleting the import from ``catkin_pkg``. + +.. code-block:: + + # Delete this + from catkin_pkg.python_setup import generate_distutils_setup + +Move all arguments given to ``generate_distutils_setup()`` directly into the call to ``setup()``. + +.. code-block:: python + + setup( + packages=['talker_py'], + package_dir={'': 'src'}, + ) + +Delete the call to ``generate_distutils_setup()``. + +.. code-block:: + + # Delete this + setup_args = generate_distutils_setup( + packages=['talker_py'], + package_dir={'': 'src'} + ) + +The call to ``setup()`` needs some `additional metadata `__ copied from the ``package.xml``: + +* package name via the ``name`` argument +* package version via the ``version`` argument +* maintainer via the ``maintainer`` and ``maintainer_email`` arguments +* description via the ``description`` argument +* license via the ``license`` argument + +The package name will be used multiple times. +Create a variable called ``package_name`` in the ``setup.py``. + +.. code-block:: python + + package_name = 'talker_py' + +Copy all of the remaining information into the arguments of ``setup()`` in ``setup.py``. +Your call to ``setup()`` should look like this: + +.. code-block:: python + + setup( + name=package_name, + version='1.0.0', + packages=['talker_py'], + package_dir={'': 'src'}, + maintainer='Brian Gerkey', + maintainer_email='gerkey@osrfoundation.org', + description='The talker_py package', + license='BSD', + ) + +A ROS 2 must install two additional data files so that command line tools like ``ros2 run`` can find the package: + +* a ``package.xml`` +* a package marker file + +You already have a ``package.xml``, but you do not yet have a package marker file. +Create the marker file by creating a directory next to your ``package.xml`` called ``resource``. +Create an empty file in that directory with the same name as your package. + +.. code-block:: bash + + mkdir resource + touch resource/talker_py + +You must tell ``setuptools`` how to install these files. +Add the following ``data_files`` argument to the call to ``setup()`` to do so. + +.. code-block:: python + + data_files=[ + ('share/ament_index/resource_index/packages', + ['resource/' + package_name]), + ('share/' + package_name, ['package.xml']), + ], + + TODO +.. code-block:: python + + install_requires=['setuptools'], + zip_safe=True, + entry_points={ + 'console_scripts': [ + 'talker_py_node = talker_py:main', + ], + }, + Conclusion ---------- From 9b77568cb614de2051e00673fb8d12f0b95ed7c4 Mon Sep 17 00:00:00 2001 From: Shane Loretz Date: Tue, 8 Oct 2024 08:00:39 -0700 Subject: [PATCH 6/6] More section headings Signed-off-by: Shane Loretz --- .../Migrating-Python-Package-Example.rst | 55 ++++++++++++++----- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst index 985114172a..392c1cc02e 100644 --- a/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst +++ b/source/How-To-Guides/Migrating-from-ROS1/Migrating-Python-Package-Example.rst @@ -183,21 +183,8 @@ It now looks like this: -Migrating to ``setup.py`` and ``setup.cfg`` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Python packages in ROS 2 do not use CMake, so delete the ``CMakeLists.txt``. - -Create a new file called ``setup.cfg`` next to the ``package.xml``. -The ``setup.cfg`` needs two pieces of information with the package's name, ``talker_py``, in it. -Put the following content into ``setup.cfg`` - -.. code-block:: - - [develop] - script_dir=$base/lib/talker_py - [install] - install_scripts=$base/lib/talker_py +Migrating the ``setup.py`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``setup.py`` can no longer be automatically generated with ``catkin_pkg``. Start by deleting the import from ``catkin_pkg``. @@ -295,6 +282,44 @@ TODO ], }, +Migrating python scripts and ``setup.cfg`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +ROS 2 python packages need to install their executables into package specific directories so that tools like ``ros2 run`` can find them. +Create a new file called ``setup.cfg`` next to the ``package.xml``. +Put the following content into ``setup.cfg`` to make sure executables are installed into the correct place. + +.. code-block:: + + [develop] + script_dir=$base/lib/talker_py + [install] + install_scripts=$base/lib/talker_py + +TODO Adding a console_scripts entry point, deleting scripts/talker_py_node + +Delete the ``CMakeLists.txt`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Python packages in ROS 2 do not use CMake, so delete the ``CMakeLists.txt``. + +Migrating Python code +~~~~~~~~~~~~~~~~~~~~~ + +The recommended ROS 2 Python APIs are significantly different from ROS 1. +Migrate your Python code in two steps: + +1. Migrate code as-is to get something working in ROS 2 +2. Refactor code to common ROS 2 Python conventions + +Migrating Python code as-is +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Refactorin Python code +^^^^^^^^^^^^^^^^^^^^^^ + +TODO inheriting from Node class, timers vs rates, more callback focussed + Conclusion ----------