[PX4 ROS 2 Programming] 6편: 최신/실험적 기능 (Interface Library와 Translation Node)
안녕하세요! 자율 비행 로봇 시스템의 최전선에서 밤낮없이 연구에 매진하고 계신 대학생 및 연구원 여러분. 드디어 기나긴 블로그 연재의 마지막, 6편에 도착했습니다.
지난 1편부터 5편까지 우리는 uXRCE-DDS 통신 환경 구축부터 시작해, QoS와 좌표계의 개념을 잡고, 기초 노드 작성, Offboard 제어를 거쳐, 다중 기체(Swarm) 시뮬레이션과 Service 기반의 견고한 통신 기법까지 숨 가쁘게 달려왔습니다. 이제 여러분은 ROS 2와 PX4를 연동하는 데 있어 훌륭한 전문가 수준의 기본기를 갖추셨습니다.
하지만 오픈소스의 세계는 지금 이 순간에도 눈부시게 발전하고 있습니다. 이번 마지막 편에서는 여러분의 연구 개발 속도를 비약적으로 끌어올려 줄 최신 PX4 버전(v1.15 및 v1.16)의 두 가지 강력한 실험적(Experimental) 기능을 소개해 드리려 합니다. 바로 복잡한 제어를 추상화해 주는 PX4 ROS 2 Interface Library와 버전을 뛰어넘는 통신을 가능케 하는 **Translation Node(메시지 변환 노드)**입니다.
1. 개발의 패러다임을 바꾼다: PX4 ROS 2 Interface Library (v1.15~)
연구실에서 드론을 개발하다 보면 흔히 이런 한계에 부딪힙니다. “단순히 Offboard 모드로 좌표만 주는 게 아니라, 내가 논문에서 제안한 새로운 제어기(Controller)를 아예 비행 모드(Flight Mode)로 만들고 싶은데?” 혹은 “Visual Odometry(VIO)나 SLAM 위치 데이터를 PX4에 주입하고 싶은데 코드 짜기가 너무 까다롭네…”
과거에는 이를 해결하기 위해 PX4 펌웨어 C++ 코드를 직접 뜯어고쳐야 했습니다. 이는 ROS 2 생태계에 익숙한 연구원들에게는 매우 고통스러운 작업이었습니다.
하지만 PX4 v1.15부터 도입된 PX4 ROS 2 Interface Library를 사용하면, ROS 2 환경 안에서 이 모든 것을 아주 우아하고 간편하게 처리할 수 있습니다. 이 라이브러리는 ROS 2에서 PX4와 상호작용하는 복잡한 과정을 고도로 추상화한 C++ 라이브러리(Python 바인딩 지원)입니다.

