19.3.2.3. 센서 모사(Mock-up) 데이터 생성 및 구조체 내부 필드 갱신 로직 구현

19.3.2.3. 센서 모사(Mock-up) 데이터 생성 및 구조체 내부 필드 갱신 로직 구현

구조체 메모리 힙의 더러운 바닥을 0으로 무자비하게 청소하고 코어 시스템의 가장 치명적인 타임스탬프(timestamp) 앵커 뼈대까지 무사히 타설했다면, 드디어 이 튼튼하고 텅 빈 깡통 수레에 우리가 궁극적으로 목표로 했던 진짜 통신 화물(Payload)을 정밀하게 실어 넣고 아가리를 닫을 차례이다.
현실적으로 실제 I2C/SPI 버스 물리 센서 드라이버 칩셋이 보드에 결합되어 있지 않은 현재의 SITL(Software-In-The-Loop) 가상 스케줄링 단계에서는, 수학 함수를 이용한 가상의 더미(Mock-up) 신호 생성기를 통해 센서 보드의 진동과 물리량 움직임을 폭력적으로 흉내(Simulation)내야만 한다.

1. 물리적 수학 노이즈가 첨가된 가상 센서 페이로드 타설

실제 필드 비행 환경에서 추출되는 센서 스칼라 로우(Raw) 값은 결코 교과서처럼 깔끔하게 소수점 단위로 떨어지지 않으며, 반드시 거친 고주파 노이즈(Noise)와 진동 편차가 악랄하게 섞여 들어오기 마련이다. 이를 가장 코드 효율적으로 모사하기 위해 C 표준 라이브러리 math.hsin() 함수와 스레드 루프의 순환 횟수를 수학적으로 결합하여, 마치 비행 중 보드의 온도가 천천히 변하고 가속도계 센서가 모터 진동에 떨리는 듯한 동적인 스칼라(Scalar) 부동소수점 시계열 값을 억지로 우겨넣어 창조해 낸다.

#include <math.h> // 사인파 수학 함수 호출을 위한 스탠다드 C 헤더 훅업

// 무한 루프 진입 전 가짜 센서 진동 가속을 위한 외부 위상 시드(Seed) 값
static float mock_angle = 0.0f; 

while (!thread_should_exit) {
    sensor_test_data_s sensor_data{};
    sensor_data.timestamp = hrt_absolute_time();

    // -- [코어 데이터 페이로드 주입 및 압축 해킹 단계] --
    
    // (1) 0번 추상 필드: 온도값 (20.0도 기준점에서 -5.0 ~ +5.0도 사이를 느린 사인파 패턴으로 요동치게 모사)
    sensor_data.temperature = 20.0f + 5.0f * sinf(mock_angle);
    
    // (2) 1~3번 하드웨어 배열 필드: 3축 가속도계(Accelerometer) 데이터 할당
    // (X, Y는 빠른 헤르츠로 진동하며 덜덜 떨게 만들고, Z축은 중력가속도 1G로 묵직하게 고정)
    sensor_data.acceleration[0] = 0.5f * sinf(mock_angle * 2.0f); // X축 (가로 횡방향 진동)
    sensor_data.acceleration[1] = 0.5f * cosf(mock_angle * 2.0f); // Y축 (세로 종방향 진동)
    sensor_data.acceleration[2] = 9.81f;                          // Z축 (지구를 향하는 절대 중력가속도 방어)

    mock_angle += 0.1f; // 다음 10ms 루프 사이클을 위해 수학적 위상 각도를 강제로 비틀어 갱신

2. 상태(State) 및 메타 비트마스크(Bitmask)의 절대적 타설

센서의 단순한 스칼라 진동 페이로드를 구조체에 채우는 행위는 하급 C 코더들이 뽐내는 기본기에 불과하다. 진정한 PX4 펌웨어 코어 아키텍처 관점에서 진짜 치명적인 시스템 데이터는, 이 퍼블리셔 데몬이 자신의 생존 건강 상태(Health State)와 에러율을 EKF 지휘자 시스템에 통신 프로토콜로 “어떻게 명확하게 통보하느냐“에 명운이 달려 있다. 앞서 19.3.1 루프 바깥 제어 로직에서 신중하게 구현해 두었던 상태 변수들과 하드코딩 비트마스크 덩어리를 정교한 레고 블록처럼 조립하여, 구조체의 남은 1바이트 빈 공간까지 꽉꽉 욱여넣는다.

    // (3) 상태 및 에러 카운터 레지스터 타설
    // 루프 앞단에서 물리적 방어벽으로 평가해둔 current_sensor_state(STATE_OK 등)를 강제로 쑤셔 넣음
    sensor_data.current_state = current_sensor_state; 
    sensor_data.error_count = sensor_error_acc;       // 누적된 I2C 하드웨어 에러 실패 횟수 던짐

    // (4) 데이터 유효성(Validity) 및 칩셋 커스텀 ID 강제 부여
    sensor_data.is_data_valid = true;                 // "이번 사이클의 데이터는 절대 오염되지 않았다"는 보장 각서
    sensor_data.sensor_id = 1;                        // 복수의 동일 I2C 센서 장착 시 충돌 방지 구분을 위한 고유 ID (e.g., MAG 1)

    // ... 모든 하드웨어 래핑 조립 타설 완료! 이제 orb_publish 미사일 발사 버튼 타격만 통제권에 남았다 ...
}

이 고된 데이터 타설 프로세스 단계까지 에러 없이 도달하게 되면, RAM 메모리 힙/스택 공간 안의 sensor_data 구조체 객체는 완벽한 메타 데이터로 무장한 채 시스템 미들웨어를 향해 출격만을 폭력적으로 기다리는 거대한 실탄(Payload) 로켓 텍스트 덩어리가 된다.
C++ 링커 컴파일러는 코드 최적화 레벨(-O3)에 따라 이 모든 절차적인 메모리 대입 할당 연산들을 하나로 뭉개어 단일 CPU 캐시 라인(Cache Line) 안에서 가장 미친 듯이 빠른 속도로 레지스터 쓰기 연산을 일괄적으로 수행해 버린다. 이제 당신의 손엔 무자비한 데이터 방출 폭탄의 킬 스위치(orb_publish()) 타격 권한 유일하게 단 하나만이 덩그러니 남게 되었다.