개발자와 함께하는 ROS2 Humble에서 패키지 만들기

IROBOU·2024년 1월 21일
2

인공지능_로봇개발

목록 보기
10/17
post-thumbnail

ROS2로 개발할 때 자주 듣게 되는 용어 중 하나는 package(패키지)이다. 이와 관련된 몇가지 실습을 진행하며 개념을 익혀보자.


목표:
CMake나 Python으로 새로운 패키지를 만든다.
만든 패키지의 executable(실행파일)을 실행한다.

tutorial level: 입문

예상 소요시간
약 15분


배경지식

배경지식(1) : ROS2 패키지란?

패키지는 로봇기능들을 담당하는 코드들을 모아놓은 집합체이다.
패키지를 이용하면 다른 사람들과 손쉽게 코드를 공유하고 설치할 수 있다.

ROS2에서 패키지를 만들기 위해 ament를 build system으로 사용하고 colcon을 build tool로 이용한다.
CMake나 Python을 사용하여 package를 생성할 수 있는게 기본이지만 다른 방식도 사용가능하긴하다.

배경지식(2) : ROS2 패키지 구성요소

앞서 말했듯이 ROS2 패키지는 CMake 와 Python이렇게 둘로 생성 가능하다.

무엇으로 만드는가에 따라 필요한 요소는 다음과 같다.

CMake로 만드는 경우
- CMakeLists.txt 파일이 필요하다. 이 파일은 패키지내 코드를 어떻게 빌드할 것인지에 대한 설명을 담고 있다. 
- include/<package_name> 경로를 갖는다. 이 경로에는 패키지를 위한 public header파일들이 있다. 
- pakcage.xml 파일이 필요하다. 이 파일은 package와 관련된 meta 정보를 갖는데 이는 필요한 의존성을 갖는 패키지이름등을 포함한다. 
- src경로를 갖는다. 이 경로에는 package의 source code가 담겨있다. 
Python로 만드는 경우
- pakcage.xml 파일이 필요하다. 이 파일은 package와 관련된 meta 정보를 갖는데 이는 필요한 의존성을 갖는 패키지이름등을 포함한다.  
- resource/<package_name> 마커 파일을 갖는다. 
- setup.cfg 가 필요한데 ros2 run 명령어가 패키지의 executable를 찾는데 도움을 준다. 
- setup.py 가 필요하다. 이 python파일은 pakcage를 어떻게 설치할 것인지에 대한 설치 방법이 포함되어 있다. 
- <package_name> 패키지와 같은 이름을 갖는 폴더이다. ROS2 tool을 이용하여 package를 찾는데 사용된다. __init__.py를 포함하고 있다. 

가장 간단한 파일구조는 각각 다음과 같다.

  • CMake의 경우
my_package/
     CMakeLists.txt
     include/my_package/
     package.xml
     src/
  • Python의 경우
my_package/
      package.xml
      resource/my_package
      setup.cfg
      setup.py
      my_package/

배경지식(3) 작업환경에서 패키지

하나의 작업공간에는 무수히 많은 패키지들이 있을 수 있다. 한 작업공간에 Python으로 만든 패키지든 CMake로 만든 패키지든 공존할 수 있다.
그렇지만 패키지안에 패키지를 만드는(nesting)은 할 수 없다.

널리 사용되는 방식으로는 작업공간에 src폴더를 만들어 그 안에 package들을 위치시키는 것이다.

그러면 다음과 같은 파일 구조를 확인 할 수 있다.

workspace_folder/
    src/
      cpp_package_1/
          CMakeLists.txt
          include/cpp_package_1/
          package.xml
          src/

      py_package_1/
          package.xml
          resource/py_package_1
          setup.cfg
          setup.py
          py_package_1/
      ...
      cpp_package_n/
          CMakeLists.txt
          include/cpp_package_n/
          package.xml
          src/

준비물

  • 지난 시간에 workspace를 생성하는 실습을 통해 생성된 작업공간이 있으면 된다.
    아직 작업공간을 만드는 방법을 모르는 사람은 다음 링크 참고
    작업공간 만들기 실습 포스트

실습

실습1. 패키지 생성

먼저 ROS2의 기본 workspace를 소스한다.

source /opt/ros/humble/setup.bash

지난 시간에 만든 ros2_ws/src로 이동

cd ~/ros2_ws/src

다음 명령어를 통해 package생성할 수 있는데 기본 양식은 다음과 같다.

  • CMake 명령어
ros2 pkg create --build-type ament_cmake --license Apache-2.0 <package_name>
  • Python 명령어
ros2 pkg create --build-type ament_python --license Apache-2.0 <package_name>

이 둘의 차이점을 보면 ament_뒤에 cmake이냐, python이냐 인 것을 확인 할 수 있다.

명령어를 배웠으니 실제로 패키지를 만들어보자.

  • CMake 명령어로 만들기
