欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Chapter 2. ROS 创建和编译功能包

程序员文章站 2022-03-05 12:20:47
...
1. 创建ROS功能包

使用catkin_create_pkg命令来创建一个新的catkin程序包。
首先切换到之前通过创建catkin工作空间教程创建的catkin工作空间中的src目录下:

~/ros_workspace$ cd src

接着使用catkin_create_pkg命令来创建一个名为’beginner_tutorials’的新程序包,这个程序包依赖于std_msgs、roscpp和rospy:

~/ros_workspace/src$ catkin_create_pkg my_demo roscpp rospy std_msgs

创建成功后,提示如下:

Created file my_demo/package.xml
Created file my_demo/CMakeLists.txt
Created folder my_demo/include/my_demo
Created folder my_demo/src
Successfully created files in /home/nic/ros_workspace/src/my_demo. Please adjust the values in package.xml.

这将会创建一个名为my_demo的文件夹,这个文件夹里面包含一个package.xml文件和一个CMakeLists.txt文件,这两个文件都已经自动包含了部分你在执行catkin_create_pkg命令时提供的信息。

catkin_create_pkg命令会要求你输入package_name,如果有需要你还可以在后面添加一些需要依赖的其它程序包:

# This is an example, do not try to run this
# catkin_create_pkg <package_name> [depend1] [depend2] [depend3]

catkin_create_pkg命令也有更多的高级功能,这些功能在catkin/commands/catkin_create_pkg中有描述。

2. 编译ROS功能包

采用CLion开发环境进行编译

CLion的安装及**请参照此文

(1)创建节点 my_demo
~/ros_workspace/src/my_demo/src$ gedit my_demo.cpp

将一下示例代码复制到my_demo.cpp中:

/*
 * Copyright (C) 2008, Morgan Quigley and Willow Garage, Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */
// %Tag(FULLTEXT)%
// %Tag(ROS_HEADER)%
#include "ros/ros.h"
// %EndTag(ROS_HEADER)%
// %Tag(MSG_HEADER)%
#include "std_msgs/String.h"
// %EndTag(MSG_HEADER)%

#include <sstream>

/**
 * This tutorial demonstrates simple sending of messages over the ROS system.
 */
int main(int argc, char **argv)
{
    /**
     * The ros::init() function needs to see argc and argv so that it can perform
     * any ROS arguments and name remapping that were provided at the command line.
     * For programmatic remappings you can use a different version of init() which takes
     * remappings directly, but for most command-line programs, passing argc and argv is
     * the easiest way to do it.  The third argument to init() is the name of the node.
     *
     * You must call one of the versions of ros::init() before using any other
     * part of the ROS system.
     */
// %Tag(INIT)%
    ros::init(argc, argv, "talker");
// %EndTag(INIT)%

    /**
     * NodeHandle is the main access point to communications with the ROS system.
     * The first NodeHandle constructed will fully initialize this node, and the last
     * NodeHandle destructed will close down the node.
     */
// %Tag(NODEHANDLE)%
    ros::NodeHandle n;
// %EndTag(NODEHANDLE)%

    /**
     * The advertise() function is how you tell ROS that you want to
     * publish on a given topic name. This invokes a call to the ROS
     * master node, which keeps a registry of who is publishing and who
     * is subscribing. After this advertise() call is made, the master
     * node will notify anyone who is trying to subscribe to this topic name,
     * and they will in turn negotiate a peer-to-peer connection with this
     * node.  advertise() returns a Publisher object which allows you to
     * publish messages on that topic through a call to publish().  Once
     * all copies of the returned Publisher object are destroyed, the topic
     * will be automatically unadvertised.
     *
     * The second parameter to advertise() is the size of the message queue
     * used for publishing messages.  If messages are published more quickly
     * than we can send them, the number here specifies how many messages to
     * buffer up before throwing some away.
     */
// %Tag(PUBLISHER)%
    ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
// %EndTag(PUBLISHER)%

// %Tag(LOOP_RATE)%
    ros::Rate loop_rate(10);
// %EndTag(LOOP_RATE)%

    /**
     * A count of how many messages we have sent. This is used to create
     * a unique string for each message.
     */
// %Tag(ROS_OK)%
    int count = 0;
    while (ros::ok())
    {
// %EndTag(ROS_OK)%
        /**
         * This is a message object. You stuff it with data, and then publish it.
         */
// %Tag(FILL_MESSAGE)%
        std_msgs::String msg;

        std::stringstream ss;
        ss << "hello world " << count;
        msg.data = ss.str();
// %EndTag(FILL_MESSAGE)%

// %Tag(ROSCONSOLE)%
        ROS_INFO("%s", msg.data.c_str());
// %EndTag(ROSCONSOLE)%

        /**
         * The publish() function is how you send messages. The parameter
         * is the message object. The type of this object must agree with the type
         * given as a template parameter to the advertise<>() call, as was done
         * in the constructor above.
         */
// %Tag(PUBLISH)%
        chatter_pub.publish(msg);
// %EndTag(PUBLISH)%

// %Tag(SPINONCE)%
        ros::spinOnce();
// %EndTag(SPINONCE)%

// %Tag(RATE_SLEEP)%
        loop_rate.sleep();
// %EndTag(RATE_SLEEP)%
        ++count;
    }


    return 0;
}
// %EndTag(FULLTEXT)%
(2)配置CLion快捷方式

进入CLion快捷方式所在的目录:

~$ cd /usr/share/applications

打开并编辑快捷方式:

/usr/share/applications$ sudo gedit jetbrains-clion.desktop

按照如下所示修改:

Exec=bash -i -c "/opt/clion-2018.1.6/bin/clion.sh" %f

重新注销系统使之生效。

(3)加载功能包

运行CLion,打开功能包下的CMakeList.txt文件,并作为工程打开,如图:
Chapter 2. ROS 创建和编译功能包

(4)编译节点并运行

打开功能包工程如图,编辑CMakeList.txt文件:

add_executable(my_demo src/my_demo.cpp)
target_link_libraries(my_demo ${catkin_LIBRARIES})

Chapter 2. ROS 创建和编译功能包

点击调试按钮,提示如下:
Chapter 2. ROS 创建和编译功能包

打开新的终端,输入:

~$ roscore

Chapter 2. ROS 创建和编译功能包

在CLion环境中,显示如下:
Chapter 2. ROS 创建和编译功能包

新建一个终端查看执行结果:
Chapter 2. ROS 创建和编译功能包

3. 创建ROS功能包并利用CLion进行编译,至此成功完成!

补充说明

如果采用标准版的QtCreator进行编译,请按以下步骤进行:

a. 参照前面,创建节点 demo_node
b. 设置QtCreator能够在启动时候添加ros环境

查找QtCreator的快捷方式
Chapter 2. ROS 创建和编译功能包
修改QtCreator的快捷方式
Chapter 2. ROS 创建和编译功能包
在Exec=处加上 bash -i -c
Chapter 2. ROS 创建和编译功能包
重启QtCreator。

c. 打开QtCreator,通过OpenProject打开工作空间下的CMakeLists.txt文件

Chapter 2. ROS 创建和编译功能包

d. 配置项目

Chapter 2. ROS 创建和编译功能包

e. 修改package中CMakeLists.txt的内容

Chapter 2. ROS 创建和编译功能包

d. 运行结果

Chapter 2. ROS 创建和编译功能包
Chapter 2. ROS 创建和编译功能包