Skip to main content
1kHz 실시간 로봇 제어 시스템 모니터링 아키텍처
Robotics

1kHz 실시간 로봇 제어 시스템 모니터링 아키텍처

EtherCAT 기반 1kHz 실시간 제어 루프의 성능 데이터를 안전하게 수집, 저장, 시각화하는 모니터링 아키텍처를 설계합니다. Lock-free SPSC Queue와 ROS2 토픽 계층화로 RT 결정성을 유지하면서 디버깅 데이터를 확보합니다.

WRWIM Robotics Team
·
roboticsreal-timemonitoringros2ethercatlock-free

1kHz 실시간 로봇 제어 시스템 모니터링 아키텍처

1kHz 실시간 제어 루프에서 성능 데이터를 수집하려면 딜레마에 직면합니다:

RT 루프 요구사항모니터링 요구사항
결정론적 실행데이터 저장 (메모리/디스크 I/O)
메모리 할당 금지네트워크 전송 (ROS2 퍼블리싱)
블로킹 호출 금지통계 계산
예외 처리 금지시각화

이 글에서는 RT 결정성을 유지하면서 고해상도 성능 데이터를 수집하는 모니터링 아키텍처를 설계합니다.

아키텍처 개요

핵심 패턴: RT/Non-RT Producer-Consumer

  • Producer: RT 스레드가 Lock-free 큐에 데이터 푸시 (블로킹 없음)
  • Consumer: Non-RT 스레드가 큐에서 폴링하여 ROS2 토픽 퍼블리시

왜 스레드 분리인가? (프로세스 분리 대신)

측면스레드 분리프로세스 분리
메모리 공유직접 힙 메모리 접근IPC 필요
레이턴시마이크로초 수준IPC 오버헤드 추가
수명 관리단일 프로세스다중 프로세스

데이터 구조

RtSample (216 bytes)

매 1ms 주기의 완전한 RT 사이클 데이터:

카테고리데이터바이트용도
타이밍monotonic_ns, sequence16시퀀스 추적
루프 성능loop_exec_us, loop_period_us, loop_jitter_us, deadline_miss17RT 성능 분석
관절 상태6축 actual/cmd (position, velocity, torque)144제어 품질 평가
드라이브 상태CiA 402 status_word, control_word, op_mode30서보 진단
필드버스wkc, wkc_mismatch, link_error4통신 안정성

제약조건: Lock-free 큐 연산을 위해 trivially_copyable이어야 합니다.

Event (64 bytes, Cache-line 정렬)

이벤트 기반 알림용 구조체:

struct alignas(64) Event {
// 분류 (4 bytes)
EventType type;
uint8_t source_id;
EventSeverity severity;
uint8_t joint_id;

// 타이밍 (24 bytes)
uint64_t monotonic_ns;
uint64_t event_sequence;
uint64_t ref_sample_seq;

// 데이터 (24 bytes)
int32_t error_code;
uint8_t extra_len;
uint8_t extra[21];

// 수치 (4 bytes)
float value;

// 패딩 (8 bytes) - 64바이트 정렬
};

Lock-Free SPSC Queue

구현 선택: rigtorp::SPSCQueue

  • Wait-free: 64비트 Linux에서 Producer가 최대 2개 atomic load만 수행
  • False sharing 방지: 64바이트 캐시 라인 정렬
// 캐시 라인 정렬로 False Sharing 방지
static constexpr size_t kCacheLineSize = 64;

alignas(kCacheLineSize) std::atomic<size_t> writeIdx_ = {0}; // Producer만 쓰기
alignas(kCacheLineSize) size_t readIdxCache_ = 0; // Producer 로컬 캐시
alignas(kCacheLineSize) std::atomic<size_t> readIdx_ = {0}; // Consumer만 쓰기
alignas(kCacheLineSize) size_t writeIdxCache_ = 0; // Consumer 로컬 캐시

성능 벤치마크 (100,000 iterations, Release -O2)

연산평균P99비고
RtSample 생성 + 큐 푸시0.3 µs0.7 µs216B 구조체
Event 생성 + 큐 푸시~0.1 µs0.3 µs64B 구조체
메모리 사용량 (큐)1.8 MB-8192 samples + 512 events

총 모니터링 오버헤드: 1ms 주기의 < 0.05%

ROS2 토픽 설계 (3-Tier)

토픽주파수QoS용도
/rt_raw1kHzbest_effort, depth=200전체 기록, 사후 분석
/rt_events이벤트 발생 시reliable + transient_local, depth=50이벤트 알림
/rt_monitor_stats10Hzreliable, depth=20실시간 헬스 대시보드

Decimation (1kHz → 10Hz)

// /rt_raw는 매 샘플 퍼블리시 (1kHz)
rt_raw_pub_->publish(to_rt_raw(sample, now));
sample_count_++;

// /rt_monitor_stats는 100:1 데시메이션 (10Hz)
if (sample_count_ % 100 == 0) {
publish_stats();
}

