1293.46 부모 노드에 의한 자식 Halt
1. 부모-자식 관계에서의 Halt 책임
행동 트리(Behavior Tree)에서 자식 노드의 Halt는 부모 노드의 책임이다. 자식 노드는 스스로 Halt를 결정하지 않으며, 부모 노드가 자신의 실행 논리에 따라 자식에 Halt를 호출한다. 이 설계 원칙은 Tick의 하향 전파와 대칭적으로, Halt 역시 부모에서 자식 방향으로 전파되는 하향식 제어 구조를 형성한다(Colledanchise & Ogren, 2018).
2. Halt 호출 메서드
BehaviorTree.CPP에서 부모 노드가 자식에 Halt를 호출하는 방법은 두 가지 패턴으로 구분된다(Faconti, 2022).
2.1 haltRunningChildren()
RUNNING 상태인 모든 자식에 Halt를 호출한다. 제어 노드가 최종 상태(SUCCESS 또는 FAILURE)를 결정한 후 호출하는 것이 일반적이다.
void ControlNode::haltRunningChildren() {
for (size_t i = 0; i < children_count(); i++) {
if (children_[i]->status() == NodeStatus::RUNNING) {
children_[i]->halt();
}
}
}
2.2 haltChildrenAfter(index)
지정된 인덱스 이후의 자식 중 RUNNING 상태인 것에 Halt를 호출한다. Reactive 노드에서 현재 RUNNING인 자식 이후의 자식을 정리할 때 사용된다.
void ControlNode::haltChildrenAfter(size_t index) {
for (size_t i = index; i < children_count(); i++) {
if (children_[i]->status() == NodeStatus::RUNNING) {
children_[i]->halt();
}
}
}
3. 제어 노드별 자식 Halt 패턴
3.1 Sequence에서의 자식 Halt
Sequence 노드에서 자식이 FAILURE를 반환하면, 다른 RUNNING 상태의 자식에 Halt를 호출한다.
Sequence.tick():
...
if child_status == FAILURE:
haltRunningChildren() // 모든 RUNNING 자식 Halt
return FAILURE
표준 WithMemory Sequence에서는 한 시점에 최대 하나의 자식만 RUNNING일 수 있으므로, 실질적으로 현재 RUNNING 자식에만 Halt가 호출된다.
3.2 Fallback에서의 자식 Halt
Fallback 노드에서 자식이 SUCCESS를 반환하면, 다른 RUNNING 상태의 자식에 Halt를 호출한다.
Fallback.tick():
...
if child_status == SUCCESS:
haltRunningChildren() // 모든 RUNNING 자식 Halt
return SUCCESS
3.3 ReactiveSequence에서의 자식 Halt
ReactiveSequence에서 부모가 자식에 Halt를 호출하는 시나리오는 두 가지이다.
3.3.1 시나리오 1: 앞선 자식의 FAILURE
ReactiveSequence.tick():
Child_0.tick() → FAILURE
haltRunningChildren() // 뒤쪽 RUNNING 자식 Halt
return FAILURE
3.3.2 시나리오 2: 자식의 RUNNING
ReactiveSequence.tick():
Child_0.tick() → SUCCESS
Child_1.tick() → RUNNING
haltChildrenAfter(2) // 인덱스 2 이후 RUNNING 자식 Halt
return RUNNING
이전 Tick에서 인덱스 2 이후의 자식이 RUNNING이었을 수 있으므로, 해당 자식에 Halt를 호출하여 정리한다.
3.4 ReactiveFallback에서의 자식 Halt
ReactiveFallback에서 부모가 자식에 Halt를 호출하는 패턴은 ReactiveSequence와 대칭적이다.
3.4.1 시나리오 1: 앞선 자식의 SUCCESS
ReactiveFallback.tick():
Child_0.tick() → SUCCESS
haltRunningChildren() // 뒤쪽 RUNNING 자식 Halt
return SUCCESS
3.4.2 시나리오 2: 자식의 RUNNING
ReactiveFallback.tick():
Child_0.tick() → FAILURE
Child_1.tick() → RUNNING
haltChildrenAfter(2) // 인덱스 2 이후 RUNNING 자식 Halt
return RUNNING
3.5 Parallel에서의 자식 Halt
Parallel 노드에서 임계값에 도달하면, 나머지 RUNNING 자식에 Halt를 호출한다.
Parallel.tick():
// 모든 활성 자식 Tick 후
if success_count >= threshold:
haltRunningChildren()
return SUCCESS
if failure_count > N - threshold:
haltRunningChildren()
return FAILURE
3.6 데코레이터에서의 자식 Halt
데코레이터 노드는 단일 자식에 대해 halt_child() 메서드를 통해 Halt를 호출한다.
void DecoratorNode::halt_child() {
if (child_node_->status() == NodeStatus::RUNNING) {
child_node_->halt();
}
}
4. 구체적 실행 흐름 예시
다음과 같은 중첩 트리 구조에서 부모에 의한 자식 Halt의 전파 과정을 추적한다.
ReactiveSequence
├── IsSafe (조건)
└── Sequence
├── MoveToA (비동기)
├── PickObject (비동기)
└── MoveToB (비동기)
4.1 정상 실행 중 안전 조건 위반
Tick 5: ReactiveSequence
IsSafe.tick() → SUCCESS
Sequence.tick() → current_index=1
PickObject.tick() → RUNNING
Sequence 반환: RUNNING
ReactiveSequence 반환: RUNNING
Tick 6: ReactiveSequence
IsSafe.tick() → FAILURE (안전 조건 위반!)
haltRunningChildren() 호출:
→ Sequence.halt() 호출
→ Sequence.haltRunningChildren()
→ PickObject.halt() (RUNNING → IDLE)
→ PickObject.onHalted() (정리 작업)
→ Sequence.current_index = 0 (메모리 리셋)
→ Sequence 상태: IDLE
ReactiveSequence 반환: FAILURE
이 예시에서 ReactiveSequence가 IsSafe의 FAILURE에 의해 Sequence에 Halt를 호출하고, Sequence는 다시 자신의 RUNNING 자식인 PickObject에 Halt를 전파한다. Halt는 재귀적으로 트리 구조를 따라 전파된다.
5. Halt 호출의 선택성
부모 노드는 모든 자식에 무차별적으로 Halt를 호출하지 않는다. RUNNING 상태인 자식에만 Halt를 호출하며, IDLE, SUCCESS, FAILURE 상태인 자식에는 Halt를 호출하지 않는다. 이는 RUNNING이 아닌 노드에 Halt를 호출하는 것이 무의미하기 때문이다.
// 상태 확인 후 선택적 Halt
if (child->status() == NodeStatus::RUNNING) {
child->halt(); // RUNNING인 경우에만 Halt
}
6. 부모 Halt와 자식 상태 리셋의 관계
부모가 자식에 Halt를 호출하면, 자식은 자신의 상태를 IDLE로 리셋한다. 이 리셋은 자식의 halt() 메서드 내에서 resetStatus()를 호출하여 수행된다. 부모는 자식의 상태를 직접 변경하지 않으며, 자식이 자신의 Halt 처리 과정에서 스스로 상태를 리셋하는 것이 원칙이다.
부모: child.halt() 호출
자식: onHalted() 실행 (정리 작업)
자식: resetStatus() → IDLE
부모: child.status() 확인 → IDLE
참고 문헌
- 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/