讲在前面:
vscode的环境已经是 如话题通信那里配置好了(主要体现在 :自动补齐,和快速编译)
本知识点将用一个实例(用发布者来发布自定义的消息,然后订阅者接收这个消息)来理解 自定义消息的基本使用,大致分为三块:
1.自定义消息*.msg的编写
2.发布者编写
3.订阅者编写
一.首先创建一个工作空间和软件包
创建工作空间
mkdir -p ~/catkin_ws_example/src
cd catkin_ws_example
catkin_make
创建软件包
cd src
catkin_create_pkg topic_pub_sub std_msg rospy roscpp
二.自定义消息*.msg的编写
(PS:这里可以完全参考ros wki上面的教程,消息创建部分,照搬就可以)
2.1编写msg文件
方式一:在终端中创建msg
cd ~/catkin_ws_example/src/topic_pub_sub
mkdir msg
gedit Person.msg
在打开的文本,然后输入如下自己定义的信息(像结构体一样编写就行):
string name
int32 age
float32 height
方式二:在vscode中创建msg
在终端中输入:
cd ~/catkin_ws_example
code .
这样就打开了vscode编辑器,在~/catkin_ws_example/src/topic_pub_sun/目录下,创建一个msg文件夹,在msg文件下,创建一个Person.msg文件,在输入自己定义的信息:
string name
int32 age
float32 height
最终效果如下:
以上两种方式实现效果一样,但是显然vscode的交互界面舒服。
2.2编辑配置文件(简记:231——package.xml改动两项,CMakeLists.txt改动三项,放开注释一项)
2.2.1首先在package.xml中添加编译依赖与执行依赖
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
2.2.2然后在CMakeLists.txt编辑 msg 相关配置
# 不要直接复制这一大段,只需将message_generation加在括号闭合前即可
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
#执行时依赖
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES demo02_talker_listener
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
#配置msg的源文件
# add_message_files(
# FILES
Person.msg //这里放你自己定义的消息文件名
# )
# 生成消息时依赖于 std_msgs
generate_messages(
DEPENDENCIES
std_msgs
)
好了,至此已经自定义消息配置完了。但是还没完,编译完了之后,还需要继续配置环境。
2.3编译
编译之后,会产生一些中间文件(后续调用相关 msg 时,是从这些中间文件调用的),但我只关注头文件在创建的工作空间的开发空间下 include的文件夹里 即(~/catkin_ws_example/devel/inlcude下)。
因为这是自己定义的消息,所以现在需要做的是,把这个头文件包含进本工作空间的路径里面(在c_cpp_properties.json 里的 includepath属性引入,这样可以避免的是 在用vscode开发时,引入 自定义消息头文件,不会出现误报错误和代码无法补齐的情况)
PS:如何快速的得到这个头文件的路径呢?——这个路径可以鼠标放在include上,然后右击鼠标打开终端,输入pwd可得
引入的框架大致如下:
{
"configurations": [
{
"browse": {
"databaseFilename": "",
"limitSymbolsToIncludedHeaders": true
},
"includePath": [
"/opt/ros/noetic/include/**",
"/usr/include/**",
"/xxx/yyy工作空间/devel/include/**" //配置 head 文件的路径
],
"name": "ROS",
"intelliSenseMode": "gcc-x64",
"compilerPath": "/usr/bin/gcc",
"cStandard": "c11",
"cppStandard": "c++17"
}
],
"version": 4
}
在本例中,引入图为:
最后面 ~/include/**的意思是,引入inlcude文件夹下的所有头文件。
至此,自定义消息部分,已经配置完成。
总结一下,做了哪些事?编写:
自定义消息
然后配置package.xml,CMakeLists.txt
引入头文件
三.发布方编写
3.1在~/catkin_ws_example/src/topic_pub_sub/src文件夹下创建一个*.cpp文件(本例为 topic_pub_Person.cpp),然后放如下代码:
#include "ros/ros.h"
#include "topic_pub_sub/Person.h"//把自定义文件包含进来
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");//如果用到日志输出ROS_INFO,如果有中文,则会乱码,这是为了解决乱码问题。
ros::init(argc,argv,"A");
ros::NodeHandle nh;
ros::Publisher pub = nh.advertise<topic_pub_sub::Person>("xinxi",100);
topic_pub_sub::Person person;//创建person对象
person.name = "zhangsan"; //然后引用Person类的三个属性
person.age = 25;
person.height = 1.73;
int count = 0;//为了方便于观察,加上的,目的是让年纪随输出而增加。单从理解消息角度来看,可有可无。
ros::Rate rate(1);//同上条命令,可有可无。目的是延迟每一条消息的输出间隔,这里为1HZ,故间隔1S
while(ros::ok())
{
person.age += 1;
pub.publish(person);
//ROS_INFO("我叫%s,今年%d,身高%.2f",person.name.c_str(),person.age,person.height);//*.c_str()是一个常量指针(临时指针),指向一个字符串数组。可读不可更改。
rate.sleep();
ros::spinOnce(); //一般有回调函数,才会用到这个。但是都推荐加上, 在while循环用spinonce,其他用spin()。
}
return 0;
}
最终vscode效果如图(不要纠结/~topic_pub_sub/src文件下,还有另外一个.cpp文件我是先写好了,才发的博客):
3.2配置CMakeLists.txt(需要修改三个地方,都是找到对应的地方,然后复制注释下来,修改需要改的部分即可)
3.2.1
3.2.2
2.3与平时的创建发布者订阅者对比,自定义消息时,修改CMakeLists.txt多了这一步。
修改的代码如下:
add_dependencies(topic_pub_Person ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
或者
add_dependencies(topic_pub_Person ${PROJECT_NAME}_generate_messages_cpp)
推荐后一句(官网推荐的)。
这行代码有了,但是这个代码放的位置有讲究(这里有坑!!!!踩了几个小时才出来):
直接复制放在133行,代码编译报错!一定要放在add_executable(topic_pub_Person src/topic_pub_Person.cpp)这句的后面!!!!如图:
OK~发布方已经编写好了,接下来就可以编译测试了(这个模块写好了,先测试没有问题在写其他模块)。
3.3编译测试
3.3.1 编译
方式一(终端编译方式):
cd ~/catkin_ws_example
catkin_make
方式二(vscode的快捷键编译方式):
在vscode中,shift+ctrl+B
3.2运行发布者节点(前提是已经运行了 roscore)
cd ~/catkin_ws_example
soure devel/setup.bash
rosrun topic_pub_sub topic_pub_Person
到这一步之后,就运行成功了,但是看不到消息(之前说过有两种验证方式的),但是我们可以用内置指令,把消息打印出来到终端看看,如:
另开一个终端:rostopic echo liaotian(你代码设置的消息名)
如图:
验证成功 ~
总结一下干了哪些事?
编写*.cpp文件
配置CMakeLists.xtxt
四.订阅方编写
4.1在~/catkin_ws_example/src/topic_pub_sub/src文件夹下创建一个*.cpp文件(本例为 topic_sub_Person.cpp),然后放如下代码:
#include<ros/ros.h>
#include<topic_pub_sub/Person.h>
void docallback(const topic_pub_sub::Person::ConstPtr &msg)//函数行参为要 订阅的地址,直接定位(指针)过去,把值取出来
{
ROS_INFO("我是%s,我今年%d,我的身高是%.2f " ,msg->name.c_str(),msg->age,msg->height);//
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"B");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe<topic_pub_sub::Person>("xinxi",100,docallback);//订阅
ros::spin();
return 0;
}
最终vscode效果如图:
4. 2配置CMakeLists.txt(需要修改三个地方,都是找到对应的地方,然后复制注释下来,修改需要改的部分即可,改的方法与发布方一样,因此这里只放了最终效果图即可,用红笔标出改了哪些部分)
shift+ctrl+B编译(或者用终端方式的编译,上面3.1写过了)通过,好了。可以联合调试了。
总结一下干了哪些事?
编写*.cpp文件
配置CMakeLists.xtxt
五.联合调试
5.1 编译(不会编译的见3.1)
5.2运行roscore
5.3运行发布者节点
新开一个终端:
cd ~/catkin_ws_example
soure devel/setup.bash
rosrun topic_pub_sub topic_pub_Person
5.4运行订阅者节点
新开一个终端:
cd ~/catkin_ws_example
soure devel/setup.bash
rosrun topic_pub_sub topic_sub_Person
最后效果如图所示(我多加了一个rqt_graph显示,可以更直观的看到):
OK~完成,结束~