1293.78 Tick 단위 Halt 이벤트 로그
1. Halt 이벤트 로그의 정의
Halt 이벤트 로그란, Tick 실행 중에 노드에 대해 halt() 또는 onHalted()가 호출된 사건을 기록한 것이다. Halt 이벤트는 실행 중인 작업의 중단을 나타내며, 조기 종료, Reactive 노드의 조건 변화, 외부 트리 종료 등에 의해 발생한다. Halt 이벤트의 로깅은 작업 취소의 원인 추적, 자원 정리의 검증, 비정상적 중단의 진단에 필수적이다(Colledanchise & Ogren, 2018).
2. Halt 이벤트의 발생 시점
Halt 이벤트는 다음의 상황에서 발생한다.
| 발생 상황 | Halt 대상 | 트리거 |
|---|---|---|
| Sequence 조기 종료 | RUNNING 상태의 후속 자식 | 선행 자식 FAILURE |
| Fallback 조기 종료 | RUNNING 상태의 후속 자식 | 선행 자식 SUCCESS |
| ReactiveSequence 조건 변화 | RUNNING 상태의 액션 자식 | 조건 자식 FAILURE |
| ReactiveFallback 조건 변화 | RUNNING 상태의 액션 자식 | 상위 대안 SUCCESS |
| 데코레이터 타임아웃 | RUNNING 상태의 자식 | Timeout 초과 |
| 트리 종료 | 모든 RUNNING 노드 | haltTree() 호출 |
3. Halt 이벤트 로그의 구성 요소
struct HaltLogEntry {
int tick_id; // Tick 순번
std::chrono::steady_clock::time_point timestamp; // 시각
std::string halted_node_name; // Halt된 노드 이름
std::string halted_node_type; // 노드 유형
BT::NodeStatus status_before_halt; // Halt 전 상태 (RUNNING)
std::string trigger_node_name; // Halt를 유발한 노드
std::string trigger_reason; // Halt 원인
std::chrono::microseconds running_duration; // RUNNING 유지 시간
};
4. Halt 이벤트의 캡처
4.1 StatusChangeLogger를 통한 캡처
Halt 이벤트는 상태 전이(RUNNING → IDLE)로 나타나므로, StatusChangeLogger에서 캡처할 수 있다.
void callback(BT::Duration timestamp,
const BT::TreeNode& node,
BT::NodeStatus prev_status,
BT::NodeStatus status) override {
if (prev_status == BT::NodeStatus::RUNNING &&
status == BT::NodeStatus::IDLE) {
// Halt 이벤트 감지
HaltLogEntry entry;
entry.timestamp = std::chrono::steady_clock::now();
entry.halted_node_name = node.name();
entry.status_before_halt = prev_status;
entry.tick_id = current_tick_;
halt_log_.push_back(entry);
RCLCPP_INFO(logger_,
"[Tick %d] HALT: %s (was RUNNING)",
current_tick_, node.name().c_str());
}
}
4.2 onHalted 내부 로깅
StatefulActionNode의 onHalted() 메서드 내에서 자원 정리의 상세 내용을 기록한다.
void onHalted() override {
RCLCPP_INFO(node_->get_logger(),
"NavigateToGoal halted: canceling action goal");
if (goal_handle_) {
action_client_->async_cancel_goal(goal_handle_);
RCLCPP_INFO(node_->get_logger(),
"Goal cancel request sent for goal_id: %s",
rclcpp_action::to_string(goal_handle_->get_goal_id()).c_str());
}
}
5. Halt 전파 체인 로그
Halt가 깊이 우선 순서로 전파될 때, 전파 체인 전체를 기록하면 Halt의 영향 범위를 파악할 수 있다.
Tick #200: Halt 전파 체인
트리거: IsBatteryAbove → FAILURE (ReactiveSequence에서)
├─ Halt: NavigateSubtree (서브트리)
│ ├─ Halt: ComputePath (RUNNING → IDLE)
│ └─ Halt: FollowPath (RUNNING → IDLE)
└─ Halt 전파 완료 (2개 노드 중단)
6. Halt 빈도 분석
Halt 이벤트 로그를 집계하면 각 노드의 Halt 빈도를 분석할 수 있다.
f_{halt}(n) = \frac{N_{halt}(n)}{N_{running}(n)}
여기서 N_{halt}(n)은 노드 n이 Halt된 횟수, N_{running}(n)은 노드가 RUNNING 상태로 진입한 횟수이다. Halt 비율이 높은 노드는 작업이 빈번히 중단되는 것을 나타내며, 다음의 원인을 의심할 수 있다.
- Reactive 노드의 조건이 불안정하게 진동하는 경우
- 액션 서버가 빈번히 실패하여 재시도가 발생하는 경우
- 트리 설계에서 불필요한 작업 취소가 포함된 경우
7. Halt 로그와 자원 정리 검증
Halt 이벤트 로그와 자원 상태를 대조하여, Halt 시 자원 정리가 정상적으로 수행되었는지 검증한다.
검증 항목:
✓ ROS2 액션 목표 취소 요청 전송 확인
✓ 외부 스레드 종료 확인
✓ 소켓/파일 핸들 해제 확인
✓ 하드웨어 장치 안전 상태 전환 확인
8. 비정상 Halt 패턴의 검출
| 비정상 패턴 | 설명 | 잠재적 문제 |
|---|---|---|
| 동일 노드 연속 Halt | 매 Tick마다 Halt 발생 | 조건 진동, 히스테리시스 부재 |
| Halt 후 즉시 재시작 | RUNNING → IDLE → RUNNING | 비효율적 작업 재시작 |
| Halt 없이 IDLE 전이 | RUNNING → IDLE (Halt 미호출) | 구현 오류 |
| 긴 RUNNING 후 Halt | 수백 Tick RUNNING 후 중단 | 장시간 작업의 낭비 |
이러한 비정상 패턴의 자동 검출을 통해 트리 설계의 문제를 조기에 식별할 수 있다.
참고 문헌
- 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/