1293.55 동기 노드와 비동기 노드의 Tick 처리 차이

1293.55 동기 노드와 비동기 노드의 Tick 처리 차이

1. 동기 노드와 비동기 노드의 구분

행동 트리(Behavior Tree)에서 노드는 Tick 처리 방식에 따라 동기 노드(synchronous node)와 비동기 노드(asynchronous node)로 구분된다. 동기 노드는 단일 Tick 내에서 실행이 완료되어 SUCCESS 또는 FAILURE를 즉시 반환하며, 비동기 노드는 복수의 Tick에 걸쳐 실행이 진행되어 RUNNING을 반환할 수 있다(Colledanchise & Ogren, 2018).

2. 동기 노드의 Tick 처리

2.1 특성

동기 노드는 tick() 메서드가 호출되면, 해당 메서드 내에서 모든 작업을 완료하고 즉시 SUCCESS 또는 FAILURE를 반환한다. RUNNING을 반환하지 않는다.

class SyncAction : public BT::SyncActionNode {
public:
    BT::NodeStatus tick() override {
        // 모든 작업을 여기서 완료
        double value;
        getInput("input", value);
        bool result = performComputation(value);
        return result 
            ? BT::NodeStatus::SUCCESS 
            : BT::NodeStatus::FAILURE;
    }
};

2.2 Tick 실행 모델

단일 Tick 내:
  tick() 호출 → 연산 수행 → SUCCESS 또는 FAILURE 반환
  
다음 Tick:
  tick() 호출 → 완전히 새로운 실행 (이전 상태 없음)

동기 노드는 상태를 유지하지 않으므로, 매 Tick마다 독립적인 실행이 수행된다. 이전 Tick의 결과가 현재 Tick에 영향을 미치지 않는다.

2.3 대표적 동기 노드

  • ConditionNode: 조건 평가 (블랙보드 값 비교, 센서 임계값 확인)
  • SyncActionNode: 즉시 완료되는 작업 (블랙보드 값 설정, 계산 수행)

3. 비동기 노드의 Tick 처리

3.1 특성

비동기 노드는 첫 번째 Tick에서 작업을 개시하고 RUNNING을 반환한다. 후속 Tick에서는 작업의 진행 상태를 확인하여 RUNNING(계속 진행), SUCCESS(완료), FAILURE(실패)를 반환한다.

class AsyncAction : public BT::StatefulActionNode {
public:
    BT::NodeStatus onStart() override {
        // 작업 개시 (첫 Tick)
        startAsyncWork();
        return BT::NodeStatus::RUNNING;
    }

    BT::NodeStatus onRunning() override {
        // 진행 상태 확인 (후속 Tick)
        if (isWorkDone()) {
            return isSuccess() 
                ? BT::NodeStatus::SUCCESS 
                : BT::NodeStatus::FAILURE;
        }
        return BT::NodeStatus::RUNNING;
    }

    void onHalted() override {
        // 중단 처리
        cancelAsyncWork();
    }
};

3.2 Tick 실행 모델

Tick 1: onStart() 호출 → 작업 개시 → RUNNING 반환
Tick 2: onRunning() 호출 → 진행 확인 → RUNNING 반환
Tick 3: onRunning() 호출 → 완료 확인 → SUCCESS 반환

비동기 노드는 IDLE에서 RUNNING으로 전이할 때 onStart()가 호출되고, RUNNING 상태에서 재Tick될 때 onRunning()이 호출된다. 이 구분을 통해 작업 개시와 진행 상태 확인이 분리된다.

4. 핵심 차이의 종합 비교

특성동기 노드비동기 노드
반환 상태SUCCESS 또는 FAILURESUCCESS, FAILURE, 또는 RUNNING
실행 Tick 수항상 1 Tick1 Tick 이상
상태 유지없음 (무상태)있음 (RUNNING 상태 유지)
Halt 처리불필요필수 (onHalted)
구현 클래스SyncActionNode, ConditionNodeStatefulActionNode
Tick 메서드tick() 단일 메서드onStart(), onRunning(), onHalted()
외부 작업 위임없음 (인라인 실행)있음 (ROS2 액션 등)
Tick 실행 시간연산 시간에 비례상태 확인 시간에 비례 (짧음)

5. Tick 실행 시간의 차이

동기 노드의 Tick 실행 시간은 수행하는 연산의 복잡도에 직접 비례한다. 연산이 오래 걸리면 Tick 실행 시간도 길어진다.

T_{sync} = T_{computation}

비동기 노드의 Tick 실행 시간은 작업 개시(onStart()) 또는 상태 확인(onRunning())의 시간에 비례한다. 실제 작업은 외부에서 수행되므로, Tick 실행 시간은 통상적으로 짧다.

T_{async\_start} = T_{initiation} \quad \text{(작업 개시)}
T_{async\_running} = T_{status\_check} \quad \text{(상태 확인)}

6. 동기 노드를 비동기로 전환해야 하는 경우

동기 노드의 연산 시간이 Tick 주기에 비해 길어지면, Tick 오버런이 발생하여 시스템 응답성이 저하된다. 이 경우 해당 작업을 별도 스레드에서 실행하고 비동기 노드로 전환해야 한다.

판단 기준:
  T_computation > T_tick_budget × 0.5  →  비동기 노드로 전환 고려

7. 제어 노드에서의 Tick 전파 영향

동기 노드와 비동기 노드의 차이는 제어 노드의 Tick 전파에 직접적 영향을 미친다.

7.1 동기 노드만 포함된 Sequence

Sequence:
  Tick 1: Child_0(SUCCESS), Child_1(SUCCESS), Child_2(SUCCESS) → SUCCESS
  // 단일 Tick 내에서 모든 자식 완료

7.2 비동기 노드를 포함한 Sequence

Sequence:
  Tick 1: Child_0(SUCCESS), Child_1(RUNNING) → RUNNING
  Tick 2: Child_1(SUCCESS), Child_2(RUNNING) → RUNNING
  Tick 3: Child_2(SUCCESS) → SUCCESS
  // 복수 Tick에 걸쳐 실행

비동기 노드의 존재로 인해 Sequence의 완료까지 복수의 Tick이 소요되며, 각 Tick에서 제어 노드는 RUNNING을 반환하여 상위 트리에 진행 중임을 알린다.


참고 문헌

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