立即注册 找回密码

微雪课堂

搜索
微雪课堂 机器人操作系统(ROS) 查看内容

ROS基础系列教程3:ROS和C++编程认知

2020-9-13 20:37| 发布者: waveshare_yf| 查看: 352| 评论: 0|原作者: waveshare|来自: waveshare

摘要: 在我们之前的课程,大家已经配置好Ubuntu+Melodic的开发环境了吧!接下来我们就开始学习ROS编程相关的内容,这节内容主要是讲ROS的C++编程。关于C++,我们不会系统性的讲解,只是会对我们案例代码使用到的部分进行系 ...
  • 在我们之前的课程,大家已经配置好Ubuntu+Melodic的开发环境了吧!接下来我们就开始学习ROS编程相关的内容,这节内容主要是讲ROS的C++编程。关于C++,我们不会系统性的讲解,只是会对我们案例代码使用到的部分进行系统性的阐述,如果你有学习C++的兴趣,可以建议你购买《C++从入门到精通》一书,或者是前往“创客制造”官网 (https://www.ncnynl.com/)。
  • 在我们本节课的内容,我们会一步步带领大家在ROS下进行C++的开发,并对教程2当 中的小海龟教程,实现我们自己的代码控制。

关于ROS系统的基础认知

  • 我们在上一讲的内容当中给大家提到了节点和节点管理器两个概念,我们在启动小海龟 的时候有三个步骤,分别是:
    • 启动节点管理器(roscore)。
    • 启动小海龟显示节点(rosrun turtlrsim turtlesim_node)。
    • 启动小海龟控制节点(rosrun turtlesim turtle_teleop_key)。
  • 同时,我们也开启了节点关系图(rqt_graph),大家可以看到,是teleop_turtle发送了一个cmd_vel的数据给了turtlesim。




  • 这样的通讯方式在ROS里面叫做话题通讯,一个节点发布了一个话题,被另外一个节点 订阅到(也就是获得数据),而ROS Master在中间的作用就是传达消息的作用。我们这里不做出过多的阐述,在我们的后面的教程会有详细的介绍,你现在只要心里有这个概念就 可以。

创建ROS工作空间

  • 在ROS系统下,我们所有的项目都放在一个工作空间下,我们在工作空间下建立不同的功能包来实现不同的功能。这些功能包可以是你自己写的,也可以是你移植其他人的。
  • 我们需要先建立一个空间,并进入到这个工作空间下。我的工作空间名字叫 catkin_ws。打开终端执行以下代码。
mkdir ‐p ~/catkin_ws/src 
cd catkin_ws
  • 在进入工作空间后,我们需要先对工作空间进行编译。指令如下。
catkin_make
  • 编译成功后的catkin_ws文件夹内,会出现build和devel文件夹,这个是编译生成的。src文件夹内放的是各个功能包,build文件夹内放的是编译项,devel则是编译输出项。




  • 此时我们需要把当前工作空间的一个环境变量添加到我们的系统当中。这个文件在devel下面的setup.bash,为了一劳永逸的解决这个这个问题,我们还是在~/.bashrc终端配置文件下添加该内容。
source /home/youruser/catkin_ws/devel/setup.bash








  • 在这里我们可以看到,ros系统的环境和catkin_ws工作空间的环境,都已经生效。我们 的工作空间创建到此结束。

    创建功能包learning_cplus

  • 我们已经创建好了工作空间,并已经成功生效了环境变量。接下来我们需要创建一个功能包,这个功能包的名字根据我们这个功能包的作用来命名。比如我现在的功能包是用来学习ROS的C++编程,那么我的功能包名称就叫做learning_cplus。打开终端,输入下面指令。
cd catkin_ws/src 
catkin_create_pkg learning_cplus roscpp rospy std_msgs
  • 我们通过cd指令切换当前路径到src文件夹下,在该路径下使用catkin_create_pkg指令 来创建一个功能包。格式如下。
catkin_create_pkg 功能包名称 依赖项1 依赖项2 ......
  • 依赖项是你的这个功能包依赖于哪些功能模块,比如我的功能包,就导入了C++、Python和std_msgs(后面会有详细介绍)。然后返回到catkin_ws目录下进行编译。








  • 我们可以看到learning_cplus功能包在catkin_ws工作空间编译成功,我们生效一下环 境变量,通过roscd learning_cplus指令即可进入该功能包。
  • 目前我们的learning_cplus下有include(头文件)和src(源文件)两个文件夹,还有CMakelist.txt编译配置文件和package.xml功能包列表文件。到这里,我们的learning_cplus功能包创建结束。

关于package.xml文件的讲解

  • 我们这里先来看一下package.xml的原始文件,我会直接在代码内进行进行介绍。
<?xml version="1.0"?> 
<!‐‐ 当前xml版本 ‐‐> 
<package format="2"> 
<name>learning_cplus</name> 
<!‐‐ 功能包名称是learning_cplus,name,名称 ‐‐> 
<version>0.0.0</version> 
<!‐‐ 当前功能包版本是0.0.0,version,版本‐‐> 
<description>The learning_cplus package</description> 
<!‐‐ 当前功能包介绍,description,详细 ‐‐> 
<maintainer email="waveshare@todo.todo">waveshare</maintainer> 
<!‐‐ 当前维护者者信息(邮箱和昵称)‐‐>
<!‐‐ BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 ‐ ‐>
<license>TODO</license> 
<!‐‐ 协议版本,默认TODO就可以。有兴趣可以自行了解。‐‐> 
<!‐‐ <url type="website">http://wiki.ros.org/learning_cplus</url> ‐‐> 
<!‐‐ 可共享路径,你可以把你的这个包上传到ROS社区或者github。‐‐> 
<author email="jane.doe@example.com">Jane Doe</author> 
<!‐‐ 当前开发者信息(邮箱和昵称)‐‐> 
<!‐‐ The *depend tags are used to specify dependencies ‐‐> 
<!‐‐ Dependencies can be catkin packages or system dependencies ‐‐> 
<!‐‐ Examples: ‐‐> 
<!‐‐ Use depend as a shortcut for packages that are both build and exec dependencies ‐‐> 
<!‐‐ <depend>roscpp</depend> ‐‐> 
<!‐‐ Note that this is equivalent to the following: ‐‐> 
<!‐‐ <build_depend>roscpp</build_depend> ‐‐> 
<!‐‐ <exec_depend>roscpp</exec_depend> ‐‐> 
<!‐‐ Use build_depend for packages you need at compile time: ‐‐> 
<!‐‐ <build_depend>message_generation</build_depend> ‐‐>
<!‐‐ Use build_export_depend for packages you need in order to build ag ainst this package: ‐‐>
<!‐‐ <build_export_depend>message_generation</build_export_depend> ‐‐> 
<!‐‐ Use buildtool_depend for build tool packages: ‐‐> 
<!‐‐ <buildtool_depend>catkin</buildtool_depend> ‐‐> 
<!‐‐ Use exec_depend for packages you need at runtime: ‐‐> 
<!‐‐ <exec_depend>message_runtime</exec_depend> ‐‐> 
<!‐‐ Use test_depend for packages you need only for testing: ‐‐> 
<!‐‐ <test_depend>gtest</test_depend> ‐‐> 
<!‐‐ Use doc_depend for packages you need only for building documentati on: ‐‐> 
<!‐‐ <doc_depend>doxygen</doc_depend> ‐‐> 
<buildtool_depend>catkin</buildtool_depend> 
<!‐‐编译工具是catkin ‐‐> 
<build_depend>roscpp</build_depend> 
<!‐‐编译依赖roscpp ‐‐> 
<build_depend>rospy</build_depend> 
<!‐‐编译依赖rospy ‐‐> 
<build_depend>std_msgs</build_depend> 
<!‐‐编译依赖std_msgs ‐‐>
<build_export_depend>roscpp</build_export_depend> 
<!‐‐编译输出依赖roscpp ‐‐>
<build_export_depend>rospy</build_export_depend> 
<!‐‐编译输出依赖rospy ‐‐> 
<build_export_depend>std_msgs</build_export_depend> 
<!‐‐编译输出依赖std_msgs ‐‐> 
<exec_depend>roscpp</exec_depend> 
<!‐‐运行依赖roscpp ‐‐> 
<exec_depend>rospy</exec_depend> 
<!‐‐运行依赖rospy ‐‐> 
<exec_depend>std_msgs</exec_depend>
<!‐‐运行依赖std_msgs ‐‐> 
<!‐‐ The export tag contains other, unspecified, tags ‐‐> 
<export> 
<!‐‐ Other tools can request additional information be placed here ‐‐>

<!‐‐ 输出 ‐‐> 
</export> 
</package>
  • 这是一个原始的package.xml文件,十分详细。我们也在接下来的例程当中,详细的讲 解package.xml文件该如何去编写。

关于CMakeList.txt文件的讲解

  • CMakeList.txt文件是CMake编译系统编译软件包过程的输入文件。任何CMake兼容包都包含一个或多个CMakeLists.txt文件,这些文件描述了如何编译代码以及将其安装到哪里。将CMakeLists.txt文件应用于一个catkin项目时,它就作为一个标准的附带一些限制条件的vanilla CMakeLists.txt文件。使用CMake编译程序时,cmake指令依据 CMakeLists.txt文件生成makefiles文件,make命令再依据makefiles文件编译链接生成可 执行文件
  • catkin是ROS官方的一个编译构建系统,是原本的ROS的编译构建系统rosbuild的发展。catkin_make是将cmake与make的编译方式做了一个封装的指令工具,规范了工作路径与生成文件路径。 CMakeList.txt的一个总体结构和顺序如下。

    • 必需的CMake版本:cmake_minimum_required()
      cmake_minimum_required(VERSION 3.0.2)
    • 软件包名:project()
      project(learning_cplus)
    • 查找编译依赖的其他CMake/Catkin包(声明依赖库):find_package()
     ## Find catkin macros and libraries 
     ## if COMPONENTS list like find_package(catkin REQUIRED COMPONENTS xyz) 
     ## is used, also find other catkin packages 
     find_package(catkin REQUIRED COMPONENTS 
     roscpp 
     rospy 
     std_msgs 
     ) 
     ## System dependencies are found with CMake's conventions 
     # find_package(Boost REQUIRED COMPONENTS system)
    
    • 启动Python模块支持:catkin_python_package()

      ## Uncomment this if the package has a setup.py. This macro ensures 
      ## modules and global scripts declared therein get installed
      
      ## See http://ros.org/doc/api/catkin/html/user_guide/setup_dot_py.html 
      # catkin_python_setup()
      
      • 消息/服务/操作(Message/Service/Action)生成器: add_message_files(),add_service_files(),add_action_files()
     ################################################ 
     ## Declare ROS messages, services and actions ##
     ################################################ 
     ## To declare and build messages, services or actions from within this
     ## package, follow these steps:
     ## * Let MSG_DEP_SET be the set of packages whose message types you use i n
     ## your messages/services/actions (e.g. std_msgs, actionlib_msgs, ...). 
     ## * In the file package.xml: 
     ## * add a build_depend tag for "message_generation"
     ## * add a build_depend and a exec_depend tag for each package in MSG_DE P_SET 
     ## * If MSG_DEP_SET isn't empty the following dependency has been pulled in
     ## but can be declared for certainty nonetheless: 
     ## * add a exec_depend tag for "message_runtime"
     ## * In this file (CMakeLists.txt): 
     ## * add "message_generation" and every package in MSG_DEP_SET to 
     ## find_package(catkin REQUIRED COMPONENTS ...) 
     ## * add "message_runtime" and every package in MSG_DEP_SET to 
     ## catkin_package(CATKIN_DEPENDS ...) 
     ## * uncomment the add_*_files sections below as needed
     ## and list every .msg/.srv/.action file to be processed 
     ## * uncomment the generate_messages entry below 
     ## * add every package in MSG_DEP_SET to generate_messages(DEPENDENCIES ...) 
     ## Generate messages in the 'msg' folder 
     # add_message_files( 
     # FILES 
     # Message1.msg 
     # Message2.msg 
     # ) 
     ## Generate services in the 'srv' folder
     # add_service_files( 
     # FILES 
     # Service1.srv 
     # Service2.srv 
     # ) 
     ## Generate actions in the 'action' folder 
     # add_action_files( 
     # FILES 
     # Action1.action
     # Action2.action 
     # )
    
    • 调用消息/服务/操作生成:generate_messages()

      ## Generate added messages and services with any dependencies listed here 
      # generate_messages( 
      # DEPENDENCIES 
      # std_msgs 
      # )
      
    • 动态重新配置参数:generate_dynamic_reconfigure_options()
      ################################################ 
      ## Declare ROS dynamic reconfigure parameters ## 
      ################################################ 
      ## To declare and build dynamic reconfigure parameters within this 
      ## package, follow these steps: 
      ## * In the file package.xml: 
      ## * add a build_depend and a exec_depend tag for "dynamic_reconfigure" 
      ## * In this file (CMakeLists.txt): 
      ## * add "dynamic_reconfigure" to 
      ## find_package(catkin REQUIRED COMPONENTS ...) 
      ## * uncomment the "generate_dynamic_reconfigure_options" section below 
      ## and list every .cfg file to be processed 
      ## Generate dynamic reconfigure parameters in the 'cfg' folder 
      # generate_dynamic_reconfigure_options( 
      # cfg/DynReconf1.cfg 
      # cfg/DynReconf2.cfg 
      # )
      
    • 指定包编译信息导出:catkin_package()

      ################################### 
      ## catkin specific configuration ## 
      ################################### 
      ## The catkin_package macro generates cmake config files for your package 
      ## Declare things to be passed to dependent projects 
      ## INCLUDE_DIRS: uncomment this if your package contains header files 
      ## LIBRARIES: libraries you create in this project that dependent project s also need 
      ## CATKIN_DEPENDS: catkin_packages dependent projects also need 
      ## DEPENDS: system dependencies of this project that dependent projects a lso need 
      catkin_package( 
      # INCLUDE_DIRS include 
      # LIBRARIES learning_cplus 
      # CATKIN_DEPENDS roscpp rospy std_msgs 
      # DEPENDS system_lib 
      )
      
    • 添加要编译的库和可执行文件:add_library()/add_executable()/target_link_libraries()

      ########### 
      ## Build ## 
      ########### 
      ## Specify additional locations of header files
      ## Your package locations should be listed before other locations 
      include_directories( 
      # include 
      ${catkin_INCLUDE_DIRS} 
      ) 
      ## Declare a C++ library 
      # add_library(${PROJECT_NAME} 
      # src/${PROJECT_NAME}/learning_cplus.cpp 
      # ) 
      ## Add cmake target dependencies of the library 
      ## as an example, code may need to be generated before libraries 
      ## either from message generation or dynamic reconfigure
      
      # add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 
      ## Declare a C++ executable 
      ## With catkin_make all packages are built within a single CMake context 
      ## The recommended prefix ensures that target names across packages do n't collide 
      # add_executable(${PROJECT_NAME}_node src/learning_cplus_node.cpp) 
      ## Rename C++ executable without prefix 
      ## The above recommended prefix causes long target names, the following renames the 
      ## target back to the shorter version for ease of user use
      ## e.g. "rosrun someones_pkg node" instead of "rosrun someones_pkg someo nes_pkg_node" 
      # set_target_properties(${PROJECT_NAME}_node PROPERTIES OUTPUT_NAME node PREFIX "") 
      ## Add cmake target dependencies of the executable 
      ## same as for the library above 
      # add_dependencies(${PROJECT_NAME}_node ${${PROJECT_NAME}_EXPORTED_TARGE TS} ${catkin_EXPORTED_TARGETS}) 
      ## Specify libraries to link a library or executable target against 
      # target_link_libraries(${PROJECT_NAME}_node 
      # ${catkin_LIBRARIES} 
      # )
      
    • 安装规则:install()

      #############
      ## Install ## 
      ############# 
      # all install targets should use catkin DESTINATION variables 
      # See http://ros.org/doc/api/catkin/html/adv_user_guide/variables.html 
      ## Mark executable scripts (Python etc.) for installation 
      ## in contrast to setup.py, you can choose the destination 
      # catkin_install_python(PROGRAMS 
      # scripts/my_python_script 
      # DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
      # ) 
      ## Mark executables for installation 
      ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/buildin g_executables.html 
      # install(TARGETS ${PROJECT_NAME}_node 
      # RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} 
      # ) 
      ## Mark libraries for installation 
      ## See http://docs.ros.org/melodic/api/catkin/html/howto/format1/buildin g_libraries.html 
      # install(TARGETS ${PROJECT_NAME} 
      # ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 
      # LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION} 
      # RUNTIME DESTINATION ${CATKIN_GLOBAL_BIN_DESTINATION} 
      # ) 
      ## Mark cpp header files for installation 
      # install(DIRECTORY include/${PROJECT_NAME}/ 
      # DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION} 
      # FILES_MATCHING PATTERN "*.h" 
      # PATTERN ".svn" EXCLUDE 
      # ) 
      ## Mark other files for installation (e.g. launch and bag files, etc.) 
      # install(FILES 
      # # myfile1 
      # # myfile2 
      # DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION} 
      # )
      
    • 测试编译:catkin_add_gtest()

      ############# 
      ## Testing ## 
      ############# 
      ## Add gtest based cpp test target and link libraries 
      # catkin_add_gtest(${PROJECT_NAME}‐test test/test_learning_cplus.cpp)
      # if(TARGET ${PROJECT_NAME}‐test)
      # target_link_libraries(${PROJECT_NAME}‐test ${PROJECT_NAME}) 
      # endif() 
      ## Add folders to be run by python nosetests 
      # catkin_add_nosetests(test)
      
    • 简单的说,首先是CMake版本,这玩意是我们的编译工具首先做声明。

    • 接下来是我们这个功能包的名字。
    • 第三是编译依赖项,我们的这个包编译的时候,需要依赖哪些文件什么的。
    • 第四是Python编译模块的,如果你没有Python的全局脚本,这玩意就不需要。
    • 第五是消息、服务、动作三大生成,这三个也是我们ROS系统的一个核心。
    • 第六是调用了哪些外部的消息包什么的(后面会有详细介绍)。
    • 第七是我们的cfg配置文件,配置一些rviz格式啊,记录一些配置参数啊等等。
    • 第八是我们的以个编译输出配置,都依赖什么,要输出什么,在这个地方会记录的清清楚楚。
    • 第九是我们需要编译的的代码和编译时候要用到的库,这两个需要给连接起来。
    • 第十就是我们的一个按照规则是什么样的。
    • 最后就是我们的测试编译配置。
    • 这是一个CMakeList.txt模板文件的一个内容,我们在实际做的时候用到的写,没用的 可以直接删除。
  • 以上是我个人对CMakeList.txt的一个认知。如果有错误或者概念混肴的情况,希望大 家积极指出。

    使用C++实现ROS

  • 我们这一讲的内容主要是ROS的C++实现,在这里,我们会通过编写一个发布节点和订阅节点的方式,让大家一睹ROS的真面目。
  • 我们先进入learning_cplus功能包内,进入src文件夹内,创建一个发布节点。(之前 有提到src放的是什么哟~)。
roscd learning_cplus 
cd src 
touch publisher.cpp




  • 发布节点publisher.cpp内容如下。建议大家自行手打。
#include "ros/ros.h" //导入ROS系统包含核心公共头文件 
#include "std_msgs/String.h" //导入std_msgs/String消息头文件,这个是由std_m sgs包的string.msg文件自动生成。
#include <sstream> 
int main(int argc, char **argv) 
{ 
    ros::init(argc, argv, "talker"); //初始化ROS,指定节点名称为“talker”,节点 名称要保持唯一性。名称定义参考 
    ros::NodeHandle n; //实例化节点 
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1 000); //发布一个消息类型为std_msgs/String,命名为chatter的话题。 
    //定义消息队列大小为1000,即超过1000条消息之后,旧的消息就会丢弃。
    ros::Rate loop_rate(10); //指定发布消息的频率,这里指10Hz,也即每秒10次 
    //通过 Rate::sleep()来处理睡眠的时间来控制对应的发布频率。 
    int count = 0; 
    while (ros::ok()) 
    { 
        /* 
        默认roscpp会植入一个SIGINT处理机制,当按下Ctrl‐C,就会让ros::ok()返回false, 那循环就会结束。 
        ros::ok() 返回false的几种情况: 
        SIGINT收到(Ctrl‐C)信号 
        另一个同名节点启动,会先中止之前的同名节点 
        ros::shutdown()被调用
        所有的ros::NodeHandles被销毁 
        */ 
        std_msgs::String msg; 
        std::stringstream ss; 
        ss << "hello world " << count; 
        msg.data = ss.str(); 
        //实例化消息msg, 定义字符串流“hello world”并赋值给ss, 最后转成为字符串赋值给 msg.data 
        ROS_INFO("%s", msg.data.c_str()); //输出调试信息 
        chatter_pub.publish(msg); //发布msg 
        ros::spinOnce(); 
        //不是必需的,但是保持增加这个调用,是好习惯 
        //如果程序里也有订阅话题,就必需,否则回调函数不能起作用 
        loop_rate.sleep(); 
        //根据之前ros::Rate loop_rate(10)的定义来控制发布话题的频率。定义10即为每秒1 0次
        ++count; 
    } 
    return 0; 
}
  • 发布节点的功能就是发布hello world并跟一个计数。发布节点的名称叫做talker,发布 的话题名称叫做chatter,发布的内容是hello world + 计数。逻辑很清晰,就是从main函数,从上往下的执行,只要Master节点管理器不死,就会移植发布。
  • 有了发布节点,那么接下来我们需要做一个订阅节点来接收这些数据。我们订阅节点由 listener.cpp实现。