🌟 라이브러리가 제공하는 3대 핵심 인터페이스
- Control Interface (제어 인터페이스): 이 라이브러리의 꽃입니다. 개발자가 펌웨어를 수정하지 않고도 ROS 2 내부에서 동적으로 완전히 새로운 비행 모드를 생성하고 등록할 수 있게 해줍니다. 고수준의 경로 탐색(Navigation) 작업부터, 모터와 액추에이터를 직접 제어하는 저수준(Direct Actuator) 제어까지 다양한 Setpoint를 쉽게 전송할 수 있는 클래스들을 제공합니다.
- Navigation Interface (내비게이션 인터페이스): VIO, SLAM, 외부 모션 캡처(OptiTrack 등) 시스템에서 얻은 기체의 위치 추정 데이터를 ROS 2에서 PX4로 매우 손쉽게 전송할 수 있도록 돕습니다.
- Waypoint Missions (경유지 임무): 기존에는 지상 통제국(QGC)에서 MAVLink를 통해 임무를 올려야 했지만, 이제는 ROS 2 내부에서 경유지 임무를 생성하고 완전히 제어할 수 있습니다.
🚀 설치 및 사용 준비
사용법도 매우 간단합니다. 기존 ROS 2 작업 공간(Workspace)의 src 폴더에 라이브러리를 클론하고 빌드하기만 하면 됩니다.
# ROS 2 워크스페이스의 src 폴더로 이동
cd ~/ros2_ws/src
# 라이브러리 클론 (서브모듈 포함 필수!)
git clone --recursive https://github.com/Auterion/px4-ros2-interface-lib
# 워크스페이스 빌드
cd ~/ros2_ws
colcon build
source install/setup.bash
(주의: 이 기능은 아직 실험적(Experimental) 단계이므로, 향후 API가 변경될 수 있으며 PX4 및 px4_msgs의 최신 main 브랜치와 함께 사용하는 것을 권장합니다.)
2. 버전 불일치의 악몽에서 해방: Translation Node (v1.16~)
대학원 연구실에서 가장 많이 들리는 비명(?) 중 하나는 바로 이것입니다. “어제까지 잘 되던 코드가 PX4 버전을 올렸더니 통신이 다 끊겼어요!”
ROS 2와 PX4는 uXRCE-DDS를 통해 통신할 때 메시지 정의 파일(.msg)을 공유합니다. 만약 PX4가 업데이트되면서 메시지에 필드가 하나라도 추가되거나 삭제되면, 기존에 컴파일해 두었던 ROS 2 노드는 이 메시지를 해석하지 못해 통신이 완전히 단절됩니다. 결국 ROS 2 애플리케이션을 새로운 메시지에 맞춰 전체를 다시 뜯어고치고 빌드해야만 했습니다.
이러한 문제를 영구적으로 해결하기 위해 PX4 v1.16부터 도입된 혁신적인 기능이 바로 **Message Translation Node (메시지 변환 노드)**입니다.

