1293.44 Tick 실행 시 Halt 메커니즘

1. Halt의 정의

Halt는 행동 트리(Behavior Tree)에서 RUNNING 상태인 노드에 중단을 요청하는 메커니즘이다. Tick이 실행을 개시하는 신호라면, Halt는 실행을 중단하는 신호이다. Halt를 수신한 노드는 진행 중인 작업을 정리하고, 자신의 상태를 IDLE로 리셋하며, 자식 노드가 있는 경우 자식에도 Halt를 전파한다(Colledanchise & Ogren, 2018).

2. Halt의 역할

Halt 메커니즘은 행동 트리의 안전하고 효율적인 동작을 위해 다음과 같은 역할을 수행한다.

  1. 자원 해제: RUNNING 중인 노드가 보유한 외부 자원(ROS2 액션 목표, 파일 핸들, 네트워크 연결 등)을 정리한다.
  2. 작업 취소: 외부 시스템에 위임된 작업(네비게이션 목표, 매니퓰레이션 명령 등)을 취소한다.
  3. 상태 리셋: 노드의 내부 상태를 초기(IDLE) 상태로 복원하여, 다음 Tick에서 깨끗한 상태에서 시작할 수 있도록 한다.
  4. 일관성 보장: 트리의 상태가 항상 일관성을 유지하도록 보장한다.

3. Halt의 호출 주체

Halt는 다음과 같은 주체에 의해 호출된다.

3.1 부모 노드에 의한 Halt

제어 노드가 자신의 실행 논리에 따라 자식에 Halt를 호출하는 경우이다. 이는 Halt의 가장 일반적인 발생 원인이다.

Sequence: 자식이 FAILURE 반환 시, 다른 RUNNING 자식에 Halt
Fallback: 자식이 SUCCESS 반환 시, 다른 RUNNING 자식에 Halt
Parallel: 임계값 도달 시, 나머지 RUNNING 자식에 Halt
Reactive: 조건 변화 시, RUNNING 자식에 Halt

3.2 트리 외부에 의한 Halt

트리의 실행을 완전히 중단해야 하는 경우, 루트 노드에 대해 Halt가 호출된다. 이는 시스템 종료, 긴급 정지, 트리 전환 등의 상황에서 발생한다.

// 트리 실행 중단
tree.haltTree();

4. Halt의 전파 구조

Halt는 Tick과 마찬가지로 트리 구조를 따라 전파된다. 부모 노드가 Halt를 수신하면, RUNNING 상태인 모든 자식에 Halt를 전파한 후 자신의 상태를 리셋한다.

function Node.halt():
    if this is ControlNode or DecoratorNode:
        for each child in children:
            if child.status() == RUNNING:
                child.halt()
    
    onHalted()          // 노드별 정리 작업
    setStatus(IDLE)     // 상태 리셋

4.1 전파 예시

ReactiveSequence (RUNNING)
├── IsBatteryOk (SUCCESS)         ← Halt 불필요 (RUNNING 아님)
├── IsPathClear (SUCCESS)         ← Halt 불필요 (RUNNING 아님)
└── Navigate (RUNNING)            ← Halt 전파
    └── (외부 ROS2 액션 취소)

ReactiveSequence에 Halt가 호출되면, RUNNING 상태인 Navigate에만 Halt가 전파된다. IsBatteryOk와 IsPathClear는 RUNNING 상태가 아니므로 Halt가 전파되지 않는다.

5. BehaviorTree.CPP에서의 Halt 구현

BehaviorTree.CPP v4에서 Halt는 노드 유형에 따라 다른 방식으로 구현된다(Faconti, 2022).

5.1 StatefulActionNode의 Halt

StatefulActionNodeonHalted() 가상 메서드를 통해 Halt 시 정리 작업을 수행한다.

class NavigateAction : public BT::StatefulActionNode {
public:
    BT::NodeStatus onStart() override {
        nav_client_->send_goal(goal_);
        return BT::NodeStatus::RUNNING;
    }

    BT::NodeStatus onRunning() override {
        if (nav_client_->is_goal_done()) {
            return nav_client_->is_success() 
                ? BT::NodeStatus::SUCCESS 
                : BT::NodeStatus::FAILURE;
        }
        return BT::NodeStatus::RUNNING;
    }

    void onHalted() override {
        nav_client_->cancel_goal();    // 네비게이션 목표 취소
    }
};

5.2 ControlNode의 Halt

제어 노드의 Halt는 자식에 대한 Halt 전파와 내부 상태 리셋을 수행한다.

void ControlNode::halt() {
    // 모든 RUNNING 자식에 Halt 전파
    for (auto& child : children_nodes_) {
        if (child->status() == NodeStatus::RUNNING) {
            child->halt();
        }
    }
    resetStatus();  // 자신의 상태를 IDLE로 리셋
}

5.3 DecoratorNode의 Halt

데코레이터 노드의 Halt는 단일 자식에 대한 Halt 전파와 내부 상태(카운터, 타이머 등) 리셋을 수행한다.

void DecoratorNode::halt() {
    halt_child();    // 자식에 Halt 전파
    resetStatus();   // 자신의 상태 리셋
}

6. Halt와 상태 전이

Halt 호출 시 노드의 상태 전이는 다음과 같다.

RUNNING → (halt() 호출) → IDLE

IDLE 상태에서의 다음 tick() 호출:
  → StatefulActionNode: onStart() 호출 (새로 시작)
  → SyncActionNode: tick() 호출 (매번 새 실행)

Halt에 의해 IDLE로 전이된 노드가 다시 Tick을 수신하면, 이전 실행의 연장이 아닌 새로운 실행이 시작된다. StatefulActionNode의 경우 onStart()가 호출되어 작업이 처음부터 시작된다.

7. Halt 발생 시점과 Tick 실행의 관계

Halt는 Tick 실행 과정에서 동기적으로 발생한다. 제어 노드가 자식의 반환 상태를 평가한 후, 특정 조건이 충족되면 다른 자식에 Halt를 호출한다. 이 과정은 현재 Tick 내에서 완료된다.

Tick N 실행 과정:
  1. ReactiveSequence.tick() 시작
  2. Child_0.tick() → FAILURE (조건 위반)
  3. haltRunningChildren() 호출
     3a. Child_2.halt() 호출     (RUNNING이었던 자식)
     3b. Child_2.onHalted() 실행 (정리 작업)
     3c. Child_2 상태: IDLE
  4. ReactiveSequence 반환: FAILURE

모든 Halt 처리는 단일 Tick 내에서 동기적으로 완료되며, 비동기적 Halt 처리는 행동 트리의 표준 실행 모델에서 지원되지 않는다.

8. Halt와 Tick의 상호 배타성

Halt와 Tick은 동일 노드에 대해 상호 배타적으로 호출된다. 동일한 Tick 주기 내에서 한 노드에 Tick과 Halt가 동시에 호출되지 않는다. 노드는 Tick을 수신하여 실행되거나, Halt를 수신하여 중단되거나, 둘 다 수신하지 않거나(건너뛰어지거나) 세 가지 경우 중 하나에 해당한다.


참고 문헌

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