Precondition 데코레이터의 동작 (Operation of the Precondition Decorator)

Precondition 데코레이터의 동작 (Operation of the Precondition Decorator)

1. 개요

Precondition 데코레이터는 BehaviorTree.CPP 4.x에서 도입된 스크립트 기반 조건부 실행 데코레이터로, 자식 노드를 tick하기 전에 스크립트 표현식을 평가하여 전제 조건(precondition)을 검사한다. 전제 조건이 충족되면 자식을 정상적으로 tick하고, 충족되지 않으면 자식을 tick하지 않고 지정된 상태를 반환한다. 이 데코레이터는 XML 속성 수준에서 경량 조건 검사를 수행할 수 있게 하여, 별도의 조건 노드 없이도 간단한 전제 조건을 표현할 수 있다.

2. BehaviorTree.CPP 4.x의 스크립트 속성

2.1 내장 스크립트 속성

BehaviorTree.CPP 4.x에서는 모든 노드에 스크립트 기반의 전처리·후처리 속성을 적용할 수 있다.

속성평가 시점조건 미충족 시 동작
_skipIftick 전SKIPPED 반환
_failureIftick 전FAILURE 반환
_successIftick 전SUCCESS 반환
_whiletick 전거짓이면 SKIPPED
_onSuccesstick 후 (SUCCESS 시)스크립트 실행
_onFailuretick 후 (FAILURE 시)스크립트 실행

이 속성들은 내부적으로 Precondition 데코레이터를 통해 구현된다.

3. 동작 규칙

3.1 전제 조건 평가 흐름

1. Precondition의 tick() 호출
2. 스크립트 표현식 평가
3. 조건 충족 → 자식 tick → 자식 상태 반환
4. 조건 미충족 → 자식 tick 안 함 → 지정된 상태 반환

3.2 상태 전이 규칙

조건 평가 결과동작반환 상태
참 (true)자식을 tick자식의 반환 상태
거짓 (false)자식을 tick하지 않음설정에 따라 SKIPPED, FAILURE, SUCCESS

4. 스크립트 표현식의 문법

BehaviorTree.CPP의 스크립트 엔진은 블랙보드 변수를 참조하는 간단한 표현식을 지원한다.

4.1 비교 연산

<Action ID="Navigate"
        _skipIf="goal_reached == true"/>

<Action ID="Charge"
        _failureIf="battery_level > 0.8"/>

<Action ID="EmergencyStop"
        _successIf="is_safe == true"/>

4.2 논리 연산

<Action ID="Patrol"
        _skipIf="battery_low == true || emergency == true"/>

<Action ID="Navigate"
        _failureIf="goal_x == 0.0 && goal_y == 0.0"/>

4.3 지원되는 연산자

연산자의미
==등호 비교
!=부등 비교
<, >, <=, >=대소 비교
&&논리 AND
||논리 OR
!논리 NOT

5. 구현 구조

class PreconditionNode : public BT::DecoratorNode
{
public:
    PreconditionNode(const std::string& name,
                     const BT::NodeConfiguration& config)
        : DecoratorNode(name, config)
    {}

    BT::NodeStatus tick() override
    {
        // 스크립트 표현식 평가
        if (evaluateScript())
        {
            // 조건 충족: 자식 tick
            return child_node_->executeTick();
        }
        else
        {
            // 조건 미충족: 자식 skip
            return failure_policy_;  // SKIPPED, FAILURE, SUCCESS 중 하나
        }
    }

private:
    bool evaluateScript();
    BT::NodeStatus failure_policy_;
};

6. XML에서의 사용

6.1 _skipIf 속성

<Sequence>
    <Action ID="ComputePath"
            _skipIf="path_valid == true"
            goal="{target}"/>
    <Action ID="FollowPath"/>
</Sequence>

경로가 이미 유효하면 ComputePath를 skip하고, 유효하지 않으면 경로를 재계산한다.

6.2 _failureIf 속성

<Action ID="NavigateToGoal"
        _failureIf="battery_level < 0.1"/>

배터리가 10% 미만이면 내비게이션을 시작하지 않고 FAILURE를 반환한다.

6.3 _while 속성

<Action ID="FollowPath"
        _while="is_path_valid == true"/>

경로가 유효한 동안에만 경로를 추종한다. 유효하지 않게 되면 SKIPPED를 반환한다.

7. 독립 Precondition 노드와 스크립트 속성의 관계

스크립트 속성(_skipIf, _failureIf 등)은 내부적으로 Precondition 데코레이터 노드를 자동 생성하여 적용한다. 다음 두 표현은 동치이다.

<!-- 스크립트 속성 방식 -->
<Action ID="Navigate"
        _skipIf="goal_reached == true"/>

<!-- 명시적 Precondition 데코레이터 방식 -->
<Precondition if="goal_reached == true"
              else="SKIP">
    <Action ID="Navigate"/>
</Precondition>

8. 설계 시 고려 사항

8.1 스크립트 표현식의 복잡도 제한

Precondition의 스크립트 표현식은 간단한 비교와 논리 연산에 한정하여야 한다. 복잡한 조건 평가는 전용 조건 노드를 사용하는 것이 가독성과 테스트 가능성 측면에서 유리하다.

8.2 블랙보드 의존성

스크립트 표현식에서 참조하는 블랙보드 변수가 아직 설정되지 않은 경우의 동작을 확인하여야 한다. 미설정 변수에 대한 기본 동작은 구현에 따라 다르며, 예외가 발생할 수 있다.

8.3 조건 노드와의 역할 분담

간단한 블랙보드 값 비교는 Precondition 속성으로, 센서 데이터 평가나 서비스 호출 기반 조건은 전용 조건 노드로 구현하는 것이 적절하다.

9. 참고 문헌

  • Colledanchise, M., & Ogren, P. (2018). Behavior Trees in Robotics and AI: An Introduction. CRC Press.
  • BehaviorTree.CPP 공식 문서. https://www.behaviortree.dev/

버전날짜변경 사항
v0.12026-04-05초안 작성