1293.56 동기 노드의 즉시 반환 (Success/Failure)

1293.56 동기 노드의 즉시 반환 (Success/Failure)

1. 즉시 반환의 정의

동기 노드의 즉시 반환이란, 노드가 tick() 메서드 호출 시 모든 연산을 단일 호출 내에서 완료하고 SUCCESS 또는 FAILURE를 즉시 반환하는 동작 방식이다. RUNNING 상태를 반환하지 않으므로, 노드의 실행이 단일 Tick 내에서 원자적으로 완료된다. 이는 행동 트리에서 조건 평가, 경량 계산, 블랙보드 값 설정 등 지연 없이 결과를 산출할 수 있는 작업에 적용된다(Colledanchise & Ogren, 2018).

2. 동기 노드의 Tick 처리 흐름

동기 노드의 Tick 처리는 단일 경로로 구성된다.

tick() 호출
  → 연산 수행 (블랙보드 읽기, 조건 평가, 값 계산 등)
  → SUCCESS 또는 FAILURE 반환
  → (RUNNING 반환 불가)

이 흐름에서 tick() 호출과 반환 사이에 Tick 경계가 존재하지 않는다. 호출자(부모 노드)의 관점에서 동기 노드의 tick()은 일반 함수 호출과 동일하게 동작한다.

3. 조건 노드의 즉시 반환

조건 노드(ConditionNode)는 동기 노드의 대표적 유형이다. 블랙보드 값이나 외부 상태를 확인하여 조건의 충족 여부를 즉시 판정한다.

class IsBatteryAbove : public BT::ConditionNode {
public:
    BT::NodeStatus tick() override {
        double battery, threshold;
        getInput("battery_level", battery);
        getInput("threshold", threshold);
        
        // 즉시 판정, 즉시 반환
        return (battery > threshold) 
            ? BT::NodeStatus::SUCCESS 
            : BT::NodeStatus::FAILURE;
    }
};

4. 동기 액션 노드의 즉시 반환

SyncActionNode는 경량 작업을 수행하고 즉시 결과를 반환한다.

class SetBlackboardValue : public BT::SyncActionNode {
public:
    BT::NodeStatus tick() override {
        double value;
        getInput("value", value);
        setOutput("result", value * 2.0);
        return BT::NodeStatus::SUCCESS;
    }
};
class LogMessage : public BT::SyncActionNode {
public:
    BT::NodeStatus tick() override {
        std::string msg;
        getInput("message", msg);
        RCLCPP_INFO(node_->get_logger(), "%s", msg.c_str());
        return BT::NodeStatus::SUCCESS;
    }
};

5. 즉시 반환의 제어 노드에 대한 영향

동기 노드의 즉시 반환은 제어 노드의 Tick 전파에서 중요한 함의를 가진다. 동기 자식이 즉시 반환하면, 부모 제어 노드는 같은 Tick 내에서 다음 자식으로 진행할 수 있다.

5.1 Sequence에서의 연속 진행

Sequence (단일 Tick 내):
  Child_0 (동기) → tick() → SUCCESS → 다음으로 진행
  Child_1 (동기) → tick() → SUCCESS → 다음으로 진행
  Child_2 (비동기) → tick() → RUNNING → 멈춤
  → Sequence 반환: RUNNING

동기 자식인 Child_0과 Child_1은 단일 Tick 내에서 연속적으로 실행되어 즉시 결과를 반환한다. 비동기 자식인 Child_2에 도달하면 RUNNING이 반환되어 Tick이 종료된다.

5.2 Fallback에서의 연속 시도

Fallback (단일 Tick 내):
  Child_0 (동기) → tick() → FAILURE → 다음으로 진행
  Child_1 (동기) → tick() → FAILURE → 다음으로 진행
  Child_2 (동기) → tick() → SUCCESS → 조기 종료
  → Fallback 반환: SUCCESS

6. 즉시 반환과 상태 비유지

동기 노드는 RUNNING을 반환하지 않으므로, Tick 간 상태를 유지할 필요가 없다. 매 Tick마다 완전히 독립적인 실행이 수행된다.

Tick 1: IsBatteryAbove.tick() → 블랙보드에서 값 읽기 → SUCCESS
Tick 2: IsBatteryAbove.tick() → 블랙보드에서 값 읽기 → SUCCESS
Tick 3: IsBatteryAbove.tick() → 블랙보드에서 값 읽기 → FAILURE
                                (배터리 값 변경됨)

각 Tick에서의 실행은 이전 Tick과 완전히 독립적이며, 현재 블랙보드 값에 기반하여 결과가 결정된다.

7. 즉시 반환의 실행 시간 제약

동기 노드의 tick() 실행 시간은 Tick 실행 예산의 일부를 소비한다. 동기 노드의 연산이 무거우면 Tick 오버런의 원인이 된다.

T_{tick} = \sum_{i \in \text{sync}} T_{sync_i} + T_{async\_running}

경량 조건 평가(T_{sync} < 1\text{μs})는 Tick 예산에 미미한 영향을 미치지만, 복잡한 기하학적 계산이나 대규모 데이터 처리가 동기 노드에서 수행되면 Tick 실행 시간이 크게 증가한다. 이 경우 해당 작업을 비동기 노드로 전환하여 외부 스레드에서 실행하는 것이 적절하다.

8. Halt 불필요성

동기 노드는 RUNNING 상태를 가지지 않으므로 Halt가 호출되는 상황이 발생하지 않는다. onHalted() 구현이 필요하지 않으며, 외부 자원 정리나 작업 취소가 불필요하다. 이는 동기 노드의 설계와 구현을 단순화하는 주요 이점이다.


참고 문헌

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