ros2 pkg create --build-type ament_cmake --license Apache-2.0 --node-name my_node my_package
  • Python 명령어로 만들기
ros2 pkg create --build-type ament_python --license Apache-2.0 --node-name my_node my_package

이 명령어를 살펴보면 my_package라는 패키지를 만들건데 my_node라는 이름을 갖는 node를 생성한다는 의미를 갖는다.

작업공간의 src폴더에 들어가면 my_package라는 폴더가 생성된것을 볼 수 있다.

패키지를 생성하는 명령어를 입력했을 때 다음과 같은 메세지가 터미널에 출력될 것이다.

  • CMake 명령어 경우
going to create a new package
package name: my_package
destination directory: /home/user/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['<name> <email>']
licenses: ['TODO: License declaration']
build type: ament_cmake
dependencies: []
node_name: my_node
creating folder ./my_package
creating ./my_package/package.xml
creating source and include folder
creating folder ./my_package/src
creating folder ./my_package/include/my_package
creating ./my_package/CMakeLists.txt
creating ./my_package/src/my_node.cpp
  • Python 명령어 경우
going to create a new package
package name: my_package
destination directory: /home/user/ros2_ws/src
package format: 3
version: 0.0.0
description: TODO: Package description
maintainer: ['<name> <email>']
licenses: ['TODO: License declaration']
build type: ament_python
dependencies: []
node_name: my_node
creating folder ./my_package
creating ./my_package/package.xml
creating source folder
creating folder ./my_package/my_package
creating ./my_package/setup.py
creating ./my_package/setup.cfg
creating folder ./my_package/resource
creating ./my_package/resource/my_package
creating ./my_package/my_package/__init__.py
creating folder ./my_package/test
creating ./my_package/test/test_copyright.py
creating ./my_package/test/test_flake8.py
creating ./my_package/test/test_pep257.py
creating ./my_package/my_package/my_node.py

log 메세지에 따르면 여러 파일들이 패키지 생성 명령어가 실행되면서 생성된 것을 확인 할 수 있다.

실습2. 패키지 빌드하기

작업공간에 패키지를 넣어놓으면 패키지가 여러개 있더라도 colcon을 이용해서 한번에 빌드할 수 있는 장점이 있다.

저번에 했던 것과 같이 빌드해보자.

cd ~/ros2_ws
colcon build

하나 알고 있으면 좋은 사실은 이렇게 colcon build를 입력하게 되면 현재 작업 공간에 있는 모든 패키지들(지난 시간에 설치한 ros_tutorials, turtlesim패키지등)이 같이 빌드 된다는 것이다. 즉 빌드 시간이 더 오래 걸릴 수 있다는 것을 의미한다.

만약에 방금 우리가 만든 my_package만 빌드하고 싶다면 다음과 같이 명령어를 변형할 수 있다.

colcon build --packages-select my_package

실습3. setup file 소스(source)하기

저번시간에 배운 것 처럼 새롭게 빌드 및 설치한 패키지의 executable을 사용하려면 현재 작업공간을 source해줘야한다.

먼저 ROS2 기본 공간을 source하고

source /opt/ros/humble/setup.bash

그후 우리 작업공간을 source해주자.

source install/local_setup.bash

실습4. 패키지 사용하기

--node-name으로 만든 node의 executable을 실행하기 위해 다음과 같이 ros2 run커맨드(명령어)를 활용할 수 있다.

ros2 run my_package my_node

CMake로 생성했는지 Python으로 생성했는지에 따라 다음과 같이 다른 메세지가 터미널에 출력될 것이다.

  • CMake로 생성한 executable
hello world my_package package
  • Python으로 생성한 executable
Hi from my_package.

실습5. package 구성 확인하기

ros2_ws/src/my_package로 이동하게 되면 ros2 pkg create명령어가 생성한 파일과 폴더들을 확인할 수 있다.

  • CMake로 생성한 경우 폴더와 파일들
CMakeLists.txt  include  package.xml  src

주목할 점은 여기 src폴더 안에 my_node.cpp가 위치한다. 이 src폴더는 앞으로 우리가 작성할 custom C++ node들이 위치할 공간이다.

  • Python으로 생성한 경우 폴더와 파일들
my_package  package.xml  resource  setup.cfg  setup.py  test

비슷하게 my_node.py는 my_package안에 위치한다. 이 패키지 이름과 같은 폴더의 경로에 앞으로 우리가 작성할 custom python node들이 위치할 것이다.

실습6. package.xml 커스터마이즈하기

관찰력이 높은 사람이라면 ros2 pkg create 명령어로 패키지를 만들 때 TODO: 가 출력된 부분을 확인 했을 것이다.

...
description: TODO: Package description
maintainer: ['<name> <email>']
licenses: ['TODO: License declaration']
...