roscd learning_cplus 
cd src 
touch listener.cpp
  • 订阅节点publisher.cpp内容如下。建议大家自行手打。
#include "ros/ros.h" //导入ROS系统包含核心公共头文件 
#include "std_msgs/String.h" //导入std_msgs/String消息头文件,这个是由std_m sgs包的string.msg文件自动生成。 
/* 
定义回调函数chatterCallback,当收到chatter话题的消息就会调用这个函数。
消息通过boost shared_ptr(共享指针)来传递。 
但收到消息,通过ROS_INFO函数显示到终端 
*/ 
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,指定节点名称为“listener” 
    ros::NodeHandle n; //实例化节点 
    ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback); 
    /* 
    定义订阅节点,名称为chatter,指定回调函数chatterCallback 
    但收到消息,则调用函数chatterCallback来处理。 
    参数1000,定义队列大小,如果处理不够快,超过1000,则丢弃旧的消息 
    */ 

     ros::spin(); //调用此函数才真正开始进入循环处理,直到 ros::ok()返回false才停 止。
     return 0; 
 }
  • 订阅节点是检测到有chatter内容,需要去打印出来这个内容。由于是监听的,所以需要使用类似中断的方式,也就是信号回调来实现。
  • 还是老样子。初始化、实例化,然后检测chatter话题,如果有,跳到chatterCallBack 执行,没有就一直循环。
  • 我们的发布节点和订阅节点都已经写好,那么接下来就需要写CMakeList.txt。 首先是find_package依赖项,修改如下。

    find_package(catkin REQUIRED COMPONENTS 
    roscpp 
    rospy 
    std_msgs
    message_generation
    )
    
  • 调用生成的消息修改如下。

