RunOnce의 최초 단일 실행 보장 (RunOnce's Single Execution Guarantee)

RunOnce의 최초 단일 실행 보장 (RunOnce’s Single Execution Guarantee)

1. 개요

RunOnce 데코레이터의 최초 단일 실행 보장은 자식 노드가 정확히 한 번만 완전히 실행(SUCCESS 또는 FAILURE로 완료)되도록 보장하는 메커니즘이다. 자식이 완료된 후에는 동일한 행동 트리가 반복적으로 tick되더라도 자식을 재실행하지 않으며, 캐싱된 결과를 즉시 반환한다.

2. 단일 실행 보장의 메커니즘

2.1 내부 플래그

RunOnce는 already_completed_ 불리언 플래그를 유지한다.

초기 상태:    already_completed_ = false
자식 완료 후: already_completed_ = true

2.2 tick() 동작

BT::NodeStatus tick() override
{
    // 이미 완료된 경우: 캐싱된 결과 즉시 반환
    if (already_completed_)
    {
        return cached_status_;
    }

    // 아직 완료되지 않은 경우: 자식 tick
    auto status = child_node_->executeTick();

    if (status != BT::NodeStatus::RUNNING)
    {
        already_completed_ = true;
        cached_status_ = status;
    }

    return status;
}

3. 단일 실행이 보장되는 범위

3.1 ReactiveSequence 내에서

<ReactiveSequence>
    <Condition ID="IsActive"/>
    <RunOnce>
        <Action ID="Initialize"/>
    </RunOnce>
    <Action ID="MainTask"/>
</ReactiveSequence>

ReactiveSequence는 매 tick마다 모든 자식을 재평가하지만, RunOnce에 의해 Initialize는 최초 한 번만 실행된다.

3.2 Repeat 내에서

<Repeat num_cycles="10">
    <Sequence>
        <RunOnce>
            <Action ID="PrepareOnce"/>
        </RunOnce>
        <Action ID="RepeatableTask"/>
    </Sequence>
</Repeat>

10회 반복 중 PrepareOnce는 첫 번째 반복에서만 실행되고, 나머지 9회에서는 캐싱된 결과가 반환된다.

4. 비동기 자식의 단일 실행

자식이 비동기 행동인 경우, RUNNING 상태 동안에는 매 tick마다 자식을 계속 tick한다. 자식이 최종적으로 SUCCESS 또는 FAILURE를 반환하면 그 시점에서 already_completed_true로 설정되고, 이후에는 캐싱된 결과가 반환된다.

Tick 1: already_completed_=false → 자식 tick → RUNNING
Tick 2: already_completed_=false → 자식 tick → RUNNING
Tick 3: already_completed_=false → 자식 tick → SUCCESS
         → already_completed_=true, cached_status_=SUCCESS
Tick 4: already_completed_=true → SUCCESS (캐시)

5. halt에 의한 리셋

RunOnce가 halt되었을 때 already_completed_ 플래그를 리셋하는지 여부는 구현 정책에 따라 다르다.

정책halt 후 재실행 여부적합한 상황
리셋다음 tick에서 자식 재실행행동 트리가 재시작될 때마다 초기화 필요
비리셋자식 재실행 안 함전체 생명주기에서 단 한 번만 필요

6. 설계 시 고려 사항

6.1 자식 FAILURE의 영구 캐싱

자식이 FAILURE를 반환하면 이것이 영구적으로 캐싱되어, 이후 모든 tick에서 FAILURE가 반환된다. 초기화 실패 시 재시도가 필요하면 RunOnce 내부에 Retry를 배치한다.

6.2 행동 트리 교체 시의 상태

행동 트리가 동적으로 교체되면 RunOnce의 내부 상태도 초기화된다. 새로운 행동 트리에서 RunOnce는 다시 자식을 실행한다.

7. 참고 문헌

  • Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
  • BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/

버전날짜변경 사항
v0.12026-04-04초안 작성