You are on page 1of 18

ROS to ROS2 Migration Guide

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

7 Setup.py (Only ROS2) 13

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

9 Command Line tools 15


9.1 Topic command line tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
9.2 Service command line tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
9.3 Launch files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

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

ros::Publisher pub = n.advertise<std msgs::String>("topic name", 1000); //Declare a Publisher, ’pub’.

std msgs::String msg; //Instantiate a std msgs::String object

msg.data = "Hello, ROS1!"; //Populate the data field of the message

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>

int main(int argc, char **argv)


{
ros::init(argc, argv, "talker");
ros::NodeHandle nh;

ros::Publisher chatter_pub = nh.advertise<std_msgs::String>("topic", 1000);

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;
}

1.2 Publisher ROS2(Cpp)


rclcpp::Node::SharedPtr node = rclcpp::Node::make shared("node name"); //Declare a shared pointer to a Node

auto pub = node->create publisher<std msgs::msg::String>("topic name", 10); //Declare a publisher ’pub’.

std msgs::msg::String msg; //Instantiate a std msgs::msg::String object

msg.data = "Hello, ROS2!"; //Populate the data field of the message

pub->publish(msg); //Publish the message to the specified topic.

Example
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>

int main(int argc, char **argv)


{
rclcpp::init(argc, argv);

auto node = rclcpp::Node::make_shared("talker");


auto publisher = node->create_publisher<std_msgs::msg::String>("topic", 10);

rclcpp::Rate rate(2);

auto message = std_msgs::msg::String();

while (rclcpp::ok())
{
message.data = "Hello ROS2";
publisher->publish(message);
rclcpp::spin_some(node);
rate.sleep();
}

rclcpp::shutdown();
return 0;
}

1.3 Publisher ROS1(Python)


pub = rospy.Publisher(’topic name’, String, queue size=1000) # Creating a publisher with topic name and message type
rospy.init node(’publisher node’, anonymous=True) # Initializing the ROS node
msg = String()
msg.data = "Hello, ROS1!"
pub.publish(msg) #Creating a message and publishing it to the topic

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

1.4 Publisher ROS2(Python)


node = rclpy.create node(’publisher node’) pub = node.create publisher(String, ’topic name’, 1000) #Creating a node and publisher

rclpy.init() #Initializing the ROS2 runtime

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"

void chatterCallback(const std_msgs::String::ConstPtr& msg)


{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}

int main(int argc, char **argv)


{
ros::init(argc, argv, "listener");
ros::NodeHandle nh;

ros::Subscriber sub = nh.subscribe("topic", 1000, chatterCallback);

ros::spin();

return 0;
}

2.2 Subscriber ROS2(Cpp)


void callback(const std msgs::msg::String::SharedPtr msg) // Define a callback function to be called when a new message is available on the ”topic name”
topic
{
RCLCPP INFO(rclcpp::get logger("rclcpp"), "Received: ’%s’", msg->data.c str()) // Print the received message
}
rclcpp::Node::SharedPtr node = rclcpp::Node::make shared("node name"); // Declare a shared pointer to a Node
auto sub = node->create subscription<std msgs::msg::String>("topic name", 10, callback); // Declare a Subscriber, ’sub’. The create subscription()
function is called on the Node. // We subscribe to the ”topic name” topic, with the message queue size of 10, and register the ’callback’ function to be called whenever
a new message is available.

Example
#include <rclcpp/rclcpp.hpp>
#include <std_msgs/msg/string.hpp>

class MinimalSubscriber : public rclcpp::Node


{
public:
MinimalSubscriber()
: Node("minimal_subscriber")
{
subscription_ = this->create_subscription<std_msgs::msg::String>(
"topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, std::placeholders::_1));
}

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_;
};

int main(int argc, char * argv[])


{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<MinimalSubscriber>());
rclcpp::shutdown();
return 0;
}

2.3 Subscriber ROS1(Python)


def callback(msg):
rospy.loginfo("Received: %s", msg.data) #Define a callback function to handle received messages

rospy.init node(’subscriber node’) # Initialize the ROS node

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()

2.4 Subscriber ROS2(Python)