## Generate added messages and services with any dependencies listed here 
generate_messages( 
DEPENDENCIES
std_msgs 
)
  • 个人编译输出配置修改如下。
################################### 
## catkin specific configuration ## 
################################### 
## The catkin_package macro generates cmake config files for your package 
## Declare things to be passed to dependent projects 
## INCLUDE_DIRS: uncomment this if your package contains header files 
## LIBRARIES: libraries you create in this project that dependent project s also need 
## CATKIN_DEPENDS: catkin_packages dependent projects also need 
## DEPENDS: system dependencies of this project that dependent projects a lso need 
catkin_package( 
# INCLUDE_DIRS include 
# LIBRARIES learning_cplus
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime 
# DEPENDS system_lib 
)
  • 我没需要添加编译项和编译输出项,打开我们的CMakeList.txt文件,在Build位置添加 如下内容。
include_directories(include ${catkin_INCLUDE_DIRS}) 
add_executable(publisher src/publisher.cpp) 
target_link_libraries(publisher ${catkin_LIBRARIES}) 
add_dependencies(publish learning_cplus_generate_messages_cpp) 
add_executable(listener src/listener.cpp) 
target_link_libraries(listener ${catkin_LIBRARIES}) 
add_dependencies(listener learning_cplus_generate_messages_cpp)
  • 至于为什么这样修改呢,希望大家自己去对照下上面的CMakeList讲解进行理解。我的 CMakeList.txt如下。
