SkipUnlessUpdated의 ���랙보드 값 변경 감지 (SkipUnlessUpdated's Blackboard Value Change Detection)

SkipUnlessUpdated의 ���랙보드 값 변경 감지 (SkipUnlessUpdated’s Blackboard Value Change Detection)

1. 개요

SkipUnlessUpdated 데코레이터의 핵심 메커니즘은 블랙보드 항목의 값 변경을 감지하는 것이다. BehaviorTree.CPP 4.x의 블랙보드는 각 항목에 수정 시퀀스 번호(sequence number)를 유지하며, SkipUnlessUpdated는 이 시퀀스 번호의 변화를 추적하여 값의 변경 여부를 판정한다.

2. 변경 감지 메커니즘

2.1 시퀀스 번호 기반 추적

블랙보드의 각 항목은 값이 수정될 때마다 시퀀스 번호가 증가한다.

set("goal", pose_A) → sequence = 1
set("goal", pose_B) → sequence = 2
set("goal", pose_B) → sequence = 3 (동일 값이라도 set이 호출되면 증가)

SkipUnlessUpdated는 마지막으로 자식을 tick했을 때의 시퀀스 번호를 기억하고, 현재 시퀀스 번호와 비교한다.

마지막 tick 시 sequence = 2
현재 sequence = 2 → 변경 없음 → skip
현재 sequence = 3 → 변경됨 → 자식 tick

2.2 값의 동일성과 변경의 구분

시퀀스 번호 기반 추적은 값의 내용이 동일하더라도 set()이 호출되면 변경으로 감지한다. 이는 값의 동일성 비교 비용을 회피하는 대신, 불필요한 재평가가 발생할 수 있다는 트레이드오프가 있다.

3. 블랙보드 항목 접근 인터페이스

BehaviorTree.CPP 4.x에서 블랙보드 항목의 타임스탬프(시퀀스 번호)에 접근하는 API:

auto entry = blackboard->getEntry("goal");
uint64_t current_seq = entry->sequence_id;

if (current_seq != last_seen_seq_)
{
    // 값이 변경됨 → 자식 tick
    last_seen_seq_ = current_seq;
    return child_node_->executeTick();
}
else
{
    // 값이 변경되지 않음 → skip
    return BT::NodeStatus::SKIPPED;
}

4. 복수 입력 포트의 변경 감지

자식 노드가 복수의 입력 포트를 가지는 경우, 각 포트에 연결된 블랙보드 항목의 시퀀스 번호를 모두 추적하여야 한다. 하나라도 변경되면 자식을 tick한다.

<SkipUnlessUpdated>
    <Action ID="ComputePath"
            start="{robot_pose}"
            goal="{target_goal}"/>
</SkipUnlessUpdated>

robot_pose 또는 target_goal 중 하나라도 변경되면 경로를 재계산한다.

5. 설계 시 고려 사항

5.1 고빈도 갱신 토픽

블랙보드 값이 매 tick마다 갱신되는 경우(센서 데이터 토픽을 블랙보드에 기록하는 경우), SkipUnlessUpdated가 매 tick마다 자식을 tick하므로 최적화 효과가 없다. 이 데코레이터는 비주기적으로 변경되는 값(목표 위치, 파라미터 등)에 적합하다.

5.2 SKIPPED 상태의 전파

BehaviorTree.CPP 4.x에서 SKIPPED 상태는 제어 노드에서 특별히 처리된다. Sequence에서 SKIPPED를 만나면 해당 자식을 건너뛰고 다음 자식으로 진행한다.

6. 참고 문헌

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

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