1297.13 조건 노드의 기반 클래스 (ConditionNode)

1297.13 조건 노드의 기반 클래스 (ConditionNode)

1. BehaviorTree.CPP의 클래스 계층 구조

BehaviorTree.CPP 라이브러리는 행동 트리(Behavior Tree)의 모든 노드를 BT::TreeNode 기반 클래스로부터 파생하여 일관된 인터페이스를 제공한다. 노드 유형에 따른 클래스 계층 구조는 다음과 같다(Faconti & Colledanchise, 2022):

BT::TreeNode
├── BT::ControlNode
│   ├── BT::SequenceNode
│   ├── BT::FallbackNode
│   ├── BT::ReactiveSequence
│   ├── BT::ReactiveFallback
│   └── BT::ParallelNode
├── BT::DecoratorNode
│   ├── BT::InverterNode
│   ├── BT::RetryNode
│   └── ...
└── BT::LeafNode
    ├── BT::ConditionNode        ← 조건 노드의 기반 클래스
    └── BT::ActionNodeBase
        ├── BT::SyncActionNode
        ├── BT::StatefulActionNode
        └── BT::CoroActionNode

BT::ConditionNodeBT::LeafNode를 상속하며, 모든 사용자 정의 조건 노드의 기반 클래스로 기능한다.

2. ConditionNode 클래스의 정의

BT::ConditionNode 클래스의 핵심 구현은 다음과 같다:

namespace BT
{

class ConditionNode : public LeafNode
{
public:
    ConditionNode(const std::string& name, const NodeConfig& config);

    virtual ~ConditionNode() = default;

    // halt()는 final로 선언되어 재정의 불가
    virtual void halt() override final;

    // 노드 유형 반환
    static NodeType type()
    {
        return NodeType::CONDITION;
    }
};

}  // namespace BT

이 클래스는 조건 노드의 핵심 특성을 구조적으로 강제하는 역할을 수행한다.

3. 생성자

ConditionNode의 생성자는 노드 이름(name)과 노드 설정(NodeConfig)을 매개변수로 받는다.

ConditionNode::ConditionNode(const std::string& name, const NodeConfig& config)
    : LeafNode(name, config)
{}

NodeConfig는 블랙보드 포트 매핑, 블랙보드 인스턴스에 대한 참조 등 노드의 설정 정보를 포함하는 구조체이다. 이 설정은 트리 빌더(tree builder)에 의해 자동으로 생성되며, XML 트리 정의에서 지정된 포트 매핑이 반영된다.

사용자 정의 조건 노드의 생성자에서는 기반 클래스의 생성자를 호출한 후, ROS2 노드 참조의 저장, 구독자의 초기화 등 노드 고유의 초기화 작업을 수행할 수 있다.

class IsBatteryOk : public BT::ConditionNode
{
public:
    IsBatteryOk(const std::string& name, const BT::NodeConfig& config)
        : BT::ConditionNode(name, config)
    {
        // 사용자 정의 초기화
    }
};

4. halt() 메서드의 final 선언

ConditionNode의 가장 중요한 구조적 특징은 halt() 메서드가 override final로 선언되어 있다는 것이다:

virtual void halt() override final
{
    resetStatus();
}

final 키워드는 이 메서드를 파생 클래스에서 재정의할 수 없음을 의미한다. halt() 메서드는 노드 상태를 IDLE로 초기화하는 resetStatus() 호출만을 수행한다.

이 설계의 의도는 다음과 같다:

  1. RUNNING 상태 불가 표현: 조건 노드는 RUNNING을 반환하지 않으므로, 진행 중인 동작을 중단할 필요가 없다. halt()에서 추가적인 정리(cleanup) 로직이 불필요하다.

  2. 설계 제약의 강제: halt()를 재정의할 수 없게 함으로써, 개발자가 조건 노드에 RUNNING 상태와 관련된 로직을 추가하는 것을 컴파일 시점에 방지한다.

  3. 일관된 동작 보장: 모든 조건 노드가 동일한 halt 동작을 수행하므로, 제어 노드가 조건 노드를 중단할 때의 동작이 예측 가능하다.