cmake_minimum_required(VERSION 3.0.2) 
#Cmake版本 
project(learning_cplus) 
#功能包名称 
find_package(catkin REQUIRED COMPONENTS 
roscpp 
rospy 
std_msgs 
message_generation 
) 
#找寻依赖包 
generate_messages( 
DEPENDENCIES 
std_msgs 
) 
#调用已生成的消息,我们的头文件有用到 
catkin_package( 
# INCLUDE_DIRS include 
# LIBRARIES learning_cplus 
CATKIN_DEPENDS roscpp rospy std_msgs message_runtime
# DEPENDS system_lib 
) 
#编译依赖配置
include_directories(include ${catkin_INCLUDE_DIRS}) 
add_executable(publisher src/publisher.cpp) 
target_link_libraries(publisher ${catkin_LIBRARIES}) 
add_dependencies(publisher learning_cplus_generate_messages_cpp) 
add_executable(listener src/listener.cpp) 
target_link_libraries(listener ${catkin_LIBRARIES}) 
add_dependencies(listener learning_cplus_generate_messages_cpp)
  • 接下来配置我们的package.xml文件,配置内容很少,直接贴出我的package.xml代 码。
<?xml version="1.0"?> 
<package format="2"> 
<name>learning_cplus</name> 
<version>0.0.0</version> 
<description>这是学习ROS C++编程的功能包</description> 
<maintainer email="1692697820@qq.com">waveshare</maintainer> 
<license>TODO</license> 
<author email="1692697820@qq.com">waveshare</author> 
<buildtool_depend>catkin</buildtool_depend> 
<build_depend>roscpp</build_depend> 
<build_depend>rospy</build_depend> 
<build_depend>std_msgs</build_depend> 
<build_depend>message_generation</build_depend> 
<build_export_depend>roscpp</build_export_depend> 
<build_export_depend>rospy</build_export_depend> 
<build_export_depend>std_msgs</build_export_depend> 
<exec_depend>roscpp</exec_depend>
<exec_depend>rospy</exec_depend>
<exec_depend>std_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend> 
<export> 
</export> 
</package>

