1.消息类型功能包
ROS的元功能包common_msgs提供了多种消息类型:
std_msgs——标准数据类型
geometry_msgs——几何学数据类型
sensor_msgs——传感器数据类型
在一些情况下需要针对自己的机器人应用设计特定的消息类型。
2.自定义话题消息
功能包中的msg文件夹中就是自定义的消息类型文件。msg文件夹在功能包根目录下。
创建文件夹msg,创建文件Person.msg:
定义一个描述个人信息的消息类型:
string name
int32 age
float32 height
为了使用这些自定义消息类型,需要编译msg文件。
在package.xml文件中添加功能包依赖:
message_generation
message_runtime
在CMakeLists.txt文件。
编译时依赖:加入message_generation
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
)
运行时依赖:取消注释并加入message_runtime
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES sub_pub
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib
)
加入文件:
add_message_files(
FILES
Person.msg
)
自定义消息类型文件的依赖:
generate_messages(
DEPENDENCIES
std_msgs
)
回到工作空间根目录,编译工作空间
catkin_make
编译后的中间文件:可以找到Person.h头文件,和Person.py中的python类。
C++ 需要调用的中间文件(.../工作空间/devel/include/包名/xxx.h)
Python 需要调用的中间文件(.../工作空间/devel/lib/python3/dist-packages/包名/msg)
3.c++调用自定义消息类型
(1)准备工作
为了在vscode中编程时,防止头文件中引入自定义消息类型误报和代码无法自动补齐,故得对vscode进行配置。
首先在复制路径的文件夹用终端打开,输入pwd。
pwd
rosmelodic@rosmelodic-virtual-machine:~/catkin_ws/devel/include$ pwd
/home/rosmelodic/catkin_ws/devel/include
复制路径/home/rosmelodic/catkin_ws/devel/include到c_cpp_properties.json,加上/**
在includePath中加入"路径/**"
(2)发布方实现
pub_person.cpp
#include "ros/ros.h"
#include "sub_pub/Person.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ROS_INFO("发布方");
ros::init(argc, argv, "ren");
ros::NodeHandle n;
ros::Publisher pub = n.advertise("renxinxi",10);
sub_pub::Person person;
person.name = "张三";
person.age = "1";
person.height = "1.73";
ros::Rate rate(1);
ros::Duration(3.0).sleep();
while(ros::ok)
{
person.age += 1;
pub.publish(person);
rate.sleep();
}
return 0;
}
头文件
#include "ros/ros.h"
#include "sub_pub/Person.h"
调用在sub_pub功能包下自定义的消息类型。
setlocale(LC_ALL, "");
控制台输出有中文,防止乱码。
ROS_INFO("发布方");
控制台输出字符串,发布方。
ros::init(argc, argv, "ren");
创建和初始化节点。
ros::NodeHandle n;
创建节点句柄。
ros::Publisher pub = n.advertise("renxinxi",10);
创建发布者,其中泛型部分调用自定义消息类型,话题名为renxinxi。
sub_pub::Person person;
person.name = "张三";
person.age = "1";
person.height = "1.73";
声明变量并赋值。
ros::Rate rate(1);
设置循环频率,1hz。
ros::Duration(3.0).sleep();
延时3秒给发布者注册留时间,防止数据丢失。
while(ros::ok)
{
person.age += 1;
pub.publish(person);
rate.sleep();
ros::spinOnce();
}
while循环体,其中条件为ros::ok(ros系统状态)。
为了观察循环情况,将其中一个变量+1。
发布person数据。
加入循环延迟。
官方建议的spinOnce。
CMakeList.txt配置
add_executable(pub_person src/pub_person.cpp)
target_link_libraries(pub_person
${catkin_LIBRARIES}
)
需要多一个配置,没有代码提示,打错了会报错。这个配置的目的时先编译自定义消息类型的msg文件,再编译调用的自定义消息类型的cpp文件,这样不会出现这两个先后的逻辑问题。
add_dependencies(pub_person ${PROJECT_NAME}_generate_messages_cpp)
(3)订阅方实现
sub_person.cpp
#include "ros/ros.h"
#include "sub_pub/Person.h"
void huidiao(const sub_pub::Person::ConstPtr & msgggg)
{
ROS_INFO("订阅人信息:%s, %d,%.2f",msgggg->name.c_str(),msgggg->age,msgggg->height);
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
ROS_INFO("订阅方");
ros::init(argc, argv, "ren_sub");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("renxinxi", 10,huidiao);
ros::spin();
return 0;
}
回调函数,name.c_str()注意改成c的字符串
void huidiao(const sub_pub::Person::ConstPtr & msgggg)
{
ROS_INFO("订阅人信息:%s, %d,%.2f",msgggg->name.c_str(),msgggg->age,msgggg->height);
}
创建订阅者,编写代码时可ctrl+shif+空格,显示函数参数提示。
ros::Subscriber sub = n.subscribe("renxinxi", 10,huidiao);
CMakeList.txt配置
add_executable(sub_person src/sub_person.cpp)
add_dependencies(sub_person ${PROJECT_NAME}_generate_messages_cpp)
target_link_libraries(sub_person
${catkin_LIBRARIES}
)
(4)rosrun发布者与订阅者,给出计算图