ROS Duration (roscpy and roscpp)

In this tutorial I’ll show you how to use ROS Duration in your ROS code – for roscpp and rospy.

Through several examples you’ll see some of the most common use cases where ROS Duration is useful. Also, for each example you’ll learn about the differences between the Python and Cpp implementation, which is sometimes quite tricky.

So, first of all, what is a ROS Duration?

A Duration is a class – rospy.Duration for Python and ros::Duration for Cpp. You can use it to monitor a time difference, create timers, rates, and so on.

To create a rospy.Duration of 2.5 seconds in Python:

duration = rospy.Duration(2.5)

And the same with ros::Duration in Cpp:

ros::Duration duration = ros::Duration(2.5);

Alright, let’s now see how to use a Duration with some examples!

Sleep with ROS Duration

In Python and Cpp you already have sleep functionalities: time.sleep() and std::this_thread::sleep_for(). However it’s strongly recommended to use the ROS sleep functionality if you want to do that in a ROS node.

rospy

rospy.sleep(2) # 2.0 seconds
# same as:
rospy.sleep(rospy.Duration(2))

The sleep() function from rospy takes a Duration as a parameter. As a shortcut you can directly give the duration in seconds, and it will cast it as a rospy.Duration for you.

roscpp

ros::Duration(2).sleep();

Differences

With rospy you have to use the rospy.sleep() function and give a Duration to it (or directly a float number), while with roscpp, the sleep() function is in fact a method of the ros::Duration class.

Print a ROS Duration

Let’s see what are the different ways to print a Duration.

rospy

duration = rospy.Duration(2.5)
rospy.loginfo("Duration seconds: " + str(duration.secs) + ", and nanoseconds: " + str(duration.nsecs))
rospy.loginfo("Duration in seconds: " + str(duration.to_sec()))
rospy.loginfo("Duration in nanoseconds: " + str(duration.to_nsec()))

A ROS Duration object is storing seconds and nanoseconds separately. First we print those 2 members.

Then we can also use 2 functions – to_sec() and to_nsec() – to directly convert a Duration into a number of seconds (float number), or a number of nanoseconds.

roscpp

ros::Duration duration = ros::Duration(2.5);
ROS_INFO("Duration seconds: %d, and nanoseconds: %d", duration.sec, duration.nsec);
ROS_INFO("Duration in seconds: %lf", duration.toSec());
ROS_INFO("Duration in nanoseconds: %lf", (double)duration.toNSec());

Code result

[INFO] [1563212541.837784]: Duration seconds: 2, and nanoseconds: 500000000
[INFO] [1563212541.840514]: Duration in seconds: 2.5
[INFO] [1563212541.841976]: Duration in nanoseconds: 2500000000

Differences

Pay attention to the Duration class attribute names! In Python, to get seconds and nanoseconds values you have to use “secs” and “nsecs”, while in Cpp it’s “sec” and “nsec”. The plurality is not the same between the Python and Cpp version.

While the plurality for the methods to convert in seconds and nanoseconds is the same here, pay attention to the case of the methods (snake_case vs camelCase).

Monitor time difference with ROS Duration

In this example we’ll make the program sleep for 1.5 seconds, and we’ll save the time before and after the sleep, so we can monitor the total duration.

rospy

time_begin = rospy.Time.now()
rospy.sleep(rospy.Duration(1.5))
time_end = rospy.Time.now()
duration = time_end - time_begin
rospy.loginfo("Slept for " + str(duration.to_sec()) + " secs")

As you can see we can create a rospy Duration object from additionning/substracting multiple ROS Time instances.

roscpp

// Init node and NodeHandle

ros::Time time_begin = ros::Time::now();
ros::Duration(1.5).sleep();
ros::Time time_end = ros::Time::now();
ros::Duration duration = time_end - time_begin;
ROS_INFO("Slept for %lf secs", duration.toSec());

Don’t forget to create a ros::NodeHandle (ros::NodeHandle nh;) before you use the Time functionality, or else you’ll get an error during compilation. As a general rule, create a ros::NodeHandle the line after you initialize your node, so you’ll avoid problems in the future.

Code result

For Python:

[INFO] [1563212617.051945]: Slept for 1.501725912 secs

For Cpp:

[ INFO] [1563213613.017092247]: Slept for 1.500124 secs

Differences

There is no special difference in the code here. For both Python and Cpp you can create a ROS Duration by combining multiple ROS Time objects.

The only difference I pointed here is about the execution of the code. As you can see, the Cpp code is much faster than the Python code in this example, by a factor of about 10. While this is not an implementation difference, this is a reminder for you about the execution speed. Usually, using Python with ROS will be fine, but sometimes for performance issues you’ll have to use Cpp.

ROS Timer with ROS Duration

rospy

def timer_callback(event):
    rospy.loginfo("In timer callback")

rospy.Timer(rospy.Duration(1), timer_callback)
rospy.spin() # don't forget to spin or else your node will exit

The Duration you give to the ROS Timer is the period of the timer. If you prefer to use a frequency, you’ll have to invert the frequency value: rospy.Duration(1.0/frequency).

For more info on using ROS Timers with Python, check out this rospy Timer tutorial.

roscpp

void timer_callback(const ros::TimerEvent &event)
{
    ROS_INFO("In timer callback");
}

int main(int argc, char **argv)
{ 
    // Init node and NodeHandle

    ros::Timer timer = nh.createTimer(ros::Duration(1.0), timer_callback);
    ros::spin();
}

For more info on using ROS Timers with Cpp, check out this roscpp Timer tutorial.

Code result

[INFO] [1563212693.284795]: In timer callback
[INFO] [1563212694.284683]: In timer callback
[INFO] [1563212695.284442]: In timer callback
[INFO] [1563212696.284409]: In timer callback

Differences

For Python, the Timer is directly a class from rospy. While in Cpp you create a Timer by calling the createTimer() function of the ros::NodeHandle you created before.

Publish on a topic with std_msgs Duration message

rospy

import rospy
from std_msgs.msg import Duration

rospy.init_node("test_duration")
duration = rospy.Duration(1.5)
rate = rospy.Rate(duration.to_sec())
duration_publisher = rospy.Publisher("/duration", Duration, queue_size=10)
while not rospy.is_shutdown():
    duration_publisher.publish(duration)
    rate.sleep()

You can create a ROS Rate by directly giving a ROS Duration to it. For more info on using ROS Rates with Python, check out this ROS Rate tutorial.

This code example is quite classic and basic. The only specificity is that we use a std_msgs/Duration message to publish on the ROS topic.

roscpp

First you’ll have to add #include <std_msgs/Duration.h> at the top of your Cpp file.

// Init node and NodeHandle

ros::Duration duration = ros::Duration(1.5);
ros::Rate rate(duration);
ros::Publisher duration_publisher = nh.advertise<std_msgs::Duration>("/duration", 10);

while (ros::ok())
{
    std_msgs::Duration msg;
    msg.data = duration;
    duration_publisher.publish(msg);
    rate.sleep();
}

Code result

The program won’t print anything. Start another terminal and check the /duration topic.

$ rostopic echo /duration 
data: 
  secs: 1
  nsecs: 500000000
---
data: 
  secs: 1
  nsecs: 500000000
---

Differences

There is no special difference here, apart from the differences on how to create a ROS publisher in Python and Cpp.

Conclusion on ROS Duration

Through some example you saw how to use a ROS Duration to accomplish multiple goals.

You will often meet those use cases when developing with ROS, so make sure you bookmark this page!

There are also some subtle differences between rospy Duration and roscpp Duration, pay attention to them when developing in Python or Cpp.

Leave a Comment