编译并执行我们的learning_cplus功能包

  • 在经历了漫长编写之后,终于进入了我们激动人心的环节——编译我们的 learning_cplus功能包。
  • 我们打开一个终端,进入catkin_ws路径,执行catkin_make进行编译。如果你没用写错的话,看到的应该是这样的。编译成功记得重新source一下,不然可能找不到这个功能包。




  • 到了这里,我们的开发就算是结束了,接下来的便是应用。我们需要先启动一个ROS Master节点管理器,然后分别启动listener订阅节点和publisher发布节点,在这里我们需 要启动三个终端。

    • 启动ROS Master节点管理器。

    roscore

    • 启动listener订阅节点。

    rosrun learning_cplus listener

    • 启动publisher发布节点。

    rosrun learning_cplus publisher

那么你看到的,会是这样的





  • 这样看着不够直观,我们来启动一下节点关系图,它是这样的。




  • 可以看到,talker节点个lisrener节点了一个chatter。但是应该是publisher给,这里怎么成talker了呢?不要急,我们先去看一下publisher.cpp的代码,原来是我们初始化的节点叫做talker,并不是BUG~~~
  • 到这里就结束了吗?并没有,接下来给大家介绍一些ROS的小工具,比如上面的rqt_graph就是来查看当前各个节点通讯关系的。
  • 拿到了一个别人的ROS功能包只能用却无法和自己的对接数据?没关系,运行一下它的功能包,开一个rqt_graph,一目了然。
  • 咳咳,重点来了,接下来我要说的小工具是rostopic。
