1.首先,创建自己的包
$ cd catkin_ws/src
$ catkin_create_pkg test roscpp
2新建一个msg文件夹用来存放自己编写的msg文件
$ roscd test
$ mkdir msg
$ cd msg
$ vi test.msg
3.编写自己需要的类型的参数。
可供选择的有:
bool
int8
uint8
int16
uint16
int32
uint32
int64
uint64
float32
float64
string
time
duration
下面举个例子:
比如我自己编写了一个叫做test.msg的文件
$ vi test.msg
并且写入以下内容(记得不要在后边加上分号 ; ,否则到时候编译会报错)
int16 a
float32 b
string c
这里的a,b,c到时候相当于一个类的几个元素啦,后边用到你就知道了
之后再改一下自己的package.xml和CMakeLists.txt文件
先看一下我的package.xml文件
以下的build_depend和run_depend可以根据自己的需要自行增加或删除
但是,需要用到message的貌似都要有以下两句
test
0.0.0
The test package
weiwie
TODO
catkin
roscpp
message_generation
roscpp
message_runtime
接下来看一下我的CMakeLists.txt文件
以下信息基本上都是必须的,但是你若是有其他的信息你也可以适当添加。
cmake_minimum_required(VERSION 2.8.3)
project(test)
#对于find_package,如果你还使用了其他的依赖,必须在其中添加对应的包的名称,
#比如你如果编写的msg文件调用了std_msg文件的信息的话,那么就必须把std_msg
#这个包也放进来
find_package(catkin REQUIRED COMPONENTS
roscpp
message_generation
)
#add_message_files用来添加你所使用的所有的msg文件
add_message_files(
FILES
test.msg
)
#generate_messages则用来添加你的信息所需要的依赖包
#同理,假如你还使用了std_msg这个包的信息,那么你必须把std_msg加进去
generate_messages(
DEPENDENCIES
test
)
#至于这个catkin_package,你只需要更改那个LIBRARIES为你自己的包名以及
#在CATKIN_DEPENDS后边加上你所依赖的其他的包名就可以啦
catkin_package(
INCLUDE_DIRS include
LIBRARIES test
CATKIN_DEPENDS message_runtime roscpp
DEPENDS system_lib
)
#这句一般就不用更改了
include_directories(
${catkin_INCLUDE_DIRS}
)
接下来,我们就可以编写自己需要的ros的发布和订阅节点啦。
首先,进入我们自己的src文件夹,创建自己需要的节点的名称(这里先写发布的节点)
$ cd src
$ vi public.cpp
写入以下内容:
#include //ros必备头文件
#include //自己的msg头文件,test是你的包名,test.h是将
//你的msg文件的.msg后缀改成了.h
#include //这个是用来定义以下的std::stringstream的
int main(int argc,char **argv)
{
ros::init(argc,argv,"test"); //test是你的节点名称
ros::NodeHandle n;
ros::Publisher test_pub = n.advertise("test",1000);
//上面这个句子注意了,advertise后边的<>里面放的是你想要发布的节点的
//包名::msg文件名去掉后缀,里面是你所发布的主题的名称。1000你可以当作是一个
//栈或者队列来看待,就是发布的消息超过1000的时候,他会开始舍弃发布过的信息
//仅此而已,你也可以自己添加,换成1或者其他的都行
ros::Rate loop_rate(10); //设置发布的频率为10,可以自己更改
//下面三个是我打算用来附给msg并发布出去的
int aount = 0;
float bount = 0.0;
std::stringstream ss("Hello World!");
while(ros::ok())
{
//定义一个test::test类型的msg变量。(也就是包名::msg文件名去掉后缀)
test::test msg;
//下面三句我们可以清楚的看到我直接用了.a还有.b跟.c,其实就是我刚才
//在msg文件下命名的名称,如果你是其他的名称,那么你就直接叫那个名字
//就可以啦。
msg.a = aount;
msg.b = bount;
msg.c = ss.str();
aount++;
bount++;
//下面之所以使用.c_str()是因为,如果直接显示msg.c的话,会出现乱码
ROS_INFO("%d,%f,%s",msg.a,msg.b,msg.c.c_str());
test_pub.publish(msg); //这句就是最重要的发布消息啦。
//最后两句跟ros::init都是固定要的,加上去就可以啦.
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
接下来,我们编写我们的监听节点
#vi listen.cpp
写入以下内容:
#include //ros程序固有的头文件
#include //自己的msg头文件
//以下函数中的test::test::ConstPtr &msg 分别是包名::msg文件名::ConstPtr &msg
//后边的ConstPtr你不需要知道是什么东西,因为他就是固定的,照写就可以啦
void testCallback(const test::test::ConstPtr &msg)
{
//下方注意,用msg的数据的适合,必须要用->不能用.。至于.c_str()同上,是为了
//不输出乱码
ROS_INFO("I heard aount is %d,bount is %f,count is %s\n",msg->a,msg->b,msg->c.c_str());
}
int main(int argc,char **argv)
{
ros::init(argc,argv,"listen"); //节点的名称
ros::NodeHandle n;
//监听的迭代器,第一个参数是监听的主题名,第三个是迭代器调用的函数
ros::Subscriber sub = n.subscribe("test",1000,testCallback);
ros::spin();
return 0;
}
写完我们的发布跟监听的节点后,我们需要在自己的CMakeLists.txt文件后边加上这几句话。(这几句都是必须的,第三和第六句后边的test_gencpp根据你自己的包名不同进行更改,test是我自己的包名,假如你的包名叫做hello,那么test_gencpp就应该改成hello_gencpp)
add_executable(public src/public.cpp)
target_link_libraries(public ${catkin_LIBRARIES})
add_dependencies(public test_gencpp)
add_executable(listen src/listen.cpp)
target_link_libraries(listen ${catkin_LIBRARIES})
add_dependencies(listen test_gencpp)
至于第一跟第二句,后边第一个参数是生成的文件名,第二个参数则分别是你想编译的文件名的位置以及一个固定的${catkin_LIBRARIES},如果你使用了像opencv的库的话,就必须加上你需要的.so文件。
比如:我自己之前编写的发布视频的节点的这几句话是这样的
link_directories(~/opencv-3.4.0/build/lib)
target_link_libraries(public_video_node ${catkin_LIBRARIES}
libopencv_highgui.so libopencv_core.so libopencv_imgproc.so
libopencv_videoio.so libopencv_imgcodecs.so)