ROS2 Tutorials #5: How to create a ROS2 Package for Python

ROS2 Tutorials #5: How to create a ROS2 Package for Python

About

In this post, you will learn how to create a simple ROS2 package for Python. You don’t need a ROS2 installation for this as we will use the ROS Development Studio (ROSDS), an online platform that provides access to ROS (1 or 2) computers and other powerful ROS tools within a browser!

PS: If you have ROS2 installed locally on your machine, you can skip Step 1.

Step 1: Create a Project (ROSject) on ROSDS

Head to http://rosds.online and create a project with a similar configuration as the one shown below. You can change the details as you like, but please ensure you select “Ubuntu 18.04 + ROS2 Crystal” under “Configuration”.

Once done with that, open your ROSject. This might take a few moments, please be patient.

Step 2: Source the ROS2 workspace

Once the ROSject is open, head to the Tools menu and pick the Shell tool (if on your local PC just fire up a terminal) and run the following command to source the workspace:

user:~$ source /opt/ros/crystal/setup.bash
ROS_DISTRO was set to 'melodic' before. Please make sure that the environment does not mix paths from different distributions.
user:~$

If you get that ROS_DISTRO warning, just ignore it.

Step 3: Create a ROS2 Python package in your ROS2 workspace

The syntax for creating a ROS2 Python package is ros2 pkg create <package_name>.

In the same terminal as in Step 2, change to your ROS2 workspace src directory and create a package there:

user:~$ cd ros2_ws/src
user:~/ros2_ws/src$ ros2 pkg create ros2_demo_py
going to create a new package
package name: ros2_demo_py
destination directory: /home/user/ros2_ws/src
package format: 2
version: 0.0.0
description: TODO: Package description
maintainer: ['user <user@todo.todo>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
creating folder ./ros2_demo_py
creating ./ros2_demo_py/package.xml
creating source and include folder
creating folder ./ros2_demo_py/src
creating folder ./ros2_demo_py/include/ros2_demo_py
creating ./ros2_demo_py/CMakeLists.txt
user:~/ros2_ws/src$

Step 4: Delete CMakeLists.txt , create setup.py and setup.cfg and edit package.xml

Unlike ROS1, ROS2 Python packages don’t use CMakeList.txt, but a new setup.py file. Let’s create one here. In the Shell:

user:~/ros2_ws/src$ cd ros2_demo_py/
user:~/ros2_ws/src/ros2_demo_py$ rm CMakeLists.txt
user:~/ros2_ws/src/ros2_demo_py$ touch setup.py
user:~/ros2_ws/src/ros2_demo_py$ touch setup.cfg
user:~/ros2_ws/src/ros2_demo_py$

Fire up the IDE, locate the setup.py file and paste in the following code:

from setuptools import setup

package_name = 'ros2_demo_py'

setup(
    name=package_name,
    version='0.7.0',
    packages=[package_name],
    install_requires=['setuptools'],
    zip_safe=True,
    author='You',
    author_email='you@youremail.com',
    maintainer='YourFirstname Lastname',
    maintainer_email='your@youremail.com',
    keywords=['ROS'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='A simple ROS2 Python package',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'demo = ros2_demo_py.demo:main'
        ],
    },
)

Locate the setup.cfg file and paste in the following code:

[develop]
script-dir=$base/lib/ros2_demo_py
[install]
install-scripts=$base/lib/ros2_demo_py

Locate package.xml and replace the contents with this snippet:

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>ros2_demo_py</name>
  <version>0.7.3</version>
  <description>A simple ROS2 Python package</description>

  <maintainer email="sloretz@openrobotics.org">Shane Loretz</maintainer>
  <license>Apache License 2.0</license>

  <exec_depend>rclpy</exec_depend>
  <exec_depend>std_msgs</exec_depend>

  <!-- These test dependencies are optional
  Their purpose is to make sure that the code passes the linters -->
  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

Step 5: Create the Python code

In the Shell, run the following commands:

user:~/ros2_ws/src/ros2_demo_py$ mkdir ros2_demo_py && cd ros2_demo_py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ touch demo.py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ touch __init__.py
user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$

We created the __init__.py file so that the ros2_demo_py folder could be recognized as a python module directory.

Locate the demo.py file, open it in the IDE and paste in the following code:

# Copyright 2016 Open Source Robotics Foundation, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import rclpy
from rclpy.node import Node

from std_msgs.msg import String


class MinimalPublisher(Node):

    def __init__(self):
        super().__init__('minimal_publisher')
        self.publisher_ = self.create_publisher(String, 'topic')
        timer_period = 0.5  # seconds
        self.timer = self.create_timer(timer_period, self.timer_callback)
        self.i = 0

    def timer_callback(self):
        msg = String()
        msg.data = 'Hello World: %d' % self.i
        self.publisher_.publish(msg)
        self.get_logger().info('Publishing: "%s"' % msg.data)
        self.i += 1


