Ros Ros2
Ros Ros2
Aditya Nisal
June 30, 2023
Contents
1 Publisher 2
1.1 Publisher ROS1(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 Publisher ROS2(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Publisher ROS1(Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.4 Publisher ROS2(Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2 Subscriber 4
2.1 Subscriber ROS1(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.2 Subscriber ROS2(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.3 Subscriber ROS1(Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.4 Subscriber ROS2(Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
3 Service 6
3.1 Service ROS1(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.2 Service ROS2(Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.3 Service ROS1 (Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
3.4 Service ROS2 (Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4 Client 8
4.1 Client ROS1 (Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.2 Client ROS2 (Cpp) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
4.3 Client ROS1 (Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.4 Client ROS2 (Python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
5 CmakeList 11
5.1 ROS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
5.2 ROS2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
6 Package.xml 12
6.1 ROS1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
6.2 ROS2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
8 Common functions 14
8.1 Timer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.2 Client Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.3 Build system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.4 Included headers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.5 Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.6 Rate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
8.7 Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
10 ROS Bridge 17
11 References 18
1
1 Publisher
1.1 Publisher ROS1(Cpp)
ros::NodeHandle n; //Define a NodeHandle to interact with ROS
pub.publish(msg); //Publish the message to the specified topic. This is a call to the publish method.
Example
#include <ros/ros.h>
#include <std_msgs/String.h>
ros::Rate loop_rate(10);
std_msgs::String msg;
msg.data = "Hello ROS1";
while (ros::ok())
{
chatter_pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
auto pub = node->create publisher<std msgs::msg::String>("topic name", 10); //Declare a publisher ’pub’.
Example
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
rclcpp::Rate rate(2);
while (rclcpp::ok())
{
message.data = "Hello ROS2";
publisher->publish(message);
rclcpp::spin_some(node);
rate.sleep();
}
rclcpp::shutdown();
return 0;
}
Example
2
import rospy
from std_msgs.msg import String
def talker():
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()
if __name__ == ’__main__’:
try:
talker()
except rospy.ROSInterruptException:
pass
msg = String() msg.data = "Hello, ROS2!" pub.publish(msg) #Creating a message and publishing it to the topic
Example
import rclpy
from std_msgs.msg import String
def talker():
rclpy.init()
node = rclpy.create_node(’talker’)
pub = node.create_publisher(String, ’chatter’, 10)
msg = String()
i = 1
while rclpy.ok():
msg.data = "hello world %d" % i
node.get_logger().info(’Publishing: "%s"’ % msg.data)
pub.publish(msg)
rclpy.spin_once(node)
i += 1
if __name__ == ’__main__’:
try:
talker()
except rclpy.exceptions.ROSInterruptException:
pass
finally:
rclpy.shutdown()
3
2 Subscriber
2.1 Subscriber ROS1(Cpp)
void callback(const std msgs::String::ConstPtr& msg) //Define a callback function to be called when a new message is available on the ”topic name” topic
{
ROS INFO("Received: %s", msg->data.c str()); // Print the received message
}
ros::NodeHandle n; // Define a NodeHandle to interact with ROS
ros::Subscriber sub = n.subscribe("topic name", 1000, callback); // Declare a Subscriber, ’sub’. The subscribe() function is called on the NodeHandle ’n’.
// We subscribe to the ”topic name” topic, with the message queue size of 1000, and register the ’callback’ function to be called whenever a new message is available.
Example
#include "ros/ros.h"
#include "std_msgs/String.h"
ros::spin();
return 0;
}
Example
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>
private:
void topic_callback(const std_msgs::msg::String::SharedPtr msg) const
{
RCLCPP_INFO(this->get_logger(), "I heard: ’%s’", msg->data.c_str());
}
rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_;
};
rospy.Subscriber(’topic name’, String, callback) # Create a subscriber with the specified topic and message type, and specify the callback function
rospy.spin() # Spin (keep the node active) until the node is shutdown
Example
#!/usr/bin/env python
4
import rospy
rospy.init_node(’example_node’)
rate = rospy.Rate(10)
while not rospy.is_shutdown():
# Perform node’s functionality here
rospy.loginfo(’Hello, ROS1!’)
rate.sleep()
subscription = node.create subscription(String, ’topic name’, callback, 10) # Create a subscriber, and specify the callback function
rclpy.spin(node) # Spin (keep the node active) until the node is shutdown
node.destroy node()
rclpy.shutdown() # Clean up resources
Example
#!/usr/bin/env python
import rclpy
from std_msgs.msg import String
class ExampleNode(rclpy.Node):
def __init__(self):
super().__init__(’example_node’)
self.timer = self.create_timer(1.0, self.timer_callback)
def timer_callback(self):
msg = String()
msg.data = ’Hello, ROS2!’
self.publisher_.publish(msg)
def main(args=None):
rclpy.init(args=args)
node = ExampleNode()
rclpy.spin(node)
node.destroy_node()
rclpy.shutdown()
if __name__ == ’__main__’:
main()
5
3 Service
Services in ROS1 and ROS2 are similar in that they allow for synchronous Request/Response communication between nodes. However, the syntax and the organization
of the code have changed quite a bit.
return 0;
}
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"
private:
void handle_service(
const std::shared_ptr<rmw_request_id_t> request_header,
const std::shared_ptr<example_interfaces::srv::AddTwoInts::Request> request,
std::shared_ptr<example_interfaces::srv::AddTwoInts::Response> response)
{
(void)request_header;
RCLCPP_INFO(this->get_logger(), "Incoming request\na: %ld" " b: %ld", request->a, request->b);
response->sum = request->a + request->b;
}
rclcpp::Service<example_interfaces::srv::AddTwoInts>::SharedPtr service_;
};
#!/usr/bin/env python
# Import the required packages
import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsResponse
6
print("Returning [%s + %s = %s]"%(req.a, req.b, (req.a + req.b))) // Log the incoming request
return AddTwoIntsResponse(req.a + req.b) // Create and return a response
def add_two_ints_server():
rospy.init_node(’add_two_ints_server’) // Initialize a ROS node with the name ’add_two_ints_server’
# Create a service called ’add_two_ints’ that will call the ’handle_add_two_ints’ function whenever a request is received
s = rospy.Service(’add_two_ints’, AddTwoInts, handle_add_two_ints)
print("Ready to add two ints.") // Log that the service is ready
rospy.spin() // Keep the program from exiting until the service is shutdown
if __name__ == "__main__":
add_two_ints_server() // Call the server function
def __init__(self):
super().__init__(’add_two_ints_server’) # Initialize the Node with the name ’add_two_ints_server’
# Create a service called ’add_two_ints’ that will call the ’add_two_ints_callback’ function whenever a request is received
self.srv = self.create_service(AddTwoInts, ’add_two_ints’, self.add_two_ints_callback)
# Main function
def main(args=None):
rclpy.init(args=args) # Initialize RCLPY
7
4 Client
4.1 Client ROS1 (Cpp)
Example
return 0;
}
#include <memory>
8
if (rclcpp::spin_until_future_complete(node, result) == rclcpp::executor::FutureReturnCode::SUCCESS)
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "Sum: %ld", result.get()->sum);
else
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Failed to call service add_two_ints");
def usage():
return "%s [x y]"%sys.argv[0] # Return the correct usage of this script
if __name__ == "__main__":
if len(sys.argv) == 3: # If the correct number of arguments has been provided
x = int(sys.argv[1]) # Assign the first command-line argument to ’x’
y = int(sys.argv[2]) # Assign the second command-line argument to ’y’
else:
print(usage()) # Print a usage message
sys.exit(1)
print("Requesting %s+%s"%(x, y)) # Print a message showing what request is being made
print("%s + %s = %s"%(x, y, add_two_ints_client(x, y))) # Call the client function and print the result
def __init__(self):
super().__init__(’add_two_ints_client’) # Initialize the Node with the name ’add_two_ints_client’
# Create a client that can call the ’add_two_ints’ service
self.cli = self.create_client(AddTwoInts, ’add_two_ints’)
while not self.cli.wait_for_service(timeout_sec=1.0):
self.get_logger().info(’service not available, waiting again...’)
self.req = AddTwoInts.Request() # Create a request object
def send_request(self):
self.req.a = int(sys.argv[1]) # Assign the first command-line argument to ’a’ in the request
self.req.b = int(sys.argv[2]) # Assign the second command-line argument to ’b’ in the request
self.future = self.cli.call_async(self.req) # Send the request asynchronously
# Main function
def main(args=None):
rclpy.init(args=args) # Initialize RCLPY
9
add_two_ints_client.get_logger().info(
’Result of add_two_ints: for %d + %d = %d’ %
(add_two_ints_client.req.a, add_two_ints_client.req.b, response.sum))
break
# After the response has been received, destroy the node and shutdown rclpy
add_two_ints_client.destroy_node()
rclpy.shutdown()
10
5 CmakeList
5.1 ROS1
Example
CMakeList.txt:
cmake_minimum_required(VERSION 3.0.2)
project(my_pub_sub)
catkin_package()
include_directories(
${catkin_INCLUDE_DIRS}
)
add_executable(pub_node src/pub_node.cpp)
add_dependencies(pub_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(pub_node
${catkin_LIBRARIES}
)
add_executable(sub_node src/sub_node.cpp)
add_dependencies(sub_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(sub_node
${catkin_LIBRARIES}
)
5.2 ROS2
Example
CMakeList.txt:
cmake_minimum_required(VERSION 3.5)
project(my_pub_sub)
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 14)
endif()
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
add_executable(pub_node src/pub_node.cpp)
ament_target_dependencies(pub_node rclcpp std_msgs)
add_executable(sub_node src/sub_node.cpp)
ament_target_dependencies(sub_node rclcpp std_msgs)
install(TARGETS
pub_node
sub_node
DESTINATION lib/${PROJECT_NAME})
ament_package()
11
6 Package.xml
6.1 ROS1
Example
package.xml:
<?xml version="1.0"?>
<package format="2">
<name>my_pub_sub</name>
<version>0.0.1</version>
<description>A simple ROS1 pub/sub package.</description>
<license>TODO</license>
<buildtool_depend>catkin</buildtool_depend>
<build_depend>roscpp</build_depend>
<build_depend>std_msgs</build_depend>
<exec_depend>roscpp</exec_depend>
<exec_depend>std_msgs</exec_depend>
</package>
6.2 ROS2
Example
package.xml:
<?xml version="1.0"?>
<package format="3">
<name>my_pub_sub</name>
<version>0.0.1</version>
<description>A simple ROS2 pub/sub package.</description>
<maintainer email="[email protected]">Your Name</maintainer>
<license>TODO</license>
<buildtool_depend>ament_cmake</buildtool_depend>
<depend>rclcpp</depend>
<depend>std_msgs</depend>
<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>
<export>
<build_type>ament_cmake</build_type>
</export>
</package>
12
7 Setup.py (Only ROS2)
ROS2 uses setup.py and package.xml for python packages while the ROS1 uses CMakeList.txt and package.xml just like the normal cpp packages.
Usually after building the package, you just need to add the package name, node name and the executable name.
Example
setup.py
from setuptools import setup
package_name = ’my_package’
setup(
name=package_name,
version=’0.0.1’,
packages=[package_name],
data_files=[
(’share/ament_index/resource_index/packages’,
[’resource/’ + package_name]),
(’share/’ + package_name, [’package.xml’]),
],
install_requires=[’setuptools’],
zip_safe=True,
author=’Your Name’,
author_email=’[email protected]’,
maintainer=’Your Name’,
maintainer_email=’[email protected]’,
keywords=[’ROS’],
classifiers=[
’Intended Audience :: Developers’,
’License :: OSI Approved :: Apache Software License’,
’Programming Language :: Python’,
’Programming Language :: Python :: 3’,
’Programming Language :: Python :: 3.5’,
’Programming Language :: Python :: 3.6’,
],
description=’ROS2 Python package.’,
license=’Apache License, Version 2.0’,
tests_require=[’pytest’],
entry_points={
’console_scripts’: [
’talker = my_package.talker:main’,
’listener = my_package.listener:main’,
],
},
)
13
8 Common functions
8.1 Timer
ROS1
ros::Timer timer = nh.createTimer(ros::Duration(1.0), timerCallback); # Declaring the timer (usually in the constructor)
ROS2
auto timer = node->create wall timer(std::chrono::seconds(1), timerCallback); # Defining the timer (usually in the constructor)
ROS2
CPP: rclcpp
Python: rclpy
ROS2
ament build system is used.
"colcon build" - Command to build the package and workspace.
ROS2
include <geometry msgs/msg/point stamped.hpp>
geometry msgs::msg::PointStamped point stamped;
.hpp is the preferred extension of the header files(.hpp is only for c++ and .h is for both C and C++)
PointStamped - point stamped.
::msg:: used in between the package and the message.
Similarly for srv, ::srv:: is used.
8.5 Time
ROS1
ros::Time
ROS2
rclcpp::Time
rclpy.time.Time
8.6 Rate
ROS1
"ros::Rate"
ROS2
"rclcpp::Rate"
8.7 Parameters
ROS1
"rosparam" Command line tool is used.
ROS2
Parameters are integrated in the rclcpp and rclpy libraries. You can add them in the constructor while writing the node.
CPP Example:
this->declare_parameter("catch_closest_turtle_first", true);
catch_closest_turtle_first_ = this->get_parameter("catch_closest_turtle_first").as_bool();
14
9 Command Line tools
9.1 Topic command line tools
ROS1
"rostopic <command>"
ROS2
"ros2 topic <command>"
<launch>
15
<arg name="my_arg" value="my_value" />
</include>
</launch>
ROS2
• Launch file in ROS2 uses Python based syntax.
• Command line command: "ros2 launch package name file.launch.py"
• Although we have added parameters to the lakunch files in the below example, generally they are stored in the YAML files and then loaded to the launch file.
• Example of launch file that loads the parameters from YAML file: /my package/params.yaml:
my turtle: # Node name
ros parameters: # Declare parameters here
background r: 150
background g: 150
background b: 200
launch.py:
def generate_launch_description():
params = get_package_share_directory(’my_package’) + ’/params.yaml’
return LaunchDescription([
Node(
package=’turtlesim’,
executable=’turtlesim_node’,
name=’my_turtle’,
parameters=[params]
)
])
Example
def generate_launch_description():
ld = LaunchDescription()
talker_node = Node(
package=’beginner_tutorials’,
executable=’talker’,
name=’talker’
)
ld.add_action(talker_node)
listener_node = Node(
package=’beginner_tutorials’,
executable=’listener’,
name=’listener’
)
ld.add_action(listener_node)
return ld
16
10 ROS Bridge
• ROS Bridge facilitates communication between ROS1 and ROS2 nodes. This tool was essentially developed to ensure a smooth transition and prevent disruption
for users currently utilizing the ROS1 framework. Thus, even when a ROS1 node is converted to ROS2, it can still interface with the existing ROS1 node provided
that the bridge is enabled.
• However, it’s important to note that the bridge is primarily intended to prevent inconveniences during the transition from ROS1 to ROS2. It’s certainly advisable
to fully transition to the ROS2 framework, given that support for ROS1 is projected to end in 2025. After this date, maintaining the ROS1 framework will fall
solely on the company using it.
• In summary, the ROS bridge allows ROS1 nodes to communicate with ROS2 nodes during the conversion process. However, long-term dependence on the ROS
bridge isn’t recommended. A complete transformation from ROS1 to ROS2 is the advised course of action.
• Click here to get more info on ros1 bridge
6. Open a third terminal and source both ROS1 and ROS2 in this terminal by running:
source /opt/ros/<ros1 distro>/setup.bash
source /opt/ros/<ros2 distro>/setup.bash
7. Now, in this terminal run the dynamic bridge: ros2 run ros1 bridge dynamic bridge
8. At this point, if both your ROS1 and ROS2 nodes are using the same topic names and message types, they should be able to communicate.
9. If your case is a bit complex, e.g., custom message types, you will need to build the bridge with those message types present. Refer to the ros1 bridge package
and documentation for details.
10. Remember to replace ros1 distro and ros2 distro with the actual ROS distributions you are using, like noetic for ROS1 and foxy for ROS2, for example. Also
note that ROS1 nodes must be running when you start the dynamic bridge. The bridge doesn’t know about ROS1 nodes and topics that were started after it.
17
11 References
References
[1] Ros2 foxy documentation
[2] Ros documentation
[3] Ros1 bridge
18