ROS Publishers using Python
It is often considered that writing a publisher in Robot Operating Systems (ROS) is far easier than working with the subscriber. On most accounts, this is true, given that publishing is a minimalist task – We only feed values to the robot or robot in simulation. To be quite frank, that is the extent to which publishers in ROS work. In fact, some professionals would even state that it is analogous to a print( ) or display function!
ROS Publishers
Since robots primarily intend to automate what humans would otherwise do, we will draw parallels between simple man-made paraphernalia, and the robot’s construction to build perspective. Therefore, it is crucial that the reader understands what ROS nodes and ROS topics are. Here’s a quick recap of nodes and topics in ROS.
A ROS node is a computational process which runs as a program in a package. Since we can have several nodes running concurrently, nodes are analogous to human organs, wherein each organ (node) performs a dedicated task for the entire human (robot) to function in the desired manner.
If you wish to establish which nodes are presently active in your package, simply execute the following commands.
# only if the master node is not running
$ roscore
# to list all active nodes
$ rosnode list
# to obtain info on a specific node
$ rosnode info /<node_name>
Another alternative would be to use rqt graphs to display the tree diagram to understand the flow of data between nodes.
A ROS topic is essentially a named bus over which nodes exchange messages. They may be thought of as radio channels on which information is sent and received. Note that every topic has a unique format of data being exchanged.
The idea of Publishing information arises from the question of how to direct a robot to do something since we are controlling it. Note that we will maintain communication with the topics individually: we write publishers for specific topics and not the whole robot as such.
We publish data to the robot. Subscribing to data works the other way around. Both are done via topics.
Now that some clarity on the notion of publishers has been provided, we shall look at a simple template for writing publishers in Python.
Template
Python
import rospy
from std_msgs.msg import String
def publisher():
pub = rospy.Publisher( '/<topic_name>' ,
String, queue_size = 10 )
rospy.init_node( '<node_name>' , anonymous = True )
rate = rospy.Rate( 10 )
while not rospy.is_shutdown():
data = "The data that you wish to publish."
rospy.loginfo(data)
pub.publish(data)
rate.sleep()
if __name__ = = '__main__' :
try :
publisher()
except rospy.ROSInterruptException:
pass
|
Explanation
- Code execution begins from the try and except clause. The publisher function is called from here.
- Define the publisher function:
- the first field indicates the name of the topic to which you wish to publish the data. For example, /odom or /rosout.
- the second field indicates the type of data being published. String, Float32 or Twist are a few examples.
- the last field declares the limit of number of messages that may be queued to the topic.
- We follow this with node initialization.
- The rest of the template is self-explanatory (refer to the comments in the code).
Example
This example implements a code for publishing data to the /rosout topic. While there is a much easier way of doing this (using rostopic echo), it serves as an easily comprehensible demonstration.
The goal is to publish data to the /cmd_vel (command velocity) topic and therefore increase the speed of the bot. As a result of the while loop as shown in the template, we will notice an acceleration in the robot.
Python
import rospy
from geometry_msgs.msg import Twist
def increase(Twist):
print ( 'We are in the callback function!' )
velo_msg = Twist
rate = rospy.Rate( 5 )
speed = float ( input ('By how much would \
you like to accelerate? '))
while not rospy.is_shutdown():
velo_msg.linear.x = (Twist.linear.x) + speed
pub.publish(velo_msg)
print ( 'Publishing was successful!' )
rate.sleep()
def main():
print ( "In main..." )
rospy.init_node( 'Velocity_publisher' , anonymous = True )
sub = rospy.Subscriber( '/cmd_vel' , Twist, increase)
rospy.spin()
if __name__ = = '__main__' :
try :
pub = rospy.Publisher( '/cmd_vel' , Twist, queue_size = 10 )
main()
except rospy.ROSInterruptException:
pass
|
Code Explanation
- We start by defining the publishing node ‘pub’. Here we define the topic (/cmd_vel) to which it will publish messages of type Twist. Then we move to main().
- Initializing the node is key. Without this, our master node (roscore) will not be able define the flow of information between all nodes.
- In order to increase the velocity of the robot, we need to know its current velocity. Therefore we subscribe to the command velocity topic.
- The callback function in the rospy.Subscriber( ) command is increase().
- Inside the increase( ) function:
- Start by obtaining the velocity onto a variable – here it is velo_msg. Notice how velo_msg is of type Twist.
- Now define the rate at which values will be published.
- The user is now prompted to choose the change in speed.
- In the while loop:
- We obtain the x component of the linear velocity. We may use the y component as well depending on the application.
- The x component is now increased by the amount specified by the user.
- Now the velocity is published and the while loop is rerun.
Deploying ROS
Input (Terminal):
$roscore
#open new terminal
$source devel/setup.bash
#launch turtlebot3 on gazebo
$roslaunch turtlebot3_gazebo turtlebot3_empty_world.launch
#open new terminal
#give turtlebot3 some starting velocity
$roslaunch turtlebot3_teleop turtlebot3_teleop_key.launch
#now press w
#open a new terminal
#run your python script from your package
$rosrun <pkg_name> publisher.py
Output:
In main...
In the callback function.
0.01
By how much would you like to increase the speed?
Publishing Successful!
Refer to the video link below for complete execution.
Code demonstration
Last Updated :
28 Feb, 2022
Like Article
Save Article
Share your thoughts in the comments
Please Login to comment...