21.8.4. 제어 명령(`vehicle_command`) 발행 및 MAVLink 응답 검증

21.8.4. 제어 명령(vehicle_command) 발행 및 MAVLink 응답 검증

이제 드디어 FSM이 고도를 돌파하여 STATE_TRIGGER(투하) 상태에 진입(Entry)했다. 드론의 배때기에 매달린 서보 모터를 징- 하고 돌려서 약통의 밸브를 열어야 할 시간이다.

초보 개발자들은 이때 하드웨어 핀(PWM Output)을 직접 제어하는 더러운 코드를 작성하려 든다. 하지만 PX4 아키텍처에서는 모듈이 하드웨어를 직접 건드리는 것을 극도로 혐오한다.
모든 통신은 오직 uORB를 거쳐야 하며, 우리는 그중에서도 가장 범용적인 지시서 봉투, vehicle_command_s 토픽을 사용하여 중앙 사령부(Commander)나 액추에이터 데몬에게 “이 문을 열어라!” 라고 고상하게 명령서를 하달할 것이다.

1. vehicle_command_s: 만능 지시서 봉투

이 구조체는 단순히 드론 내부를 넘어, GCS(지상 통제소)와 통신하는 MAVLink 프로토콜의 COMMAND_LONG 메시지 규격과 1:1로 정확히 맞닿아 있는 아주 특별한 봉투다.
이 봉투 안에는 “무엇을 할 것인가(Command ID)“와 “디테일한 7개의 파라미터(Param 1~7)“가 담긴다.

#include <uORB/topics/vehicle_command.h>
#include <uORB/Publication.hpp>

// 모듈 헤더 파일에 명령어 발행(Publication) 객체 선언
uORB::Publication<vehicle_command_s> _vehicle_command_pub{ORB_ID(vehicle_command)};

2. 서보 모터 조작 명령 포장하기

페이로드 도어를 열기 위해 보통 특정 PWM 펄스(예: 2000us)를 쏴주어야 한다. 이를 위해 MAVLink 규격의 VEHICLE_CMD_DO_SET_ACTUATOR 명령어를 사용한다.

void PayloadAutoDrop::open_payload_servo() {
    // 1. 빈 지시서 봉투 하나를 꺼냄
    vehicle_command_s vcmd{};

    // 2. 이 지시서가 누구를 향한 것인지 타겟 명시 (매우 중요!)
    // 내 기체의 ID와 부품 컴포넌트 ID를 적는다.
    vcmd.target_system = _vehicle_status.system_id;       
    vcmd.target_component = _vehicle_status.component_id; 

    // 3. 내가 내릴 명령의 고유 번호 기입 (MAVLink 규격서 참고)
    vcmd.command = vehicle_command_s::VEHICLE_CMD_DO_SET_ACTUATOR;

    // 4. MAVLink param1 ~ param7 포맷팅
    // param1~3 은 Actuator 1~3의 값 (-1.0 ~ 1.0)
    // 페이로드 서보가 'AUX 1' 채널(Actuator 1)에 꽂혀있다고 가정하고, 
    // 최대치(1.0)를 주어 밸브를 활짝 연다.
    vcmd.param1 = 1.0f; // Actuator 1 Value
    vcmd.param2 = NAN;  // 안 쓰는 파라미터는 무조건 NAN (Not a Number) 처리!
    vcmd.param3 = NAN;
    vcmd.param4 = NAN;
    vcmd.param5 = NAN;
    vcmd.param6 = NAN;
    vcmd.param7 = NAN;

    // 5. 명령서를 발행함과 동시에 현재 타임스탬프를 찍는다.
    vcmd.timestamp = hrt_absolute_time();

    // 6. uORB 우체통에 던져 넣는다!
    _vehicle_command_pub.publish(vcmd);
    
    PX4_INFO("Payload Servo Openned! (Command Issued)");
}

이렇게 publish()를 날리면, 픽스호크 내부에서 px4iopwm_out 같은 하위 액추에이터 드라이버가 이 vehicle_command 토픽을 받아서 진짜 전기 신호(PWM 2000us)로 바꾸어 서보 모터를 구동시킨다.

그런데 잠깐. 내가 보낸 지시서가 중간에 유실되거나, 하위 드라이버가 너무 바빠서 명령을 씹어버리면 어떻게 될까? 모듈 개발자는 “명령 보냈으니까 알아서 문 열렸겠지?” 하고 기도만 해야 할까?

항공 시스템에서는 절대로 ’기도 메타’가 통하지 않는다. 내가 명령(vehicle_command)을 보냈다면, 반드시 상대방으로부터 “명령 잘 받았고, 문 잘 열었어. (ACK)” 라는 영수증을 돌려받아야만 안심하고 다음 FSM 상태로 넘어갈 수 있다.

이 영수증 역할을 하는 위대한 구조체, vehicle_command_ack_s를 통해 나의 명령이 완벽하게 성공했음을 검증하는 아키텍처를 21.8.4.1장에서 마저 뜯어보자.