rostopic list:查看当前话题都有哪些。 
rostopic echo 话题名:查看该话题的数据。
rostopic pub 话题名 功能包数据:发布指定内容到指定话题。












小乌龟游啊游

  • 大家还记我们在安装ROS成功之后运行的小乌龟吗?没错,就是teleop_turtle发送了一个cmd_vel的数据给了turtlesim这个!




  • 那么我们是不是也可以写一个发布节点来控制小乌龟呢?欧克,动手试一下!
  • 首先我们在这个节点关系当中,cmd_vel话题是核心,那么我们现在启动小乌龟,看看 以下cmd_vel的数据内容。

    • 启动ROS Master节点管理器。

      roscore

    • 启动小乌龟节点。

      rosrun turtlesim turtlesim_node

    • 启动小乌龟控制节点。

      rosrun turtlesim turtle_teleop_key

    • rostopic查看cmd_vel数据。

    rostopic echo /cmd_vel





  • 我们可以看到,cmd_vel的内容是这样的,那么我们来尝试一下通过rostopic发送 cmd_vel来控制以下小乌龟。
rostopic pub /turtle1/cmd_vel geometry_msgs/Twist  
"linear: 
x: 5.0 
y: 5.0 
z: 0.0 
angular: 
x: 0.0 
y: 2.0 
z: 2.0"




  • 我的小乌龟撞墙了,所以会有一个WARM警告。
  • 欧克,现在cmd_vel搞清楚了,那么我们就来写一个发布节点来控制小乌龟(数据先随便写,先动起来。关于cmd_vel的内容,会在我们的雷达车有详细介绍)
  • 还是进入我们的learning_cplus功能包的src目录下,创建wugui.cpp文件。
