1294.45 ReactiveFallback의 개념

1. ReactiveFallback의 정의

ReactiveFallback은 Fallback 노드의 변형으로, 매 Tick마다 첫 번째 자식(인덱스 0)부터 모든 자식을 순차적으로 재평가하는 제어 흐름 노드이다. FallbackWithMemory와 달리, 이전 Tick에서 FAILURE를 반환한 자식도 다음 Tick에서 다시 평가된다. 이를 통해 우선순위가 높은 대안의 가용성 변화를 매 Tick마다 감지하고, 더 나은 대안이 가용해지면 현재 진행 중인 대안을 즉시 중단하고 전환할 수 있다(Colledanchise & Ogren, 2018).

“Reactive“라는 명칭은 ReactiveSequence와 동일하게 환경 변화에 대한 반응성(reactivity)을 강조한 것으로, 조건 및 대안의 가용성 변화에 즉각적으로 반응하는 능력을 의미한다.

2. ReactiveFallback의 핵심 특성

2.1 매 Tick 전면 재평가

ReactiveFallback은 내부에 current_child_idx 상태를 유지하지 않는다. 매 Tick에서 항상 인덱스 0의 자식부터 순차적으로 평가를 시작한다.

매 Tick의 실행:
  항상 children[0]부터 시작 → children[1] → ... → children[k]

2.2 우선순위 기반 대안 전환

앞쪽에 배치된 자식(더 높은 우선순위)이 매 Tick마다 재평가되므로, 이전에 FAILURE였던 앞쪽 자식이 SUCCESS로 변하면 즉시 감지된다. 이 경우 뒤쪽에서 RUNNING 상태인 자식이 Halt되고, Fallback은 SUCCESS를 반환한다.

Tick N:   CondA→F  ActB→R          → RUNNING
Tick N+1: CondA→S                   → SUCCESS (ActB를 Halt)

2.3 RUNNING 자식의 Halt

앞쪽 자식의 재평가에서 SUCCESS가 발생하면, 뒤쪽에서 RUNNING이었던 자식에게 Halt를 전달하여 진행 중인 비동기 작업을 즉시 중단시킨다.

3. FallbackWithMemory와의 비교

동일한 트리: [CondA, AsyncActB, ActC]

FallbackWithMemory:
  Tick 1: CondA→F, AsyncActB→R  → RUNNING (idx=1)
  Tick 2: AsyncActB→R            → RUNNING (CondA 건너뜀)
  Tick 3: AsyncActB→S            → SUCCESS

ReactiveFallback:
  Tick 1: CondA→F, AsyncActB→R  → RUNNING
  Tick 2: CondA→S                → SUCCESS (AsyncActB Halt)

ReactiveFallback에서는 Tick 2에서 CondA의 변화를 감지하여 더 우선순위가 높은 대안으로 즉시 전환한다. FallbackWithMemory에서는 CondA를 건너뛰므로 이 변화를 감지하지 못한다.

4. ReactiveSequence와의 대칭적 관계

ReactiveFallback과 ReactiveSequence는 동일한 “Reactive” 패턴을 공유하며, SUCCESS와 FAILURE의 역할이 교환된 대칭 관계이다.

특성ReactiveSequenceReactiveFallback
매 Tick 재평가
조기 종료 조건FAILURESUCCESS
계속 진행 조건SUCCESSFAILURE
RUNNING 자식 Halt 트리거앞쪽 자식 FAILURE앞쪽 자식 SUCCESS
전형적 앞쪽 노드조건 (안전 감시)조건 (목표 달성 확인)

5. ReactiveFallback의 전형적 사용 패턴

5.1 우선순위 기반 조건부 행동 선택

<ReactiveFallback>
    <Condition ID="IsGoalAlreadyAchieved"/>   <!-- 1순위: 이미 달성? -->
    <Action ID="AchieveGoalMethodA"/>          <!-- 2순위: 방법 A -->
    <Action ID="AchieveGoalMethodB"/>          <!-- 3순위: 방법 B -->
</ReactiveFallback>

매 Tick마다 목표 달성 여부가 재검사되며, 방법 A나 B를 수행하는 도중 목표가 달성되면(다른 요인에 의해) 현재 작업이 즉시 중단된다.

5.2 동적 대안 전환

<ReactiveFallback>
    <Sequence>
        <Condition ID="IsPrimaryPathClear"/>
        <Action ID="UsePrimaryPath"/>
    </Sequence>
    <Action ID="UseDetourPath"/>
</ReactiveFallback>

우회 경로를 사용하는 도중 주 경로가 정리되면, 우회를 중단하고 주 경로로 즉시 전환한다.

5.3 조건 기반 행동 재개

<ReactiveFallback>
    <Condition ID="IsTaskComplete"/>
    <Condition ID="IsRecharging"/>
    <Action ID="PerformTask"/>
</ReactiveFallback>

작업 수행 중 충전 상태가 되거나 작업이 완료되면 즉시 감지된다.

6. ReactiveFallback의 대가

6.1 Tick 비용 증가

매 Tick마다 첫 번째 자식부터 재평가하므로, RUNNING 상태가 지속되는 동안 Tick당 방문 노드 수가 FallbackWithMemory보다 많다.

6.2 앞쪽 액션의 반복 실행 위험

ReactiveSequence와 마찬가지로, 앞쪽에 부수 효과가 있는 액션 노드를 배치하면 매 Tick마다 재실행되어 의도하지 않은 동작이 발생할 수 있다. ReactiveFallback에서도 앞쪽에는 조건 노드만 배치하는 것이 일반적 관례이다.

7. BehaviorTree.CPP v4에서의 표현

BehaviorTree.CPP v4에서 ReactiveFallback은 <ReactiveFallback> XML 태그로 정의된다(Faconti, 2022).

<ReactiveFallback>
    <Condition ID="IsAtGoal"/>
    <Action ID="NavigateToGoal"/>
</ReactiveFallback>

기본 <Fallback> 태그(WithMemory 동작)와 명확히 구분되며, 개발자가 의도적으로 ReactiveFallback을 선택해야 한다.


참고 문헌

  • 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/