워크스페이스 설정 및 빌드

워크스페이스 구조 이해

ROS2에서 워크스페이스는 여러 패키지의 빌드, 실행 및 관리를 효율적으로 수행하기 위한 디렉토리 구조이다. 일반적으로 ROS2 프로젝트에서는 다양한 패키지들이 독립적으로 존재하며, 이 패키지들은 공통의 워크스페이스에서 관리된다.

워크스페이스를 설정하기 위해서는 다음과 같은 디렉토리 구조를 유지하는 것이 권장된다:

workspace/
  ├── src/
  └── install/
  └── log/
  └── build/
  • src/: 소스 코드와 패키지가 저장되는 디렉토리이다. 새로 생성한 패키지는 이 디렉토리 하위에 위치한다.

  • install/: 빌드된 결과물이 저장되는 디렉토리이다.

  • log/: 빌드 또는 실행 중에 생성된 로그 파일들이 저장된다.

  • build/: 빌드 도중 임시로 생성되는 파일들이 저장된다.

워크스페이스 생성

다음 명령어를 통해 새로운 워크스페이스를 생성할 수 있다:

mkdir -p ~/ros2_ws/src

여기서 ~/ros2_ws는 워크스페이스의 루트 디렉토리이며, src는 패키지들이 저장되는 소스 디렉토리이다.

colcon을 이용한 빌드

ROS2에서는 colcon이라는 빌드 도구를 사용하여 패키지를 빌드한다. colcon은 CMake 및 Python 기반의 빌드 시스템을 모두 지원하며, 종속성 관리 및 병렬 빌드를 자동으로 처리한다.

빌드를 하기 전에 반드시 현재 워크스페이스 경로로 이동한 후 실행해야 한다:

이 명령어는 src 디렉토리 내의 모든 패키지를 탐색하여 빌드를 수행한다.

빌드 설정

colcon build 명령어는 다양한 옵션을 지원한다. 그 중 대표적인 옵션 몇 가지를 살펴보면 다음과 같다:

  • --packages-select: 특정 패키지만 빌드할 때 사용한다.

  • --symlink-install: 빌드 후 설치된 파일을 심볼릭 링크로 관리하여 빠른 업데이트가 가능하게 한다.

이 외에도 colcon은 빌드 프로세스의 출력을 보다 직관적으로 관리하기 위한 다양한 옵션을 제공한다.

종속성 관리

ROS2에서는 패키지 간의 종속성을 정의하기 위해 package.xml 파일을 사용한다. 이 파일은 각 패키지의 종속성과 버전 정보를 담고 있어, 다른 패키지에서 이 패키지를 의존하거나 함께 빌드할 수 있다.

package.xml에서 종속성을 정의하는 방법은 다음과 같다:

<build_depend>는 빌드 중에 필요한 패키지를, <exec_depend>는 실행 시 필요한 패키지를 정의한다.

CMakeLists.txt 파일의 설정

ROS2 패키지는 CMake 빌드 시스템을 사용하는데, 이를 위한 설정 파일이 CMakeLists.txt이다. CMakeLists.txt 파일에서는 패키지의 빌드 방법 및 종속성 등을 설정한다.

대표적인 설정은 다음과 같다:

위 설정에서 find_package는 종속 패키지를 탐색하고, ament_target_dependencies는 타겟 실행 파일이 어떤 패키지에 의존하는지를 명시한다.

빌드 후 환경 설정

빌드가 완료된 후에는, 환경 변수를 설정해야 ROS2 노드 및 기타 실행 파일을 올바르게 실행할 수 있다. 이를 위해 다음 명령어를 사용하여 환경을 설정한다:

이 명령어는 빌드된 ROS2 패키지의 경로를 시스템 환경 변수에 추가하여 ROS2 시스템 내에서 사용될 수 있도록 한다.

빌드 시스템의 최적화

ROS2의 빌드 시스템에서는 소스 코드의 크기 및 복잡도에 따라 빌드 시간이 오래 걸릴 수 있다. 이를 해결하기 위한 최적화 방법을 살펴보자.

1. 병렬 빌드

colcon build 명령어는 병렬로 빌드를 진행할 수 있으며, 기본적으로 시스템의 모든 코어를 사용하여 빌드를 수행한다. 하지만 수동으로 코어 수를 조정하여 빌드 속도를 제어할 수도 있다:

