# 워크스페이스 설정 및 빌드

#### 워크스페이스 구조 이해

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

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

```bash
workspace/
  ├── src/
  └── install/
  └── log/
  └── build/
```

* **src/**: 소스 코드와 패키지가 저장되는 디렉토리이다. 새로 생성한 패키지는 이 디렉토리 하위에 위치한다.
* **install/**: 빌드된 결과물이 저장되는 디렉토리이다.
* **log/**: 빌드 또는 실행 중에 생성된 로그 파일들이 저장된다.
* **build/**: 빌드 도중 임시로 생성되는 파일들이 저장된다.

#### 워크스페이스 생성

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

```bash
mkdir -p ~/ros2_ws/src
```

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

#### colcon을 이용한 빌드

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

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

```bash
cd ~/ros2_ws
colcon build
```

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

#### 빌드 설정

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

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

  ```bash
  colcon build --packages-select <package_name>
  ```
* **--symlink-install**: 빌드 후 설치된 파일을 심볼릭 링크로 관리하여 빠른 업데이트가 가능하게 한다.

  ```bash
  colcon build --symlink-install
  ```

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

#### 종속성 관리

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

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

```xml
<build_depend>package_name</build_depend>
<exec_depend>package_name</exec_depend>
```

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

#### CMakeLists.txt 파일의 설정

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

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

```cmake
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(my_node src/my_node.cpp)
ament_target_dependencies(my_node rclcpp std_msgs)
```

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

#### 빌드 후 환경 설정

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

```bash
source ~/ros2_ws/install/setup.bash
```

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

#### 빌드 시스템의 최적화

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

**1. 병렬 빌드**

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

```bash
colcon build --parallel-workers <worker_count>
```

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

**2. 빌드 캐시 활용**

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

```bash
colcon build --no-clean
```

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

**3. 선택적 패키지 빌드**

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

```bash
colcon build --packages-select <package1> <package2>
```

**4. 빌드 로그 분석**

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

```bash
cat ~/ros2_ws/log/latest_build.log
```

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

#### 패키지 의존성 최적화

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

**1. 종속성 최소화**

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

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

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

**3. 중복 종속성 제거**

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

#### 빌드 오류 해결

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

**1. 종속 패키지 확인**

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

```bash
rosdep install --from-paths src --ignore-src -r -y
```

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

**2. 빌드 로그 분석**

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

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

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

```
my_ros2_ws/
 ├── src/
 ├── build/
 ├── install/
 └── log/
```

* **src/**: ROS2 패키지들의 소스 코드가 위치한다.
* **build/**: colcon 빌드 도구가 컴파일 결과물을 임시로 저장한다.
* **install/**: 빌드 결과물이 설치되는 디렉터리이며, 실행파일이나 라이브러리를 참조할 때 사용한다.
* **log/**: 빌드 및 실행 과정에서 발생하는 로그 파일들이 저장된다.

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

#### colcon 빌드 개요

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

1. **패키지 탐색**: `src/` 디렉터리를 탐색하여 패키지를 찾는다.
2. **빌드 순서 결정**: 의존 관계를 파악하여 빌드 순서를 정한다.
3. **컴파일**: 패키지 내의 CMakeLists.txt 또는 setup.py를 기반으로 컴파일한다.
4. **설치**: 컴파일된 결과물을 `install/` 디렉터리에 배치한다.

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

#### 환경 변수 설정

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

```
source install/setup.bash
```

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

```
source install/setup.zsh
source install/setup.fish
```

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

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

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

$$
\mathbf{A} =  \begin{pmatrix} a & b \ c & d \end{pmatrix}
$$

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

$$
\mathbf{x} =  \begin{pmatrix} x\_1 \ x\_2 \end{pmatrix}
$$

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

$$
\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` 명령어를 사용한다.

```
ros2 pkg create --build-type ament_cmake my_example_pkg
```

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

```
cd ~/my_ros2_ws
colcon build
```

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

```
colcon build --packages-select my_example_pkg
```

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

```
source install/setup.bash
```

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

#### 빌드 단계 시각화

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

{% @mermaid/diagram content="flowchart TB
A\[시작] --> B\[src 디렉터리 내 패키지 탐색]
B --> C\[의존 관계 계산]
C --> D\[패키지 빌드]
D --> E\[결과물 설치]
E --> F\[설정 파일 생성]
F --> G\[환경 변수 source로 적용]" %}

#### 빌드 환경 최적화

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

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

  ```
  colcon build --parallel-workers 4
  ```

  사용 가능한 CPU 코어 수에 맞춰 적절히 설정하면 빌드 시간을 단축할 수 있다.
* **빌드 타입 설정**: C++ 프로젝트인 경우 `CMAKE_BUILD_TYPE`을 `Release`로 설정하면 최적화가 활성화된다.

  ```
  colcon build --cmake-args -DCMAKE_BUILD_TYPE=Release
  ```

  디버그 목적이라면 `Debug` 또는 `RelWithDebInfo`를 사용하기도 한다.
* **캐시 활용**: ccache 등의 캐시 도구를 사용해 빌드된 오브젝트를 재활용할 수 있다. 이를 위해서는 따로 ccache를 설치하고, CMake 설정에서 사용하도록 지정해야 한다.

#### 자동 의존성 관리

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

1. **의존 관계 설정**: `package.xml` 파일에 `<build_depend>`나 `<exec_depend>` 등의 태그를 넣어 의존 라이브러리를 명시한다.
2. rosdep 초기화 및 업데이트

   :

   ```
   sudo rosdep init
   rosdep update
   ```
3. 의존성 설치

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

   ```
   rosdep install --from-paths src --ignore-src -y
   ```

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

#### 오버레이 워크스페이스

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

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

   ```
   cd ~/base_ws
   colcon build
   source install/setup.bash
   ```
2. 오버레이용 워크스페이스 생성

   ```
   mkdir -p ~/overlay_ws/src
   cd ~/overlay_ws
   ```
3. 오버레이 워크스페이스 빌드

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

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

#### 복잡한 좌표 변환 예시

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

$$
\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}'$는 다음과 같이 정의된다.

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

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

1. 메시지 타입(geometry\_msgs 등)을 사용하여 $\mathbf{x}$와 $\mathbf{t}$를 주고받는다.
2. 변환 수식을 코드로 작성한다.
3. 빌드 후, 노드 간 통신으로 실제 로봇 상태를 업데이트하거나 시뮬레이션에서 시각화한다.

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

#### 빌드 결과 확인과 디버깅

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

* 빌드 에러 로그:

  ```
  cat log/latest_build/my_example_pkg/build.txt
  ```
* **실행 로그**: 패키지 실행 중 에러가 발생하면 `ros2 run` 명령어의 콘솔 출력 또는 별도의 로그 파일을 확인한다.

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

#### 더 복잡한 빌드 흐름

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

{% @mermaid/diagram content="flowchart TB
A\[시작] --> B\["src 디렉터리 내 패키지 탐색"]
B --> C\["의존 관계 계산(rosdep)"]
C --> D\[패키지 빌드]
D --> E\["테스트 수행(colcon test)"]
E --> F\[Doxygen 등 문서화]
F --> G\[결과물 설치]
G --> H\[환경 변수 source로 적용]" %}

#### 교차 컴파일(Cross-Compiling)

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

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

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

   ```
   toolchain-arm.cmake
   ```

   을 만든다. 예시 구조:

   ```
   set(CMAKE_SYSTEM_NAME Linux)
   set(CMAKE_SYSTEM_PROCESSOR arm)
   set(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
   set(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
   ...
   ```
3. colcon 빌드 시 툴체인 적용:

   ```
   colcon build \
     --cmake-force-configure \
     --cmake-args \
       -DCMAKE_TOOLCHAIN_FILE=./toolchain-arm.cmake \
       -DCMAKE_BUILD_TYPE=Release
   ```
4. **설치된 결과물 전송**: 빌드가 끝난 후 `install/` 디렉터리 내 바이너리나 라이브러리를 타겟 장치로 복사하여 실행한다.

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

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

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

* default.yaml (예시)

  ```yaml
  build:
    merge-install: true
    cmake-args:
      - -DCMAKE_BUILD_TYPE=Release
    packages-up-to: [my_example_pkg, another_pkg]
  ```

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

```
colcon build --defaults default.yaml
```

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

#### 병렬 빌드, 우선순위 빌드

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

* \--packages-up-to

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

  ```
  colcon build --packages-up-to my_example_pkg
  ```
* \--packages-skip

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

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

#### Multi-Directory Workspace

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

```
my_ros2_ws/
 ├── src/
 │   ├── core_packages/
 │   ├── sensor_packages/
 │   └── navigation_packages/
 ├── build/
 ├── install/
 └── log/
```

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

#### 확장된 수학적 예시

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

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

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

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

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

#### 테스팅(Testing) 및 연동

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

```sh
colcon test
colcon test-result
```

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

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

#### Docker를 활용한 빌드 환경

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

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

   ```dockerfile
   FROM ubuntu:22.04

   # 필수 도구 및 ROS2 키 설치
   RUN apt-get update && apt-get install -y curl gnupg lsb-release
   RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
       | apt-key add -
   RUN sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" \
       > /etc/apt/sources.list.d/ros2-latest.list'

   # ROS2 Humble 설치
   RUN apt-get update && apt-get install -y ros-humble-desktop

   # colcon, 빌드 종속성 설치
   RUN apt-get install -y python3-colcon-common-extensions python3-rosdep

   # Locale 설정
   RUN apt-get install -y locales
   RUN locale-gen en_US en_US.UTF-8
   ENV LANG=en_US.UTF-8
   ENV LANGUAGE=en_US:en
   ENV LC_ALL=en_US.UTF-8

   # rosdep 초기화
   RUN rosdep init || true
   RUN rosdep update

   # 기본 ros2 환경변수 설정
   SHELL ["/bin/bash", "-c"]
   RUN echo "source /opt/ros/humble/setup.bash" >> /root/.bashrc
   ```

   이 Dockerfile을 빌드하면, ROS2 Humble 및 colcon 도구를 포함한 우분투 환경을 갖춘 Docker 이미지가 만들어진다.
2. **소스 코드 복사와 빌드** 위 예시 Dockerfile에 이어서, 컨테이너 내부에서 ROS2 패키지를 빌드하려면 추가로 아래와 같은 단계를 수행한다.

   ```dockerfile
   # 프로젝트 소스 복사 (예: /my_ros2_ws/src)
   COPY . /my_ros2_ws/

   WORKDIR /my_ros2_ws

   # 의존성 설치
   RUN rosdep install --from-paths src --ignore-src -y

   # 빌드
   RUN colcon build
   ```

   이렇게 구성하면 컨테이너 이미지를 빌드하는 시점에 ROS2 패키지가 자동으로 빌드되며, 컨테이너 실행 시 별도의 빌드 단계 없이 바로 ROS2 실행 파일을 사용할 수 있다.
3. **Multi-stage Build 활용** Docker 이미지 크기를 줄이기 위해, **multi-stage build** 기법을 사용한다. 빌드 전용 이미지를 먼저 구성한 뒤, 빌드 결과물만 최종 실행 이미지에 담는 방식이다. 예시는 다음과 같다.

   ```dockerfile
   # Stage 1: 빌드 전용 이미지
   FROM ubuntu:22.04 AS builder

   RUN apt-get update && apt-get install -y \
       curl gnupg lsb-release \
       python3-colcon-common-extensions python3-rosdep

   # ROS2 저장소 등록 및 설치 (간략화)
   RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
       | apt-key add -
   RUN sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" \
       > /etc/apt/sources.list.d/ros2-latest.list'
   RUN apt-get update && apt-get install -y ros-humble-ros-base

   SHELL ["/bin/bash", "-c"]
   RUN echo "source /opt/ros/humble/setup.bash" >> /root/.bashrc

   # 소스 복사
   COPY . /my_ros2_ws/
   WORKDIR /my_ros2_ws

   # 의존성 설치
   RUN rosdep init || true
   RUN rosdep update
   RUN rosdep install --from-paths src --ignore-src -y

   # 빌드
   RUN colcon build

   # Stage 2: 런타임 이미지
   FROM ubuntu:22.04

   RUN apt-get update && apt-get install -y \
       curl gnupg lsb-release

   RUN curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key \
       | apt-key add -
   RUN sh -c 'echo "deb http://packages.ros.org/ros2/ubuntu $(lsb_release -cs) main" \
       > /etc/apt/sources.list.d/ros2-latest.list'
   RUN apt-get update && apt-get install -y ros-humble-ros-base

   SHELL ["/bin/bash", "-c"]
   RUN echo "source /opt/ros/humble/setup.bash" >> /root/.bashrc

   # builder 스테이지에서 빌드된 결과물 복사
   COPY --from=builder /my_ros2_ws/install /my_ros2_ws/install

   WORKDIR /my_ros2_ws
   ```

   이 구성에서는 빌드 관련 툴체인을 포함한 거대한 **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 환경이라면 다음과 같은 명령어로 설치한다.

   ```
   sudo apt-get install -y lcov
   ```
2. CMake 설정

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

   ```
   colcon build --cmake-args -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="--coverage"
   ```
3. 테스트 실행 후 커버리지 측정

   :

   ```
   colcon test
   lcov --directory . --capture --output-file coverage.info
   ```
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.txt`에 `find_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)를 사용하기도 한다.

$$
\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 등을 잘 활용해 빌드 시간을 줄인다.
* **테스트 분리**: 통합 테스트가 너무 커지면 빌드/테스트 시간을 관리하기 어렵다. 핵심 패키지부터 단계적으로 테스트를 나누어 수행한다.
* **오버레이**: 본 프로젝트와 별개로, 새로운 실험적 기능을 빠르게 시도하려면 오버레이 워크스페이스에만 패키지를 두고 빌드해 본다.
