(訳注:最新の情報は原文を参照してください.)
シンプルな配信者と購読者を書く
Contents
Writing the Publisher Node
"Node" is the ROS term for an executable that is connected to the ROS network. Here we'll create the publisher ("talker") node which will continually broadcast a message.
Change directory into the beginner_tutorials package, you created in the earlier tutorial, creating a package::
roscd beginner_tutorials
The Code
Create the src/talker.cpp file within the beginner_tutorials package and paste the following inside it:
1 #include <ros/ros.h>
2 #include <std_msgs/String.h>
3 #include <sstream>
4 int main(int argc, char** argv)
5 {
6 ros::init(argc, argv, "talker");
7 ros::NodeHandle n;
8 ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 100);
9 ros::Rate loop_rate(5);
10 int count = 0;
11 while (ros::ok())
12 {
13 std::stringstream ss;
14 ss << "Hello there! This is message [" << count << "]";
15 std_msgs::String msg;
16 msg.data = ss.str();
17 chatter_pub.publish(msg);
18 ROS_INFO("I published [%s]", ss.str().c_str());
19 ros::spinOnce();
20 loop_rate.sleep();
21 ++count;
22 }
23 }
The Code Explained
Now, let's break the code down.
ros/ros.h is a convenience include that includes all the headers necessary to use all the public pieces of the ROS system.
This includes String message from the std_msgs package. This is a header generated automatically from the String.msg file in that package. For more information on message definitions, see the msg page.
Initialize ROS. This allows ROS to do name remapping through the command line -- not important for now. This is also where we specify the name of our Node. Node names must be unique in a running system.
The name used here must be a base name, ie. it cannot have a / in it.
7 ros::NodeHandle n;
Create a handle to this process' Node. The first NodeHandle created will actually do the initialization of the Node, and the last one destructed will cleanup any resources the Node was using.
8 ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 100);
Tell the master that we are going to be publishing a message of type "std_msgs::String" on the topic "chatter". This lets the master tell any nodes listening on "chatter" that we are going to publish data on that topic. The second argument is the size of our publishing queue. In this case if we are publishing too quickly it will buffer up a maximum of 100 messages before beginning to throw away old ones.
advertise() returns a Publisher object, which serves two purposes: 1) it contains a publish() method that lets you publish messages onto the topic it was created with, and 2) when it goes out of scope, it will automatically unadvertise.
9 ros::Rate loop_rate(5);
A Rate object allows you to specify a frequency that you would like to loop at. It will keep track of how long it has been since the last call to Rate::sleep(), and sleep for the correct amount of time.
In this case we tell it we want to run at 5hz.
By default roscpp will install a SIGINT handler which provides Ctrl-C handling. ros::ok() will return false if this happens, or if we have been kicked off the network by another node with the same name, or if ros::shutdown() has been called by another part of the application. Once ok() returns false, all ROS calls will fail.
We broadcast a message on ROS using a ros::Message-derived, class, generally generated from a msg file. More complicated datatypes are possible, but for now we're going to use the standard String message, which has one member: "data".
17 chatter_pub.publish(msg);
Now we actually broadcast the message to anyone who is connected.
18 ROS_INFO("I published [%s]", ss.str().c_str());
ROS_INFO and friends are our replacement for printf/cout. See the rosconsole documentation for more information.
19 ros::spinOnce();
Calling ros::spinOnce() here is not necessary for this simple program, because we are not receiving any callbacks. However, if you were to add a subscription into this application, and did not have spinOnce() here, your callbacks would never get called. So, add it for good measure.
Now we use the Rate object to sleep for the time remaining to let us hit our 5hz publish rate.
Here's the condensed version of what's going on:
- Initialize the ROS system
- Advertise that we are going to be publishing std_msgs::String messages on the "chatter" topic to the master
- Loop while publishing messages to "chatter" 5 times a second
Now we need to write a node to receive the messsages.
Writing the Subscriber Node
The Code
Create the src/listener.cpp file within the beginner_tutorials package and paste the following inside it:
1 #include <ros/ros.h>
2 #include <std_msgs/String.h>
3 void chatterCallback(const std_msgs::StringConstPtr& msg)
4 {
5 ROS_INFO("Received [%s]", msg->data.c_str());
6 }
7 int main(int argc, char** argv)
8 {
9 ros::init(argc, argv, "listener");
10 ros::NodeHandle n;
11 ros::Subscriber chatter_sub = n.subscribe("chatter", 100, chatterCallback);
12 ros::spin();
13 }
The Code Explained
Now, let's break it down piece by piece, ignoring some pieces that have already been explained above.
This is the callback function that will get called when a new message has arrived on the "chatter" topic. The message is passed in a boost shared_ptr, which means you can store it off if you want, without worrying about it getting deleted underneath you, and without copying the underlying data.
Subscribe to the "chatter" topic with the master. ROS will call the "chatterCallback" function whenever a new message arrives. The 2nd argument is the queue size, in case we are not able to process messages fast enough. In this case, if the queue reaches 100 messages, we will start throwing away old messages as new ones arrive.
subscribe() returns a Subscriber object, that you must hold on to until you want to unsubscribe. When the Subscriber object is destructed, it will automatically unsubscribe from the "chatter" topic.
There are versions of the subscribe() function which allow you to specify a class member function, or even anything callable by a Boost.Function object.
spin() enters a loop, calling message callbacks as fast as possible. Don't worry though, if there's nothing for it to do it won't use much CPU. spin() will exit once ros::ok() returns false, which means ros::shutdown() has been called, either by the default Ctrl-C handler, the master telling us to shutdown, or it being called manually.
There are other ways of pumping callbacks, but we won't worry about those here. The roscpp_tutorials package has some demo applications which demonstrate this.
Again, here's a condensed version of what's going on:
- Initialize the ROS system
- Subscribe to the "chatter" topic
- Spin, waiting for messages to arrive
- When a message arrives, the "chatterCallback" function is called
Building your nodes
roscreate-pkg will create a default Makefile and CMakeLists.txt for your package.
$ rosed beginner_tutorials CMakeLists.txt
It should look something like this:
cmake_minimum_required(VERSION 2.4.6) include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake) # Set the build type. Options are: # Coverage : w/ debug symbols, w/o optimization, w/ code-coverage # Debug : w/ debug symbols, w/o optimization # Release : w/o debug symbols, w/ optimization # RelWithDebInfo : w/ debug symbols, w/ optimization # MinSizeRel : w/o debug symbols, w/ optimization, stripped binaries #set(ROS_BUILD_TYPE RelWithDebInfo) rosbuild_init() #set the default path for built executables to the "bin" directory set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) #set the default path for built libraries to the "lib" directory set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) #uncomment if you have defined messages #rosbuild_genmsg() #uncomment if you have defined services #rosbuild_gensrv() #common commands for building c++ executables and libraries #rosbuild_add_library(${PROJECT_NAME} src/example.cpp) #target_link_libraries(${PROJECT_NAME} another_library) #rosbuild_add_boost_directories() #rosbuild_link_boost(${PROJECT_NAME} thread) #rosbuild_add_executable(example examples/example.cpp) #target_link_libraries(example ${PROJECT_NAME})
Adding the following at the bottom:
rosbuild_add_executable(talker src/talker.cpp) rosbuild_add_executable(listener src/listener.cpp)
This will create two executables, "talker" and "listener", which by default will go into the "bin" directory.
For more information on using CMake with ROS, see CMakeLists Now run make:
$ make
Running the nodes
Running nodes requires you have a ROS core started. Open a new shell, and type:
roscore
If all goes well, you should see an output that looks something like this:
... logging to /u/takayama/.ros/logs/83871c9c-934b-11de-a451-001d927076eb/roslaunch-ads-31831.log ... loading XML file [/wg/stor1a/rosbuild/shared_installation/ros/tools/roslaunch/roscore.xml] Added core node of type [rosout/rosout] in namespace [/] started roslaunch server http://ads:54367/ SUMMARY ======== NODES changing ROS_MASTER_URI to [http://ads:11311/] for starting master locally starting new master (master configured for auto start) process[master]: started with pid [31874] ROS_MASTER_URI=http://ads:11311/ setting /run_id to 83871c9c-934b-11de-a451-001d927076eb +PARAM [/run_id] by /roslaunch +PARAM [/roslaunch/uris/ads:54367] by /roslaunch process[rosout-1]: started with pid [31889] started core service [/rosout] +SUB [/time] /rosout http://ads:33744/ +SERVICE [/rosout/get_loggers] /rosout http://ads:33744/ +SERVICE [/rosout/set_logger_level] /rosout http://ads:33744/ +PUB [/rosout_agg] /rosout http://ads:33744/ +SUB [/rosout] /rosout http://ads:33744/
Now everything is set to run talker/listener. Open a new shell, go to the talker_listener package and type:
./bin/talker
Now in the original shell type:
./bin/listener
Talker should begin outputting text similar to:
[ INFO] I published [Hello there! This is message [0]] [ INFO] I published [Hello there! This is message [1]] [ INFO] I published [Hello there! This is message [2]] ...
And listener should begin outputting text similar to:
[ INFO] Received [Hello there! This is message [20]] [ INFO] Received [Hello there! This is message [21]] [ INFO] Received [Hello there! This is message [22]] ...
Congratulations! You've just run your first ROS nodes. For more example code, see the roscpp_tutorials package.