def callback(msg): print("Received:", msg.data) # Define a callback function to handle received messages

rclpy.init() # Initialize the ROS node

node = rclpy.create node(’subscriber node’) # Create a node

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.

3.1 Service ROS1(Cpp)


Example
// ROS header for service messages related to "AddTwoInts"
#include "beginner_tutorials/AddTwoInts.h"

// Standard ROS header


#include "ros/ros.h"

// Definition of the service callback


bool add(beginner_tutorials::AddTwoInts::Request &req,
beginner_tutorials::AddTwoInts::Response &res)
{
res.sum = req.a + req.b; // Perform the addition operation
ROS_INFO("request: x=%ld, y=%ld", (long int)req.a, (long int)req.b); // Log the request
ROS_INFO("sending back response: [%ld]", (long int)res.sum); // Log the response
return true;
}

int main(int argc, char **argv)


{
ros::init(argc, argv, "add_two_ints_server"); // Initialize the ROS node
ros::NodeHandle n; // Create a handle to this process’ node

// Create the service and advertise it over ROS


ros::ServiceServer service = n.advertiseService("add_two_ints", add);
ROS_INFO("Ready to add two ints."); // Log ready status
ros::spin(); // Keep the program alive until it’s killed or until Ctrl-C is pressed

return 0;
}

3.2 Service ROS2(Cpp)


Example

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

class AddTwoIntsServer : public rclcpp::Node


{
public:
AddTwoIntsServer() : Node("add_two_ints_server")
{
service_ = this->create_service<example_interfaces::srv::AddTwoInts>(
"add_two_ints",
std::bind(&AddTwoIntsServer::handle_service, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}

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_;
};

int main(int argc, char ** argv)


{
rclcpp::init(argc, argv);
auto server = std::make_shared<AddTwoIntsServer>();
rclcpp::spin(server);
rclcpp::shutdown();
return 0;
}

3.3 Service ROS1 (Python)


Example

#!/usr/bin/env python
# Import the required packages
import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsResponse

# Define a function that processes requests and sends responses


def handle_add_two_ints(req):

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

3.4 Service ROS2 (Python)


Example

# Import the required packages


from example_interfaces.srv import AddTwoInts
import rclpy
from rclpy.node import Node

# Define a class that inherits from Node


class AddTwoIntsServer(Node):

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)

# Define the callback for the service


def add_two_ints_callback(self, request, response):
# The callback simply adds two integers together and returns the result
response.sum = request.a + request.b
self.get_logger().info(’Incoming request\na: %d b: %d’ % (request.a, request.b))
return response # Return the response to the client

# Main function
def main(args=None):
rclpy.init(args=args) # Initialize RCLPY

# Create an instance of the service


add_two_ints_server = AddTwoIntsServer()

# Spin the node so it can service requests from clients


rclpy.spin(add_two_ints_server)

# After spinning, destroy the node and shutdown rclpy


add_two_ints_server.destroy_node()
rclpy.shutdown()

# Check if the script is executed directly


if __name__ == ’__main__’:
main() # Call the main function

7
4 Client
4.1 Client ROS1 (Cpp)
Example

// ROS header for service messages related to "AddTwoInts"


#include "beginner_tutorials/AddTwoInts.h"

// Standard ROS headers


#include "ros/ros.h"
#include "ros/service_client.h"

#include <cstdlib> // For access to the "atoll" function

int main(int argc, char **argv)


{
ros::init(argc, argv, "add_two_ints_client"); // Initialize the ROS node

// Ensure the service client is being used correctly


if (argc != 3)
{
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}

ros::NodeHandle n; // Create a handle to this process’ node


ros::ServiceClient client = n.serviceClient<beginner_tutorials::AddTwoInts>("add_two_ints"); // Create a client for the "add_two_ints" service

beginner_tutorials::AddTwoInts srv; // Create a service object

// Set the service request values based on command line arguments


srv.request.a = atoll(argv[1]);
srv.request.b = atoll(argv[2]);

// Call the service and check if it was successful


if (client.call(srv))
{
ROS_INFO("Sum: %ld", (long int)srv.response.sum); // If successful, log the result
}
else
{
ROS_ERROR("Failed to call service add_two_ints"); // If not successful, log an error message
return 1;
}

return 0;
}

4.2 Client ROS2 (Cpp)


Example
// Import the required headers
#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/srv/add_two_ints.hpp"

#include <memory>

int main(int argc, char **argv)


{
rclcpp::init(argc, argv); // Initialize RCLCPP

if (argc != 3) { // If the number of command-line arguments is not 3


RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "usage: add_two_ints_client X Y"); // Print a usage message
return 1;
}

std::shared_ptr<rclcpp::Node> node = rclcpp::Node::make_shared("add_two_ints_client"); // Create a new Node


rclcpp::Client<example_interfaces::srv::AddTwoInts>::SharedPtr client = // Create a client
node->create_client<example_interfaces::srv::AddTwoInts>("add_two_ints");

auto request = std::make_shared<example_interfaces::srv::AddTwoInts::Request>(); // Create a request


request->a = atoll(argv[1]); // Assign the first command-line argument to ’a’ in the request
request->b = atoll(argv[2]); // Assign the second command-line argument to ’b’ in the request

// Wait for the service to be available before making a request


while (!client->wait_for_service(std::chrono::seconds(1))) {
if (!rclcpp::ok()) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "client interrupted while waiting for service to appear.");
return 1;
}
RCLCPP_INFO(rclcpp::get_logger("rclcpp"), "waiting for service to appear...");
}