이 명령어는 <worker_count> 개수만큼의 병렬 작업을 수행한다. 일반적으로 시스템의 CPU 코어 수보다 1~2개 적은 수로 설정하는 것이 좋다.

2. 빌드 캐시 활용

빌드 과정에서 반복되는 작업을 줄이기 위해 빌드 캐시를 활용할 수 있다. 캐시는 이전 빌드에서 사용된 파일이나 중간 파일들을 저장하여 불필요한 작업을 피할 수 있게 해준다. colcon은 기본적으로 빌드 캐시를 자동으로 관리하지만, 빌드 캐시를 수동으로 관리하고 싶다면 다음 명령어를 사용할 수 있다:

이 명령어는 빌드를 다시 수행할 때 이전 빌드 결과를 삭제하지 않고 캐시를 재사용한다.

3. 선택적 패키지 빌드

모든 패키지를 빌드하는 대신, 특정 패키지만 빌드하는 것이 빌드 시간을 크게 단축시킬 수 있다. 이를 위해서는 --packages-select 옵션을 사용하여 원하는 패키지들만 선택적으로 빌드할 수 있다:

4. 빌드 로그 분석

colcon은 빌드 과정에서 발생하는 로그를 상세하게 제공하며, 이를 통해 어떤 부분에서 성능 저하가 발생하는지 파악할 수 있다. 빌드 로그는 log 디렉토리에 저장되며, 문제를 해결하거나 최적화를 수행하는 데 매우 유용하다.

이 명령어로 최신 빌드 로그를 확인할 수 있으며, 빌드 중 발생한 경고나 오류 메시지를 분석하여 빌드 최적화에 도움이 될 수 있다.

패키지 의존성 최적화

복잡한 프로젝트에서는 패키지 간의 의존성이 매우 중요하다. 잘못된 종속성 관리는 빌드 시간뿐만 아니라 실행 성능에도 큰 영향을 미친다. 다음은 패키지 의존성을 최적화하기 위한 몇 가지 방법이다.

1. 종속성 최소화

package.xml에서 정의된 종속성을 최소화함으로써 불필요한 패키지 빌드를 방지할 수 있다. 필요하지 않은 종속 패키지는 제거하고, 가능하다면 공통 라이브러리를 활용하는 것이 좋다.

2. 빌드 종속성과 실행 종속성 구분

build_dependexec_depend를 명확하게 구분하여 빌드 과정에서만 필요한 패키지와 실행 중에만 필요한 패키지를 정확히 정의해야 한다. 이렇게 하면 빌드 시간과 실행 환경 설정에서의 불필요한 작업을 줄일 수 있다.

3. 중복 종속성 제거

여러 패키지가 동일한 종속성을 가질 경우, 이를 관리하는 방법을 최적화할 수 있다. find_packageament_target_dependencies에서 중복된 항목을 제거하여 컴파일 시간과 링크 시간을 줄일 수 있다.

빌드 오류 해결

ROS2 환경에서 발생할 수 있는 다양한 빌드 오류를 해결하기 위해서는 다음과 같은 일반적인 접근 방식을 사용할 수 있다:

1. 종속 패키지 확인

빌드 오류가 발생했을 때, 가장 먼저 확인해야 할 것은 종속 패키지의 설치 여부이다. 다음 명령어로 누락된 패키지를 확인할 수 있다:

이 명령어는 현재 워크스페이스의 src 디렉토리에 있는 모든 패키지의 종속성을 자동으로 설치한다.

2. 빌드 로그 분석

빌드가 실패할 경우, log/latest_build.log 파일을 확인하여 오류 메시지를 분석하는 것이 중요하다. 오류 메시지의 내용에 따라 빌드 오류의 원인을 정확히 파악할 수 있다.

워크스페이스 디렉터리 구조

ROS2 Humble에서 프로젝트를 체계적으로 관리하기 위해서는 워크스페이스(workspace)라는 개념을 반드시 이해해야 한다. 일반적으로 워크스페이스는 다음과 같은 디렉터리 구조를 갖는다.

  • src/: ROS2 패키지들의 소스 코드가 위치한다.

  • build/: colcon 빌드 도구가 컴파일 결과물을 임시로 저장한다.

  • install/: 빌드 결과물이 설치되는 디렉터리이며, 실행파일이나 라이브러리를 참조할 때 사용한다.

  • log/: 빌드 및 실행 과정에서 발생하는 로그 파일들이 저장된다.

이를 통해 서로 다른 프로젝트나 여러 패키지를 한꺼번에 빌드하고 설치할 수 있다.

colcon 빌드 개요

ROS2에서는 주로 colcon이라는 빌드 도구를 사용한다. colcon은 다음과 같은 단계를 거쳐 패키지를 빌드한다.

  1. 패키지 탐색: src/ 디렉터리를 탐색하여 패키지를 찾는다.

  2. 빌드 순서 결정: 의존 관계를 파악하여 빌드 순서를 정한다.

  3. 컴파일: 패키지 내의 CMakeLists.txt 또는 setup.py를 기반으로 컴파일한다.

  4. 설치: 컴파일된 결과물을 install/ 디렉터리에 배치한다.

이 과정을 통해 ROS2 프로젝트에 속한 여러 패키지를 일괄로 빌드 및 설치할 수 있다.

환경 변수 설정

colcon으로 빌드한 결과물을 활용하려면 적절한 환경 변수를 설정해야 한다. 일반적으로 빌드가 끝나면 다음과 같은 명령어를 이용해 워크스페이스를 활성화한다.

이 명령은 워크스페이스 내의 실행파일, 라이브러리, 메시지 타입 등을 시스템 환경에 등록한다. Bash 이외에도 Zsh나 Fish 같은 쉘을 쓰는 경우 아래와 같이 해당 쉘용 스크립트를 실행해야 한다.

이후 ROS2 명령어(ros2 run, ros2 topic, ros2 service 등)를 실행할 때, 현재 워크스페이스에서 빌드된 패키지들을 바로 참조할 수 있게 된다.

워크스페이스 내에서의 수학적 개념 예시

ROS2 환경에서 서로 다른 패키지가 상호작용하며 데이터(예: 센서 값, 로봇 상태, 지도 정보 등)를 주고받는다. 이를 수학적으로 표현할 때 벡터와 행렬을 다루는 경우가 많다. 예를 들어, 2×2 크기의 어떤 행렬 $\mathbf{A}$를 생각해보자.

A=(abcd)\mathbf{A} = \begin{pmatrix} a & b \\ c & d \end{pmatrix}

이 행렬을 사용하여 센서 데이터의 변환이나 좌표계 변환 등을 모델링할 수 있다. 예를 들어, 2차원 공간에서 위치를 나타내는 벡터 $\mathbf{x}$가 있다고 할 때

x=(x1x2)\mathbf{x} = \begin{pmatrix} x_1 \\ x_2 \end{pmatrix}

위의 행렬 $\mathbf{A}$와 벡터 $\mathbf{x}$의 곱을 통해 새로운 좌표계를 계산할 수 있다.

Ax=(abcd)(x1x2)=(ax1+bx2cx1+dx2)\mathbf{A}\mathbf{x} = \begin{pmatrix} a & b \\ c & d \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix} = \begin{pmatrix} ax_1 + b x_2 \\ c x_1 + d x_2 \end{pmatrix}

이와 같은 선형변환(linear transformation) 개념은 로봇의 조인트 변환이나 센서값 해석 등 다양한 로보틱스 응용 분야에서 자주 활용된다. ROS2의 여러 패키지를 연계하여 이 수학적 연산을 보다 편리하게 자동화할 수 있다.

예시 코드를 통해 살펴보기

간단한 예시로, C++ 기반 패키지를 생성하고 빌드하는 작업을 살펴보자. 패키지를 생성하기 위해서는 ros2 pkg create 명령어를 사용한다.

생성이 완료되면 my_ros2_ws/src/my_example_pkg/ 경로에 기본적인 C++ 패키지 구조가 만들어진다. 이후 다음과 같이 워크스페이스 최상위 디렉터리(my_ros2_ws)로 이동하여 빌드를 수행한다.

만약 특정 패키지만 빌드하고 싶다면 다음과 같이 --packages-select 옵션을 사용할 수 있다.

빌드가 끝나면 반드시 아래 명령어를 통해 환경 변수를 업데이트해준다.

이와 같은 과정을 통해 새로운 패키지를 만들고 빌드해볼 수 있다.

빌드 단계 시각화

아래 다이어그램은 colcon 빌드 프로세스의 흐름을 간단히 나타낸다.

spinner

빌드 환경 최적화

colcon을 사용할 때는 다양한 옵션을 활용하여 빌드 환경을 최적화할 수 있다. 일반적으로 다음과 같은 방법이 있다.

  • 병렬 빌드: 멀티코어 CPU 환경에서 빌드 속도를 높이기 위해 --parallel-workers 또는 -j 옵션을 사용한다.

    사용 가능한 CPU 코어 수에 맞춰 적절히 설정하면 빌드 시간을 단축할 수 있다.

  • 빌드 타입 설정: C++ 프로젝트인 경우 CMAKE_BUILD_TYPERelease로 설정하면 최적화가 활성화된다.

    디버그 목적이라면 Debug 또는 RelWithDebInfo를 사용하기도 한다.

  • 캐시 활용: ccache 등의 캐시 도구를 사용해 빌드된 오브젝트를 재활용할 수 있다. 이를 위해서는 따로 ccache를 설치하고, CMake 설정에서 사용하도록 지정해야 한다.

자동 의존성 관리

워크스페이스에서 ROS2 패키지를 빌드할 때, 자동으로 의존성을 확인하고 설치해주는 툴인 rosdep을 사용하면 편리하다. 예를 들어, C++ 패키지가 특정 라이브러리에 의존하는 경우 package.xml에 해당 라이브러리를 기술해두면, rosdep이 알아서 설치해준다.

  1. 의존 관계 설정: package.xml 파일에 <build_depend><exec_depend> 등의 태그를 넣어 의존 라이브러리를 명시한다.

  2. rosdep 초기화 및 업데이트

    :

  3. 의존성 설치

    : 워크스페이스 내의 패키지들이 필요로 하는 의존성을 한꺼번에 설치한다.

이를 통해 colcon 빌드 시 필요한 라이브러리가 누락되지 않도록 자동으로 관리할 수 있다.

오버레이 워크스페이스

ROS2에서는 여러 개의 워크스페이스를 "오버레이(overlay)" 형태로 겹쳐서 사용할 수 있다. 예를 들어, 먼저 빌드된 공통 라이브러리나 메시지 정의 패키지를 다른 워크스페이스에 중첩하여 사용할 수 있다.

  1. 기본 워크스페이스 빌드 및 source

  2. 오버레이용 워크스페이스 생성

  3. 오버레이 워크스페이스 빌드

  4. 테스트: 오버레이에 있는 패키지(새로운 기능)와 기본 워크스페이스(기존 기능)가 함께 참조되는지 확인한다.

이 방식을 잘 활용하면 공통 패키지를 공유하면서, 새로운 기능을 실험하거나 다른 버전의 패키지를 부분적으로 교체할 수 있다.

복잡한 좌표 변환 예시

예를 들어, 2차원 회전변환 행렬 $\mathbf{R}_{\theta}$와 이동 벡터 $\mathbf{t}$를 사용하여 로봇의 좌표계를 변환하는 상황을 생각해보자.

Rθ=(cosθsinθsinθcosθ),t=(txty)\mathbf{R}_{\theta} = \begin{pmatrix} \cos \theta & -\sin \theta \\ \sin \theta & \cos \theta \end{pmatrix} ,\quad \mathbf{t} = \begin{pmatrix} t_x \\ t_y \end{pmatrix}

2차원 위치 벡터 $\mathbf{x}$에 위 변환을 적용하면, 새로운 좌표 $\mathbf{x}'$는 다음과 같이 정의된다.

x=Rθx+t\mathbf{x}' = \mathbf{R}_{\theta}\mathbf{x} + \mathbf{t}

이를 C++ 또는 Python 패키지에서 구현한다면, 다음과 같은 단계를 거친다.

  1. 메시지 타입(geometry_msgs 등)을 사용하여 $\mathbf{x}$와 $\mathbf{t}$를 주고받는다.

  2. 변환 수식을 코드로 작성한다.

  3. 빌드 후, 노드 간 통신으로 실제 로봇 상태를 업데이트하거나 시뮬레이션에서 시각화한다.

이렇듯 여러 패키지가 각자 맡은 수학 연산이나 로직을 수행하고, 서로 메시지를 교환하며 시스템 전체가 돌아가게 된다.

빌드 결과 확인과 디버깅

빌드가 성공적으로 끝났다면 install/ 디렉터리에 패키지별로 실행 파일이 설치되고, log/ 디렉터리에는 빌드와 관련된 로그가 남는다. 빌드 및 실행 과정에서 문제가 생겼다면 log/ 디렉터리에서 빌드 에러 메시지를 확인한다.

  • 빌드 에러 로그:

  • 실행 로그: 패키지 실행 중 에러가 발생하면 ros2 run 명령어의 콘솔 출력 또는 별도의 로그 파일을 확인한다.

이러한 로그는 특히 대규모 프로젝트나 여러 의존성을 가진 패키지를 빌드할 때 문제점을 분석하는 데 중요한 자료가 된다.

더 복잡한 빌드 흐름

프로젝트 규모가 커질수록 여러 의존 패키지가 늘어나고, 테스트를 비롯한 다양한 빌드 대상이 생긴다. 아래는 이를 확장하여 테스트 및 문서화 단계까지 추가한 흐름 예시다.

spinner

교차 컴파일(Cross-Compiling)

ROS2를 임베디드 보드나 다른 아키텍처에서 구동해야 하는 경우, 워크스페이스를 교차 컴파일하여 타겟 환경에 맞는 실행 파일을 생성할 수 있다. 이때는 다음과 같은 절차가 필요하다.

  1. 타겟 크로스 컴파일 툴체인 설치: 예를 들어, ARM 계열 보드라면 GCC ARM 크로스 컴파일러를 설치한다.

  2. 툴체인 파일 작성

    : CMake를 통해 빌드를 진행할 때, 크로스 컴파일용 툴체인 파일

    을 만든다. 예시 구조:

  3. colcon 빌드 시 툴체인 적용:

  4. 설치된 결과물 전송: 빌드가 끝난 후 install/ 디렉터리 내 바이너리나 라이브러리를 타겟 장치로 복사하여 실행한다.

교차 컴파일 시에는 타겟 플랫폼에 맞는 ROS2 버전, 종속 라이브러리 등의 호환성을 충분히 고려해야 한다.

빌드 구성 파일 사용(Colcon Default Options)

프로젝트 규모가 커질수록 매번 명령줄에서 긴 빌드 옵션을 입력하는 것은 번거롭다. colcon은 colcon defaults 기능을 통해 YAML 포맷의 빌드 옵션 설정 파일을 지원한다. 다음 예시를 살펴보자.

  • default.yaml (예시)

이후 빌드시 다음과 같이 간단히 명령어를 입력한다.

이렇게 하면 default.yaml 내 설정이 자동으로 적용되면서, 빌드 설정을 매번 입력하지 않아도 된다.

병렬 빌드, 우선순위 빌드

패키지가 아주 많거나, 일부 패키지만 빠르게 빌드해서 테스트해야 할 때는 colcon의 패키지 필터 기능을 활용할 수 있다.

  • --packages-up-to

    : 특정 패키지와 그 패키지에 필요한 의존 패키지만 빌드한다.

  • --packages-skip

    : 특정 패키지(와 의존 패키지)를 빌드 대상에서 제외한다.

  • --continue-on-error: 일부 패키지에서 빌드 에러가 나도 전체 빌드를 중단하지 않고 계속 진행한다.

Multi-Directory Workspace

ROS2 프로젝트의 규모가 매우 커지면, 워크스페이스 내에 하나의 src/ 디렉터리만 사용하기보다는 서브 디렉터리를 여러 개 두어 그룹화할 수 있다. 예를 들어,

이 구조에서 core_packages/에는 핵심 라이브러리와 메시지 정의를, sensor_packages/에는 센서 관련 패키지를, navigation_packages/에는 경로 계획 및 로봇 내비게이션 패키지를 넣을 수 있다. 이렇게 하면 colcon 빌드시 특정 서브 디렉터리만 선택적으로 빌드하거나 관리하기가 용이해진다.

확장된 수학적 예시

3차원 공간에서의 회전행렬 $\mathbf{R}$과 변환 벡터 $\mathbf{t}$를 고려해보자. 3차원 회전변환 행렬은 특수 직교 행렬(SO(3))로서, 다음과 같은 성질을 만족한다.

RSO(3)RR=I,det(R)=1\mathbf{R} \in SO(3) \quad\Longrightarrow\quad \mathbf{R}^\top \mathbf{R} = \mathbf{I}, \quad \det(\mathbf{R}) = 1

이때 위치 벡터 $\mathbf{x}$를 새로운 좌표계로 변환하는 식은 다음과 같다.

x=Rx+t\mathbf{x}' = \mathbf{R}\mathbf{x} + \mathbf{t}

예컨대 로봇 팔의 조인트 변환, 카메라 좌표계 변환 등 다양한 로보틱스 시나리오에서 이와 같은 3×3 회전행렬과 3×1 이동벡터를 통해 좌표계를 자유롭게 옮길 수 있다. C++ 또는 Python 노드에서 이를 구현할 때, Eigen 라이브러리 등을 사용하면 행렬 연산을 간단히 처리할 수 있다. 빌드 과정에서는 package.xmlCMakeLists.txt 파일에 Eigen을 의존성으로 명시해야 한다.

테스팅(Testing) 및 연동

colcon은 빌드 후 바로 테스트를 실행하기 위한 옵션을 제공한다.

  • colcon test: 워크스페이스에 포함된 모든 패키지의 테스트를 수행한다.

  • colcon test-result: 테스트 결과를 요약해 보여준다. 테스트에서 사용되는 프레임워크(C++의 gtest, Python의 pytest 등)는 각 패키지별로 구성할 수 있다.

단위 테스트, 통합 테스트를 체계적으로 적용하면, 여러 패키지가 상호 작용하는 복잡한 시스템에서도 안정성을 확보할 수 있다.

Docker를 활용한 빌드 환경

ROS2 Humble 프로젝트를 진행할 때, 개별 개발 환경을 통일하거나 종속 라이브러리 충돌 문제를 줄이기 위해 Docker를 자주 활용한다. Docker 이미지를 사용하면 일관된 환경에서 빌드를 수행할 수 있고, 교차 컴파일 환경 세팅도 비교적 간단해진다.

  1. 기본 Dockerfile 작성 아래는 ROS2 Humble 환경을 담은 간단한 Dockerfile 예시다.

    이 Dockerfile을 빌드하면, ROS2 Humble 및 colcon 도구를 포함한 우분투 환경을 갖춘 Docker 이미지가 만들어진다.

  2. 소스 코드 복사와 빌드 위 예시 Dockerfile에 이어서, 컨테이너 내부에서 ROS2 패키지를 빌드하려면 추가로 아래와 같은 단계를 수행한다.

    이렇게 구성하면 컨테이너 이미지를 빌드하는 시점에 ROS2 패키지가 자동으로 빌드되며, 컨테이너 실행 시 별도의 빌드 단계 없이 바로 ROS2 실행 파일을 사용할 수 있다.

  3. Multi-stage Build 활용 Docker 이미지 크기를 줄이기 위해, multi-stage build 기법을 사용한다. 빌드 전용 이미지를 먼저 구성한 뒤, 빌드 결과물만 최종 실행 이미지에 담는 방식이다. 예시는 다음과 같다.

    이 구성에서는 빌드 관련 툴체인을 포함한 거대한 builder 스테이지와, 실행에 필요한 최소 구성만 담은 runtime 스테이지를 분리한다. 최종 런타임 이미지는 훨씬 작아질 수 있다.

  4. Docker 컨테이너 내 테스트 컨테이너 내에서 테스트를 진행하고 싶다면, colcon test를 이용해 빌드 후 테스트 과정을 수행할 수 있다. 이를 CI/CD 파이프라인과 결합하면, 호스트 시스템의 설정에 영향을 받지 않는 일관된 테스트 환경을 구축할 수 있다.

CI/CD 파이프라인 연동

GitHub Actions, GitLab CI, Jenkins 등 다양한 CI/CD 도구를 활용하여, ROS2 Humble 빌드를 자동화할 수 있다. 일반적으로 다음 과정을 거친다.

  1. CI 스크립트 작성: 예를 들어 GitHub Actions에서 .github/workflows/ci.yml 파일을 작성하여, 빌드와 테스트 단계를 정의한다.

  2. 도커 기반 빌드: CI 환경에 Docker를 설치하거나 Docker In Docker(단독 Runner) 방식을 사용해, 앞서 언급한 Dockerfile로 빌드를 수행한다.

  3. 테스트 및 배포: 빌드 후 자동으로 테스트를 수행하고, 성공하면 이미지를 레지스트리에 업로드하거나 바이너리를 공개 Repository로 배포한다.

CI/CD 파이프라인을 구축하면, 팀원 간의 코드 변경 시에도 빠르게 빌드 오류나 의존성 문제를 파악할 수 있다.

정적 분석과 코드 포매팅

ROS2 프로젝트가 커질수록 코드의 일관성과 품질을 유지하기 위해 정적 분석(static analysis)나 자동 포매팅 도구를 사용하는 것이 유리하다.

  • clang-tidy: C++ 코드에 대해 정적 분석을 수행한다. CMake 설정에서 -DCMAKE_CXX_CLANG_TIDY= 옵션을 추가하거나, ament_clang_tidy를 활용한다.

  • clang-format: 코드를 자동으로 정해진 스타일에 맞춰 포매팅한다.

  • cppcheck: 또 다른 정적 분석 도구로, 코딩 실수를 미리 찾아낼 수 있다.

colcon 빌드시 이들 도구를 적용하려면 CMakeLists.txt나 별도의 Quality-of-Life(QoL) 스크립트를 작성하여 자동 실행되도록 설정한다.

코드 커버리지(Coverage) 측정

테스트가 제대로 동작하는지, 소스 코드가 어느 정도 커버되었는지 확인하기 위해 코드 커버리지 도구를 사용할 수 있다.

  1. gcov, lcov 설치

    : Ubuntu 환경이라면 다음과 같은 명령어로 설치한다.

  2. CMake 설정

    : 빌드시 커버리지 옵션을 활성화한다.

  3. 테스트 실행 후 커버리지 측정

    :

  4. 그래프화: genhtml 등을 사용하여 HTML 리포트를 생성한다.

이 과정을 CI/CD와 연동하면, 빌드마다 자동으로 커버리지 결과가 생성되어 품질 관리에 도움이 된다.

ament 빌드 타입과 Python 패키지

ROS2에서는 ament 계열 빌드 도구를 사용하여 C++부터 Python, 그리고 기타 언어를 포함한 다양한 패키지를 동시에 관리한다. 일반적으로 C++ 패키지는 ament_cmake 빌드 방식을, Python 패키지는 ament_python 빌드 방식을 사용한다.

  • C++: ament_cmake CMakeLists.txt 파일에 find_package(ament_cmake REQUIRED)와 같은 구문을 추가하고, ament_package() 호출을 통해 ROS2 패키지로서 동작하게 만든다.

  • Python: ament_python setup.py, setup.cfg 등을 통해 파이썬 패키지를 정의하고, package.xml 파일에서 <build_type>ament_python</build_type> 등을 명시한다. Python 스크립트 기반으로 노드를 작성하면 빌드(설치) 과정에서 자동으로 패키징된다.

이와 같은 구조를 통해 C++와 Python 노드가 혼합된 복합 프로젝트도 하나의 워크스페이스에서 일괄 빌드가 가능하다.

하드웨어 가속과 특별한 빌드 설정

GPU나 FPGA 같은 특수 하드웨어를 사용하는 경우, ROS2 패키지 빌드시 해당 하드웨어용 라이브러리를 링크하거나 특수 플래그를 설정해야 한다.

  1. GPU 가속: CUDA, OpenCL 라이브러리를 사용하는 패키지라면, package.xml에 해당 라이브러리를 의존성으로 명시하고 CMakeLists.txt에서 컴파일 플래그를 추가한다.

  2. FPGA: Xilinx 또는 Intel FPGA 툴체인을 설치하고, 교차 컴파일 방식과 유사하게 빌드를 진행한다. FPGA 보드에서 동작하는 커스텀 로직을 ROS2 메시지 인터페이스로 감싸는 과정을 거칠 수 있다.

하드웨어 별로 빌드 설정이 크게 달라질 수 있으므로, 워크스페이스를 분리하거나 오버레이 워크스페이스 기법을 적극 활용한다.

버전 관리 전략

ROS2 패키지의 버전 관리(semantic versioning 등)는 package.xml 파일의 <version> 태그와 Git 태그를 함께 사용한다. 프로젝트가 커질수록 다음과 같은 전략이 권장된다.

  • 단일 리포지토리 vs. 멀티 리포지토리: 여러 패키지를 하나의 리포지토리에 모으는 방식을 “monorepo”라고 부르며, 각각 별도의 리포지토리로 관리하는 것을 “multirepo”라고 부른다. 빌드/배포 편의성, 팀 규모 등에 따라 결정한다.

  • branch 전략: 지속적으로 개발되는 main(default) branch 외에, 기능별 branch나 릴리스 branch를 구분하여 관리한다.

  • tagging: 안정 버전의 시점에 태그를 달아, colcon 빌드 및 배포 시점에 특정 태그를 체크아웃해 사용한다.

