ROS官方中文教程:http://wiki.ros.org/cn/ROS/Tutorials/ 里面内容都很详细。
这里,简单介绍ROS系统的主要操作步骤:
一、安装并配置ROS环境
教程如下:https://blog.csdn.net/qq_38236355/article/details/97820398
二、创建ROS工作空间(catkin工作空间)
打开终端:
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
这样便创建了一个名为catkin_ws的工作空间,可以试着编译它
// 可以不用做,等到最后写完程序再一起编译
cd ~/catkin_ws/
catkin_make
// 这里catkin_make是ROS特有的,相当于依次调用了cmake和make指令,它会编译src文件夹下的所以工程
三、创建ROS程序包
在catkin_ws工作空间下创建:
cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
这将会创建一个名为beginner_tutorials的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,而std_msgs,rospy,roscpp是程序包的三个依赖包。
四、编写发布器节点
切换到之前创建的 beginner_tutorials package 路径下,创建一个src文件夹:
cd ~/catkin_ws/src/beginner_tutorials
mkdir -p ~/catkin_ws/src/beginner_tutorials/src
在 src里创建talker.cpp 文件,并将如下代码粘贴到文件内:
27 #include "ros/ros.h"
28 #include "std_msgs/String.h" //调用的ROS现有的消息文件String.msg,可替换成其它消息文件
29
30 #include
31
32 /**
33 * This tutorial demonstrates simple sending of messages over the ROS system.
34 */
35 int main(int argc, char **argv)
36 {
37 /**
38 * The ros::init() function needs to see argc and argv so that it can perform
39 * any ROS arguments and name remapping that were provided at the command line. For programmatic
40 * remappings you can use a different version of init() which takes remappings
41 * directly, but for most command-line programs, passing argc and argv is the easiest
42 * way to do it. The third argument to init() is the name of the node.
43 *
44 * You must call one of the versions of ros::init() before using any other
45 * part of the ROS system.
46 */
47 ros::init(argc, argv, "talker"); //节点名称 "talker"
48
49 /**
50 * NodeHandle is the main access point to communications with the ROS system.
51 * The first NodeHandle constructed will fully initialize this node, and the last
52 * NodeHandle destructed will close down the node.
53 */
54 ros::NodeHandle n; //开始节点句柄完全初始化节点
55
56 /**
57 * The advertise() function is how you tell ROS that you want to
58 * publish on a given topic name. This invokes a call to the ROS
59 * master node, which keeps a registry of who is publishing and who
60 * is subscribing. After this advertise() call is made, the master
61 * node will notify anyone who is trying to subscribe to this topic name,
62 * and they will in turn negotiate a peer-to-peer connection with this
63 * node. advertise() returns a Publisher object which allows you to
64 * publish messages on that topic through a call to publish(). Once
65 * all copies of the returned Publisher object are destroyed, the topic
66 * will be automatically unadvertised.
67 *
68 * The second parameter to advertise() is the size of the message queue
69 * used for publishing messages. If messages are published more quickly
70 * than we can send them, the number here specifies how many messages to
71 * buffer up before throwing some away.
72 */
73 ros::Publisher chatter_pub = n.advertise("chatter", 1000); //声明发布一个std_msgs::String类型的消息,可更换。主题名为"chatter",最多缓冲1000条消息
74
75 ros::Rate loop_rate(10); //循环频率(10HZ)
76
77 /**
78 * A count of how many messages we have sent. This is used to create
79 * a unique string for each message.
80 */
81 int count = 0; //计数的,没啥用
82 while (ros::ok())
83 {
84 /**
85 * This is a message object. You stuff it with data, and then publish it.
86 */
87 std_msgs::String msg; // 定义 std_msgs::String类型参数msg
88
89 std::stringstream ss; // std::stringstream类型参数 ss
90 ss << "hello world " << count; // 字符串传入ss
91 msg.data = ss.str(); //再由ss传给msg
92
93 ROS_INFO("%s", msg.data.c_str()); //显示msg内容,相当于cout,print
94
95 /**
96 * The publish() function is how you send messages. The parameter
97 * is the message object. The type of this object must agree with the type
98 * given as a template parameter to the advertise<>() call, as was done
99 * in the constructor above.
100 */
101 chatter_pub.publish(msg); //向话题发布消息
102
103 ros::spinOnce();
104
105 loop_rate.sleep(); //使对象休眠,以使剩余时间内正好以10hz频率发布消息
106 ++count;
107 }
108
109
110 return 0;
111 }
其中重要语句都已注释过了,将自己的程序对应填入其中即可。
五、编写订阅器节点
在 beginner_tutorials package 目录下创建 src/listener.cpp 文件,并粘贴如下代码:
28#include "ros/ros.h"
29 #include "std_msgs/String.h"
30
31 /**
32 * This tutorial demonstrates simple receipt of messages over the ROS system.
33 */
34 void chatterCallback(const std_msgs::String::ConstPtr& msg)
35 {
36 ROS_INFO("I heard: [%s]", msg->data.c_str()); //显示接受内容
37 }
38
39 int main(int argc, char **argv)
40 {
41 /**
42 * The ros::init() function needs to see argc and argv so that it can perform
43 * any ROS arguments and name remapping that were provided at the command line. For programmatic
44 * remappings you can use a different version of init() which takes remappings
45 * directly, but for most command-line programs, passing argc and argv is the easiest
46 * way to do it. The third argument to init() is the name of the node.
47 *
48 * You must call one of the versions of ros::init() before using any other
49 * part of the ROS system.
50 */
51 ros::init(argc, argv, "listener");
52
53 /**
54 * NodeHandle is the main access point to communications with the ROS system.
55 * The first NodeHandle constructed will fully initialize this node, and the last
56 * NodeHandle destructed will close down the node.
57 */
58 ros::NodeHandle n;
59
60 /**
61 * The subscribe() call is how you tell ROS that you want to receive messages
62 * on a given topic. This invokes a call to the ROS
63 * master node, which keeps a registry of who is publishing and who
64 * is subscribing. Messages are passed to a callback function, here
65 * called chatterCallback. subscribe() returns a Subscriber object that you
66 * must hold on to until you want to unsubscribe. When all copies of the Subscriber
67 * object go out of scope, this callback will automatically be unsubscribed from
68 * this topic.
69 *
70 * The second parameter to the subscribe() function is the size of the message
71 * queue. If messages are arriving faster than they are being processed, this
72 * is the number of messages that will be buffered up before beginning to throw
73 * away the oldest ones.
74 */
75 ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
76
77 /**
78 * ros::spin() will enter a loop, pumping callbacks. With this version, all
79 * callbacks will be called from within this thread (the main one). ros::spin()
80 * will exit when Ctrl-C is pressed, or the node is shutdown by the master.
81 */
82 ros::spin();
83
84 return 0;
85 }
同样,可根据自己代码要求更改填充内容。
六、编译
之前教程中使用 catkin_create_pkg 创建了 package.xml 和 CMakeLists.txt 文件。 在生成的 CMakeLists.txt末尾加入几条语句:
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
这会生成两个可执行文件, talker 和 listener, 默认存储到 devel space 目录下,具体是在~/catkin_ws/devel/lib/ 中。
如果在节点程序中用到了其它的库,如opencv,需要在CMakeList.txt中添加依赖,具体可参考 https://blog.csdn.net/qq_38236355/article/details/88864023
现在运行catkin_make:
# In your catkin workspace
catkin_make
七、运行节点
编译通过后便可以运行发布器和订阅器节点了。
1、打开一个终端:
roscore
# 这是运行所有ROS程序前首要运行的命令
2、新打开一个终端
cd catkin_ws
source devel/setup.bash
# 将当前工作空间设置在ROS工作环境最顶层
rosrun beginner_tutorials talker
3、再新打开一个终端
cd catkin_ws
source devel/setup.bash
rosrun beginner_tutorials listener
没有意外的话talker发送的消息在listener中就可以接收到了。
上述过程执行起来比较繁琐,有一款专门用于ROS的编辑软件roboware,可以自动生成节点模板和CMakeList.txt文件。下载地址:http://www.roboware.me/#/home