1.寫(xiě)一個(gè)publisher節(jié)點(diǎn)
“節(jié)點(diǎn)”是連接到ROS網(wǎng)絡(luò)的可執(zhí)行文件的ROS術(shù)語(yǔ)滤淳。在這里贤徒,我們將創(chuàng)建一個(gè)發(fā)布者(“ talker”)節(jié)點(diǎn)醉蚁,該節(jié)點(diǎn)將不斷廣播消息睛琳。
1.1 將目錄更改為在catkin工作區(qū)以前的教程中創(chuàng)建的beginner_tutorials包:
roscd beginner_tutorials
1.2 在beginner_tutorials包目錄中創(chuàng)建一個(gè)src目錄:
mkdir -p src
該目錄將包含我們beginner_tutorials包的所有源文件盒蟆。
1.3 在beginner_tutorials包中創(chuàng)建src / talker.cpp文件,并將以下內(nèi)容粘貼到其中:
// ros/ros.h是一個(gè)方便的工具掸掏,其中包括使用ROS系統(tǒng)最常見(jiàn)的公共部分所需的所有標(biāo)頭茁影。
#include "ros/ros.h"
// 這包括std_msgs / String消息,該消息駐留在std_msgs包中丧凤。
// 這是從該程序包中的String.msg文件自動(dòng)生成的標(biāo)頭募闲。有關(guān)消息定義的更多信息,請(qǐng)參見(jiàn)msg頁(yè)面愿待。
#include "std_msgs/String.h"
#include <sstream>
/**
* 本教程演示了如何通過(guò)ROS系統(tǒng)簡(jiǎn)單地發(fā)送消息浩螺。
*/
// 這是下面事情的精簡(jiǎn)版:
// 初始化ROS系統(tǒng)
// 宣傳我們將在chatter主題上向主服務(wù)器發(fā)布std_msgs / String消息
// 在將消息發(fā)布到聊天時(shí)每秒循環(huán)10次
int main(int argc, char** argv)
{
// 初始化ROS。這使ROS可以通過(guò)命令行進(jìn)行名稱重映射-目前尚不重要仍侥。
// 這也是我們指定節(jié)點(diǎn)名稱的地方要出。節(jié)點(diǎn)名稱在運(yùn)行的系統(tǒng)中必須唯一。
ros::init(argc, argv, "talker");
// 創(chuàng)建此進(jìn)程的節(jié)點(diǎn)的句柄农渊。創(chuàng)建的第一個(gè)NodeHandle實(shí)際上將對(duì)節(jié)點(diǎn)進(jìn)行初始化患蹂,
// 而最后一個(gè)被破壞的節(jié)點(diǎn)將清理該節(jié)點(diǎn)正在使用的所有資源。
ros::NodeHandle node_handle;
// 告訴管理員,我們將在主題討論中發(fā)布std_msgs / String類型的消息传于。
// 這樣囱挑,主服務(wù)器就可以告訴所有正在聊天的節(jié)點(diǎn),我們將發(fā)布有關(guān)該主題的數(shù)據(jù)沼溜。
// 第二個(gè)參數(shù)是發(fā)布隊(duì)列的大小平挑。在這種情況下,如果我們發(fā)布得太快系草,
// 它將最多緩沖1000條消息通熄,然后再開(kāi)始丟棄舊消息。
// NodeHandle :: advertise()返回一個(gè)ros :: Publisher對(duì)象找都,
// 該對(duì)象有兩個(gè)作用:
// 1)它包含一個(gè)publish()方法唇辨,可用于將消息發(fā)布到其創(chuàng)建的主題上;
// 2)當(dāng)它超出范圍時(shí)檐嚣,它將自動(dòng)取消廣告助泽。
ros::Publisher chatter_pub = node_handle.advertise<std_msgs::String>("chatter", 100);
// ros :: Rate對(duì)象允許您指定要循環(huán)播放的頻率。
// 它將跟蹤自上次調(diào)用Rate::sleep()以來(lái)已等待了多長(zhǎng)時(shí)間嚎京,并睡眠了正確的時(shí)間嗡贺。
// 在這種情況下,我們告訴我們要以10Hz運(yùn)行鞍帝。
ros::Rate loop_rate(10);
int count = 0;
// 默認(rèn)情況下诫睬,roscpp將安裝SIGINT處理程序,
// 該處理程序提供Ctrl-C處理帕涌,如果發(fā)生這種情況摄凡,
// 將導(dǎo)致ros :: ok()返回false。
// ros :: ok()將在以下情況下返回false:
// 收到SIGINT(Ctrl-C)
// 我們已經(jīng)被另一個(gè)同名節(jié)點(diǎn)踢出網(wǎng)絡(luò)
// ros :: shutdown()已由應(yīng)用程序的另一部分調(diào)用蚓曼。
// 所有ros :: NodeHandles已被銷毀
// 一旦ros :: ok()返回false亲澡,所有ROS調(diào)用都會(huì)失敗。
while (ros::ok())
{
// 我們使用消息自適應(yīng)類在ROS上廣播消息纫版,該類通常是從msg文件生成的床绪。
// 可能有更復(fù)雜的數(shù)據(jù)類型,但是現(xiàn)在我們將使用標(biāo)準(zhǔn)的String消息其弊,
// 該消息具有一個(gè)成員:“ data”癞己。
std_msgs::String msg;
std::stringstream ss;
ss << "hello world" << count;
msg.data = ss.str();
// ROS_INFO可以代替printf / cout。有關(guān)更多信息梭伐,請(qǐng)參見(jiàn)rosconsole文檔痹雅。
ROS_INFO("%s", msg.data.c_str());
// 現(xiàn)在,我們實(shí)際上將消息廣播給了已連接的任何人糊识。
chatter_pub.publish(msg);
// 對(duì)于這個(gè)簡(jiǎn)單的程序绩社,不需要在此處調(diào)用ros :: spinOnce()摔蓝,
// 因?yàn)槲覀儧](méi)有收到任何回調(diào)。但是愉耙,如果您要向此應(yīng)用程序添加訂閱项鬼,
// 并且在此處沒(méi)有ros :: spinOnce(),則將永遠(yuǎn)不會(huì)調(diào)用您的回調(diào)劲阎。
// 因此,請(qǐng)將其添加為良好的度量鸠真。
ros::spinOnce();
// 現(xiàn)在悯仙,我們使用ros :: Rate對(duì)象休眠剩余時(shí)間,使我們達(dá)到10Hz的發(fā)布速率吠卷。
loop_rate.sleep();
++count;
}
return 0;
}
2.寫(xiě)一個(gè)subscriber節(jié)點(diǎn)
- 在beginner_tutorials包中創(chuàng)建src / listener.cpp文件锡垄,并將以下內(nèi)容粘貼到其中:
// ros/ros.h是一個(gè)方便的工具,其中包括使用ROS系統(tǒng)最常見(jiàn)的公共部分所需的所有標(biāo)頭祭隔。
#include "ros/ros.h"
// 這包括std_msgs / String消息货岭,該消息駐留在std_msgs包中。
// 這是從該程序包中的String.msg文件自動(dòng)生成的標(biāo)頭疾渴。有關(guān)消息定義的更多信息千贯,請(qǐng)參見(jiàn)msg頁(yè)面。
#include "std_msgs/String.h"
/**
本教程演示了通過(guò)ROS系統(tǒng)簡(jiǎn)單接收消息的過(guò)程搞坝。
*/
//當(dāng)在chatter主題上收到新消息時(shí)搔谴,將調(diào)用此回調(diào)函數(shù)。
// 該消息在boost shared_ptr中傳遞桩撮,
// 這意味著您可以根據(jù)需要將其存儲(chǔ)起來(lái)敦第,
// 而不必?fù)?dān)心它下面的內(nèi)容被刪除,也無(wú)需復(fù)制基礎(chǔ)數(shù)據(jù)店量。
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
// 同樣芜果,這是正在發(fā)生的事情的精簡(jiǎn)版:
// 初始化ROS系統(tǒng)
// 訂閱聊天主題
// 旋轉(zhuǎn),等待消息到達(dá)
// 消息到達(dá)時(shí)融师,將調(diào)用chatterCallback()函數(shù)
int main(int argc, char** argv)
{
// 初始化ROS右钾。這使ROS可以通過(guò)命令行進(jìn)行名稱重映射-目前尚不重要。
// 這也是我們指定節(jié)點(diǎn)名稱的地方诬滩。節(jié)點(diǎn)名稱在運(yùn)行的系統(tǒng)中必須唯一霹粥。
ros::init(argc, argv, "listener");
// 創(chuàng)建此進(jìn)程的節(jié)點(diǎn)的句柄。創(chuàng)建的第一個(gè)NodeHandle實(shí)際上將對(duì)節(jié)點(diǎn)進(jìn)行初始化疼鸟,
// 而最后一個(gè)被破壞的節(jié)點(diǎn)將清理該節(jié)點(diǎn)正在使用的所有資源后控。
ros::NodeHandle node_handle;
// 訂閱與主機(jī)的聊天主題。每當(dāng)有新消息到達(dá)時(shí)空镜,ROS就會(huì)調(diào)用chatterCallback()函數(shù)浩淘。
// 第二個(gè)參數(shù)是隊(duì)列大小捌朴,以防萬(wàn)一我們不能足夠快地處理消息。
// 在這種情況下张抄,如果隊(duì)列達(dá)到1000條消息砂蔽,我們將在新消息到達(dá)時(shí)開(kāi)始丟棄舊消息。
// NodeHandle :: subscribe()返回ros :: Subscriber對(duì)象署惯,
// 您必須保留該對(duì)象直到要取消訂閱為止左驾。破壞Subscriber對(duì)象后,
// 它將自動(dòng)取消訂閱chatter主題极谊。
// NodeHandle :: subscribe()函數(shù)有多種版本诡右,
// 可讓您指定類成員函數(shù),甚至可以指定Boost.Function對(duì)象可以調(diào)用的任何函數(shù)轻猖。
ros::Subscriber sub = node_handle.subscribe("chatter", 100, chatterCallback);
// ros :: spin()進(jìn)入循環(huán)帆吻,并盡可能快地調(diào)用消息回調(diào)。
// 不過(guò)咙边,請(qǐng)不要擔(dān)心猜煮,如果沒(méi)有什么可做的,則不會(huì)占用太多CPU败许。
// 一旦ros :: ok()返回false王带,ros :: spin()將退出,
// 這意味著ros :: shutdown()已被默認(rèn)Ctrl-C處理程序市殷,
// 主程序告訴我們關(guān)閉或被調(diào)用了手動(dòng)辫秧。
ros::spin();
return 0;
}
3.編譯節(jié)點(diǎn)
您在上一教程中使用過(guò)catkin_create_pkg,該教程為您創(chuàng)建了package.xml和CMakeLists.txt文件被丧。 生成的CMakeLists.txt應(yīng)該如下所示(對(duì)“創(chuàng)建Msgs和Srvs”教程進(jìn)行了修改盟戏,并刪除了未使用的注釋和示例):
1 cmake_minimum_required(VERSION 2.8.3)
2 project(beginner_tutorials)
3
4 ## Find catkin and any catkin packages
5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
6
7 ## Declare ROS messages and services
8 add_message_files(DIRECTORY msg FILES Num.msg)
9 add_service_files(DIRECTORY srv FILES AddTwoInts.srv)
10
11 ## Generate added messages and services
12 generate_messages(DEPENDENCIES std_msgs)
13
14 ## Declare a catkin package
15 catkin_package()
不必?fù)?dān)心修改注釋的(#)示例,只需將以下幾行添加到CMakeLists.txt的底部:
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_dependencies(talker beginner_tutorials_generate_messages_cpp)
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener beginner_tutorials_generate_messages_cpp)
- 生成的CMakeLists.txt文件應(yīng)如下所示:
1 cmake_minimum_required(VERSION 2.8.3)
2 project(beginner_tutorials)
3
4 ## Find catkin and any catkin packages
5 find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
6
7 ## Declare ROS messages and services
8 add_message_files(FILES Num.msg)
9 add_service_files(FILES AddTwoInts.srv)
10
11 ## Generate added messages and services
12 generate_messages(DEPENDENCIES std_msgs)
13
14 ## Declare a catkin package
15 catkin_package()
16
17 ## Build talker and listener
18 include_directories(include ${catkin_INCLUDE_DIRS})
19
20 add_executable(talker src/talker.cpp)
21 target_link_libraries(talker ${catkin_LIBRARIES})
22 add_dependencies(talker beginner_tutorials_generate_messages_cpp)
23
24 add_executable(listener src/listener.cpp)
25 target_link_libraries(listener ${catkin_LIBRARIES})
26 add_dependencies(listener beginner_tutorials_generate_messages_cpp)
這將創(chuàng)建兩個(gè)可執(zhí)行文件甥桂,talker和listener柿究,默認(rèn)情況下它們將進(jìn)入開(kāi)發(fā)空間的package目錄,默認(rèn)情況下位于?/ catkin_ws / devel / lib / <package name>黄选。
- 請(qǐng)注意蝇摸,您必須將可執(zhí)行目標(biāo)的依賴項(xiàng)添加到消息生成目標(biāo):
target_link_libraries(talker ${catkin_LIBRARIES})
您可以直接調(diào)用可執(zhí)行文件,也可以使用rosrun調(diào)用它們办陷。它們沒(méi)有放在'<prefix> / bin'中貌夕,因?yàn)樵趯④浖惭b到系統(tǒng)時(shí),這會(huì)污染PATH民镜。
- 現(xiàn)在運(yùn)行catkin_make編譯:
# In your catkin workspace
cd ~/catkin_ws
catkin_make
4.測(cè)試你的節(jié)點(diǎn)(兩種方式)
- 打開(kāi)三個(gè)終端分別運(yùn)行:
roscore
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials talker
source ~/catkin_ws/devel/setup.bash
rosrun beginer_tutorials listener
- 打開(kāi)三個(gè)終端分別運(yùn)行:
roscore
~/catkin_ws/devel/lib/beginer_tutorials/talker
~/catkin_ws/devel/lib/beginer_tutorials/listener
最后結(jié)果: