引言
最近项目中遇到一个需求:将 C++ 程序 (不是 ROS node,只是普通的 C++ 程序)中的变量发布到 ROS topic 上,以便 ROS 中的其他 node 进行后续处理。
原 C++ 程序比较复杂,我们希望尽量少修改原程序,只要输出其中某些变量的值即可,不要大规模改写成 ROS node 的形式,不要新建 ROS package。
在以往使用 ROS 的过程中,我们一般是借助 catkin 来编译 ROS node C++ 程序。这可以看成是将 C++ 程序放入 ROS 框架中,以 ROS 的标准形式来编译。现在这个项目需求正好相反,我们要将 ROS 的相关库(library)嵌入到普通 C++ 程序中,采用 C++ 标准的 cmake 方式来编译。这就要求我们对 cmake 和 catkin 的关系有比较深入的了解。
在查找资料的过程中,我们发现了一篇讲解 catkin 编译系统的文章,从最基本的命令行编译方式,到 makefile 文件编译,再到 catkin 编译,每一步发展的必要性都讲解的很清楚,看完之后,我们对 catkin 有了更深入的认识。
本文是一篇学习笔记,也可以看成是对原文的意译。
对原文感兴趣的读者可以移步这里 http://jbohren.com/tutorials/2014-02-12-gentle-catkin-intro/
预安装
原文例子中使用了 hydro 版本的 ROS,现在看来比较古老了,这里替换为 kinetic 版本。
- Ubuntu 16.04
- ROS kinetic (base 即可)
从最简单的例子开始
首先创建一个文件夹 hello_world_tutorial,存放我们的程序
mkdir hello_world_tutorial cd hello_world_tutorial
创建 C++ 源文件,名为 hello_world_node.cpp
:
// 为了与 ROS 交互,需要调用 ROS C++ APIs #include <ros/ros.h> // 标准的 C++ main 函数 int main(int argc, char** argv) { // 该命令告诉 ROS 初始化了一个 node,名为 hello_world_node ros::init(argc, argv, "hello_world_node"); // 在一般的 ROS node 程序中,我们会用 ros::NodeHandle nh 来启动 node 程序, // ros::NodeHandle nh 默认会调用 ros::start() 函数,程序关闭时也会自动调用 ros::shutdown() 函数。 // 我们也可以直接通过 ros::start() 和 ros::shutdown() 来手动控制 node 的开启和关闭 ros::start(); // 显示 hello, world! 信息 ROS_INFO_STREAM("Hello, world!"); // 用 ros::spin() 保持该程序运行,一直等待处理 subscribe 的数据 // 由于该程序并没有 sub,所以就是简单的保持程序不退出而已, 直到接受到终止信号 SIGINT (ctrl-c) ros::spin(); // 关闭 node 程序 ros::shutdown(); // 结束主程序 return 0; }