ament_lint와 코드 품질 도구

ROS2는 ament_lint 패키지를 통해 린팅과 포맷 체크, 정적 분석을 쉽게 적용할 수 있다. CMakeLists.txtfind_package(ament_lint_auto REQUIRED)를 추가하고, ament_lint_auto_find_test_dependencies() 등을 호출하면 여러 린트 체크를 자동화한다.

  • ament_lint_common: ROS2 코딩 규칙에 맞춰 C++ 및 Python 코드를 검사한다.

  • ament_cpplint, ament_flake8: C++용 cpplint, Python용 flake8 같은 구체적인 툴에 대한 래퍼.

  • ament_xmllint: package.xml 문법 및 형식을 검사한다.

Embedded ROS2 빌드 사례

아주 제한된 환경(예: Raspberry Pi Zero W, BeagleBone Black)에서 ROS2를 동작시키려면, 많은 패키지를 제거하고 최소한의 기능만 남긴 빌드가 필요하다.

  1. ROS2 Base 설치: ros-humble-ros-base 정도만 깔고, GUI 관련 패키지나 RViz는 제외한다.

  2. colcon build --packages-up-to 옵션으로 정말 필요한 패키지까지만 빌드한다.

  3. 네트워크 설정: 임베디드 장치에서 DDS 통신(예: CycloneDDS, Fast DDS)이 안정적으로 동작하도록 QoS 설정을 간단하게 조정한다.

추가적인 상태 머신, 동적 파라미터

워크스페이스에서 상태 머신(state machine) 라이브러리(예: SMACH, rclcpp_lifecycle)나 동적 파라미터(dynparam)를 적극 활용할 수도 있다. 빌드 자체는 동일하게 colcon을 사용하지만, 추가 라이브러리가 필요하면 package.xml에 해당 의존성을 명시한 뒤 rosdep install을 통해 미리 설치하도록 한다.

빌드 산출물 배포

빌드가 완료된 패키지를 다른 환경으로 옮기거나, 팀원과 공유해야 할 때 다음 방법을 쓸 수 있다.

  • Binary Archive: install/ 디렉터리를 통째로 tar 압축 후, 타겟 환경에 압축 해제하여 사용한다.

  • Debian 패키지: bloom 툴과 함께 ROS Build Farm을 통해 Debian 패키지(.deb) 형태로 배포할 수도 있다.

  • Docker 이미지: 앞서 언급한 Dockerfile을 통해 컨테이너 이미지를 빌드하여 Docker Hub 등 레지스트리에 올린다.

고차원 행렬 연산 예시

로봇 움직임 계획(trajectory planning) 등을 위한 고차원 행렬 연산을 예로 들면, $6×6$ 크기의 조인트 변환 행렬 $\mathbf{J}$ (Jacobian matrix)를 사용하기도 한다.

J=(x1θ1x1θ6x6θ1x6θ6)\mathbf{J} = \begin{pmatrix} \frac{\partial x_1}{\partial \theta_1} & \dots & \frac{\partial x_1}{\partial \theta_6} \\ \vdots & \ddots & \vdots \\ \frac{\partial x_6}{\partial \theta_1} & \dots & \frac{\partial x_6}{\partial \theta_6} \end{pmatrix}

이 행렬 $\mathbf{J}$은 로봇 조인트각 $\theta_i$ 변화가 엔드 이펙터(말단)의 위치, 속도 등에 어떤 영향을 미치는지 표현한다. 실제 코드에서는 Eigen 등을 사용해 $\mathbf{J}$를 계산하고, colcon 빌드를 통해 결과를 배포한다. 이러한 수학 연산은 고성능 CPU/GPU가 요구될 수도 있으며, 빌드 시 적절한 최적화(컴파일 플래그)를 지정하여 성능을 개선한다.

유지 보수와 확장

워크스페이스가 커질수록 다음과 같은 측면을 고민해야 한다.

  • 캐시 전략: ccache, sccache 등을 잘 활용해 빌드 시간을 줄인다.

  • 테스트 분리: 통합 테스트가 너무 커지면 빌드/테스트 시간을 관리하기 어렵다. 핵심 패키지부터 단계적으로 테스트를 나누어 수행한다.

  • 오버레이: 본 프로젝트와 별개로, 새로운 실험적 기능을 빠르게 시도하려면 오버레이 워크스페이스에만 패키지를 두고 빌드해 본다.

Last updated