1297.16 ConditionNode의 Halt 처리 (비활성)

1. Halt 메커니즘의 개요

행동 트리(Behavior Tree)에서 halt는 진행 중인 노드의 실행을 중단시키는 메커니즘이다. 제어 노드가 실행 흐름을 변경해야 할 때, RUNNING 상태에 있는 자식 노드에 halt() 메서드를 호출하여 안전한 중단을 요청한다. 예를 들어, ReactiveSequence의 조건 노드가 FAILURE를 반환하면, RUNNING 상태의 액션 노드에 halt가 호출되어 진행 중인 동작이 중단된다(Colledanchise & Ogren, 2018).

2. ConditionNode에서의 Halt 비활성화

BT::ConditionNode에서 halt() 메서드는 override final로 선언되어 있다:

class ConditionNode : public LeafNode
{
public:
    // ...

    virtual void halt() override final
    {
        resetStatus();
    }
};

이 선언은 두 가지 중요한 의미를 갖는다:

  1. override: 기반 클래스 TreeNode의 가상 함수 halt()를 재정의한다.
  2. final: 이 재정의가 최종적이며, ConditionNode를 상속하는 파생 클래스에서 더 이상 재정의할 수 없다.

3. Halt 비활성화의 근거

3.1 RUNNING 상태의 부재

halt 메커니즘의 존재 이유는 RUNNING 상태에 있는 노드를 안전하게 중단하기 위함이다. 조건 노드는 RUNNING 상태를 반환하지 않으므로, “진행 중인 동작“이라는 개념 자체가 존재하지 않는다. 따라서 중단해야 할 동작이 없으며, halt에서 수행할 정리(cleanup) 작업도 없다.

3.2 무상태 특성

조건 노드는 tick 간에 내부 상태를 유지하지 않는 무상태(stateless) 노드로 설계된다. halt 시 복원해야 할 상태가 없으므로, 노드 상태를 IDLE로 초기화하는 resetStatus() 호출만으로 충분하다.

3.3 자원 해제의 불필요성

조건 노드는 tick 내에서 자원을 할당하고 즉시 해제하거나, 아예 자원을 할당하지 않는다. 파일 핸들, 네트워크 연결, 비동기 요청 등 halt 시 해제해야 할 장기 자원을 보유하지 않는다.

4. resetStatus()의 동작

halt() 메서드 내에서 호출되는 resetStatus()는 노드의 상태를 NodeStatus::IDLE로 설정하는 메서드이다. IDLE 상태는 노드가 현재 실행 중이 아니며, 다음 tick에서 새롭게 시작될 준비가 되었음을 나타낸다.

void TreeNode::resetStatus()
{
    NodeStatus prev_status;
    {
        std::unique_lock<std::mutex> lock(state_mutex_);
        prev_status = status_;
        status_ = NodeStatus::IDLE;
    }
    if (prev_status != NodeStatus::IDLE)
    {
        // 상태 변경 콜백 호출
        state_change_signal_.notify(prev_status, NodeStatus::IDLE);
    }
}

5. Halt 비활성화의 설계적 효과

5.1 컴파일 시점 오류 검출

개발자가 조건 노드에서 halt()를 재정의하려고 시도하면, 컴파일 시점에 오류가 발생한다:

class MyCondition : public BT::ConditionNode
{
    void halt() override  // 컴파일 오류: cannot override 'final' function
    {
        cleanup_resources();
        resetStatus();
    }
};

이 오류는 개발자에게 설계 원칙의 위반을 즉시 알려준다. 조건 노드에서 halt 정리 로직이 필요하다면, 해당 기능이 조건 노드가 아닌 액션 노드로 구현되어야 함을 시사한다.

5.2 일관된 halt 동작 보장

모든 조건 노드가 동일한 halt 동작(resetStatus())을 수행하므로, 트리 실행 엔진은 조건 노드의 halt 동작을 예측할 수 있다. 이는 트리의 상태 관리 복잡도를 감소시킨다.

6. Halt가 호출되는 상황

조건 노드에서 halt가 호출되는 상황은 제한적이다. 조건 노드는 RUNNING을 반환하지 않으므로, RUNNING 노드를 중단하기 위한 halt 호출은 발생하지 않는다. 그러나 다음의 상황에서 halt가 호출될 수 있다:

  1. 트리 전체 중단: BT::Tree::haltTree() 호출 시 모든 노드에 halt가 전파된다.
  2. 서브트리 교체: 동적 트리 전환 시 기존 서브트리의 모든 노드에 halt가 호출된다.
  3. 트리 재시작: 트리 실행을 처음부터 재시작할 때 모든 노드의 상태가 초기화된다.

이러한 상황에서 조건 노드의 halt는 단순히 상태를 IDLE로 초기화하여, 다음 실행 시 깨끗한 상태에서 시작할 수 있도록 한다.

7. 액션 노드의 halt와의 대비

액션 노드에서는 halt가 적극적으로 활용된다. RUNNING 상태의 액션 노드가 halt될 때, 개발자가 구현한 정리 로직이 실행된다:

// 액션 노드의 halt 구현 예시
class NavigateToGoal : public BT::StatefulActionNode
{
    void onHalted() override
    {
        // 내비게이션 취소
        navigation_client_->async_cancel_all_goals();
        // 속도 명령 영점화
        publishZeroVelocity();
        // 자원 해제
        RCLCPP_INFO(logger_, "Navigation halted safely");
    }
};

조건 노드에서는 이러한 정리 로직이 필요하지 않으며, final 선언에 의해 구현 자체가 불가능하다.

8. 캐싱과 halt의 관계

조건 노드에서 캐싱을 사용하는 경우, halt 시 캐시가 resetStatus()에 의해 자동으로 무효화되지 않는다. 캐시의 관리는 tick() 메서드 내에서 자체적으로 처리해야 한다. halt 후 다음 tick에서 캐시가 여전히 유효한지를 확인하는 로직을 포함하는 것이 바람직하다.

9. 참고 문헌

  • Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
  • Faconti, D., & Colledanchise, M. (2022). BehaviorTree.CPP Documentation. https://www.behaviortree.dev/

version: 0.1.0