이 description, maintainer, licenses 정보는 자동으로 결정되지 않지만 나중에 이 패키지를 배포하고 싶을 때 필요한 정보라서 ros2 pkg create명령어는 자동으로 공간만 일단 만들어놓고 내용을 의미없게 채워놓은 것이다.

이를 의미있게 바꾸려면 package.xml에 들어가서 바꿔주면 된다.

cd ~/ros2_ws/src/my_package
gedit package.xml
  • CMake로 만든 경우
<?xml version="1.0"?>
<?xml-model
   href="http://download.ros.org/schema/package_format3.xsd"
   schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
 <name>my_package</name>
 <version>0.0.0</version>
 <description>TODO: Package description</description>
 <maintainer email="user@todo.todo">user</maintainer>
 <license>TODO: License declaration</license>

 <buildtool_depend>ament_cmake</buildtool_depend>

 <test_depend>ament_lint_auto</test_depend>
 <test_depend>ament_lint_common</test_depend>

 <export>
   <build_type>ament_cmake</build_type>
 </export>
</package>
  • Python으로 만든경우
<?xml version="1.0"?>
<?xml-model
   href="http://download.ros.org/schema/package_format3.xsd"
   schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
 <name>my_package</name>
 <version>0.0.0</version>
 <description>TODO: Package description</description>
 <maintainer email="user@todo.todo">user</maintainer>
 <license>TODO: License declaration</license>

 <test_depend>ament_copyright</test_depend>
 <test_depend>ament_flake8</test_depend>
 <test_depend>ament_pep257</test_depend>
 <test_depend>python3-pytest</test_depend>

 <export>
   <build_type>ament_python</build_type>
 </export>
</package>

위에서

<description>TODO: Package description</description>
 <maintainer email="user@todo.todo">user</maintainer>
 <license>TODO: License declaration</license>

부분에 해당하는 내용을 바꿔주면 된다.

다음과 같이 변경해보겠다.

<description>Beginner client libraries tutorials practice package</description>
<maintainer email="irobou@gmail.com">user</maintainer>
<license>Apache License 2.0</license>

그 다음 변경사항을 ctrl+s를 눌러 저장해준다.

추가로 package.xml에서 알아야 할 것은 tag 이름들중에 "_depend" 로 끝나는 태그들이 있는데 이는 우리 패키지가 어떤 패키지에 의존하는지를 나열하는데 사용한다.
여기에 나열해놓음으로써 colcon이 빌드할 때 어떤 의존 패키지를 찾아야하는지 알 수 있다.
my_package 같은 경우에는 단순한 패키지라 특별한 dependency를 갖지 않는다.
그렇지만 앞으로 배울 tutorial에 사용되기위해 해당 공간은 몇가지 dependency를 나열하고 있다.

Python으로 생성한 경우 한가지 작업을 더해줘야 하는데 바로 setup.py에서 우리가 package.xml에서 수정한 부분에 해당하는 곳을 변경하는 일이다.

먼저 setup.py를 편집기로 열어준다.

cd ~/ros2_ws/src/my_package
gedit setup.py
from setuptools import setup

package_name = 'my_py_pkg'

setup(
 name=package_name,
 version='0.0.0',
 packages=[package_name],
 data_files=[
     ('share/ament_index/resource_index/packages',
             ['resource/' + package_name]),
     ('share/' + package_name, ['package.xml']),
   ],
 install_requires=['setuptools'],
 zip_safe=True,
 maintainer='TODO',
 maintainer_email='TODO',
 description='TODO: Package description',
 license='TODO: License declaration',
 tests_require=['pytest'],
 entry_points={
     'console_scripts': [
             'my_node = my_py_pkg.my_node:main'
     ],
   },
)

위에서 description, license, maintainer, maintainer이름을 package.xml에서 변경한대로 바꿔준다.

예시
maintainer='irobou',
maintainer_email='irobou@gmail.com',
description='Beginner client libraries tutorials practice package',
license='Apache License 2.0',

ctrl+s를 눌러 저장한다.


여태까지 ROS2 custom package를 생성하고 그 내부 구성에 대해 살펴봤다.

요약하자면 package는 코드모음이고 쉽게 남들과 공유 가능하다.
ros2 pkg create 명령어는 ROS2 package에 필요한 폴더 및 파일들을 만들어준다.
만든 패키지를 빌드할 땐 colcon build를 사용할 수 있으며
빌드한 후 사용하기 위해선 작업공간을 source해줘야 한다.

다음시간에는 ROS2의 꽃 (c++)로 publisher와 subscriber를 작성하는 방법을 알아볼 것이다.


오늘도 여기까지 온 스스로를 칭찬해주자!

질문하고 싶거나 인공지능 & 로봇 개발에 대해 다뤄줬으면 하는 주제를 댓글로 남겨주기 바란다~!

profile
지식이 현실이 되는 공간

0개의 댓글