ROS2로 개발할 때 자주 듣게 되는 용어 중 하나는 package(패키지)이다. 이와 관련된 몇가지 실습을 진행하며 개념을 익혀보자.
목표:
CMake나 Python으로 새로운 패키지를 만든다.
만든 패키지의 executable(실행파일)을 실행한다.
tutorial level: 입문
예상 소요시간
약 15분
패키지는 로봇기능들을 담당하는 코드들을 모아놓은 집합체이다.
패키지를 이용하면 다른 사람들과 손쉽게 코드를 공유하고 설치할 수 있다.
ROS2에서 패키지를 만들기 위해 ament를 build system으로 사용하고 colcon을 build tool로 이용한다.
CMake나 Python을 사용하여 package를 생성할 수 있는게 기본이지만 다른 방식도 사용가능하긴하다.
앞서 말했듯이 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를 포함하고 있다.
가장 간단한 파일구조는 각각 다음과 같다.
my_package/
CMakeLists.txt
include/my_package/
package.xml
src/
my_package/
package.xml
resource/my_package
setup.cfg
setup.py
my_package/
하나의 작업공간에는 무수히 많은 패키지들이 있을 수 있다. 한 작업공간에 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/
먼저 ROS2의 기본 workspace를 소스한다.
source /opt/ros/humble/setup.bash
지난 시간에 만든 ros2_ws/src로 이동
cd ~/ros2_ws/src
다음 명령어를 통해 package생성할 수 있는데 기본 양식은 다음과 같다.
ros2 pkg create --build-type ament_cmake --license Apache-2.0 <package_name>
ros2 pkg create --build-type ament_python --license Apache-2.0 <package_name>
이 둘의 차이점을 보면 ament_뒤에 cmake이냐, python이냐 인 것을 확인 할 수 있다.
명령어를 배웠으니 실제로 패키지를 만들어보자.
ros2 pkg create --build-type ament_cmake --license Apache-2.0 --node-name my_node my_package
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라는 폴더가 생성된것을 볼 수 있다.
패키지를 생성하는 명령어를 입력했을 때 다음과 같은 메세지가 터미널에 출력될 것이다.
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
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 메세지에 따르면 여러 파일들이 패키지 생성 명령어가 실행되면서 생성된 것을 확인 할 수 있다.
작업공간에 패키지를 넣어놓으면 패키지가 여러개 있더라도 colcon을 이용해서 한번에 빌드할 수 있는 장점이 있다.
저번에 했던 것과 같이 빌드해보자.
cd ~/ros2_ws
colcon build
하나 알고 있으면 좋은 사실은 이렇게 colcon build를 입력하게 되면 현재 작업 공간에 있는 모든 패키지들(지난 시간에 설치한 ros_tutorials, turtlesim패키지등)이 같이 빌드 된다는 것이다. 즉 빌드 시간이 더 오래 걸릴 수 있다는 것을 의미한다.
만약에 방금 우리가 만든 my_package만 빌드하고 싶다면 다음과 같이 명령어를 변형할 수 있다.
colcon build --packages-select my_package
저번시간에 배운 것 처럼 새롭게 빌드 및 설치한 패키지의 executable을 사용하려면 현재 작업공간을 source해줘야한다.
먼저 ROS2 기본 공간을 source하고
source /opt/ros/humble/setup.bash
그후 우리 작업공간을 source해주자.
source install/local_setup.bash
--node-name으로 만든 node의 executable을 실행하기 위해 다음과 같이 ros2 run커맨드(명령어)를 활용할 수 있다.
ros2 run my_package my_node
CMake로 생성했는지 Python으로 생성했는지에 따라 다음과 같이 다른 메세지가 터미널에 출력될 것이다.
hello world my_package package
Hi from my_package.
ros2_ws/src/my_package로 이동하게 되면 ros2 pkg create명령어가 생성한 파일과 폴더들을 확인할 수 있다.
CMakeLists.txt include package.xml src
주목할 점은 여기 src폴더 안에 my_node.cpp가 위치한다. 이 src폴더는 앞으로 우리가 작성할 custom C++ node들이 위치할 공간이다.
my_package package.xml resource setup.cfg setup.py test
비슷하게 my_node.py는 my_package안에 위치한다. 이 패키지 이름과 같은 폴더의 경로에 앞으로 우리가 작성할 custom python node들이 위치할 것이다.
관찰력이 높은 사람이라면 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
<?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>
<?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를 작성하는 방법을 알아볼 것이다.
오늘도 여기까지 온 스스로를 칭찬해주자!
질문하고 싶거나 인공지능 & 로봇 개발에 대해 다뤄줬으면 하는 주제를 댓글로 남겨주기 바란다~!