1294.19 ReactiveSequence의 개념
1. ReactiveSequence의 정의
ReactiveSequence는 Sequence 노드의 변형으로, 매 Tick마다 첫 번째 자식부터 모든 자식을 순차적으로 재평가하는 제어 흐름 노드이다. SequenceWithMemory와 달리, 이전 Tick에서 SUCCESS를 반환한 자식도 다음 Tick에서 다시 평가된다. 이를 통해 조건의 변화를 매 Tick마다 감지하고, 조건이 충족되지 않으면 진행 중인 작업을 즉시 중단할 수 있다(Colledanchise & Ogren, 2018).
“Reactive“라는 명칭은 환경 변화에 대한 반응성(reactivity)을 강조한 것으로, 조건의 변화에 즉각적으로 반응하여 행동을 조정하는 능력을 의미한다.
2. ReactiveSequence의 핵심 특성
2.1 매 Tick 전면 재평가
ReactiveSequence는 내부에 current_child_idx 상태를 유지하지 않는다. 매 Tick에서 항상 인덱스 0의 자식부터 순차적으로 평가를 시작한다.
매 Tick의 실행:
항상 children[0]부터 시작 → children[1] → ... → children[k]
2.2 조건 재검사 능력
앞쪽에 배치된 조건 노드가 매 Tick마다 재평가되므로, 조건의 변화를 즉시 감지할 수 있다. 이전 Tick에서 SUCCESS였던 조건이 FAILURE로 변하면, 뒤쪽의 RUNNING 중인 액션이 Halt된다.
Tick N: CondA→S CondB→S ActC→R → RUNNING
Tick N+1: CondA→S CondB→F → FAILURE (ActC를 Halt)
2.3 RUNNING 자식의 Halt
조건 재평가에서 FAILURE가 발생하면, 이전에 RUNNING이었던 자식에게 Halt를 전달하여 진행 중인 비동기 작업을 중단시킨다. 이 Halt는 ReactiveSequence의 안전 보장 메커니즘의 핵심이다.
3. SequenceWithMemory와의 비교
동일한 트리: [CondA, CondB, AsyncAct]
SequenceWithMemory:
Tick 1: CondA→S, CondB→S, AsyncAct→R → RUNNING (idx=2)
Tick 2: AsyncAct→R → RUNNING (CondA, CondB 건너뜀)
Tick 3: AsyncAct→S → SUCCESS
ReactiveSequence:
Tick 1: CondA→S, CondB→S, AsyncAct→R → RUNNING
Tick 2: CondA→S, CondB→S, AsyncAct→R → RUNNING (매번 재평가)
Tick 3: CondA→S, CondB→F → FAILURE (AsyncAct Halt)
ReactiveSequence에서는 Tick 3에서 CondB의 변화를 감지하여 AsyncAct를 중단한다. SequenceWithMemory에서는 CondB를 건너뛰므로 이 변화를 감지하지 못한다.
4. ReactiveSequence의 전형적 사용 패턴
4.1 안전 조건 감시 패턴
<ReactiveSequence>
<Condition ID="IsNotEmergency"/> <!-- 매 Tick 재검사 -->
<Condition ID="IsBatteryAbove10"/> <!-- 매 Tick 재검사 -->
<Action ID="NavigateToGoal"/> <!-- 비동기 작업 -->
</ReactiveSequence>
비상 상황이 발생하거나 배터리가 소진되면, NavigateToGoal이 진행 중이더라도 즉시 중단된다.
4.2 환경 조건 감시 패턴
<ReactiveSequence>
<Condition ID="IsPathClear"/> <!-- 장애물 감지 시 중단 -->
<Action ID="FollowPath"/> <!-- 경로 추종 -->
</ReactiveSequence>
경로상에 장애물이 감지되면 FollowPath가 즉시 Halt된다.
5. ReactiveSequence의 대가
5.1 Tick 비용 증가
매 Tick마다 첫 번째 자식부터 재평가하므로, RUNNING 상태가 지속되는 동안 Tick당 방문 노드 수가 SequenceWithMemory보다 많다. 조건 노드의 평가 비용이 큰 경우, 이 비용이 누적된다.
5.2 부수 효과의 위험
조건 노드가 아닌 액션 노드가 앞에 배치된 경우, 매 Tick마다 재실행되어 의도하지 않은 부수 효과가 발생할 수 있다. ReactiveSequence에서는 앞쪽에 조건 노드만, 뒤쪽에 액션 노드를 배치하는 것이 일반적 관례이다.
6. BehaviorTree.CPP v4에서의 표현
BehaviorTree.CPP v4에서 ReactiveSequence는 <ReactiveSequence> XML 태그로 정의된다(Faconti, 2022).
<ReactiveSequence>
<Condition ID="IsSafe"/>
<Action ID="PerformTask"/>
</ReactiveSequence>
<Sequence> 태그(WithMemory 기본)와 명확히 구분되며, 개발자가 의도적으로 ReactiveSequence를 선택해야 한다.
참고 문헌
- 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/