ROS学习笔记二:Defining messages
发现把build文件夹删掉后,或者把包给别人后,重新编译就会报缺少自定义消息的头文件,检查了CMakeLists和package.xml都没发现有问题,后来仔细想想其实顺序错了,应该先把CMakeLists里面那些要调用到头文件生成可执行程序的cpp文件先去掉,先catkin_make 把自定义消息的头文件生成出来先,然后再把这些需要用到对应头文件 来生成可执行文件的cpp加上去。这样就可以了,如下:
add_executable(robot_ik src/robot_ik.cpp)
target_link_libraries(robot_ik ${catkin_LIBRARIES})
像上面这种,要调用到自定义消息的cpp,先删掉,catkin_make第一次,再把它们加上,catkin_make第二次,就不会报错了。
2021.05.05
ROS有14种内置的消息类型,可供调用,当然可以即可单独使用也可以混合使用,利用这些内置的消息类型就可以构建出复杂的消息类型。
##一.创建自定义的message
以下是一个将三个内置消息类型组合成一个自定义的message例子(这三个消息类型的定义都在package std_msgs里面):
###1.创建message文件
①先再工作空间内创建一个package
catkin_create_pkg example_ros_msg roscpp std_msgs
也可以使用
cs_create_pkg example_ros_msg roscpp std_msgs
它们的功能很相像,第二条指令生成的CMakeLists会更简洁一点,还有README file(markdown格式)。
②在package里面创建一个msg文件夹,存放message文件
cd example_ros_msg
mkdir msg
③在msg文件夹里面创建一个message文件
touch ExampleMessage.msg
④在第三步创建的.msg
文件中写入以下信息
Header header
int32 demo_int
float64 demo_double
###2.编辑package.xml文件
要使编译器能顺利编译并生成新的message头文件,需要在package.xml中添加以下语句:
<build_depend>message_generation</build_depend>
<run_depend>message_runtime</run_depend>
###3.编辑CMakeLists.txt文件
①添加需要调用的package,这里调用的三个消息类型都在std_msgs这个package里面,所以需要加上这个包,在CMakeLists.txt
中添加以下语句:
find_package(catkin REQUIRED COMPONENTS roscpp rospy message_generation std_msgs)
②指定.msg
文件,这里使用的.msg
文件是ExampleMessage.msg
,所以添加以下语句:
add_message_files(
FILES
ExampleMessage .msg
)
③指定生成新的message头文件需要的依赖项,这里的消息类型都是在std_msgs
中的,添加以下语句:
generate_messages(
DEPENDENCIES
std_msgs
)
注意,generate_messages必须在catkin_package前面。
④最后是设置运行的依赖项
catkin_package(
CATKIN_DEPENDS message_runtime
)
至此,自定义的message文件的准备工作已经完成了,现在可以尝试编译这个message文件
cd catkin_ws
catkin_make
编译之后会生成一个头文件,名称与.msg
文件的名称相同,它生成的位置在
~/catkin_ws/devel/include/example_ros_msg/ExampleMessage.h
然后使用功能rosmsg show
查看显示的消息类型是否与我们预想的一样:
rosmsg show example_ros_msg/ExampleMessage
若显示如下,则说明我们成功的创建了一个自定义的message类型。
std_msgs/Header header
uint32 seq
time stamp
string frame_id
int32 demo_int
float64 demo_double
##二.调用自定义的message类型
要想在任意节点中调用自定义的message类型,需要在该节点的源代码中添加对应的package及包含的头文件,如下:
#include <example_ros_msg/ExampleMessage.h>
格式为
#include <packageName/headerfileName.h>
以下是一个调用刚刚我们自定义的message类型的节点程序:
#include <ros/ros.h>
#include <example_ros_msg/ExampleMessage.h>//添加message类型对应的package和header file是关键
#include <math.h>
int main(int argc, char **argv) {
ros::init(argc, argv, "example_ros_message_publisher"); //命名这个节点
ros::NodeHandle n; //创建一个与ROS沟通的发布对象
ros::Publisher my_publisher_object = n.advertise<example_ros_msg::ExampleMessage>("example_topic", 1);
//"example_topic"为topic的名称,后面的数字"1"为queue size
example_ros_msg::ExampleMessage my_new_message;
//创建一个类型为ExampleMessage的变量
ros::Rate naptime(1.0); //create a ros object from the ros “Rate” class;
//set the sleep timer for 1Hz repetition rate (arg is in units of Hz)
my_new_message.header.stamp = ros::Time::now(); //初始化各项参数的值
my_new_message.header.seq=0; // 初始化各项参数的值
my_new_message.header.frame_id = "base_frame"; // 初始化各项参数的值
my_new_message.demo_int= 1; // 初始化各项参数的值
my_new_message.demo_double=100.0; //初始化各项参数的值
double sqrt_arg;
while (ros::ok())
{
my_new_message.header.seq++; //叠加seq的数值
my_new_message.header.stamp = ros::Time::now(); //更新时间标签
my_new_message.demo_int*=2.0; //倍乘
sqrt_arg = my_new_message.demo_double;
my_new_message.demo_double = sqrt(sqrt_arg);开根号
my_publisher_object.publish(my_new_message); // 发布以自定义message类型为格式的变量到topic上
naptime.sleep();
}
}
若以上这个节点是在自定义的message文件夹里面的,那么到这里就完成了,即只需要在源代码中添加对应的头文件。
若是在其他包中调用这个自定义的message包中的消息类型,这还需要编辑调用这个消息类型的包中的package.xml和CMakeLists.txt文件:
①编辑package.xml
添加一下语句:
<build_depend>example_ros_msg</build_depend>
<run_depend>example_ros_msg</run_depend>
②编辑CMakeLists.txt
在find_package
中添加自定义的message包
find_package(catkin REQUIRED COMPONENTS
roscpp
example_ros_msg
)
到这里就完成了调用其他包中的消息类型所需完成的工作了,下面就可以编译运行,看看是不是如我们预期的一样。
有一种情况会报错,是因为编辑好自定义的message包后,没有编译,也就没有生成对应的头文件,所以在编译节点的时候会报错
fatal error: example_ros_msg/ExampleMessage.h: 没有那个文件或目录
最后,在catkin_make
编译完成后,运行上述的节点(默认已经运行roscore)
rosrun example_ros_msg example_ros_message_publisher
然后在另一个terminal中运行
rostopic echo example_topic
查看是否有如下的输出:
header:
seq: 1
stamp:
secs: 1520818931
nsecs: 955151058
frame_id: base_frame
demo_int: 4
demo_double: 3.16227766017
---
header:
seq: 2
stamp:
secs: 1520818932
nsecs: 955130728
frame_id: base_frame
demo_int: 8
demo_double: 1.77827941004
---
若正确输出,则说明成功的调用了其他包中的消息类型。