roscd learning_cplus 
cd src 
touch wugui.cpp
  • 其实设计思路就是就是发布cmd_vel数据就可以了,我的代码如下。
#include "ros/ros.h" //导入ROS系统包含核心公共头文件 
#include "std_msgs/String.h" //导入std_msgs/String消息头文件,这个是由std_m sgs包的string.msg文件自动生成。 
#include "geometry_msgs/Twist.h" //导入geometry_msgs/Twist消息头文件,这个 是由geometry_msgs包的twist.msg文件自动生成。
int main(int argc,char **argv) 
{ 
ros::init(argc,argv,"wugui"); ////初始化ROS,指定节点名称为“wugui”,节点名 称要保持唯一性。名称定义参考 
ros::NodeHandle n; //实例化节点 
ros::Publisher pub = n.advertise<geometry_msgs::Twist>("/turtle1/cmd_ve l",1000); 
//发布一个消息类型为geometry_msgs::Twist,命名为turtle1/cmd_vel的话题。 
//定义消息队列大小为1000,即超过1000条消息之后,旧的消息就会丢弃。 
ros::Rate loop_rate(10); //指定发布消息的频率,这里指10Hz,也即每秒10次 
//通过 Rate::sleep()来处理睡眠的时间来控制对应的发布频率。 
geometry_msgs::Twist msg; //实例化消息msg
while (ros::ok()) 
{ 
//为msg赋值 
msg.linear.x = 0.5; 
msg.linear.y = 0; 
msg.linear.z = 0; 
msg.angular.x = 0; 
msg.angular.y = 0; 
msg.angular.z = 0.5; 
pub.publish(msg); //发布msg 
ros::spinOnce();
//不是必需的,但是保持增加这个调用,是好习惯 
//如果程序里也有订阅话题,就必需,否则回调函数不能起作用 
loop_rate.sleep(); 
//根据之前ros::Rate loop_rate(10)的定义来控制发布话题的频率。定义10即为每秒1 0次
} 
return 0; 
}
  • 然后就是修改CMakeList.txt和package.xml,主要是要引入geometry_msgs功能包(cmd_vel在这个功能包里面,我们在安装ROS的时候已经自动安装好的)。
  • 我的CMakeList.txt内容如下。
