SMACC2(State Machine Asynchronous C++ for ROS2)는 단순한 상태 머신 라이브러리를 넘어, 복잡한 로봇 시스템의 행동을 체계적으로 설계하고 제어하기 위한 명확한 철학을 담고 있는 프레임워크다. 그 핵심은 다수의 하드웨어 컴포넌트가 유기적으로 결합된 현대 로봇 시스템의 복잡성을 정면으로 다루는 데 있다.1 SMACC2의 개발자들은 라이브러리의 적용 대상을 명확히 정의하는데, 단순히 광원을 따라가는 소형 로봇과 같은 단일 목적의 시스템이 아니라, 모바일 베이스, 다관절 로봇 팔, 그리퍼, 그리고 다수의 라이다(LIDAR) 및 IMU 센서가 통합된 복잡한 로봇을 위한 것이라고 강조한다.1 이는 SMACC2가 제공하는 아키텍처, 예를 들어 직교(Orthogonals)와 같은 개념들이 내포하는 일정 수준의 복잡성과 오버헤드는 오직 다수의 하위 시스템을 동시에 조율하고 관리해야 하는 복잡한 문제 상황에서만 그 가치를 발휘한다는 것을 시사한다.
이러한 접근법은 복잡한 로봇 프로젝트에서 흔히 발생하는 비정형적이고 유지보수가 어려운 코드(ad-hoc code)의 난립을 방지하려는 의도에서 비롯된다. 즉, SMACC2는 단순히 기능을 구현하는 스크립팅 도구가 아니라, 로봇의 전체 행동을 구조적으로 설계하는 아키텍처 프레임워크로서의 역할을 지향한다. 따라서 SMACC2의 철학은 ‘단순한 작업의 자동화’를 넘어, 여러 하위 시스템의 상태와 행동을 동기화하고 조율하는 ‘복잡한 행동의 오케스트레이션(Orchestration)’을 목표로 한다고 볼 수 있다. 이는 개발자에게 높은 수준의 구조화된 설계를 요구하는 대신, 시스템의 예측 가능성과 안정성, 그리고 장기적인 유지보수성을 제공하려는 전략적 선택이다.
SMACC2는 ROS1 환경에서 검증된 SMACC 라이브러리의 직접적인 후속 버전으로, ROS2 생태계의 근본적인 변화에 발맞춰 진화한 결과물이다.3 SMACC의 핵심 철학인 Harel Statecharts 기반의 계층 구조, 직교성(Orthogonality), 그리고 C++를 통한 성능 확보는 그대로 계승되었다. 하지만 SMACC2는 단순히 ROS2 API에 맞춰 코드를 수정한 ‘포팅(porting)’ 수준을 넘어선다. 이는 ROS1에서 ROS2로의 전환이 단순한 API 변경이 아닌, 통신 미들웨어(DDS), 노드 실행 모델(Executors), 그리고 비동기 작업 처리(actionlib에서 rclcpp_action으로) 등 시스템의 근본적인 패러다임 변화를 수반하기 때문이다.1
SMACC1이 ROS1의 actionlib 인터페이스를 활용했다면 4, SMACC2는 ROS2의 rclcpp_action을 네이티브하게 지원하도록 재설계되었다. 이는 SMACC2 내부의 이벤트 처리 메커니즘과 클라이언트 구현이 ROS2의 비동기 콜백 기반 아키텍처와 QoS(Quality of Service) 정책을 적극적으로 활용하도록 재구성되었음을 의미한다. QoS 설정은 실시간성이 중요한 산업용 로봇 애플리케이션에서 데이터의 신뢰성과 전달 시간을 보장하는 핵심 기능이며, SMACC2가 이를 네이티브하게 지원한다는 것은 단순한 호환성 확보를 넘어 ROS2의 장점을 최대한 활용하려는 설계 의도를 보여준다. 따라서 SMACC2로의 진화는 ROS2라는 새로운 미들웨어 철학에 대한 깊은 이해를 바탕으로 한 ‘재설계(Re-architecture)’의 결과물로 평가하는 것이 타당하다.
SMACC2는 ROS2 Humble LTS(Long-Term Support) 버전을 공식적으로 지원하며, 공식 GitHub 저장소를 통해 명확한 설치 및 빌드 가이드라인을 제공한다.1 주목할 점은 apt를 통한 바이너리 패키지 설치 방식이 아닌, 소스 코드를 직접 내려받아 빌드하는 방식을 기본으로 안내한다는 점이다. 이는 SMACC2가 목표로 하는 사용자가 단순한 패키지 사용자를 넘어, 자신의 시스템에 맞게 라이브러리를 최적화하고 커스터마이징할 필요가 있는 전문 개발자임을 암시한다.
빌드 프로세스는 ROS2의 표준 도구 체인인 colcon과 vcstool을 철저히 따른다.1 특히 vcs import 명령어와 각 ROS 배포판에 특화된 .repos 파일(예: SMACC2.humble.repos)을 사용하여 의존성 패키지를 관리하는 방식은 주목할 만하다.1 이는 시스템에 설치된 표준 패키지 버전에 의존하지 않고, SMACC2가 테스트하고 호환성을 보장하는 특정 버전의 의존성 라이브러리들을 소스 코드 레벨에서 함께 빌드하도록 강제한다. 이러한 방식은 개발 환경의 일관성을 보장하고 예기치 않은 의존성 충돌을 방지하여 시스템의 안정성을 높이는 데 크게 기여한다. 이는 산업 현장이나 장기 연구 프로젝트에서 요구되는 높은 수준의 신뢰성과 재현성을 확보하기 위한 전문적인 소프트웨어 공학 접근법이다.
또한, SMACC2는 바이너리, 세미-바이너리, 소스 빌드의 세 가지 빌드 단계를 정의하여 CI(Continuous Integration)에서 현재 및 미래의 ROS 배포판과의 호환성을 지속적으로 검증하는 체계를 갖추고 있다.1 이는 라이브러리의 장기적인 안정성과 유지보수에 대한 개발팀의 강력한 의지를 보여주는 부분이다. 그러나 이러한 소스 기반의 빌드 및 의존성 관리 방식은 ROS2 초심자나 개발 환경 제어에 익숙하지 않은 사용자에게는 상당한 진입 장벽으로 작용할 수 있다. 워크스페이스 관리, colcon 빌드 옵션, vcs 사용법 등에 대한 사전 지식이 요구되기 때문이다. 결국, SMACC2의 빌드 시스템은 사용자에게 정교한 제어권을 부여하는 대신, 그에 상응하는 전문성을 요구하는 트레이드오프를 선택했다고 볼 수 있다.
SMACC2 아키텍처의 근간은 복잡한 로봇 행동을 체계적으로 분해하고 관리하기 위한 계층적 상태 머신(Hierarchical State Machine, HSM)이다.5 이 구조는 단일 계층의 평면적인 상태 머신(Flat State Machine)이 가질 수 있는 ‘상태 폭발(state explosion)’ 문제와 그로 인한 복잡성 증가를 해결하기 위해 설계되었다. SMACC2는 크게 세 가지 수준의 계층을 정의하여, 추상적인 미션 레벨부터 구체적인 하드웨어 제어 레벨까지 로봇의 행동을 구조화한다.3
슈퍼상태(Super States)는 계층 구조의 최상위에 위치하며, 로봇의 전체 미션이나 반복적인 주요 작업을 포괄하는 가장 큰 단위의 상태를 정의한다. 예를 들어, sm_dance_bot 예제에서 로봇이 지정된 웨이포인트들을 순차적으로 방문하고 각 지점에서 특정 패턴의 춤을 추는 전체 시퀀스는 하나의 슈퍼상태로 구현될 수 있다.3 이는 미션의 시작, 진행, 종료와 같은 거시적인 흐름을 관리하는 역할을 한다.
모드상태(Mode States)는 슈퍼상태 내부에 정의되는 중간 계층으로, 미션 수행 중 뚜렷하게 구분되는 작동 모드(operational mode)를 나타낸다. 예를 들어, 자율 비행 드론의 미션을 슈퍼상태로 정의했다면, 그 내부에는 ‘이륙 준비’, ‘이륙’, ‘경로 비행’, ‘임무 수행’, ‘귀환’, ‘착륙’과 같은 명확한 모드상태들이 순차적으로 또는 조건에 따라 존재할 수 있다.3 이 계층은 복잡한 미션을 논리적인 하위 단계들로 분할하여 관리할 수 있게 해준다.
리프상태(Leaf States)는 계층 구조의 가장 말단에 위치하며, 실제 로봇의 구체적인 행동이 구현되는 곳이다.3 예를 들어, ‘경로 비행’ 모드상태 내부에는 ‘다음 웨이포인트 설정’, ‘경로 계획 요청’, ‘경로 추종’과 같은 여러 리프상태가 존재할 수 있다. 바로 이 리프상태 수준에서 SMACC2의 또 다른 핵심 아키텍처인 서브상태 아키텍처(Substate Architecture), 즉 직교(Orthogonals), 클라이언트(Clients), 클라이언트 행동(Client Behaviors) 등이 정의되고 동작한다.6
이러한 HSM 구조는 ‘하향식(Top-Down)’ 방식의 로봇 행동 설계를 자연스럽게 유도한다. 개발자는 먼저 “창고를 순찰하라”와 같은 추상적인 미션 목표를 슈퍼상태로 정의하고, 이를 “다음 지점으로 이동”, “구역 스캔”, “상태 보고”와 같은 모드상태로 구체화한 뒤, 마지막으로 “Nav2에 목표 전송”과 같은 구체적인 액션을 리프상태에서 구현하게 된다. 이처럼 인간이 복잡한 과업을 사고하는 방식과 유사하게 소프트웨어 아키텍처를 구성할 수 있다는 점은, 결과적으로 코드의 가독성, 유지보수성, 그리고 디버깅 용이성을 크게 향상시키는 핵심적인 장점이다.
SMACC2 아키텍처를 다른 상태 머신 패러다임과 구별 짓는 가장 독창적이고 강력한 개념은 바로 ‘직교(Orthogonals)’다. 1987년 David Harel의 Statecharts 이론에서 유래한 이 개념은 복잡한 로봇 시스템을 구성하는 다수의 물리적 하위 시스템을 소프트웨어적으로 모델링하고, 이들을 동시에, 그리고 독립적으로 제어하기 위한 핵심 메커니즘이다.2 로봇은 단일 개체가 아니라 모바일 베이스, 로봇 팔, 그리퍼, 카메라, 라이다 등 다양한 컴포넌트의 집합체라는 공학적 현실을 소프트웨어 아키텍처에 직접적으로 반영한 것이다.1
각 직교는 상태 머신의 전체 생명주기 동안 유지되는 논리적인 ‘슬롯’ 또는 ‘컨테이너’로 생각할 수 있으며, 특정 하드웨어 컴포넌트나 기능적 서브시스템에 대한 모든 인터페이스(ROS 통신, 상태 관리, 초기화/종료 로직 등)를 캡슐화한다.3 예를 들어, 이동 로봇 팔(Mobile Manipulator)을 제어하는 상태 머신은 OrBase (모바일 베이스 제어), OrArm (로봇 팔 제어), OrGripper (그리퍼 제어), OrPerception (센서 데이터 처리)과 같은 여러 직교를 가질 수 있다.
직교의 가장 큰 가치는 동시성(Concurrency)을 다루는 방식에 있다. 일반적인 로봇 프로그래밍에서 여러 하드웨어를 동시에 구동시키기 위해 멀티스레딩이나 다중 프로세스(ROS 노드) 방식을 사용하는 것은 흔하다. 하지만 이는 스레드 간의 동기화, 데이터 경쟁(race condition), 교착 상태(deadlock) 등 복잡하고 디버깅하기 어려운 문제를 야기할 수 있다.7 SMACC2의 직교는 이러한 문제에 대한 우아한 대안을 제시한다. 모든 직교는 단일 상태 머신 프로세스 내에서 실행되지만, 각 직교는 독립적인 상태와 로직을 가지고 병렬적으로 작동하는 것처럼 동작한다. 상태 머신의 주된 흐름에서 하나의 상태 전이(transition)가 발생하면, 이와 관련된 여러 직교 내의 행동들이 동시에 트리거될 수 있다. 개발자는 복잡한 스레드 동기화 코드를 작성할 필요 없이, 상태 머신의 구조적 설계를 통해 다중 컴포넌트의 동시 동작을 결정론적이고 안전하게 구현할 수 있다.
결론적으로, 직교는 단순한 동시 실행 기능을 넘어, 로봇의 물리적 구성을 소프트웨어 아키텍처에 1:1로 투영하는 강력한 설계 패턴이다. 이는 로봇의 실제 구조와 소프트웨어의 구조 사이의 간극을 줄여 시스템에 대한 개발자의 직관적인 이해를 돕고, 각 하드웨어 서브시스템의 로직을 독립적으로 개발하고 테스트할 수 있게 하여 코드의 모듈성과 재사용성을 극대화한다.
SMACC2의 리프상태 내부, 즉 직교(Orthogonals) 안에서는 로봇의 실제 행동을 구성하는 여러 핵심 컴포넌트들이 상호작용한다. 이 컴포넌트들은 각기 다른 생명주기(lifecycle)와 역할을 가지며, 이들의 정교한 분리는 SMACC2 아키텍처의 효율성과 유연성을 보장하는 핵심 요소다.
클라이언트(Clients)는 직교 내부에 위치하며, 상태 머신 전체의 생명주기와 동일한 가장 긴 생명주기를 가진다.3 클라이언트의 주된 역할은 외부 ROS 노드와의 통신 채널을 설정하고 유지하거나, 하드웨어 드라이버를 초기화하는 등, 상태 머신이 실행되는 동안 영속적으로 유지되어야 하는 리소스와 상태를 관리하는 것이다.3 예를 들어, Nav2와 통신하기 위한 nav2z_client의 경우, Nav2 액션 서버와의 연결 설정 및 유지는 상태가 바뀔 때마다 반복해서는 안 되는 작업이다. 이러한 로직은 클라이언트에 구현되어 한 번 초기화된 후 계속 유지된다. 또한, 배터리 잔량 모니터링이나 비상 정지 신호 감지와 같이 모든 상태에서 공통적으로 감시해야 하는 전역적인 로직을 처리하기에도 적합하다. 클라이언트는 ROS 메시지 수신 등을 통해 상태 머신에 이벤트를 발생시키는 주요 원천이 된다.
클라이언트 행동(Client Behaviors, CBs)은 클라이언트와 달리 특정 리프상태의 생명주기에만 종속되는 일시적인 객체다.6 즉, 상태 머신이 특정 상태에 진입할 때 생성(instantiated)되고, 해당 상태를 벗어날 때 소멸(destroyed)된다. CB는 ‘목표 지점으로 이동 명령 전송’, ‘로봇 팔을 특정 자세로 움직이기’, ‘그리퍼로 물체 잡기’와 같이 해당 상태에서만 수행되는 구체적이고 일회성인 행동을 구현하는 데 사용된다.3 이 개념은 Unity와 같은 게임 엔진에서 사용되는 컴포넌트 기반 아키텍처에서 영감을 받았으며 9, 행동 로직을 재사용 가능한 작은 단위로 캡슐화하여 코드의 모듈성을 극대화한다. 예를 들어, ‘물체 집기’라는 CB는 StApproachObject, StGraspObject 등 여러 상태에서 재사용될 수 있다.
이처럼 클라이언트와 클라이언트 행동을 분리하는 설계는 ‘영속적인 상태(Stateful) 관리’와 ‘일시적인 행동(Task-specific) 실행’을 명확하게 구분하는 매우 정교한 접근법이다. 리소스(예: ROS 통신 연결)의 생성 및 소멸은 클라이언트에서 최소한으로 이루어지게 하고, 실제 작업 로직은 필요한 상태에서만 CB를 통해 동적으로 생성하여 실행함으로써 시스템의 효율성과 안정성을 동시에 확보한다.
상태 리액터(State Reactors, SRs)는 이벤트 처리 로직을 더욱 정교하게 만들기 위한 특수한 컴포넌트다. SR은 하나 이상의 이벤트를 입력으로 받아, 내부 로직에 따라 새로운 이벤트를 출력하는 역할을 한다.3 이는 단순한 ‘A 이벤트 발생 시 B 상태로 전이’를 넘어, ‘A 이벤트와 B 이벤트가 모두 발생했을 때 C 이벤트를 발생시켜 D 상태로 전이’와 같은 복합적인 조건을 처리할 수 있게 해준다. 공식 예제인 SrAllEventsGo는 여러 센서로부터 ‘준비 완료’ 이벤트가 모두 수신되어야만 비로소 EvAllGo라는 통합 이벤트를 발생시켜 다음 단계로 진행시키는 역할을 한다.6 이를 통해 복잡한 동기화나 조건부 로직을 상태 전이 테이블에서 분리하여 독립적인 컴포넌트로 관리할 수 있다.
이벤트(Events)는 이 모든 컴포넌트를 구동하는 혈액과 같다. SMACC2는 이벤트 주도(event-driven) 아키텍처를 채택하고 있으며, 모든 상태 전이는 이벤트에 의해 촉발된다.1 ROS 토픽 메시지 수신, 서비스 응답, 액션 서버의 결과 피드백 등 로봇 외부 또는 내부의 모든 유의미한 변화는 클라이언트나 CB에 의해 이벤트 객체로 변환되어 상태 머신에 전달된다.10 상태(State)는 이벤트를 소비하여 상태 전이(Transition)를 출력하고, 상태 리액터는 이벤트를 소비하여 또 다른 이벤트를 출력하는 구조를 통해 전체 시스템이 비동기적으로 반응하며 동작하게 된다.6
SMACC2 아키텍처의 기술적 근간을 이루는 것은 Boost 라이브러리 중 하나인 Boost.Statechart이다.4 이는 C++의 템플릿 메타프로그래밍(Template Metaprogramming, TMP) 기법을 적극적으로 활용하여 상태 머신을 구현하는 라이브러리로, SMACC2에 매우 중요한 특성을 부여한다.
가장 핵심적인 장점은 상태 머신의 구조적 유효성을 런타임이 아닌 컴파일 타임에 검증한다는 것이다.1 일반적인 상태 머신 구현에서는 존재하지 않는 상태로의 전이를 시도하거나, 특정 상태가 처리할 수 없는 이벤트를 보내는 등의 논리적 오류가 런타임에 발생하여 디버깅을 어렵게 만들고, 심지어 실제 로봇의 오작동을 유발할 수 있다. 하지만 SMACC2는 Boost.Statechart를 통해 상태 머신의 모든 상태, 이벤트, 전이 관계를 C++ 타입 시스템(type system) 내에서 정의한다. 이로 인해 C++ 컴파일러는 컴파일 과정에서 마치 상태 머신을 시뮬레이션하듯 모든 가능한 전이 경로의 유효성을 검사할 수 있다. 만약 코드에 정의되지 않은 상태로의 전이나 잘못된 이벤트 사용이 있다면, 이는 런타임 에러가 아닌 컴파일 에러로 즉시 드러난다.
이러한 컴파일 타임 검증은 특히 안전이 중요한(safety-critical) 산업용 로봇이나 자율주행차와 같은 분야에서 소프트웨어의 신뢰성과 안정성을 극적으로 향상시키는 강력한 무기가 된다.1 개발자는 잠재적인 구조적 결함을 개발 초기 단계에서 발견하고 수정할 수 있어, 값비싼 런타임 테스트와 디버깅에 소요되는 시간과 비용을 크게 줄일 수 있다. “가능한 한 컴파일러가 일하게 하라(Wherever possible, let the compiler do it)”는 SMACC2의 철학은 바로 이 Boost.Statechart의 특성에서 비롯된 것이다.1
또한, Boost.Statechart는 비동기 상태 머신, 상태의 계층적 구성, 그리고 각 상태가 자신만의 멤버 변수와 함수를 가질 수 있는 ‘상태 지역 저장소(State Local Storage)’ 기능을 네이티브하게 지원한다.10 이는 SMACC2가 복잡하고 상태 의존적인(stateful) 로봇 행동을 모델링하는 데 필요한 풍부한 표현력을 갖추게 하는 기반이 된다.
그러나 이러한 강력한 기능에는 트레이드오프가 따른다. 템플릿 메타프로그래밍에 기반한 코드는 일반적인 C++ 코드에 비해 가독성이 떨어질 수 있으며, 특히 컴파일 에러 메시지가 매우 길고 복잡하여 초심자가 원인을 파악하기 어려울 수 있다. 즉, 컴파일 타임 검증이라는 큰 안정성을 얻는 대가로, 개발자에게 더 높은 수준의 C++ 전문성을 요구하게 되는 것이다.
SMACC2의 핵심 아키텍처가 로봇 행동을 구조화하는 ‘뼈대’를 제공한다면, SMACC2 클라이언트 라이브러리는 그 뼈대에 살을 붙이고 ROS2 생태계라는 외부 세계와 연결하는 ‘신경망’과 같은 역할을 한다. 이 라이브러리는 SMACC2의 실용성을 극대화하는 핵심 요소로, 개발자가 ROS2의 주요 기능들을 상태 머신 내에서 손쉽게 사용할 수 있도록 추상화된 인터페이스를 제공한다.1
클라이언트 라이브러리의 가장 큰 가치는 ROS2의 핵심 패키지들, 특히 Nav2, MoveIt2, ros2_control 등과의 즉각적인 통합을 지원하는 사전 구현된 클라이언트들을 제공한다는 점이다.1 예를 들어, nav2z_client는 ROS2 Navigation Stack(Nav2)과의 복잡한 통신 로직을 완전히 캡슐화한다.11 개발자는 Nav2의 액션 서버(NavigateToPose)를 직접 다루고, 목표(goal)를 보내고, 피드백을 처리하고, 결과에 따라 콜백 함수를 작성하는 번거로운 과정 없이, 단순히 nav2z_client의 클라이언트 행동(CB)을 사용하여 “이 좌표로 이동하라”는 명령을 내리고, 그 결과를 ‘성공’, ‘실패’, ‘취소’와 같은 SMACC2 이벤트로 간편하게 수신할 수 있다.
이러한 클라이언트들은 단순히 편의성을 제공하는 것을 넘어, SMACC2의 아키텍처 철학에 맞춰 설계되었다. 클라이언트들은 컴포넌트 기반 아키텍처를 채택하여, 개발자가 기존 클라이언트를 상속받거나 조합하여 자신만의 커스텀 클라이언트를 쉽게 제작하고 확장할 수 있도록 지원한다.1 예를 들어, 특정 제조사의 커스텀 센서와 통신하는 클라이언트를 만들고 싶다면, multirole_sensor_client와 같은 기존 클라이언트의 구조를 참조하여 새로운 클라이언트를 효율적으로 개발할 수 있다.
이처럼 SMACC2 클라이언트 라이브러리는 반복적인 보일러플레이트 코드 작성을 줄여 개발 생산성을 극적으로 향상시키고, 복잡한 ROS2 통신 메커니즘에 대한 깊은 이해 없이도 상위 레벨의 로봇 행동을 설계하는 데 집중할 수 있게 해준다. 이는 SMACC2를 범용 C++ 상태 머신 라이브러리가 아닌, 로보틱스 도메인에 특화된 강력한 ‘프레임워크’로 만드는 핵심적인 차별점이다. 따라서 SMACC2의 전체적인 유용성은 이 클라이언트 라이브러리의 완성도와 지원 범위에 크게 좌우된다고 할 수 있다.
복잡한 계층적 상태 머신(HSM)을 텍스트 기반의 코드로만 이해하고 디버깅하는 것은 매우 어려운 일이다. SMACC2는 이러한 문제를 해결하기 위해 SMACC2 런타임 분석기(Runtime Analyzer, RTA)라는 강력한 그래픽 사용자 인터페이스(GUI) 도구를 제공한다.1 RTA는 개발자가 설계한 상태 머신의 전체 구조, 즉 슈퍼상태, 리프상태, 직교, 그리고 상태 간의 전이 관계를 다이어그램 형태로 시각화해준다.
RTA의 가장 중요한 기능은 런타임 디버깅이다. 상태 머신이 실제로 로봇 위에서 실행될 때, RTA는 현재 활성화된 상태를 실시간으로 하이라이트하고, 이벤트 발생에 따른 상태 전이 과정을 시각적으로 보여준다. 이를 통해 개발자는 로봇이 왜 예상치 못한 행동을 하는지, 어떤 이벤트가 누락되었는지, 또는 어떤 상태에서 머물러 있는지(stuck) 등을 직관적으로 파악할 수 있다. 복잡한 동시성 로직을 포함하는 직교들의 현재 상태를 한눈에 모니터링할 수 있다는 점 또한 RTA의 강력한 장점이다.
하지만 이 필수적인 도구에는 명확한 한계점이 존재한다. 바로 RTA가 오픈 소스가 아닌 폐쇄 소스(closed source) 소프트웨어라는 점이다.1 SMACC2 라이브러리 자체는 Apache 2.0 라이선스로 공개되어 있지만, 실질적인 개발과 디버깅에 필수적인 RTA는 개발사인 Robosoft AI에 의해 통제된다.14 개인 개발자나 학술적 용도로는 무료로 제공되지만, 상업적 활용 시 라이선스 정책이 어떻게 적용될지 불분명하며, 커뮤니티가 버그를 수정하거나 새로운 기능을 추가하는 등의 기여가 원천적으로 불가능하다.13
이러한 정책은 ROS 생태계의 근간을 이루는 완전한 개방성 원칙과는 다소 거리가 있다. 이는 Robosoft AI가 SMACC2를 통해 추구하는 비즈니스 모델을 엿볼 수 있는 부분이기도 하다. 즉, 핵심 라이브러리는 무료로 제공하여 사용자 기반을 넓히고 생태계를 구축하되, 생산성 향상에 직결되는 부가적인 도구(RTA)를 통해 수익을 창출하는 ‘오픈 코어(open core)’ 또는 ‘프리미엄(freemium)’ 모델을 지향하는 것으로 보인다. 따라서 SMACC2 도입을 고려하는 기업 입장에서는 이 RTA에 대한 의존성과 라이선스 정책이 장기적인 개발 워크플로우와 비용에 미칠 영향을 신중하게 검토해야 할 필요가 있다. 이는 잠재적인 벤더 종속(vendor lock-in)의 위험을 내포하기 때문이다.
현대 로보틱스에서 복잡한 행동을 설계하는 두 가지 주요 패러다임은 상태 머신(State Machines)과 행동 트리(Behavior Trees, BTs)다. SMACC2는 전자를 대표하는 정교한 구현체이며, Nav2와 같은 주요 ROS2 프로젝트는 후자를 채택하고 있다. 따라서 SMACC2의 기술적 가치를 제대로 평가하기 위해서는 행동 트리와의 심층적인 비교 분석이 필수적이다.
동시성 관리는 다중 컴포넌트 로봇을 제어할 때 가장 중요한 문제 중 하나이며, 이 지점에서 두 패러다임은 근본적인 철학의 차이를 보인다.
SMACC2는 앞서 설명한 ‘직교(Orthogonals)’ 개념을 통해 동시성을 구조적으로 해결한다.1 여러 하드웨어 서브시스템에 해당하는 직교들이 단일 프로세스 내에서 논리적으로 분리되어 병렬 실행되는 모델을 제공한다. 이는 개발자가 스레드 동기화나 프로세스 간 통신(IPC)의 복잡성을 직접 다루지 않으면서도, 결정론적이고 예측 가능한 동시 동작을 설계할 수 있게 해준다. SMACC2의 지지자들은 이 방식이 특히 다수의 하드웨어(예: 군용 UAV의 26개 서브시스템)를 동시에 제어해야 하는 극도로 복잡한 시스템에서 BTs의 접근법보다 훨씬 우수하고 확장성이 높다고 주장한다.8
반면 행동 트리(BTs)는 Parallel 노드를 통해 여러 행동을 동시에 실행할 수 있는 기능을 제공한다. 하지만 SMACC2 측에서는 이 Parallel 노드가 근본적인 동시성 문제를 해결하지 못하며, 실제로는 충돌을 피하기 위해 단순한 행동의 조합에만 제한적으로 사용된다고 비판한다.7 이들의 주장에 따르면, BTs에서 진정한 의미의 독립적인 서브시스템 제어는 각 서브시스템을 별도의 스레드나 ROS 노드로 분리하여 실행하는 방식으로 구현되는 경우가 많다. 이 경우, 시스템의 복잡도가 증가함에 따라 수많은 프로세스와 그 사이의 통신을 관리해야 하는 부담이 기하급수적으로 커지며, 디버깅이 거의 불가능한 수준에 이를 수 있다는 것이다.8
물론 BTs 커뮤니티의 반론도 존재한다. BehaviorTree.CPP와 같은 현대적인 BT 라이브러리들은 ReactiveSequence, ParallelNode 등의 정교한 제어 흐름 노드를 제공하며, 이를 통해 스레드를 남용하지 않고도 반응성이 뛰어난 병렬 동작을 구현할 수 있다고 주장한다.7 결국 사용자가 어떤 접근법이 더 직관적이고 효과적인지 판단해야 한다는 것이다.
소프트웨어 아키텍처의 장기적인 가치는 모듈성, 재사용성, 확장성에 의해 결정된다. 이 측면에서 BTs는 일반적으로 높은 평가를 받는다.
행동 트리(BTs)는 본질적으로 모듈식이다. 트리의 모든 노드(와 그 하위 서브트리)는 독립적인 빌딩 블록으로 간주될 수 있다.15 “물체를 향해 이동”이라는 서브트리는 다른 어떤 트리에든 쉽게 가져다 붙여 재사용할 수 있다. 새로운 행동을 추가하거나 기존 행동을 제거하는 작업은 단순히 트리에서 해당 노드를 추가하거나 제거하는 것으로 완료될 수 있어, 시스템의 확장성이 매우 뛰어나다.15
반면 상태 머신(SMACC2)은 ‘상태 전이의 복잡성’이라는 고질적인 비판에 직면한다. 시스템에 상태의 수가 증가할수록, 각 상태를 연결하는 전이의 수가 기하급수적으로 늘어나 전체 구조가 복잡하게 얽히는 이른바 ‘스파게티 다이어그램’이 될 수 있다.16 새로운 상태를 하나 추가하기 위해, 그 상태와 연결될 가능성이 있는 모든 기존 상태들의 전이 로직을 일일이 수정해야 할 수도 있다.16 이는 모듈성을 저해하고 확장성을 떨어뜨리는 요인으로 작용한다.
이에 대해 SMACC2는 두 가지 해결책을 제시한다. 첫째, 계층적 상태 머신(HSM) 구조를 통해 관련 상태들을 그룹화하여 복잡도를 관리한다. 둘째, ‘클라이언트 행동(Client Behaviors)’이라는 컴포넌트 기반 접근법을 도입하여, 특정 행동 로직을 상태로부터 분리된 재사용 가능한 모듈로 만들었다.9 이를 통해 상태 자체는 단순한 껍데기(shell)로 남기고, 실제 행동은 재사용 가능한 CB 컴포넌트들이 담당하게 함으로써 모듈성을 높이려 시도한다.
로봇은 예측 불가능한 동적 환경에서 작동하므로, 외부 자극에 신속하게 반응하는 능력(Reactivity)과 실패 상황에서 복구하는 능력은 매우 중요하다.
행동 트리(BTs)는 ‘틱(tick)’이라는 주기적인 실행 모델을 기반으로 한다. 매 틱마다 트리는 루트부터 다시 평가되며, 항상 우선순위가 높은 행동부터 실행할 기회를 가진다. 이 덕분에 반응성이 매우 뛰어나다. 예를 들어, 비상 정지(e-stop) 조건을 트리의 가장 높은 우선순위에 배치하면, 로봇이 어떤 다른 행동을 수행하고 있더라도 즉시 모든 것을 중단하고 정지 행동을 수행하게 만들 수 있다.15
SMACC2는 이벤트 기반(event-driven) 모델을 사용한다. 이는 외부의 유의미한 변화(이벤트)가 발생했을 때만 상태 전이가 일어난다는 것을 의미한다.6 아무런 이벤트가 없다면 시스템은 현재 상태를 안정적으로 유지한다. 이는 지속적으로 전체 트리를 평가하는 BTs의 폴링(polling) 방식에 비해 계산적으로 더 효율적일 수 있다는 장점을 가진다. SMACC2에서는 복구 시퀀스를 ‘복구 상태(Recovery States)’라는 명시적인 상태로 설계하여 예외 상황을 체계적으로 다룰 수 있다.3 예를 들어, ‘경로 계획 실패’ 이벤트가 발생하면, ‘장애물 회피 기동’이라는 복구 상태로 명시적으로 전이하여 문제를 해결한 뒤 이전 작업으로 복귀하는 흐름을 구조적으로 설계할 수 있다.
두 패러다임의 기술적 특성을 종합해 볼 때, 각각이 더 유리한 애플리케이션 시나리오를 다음과 같이 정리할 수 있다.
SMACC2(상태 머신)가 유리한 경우:
행동 트리(BTs)가 유리한 경우:
아래 표는 두 패러다임의 주요 특징을 요약하여 비교한 것이다.
| 항목 (Criteria) | SMACC2 (State Machine) | 행동 트리 (Behavior Tree) | 주요 근거 (Supporting Snippets) |
|---|---|---|---|
| 동시성 모델 (Concurrency Model) | 직교(Orthogonals)를 통한 구조적 병렬 처리 (단일 프로세스) | Parallel 노드 및 스레드/프로세스 생성 | 7 |
| 모듈성/확장성 (Modularity/Scalability) | 상태 증가 시 전이 복잡도 증가 가능성. CB로 모듈성 확보. | 서브트리 단위의 높은 모듈성, 노드 추가/제거 용이. | 15 |
| 반응성 (Reactivity) | 이벤트 기반. 특정 이벤트에 반응. | Tick 기반. 지속적인 조건 재평가로 높은 반응성. | 6 |
| 상태 관리 (State Management) | ‘상태’가 명시적이고 핵심적인 개념. | ‘상태’ 개념이 암시적이며, 블랙보드를 통해 데이터 공유. | 8 |
| 가독성 (Readability) | 순차적이고 명확한 작업 흐름에 강점. | 조건 기반의 복잡한 로직 표현에 강점. (주관적) | 7 |
| 주요 적용 분야 (Primary Use Case) | 다중 하드웨어 동시 제어가 필요한 산업용/안전 중시 시스템 | 유연하고 동적인 행동 전환이 필요한 서비스/게임 AI | 1 |
SMACC2의 아키텍처와 기술적 특징을 이해하는 가장 좋은 방법은 실제 적용 사례를 분석하는 것이다. SMACC2 개발팀이 제공하는 참조 상태 머신과 커뮤니티에 공개된 데모들은 SMACC2가 ROS2의 핵심 기능들과 어떻게 통합되어 복잡한 로봇 행동을 구현하는지 구체적으로 보여준다.
sm_dance_bot과 그 확장 버전인 sm_dance_bot_strikes_back은 SMACC2의 공식 GitHub 저장소에 포함된 핵심 참조 상태 머신으로, ROS2의 표준 내비게이션 스택인 Nav2와의 통합을 보여주는 가장 중요한 예제다.1 이 예제들은 SMACC2의 문서가 부족하다는 비판에 대한 개발팀의 공식적인 답변과도 같다. 즉, “코드를 보고 배우라”는 것이다.
sm_dance_bot의 구조를 분석해 보면 SMACC2의 핵심 아키텍처 패턴을 학습할 수 있다.
OrNavigation과 같은 직교가 정의된다. 이 직교는 Nav2와의 모든 상호작용을 책임지는 독립적인 컴포넌트 역할을 한다.OrNavigation 내부에는 nav2z_client가 클라이언트로 존재한다. 이 클라이언트는 상태 머신이 시작될 때 Nav2의 NavigateToPose 액션 서버에 연결하고, 이 연결을 상태 머신이 종료될 때까지 유지한다.StNavigateToWaypoint1과 같은 리프상태로 진입한다. 이 상태에서는 CbNavigate와 같은 클라이언트 행동(CB)이 동적으로 생성된다. 이 CB는 nav2z_client를 통해 실제 목표 좌표를 Nav2에 전송하고, 액션 서버로부터 피드백을 기다리는 역할을 수행한다.nav2z_client는 smacc2::client_bases::SmaccActionClientBase로부터 상속받은 로직을 통해 EvActionSucceeded와 같은 이벤트를 발생시킨다. 상태 머신은 이 이벤트를 감지하고, StPerformDance와 같은 다음 상태로 전이한다. 만약 경로 계획에 실패하거나 이동 중 문제가 발생하면, EvActionAborted와 같은 다른 이벤트가 발생하여 에러 처리 상태로 전이될 수 있다.이처럼 sm_dance_bot은 단순한 데모 애플리케이션을 넘어, SMACC2의 아키텍처 철학이 실제 로봇 내비게이션 문제에 어떻게 적용되는지를 보여주는 ‘실행 가능한 교과서’ 역할을 한다. 문서가 부족한 현 상황에서, SMACC2를 도입하려는 개발자는 이 참조 코드를 분석하는 과정을 통해 프레임워크의 의도된 사용법과 설계 패턴을 역으로 학습해야만 한다.
SMACC2의 직교 개념이 가진 진정한 힘은 단일 로봇의 여러 컴포넌트를 제어하는 것을 넘어, 여러 로봇이나 여러 동일한 서브시스템을 동시에 조율해야 하는 복잡한 시나리오에서 드러난다. 이를 가장 잘 보여주는 사례가 바로 MoveIt2와 ros2_control을 사용하여 두 개의 6축 로봇 팔을 동시에, 그리고 협조적으로 제어하는 데모다.17
이 데모의 핵심적인 기술적 성과는 각 로봇 팔이 ROS2의 표준 방식에 따라 별도의 네임스페이스(arm1, arm2)에서 자신만의 move_group 노드와 ros2_control 컨트롤러 매니저를 가진다는 점이다.17 즉, 각 팔은 독립적으로 제어될 수 있는 완전한 개체다. SMACC2 상태 머신은 이 두 독립적인 시스템의 상위에서 이들을 동시에 조율하는 ‘지휘자’ 역할을 수행한다.
이러한 아키텍처는 SMACC2의 직교를 통해 매우 명료하게 구현될 수 있다.
OrArm1과 OrArm2라는 두 개의 직교를 정의한다.OrArm1의 클라이언트는 arm1 네임스페이스의 MoveIt2 액션 서버와 통신하고, OrArm2의 클라이언트는 arm2 네임스페이스의 서버와 통신한다.StDualArmPickAndPlace와 같은 상태에 진입하면, 이 상태는 OrArm1에는 “A 지점으로 이동”이라는 클라이언트 행동을, OrArm2에는 “B 지점으로 이동”이라는 클라이언트 행동을 동시에 실행시키도록 명령할 수 있다.State Reactor)를 사용하면 “두 팔이 모두 이동을 성공적으로 마쳤을 때” 다음 상태로 전이하는 것과 같은 복합적인 동기화 로직을 쉽게 구현할 수 있다.이 사례는 SMACC2의 직교성이 단순한 이론적 개념에 그치지 않고, 다중 로봇 협조 작업과 같은 고도로 복잡한 동시 조작(concurrent manipulation) 문제를 해결하는 데 매우 실용적이고 강력한 솔루션임을 명확하게 입증한다. 다른 패러다임으로는 구현하기 매우 까다로운 수준의 동시성 제어를 구조적으로 명확하게 풀어낼 수 있다는 점에서 SMACC2의 핵심적인 경쟁력을 보여주는 사례라 할 수 있다.
SMACC2 프레임워크의 견고성과 신뢰성은 산업계뿐만 아니라 학술 연구 커뮤니티에서도 그 가치를 인정받고 있다. SMACC2 공식 문서의 인용(Citations) 섹션에는 SMACC(SMACC2의 전신 포함)를 기반으로 한 여러 학술 논문이 등재되어 있으며, 이는 SMACC2가 실제 필드 로보틱스 및 미션 크리티컬 시스템의 엄격한 요구사항을 충족할 수 있는 잠재력을 가졌음을 시사한다.20
대표적인 예로 Carvalho 등의 2022년 IEEE OCEANS 학회 발표 논문인 “A SMACC based mission control system for autonomous underwater vehicles”가 있다.20 자율 무인 잠수정(AUV)과 같은 시스템은 예측 불가능하고 통신이 제한적인 수중 환경에서 장시간 동안 자율적으로 임무를 수행해야 한다. 이러한 시스템의 임무 제어 시스템(Mission Control System)은 극도의 신뢰성과 견고성(robustness)을 요구하며, 다양한 센서 데이터와 내부 상태를 기반으로 복잡한 의사결정을 내려야 한다. 연구자들이 이러한 까다로운 애플리케이션의 제어 아키텍처 기반으로 SMACC를 선택했다는 사실은 SMACC의 이벤트 기반 아키텍처와 계층적 상태 관리 능력이 미션 크리티컬 시스템 설계에 적합하다고 평가받았음을 의미한다.
또 다른 예로 Schrick 등의 2022년 IEEE ICAC 학회 논문인 “A novel control architecture for mobile robots in safety-critical applications”가 있다.20 안전이 중요한(safety-critical) 애플리케이션, 예를 들어 인간과 협업하는 로봇이나 의료 로봇, 원자력 발전소 순찰 로봇 등은 소프트웨어의 결함이 심각한 인명 또는 재산 피해로 이어질 수 있다. 이러한 시스템에서는 로봇의 모든 행동이 예측 가능하고 검증 가능해야 한다. SMACC2가 제공하는 컴파일 타임 상태 머신 검증 기능은 이러한 요구사항을 충족하는 데 큰 도움이 된다. 런타임에 발생할 수 있는 구조적 오류를 개발 단계에서 원천적으로 차단함으로써 시스템의 전체적인 안정성을 크게 높일 수 있기 때문이다.
이러한 학술적 채택 사례들은 SMACC2가 단순한 프로토타이핑 도구를 넘어, 실제 세계의 복잡하고 까다로운 로봇 애플리케이션을 구축하기 위한 진지한 엔지니어링 프레임워크로서의 가능성을 인정받고 있음을 보여주는 중요한 증거다.
SMACC2는 강력한 아키텍처와 기술적 장점에도 불구하고, 널리 채택되기까지 해결해야 할 몇 가지 명확한 한계점과 도전 과제를 안고 있다. 이러한 문제점들을 극복하는 것이 SMACC2의 미래 성공을 좌우할 것이다.
현재 SMACC2가 직면한 가장 큰 장벽은 공식 문서의 부족이다.13 라이브러리가 제공하는 강력한 개념들, 예를 들어 직교, 클라이언트, 클라이언트 행동, 상태 리액터 등에 대한 상세한 설명이나 단계별 튜토리얼이 매우 부족한 실정이다. 이로 인해 신규 사용자는 라이브러리의 철학을 이해하고 올바르게 활용하는 데 상당한 어려움을 겪는다.
현재로서는 SMACC2를 배우는 가장 효과적인 방법이 sm_dance_bot과 같은 제공된 예제 코드를 직접 분석하고 역으로 설계 의도를 파악하는 것인데 1, 이는 모든 개발자에게 기대할 수 있는 학습 방식이 아니다. 특히 C++ 템플릿 메타프로그래밍에 익숙하지 않은 개발자에게는
Boost.Statechart의 복잡한 문법과 난해한 컴파일 에러 메시지가 더해져 학습 곡선이 매우 가파르게 느껴질 수 있다. 이러한 높은 진입 장벽은 SMACC2의 우수한 아키텍처에도 불구하고 커뮤니티의 성장을 저해하고 잠재적인 사용자들을 이탈시키는 주요 원인으로 작용하고 있다.
SMACC2는 C++로 작성되어 높은 성능을 목표로 하지만, 극도로 복잡한 대규모 시스템에서의 확장성과 성능 오버헤드에 대한 정량적인 데이터는 아직 부족하다. 일반적인 ROS2 시스템에서는 수십 개의 노드와 수백 개의 통신 객체(publisher, subscriber, client 등)가 생성되면 DDS의 디스커버리 메커니즘과 내부 스케줄링으로 인해 상당한 오버헤드가 발생하고 시스템 전체의 반응성이 저하될 수 있다는 보고가 있다.21
SMACC2는 상태 머신을 단일 ROS2 노드 내에서 실행함으로써 이러한 노드 간 통신 오버헤드를 최소화하는 구조를 가지고 있다. 하지만 상태 머신 자체가 수백 개의 상태와 수십 개의 직교를 가지는 거대한 규모로 성장할 경우, 상태 전이 시 발생하는 내부 이벤트 처리, 클라이언트 행동 객체의 빈번한 동적 생성 및 소멸에 따른 메모리 할당 오버헤드, 그리고 복잡한 이벤트 큐 관리 등이 성능에 어떤 영향을 미칠지에 대한 심층적인 분석이 필요하다. 특히 실시간성이 요구되는 애플리케이션에서는 이러한 내부 오버헤드가 시스템의 결정론을 해칠 수 있는지에 대한 벤치마크 테스트와 검증이 요구된다.
다행히 SMACC2 개발팀과 커뮤니티는 이러한 문제점들을 인지하고 있으며, 이를 해결하기 위한 구체적인 노력을 기울이고 있다. 그 중심에는 SMACC 워킹 그룹(WG)이 있다.22 ROS2 생태계에서 워킹 그룹은 특정 기술 분야의 발전을 위해 커뮤니티의 힘을 모으는 공식적인 협의체 역할을 한다.
SMACC WG의 공식적인 임무 선언문에는 라이브러리의 핵심적인 약점을 보완하려는 의지가 명확하게 드러나 있다. 주요 목표는 다음과 같다 22:
WG는 정기적으로 온라인 회의를 개최하고 이를 ROS Discourse를 통해 공지하며 커뮤니티의 참여를 유도하고 있다.23 이는 SMACC2가 더 이상 Robosoft AI라는 단일 기업에 의해 주도되는 프로젝트가 아니라, 커뮤니티와 함께 발전해나가는 개방적인 생태계를 지향하고 있음을 보여주는 긍정적인 신호다. 따라서 SMACC2의 미래와 장기적인 성공 가능성은 이 워킹 그룹이 얼마나 활발하게 활동하고 실질적인 결과물(특히 문서화)을 만들어 내는지에 달려있다고 해도 과언이 아니다. SMACC2 도입을 고려하는 개발팀은 이 WG의 활동을 주시하며 라이브러리의 발전 방향과 커뮤니티 지원 수준을 가늠하는 것이 중요하다.
ROS2 Humble 환경에서 SMACC2를 기술적으로 심층 분석한 결과를 바탕으로, 도입 시 고려해야 할 장단점을 다음과 같이 요약할 수 있다.
장점 (Pros):
단점 (Cons):
Boost.Statechart의 복잡한 문법과 난해한 컴파일 에러에 대응하기 어렵다.이러한 장단점을 고려할 때, 모든 로봇 프로젝트에 SMACC2가 최적의 선택은 아니다. 프로젝트의 특성과 팀의 역량에 따라 도입 여부를 신중하게 결정해야 한다.
SMACC2 도입을 적극적으로 권장하는 경우:
도입에 신중을 기해야 하는 경우:
만약 프로젝트의 특성이 SMACC2에 적합하다고 판단하여 도입을 결정했다면, 성공적인 활용을 위해 다음의 전략을 제안한다.
첫째, 참조 코드를 교과서로 삼아야 한다. 공식 문서의 한계를 인정하고, smacc2_sm_reference_library에 포함된 sm_dance_bot, sm_three_some 등의 참조 상태 머신을 라인 바이 라인으로 분석하는 데 충분한 시간을 투자해야 한다. 이 코드들은 SMACC2의 아키텍처 패턴과 모범 사례를 담고 있는 가장 신뢰할 수 있는 학습 자료다.
둘째, SMACC 워킹 그룹(WG)에 적극적으로 참여하거나 최소한 활동을 주시해야 한다. WG의 회의록, GitHub 저장소의 이슈 트래커, 그리고 ROS Discourse의 관련 논의는 라이브러리의 최신 발전 방향, 알려진 문제점, 그리고 해결책에 대한 가장 정확한 정보를 제공한다. 버그를 발견하거나 기능 개선이 필요할 경우, 수동적으로 기다리기보다 직접 이슈를 제기하고 논의에 참여하는 것이 문제를 더 빨리 해결하는 길이다.
셋째, 팀 내부에 C++ 템플릿 전문가를 양성해야 한다. SMACC2 사용 시 마주하게 될 가장 큰 기술적 허들은 Boost.Statechart에서 비롯되는 복잡한 컴파일 에러일 가능성이 높다. 팀 내에 최소 한 명이라도 템플릿 메타프로그래밍의 원리를 이해하고 이러한 에러를 디버깅할 수 있는 전문가를 확보하는 것이 장기적인 개발 생산성 유지를 위해 필수적이다.
SMACC2는 분명 높은 잠재력을 가진 강력한 프레임워크지만, 아직은 ‘만인을 위한’ 도구가 아니다. 그 가치를 온전히 이끌어내기 위해서는 기술적 깊이와 명확한 아키텍처 설계, 그리고 커뮤니티와 함께 성장하려는 적극적인 자세가 요구된다.
| SMACC – State Machine Asynchronous C++ | An Event-Driven, Asynchronous, Behavioral State Machine Library for real-time ROS (Robotic Operating System) applications written in C++, accessed July 23, 2025, https://smacc.dev/ |
| Intro to Substate Objects | SMACC – State Machine Asynchronous C++, accessed July 23, 2025, https://smacc.dev/intro-to-substate-objects/ |