🛠️ Translation Node의 원리와 기능
이 노드는 uXRCE-DDS 브릿지와 ROS 2 애플리케이션 사이에서 DDS 데이터 공간을 동적으로 감시합니다. 만약 PX4는 최신 버전(예: v3)의 메시지를 쏘고 있는데, 여러분이 만든 ROS 2 앱은 구형 버전(예: v1)을 기다리고 있다면? Translation Node가 중간에서 이 둘 사이의 메시지를 실시간으로 번역(변환)하여 서로가 원하는 버전으로 호환시켜 줍니다.
이를 위해 시스템은 토픽 이름 뒤에 버전을 명시하는 접미사 규칙(<topic_name>_v<version>)을 도입했습니다. 예를 들어 VehicleAttitude 토픽의 버전이 3이라면, 실제 네트워크에 흘러다니는 토픽 이름은 /fmu/out/vehicle_attitude_v3가 됩니다.
💻 실전 적용: 버전에 구애받지 않는 C++ 노드 작성법
그렇다면 우리는 노드를 짤 때 매번 버전을 확인해서 _v3 같은 숫자를 하드코딩해야 할까요? 전혀 그렇지 않습니다! 메시지 헤더 파일에서 자동으로 버전을 추론해 주는 템플릿 함수를 사용하면, 버전이 업데이트되더라도 코드를 한 줄도 수정할 필요가 없는 우아한 프로그램을 만들 수 있습니다.
아래는 버전을 자동으로 인식하여 토픽 이름을 생성하는 똑똑한 C++ Publisher & Subscriber 예제 코드입니다.
#include <string>
#include <rclcpp/rclcpp.hpp>
#include <px4_msgs/msg/vehicle_command.hpp>
#include <px4_msgs/msg/vehicle_attitude.hpp>
// 핵심!: 메시지 정의에서 버전을 직접 추론하여 접미사(_vX)를 만들어주는 템플릿 함수
template <typename T>
std::string getMessageNameVersion() {
// 버전이 0이면 (버전 관리가 안 되는 구형 메시지면) 빈 문자열 반환
if (T::MESSAGE_VERSION == 0) return "";
// 버전이 존재하면 "_v" 뒤에 숫자를 붙여 반환 (예: "_v3")
return "_v" + std::to_string(T::MESSAGE_VERSION);
}
class VersionTolerantNode : public rclcpp::Node
{
public:
VersionTolerantNode() : Node("version_tolerant_node")
{
// 1. 템플릿 함수를 사용하여 자동으로 올바른 토픽 이름 생성
const std::string sub_topic = "/fmu/out/vehicle_attitude" + getMessageNameVersion<px4_msgs::msg::VehicleAttitude>();
const std::string pub_topic = "/fmu/in/vehicle_command" + getMessageNameVersion<px4_msgs::msg::VehicleCommand>();
// 출력으로 어떤 토픽 이름이 생성되었는지 확인해 봅니다.
RCLCPP_INFO(this->get_logger(), "구독 토픽: %s", sub_topic.c_str());
RCLCPP_INFO(this->get_logger(), "발행 토픽: %s", pub_topic.c_str());
// 2. 구독자(Subscriber) 및 발행자(Publisher) 생성
subscription_ = this->create_subscription<px4_msgs::msg::VehicleAttitude>(
sub_topic, 10,
std::bind(&VersionTolerantNode::attitude_callback, this, std::placeholders::_1)
);
publisher_ = this->create_publisher<px4_msgs::msg::VehicleCommand>(pub_topic, 10);
}
private:
void attitude_callback(const px4_msgs::msg::VehicleAttitude::SharedPtr msg) {
RCLCPP_INFO(this->get_logger(), "자세(Attitude) 데이터를 수신했습니다.");
}
rclcpp::Publisher<px4_msgs::msg::VehicleCommand>::SharedPtr publisher_;
rclcpp::Subscription<px4_msgs::msg::VehicleAttitude>::SharedPtr subscription_;
};
int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<VersionTolerantNode>());
rclcpp::shutdown();
return 0;
}
위의 코드에서 getMessageNameVersion<T>() 함수를 사용하면, 현재 여러분의 워크스페이스에 설치된 px4_msgs의 버전을 컴파일러가 스스로 읽어내어 완벽한 토픽 이름을 조립합니다. 그리고 만약 이 노드의 버전과 실행 중인 PX4의 메시지 버전이 다르더라도, 백그라운드에서 실행해 둔 translation_node가 모든 것을 자동으로 통역해 주니 개발자는 비행 알고리즘 개발에만 온전히 집중할 수 있습니다!
마치며: 성공적인 자율 비행 연구를 응원합니다!
이것으로 총 6편에 걸친 [PX4 ROS 2 Programming] 블로그 연재를 모두 마칩니다.
초기 환경 구축(1편)의 막막함부터 시작해, QoS와 좌표계(2편)라는 통곡의 벽을 넘고, 데이터를 주고받으며(3편), 내 손으로 드론을 허공에 띄워 올리고(4편), 여러 대의 군집 드론과 서비스 기반 제어(5편)를 거쳐, 마침내 오늘 최신의 실험적 기능(6편)까지 도달하셨습니다.
여러분은 이제 단순한 ‘사용자’를 넘어, 세계 최고 수준의 오픈소스 비행 제어 소프트웨어인 PX4와 ROS 2를 자유자재로 다루며 자율 비행 로봇의 코어(Core) 시스템을 설계할 수 있는 역량을 갖추셨습니다.
앞으로 여러분이 연구실에서 탄생시킬 눈부신 인공지능 기반 회피 알고리즘, 군집 비행 예술, 그리고 고도화된 컴퓨터 비전 시스템들이 오늘 우리가 함께 쌓아 올린 이 튼튼한 뼈대 위에서 하늘을 자유롭게 수놓기를 진심으로 기원합니다.
그동안 긴 연재를 따라와 주셔서 대단히 감사합니다. 논문과 프로젝트 모두에 최고의 성과가 함께하시길 응원합니다. 화이팅입니다!
YouTube 강좌

Author: maponarooo, CEO of QUAD Drone Lab
Date: February 28, 2026
