28.3.4.1. trajectory_setpoint.msg 메시지 생성 및 패킹(Packing) 아키텍처
FlightTask의 모든 자식 클래스들이 구사하는 화려한 비행 비선형 로직들은 최종적으로 0과 1로 이루어진 바이너리 데이터 뭉치로 변환되어 uORB 버스에 실려야 한다. 이 변환의 종착역이자 표준 규격 포맷이 바로 trajectory_setpoint.msg 메시지다.
1. 메시지 내부 구조: 4차원 운동학 상태 공간
이 메시지는 단순한 GPS 좌표 하나를 전달하는 수준이 아니다. 뉴턴 역학의 미분 단계를 모두 포괄하는 기체 동역학의 종합 선물 세트다.
// trajectory_setpoint.msg 의 핵심 구조 (의사 코드)
uint64 timestamp // 메시지 발행 마이크로초 타임스탬프
float32[3] position // 목표 절대 위치 (Local NED, 미터 단위)
float32[3] velocity // 목표 속도 (m/s)
float32[3] acceleration// 목표 가속도 (m/s^2)
float32[3] jerk // 목표 가속도 변화율 (m/s^3)
float32 yaw // 목표 요 비행 각도 (라디안)
float32 yawspeed // 목표 요 각속도 (rad/s)
이처럼 위치부터 저크(Jerk)까지 아우르는 촘촘한 구조를 가진 이유는, 최신 PX4 제어기(Controller) 코어인 mc_pos_control 내부 필터들이 단일 목표값(예: 위치)만 매끄럽게 따라가는 것이 아니라, 전체 피드포워드(Feedforward) 지향성 제어를 수행하기 위해 미분값들을 모두 요구하기 때문이다.
2. 생성 지점: FlightTask 멤버 변수 _trajectory_setpoint
이 메시지는 갑자기 하늘에서 뚝 떨어지는 것이 아니라, FlightTask 기저 클래스 내부에 선언된 vehicle_local_position_setpoint_s _trajectory_setpoint; 라는 전용 버퍼를 통해 빚어진다. (최신 PX4 버전에서는 메시지 이름과 C++ 구조체 이름이 trajectory_setpoint로 통일되는 추세다).
새로운 update() 루프가 시작될 때마다, 기저 클래스의 템플릿 메서드는 이 버퍼 안의 모든 숫자 배열을 NAN (Not a Number, 유효하지 않은 숫자)으로 완전히 초기화해 버린다(Wipe-out). 이는 어설프게 지난 루프의 과거 값이 남아있어 제어기가 오작동하는 것을 원천 차단하기 위함이다.
이후 각각의 자식 태스크가 자신의 능력이 닿는 데까지 버퍼의 빈칸을 채운다. 어떤 태스크는 속도(velocity)만 채우고, 어떤 똑똑한 태스크는 저크(jerk)까지 세밀하게 깎아서 채워 넣는다.
3. 물리적 파라미터 제약(Constraint) 패킹 방어벽
가장 중요한 아키텍처적 방어선은, 이 버퍼가 실제 uORB로 퍼블리싱되기 직전 **물리적 파라미터 제약 검사(Constraint Checking)**를 거친다는 점이다.
- 만약 어떤 실험적인 커스텀 비행 모드가 버그를 일으켜
velocity[2](하강 속도)를10m/s로 막무가내로 채워 넣었다고 가정해 보자. - 패킹 매니저는 이 값이 기압계나 모터 스러스트 동역학 상 너무 가파르다고 판단되면, 시스템 파라미터
MPC_Z_VEL_MAX_DN(최대 하강 허용 속도, 예:3.0 m/s) 제한(Slew-rate limit)에 걸리게 하여 즉각 강제로3.0으로 잘라내버린다(Clipping).
즉, 이 패킹 아키텍처는 제어기에게 던지는 지시서의 규격을 맞추는 ‘포장지’ 역할뿐만 아니라, 미쳐 날뛰는 비행 모드의 수학적 버그가 기체를 수직 추락으로 이끌지 못하도록 막아주는 마지막 안전망(Final Safety Net) 역할도 겸비하고 있다.