Edge Detection (이벤트 중복 방지)

// Rising edge 검출: current=true && previous=false일 때만 이벤트 발생
const bool faulted = servo.faulted;
if (faulted && !prev_faulted_) {
emit(EventType::SERVO_FAULT, ...);
}
prev_faulted_ = faulted;

Cooldown 메커니즘 (이벤트 폭주 방지)

데드라인 미스 같은 연속 발생 이벤트는 짧은 시간에 수천 개가 발생할 수 있습니다. 이를 방지하기 위해 100ms 쿨다운을 적용합니다:

// 같은 타입의 이벤트는 100ms 이내 재발생 시 무시
constexpr auto kEventCooldown = std::chrono::milliseconds(100);

if (now - last_event_time_[type] > kEventCooldown) {
emit(type, ...);
last_event_time_[type] = now;
}

저장 및 시각화

MCAP 포맷

  • PlotJuggler 네이티브 지원
  • 효율적인 시간 기반 인덱싱
  • 압축 옵션 (zstd, lz4)
rosbag2 QoS 호환성 주의

best_effort QoS로 퍼블리시되는 /rt_raw 토픽을 녹화할 때, rosbag2의 기본 QoS(reliable)와 충돌할 수 있습니다. QoS override 파일을 사용하세요:

# qos_override.yaml
/rt_raw:
reliability: best_effort
history: keep_last
depth: 200
ros2 bag record /rt_raw /rt_events --qos-profile-overrides-path qos_override.yaml

저장 용량 계산

토픽계산시간당 저장량
/rt_raw1kHz × ~250B × 3600s~1.0 GB
/rt_events이벤트 빈도에 따라 가변10-50 MB
/rt_monitor_stats10Hz × 80B × 3600s~3 MB
총계~1.0-1.1 GB

Rolling Retention (외부 스크립트)

무한 운영을 위한 2단계 정리 정책:

# 시간 기반: 60분 이상 된 파일 삭제
cleanup_old_files() {
find "$BAG_DIR" -name "*.mcap" -mmin +"$RETENTION_MIN" -delete
}

# 용량 기반: 디스크 사용량 70% 초과 시 FIFO 삭제
cleanup_disk_space() {
# 가장 오래된 파일부터 삭제
}

PlotJuggler 설정

PlotJuggler 모니터링 화면

PlotJuggler로 6축 관절의 actual_pos vs cmd_pos를 실시간 시각화

스트리밍 모드 설정:

  • Mode: ROS2 Topic Subscriber
  • Time Window: 180초 (3분 롤링)
  • Max Points: 20,000
uint64 필드 제외

monotonic_ns, sequence 등 uint64 필드는 PlotJuggler에서 truncation 에러가 발생할 수 있습니다. 이 필드들은 시각화에서 제외하세요.

모니터링 헬스 메트릭

자기 모니터링

필드의미경고 임계값
rt_queue_fill_pctSPSC 큐 사용률> 70%
rt_overflow_delta큐 오버플로우 횟수> 0
publisher_lag_msRT → Non-RT 전파 지연> 50ms
seq_gap_count_delta손실된 샘플 수> 0

운영 임계값

메트릭정상경고위험
rt_queue_fill_pct< 50%> 70%> 90%
publisher_lag_ms< 10ms> 50ms> 100ms
loop_jitter_us (P99)< 50µs> 100µs> 200µs
seq_gap_count0> 0-

운영 권장사항

개발/디버깅 용도

이 모니터링 시스템은 개발 및 디버깅 목적으로 설계되었습니다.

상황권장
개발 환경PlotJuggler 실시간 시각화 활성화
프로덕션1kHz 토픽 퍼블리싱 비활성화 또는 필요시만 활성화
문제 발생 시모니터링 활성화하여 근본 원인 분석

주의: PlotJuggler 실시간 시각화는 CPU 자원을 상당히 소모합니다. 1kHz 토픽 퍼블리싱도 시스템 부하를 유발할 수 있습니다.

핵심 정리

  1. RT/Non-RT 분리: Lock-free SPSC Queue로 RT 스레드의 결정성을 유지하면서 데이터를 Non-RT 스레드로 전달합니다.

  2. 3-Tier 토픽 설계: 목적별로 QoS를 최적화합니다.

    • /rt_raw (1kHz): 전체 기록용
    • /rt_events: 이벤트 알림용
    • /rt_monitor_stats (10Hz): 대시보드용
  3. Lock-free 큐 성능: RtSample 푸시에 0.3µs, 1ms 주기의 0.05% 미만 오버헤드.

  4. MCAP Rolling Retention: 시간/용량 기반 외부 스크립트로 무한 운영 지원.

  5. 자기 모니터링: 큐 사용률, 지연, 손실 샘플을 추적하여 모니터링 시스템 자체의 건강 상태를 확인합니다.

  6. 개발용 도구: PlotJuggler와 1kHz 퍼블리싱은 개발 환경에서만 사용하고, 프로덕션에서는 필요시에만 활성화합니다.