패키지 배포와 관리
배포 전 테스트와 연속통합(간단 개념)
ROS2 패키지를 배포하기 전에는 안정성과 신뢰도를 높이기 위해 다양한 테스트 전략이 필요하다. 이는 간단히 말해 “소프트웨어를 릴리스하기 전에 오류를 최대한 사전에 잡기 위해 수행하는 단계”이며, 연속통합(Continuous Integration, CI)을 통해 이러한 테스트 과정을 자동화하여 효율성을 높일 수 있다.
테스트와 연속통합 과정은 보통 다음과 같은 흐름을 가진다.
코드 업데이트: 새 기능이나 버그 수정을 커밋(Pull Request 제출 포함)
빌드 테스트: 컴파일 및 패키지 종속성 확인
유닛 테스트: 개별 함수 혹은 클래스가 의도한 대로 동작하는지 확인
통합 테스트: 여러 노드나 패키지를 결합했을 때 정상 동작하는지 확인
시스템 테스트: 실제 로보틱스 환경(시뮬레이션 포함)에서 동작 테스트
결과 확인 및 피드백: 테스트가 통과하거나 실패하면 자동으로 리포트를 생성
빌드 테스트와 colcon
ROS2 Humble에서 표준 빌드 도구로는 colcon이 많이 사용된다. 패키지를 빌드하고 테스트하기 위해서는 다음과 같은 명령을 사용할 수 있다.
colcon build
colcon test
colcon test-result --verbosecolcon build: 현재 워크스페이스(workspace)에 있는 모든 패키지를 빌드한다.
colcon test: 등록된 모든 테스트(유닛 테스트, 통합 테스트 등)를 실행한다.
colcon test-result --verbose: 테스트 결과에 대한 세부 정보를 확인한다.
테스트 코드는 일반적으로 C++의 경우 GTest, Python의 경우 pytest 등을 사용한다. C++ 테스트 예시를 보면 다음과 같은 형태를 많이 사용한다.
통합 테스트와 launch 파일
ROS2에서는 여러 노드를 동시에 테스트하기 위해 launch 테스트를 적극적으로 활용한다. 예컨대 여러 노드를 띄우고 그 노드 간 메시지 통신이 정상적으로 이뤄지는지 자동으로 검증할 수 있다. 간단한 예로서, 두 개의 노드를 동시에 실행해 메시지를 주고받는 테스트를 구성할 수 있다.
이처럼 launch 테스트를 통해 실제 노드 실행 과정을 재현할 수 있고, 로컬에서만 아니라 CI 환경에서도 같은 테스트를 수행하도록 스크립트를 구성할 수 있다.
연속통합(CI) 구성
연속통합(Continuous Integration, CI)을 구성하면, 개발자가 코드를 push 하거나 Pull Request를 생성했을 때 자동으로 빌드와 테스트가 수행된다. 성공이나 실패 여부에 따라 알림을 받게 되므로, 팀원 모두가 코드 변경에 대한 영향을 신속하게 파악할 수 있다.
다양한 CI 도구 중에서 Github Actions, GitLab CI, Jenkins 등이 널리 사용되며, ROS2 패키지 빌드와 테스트 또한 이러한 환경에서 자동으로 수행할 수 있다. 예시로, GitHub Actions에 YAML 파일을 작성해 두면, 특정 이벤트(Push, Pull Request 등)가 발생할 때마다 워크플로가 실행된다.
아래 예시는 GitHub Actions에서 ROS2 Humble 환경을 Docker 컨테이너로 설정하고, 빌드와 테스트를 수행하는 워크플로의 스니펫이다.
위와 같이 구성하면 CI 환경에서 빌드와 테스트를 자동으로 수행하고, 결과 로그가 웹 인터페이스 상에서 바로 확인 가능하므로 개발 효율이 크게 향상된다.
코드 커버리지와 자동화된 품질 관리
소스 코드에 대한 테스트를 단순히 통과 여부만 확인하는 것에서 나아가, 얼마나 많은 부분을 실제로 테스트했는지 측정하는 “코드 커버리지(Code Coverage)” 기법도 자주 활용한다. 코드 커버리지 도구로는 Gcov, LCOV, Cobertura 등이 있으며, ROS2의 경우에도 다음과 같은 과정을 통해 코드 커버리지를 수집할 수 있다.
컴파일 옵션 설정: Gcov 등을 활용하려면 컴파일 시에
-fprofile-arcs -ftest-coverage와 같은 플래그를 적용해야 한다.테스트 실행: colcon 빌드 뒤에 테스트를 실행하면, 각 소스 파일마다
.gcno,.gcda등 커버리지 데이터 파일이 생성된다.결과 수집: lcov나 gcov 등으로 커버리지 데이터를 수집하고, HTML 리포트 같은 형태로 변환하여 확인한다.
아래는 C++ 기반 패키지에서 gcov, lcov를 활용한 예시다(간단 스니펫).
이처럼 CI 환경에서도 동일한 명령을 실행해두면 매 빌드마다 커버리지 리포트를 확인할 수 있어, 테스트 수준 향상과 코드 품질 개선에 도움이 된다.
코드 스타일 검사와 정적 분석
ROS2 프로젝트를 유지보수하려면 일관된 코드 스타일, 잠재적 오류 점검을 위한 정적 분석이 필수적이다. 대표적인 방식은 다음과 같다.
코드 스타일 검사: ament_lint, cpplint, clang-format 등을 이용해 코드 스타일 준수 여부를 자동으로 확인한다.
정적 분석: clang-tidy, cppcheck 등을 통해 런타임 이전에 발견 가능한 위험 요소(Null 포인터 참조, 메모리 누수 가능성 등)를 점검한다.
아래는 ament_lint를 활용해 간단히 C++ 코드를 검사하는 예시다.
ament_cmake 기반의 ROS2 패키지라면 CMakeLists.txt에 ament_lint_auto_find_test_dependencies()를 선언해두고, ament_add_*_test 계열 함수들을 적절히 작성해두면 스타일 검사와 유닛 테스트를 한 번에 진행할 수 있다.
확장된 테스트 범위: Hardware-in-the-Loop(HIL) 테스트
실제 로봇 하드웨어(센서, 모터, 제어기 등)가 동원되는 테스트를 “Hardware-in-the-Loop(HIL) 테스트”라고 한다. 시뮬레이션으로 대체하기 어려운 센서 반응이나 통신 지연 등을 실제 장비와 연동해 테스트할 수 있다. 예를 들어, 센서 데이터를 실제 장비에서 수집하고, 이를 ROS2 토픽으로 퍼블리시해서 알고리즘이 의도대로 동작하는지 확인할 수 있다.
일반적으로 HIL 테스트를 CI에 완전히 통합하기는 어려우므로, 다음과 같은 전략을 사용할 수 있다.
로컬(개발 PC) 및 테스트베드: 개발 중에는 시뮬레이션 테스트(소프트웨어만)와 실제 하드웨어 테스트를 병행.
CI 파이프라인 분리: 소프트웨어만으로 확인 가능한 부분(유닛/통합 테스트)은 일반 CI로 처리하되, 실제 하드웨어가 필요한 부분은 별도 환경에서 주기적으로 자동 실행.
이러한 접근 방식을 통해 기능 개발 단계부터 실제 하드웨어 구동을 염두에 둔 테스트 과정을 밟을 수 있다.
병렬화와 테스트 효율
CI 파이프라인이 복잡해지고 테스트가 방대해질수록, 빌드와 테스트 시간을 단축해야 하는 요구가 생긴다. 이를 위해 빌드를 병렬화하거나, 여러 테스트를 동시에 실행해 시간을 절약하는 방법을 쓴다.
병렬 빌드:
colcon build --parallel-workers <N>혹은-j <N>같은 옵션을 통해 CPU 코어를 최대한 활용한다.Test splitting: 테스트가 많을 경우, 여러 워커(Worker) 또는 여러 머신(Machine)에 테스트를 분산 실행하도록 스크립트를 구성한다.
ROS2 프로젝트가 대규모화되면, 테스트를 병렬화하지 않으면 시간이 매우 길어질 수 있으므로 CI 시스템에서 제공하는 캐시(예: ccache)나 병렬화 옵션을 적극적으로 사용한다.
메모리 및 자원 사용량 모니터링
일부 테스트는 단순히 “기능이 맞게 동작하는지”만 확인하는 것이 아니라, 메모리 사용량, CPU 로드, 대역폭 등을 모니터링하기도 한다. 로봇 시스템에서는 처리 지연과 자원 부족이 치명적일 수 있으므로, 테스트 단계에서 이를 계측하고 분석해야 한다. 대표적으로 valgrind나 clang AddressSanitizer 등을 통해 메모리 누수, 스택 오버플로 등 잠재적 문제를 조기에 발견할 수 있다. CI에 이 같은 체크를 포함해두면, 배포 전 소프트웨어 안정성을 한층 높일 수 있다.
성능(Performance) 테스트
ROS2 애플리케이션은 실시간성, 고속 데이터 처리, 네트워크 통신량 제어 등 다양한 요구사항에 직면하기 때문에 성능 테스트도 매우 중요하다. 주로 다음과 같은 요소를 점검한다.
지연 시간(Latency): 특정 노드에서 메시지를 발행한 후, 다른 노드가 이를 수신하기까지 걸리는 시간
처리량(Throughput): 초당 처리 가능한 메시지 수, 데이터 양
자원 사용량(Resource Usage): CPU, 메모리, 네트워크 대역폭 사용률 등
ROS2에는 rclcpp::Clock 등을 활용해 노드 간 통신 시간을 간단히 측정하거나, performance_test 라이브러리를 통해 대규모 토픽·서비스·액션 상호작용 성능을 자동으로 평가하는 방법이 있다.
예시로, eProsima에서 개발한 Performance Test 툴(ROS2 메시지 타입 사용 가능)을 통해 아래와 같이 성능 측정이 가능하다.
이처럼 성능 테스트 또한 CI 파이프라인에 부분적으로 통합할 수 있으며, 주로 야간 빌드나 주기적인 릴리스 테스트 과정에 포함시켜 성능의 변화 추이를 모니터링하는 전략을 사용하기도 한다.
배포 브랜치와 안정화 전략
실제 ROS2 패키지를 배포할 때는, 다음과 같은 브랜치 전략(Branch Strategy)으로 관리하는 경우가 많다.
메인(Main) 또는 develop 브랜치: 최신 기능이 반영되는 작업용 브랜치
릴리스(Release) 브랜치: 실제 배포할 버전을 관리하는 브랜치
핫픽스(Hotfix) 브랜치: 릴리스 후 발견된 버그를 빠르게 수정하는 별도 브랜치
CI가 잘 구성되어 있다면, PR(Pull Request) 혹은 MR(Merge Request)을 릴리스 브랜치로 병합하기 전에 자동으로 빌드·테스트 과정을 거쳐 품질이 확보된 상태로 버전을 태그(Tag)하고 배포하게 된다.
ROS2 생태계에서는 각 배포(갤럭시, 험블, 아이언 등)에 맞춰 패키지를 릴리스해야 하는 경우가 있으므로, 다중 브랜치를 운영하면서 빌드된 아티팩트를 각각 별도로 관리하기도 한다. 예컨대, GitHub Actions나 GitLab CI에서 “ROS_DISTRO” 변수를 바꾸어 가며 병렬로 빌드·테스트를 수행하는 식이다.
배포 전 사전 체크리스트
ROS2 패키지 배포 전에는 다음 항목들을 최종적으로 점검한다.
모든 테스트가 통과하는지
코드 스타일 및 정적 분석 결과에 문제는 없는지
필요한 ROS2 버전(의존성 버전)과 호환성 검증이 끝났는지
패키지 매니페스트(package.xml)에 누락된 의존성은 없는지
설치 절차와 README, 문서화가 충분한지
라이선스 표기 및 저작권 정보가 정확한지
이러한 체크리스트를 자동화하기 위해 ROS2 빌드 팜(ROS Build Farm)을 사용할 수도 있다. ROS Build Farm은 공개된 오픈소스 ROS 패키지를 자동으로 빌드·테스트하고, 성공 시 패키지를 빌드하여 저장소(ROS Index)에 업로드하는 역할을 한다.
지속적인 유지관리와 모범 사례
패키지를 배포한 후에도 지속적으로 테스트와 연속통합을 돌려가며 유지보수해야 한다. 특히 다음 모범 사례(Best Practices)를 참고할 수 있다.
Test-driven Development(TDD)를 적극 활용: 기능 개발 이전에 테스트를 작성해두면, 코드 변경 시 회귀(regression) 오류를 빠르게 잡을 수 있다.
테스트 자동화 수준을 지속 개선: 단순 유닛 테스트에서 통합 테스트, HIL 테스트까지 확장하고, 결과 리포트의 가시성을 높인다.
CI/CD 파이프라인에서 실패 시 즉각 알림: 테스트가 실패했을 때 개발자에게 빠르게 알림이 가도록 설정해, 빠른 문제 수정이 가능하도록 한다.
CI 서버 리소스 모니터링: 로보틱스 프로젝트는 빌드 시간이 길고, 의존성이 많을 수 있으므로, CI 서버 자원을 효율적으로 배분하거나 확장한다.
Last updated