【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
前面我们安装了ROS环境,接着就可以开始进行ROS程序的开发了。在开发之前,我们有几个概念需要厘清一下。第一个是workspace,它相当于一个项目。毕竟,一个电脑上面可以有很多的workspace,也就相当于有很多的项目。第二个是package,它相当于功能块,功能块里面可以有很多的程序,package本身就是很多程序的一个集合。第三个就是node,直接把它看成独立的程序就可以了。
创建工作区是所有工作的第一步。可以通过创建workspace下面src目录的方法,直接进行创建,
mkdir -p ./catkin_ws/src
创建完成之后,就可以直接编译了。这个时候虽然什么也没有,但是catkin_make命令会帮我们自动创建build和dev这两个目录,
- cd ./catkin_ws
- catkin_make
有了工作区,就可以开始创建工作包了。工作包的创建方法也不复杂,主要使用catkin_create_pkg命令即可,前提是先进入src目录,
- cd ./catkin_ws/src
- catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
package里面也是有src目录的,虽然有点绕,这个我们可以稍微花点时间理解一下。现在假设有两个程序,一个是talker.cpp,一个是listener.cpp,他们都是放在package的src目录里面。所以第一步,先进入package里面的src目录,即,
./catkin_ws/src/beginner_tutorials/src
准备talker.cpp文件,
- #include "ros/ros.h"
- #include "std_msgs/String.h"
- #include <sstream>
-
- int main(int argc, char **argv)
- {
- ros::init(argc, argv, "talker");
- ros::NodeHandle n;
- ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
-
- ros::Rate loop_rate(10);
- int count = 0;
-
- while (ros::ok())
- {
- std_msgs::String msg;
-
- std::stringstream ss;
- ss << "hello world " << count;
- msg.data = ss.str();
-
- ROS_INFO("%s", msg.data.c_str());
- chatter_pub.publish(msg);
-
- ros::spinOnce();
-
- loop_rate.sleep();
- ++count;
- }
-
- return 0;
- }
接着准备listener.cpp文件,
- #include "ros/ros.h"
- #include "std_msgs/String.h"
-
- void chatterCallback(const std_msgs::String::ConstPtr& msg)
- {
- ROS_INFO("I heard: [%s]", msg->data.c_str());
- }
-
- int main(int argc, char **argv)
- {
-
- ros::init(argc, argv, "listener");
- ros::NodeHandle n;
-
- ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
- ros::spin();
-
- return 0;
- }
这里需要注意的是,相关的CMakeLists.txt文件不是src目录下面文件,而是package下面的文件。这一点很容易改错的。
-
- cmake_minimum_required(VERSION 2.8.3)
- project(beginner_tutorials)
-
- ## Find catkin and any catkin packages
- find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs genmsg)
-
- ## Declare ROS messages and services
- #add_message_files(FILES Num.msg)
- #add_service_files(FILES AddTwoInts.srv)
-
- ## Generate added messages and services
- generate_messages(DEPENDENCIES std_msgs)
-
- ## Declare a catkin package
- catkin_package()
-
- ## Build talker and listener
- include_directories(include ${catkin_INCLUDE_DIRS})
-
- add_executable(talker src/talker.cpp)
- target_link_libraries(talker ${catkin_LIBRARIES})
- add_dependencies(talker beginner_tutorials_generate_messages_cpp)
-
- add_executable(listener src/listener.cpp)
- target_link_libraries(listener ${catkin_LIBRARIES})
- add_dependencies(listener beginner_tutorials_generate_messages_cpp)
编译就非常简单了。需要回到workspace的目录,然后输入catkin_make就可以了,
- cd ./catkin_ws
- catkin_make
不出意外的话,我们在./catkin_ws/devel/lib/beginner_tutorials看到对应的可执行文件。
启动程序需要三个步骤。第一个步骤,设置一下rosrun的环境,即,
source devel/setup.sh
这样后期rosrun的时候,就可以直接启动node程序了。第二个步骤,输入roscore,这个相当于整个底层信息交换的大脑。第三个步骤,就是启动talker和listener了,
- rosrun beginner_tutorials talker
- rosrun beginner_tutorials listener
所有操作都完成之后,我们就可以看到talker程序这边在不断发送消息,而listener这边在不断地接收消息。这是一个完整的publish和subscribe程序对。
整个过程看上去自己要做的内容很少。这是因为ros已经帮助我们完成了大部分的工作,用ldd命令看下生成的程序就知道了,
- feixiaoxing@feixiaoxing-VirtualBox:~/Desktop/catkin_ws/devel/lib/beginner_tutorials$ ldd listener
- linux-vdso.so.1 (0x00007ffeb4bfe000)
- libroscpp.so => /opt/ros/noetic/lib/libroscpp.so (0x00007f2381bc9000)
- libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2381b69000)
- librosconsole.so => /opt/ros/noetic/lib/librosconsole.so (0x00007f2381b06000)
- libroscpp_serialization.so => /opt/ros/noetic/lib/libroscpp_serialization.so (0x00007f2381b01000)
- libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f238191f000)
- libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f2381904000)
- libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2381710000)
- libxmlrpcpp.so => /opt/ros/noetic/lib/libxmlrpcpp.so (0x00007f23816ec000)
- librostime.so => /opt/ros/noetic/lib/librostime.so (0x00007f23816bf000)
- libcpp_common.so => /opt/ros/noetic/lib/libcpp_common.so (0x00007f23816b1000)
- libboost_thread.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_thread.so.1.71.0 (0x00007f2381685000)
- libboost_chrono.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_chrono.so.1.71.0 (0x00007f2381677000)
- libboost_filesystem.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_filesystem.so.1.71.0 (0x00007f2381657000)
- libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f2381508000)
- /lib64/ld-linux-x86-64.so.2 (0x00007f2381db2000)
- librosconsole_log4cxx.so => /opt/ros/noetic/lib/librosconsole_log4cxx.so (0x00007f23814e8000)
- librosconsole_backend_interface.so => /opt/ros/noetic/lib/librosconsole_backend_interface.so (0x00007f23814e3000)
- liblog4cxx.so.10 => /lib/x86_64-linux-gnu/liblog4cxx.so.10 (0x00007f2381305000)
- libboost_regex.so.1.71.0 => /lib/x86_64-linux-gnu/libboost_regex.so.1.71.0 (0x00007f2381205000)
- libconsole_bridge.so.0.4 => /lib/x86_64-linux-gnu/libconsole_bridge.so.0.4 (0x00007f23811fd000)
- libapr-1.so.0 => /lib/x86_64-linux-gnu/libapr-1.so.0 (0x00007f23811c4000)
- libaprutil-1.so.0 => /lib/x86_64-linux-gnu/libaprutil-1.so.0 (0x00007f2381196000)
- libicui18n.so.66 => /lib/x86_64-linux-gnu/libicui18n.so.66 (0x00007f2380e97000)
- libicuuc.so.66 => /lib/x86_64-linux-gnu/libicuuc.so.66 (0x00007f2380cb1000)
- libuuid.so.1 => /lib/x86_64-linux-gnu/libuuid.so.1 (0x00007f2380ca6000)
- libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2380ca0000)
- libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f2380c65000)
- libexpat.so.1 => /lib/x86_64-linux-gnu/libexpat.so.1 (0x00007f2380c37000)
- libicudata.so.66 => /lib/x86_64-linux-gnu/libicudata.so.66 (0x00007f237f176000)