[ROS 튜토리얼] 1.1.3 패키지 생성하기

    Creating a ROS Package

    • Description : 이 튜토리얼에서는 roscreate-pkg 혹은 catkin을 사용하여 패키지를 새롭게 생성하고 rospack을 사용하여 패키지의 의존성을 나열하는 방법을 다룬다.
    • Tutorial Level : BEGINNER
    • Next Tutorial : Building a ROS package

    1. What makes up a catkin Package?

    어떤 패키지가 catkin 패키지로써 인식되려면 몇 가지 조건들을 만족해야 한다.

    • 반드시 catkin과 호환되는 package.xml 파일이 있어야 한다.
      • package.xml 파일은 패키지의 메타 정보를 포함하고 있다.
    • 반드시 catkin을 사용하는 CMakeLists.txt 파일이 있어야 한다.
      • 해당 패키지가 catkin 메타 패키지인 경우, 반드시 관련 보일러 플레이트(boilerplate) CMakeLists.txt 파일을 포함하고 있어야 한다.
    • 각 패키지는 반드시 고유 폴더를 갖고 있어야 한다.
      • 즉, 중첩된 패키지, 혹은 다수의 패키지가 동일한 디렉토리를 사용하면 안 된다.

    가장 간단한 패키지는 다음과 같은 구조를 가질 것이다.

    my_package/
      CMakeLists.txt
      package.xml

    2. Package in a catkin Workspace

    catkin 패키지로 작업하는데에 있어서 catkin 작업 공간(workspace)을 사용하는 것을 권장하지만, catkin 패키지를 독립적으로 작성할 수도 있다. 간단한 작업 공간은 다음과 같은 구조로 되어있을 것이다.

    workspace_folder/        -- WORKSPACE
      src/                   -- SOURCE SPACE
        CMakeLists.txt       -- 'Toplevel' CMake file, provided by catkin
        package_1/
          CMakeLists.txt     -- CMakeLists.txt file for package_1
          package.xml        -- Package manifest for package_1
        package_2/
          CMakeLists.txt     -- CMakeLists.txt file for package_2
          package.xml        -- Package manifest for package_2
        ...
        package_n/
          CMakeLists.txt     -- CMakeLists.txt file for package_n
          package.xml        -- Package manifest for package_n
    

    이 튜로리얼을 진행함에 앞서서 Creating a workspace for catkin 튜토리얼을 참고하여 빈 catkin 작업 공간을 만들어 둔다.

    2021.03.14 - [ROS/ROS 튜토리얼] - [ROS 튜토리얼] 1.1.1 ROS 설치 및 환경 구축


    3. Creating a catkin Package

    이 튜토리얼에서는 catkin_create_pkg 명령어를 사용하여 새로운 catkin 패키지를 만드는 방법과 만든 후에 이 패키지로 무엇을 할 수 있는지를 보여줄 것이다.

     

    먼저 만들어 두었던 작업 공간의 소스 디렉토리인 ~/catkin_ws/src 로 이동한다.

    cd ~/catkin_ws/src

    이제 catkin_create_pkg 명령어를 사용하여 beginner_tutorials 라는 이름의 패키지를 만들 것이며, 패키지의 의존성은 std_msgs, roscpp, rospy를 사용할 것이다. 앞으로 패키지를 생성하거나 다운로드 받을 때는 catkin 작업 공간의 src 디렉토리에 생성/다운로드 하여 빌드한다.

    catkin_create_pkg beginner_tutorials std_msgs roscpp rospy

    이 작업으로 beginner_tutorials 폴더가 생성되고, 이 폴더 안에 package.xmlCMakeLists.txt 파일이 추가된다. 이 파일들에는 catkin_create_pkg 명령어를 사용할 때 같이 작성한 정보들이 담겨있다.

     

    현재 패키지를 빌드할 준비를 갖춰놓은 것이지, 실행할 수 있는 패키지가 생성된 것은 아직 아니다.


    4. Building a catkin workspace and sourcing the setup file

    이제 catkin 작업 공간에서 패키지를 빌드할 것이다.

    이 때, 작업 공간의 src 디렉토리가 아닌, 상위의 작업 공간 디렉토리로 이동해야 한다는 것을 주의한다.

    위처럼 상위로 한 단계 이동하여 빌드해야 한다. 디렉토리 이동 후 빌드 명령어인 catkin_make를 사용하여 빌드한다.

    # ~/catkin_ws 에서 아래 명령어를 실행한다.
    catkin_make

    아래는 실행 결과를 통째로 복사한 것이다.

    conceptbug95@ubuntu-linux-ongoing:~/catkin_ws$ catkin_make
    Base path: /home/conceptbug95/catkin_ws
    Source space: /home/conceptbug95/catkin_ws/src
    Build space: /home/conceptbug95/catkin_ws/build
    Devel space: /home/conceptbug95/catkin_ws/devel
    Install space: /home/conceptbug95/catkin_ws/install
    ####
    #### Running command: "cmake /home/conceptbug95/catkin_ws/src -DCATKIN_DEVEL_PREFIX=/home/conceptbug95/catkin_ws/devel -DCMAKE_INSTALL_PREFIX=/home/conceptbug95/catkin_ws/install -G Unix Makefiles" in "/home/conceptbug95/catkin_ws/build"
    ####
    -- Using CATKIN_DEVEL_PREFIX: /home/conceptbug95/catkin_ws/devel
    -- Using CMAKE_PREFIX_PATH: /home/conceptbug95/catkin_ws/devel;/opt/ros/melodic
    -- This workspace overlays: /home/conceptbug95/catkin_ws/devel;/opt/ros/melodic
    -- Found PythonInterp: /usr/bin/python2 (found suitable version "2.7.17", minimum required is "2") 
    -- Using PYTHON_EXECUTABLE: /usr/bin/python2
    -- Using Debian Python package layout
    -- Using empy: /usr/bin/empy
    -- Using CATKIN_ENABLE_TESTING: ON
    -- Call enable_testing()
    -- Using CATKIN_TEST_RESULTS_DIR: /home/conceptbug95/catkin_ws/build/test_results
    -- Found gtest sources under '/usr/src/googletest': gtests will be built
    -- Found gmock sources under '/usr/src/googletest': gmock will be built
    -- Found PythonInterp: /usr/bin/python2 (found version "2.7.17") 
    -- Using Python nosetests: /usr/bin/nosetests-2.7
    -- catkin 0.7.29
    -- BUILD_SHARED_LIBS is on
    -- BUILD_SHARED_LIBS is on
    -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- ~~  traversing 1 packages in topological order:
    -- ~~  - beginner_tutorials
    -- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    -- +++ processing catkin package: 'beginner_tutorials'
    -- ==> add_subdirectory(beginner_tutorials)
    -- Configuring done
    -- Generating done
    -- Build files have been written to: /home/conceptbug95/catkin_ws/build
    ####
    #### Running command: "make -j2 -l2" in "/home/conceptbug95/catkin_ws/build"
    ####
    

    devel 폴더와 build 폴더를 보면 빌드 후 추가된 것들이 있는것을 볼 수 있다.

    작업 공간을 빌드한 후 하위 폴더인 devel을 살펴보면 이전의 튜토리얼에서 ROS 환경 변수 경로에 등록했던 경로를 살펴볼 때 보았던 구조와 유사한 구조를 지니게 된 것을 볼 수 있다.

    빌드 후 변경된 작업 공간의 내용을 ROS 환경 변수에 다시 등록하기 위해 아래와 같이 setup 파일을 소싱한다. 혹은 터미널을 닫았다가 다시 실행해도 된다.

    source ~/catkin_ws/devel/setup.bash

    5. package dependencies

    5.1 First-order dependencies

    앞서 catkin_create_pkg를 사용하여 패키지를 생성할 때 몇 가지 의존성을 같이 적어주어 생성했다. 이 때 집어 넣었던 의존성들을 1차 의존성(first-order dependencies)이라 하며 rospack 툴을 사용해 제대로 적용되었는지 확인할 수 있다.

    실행 결과로도 알 수 있듯이 catkin_create_pkg 단계에서 인수(argument)로 넣어주었던 의존성들이 출력됐다. 이 의존성들은 해당 패키지의 package.xml 파일에 저장되어 있다.

     

    5.2 Indirect dependencies

    대부분의 경우 하나의 의존성 밑에 또 다른 의존성들이 존재한다. 예를 들어 현재 beginner_tutorials라는 패키지의 1차 의존성들 중 rospy가 있는데, 이 rospy 또한 의존성이 있다는 것이다(의존성의 의존성 같은 느낌이랄까). 위에서 beginner_tutorials 패키지의 1차 의존성을 찾아본 것을 그대로 응용하여 다시 사용해 보았다. 나는 beginner_tutorials 패키지의 모든 1차 의존성들을 살펴보았다.

    roscpp, rospy, std_msgs를 조회해봤다.

    depend1이 아닌 depend를 사용하면 아래와 같이 한꺼번에 조회 가능하다.

    conceptbug95@ubuntu-linux-ongoing:~$ rospack help
    USAGE: rospack <command> [options] [package]
      Allowed commands:
        help
        cflags-only-I     [--deps-only] [package]
        cflags-only-other [--deps-only] [package]
        depends           [package] (alias: deps)
        depends-indent    [package] (alias: deps-indent)
        depends-manifests [package] (alias: deps-manifests)
        depends-msgsrv    [package] (alias: deps-msgsrv)
        depends-on        [package]
        depends-on1       [package]
        depends-why --target=<target> [package] (alias: deps-why)
        depends1          [package] (alias: deps1)
        export [--deps-only] --lang=<lang> --attrib=<attrib> [package]
        find [package]
        langs
        libs-only-L     [--deps-only] [package]
        libs-only-l     [--deps-only] [package]
        libs-only-other [--deps-only] [package]
        list
        list-duplicates
        list-names
        plugins --attrib=<attrib> [--top=<toppkg>] [package]
        profile [--length=<length>] [--zombie-only]
        rosdep  [package] (alias: rosdeps)
        rosdep0 [package] (alias: rosdeps0)
        vcs  [package]
        vcs0 [package]
      Extra options:
        -q     Quiets error reports.
    
     If [package] is omitted, the current working directory
     is used (if it contains a package.xml or manifest.xml).

    6. Customizing Your Package

    이 튜토리얼에서는 catkin_create_pkg 명령을 실행했을 때 생성된 파일들을 살펴보고, 해당 파일의 각 구성 요소를 한줄 한줄 뜯어볼 것이며 어떻게 이들을 customizing 할 것인지에 대해 다룰 것이다.

     

    6.1 Customizing the package.xml

    새로운 패키지인 beginner_tutorials 디렉토리 안에 package.xml 파일이 생성되어 있는 것을 볼 수 있다.

    이제 이 package.xml 파일을 살펴보면서 주의를 기울여야 할 모든 요소들을 짚어볼 것이다. 아래는 pcakage.xml 파일의 전문이다.

    <?xml version="1.0"?>
    <package format="2">
      <name>beginner_tutorials</name>
      <version>0.0.0</version>
      <description>The beginner_tutorials package</description>
    
      <!-- One maintainer tag required, multiple allowed, one person per tag -->
      <!-- Example:  -->
      <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
      <maintainer email="conceptbug95@todo.todo">conceptbug95</maintainer>
    
    
      <!-- One license tag required, multiple allowed, one license per tag -->
      <!-- Commonly used license strings: -->
      <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
      <license>TODO</license>
    
    
      <!-- Url tags are optional, but multiple are allowed, one per tag -->
      <!-- Optional attribute type can be: website, bugtracker, or repository -->
      <!-- Example: -->
      <!-- <url type="website">http://wiki.ros.org/beginner_tutorials</url> -->
    
    
      <!-- Author tags are optional, multiple are allowed, one per tag -->
      <!-- Authors do not have to be maintainers, but could be -->
      <!-- Example: -->
      <!-- <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 against 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 documentation: -->
      <!--   <doc_depend>doxygen</doc_depend> -->
      <buildtool_depend>catkin</buildtool_depend>
      <build_depend>roscpp</build_depend>
      <build_depend>rospy</build_depend>
      <build_depend>std_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>
      <exec_depend>roscpp</exec_depend>
      <exec_depend>rospy</exec_depend>
      <exec_depend>std_msgs</exec_depend>
    
    
      <!-- The export tag contains other, unspecified, tags -->
      <export>
        <!-- Other tools can request additional information be placed here -->
    
      </export>
    </package>

    (1) description tag

    먼저, description tag를 업데이트 한다.

      <description>The beginner_tutorials package</description>

    이 태그는 말 그대로 패키지에 대한 개요를 적어놓는 영역으로 마음껏 변경할 수 있지만, 반드시 해당 패키지의 scope를 모두 다루면서 내용과 기능을 모두 함축할 수 있어야 한다. 즉, 어느 누가 이 설명을 읽어 보아도 해당 패키지의 내용과 기능을 이해할 수 있을 정도로 간단 명료한 설명을 적어야 한다. 구구절절 부연 설명을 할 필요도 없고, 너무 함축시켜 패키지의 내용이 모두 담기지 못해도 안된다. 만약 패키지를 한 문장으로 표현하기 힘들다면, 해당 패키지에 너무 많은 내용과 기능이 들어간 것으로, 패키지를 분리하여 하나의 역할/기능을 하는 패키지로 세분화 시켜 프로그램을 관리해야 편할 것이다.

    예를 들어 코드를 작성할 때 하나의 함수(혹은 메소드)는 반드시 하나의 기능만을 하도록 설계해야 back-trace가 편하고 여러 구성원이 협업할 때 용이한 것과 같은 맥락이다.

     

    (2) maintainer tags

    다음으로 maintainer tags가 있다.

    <!-- One maintainer tag required, multiple allowed, one person per tag -->
      <!-- Example:  -->
      <!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
      <maintainer email="conceptbug95@todo.todo">conceptbug95</maintainer>

    이 태그는 말 그대로 패키지의 유지 관리자를 적어놓은 영역으로, (패키지가 개인 용도가 아니라면)사용자가 유지 관리자에게 연락 가능한 수단을 알려주기 때문에 package.xml 파일에 필수적이며 중요한 태그 영역이다. 최소 1명의 유지 관리자를 적어줘야 하고, 필요하다면 다수를 적어도 된다. (나는 튜토리얼을 위한 패키지를 생성한 것이기 때문에 따로 명시해두지는 않을 것이다)

     

    (3) license tags

    다음은 license tag다.

      <!-- One license tag required, multiple allowed, one license per tag -->
      <!-- Commonly used license strings: -->
      <!--   BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
      <license>TODO</license>

    사용할 라이센스를 선택한 후 이 영역에 채워넣어야 한다. 자주 사용되는 오픈 소스 라이센스들은 다음과 같다 :

    • BSD
    • MIT
    • Boost Software License
    • GPLv2
    • GPLv3
    • LGPLv2.1
    • LGPLv3

    다음 링크에서 이들 중 일부를 읽어볼 수 있다.

    opensource.org/licenses/alphabetical

     

    Licenses by Name | Open Source Initiative

     

    opensource.org

    이 튜토리얼에서는 나머지 핵심 ROS 구성 요소들이 이미 BSD 라이센스를 사용중이므로, BSD 라이센스를 사용할 것이다.

      <license>BSD</license>

     

    (4) dependencies tags

    다음으로 살펴볼 태그들의 set은 해당 패키지의 의존성에 대해 설명 및 나열하고 있다. 의존성은 다음과 같이 나눌 수 있다.

    • <build_depend> build dependent : 해당 패키지를 빌드하는데에 필요한 다른 패키지를 의존성 패키지로써 지정하는 태그.
    • <buildtool_depend> buildtool dependent : 해당 패키지를 빌드하는데에 필요한 build system tool을 지정하는 태그.
    • <exec_depend> exec dependent : 해당 패키지에서 코드를 실행하는데에 필요한 다른 패키지를 의존성 패키지로써 지정하는 태그. 이 패키지의 공유 라이브러리에 의존하는 경우에 해당된다.
    • <test_depend> test dependent : 유닛 테스트에 대한 추가 의존성만을 지정하는 태그로, build dependencies나 run dependencies로 이미 사용된 것을 다시 복제하면 안된다.
    • <doc_depend> documentation tool dependent : 해당 패키지가 documendation을 생성하는데에 필요한 documendation tool을 지정한다.

    위의 태그들에 대한 제세한 내용은 Catkin Dependencies 문서를 참고하도록 한다.

     

    현재 catkin_create_pkg 명령어를 사용할때 std_msgs, roscpp, rospy를 인수(arguments)로써 넘겨주었기 때문에 이 의존성들은 다음과 같이 나타날 것이다.

      <!-- 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 against 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 documentation: -->
      <!--   <doc_depend>doxygen</doc_depend> -->
      <buildtool_depend>catkin</buildtool_depend>
      <build_depend>roscpp</build_depend>
      <build_depend>rospy</build_depend>
      <build_depend>std_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>
      <exec_depend>roscpp</exec_depend>
      <exec_depend>rospy</exec_depend>
      <exec_depend>std_msgs</exec_depend>

    buildtool_depend 태그의 기본(default)값인 catkin과 함께, 리스트에 올린 모든 의존성들이 build_depend로 추가되었다. 이 경우 지정된 모든 의존성을 빌드(build) 및 실행(execute)시 사용 가능해야 하므로 각 의존성 패키지에 대해 exec_depend 태그를 추가할 것이다 :

      <buildtool_depend>catkin</buildtool_depend>
    
      <build_depend>roscpp</build_depend>
      <build_depend>rospy</build_depend>
      <build_depend>std_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>
    
      <exec_depend>roscpp</exec_depend>
      <exec_depend>rospy</exec_depend>
      <exec_depend>std_msgs</exec_depend>

     

    (5) Final package.xml

    코멘트(주석)와 미사용 태그를 모두 지운 최종 package.xml 파일은 아래와 같이 간결하게 보일 것이다.

    <?xml version="1.0"?>
    <package format="2">
      <name>beginner_tutorials</name>
      <version>0.0.0</version>
      <description>The beginner_tutorials package</description>
    
      <maintainer email="conceptbug95@todo.todo">conceptbug95</maintainer>
    
      <license>BSD</license>
    
      <buildtool_depend>catkin</buildtool_depend>
      <build_depend>roscpp</build_depend>
      <build_depend>rospy</build_depend>
      <build_depend>std_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>
      <exec_depend>roscpp</exec_depend>
      <exec_depend>rospy</exec_depend>
      <exec_depend>std_msgs</exec_depend>
    
    </package>

    6.2 Customizing the CMakeLists.txt

    메타 정보를 포함한 package.xml 파일이 패키지에 알맞게 작성 되었으므로, 이제 다음 튜토리얼로 넘어가도록 한다. catkin_create_pkg로 생성된 CMakeLists.txt 파일은 ROS 코드를 빌드하는 다음 튜토리얼에서 다루도록 할 것이다.

    댓글

    Designed by JB FACTORY