Inverter 데코레이터의 동작 (Operation of the Inverter Decorator)
1. 개요
Inverter 데코레이터는 행동 트리에서 가장 기본적이고 빈번히 사용되는 데코레이터로, 자식 노드의 SUCCESS와 FAILURE 반환 상태를 상호 반전시킨다. 이는 명제 논리의 NOT 연산자(\neg)에 직접 대응하며, 조건 노드의 의미를 반전시키거나, 행동의 결과를 뒤집어 해석하는 데 활용된다.
2. 상태 변환 규칙
2.1 변환 테이블
| 자식 반환 상태 | Inverter 반환 상태 | 설명 |
|---|---|---|
SUCCESS | FAILURE | 성공을 실패로 반전 |
FAILURE | SUCCESS | 실패를 성공으로 반전 |
RUNNING | RUNNING | 변환 없이 통과 |
2.2 수학적 표현
f_{\text{Inverter}}(s) = \begin{cases} \neg s & \text{if } s \in \{\text{SUCCESS}, \text{FAILURE}\} \\ s & \text{if } s = \text{RUNNING} \end{cases}
여기서 \neg \text{SUCCESS} = \text{FAILURE}, \neg \text{FAILURE} = \text{SUCCESS}이다.
BehaviorTree.CPP 구현
class InverterNode : public DecoratorNode
{
public:
InverterNode(const std::string& name)
: DecoratorNode(name, {})
{}
private:
BT::NodeStatus tick() override
{
setStatus(BT::NodeStatus::RUNNING);
const BT::NodeStatus child_status =
child_node_->executeTick();
switch (child_status)
{
case BT::NodeStatus::SUCCESS:
return BT::NodeStatus::FAILURE;
case BT::NodeStatus::FAILURE:
return BT::NodeStatus::SUCCESS;
case BT::NodeStatus::RUNNING:
return BT::NodeStatus::RUNNING;
default:
throw BT::LogicError("Invalid status");
}
}
};
Inverter는 무상태(stateless) 데코레이터로, 내부 상태를 유지하지 않으며 입력 포트도 요구하지 않는다. 따라서 halt() 메서드에서의 별도 초기화가 불필요하다.
RUNNING 통과의 근거
RUNNING 상태를 반전하지 않고 그대로 전달하는 이유는 다음과 같다.
- 비동기 실행의 보존: 자식이 비동기적으로 실행 중임을 부모에게 올바르게 전달하여야 한다.
- tick 전파의 일관성: 다음 tick에서 자식을 다시 tick하기 위해
RUNNING신호가 필요하다. - halt 메커니즘의 정합성:
RUNNING상태의 노드만이 halt 대상이다.
만약 RUNNING을 RUNNING이 아닌 다른 상태로 반전하면, 자식이 여전히 실행 중임에도 부모가 이를 인지하지 못하여 다음 tick에서 자식이 tick되지 않고, halt도 호출되지 않아 리소스 누수가 발생한다.
논리적 NOT 연산으로서의 의미
Inverter는 행동 트리에서 논리적 NOT 연산을 구현하는 유일한 메커니즘이다.
조건 반전
“장애물이 감지되었는가?“를 “장애물이 감지되지 않았는가?“로 변환한다.
<Inverter>
<Condition ID="IsObstacleDetected"/>
</Inverter>
복합 논리와의 결합
드모르간 법칙(De Morgan’s laws)의 적용:
\neg(A \wedge B) = \neg A \vee \neg B
<!-- ¬(A ∧ B) -->
<Inverter>
<Sequence>
<Condition ID="A"/>
<Condition ID="B"/>
</Sequence>
</Inverter>
3. 활용 사례
3.1 안전 조건의 표현
<ReactiveSequence>
<Inverter>
<Condition ID="IsEmergencyStopActive"/>
</Inverter>
<Action ID="ContinueOperation"/>
</ReactiveSequence>
비상 정지가 활성화되지 않은 동안에만 운용을 계속한다.
3.2 Fallback 내 조건부 행동 선택
<Fallback>
<Sequence>
<Inverter>
<Condition ID="IsNightTime"/>
</Inverter>
<Action ID="DaytimeOperation"/>
</Sequence>
<Action ID="NighttimeOperation"/>
</Fallback>
3.3 이중 반전의 제거
<!-- 안티패턴: 이중 Inverter는 무의미 -->
<Inverter>
<Inverter>
<Condition ID="A"/>
</Inverter>
</Inverter>
<!-- 올바른 형태: 단순히 A를 사용 -->
<Condition ID="A"/>
\neg(\neg A) = A이므로, 이중 Inverter는 항등 변환이다.
4. 설계 시 고려 사항
4.1 명명의 명확성
Inverter 사용 시 반전된 의미가 직관적인지를 확인한다. 빈번히 반전하여 사용하는 조건에 대해서는 반대 의미의 조건 노드(예: IsPathClear vs IsObstacleDetected)를 별도로 구현하는 것이 가독성 측면에서 유리하다.
4.2 액션 노드에 대한 Inverter
조건 노드뿐만 아니라 액션 노드에도 Inverter를 적용할 수 있으나, 액션 노드는 RUNNING을 반환할 수 있으므로 RUNNING 통과 규칙을 숙지하여야 한다.
5. 참고 문헌
- Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
- BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/
| 버전 | 날짜 | 변경 사항 |
|---|---|---|
| v0.1 | 2026-04-04 | 초안 작성 |