1293.94 Tick 메커니즘의 실시간 제약
1. 실시간 시스템과 Tick 실행
실시간 시스템(real-time system)이란, 연산의 정확성뿐만 아니라 연산이 완료되는 시간적 한계(deadline)의 준수가 시스템의 올바른 동작을 결정하는 시스템이다. 로봇 공학에서 행동 트리의 Tick은 로봇의 의사 결정을 주기적으로 수행하는 핵심 루프이므로, Tick 실행이 설정된 데드라인 내에 완료되지 않으면 제어 응답의 지연, 센서 데이터의 누락, 그리고 궁극적으로 안전 사고로 이어질 수 있다(Colledanchise & Ogren, 2018).
2. 실시간 제약의 유형
2.1 경성 실시간 제약 (Hard Real-Time)
데드라인의 위반이 시스템의 치명적 실패를 초래하는 제약이다. 산업용 로봇 팔의 충돌 회피, 자율 주행 차량의 긴급 제동 등에서 행동 트리의 Tick이 지정된 시간 내에 완료되어야 한다. 데드라인을 한 번이라도 위반하면 물리적 손상이나 인명 피해가 발생할 수 있다.
T_{tick} \leq D_{hard} \quad \forall \text{ ticks}
여기서 T_{tick}은 Tick 실행 시간, D_{hard}는 경성 데드라인이다.
연성 실시간 제약 (Soft Real-Time)
데드라인의 간헐적 위반은 허용되지만, 위반 빈도가 증가하면 시스템 성능이 저하되는 제약이다. 서비스 로봇의 네비게이션, 물류 로봇의 경로 추종 등에서 Tick 지연이 발생하면 동작이 부자연스러워지지만 즉각적인 위험은 아니다.
P(T_{tick} \leq D_{soft}) \geq p_{required}
여기서 p_{required}는 데드라인 준수율 요구 사항(예: 99%)이다.
2.2 확고한 실시간 제약 (Firm Real-Time)
데드라인을 위반한 결과는 무의미하여 폐기되지만, 시스템의 치명적 실패는 아닌 제약이다. 데드라인을 넘긴 Tick의 결과는 이미 시효가 지나 유효하지 않으므로, 해당 Tick을 건너뛰고 다음 Tick을 실행한다.
3. Tick 데드라인의 결정 요인
3.1 제어 주기와의 관계
Tick 데드라인은 행동 트리의 Tick 주기보다 짧아야 한다. Tick 주기가 T_{period}이면, Tick 실행 시간은 다음을 만족해야 한다.
T_{tick} < T_{period}
실제로는 ROS2 콜백 처리, 스레드 스케줄링 오버헤드 등을 고려하여 여유를 두어야 한다.
T_{tick} \leq \alpha \cdot T_{period}, \quad \alpha \in [0.5, 0.8]
3.2 센서 갱신 주기
행동 트리가 참조하는 센서 데이터의 갱신 주기보다 Tick 주기가 느리면, 센서 데이터의 누락이 발생한다. Tick 데드라인은 센서 갱신 주기와 동기화되어야 한다.
3.3 액추에이터 명령 주기
행동 트리가 출력하는 제어 명령의 갱신 주기가 Tick 주기에 의해 결정되므로, 액추에이터가 요구하는 최소 명령 주기를 충족하는 Tick 데드라인이 필요하다.
4. 실시간 Tick 실행의 장애 요인
4.1 운영 체제 스케줄링 지연
범용 Linux 커널은 선점형 스케줄링을 제공하지만, 실시간 보장은 제공하지 않는다. 커널 모드 실행, 인터럽트 처리, 메모리 관리 등에 의해 Tick 실행 스레드가 예측 불가능하게 지연될 수 있다.
실시간 커널 (PREEMPT_RT) 적용:
- 일반 커널: 스케줄링 지터 수 ms
- PREEMPT_RT: 스케줄링 지터 수십 μs
4.2 동적 메모리 할당
malloc/new 호출은 힙 관리자의 락과 페이지 폴트에 의해 비결정적 지연을 유발한다. Tick의 핫 경로에서 동적 할당을 제거해야 실시간 요구를 충족할 수 있다.
4.3 페이지 폴트
가상 메모리 시스템의 페이지 폴트(page fault)는 디스크 I/O를 수반하며, 밀리초 단위의 지연을 유발한다. mlockall() 시스템 콜을 통해 프로세스의 모든 페이지를 물리 메모리에 고정하여 페이지 폴트를 방지한다.
#include <sys/mman.h>
// 프로세스 시작 시 메모리 잠금
mlockall(MCL_CURRENT | MCL_FUTURE);
4.4 우선순위 역전
Tick 실행 스레드가 낮은 우선순위의 스레드와 공유 자원(mutex)을 경쟁하면, 우선순위 역전(priority inversion)이 발생할 수 있다. 우선순위 상속(priority inheritance) 뮤텍스를 사용하여 이를 방지한다.
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
pthread_mutex_init(&mutex, &attr);
4.5 ROS2 통신 지연
ROS2의 DDS 통신 계층은 네트워크 지연, 직렬화/역직렬화 비용, QoS 처리 등에 의해 비결정적 지연을 유발할 수 있다. Tick 실행 중 동기적 서비스 호출은 이 지연이 Tick 실행 시간에 직접 추가된다.
5. 실시간 Tick 실행을 위한 시스템 설정
5.1 실시간 스레드 우선순위
Tick 실행 스레드에 실시간 스케줄링 정책과 높은 우선순위를 할당한다.
#include <pthread.h>
#include <sched.h>
void setRealtimePriority(int priority) {
struct sched_param param;
param.sched_priority = priority;
int ret = pthread_setschedparam(
pthread_self(), SCHED_FIFO, ¶m);
if (ret != 0) {
RCLCPP_WARN(logger_, "Failed to set RT priority: %d", ret);
}
}
5.2 CPU 코어 격리
Tick 실행 스레드를 전용 CPU 코어에 할당(affinity)하여, 다른 프로세스에 의한 캐시 오염과 스케줄링 간섭을 방지한다.
#include <pthread.h>
void setCPUAffinity(int core_id) {
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(core_id, &cpuset);
pthread_setaffinity_np(
pthread_self(), sizeof(cpu_set_t), &cpuset);
}
5.3 PREEMPT_RT 커널
Linux의 PREEMPT_RT 패치를 적용하면 커널 내부의 비선점 구간을 최소화하여, 스레드 스케줄링의 지터를 수십 마이크로초 수준으로 감소시킬 수 있다.
6. 실시간 제약과 행동 트리 설계의 관계
실시간 제약이 엄격한 환경에서는 행동 트리의 설계 자체가 실행 시간에 영향을 미친다. 트리의 깊이, 노드의 수, 각 노드의 연산 비용, 블랙보드 접근 패턴 등을 고려하여 최악 Tick 실행 시간이 데드라인 이내에 들도록 설계해야 한다. 이를 위해 Tick 실행 시간의 상한을 정적으로 분석하거나, 프로파일링을 통해 경험적으로 검증한다.
참고 문헌
- 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/