// Make a request to add the two integers


auto result = client->async_send_request(request);
// Wait for the result

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");

rclcpp::shutdown(); // Shutdown RCLCPP


return 0;
}

4.3 Client ROS1 (Python)


Example
#!/usr/bin/env python
# Import necessary packages
import sys
import rospy
from rospy_tutorials.srv import AddTwoInts, AddTwoIntsRequest

def add_two_ints_client(x, y):


rospy.wait_for_service(’add_two_ints’) # Wait until the ’add_two_ints’ service becomes available
try:
# Create a handle to the add_two_ints service
add_two_ints = rospy.ServiceProxy(’add_two_ints’, AddTwoInts)
# Use the handle like a function and call it, providing the two numbers to add.
resp1 = add_two_ints(x, y)
return resp1.sum # Return the response from the service
except rospy.ServiceException as e: # Catch any exceptions that are raised
print("Service call failed: %s"%e)

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

4.4 Client ROS2 (Python)


Example
# Import the required packages
import sys
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

# Define a class that inherits from Node


class AddTwoIntsClient(Node):

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

# Create an instance of the client


add_two_ints_client = AddTwoIntsClient()
add_two_ints_client.send_request() # Send the request

# Keep spinning until the response has been received


while rclpy.ok():
rclpy.spin_once(add_two_ints_client)
if add_two_ints_client.future.done():
try:
response = add_two_ints_client.future.result()
except Exception as e:
add_two_ints_client.get_logger().info(
’Service call failed %r’ % (e,))
else:

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()

# Check if the script is executed directly


if __name__ == ’__main__’:
main() # Call the main function

10
5 CmakeList
5.1 ROS1
Example
CMakeList.txt:

cmake_minimum_required(VERSION 3.0.2)
project(my_pub_sub)

find_package(catkin REQUIRED COMPONENTS


roscpp
std_msgs
)

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>

<maintainer email="youremail@something.com">Your Name</maintainer>

<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="youremail@something.com">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=’your.email@example.com’,
maintainer=’Your Name’,
maintainer_email=’your.email@example.com’,
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)

ros::Timer timer ; # Declaring the timer in the class

ROS2
auto timer = node->create wall timer(std::chrono::seconds(1), timerCallback); # Defining the timer (usually in the constructor)

rclcpp::TimerBase::SharedPtr timer ; # Declaring it in the class

8.2 Client Libraries


ROS1
CPP: roscpp
Python: rospy

ROS2
CPP: rclcpp
Python: rclpy

8.3 Build system


ROS1
catkin build system is used.
"catkin make" - Command to build the package and workspace.

ROS2
ament build system is used.
"colcon build" - Command to build the package and workspace.

8.4 Included headers


ROS1
include <geometry msgs/PointStamped.h>
geometry msgs::PointStamped point stamped;