def main(args=None):
    rclpy.init(args=args)

    minimal_publisher = MinimalPublisher()

    rclpy.spin(minimal_publisher)

    # Destroy the node explicitly
    # (optional - otherwise it will be done automatically
    # when the garbage collector destroys the node object)
    minimal_publisher.destroy_node()
    rclpy.shutdown()


if __name__ == '__main__':
    main()

Step 6: Compile the package and source the workspace

We have created all the files needed. Now let’s compile.

user:~/ros2_ws/src/ros2_demo_py/ros2_demo_py$ cd /home/user/ros2_ws/
user:~/ros2_ws$ colcon build --symlink-install

Starting >>> ros2_demo_py
Finished <<< ros2_demo_py [0.78s]

Summary: 1 package finished [0.90s]
user:~/ros2_ws$ source install/setup.bash # source the workspace
user:~/ros2_ws$

Step 7: Test-run the package

Here comes the moment of truth…will it run?

user:~/ros2_ws$ ros2 run ros2_demo_py demo
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...

Great, it ran! We’re done here!!

Extra 1: ROSject link

Get the ROSject containing all code used in the post in the following link: http://www.rosject.io/l/bd0cfbd/

Extra 2: Video

Prefer to watch a video demonstrating the steps above? We have one for you below!

Related Resources

Feedback

Did you like this post? Do you have questions about what is explained? Whatever the case, please leave a comment on the comments section below, so we can interact and learn from each other.

If you want to learn about other ROS topics, please let us know in the comments area and we will do a video or post about it ?

 

Code edited by Bayode Aderinola

[ROS in 5 mins] 037 – What is ROS PACKAGE PATH and how to use it?

[ROS in 5 mins] 037 – What is ROS PACKAGE PATH and how to use it?

Hello ROS Developers

Welcome to this new post about ROS. In today’s post, we are going to learn what is the ROS_PACKAGE_PATH variable and how it is used by the ROS ecosystem.

The commands used here can be executed in your own computer if you have ROS installed, but for simplicity, we are going to use Robot Ignite Academy.

Before we start, if you are new to ROS, I highly recommend you taking the following course:

Ok, let’s get started, shall we?

In a computer with ROS installed, we have many variables with the ROS_ prefix. If we run env | grep ROS , for example, we may have something like the output below:

ROS_ROOT=/opt/ros/kinetic/share/ros
ROS_PACKAGE_PATH=/home/user/catkin_ws/src:/home/simulations/public_sim_ws/src:/opt/ros/kinetic/share
ROS_MASTER_URI=http://localhost:11311
ROS_VERSION=1
ROSLISP_PACKAGE_DIRECTORIES=/home/user/catkin_ws/devel/share/common-lisp:/home/simulations/public_sim_ws/devel/share/common-lisp
ROS_DISTRO=kinetic
ROS_ETC_DIR=/opt/ros/kinetic/etc/ros

Among these variables we can find the one we are looking for: ROS_PACKAGE_PATH

This variable is used by ROS in order to find ROS Packages. To better understand this, let’s consider the command below, used to control robots using the keyboard:

roslaunch turtlebot_teleop keyboard_teleop.launch

The first parameter of the roslaunch  command is the package name, which in this case is turtlebot_teleop .

When we run the command exemplified above, in order to find the turtlebot_teleop  package, ROS will look for the ROS_PACKAGE_PATH variable.

If we run roscd turtlebot_teleop to enter on the that package, for instance, on Robot Ignite Academy the package is located at /home/simulations/public_sim_ws/src/all/turtlebot/turtlebot_teleop  as can be seen below:

user:~$ roscd turtlebot_teleop
user:/home/simulations/public_sim_ws/src/all/turtlebot/turtlebot_teleop$ pwd
/home/simulations/public_sim_ws/src/all/turtlebot/turtlebot_teleop

If you look carefully, you can notice that the turtlebot_telop package is on the “Public Simulations Workspace”, which is /home/simulations/public_sim_ws/src. Now, with a closer look at the ROS_PACKAGE_PATH variable, we can find that path on it:

ROS_PACKAGE_PATH=/home/user/catkin_ws/src:/home/simulations/public_sim_ws/src:/opt/ros/kinetic/share

So, the turtlebot_teleop package only was found because its workspace path is set on ROS_PACKAGE_PATH.

If we unset that variable and try to roscd on that package again, it is not going to work, as can be seen with the commands  unset ROS_PACKAGE_PATH and roscd turtlebot_teleop.

user:~$ cd
user:~$ unset ROS_PACKAGE_PATH
user:~$ roscd turtlebot_teleop
roscd: No such package/stack 'turtlebot_teleop'

Here we can see that ROS wasn’t able to find the package. If we look at the ROS_ prefixed environment variables again, we won’t find ROS_PACKAGE_PATH:

user:~$ env | grep ROS
ROS_ROOT=/opt/ros/kinetic/share/ros
ROS_MASTER_URI=http://localhost:11311
ROS_VERSION=1
ROSLISP_PACKAGE_DIRECTORIES=/home/user/catkin_ws/devel/share/common-lisp:/home/simulations/public_sim_ws/devel/share/common-lisp
ROS_DISTRO=kinetic
ROS_ETC_DIR=/opt/ros/kinetic/etc/ros

If we source our catkin_ws again with source ~/catkin_ws/devel/setup.bash, the variable will be exported and ROS  will be able to find the package again:

user:~$ source ~/catkin_ws/devel/setup.bash
user:~$ roscd turtlebot_teleop
user:/home/simulations/public_sim_ws/src/all/turtlebot/turtlebot_teleop$

Creating a package in an unexpected location

Now let’s go a bit further and create a package in a place that nobody would do it. We are going to create it in the /tmp folder, just to let you better understand the importance of ROS_PACKAGE_PATH.

We can use the cd /tmp/  and catkin_create_pkg tutorial_package  commands to achieve that:

user:~$ cd /tmp/
user:/tmp$ catkin_create_pkg tutorial_package
Created file tutorial_package/package.xml
Created file tutorial_package/CMakeLists.txt
Successfully created files in /tmp/tutorial_package. Please adjust the values in package.xml.

We can clearly see that the package was created in /tmp/tutorial_package, but if we try to navigate to it using roscd tutorial_package, ROS won’t be able to find it:

user:/tmp$ roscd tutorial_package
roscd: No such package/stack 'tutorial_package'

That happens because the /tmp folder is not on the ROS_PACKAGE_PATH variable. We can easily add it using the next command:

export ROS_PACKAGE_PATH=/tmp:$ROS_PACKAGE_PATH

Now if we check the value of the variable with env | grep ROS_P , we can find /tmp there:

user:/tmp$ export ROS_PACKAGE_PATH=/tmp:$ROS_PACKAGE_PATH
user:/tmp$ env | grep ROS_P
ROS_PACKAGE_PATH=/tmp:/home/user/catkin_ws/src:/home/simulations/public_sim_ws/src:/opt/ros/kinetic/share

If we try to enter our package with roscd tutorial_package again, ROS will find it:

user:/tmp$ roscd tutorial_package
user:/tmp/tutorial_package$ pwd
/tmp/tutorial_package

So easy to understand the ROS_PACKAGE_PATH variable, isn’t it?

Remember that we also have a video version of this post on YouTube:

I hope you liked the post (and the video), if that is the case, please consider subscribing to our channel on YouTube. Additionally, should you have any questions or suggestions, please leave your comment on the comments section of the video.

Keep pushing your ROS Learning.

[ROS In 5 Minutes] 002 – How to create a ROS Package

[ROS In 5 Minutes] 002 – How to create a ROS Package

Hi all,

welcome to this “ROS In 5 Minutes” videos series.

In today’s video, we are going to see how to create a ROS Package.

But before we start, if you want to Learn ROS Fast, we recommend you the following courses:

ROS In 5 Days (Python) 
ROS In 5 Days (C++)

Either you like the video or not, please leave a comment on the comments section below, so we can interact and learn from each other.

Step1. Create a project in Robot Ignite Academy(RIA)

We have the best online ROS course available in RIA. It helps you learn ROS in the easiest way without setting up ROS environment locally. The only thing you need is a browser! Create an account here and start to browse the trial course for free now! We’ll use the ROS Basics in 5 Days course as an example today.

Step2. Create a ROS Package

You can see the help about the catkin_create_pkg by passing the “-h” parameter: catkin_create_pkg -h

To create your package in the catkin_ws/src folder with the command catkin_create_pkg +package name +package dependencies. For example,

catkin_create_pkg tutorial rospy std_msgs

Here we create a package called tutorial with the dependencies rospy and std_msgs because we want to use the python api and std_msgs package.

After that, ROS will create a package for you. Inside the package, you’ll find the package.xml and CMakeLists.txt which will help you to compile the package.

You can compile them with the catkin_make command.

But sometimes when you create a package, ROS is not able to find it “instantly”. If this happens, just type source devel/setup.bash  to source the file.

Want to learn more?

If you are interested in this topic please visit our ROS In 5 Days (Python)  course. You’ll learn how to create workspace, package, topic, service, and action in this course.

 

Edit by: Tony Huang

Pin It on Pinterest