1294.9 Sequence 노드의 Failure 반환 조건
1. Failure 반환의 정의
Sequence 노드가 FAILURE를 반환하는 조건은 자식 노드 중 하나가 FAILURE를 반환하는 것이다. 순차적 평가 과정에서 첫 번째로 FAILURE를 반환하는 자식이 발견되면, Sequence는 나머지 자식의 평가를 생략하고 즉시 FAILURE를 반환한다(Colledanchise & Ogren, 2018).
\text{Sequence} = \text{FAILURE} \iff \exists\, i \in \{1, \ldots, N\},\ C_i = \text{FAILURE} \wedge \forall\, j < i,\ C_j = \text{SUCCESS}
Failure 발생 시점
조건 노드에서의 Failure
조건 노드는 즉시 반환하므로, 조건이 충족되지 않으면 해당 Tick에서 바로 FAILURE가 결정된다.
Tick:
children[0]: IsBatteryAbove20 → FAILURE
children[1]: NavigateToGoal → (평가되지 않음)
Sequence → FAILURE
액션 노드에서의 Failure
비동기 액션 노드는 여러 Tick 동안 RUNNING을 반환한 후 FAILURE를 반환할 수 있다. 이 경우 해당 Tick에서 Sequence의 FAILURE가 확정된다.
Tick 1:
children[0]: CheckCondition → SUCCESS
children[1]: NavigateToGoal → RUNNING
Sequence → RUNNING
Tick 2:
children[1]: NavigateToGoal → FAILURE ← 네비게이션 실패
Sequence → FAILURE
Failure 시의 후속 처리
RUNNING 자식의 Halt
Sequence가 FAILURE를 반환하기로 결정할 때, 현재 RUNNING 상태인 다른 자식이 존재하면 해당 자식에게 Halt를 전달한다. 이 상황은 주로 ReactiveSequence에서 발생한다.
ReactiveSequence에서:
Tick 1:
children[0]: IsBatteryAbove20 → SUCCESS
children[1]: NavigateToGoal → RUNNING
Sequence → RUNNING
Tick 2:
children[0]: IsBatteryAbove20 → FAILURE ← 배터리 부족
children[1]: NavigateToGoal → Halt 호출 (RUNNING → IDLE)
Sequence → FAILURE
WithMemory에서의 인덱스 초기화
WithMemory 모드의 Sequence가 FAILURE를 반환하면, 기억하고 있던 현재 자식 인덱스가 0으로 초기화된다. 다음에 Sequence가 다시 Tick되면 첫 번째 자식부터 실행을 시작한다.
if (child_status == NodeStatus::FAILURE) {
haltChildren();
current_child_idx_ = 0; // 인덱스 초기화
return NodeStatus::FAILURE;
}
Failure의 전파
Sequence의 FAILURE는 부모 노드에 전달된다. 부모 노드의 유형에 따라 이 FAILURE가 다르게 해석된다.
| 부모 노드 유형 | Sequence FAILURE 시 동작 |
|---|---|
| Fallback | 다음 자식으로 이동 (대안 시도) |
| Sequence | 부모 Sequence도 FAILURE 반환 |
| Decorator (Inverter) | SUCCESS로 반전 |
| 루트 노드 | 트리 전체가 FAILURE |
Fallback 노드 하에서 Sequence의 FAILURE는 “이 방법은 실패했으니 다음 대안을 시도하라“는 의미를 가진다. 이는 시도-대안(try-alternative) 패턴의 기반이 된다.
<Fallback>
<Sequence> <!-- 방법 1: 실패하면 다음으로 -->
<Condition ID="IsPathClear"/>
<Action ID="NavigateDirect"/>
</Sequence>
<Sequence> <!-- 방법 2: 대안 -->
<Action ID="ComputeDetour"/>
<Action ID="NavigateDetour"/>
</Sequence>
</Fallback>
Failure 원인의 진단
Sequence의 FAILURE만으로는 어떤 자식이 실패했는지를 알 수 없다. 디버깅과 로그 분석에서 FAILURE의 원인을 추적하기 위해, StatusChangeLogger를 사용하여 각 자식의 상태 전이를 기록하거나, 실패한 자식이 블랙보드에 실패 원인을 기록하는 패턴을 사용한다.
BT::NodeStatus tick() override {
bool result = performNavigation();
if (!result) {
setOutput("failure_reason", "Goal unreachable");
return BT::NodeStatus::FAILURE;
}
return BT::NodeStatus::SUCCESS;
}
Sequence의 FAILURE는 그 자체로 오류가 아니라, 트리의 정상적인 의사 결정 결과이다. FAILURE는 “현재 조건에서 이 순차 작업을 수행할 수 없음“을 나타내는 논리적 신호이며, 상위 트리가 이를 활용하여 대안 행동을 선택할 수 있도록 한다(Colledanchise & Ogren, 2018).
참고 문헌
- Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
- Faconti, D. (2022). BehaviorTree.CPP documentation and API reference. https://www.behaviortree.dev/