cpp节点编写(ros1)

ROS1中,cpp对应的接口叫—roscpp

与ROS2一样,创建一个功能包之后,在该包的src(source)文件下新建cpp文件,先在工作空间下的 src/ 下创建一个功能包

1
2
roscd ros_workspace/src/
catkin_create_pkg test_pkg roscpp rospy std_msgs

进入 test_pkg/src/ ,创建一个cpp文件,

1
2
cd test_pkg/src
touch test.cpp

然后开始编写第一个cpp节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include "ros/ros.h"        // 包含ROS的核心头文件
#include "std_msgs/String.h" // 包含标准消息类型String的头文件
#include <sstream> // 包含字符串流处理的头文件

int main(int argc, char **argv){
// 初始化ROS节点,命名为"talker"
ros::init(argc, argv, "talker");

// 创建一个NodeHandle对象,用于与ROS系统通信
ros::NodeHandle n;

// 创建一个发布者对象,发布名为"chatter"的消息队列长度为1000
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);

// 设置循环频率为10Hz
ros::Rate loop_rate(10);

// 计数器变量,用于在发布的消息中增加计数值
int count = 0;

// 进入主循环,只要ROS系统正常运行就会一直执行
while(ros::ok()){
// 创建一个String类型的消息对象
std_msgs::String msg;

// 使用字符串流创建消息内容,包含"hello world"和当前计数值
std::stringstream ss;
ss << "hello world " << count;
msg.data = ss.str();

// 在控制台打印出即将发布的消息内容
ROS_INFO("%s", msg.data.c_str());

// 发布消息到"chatter"主题
chatter_pub.publish(msg);

// 处理回调函数,确保其他节点可以及时收到消息
ros::spinOnce();

// 按照设定的频率休眠一段时间
loop_rate.sleep();

// 增加计数器值
++count;
}

// 主程序返回0,表示成功结束
return 0;
}

与 ros2 的cpp节点大致是一样的,都有节点的初始化,只是使用的方法不同了

创建并编写好结点之后,修改CMakeList文件

1
2
3
4
5
6
7
# 指定src/下需要编译为可执行文件的源文件,前面节点名可以直接自己指定
add_executable(${PROJECT_NAME}_node src/test.cpp)

# 指定所要使用的链接库
target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES}

修改完CMakeList文件之后,就开始编译

1
2
3
roscd ros_workspace/
catkin_make
source ~/.bashrc

执行,先打开一个命令框执行 roscore

1
roscore

再打开一个窗口运行节点

1
rosrun test_pkg test_pkg_node

头文件的引用,在 ros1 下,cpp的 .h 头文件要放在功能包目录下的include/pkg_name/ 路径下,

创建好了头文件之后,需要引用头文件的cpp文件需要导入该头文件

1
#include "pkg_name/xxx.h"

编译功能包时,cpp文件中引用的头文件,ros会在该功能包的 include/ 文件下开始找,给出以上路径后就可以精确找到被引用的头文件

如果要引用同一工作空间其他包的头文件,那么在创建功能包时,需要依赖要引用头文件所在的包

1
catkin_create_pkg my_pkg roscpp rospy std_msgs test_pkg

包创建好之后,他的CMakeList修改没有区别跟其他的包,被引用头文件的包的CMakeList文件需要修改

1
2
3
4
5
6
catkin_package(
INCLUDE_DIRS include
# LIBRARIES test_pkg
# CATKIN_DEPENDS roscpp rospy std_msgs
# DEPENDS system_lib
)

这样修改之后,引用该包的头文件的包就能找到根据对应的路径找到需要引用的头文件了

launch文件的编写

因为,一个完整的ros程序,需要多个节点来完成所需实现的功能,而roslaunch一次性执行好多个节点的方法显然不够合理和高效,由此引出 launch文件。

launch文件就是一个xml格式的脚本文件,把需要启动的节点都写进launch文件 中,这样就可以通过roslaunch工具来调用launch文件,执行这个脚本文件就一次性启动所有的节点程序。

创建一个包 robot_bringup,在其路径下创建一个文件 launch,在 launch/ 下创建并编辑 startup.launch 文件,用于同时启动多个节点

1
2
3
4
5
6
catkin_create_pkg robot_bringup
cd robot_bringup
mkdir launch
cd launch/
touch startup.launch
subl startup.launch

编辑使之能同时运行 test_pkg_node 和 my_pkg_node 两个节点

1
2
3
4
5
6
# <launch> 是根标签
# <node> 是节点标签,至少要有三个属性 pkg type name, type是指节点名,name给所运行的节点指定名称,他会覆盖ros::init的节点名, output 可以将单个节点的标准输出到终端
<launch>
<node pkg="test_pkg" type="test_pkg_node" name="test_pkg_node" output="screen"/>
<node pkg="my_pkg" type="my_pkg_node" name="my_pkg_node" output="screen"/>
</launch>

编译并运行

1
2
3
catkin_make
source ~/.bashrc
roslaunch robot_bringup startup.launch

使用 include 标签,可以在当前 launch 文件中调用另外一个包的 launch文件

1
2
# find 命令可以直接搜索功能包的位置,代替直接使用绝对路径
<include file="$(find package-name)/launch-file-name">

创建新的功能包 third_pkg,在 src 中创建并编写 third_pkg.cpp

1
2
3
4
catkin_create_pkg third_pkg roscpp rospy std_msgs
cd third_pkg/src
touch third_pkg.cpp
subl third_pkg.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

#include "ros/ros.h"
#include"std_msgs/String.h"
#include<sstream>

int main(int argc,char **argv){

ros::init(argc,argv,"third_pkg");

ros::NodeHandle n;// 更新话题的消息格式为自定义的消息格式

ros::Publisher chatter_pub = n.advertise<std_msgs::String>("third_pkg",1000);

ros::Rate loop_rate(10);

int count = 0;

while(ros::ok()){

std_msgs::String msg;

std::stringstream ss;

ss<<"third pkg:"<<count;

msg.data = ss.str();

ROS_INFO("%s",msg.data.c_str());

chatter_pub.publish(msg);//将消息发布到话题中

ros::spinOnce();

loop_rate.sleep();

++count;
}

return 0;
}

修改CMakeList文件

1
2
3
4
5
add_executable(third_pkg_node src/third_pkg.cpp)

target_link_libraries(third_pkg_node
${catkin_LIBRARIES}
)

在 third_pkg/ 下创建一个 launch 文件夹,并在该文件中创建并编译 third_pkg.launch 文件

1
2
3
4
mkdir launch
cd launch
touch third_pkg.launch
subl third_pkg.launch
1
2
3
<launch>
<node pkg="third_pkg" type="third_pkg_node" name="third_pkg_node" output="screen"/>
</launch>

修改 robot_bringup/launch/ 下的 launch 文件

1
2
3
4
5
<launch>
<node pkg="test_pkg" type="test_pkg_node" name="test_pkg_node" respawn="true" output="screen"/>
<node pkg="my_pkg" type="my_pkg_node" name="my_pkg_node" required="true" output="screen"/>
<include file="$(find third_pkg)/launch/third_pkg.launch"/>
</launch>

然后编译运行

1
2
3
catkin_make
source ~/.bashrc
roslaunch robot_bringup startup.launch

好久没更新了,damn!