빌드 시스템(build system)과 빌드 툴(build tools)을 나누어 비교하고 ROS에서는 어떻게 역할 분담이 되어 있는지 알아보자. 결론부터 말하자면 빌드 시스템과 빌드 툴의 큰 차이는 단일 패키지를 대상으로 하느냐 전체 패키지를 대상으로 하느냐이다. 즉, 빌드 시스템은 단일 패키지를 대상으로 하며, 빌드 툴은 전체 패키지를 대상으로 한다.
단순히 생각하면 빌드 시스템만을 이용하면 ROS의 패키지들을 사용할 수 있는 것처럼 보인다. 하지만 ROS에서는 수많은 패키지를 함께 빌드하여 실행시키는 구조이기 때문에 각 패키지별로 서로 다른 빌드 시스템을 호출하고 패키지들의 종속성이 매우 얽혀있는 경우에는 이 얽혀있는 의존성 실타래를 풀고 토폴로지 순서대로 빌드 해야만 한다. 이때에 사용되는 것이 ROS의 빌드 툴이다. ROS빌드 툴은 각 패지키에 기술되어있는 종속성 그래프를 해석하고 토폴로지 순서로 각 패키지에 대한 특정 빌드 시스템을 호출한다. 이러한 빌드 툴은 ROS의 개발환경을 설정하고 빌드 시스템을 호출하고 빌드된 패키지를 사용하도록 실행 환경을 구성하게 된다. ROS의 빌드 툴로는 rosbulid
catkin_make
cakin_make_isolated
cakin_tools
ament_tools
그리고 현재 ROS2 버전에서 제일 많이 사용하는 colcon
⭐️이 있다.
ROS1의 빌드 시스템은 기본적으로 CMake(Cross Platform Make)를 사용하고 빌드 환경은 패키지 폴더의 "CMakeLists.txt" 파일에 기술한다. ROS에서는 CMake를 ROS에 맞도록 수정해주는 catkin 빌드 시스템을 제공한다. ROS에서 CMake를 이용하는 이유는 ROS 패키지를 멀티 플랫폼 에서 빌드 할수 있게 하기 위함이다. Make가 유닉스(Unix) 계열만 지원하는 것과 달리, CMake는 유닉스 계열인 리눅스(Linux),BSD, macOS뿐만 아니라 윈도우 계열도 지원하기 때문이다. 또한 "CMakeLists.txt" 는 Visual Studio, Eclipse, Qt Creator 등 다양한 IDE에서 기본적으로 지원하여 쉽게 사용할수 있다. 그리고 catkin 빌드 시스템은 catkin_make 빌드 툴과 함께 사용되어 ROS와 관련된 빌드, 패키지 관리, 패키지 간 의존관계 등을 편리하게 사용할 수 있도록 하고 있다.
ROS2에서는 새로운 빌드 시스템인 ament를 사용한다. ament도 크게는 두 가지 인데 그중 가장 많이 사용되는 ament_cmake는 ROS1에서 사용되는 빌드 시스템인 catkin의 업그레이드 버전으로 CMake의 빌드 설정 파일인 "CMakeLists.txt" 에 기술된 빌드 설정을 기반으로 빌드를 수행하게 된다. ROS1의 catkin 과 ROS2의 ament의 다른 점으로는 파일 시스템에서 devel
공간을 사용하지 않는다는 점과 CMAKE_PREFIX_PATH
이 아닌 AMENT_PREFIX_PATH
와 같은 고유 환경설정을 사용할 수 있다는 점이다.
그리고 ROS 1의 catkin이 CMake(Cross Platform Make)만을 지원했던 반면, ament의 또 다른 ament_python으로 CMake를 사용하지 않는 Python 패키지 관리도 가능하다. 즉, ROS 2에 와서는 Python 패키지는 비로소 처음으로 완전 독립을 이루게 되었는데 ROS 1에서 Python 코드가 있는 패키지는 setup.py 파일이 CMake 내에서 사용자 정의 로직으로 처리되었다. 하지만 ROS 2에서 Python 패키지는 setup.py 파일의 모든 기능을 순수 Python 모듈과 동등한 수준으로 개발할 수 있게 되었다
ROS 1의 경우 여러 가지 다른 도구, 즉 catkin_make, catkin_make_isolated 및 catkin_tools가 지원되었다. ROS 2에서는 알파, 베타, 그리고 Ardent 릴리스까지 빌드 도구로 ament_tools가 이용되었고 ROS 2 Bouncy부터는 colcon을 추천하고 있다. colcon (collective construction)은 ROS 2 패키지를 작성, 테스트, 빌드 등 ROS 2 기반의 프로그램할 때 빼놓을 수 없는 툴로 작업 흐름을 향상시키는 CLI 타입의 명령어 도구이다. 사용 방법은 colcon build
와 같은 CLI 형태의 명령어로 터미널창에서 수행하게 되며 다양한 옵션과 함께 사용할 수 있다.
ROS2 패키지를 생성하기 위해서는 두 가지 방법이 있는데, 하나는 직접 패키지 폴더를 만들고 그 안에 파일 시스템에 필수적인 "package.xml" 이나 "CMakeLists.txt" 또는 "setup.py" 등을 포함시켜 주고 소스코드를 작성하는 것과 ros2cli
명령어를 이용하는것이다. 이 장에서는 ros2cli
명령어를 사용하여 소스코드 작업을 해보겠다.
일단 사용자 작업폴더(파일시스템 참조)로 이동한 후 패키지를 생성해보자
패키지 생성 명령어는 다음과 같다. ros2 pkg create
명령어를 사용하고 그 뒤에 옵션을 붙여주면 된다.
$ ros2 pkg create [패키지이름] --build-type [빌드 타입] --dependencies [의존하는패키지1] [의존하는패키지n]
우선 빌드 타입으로는 C++ 를 사용한다면 ament_cmake 를 설정하고, Python 을 사용한다면 ament_python 을 입력한다. 참고로 GUI 프로그램을 작성해야 한다면 Python을 사용한다고 하더라도 rqt plugin 계열을 써야 하기 때문에 ament_cmake 를 입력해야한다.
$ ros2 pkg create test_pkg_rclcpp --build-type ament_cmake
$ ros2 pkg create test_pkg_rclpy --build-type ament_python
ros2 pkg create
명령어는 사용자가 패키지를 작성할 때 ament 빌드 시스템에 꼭 필요한 "CMakeLists.txt", "package.xml" 을 포함한 패키지 폴더를 생성한다.
실제로 패키지 생성을 해보자
$ cd robot_ws/src
생성할 패키지 이름은 'myfirst_ros_rclcpp_pkg'이다. ROS에서 패키지 이름은 모두 소문자를 사용하며 공백이 있으면 안 된다. 그리고 붙임표(-) 대신에 밑줄()을 사용해 각 단어를 이어붙이는 것을 스타일 규칙으로 삼고 있다. ROS 프로그래밍에서 코딩 스타일과 이름 규칙은 추후 이어지는 강좌에서 더 자세히 다루도록 하겠다. 그럼 다음 명령어로 my_first_ros_rclcpp_pkg 이름의 패키지를 생성해보자.
$ ros2 pkg create my_first_ros_rclcpp_pkg --build-type ament_cmake --dependencies rclcpp std_msgs
파이썬인 경우에는 다음과 같다.
$ ros2 pkg create my_first_ros_rclpy_pkg --build-type ament_python --dependencies rclpy std_msgs
앞의 명령어에서 의존하는 패키지로 'std_msgs'와 사용되는 클라이언트 라이브러리에 따라 'rclcpp' 또는 'rclpy'를 옵션으로 달아주었다. ROS의 표준 메시지 패키지인 std_msgs와 ROS에서 C/C++를 사용하기 위하여 클라이언트 라이브러리인 rclcpp 또는 Python을 사용하기 위한 클라이언트 라이브러리 rclpy를 사용하겠다는 것으로 패키지 생성에 앞서 미리 설치해야 한다는 의미이다. 이러한 의존하는 패키지 설정은 패키지를 생성할 때 지정할 수도 있지만, 생성한 다음 package.xml에서 직접 입력해도 된다.
패키지를 생성하였다면 '~/robot_ws/src'에 'my_first_ros_xxxxx_pkg' 패키지 폴더와 ROS 패키지가 갖추어야 할 기본 내부 폴더 그리고 package.xml 파일들이 생성된다. ament_cmake이냐 ament_python이냐에 따라 기본 구성 파일 시스템이 좀 상이한데 기본적으로는 아래와 같이 구성된다.
(my_first_ros_rclcpp_pkg)
.
├── include
│ └── my_first_ros_rclcpp_pkg
├── src
├── CMakeLists.txt
└── package.xml
3 directories, 2 files
(my_first_ros_rclpy_pkg)
.
├── my_first_ros_rclpy_pkg
│ └── __init__.py
├── resource
│ └── my_first_ros_rclpy_pkg
├── test
│ ├── test_copyright.py
│ ├── test_flake8.py
│ └── test_pep257.py
├── package.xml
├── setup.cfg
└── setup.py
3 directories, 8 files
ROS 2 특정 패키지 또는 전체 패키지를 빌드할 때에는 colcon 빌드 툴을 사용한다. 사용 방법은 매우 간단한 편인데 우선 소스 코드가 있는 workspace로 이동하고 colcon build 명령어로 전체를 빌드하게 된다. 여기서 빌드 옵션을 추가하여 사용하는게 일반적인데 특정 패키지만 선택하여 빌드하고자 할 때에는 --packages-select
옵션을 이용하고 symlink를 이용하려면 --symlink-install
옵션을 붙여주면 된다.
경험상 가장 많이 사용하게 되는 빌드 명령어는 아래와 같다. 첫 번째 명령어가 전체 패키지를 빌드할 때 사용되며 두 번째 명령어는 명령어 마지막에 특정 패키지 이름을 기재하여 그 해당 패키지만 빌드할 때 사용한다.
$ cd ~/robot_ws && colcon build --symlink-install
$ cd ~/robot_ws && colcon build --symlink-install --packages-select [패키지 이름]
추가
$ cd ~/robot_ws && colcon build --symlink-install --packages-up-to [패키지이름]
빌드 시스템에 필요한 부가 기능으로 ROS의 버전 컨트롤 시스템 툴인 vcstool
, 의존성 관리 툴인 rosdep
, 바이너리 패키지 관리 툴인 bloom
이 있다.
이번 장에서는 의존성 관리 툴인 rosdep
만 알아보자
ROS에서는 rosdep
이라는 툴을 쓰고 있는데 이는 "package.xml" 에 기술된 의존성 정보를 가지고 의존성 패키지들을 설치해 주는 역할을 한다.
예를 들어 ROS2-foxy를 소스코드로 설치 할 때 다음과 같은 명령어를 사용한다. 즉 /ros2_foxy/src 에 설치된 패키지들의 의존성을 살펴보고 필요한 패키지들을 설치하거나 특정 패키지는 의존성 문제를 무시한다는 것이다. 각 패키지의 package.xml의 depend 옵션을 보고 사용자가 직접 의존성 패키지들을 설치하는 방법도 있지만 간단한 rosdep 툴을 이용하여 해당 패키지의 의존성 환경을 해결하는 것도 상당히 편하며 다수의 패키지의 의존성을 해결할 때에는 직접 하나하나 체크하는 것보다 훨씬 수월할 것이다
$ sudo rosdep init
$ rosdep update
$ rosdep install --from-paths src --ignore-src --rosdistro foxy -y --skip-keys "console_bridge fastcdr fastrtps rti-connext-dds-5.3.1 urdfdom_headers"
지금 까지 빌드 시스템과 빌드 툴에 대해 알아보았다. 다음시간에는 ROS2의 패키지 파일에 대해 알아보고 직접 프로그래밍해보는 시간을 가져보겠다.