본문으로 건너뛰기
1kHz 실시간 로봇 제어 시스템 모니터링 아키텍처
임베디드/실시간

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 퍼블리싱은 개발 환경에서만 사용하고, 프로덕션에서는 필요시에만 활성화합니다.