cmake_minimum_required(VERSION 3.0.2) 
project(learning_cplus) 
find_package(catkin REQUIRED COMPONENTS 
roscpp 
rospy 
std_msgs 
message_generation 
geometry_msgs 
) 
generate_messages( 
DEPENDENCIES
std_msgs 
geometry_msgs 
) 
catkin_package( 
# INCLUDE_DIRS include 
# LIBRARIES learning_cplus 
CATKIN_DEPENDS roscpp rospy std_msgs geometry_msgs message_runtime
# DEPENDS system_lib 
) 
include_directories(include ${catkin_INCLUDE_DIRS}) 
add_executable(publisher src/publisher.cpp) 
target_link_libraries(publisher ${catkin_LIBRARIES})
add_dependencies(publisher learning_cplus_generate_messages_cpp) 
add_executable(listener src/listener.cpp) 
target_link_libraries(listener ${catkin_LIBRARIES})
add_dependencies(listener learning_cplus_generate_messages_cpp) 
add_executable(wugui src/wugui.cpp) 
target_link_libraries(wugui ${catkin_LIBRARIES}) 
add_dependencies(wugui learning_cplus_generate_messages_cpp)
  • 我的package.xml内容如下。
<?xml version="1.0"?> 
<package format="2"> 
<name>learning_cplus</name> 
<version>0.0.0</version> 
<description>这是学习ROS C++编程的功能包</description> 
<maintainer email="1692697820@qq.com">waveshare</maintainer> 
<license>TODO</license> 
<author email="1692697820@qq.com">waveshare</author> 
<buildtool_depend>catkin</buildtool_depend> 
<build_depend>roscpp</build_depend> 
<build_depend>rospy</build_depend>

<build_depend>std_msgs</build_depend> 
<build_depend>message_generation</build_depend> 
<build_depend>geometry_msgs</build_depend> 
<build_export_depend>roscpp</build_export_depend>
<build_export_depend>rospy</build_export_depend> 
<build_export_depend>std_msgs</build_export_depend> 
<build_export_depend>geometry_msgs</build_export_depend> 
<exec_depend>roscpp</exec_depend> 
<exec_depend>rospy</exec_depend> 
<exec_depend>std_msgs</exec_depend> 
<exec_depend>message_runtime</exec_depend>
<exec_depend>geometry_msgs</exec_depend> 
<export> 
</export> 
</package>
  • 接下来进行编译,然后分别启动ROS Master节点管理器 turtlesim_node节点、wugui节点。效果如下。




  • 关于ROS下C++编程的介绍就到这里,接下来还会有实际案例来让大家继续学习。
  • 最后的这个小乌龟例程是突发奇想添加上来的,我觉得这样可以让大家看到ROS的一个效果,而不是干巴巴的代码和理论。
  • 最最最最后,友情提示大家,这个cmd_vel很重要!!!(PS:如果你要设计雷达车 的话)
    请期待接下来的内容~

22

顶一下

刚表态过的朋友 (22 人)

关键词ROS 机器人

最新评论

微雪官网|产品资料|手机版|小黑屋|微雪课堂. ( 粤ICP备05067009号 )

GMT+8, 2020-11-28 01:19 , Processed in 0.019335 second(s), 13 queries .