.h files are used.


No msg or srv added between the messages and services.

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>"

"rostopic bw" display bandwidth used by topic


"rostopic delay" display delay for topic which has header
"rostopic echo" print messages to screen
"rostopic find" find topics by type
"rostopic hz" display publishing rate of topic
"rostopic info" print information about active topic
"rostopic list" print information about active topics
"rostopic pub" publish data to topic
"rostopic type" print topic type

ROS2
"ros2 topic <command>"

"rostopic bw" display bandwidth used by topic


"ros2 topic delay" display delay for topic which has header
"ros2 topic echo" print messages to screen
"ros2 topic find" find topics by type
"ros2 topic hz" display publishing rate of topic
"ros2 topic info" print information about active topic
"ros2 topic list" print list of active topics
"ros2 topic pub" publish data to topic
"ros2 topic type" print topic type

9.2 Service command line tools


ROS1 "rosservice <command>"
"rosservice call /service name" call the service
"rosservice call /service name service-arg" call the service with the provided args
"rosservice find" find services by service type
"rosservice info" print information about service
"rosservice list" list active services
"rosservice list -n" include the name of the node that implements the service
"rosservice type /service name" print service type
"rosservice uri" print service ROSRPC uri
"rosservice args /service name" print the arguments to a service
"rosservice node /service name" display the name of the node that provides a particular service
"rossrv show rosservice type /service name" show the srv file that defines a service

ROS2 "ros2 service <command>"


"ros2 service call /service name service type" call the service
"ros2 service call /service name service type ’service arg’" call the service with the provided args
"ros2 service find" find services by service type
"ros2 service info" print information about service
"ros2 service list" list active services
"ros2 node info /node name" to see service sprovided by specif node. The ROS2 equivalent of the ROS1 command is not supported
"ros2 service type /service name" print service type
uri feature not directly supported in ROS2
"ros2 interface show service type" pshow the input and output types of the service. ROS1 equivalent not supported
"ros2 service info /service name" display the name of the node that provides a particular service
"ros2 interface show rosservice type /service name" show the srv file that defines a service

9.3 Launch files


ROS1

• Launch file in ROS1 uses XML based syntax.


• Command line command: "roslaunch package name file.launch"
• Remapping: roslaunch package name launch file.launch <remap arguments>
<remap from="original topic" to="remapped topic" />

• Arguments: <arg> tag is used.


• Paramteres are set directly through the <param> tags.
Example

<launch>

<!-- Node 1 -->


<node pkg="my_package" type="my_node_type1" name="node1">
<param name="rate" value="10" />
</node>

<!-- Node 2 -->


<node pkg="my_package" type="my_node_type2" name="node2">
<param name="rate" value="5" />
</node>

<!-- Include another launch file -->


<include file="$(find my_package)/launch/another_launch_file.launch">

15
<arg name="my_arg" value="my_value" />
</include>

</launch>

Command line command


"roslaunch beginner tutorials sample.launch"

ROS2
• Launch file in ROS2 uses Python based syntax.
• Command line command: "ros2 launch package name file.launch.py"

• Remapping: ros2 launch package name launch file.launch <remap arguments>


<remap from="original topic" to="remapped topic" />
Remapping can also be done through the launch file by adding a ”remapping” in the node.
• Arguments: Use the ’DeclareLaunchArgument’ and ’LaunchConfiguration’ class.

• 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:

from launch import LaunchDescription


from launch_ros.actions import Node
from ament_index_python.packages import get_package_share_directory

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

from launch import LaunchDescription


from launch_ros.actions import Node

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

Command line command


"ros2 launch beginner tutorials sample launch.py"

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

Simple example for the bridge:


1. Open a new terminal.

2. SSource ROS1 by running: source /opt/ros/<ros1 distro>/setup.bash


3. Start your ROS1 nodes in this terminal. You may need to run roscore first if it’s not already running.
4. Open a new terminal and source ROS2 by running: source /opt/ros/<ros2 distro>/setup.bash
5. Start your ROS2 nodes in this terminal.

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

[4] ROS migration guide


[5] ROS migration guide The-Robotics-Backend
[6] Migration tools - Amazon

18

You might also like