실행 제어 데코레이터 (Execution Control Decorators)

실행 제어 데코레이터 (Execution Control Decorators)

1. 개요

실행 제어 데코레이터는 자식 노드의 실행 횟수, 재시도 정책, 반복 패턴 등을 제어하는 데코레이터 노드의 범주이다. 반환 상태 변환 데코레이터가 자식의 결과만을 수정하는 반면, 실행 제어 데코레이터는 자식이 언제, 몇 번 실행되는지를 결정한다. 이 유형의 데코레이터는 내부 상태(카운터, 플래그)를 유지하며, 상태 유지 데코레이터(stateful decorator)에 해당한다.

2. 주요 실행 제어 데코레이터

2.1 RetryNode (재시도)

자식이 FAILURE를 반환하면 지정된 최대 횟수까지 재시도한다.

자식 반환RetryNode 동작결과
SUCCESS재시도 종료SUCCESS 반환
FAILURE (횟수 미초과)카운터 증가, 다음 tick에서 재시도RUNNING 반환
FAILURE (횟수 초과)재시도 포기FAILURE 반환
RUNNING자식 실행 계속RUNNING 반환
<RetryNode num_attempts="3">
    <Action ID="ConnectToSensor"/>
</RetryNode>

센서 연결에 실패하면 최대 3회 재시도한다.

2.2 RepeatNode (반복)

자식이 SUCCESS를 반환하면 지정된 횟수만큼 반복 실행한다.

자식 반환RepeatNode 동작결과
SUCCESS (횟수 미도달)카운터 증가, 다음 tick에서 재실행RUNNING 반환
SUCCESS (횟수 도달)반복 완료SUCCESS 반환
FAILURE반복 중단FAILURE 반환
RUNNING자식 실행 계속RUNNING 반환
<Repeat num_cycles="5">
    <Action ID="PatrolWaypoint"/>
</Repeat>

num_cycles-1로 설정하면 무한 반복이 된다.

2.3 RunOnce (일회 실행)

자식을 최초 한 번만 실행하고, 이후 tick에서는 이전 결과를 캐싱하여 반환한다.

상태동작
최초 tick자식을 tick하고 결과를 캐싱
이후 tick캐싱된 결과를 즉시 반환 (자식을 tick하지 않음)
<RunOnce>
    <Action ID="InitializeHardware"/>
</RunOnce>

시스템 초기화와 같이 한 번만 수행하여야 하는 행동에 적합하다.

2.4 KeepRunningUntilFailure (실패까지 계속)

자식이 FAILURE를 반환할 때까지 RUNNING을 반환하여 실행을 지속한다.

자식 반환데코레이터 결과
SUCCESSRUNNING (다음 tick에서 자식 재실행)
FAILUREFAILURE
RUNNINGRUNNING
<KeepRunningUntilFailure>
    <Action ID="MonitorSensorData"/>
</KeepRunningUntilFailure>

센서 감시와 같이 지속적으로 실행되어야 하는 행동에 적합하다.

3. 내부 상태 관리

3.1 카운터 기반 데코레이터

RetryNodeRepeatNode는 내부 카운터를 유지하여 실행 횟수를 추적한다.

class RetryNode : public BT::DecoratorNode
{
    BT::NodeStatus tick() override
    {
        setStatus(BT::NodeStatus::RUNNING);
        BT::NodeStatus child_status = child_node_->executeTick();

        if (child_status == BT::NodeStatus::SUCCESS)
        {
            try_count_ = 0;
            return BT::NodeStatus::SUCCESS;
        }
        if (child_status == BT::NodeStatus::FAILURE)
        {
            ++try_count_;
            if (try_count_ >= max_attempts_)
            {
                try_count_ = 0;
                return BT::NodeStatus::FAILURE;
            }
            return BT::NodeStatus::RUNNING;
        }
        return child_status;  // RUNNING
    }

    void halt() override
    {
        try_count_ = 0;
        DecoratorNode::halt();
    }

private:
    int try_count_ = 0;
    int max_attempts_ = 1;
};

3.2 halt() 시 상태 초기화

실행 제어 데코레이터가 halt될 때, 내부 카운터와 플래그를 반드시 초기화하여야 한다. 초기화하지 않으면 다음 실행에서 이전 상태가 잔존하여 예기치 않은 동작이 발생한다.

4. 실행 제어 데코레이터의 조합

<Timeout msec="60000">
    <RetryNode num_attempts="5">
        <Action ID="DownloadMap"/>
    </RetryNode>
</Timeout>

전체 60초 이내에서 지도 다운로드를 최대 5회 재시도한다. Timeout은 시간 제어 데코레이터이며, RetryNode는 실행 제어 데코레이터이다. 두 유형의 조합으로 시간과 횟수 모두 제한된 재시도 정책을 구현한다.

5. 설계 시 고려 사항

5.1 무한 반복 방지

RepeatNode-1을 설정하거나, KeepRunningUntilFailure를 사용하면 무한 실행이 발생한다. 반드시 Timeout 또는 외부 조건에 의한 종료 메커니즘과 함께 사용하여야 한다.

5.2 재시도 간격

RetryNode는 기본적으로 다음 tick에서 즉시 재시도한다. 재시도 사이에 지연이 필요한 경우 Delay 데코레이터를 내부에 배치한다.

<RetryNode num_attempts="3">
    <Delay delay_msec="1000">
        <Action ID="ConnectToServer"/>
    </Delay>
</RetryNode>

5.3 RUNNING 반환의 의미

RetryNodeRepeatNodeRUNNING을 반환할 때, 이는 자식이 실행 중인 것이 아니라 데코레이터가 다음 시도/반복을 준비 중임을 나타내는 경우가 있다. 이 구분은 halt 처리에 중요하다.

6. 참고 문헌

  • 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초안 작성