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/