5. NodeType 식별

ConditionNodeNodeType::CONDITION을 반환하는 정적 메서드를 제공한다. 이를 통해 트리 실행 엔진은 런타임에 노드의 유형을 식별할 수 있다.

static NodeType type()
{
    return NodeType::CONDITION;
}

트리 실행 엔진은 이 유형 정보를 사용하여 조건 노드의 반환값 검증(RUNNING 반환 시 오류 발생), 시각화 도구에서의 노드 유형별 구분 표시, 로깅에서의 노드 유형 기록 등을 수행한다.

6. LeafNode로부터의 상속

ConditionNodeLeafNode를 통해 TreeNode의 모든 기능을 상속받는다. 주요 상속 기능은 다음과 같다:

6.1 블랙보드 접근

getInput<T>() 메서드를 통해 블랙보드에서 입력 포트의 값을 읽을 수 있다:

double value;
auto result = getInput("port_name", value);

6.2 노드 상태 관리

status() 메서드를 통해 현재 노드의 상태를 조회할 수 있으며, resetStatus() 메서드를 통해 상태를 IDLE로 초기화할 수 있다.

6.3 노드 메타데이터

name() 메서드를 통해 노드의 이름을, registrationName() 메서드를 통해 등록 시 사용된 ID를 조회할 수 있다.

7. 사용자 정의 조건 노드의 구현 패턴

사용자가 조건 노드를 구현할 때 최소한으로 필요한 작업은 ConditionNode를 상속하고, tick() 메서드를 재정의하고, providedPorts() 정적 메서드를 정의하는 것이다.

class IsDistanceSafe : public BT::ConditionNode
{
public:
    IsDistanceSafe(const std::string& name, const BT::NodeConfig& config)
        : BT::ConditionNode(name, config)
    {}

    // tick() 메서드 재정의: 조건 평가 로직 구현
    BT::NodeStatus tick() override
    {
        double distance;
        getInput("distance", distance);

        double threshold;
        getInput("threshold", threshold);

        return (distance > threshold)
            ? BT::NodeStatus::SUCCESS
            : BT::NodeStatus::FAILURE;
    }

    // 포트 정의: 노드가 사용하는 입출력 포트 선언
    static BT::PortsList providedPorts()
    {
        return {
            BT::InputPort<double>("distance", "현재 거리 값"),
            BT::InputPort<double>("threshold", 1.0, "안전 거리 임계값")
        };
    }
};

8. 노드 등록

사용자 정의 조건 노드는 BehaviorTreeFactory에 등록하여 XML 트리 정의에서 사용할 수 있도록 한다:

BT::BehaviorTreeFactory factory;
factory.registerNodeType<IsDistanceSafe>("IsDistanceSafe");

등록 시 ConditionNode를 상속한 클래스는 자동으로 NodeType::CONDITION으로 분류되며, 트리 실행 엔진이 이 노드에 대하여 조건 노드 고유의 검증(RUNNING 반환 방지 등)을 적용한다.

9. ConditionNode와 ActionNodeBase의 구조적 대비

특성ConditionNodeActionNodeBase
halt() 재정의불가 (final)가능
RUNNING 반환금지허용
하위 클래스단일 (ConditionNode)복수 (SyncAction, StatefulAction 등)
실행 모델동기 즉시 반환동기/비동기/코루틴
부작용금지허용

이 구조적 차이는 ConditionNode가 조건 노드의 설계 원칙을 클래스 수준에서 강제하며, 액션 노드의 다양한 실행 모델과 명확히 구분되는 단순한 인터페이스를 제공함을 보여준다.

10. 참고 문헌

  • Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
  • Faconti, D., & Colledanchise, M. (2022). BehaviorTree.CPP Documentation. https://www.behaviortree.dev/

version: 0.1.0