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::ConditionNode는 BT::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() 호출만을 수행한다.
이 설계의 의도는 다음과 같다:
-
RUNNING 상태 불가 표현: 조건 노드는
RUNNING을 반환하지 않으므로, 진행 중인 동작을 중단할 필요가 없다.halt()에서 추가적인 정리(cleanup) 로직이 불필요하다. -
설계 제약의 강제:
halt()를 재정의할 수 없게 함으로써, 개발자가 조건 노드에RUNNING상태와 관련된 로직을 추가하는 것을 컴파일 시점에 방지한다. -
일관된 동작 보장: 모든 조건 노드가 동일한 halt 동작을 수행하므로, 제어 노드가 조건 노드를 중단할 때의 동작이 예측 가능하다.
5. NodeType 식별
ConditionNode는 NodeType::CONDITION을 반환하는 정적 메서드를 제공한다. 이를 통해 트리 실행 엔진은 런타임에 노드의 유형을 식별할 수 있다.
static NodeType type()
{
return NodeType::CONDITION;
}
트리 실행 엔진은 이 유형 정보를 사용하여 조건 노드의 반환값 검증(RUNNING 반환 시 오류 발생), 시각화 도구에서의 노드 유형별 구분 표시, 로깅에서의 노드 유형 기록 등을 수행한다.
6. LeafNode로부터의 상속
ConditionNode는 LeafNode를 통해 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의 구조적 대비
| 특성 | ConditionNode | ActionNodeBase |
|---|---|---|
| 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