无人机 MAVROS 安装与基础知识梳理及 ROS C++ 仿真案例
MAVROS 作为 ROS 与飞控间中间件的功能,涵盖安装步骤(含 GeographicLib 配置)、核心坐标系(Global/Local/Body)差异、常用话题与服务详解,并通过 C++ 代码演示了板外模式解锁、定点起飞及位姿获取的仿真流程。

MAVROS 作为 ROS 与飞控间中间件的功能,涵盖安装步骤(含 GeographicLib 配置)、核心坐标系(Global/Local/Body)差异、常用话题与服务详解,并通过 C++ 代码演示了板外模式解锁、定点起飞及位姿获取的仿真流程。

MAVROS是无人机开发中连接机器人操作系统(ROS)与飞控系统的关键中间件,通过标准化通信协议实现 ROS 节点与无人机的交互。它基于**MAVLink(Micro Air Vehicle Link)**轻量级通信协议,为 ROS 生态提供了与飞控(如 Pixhawk、ArduPilot、PX4 等)通信的统一接口,使开发者无需深入理解底层飞控协议,即可直接调用 ROS 的丰富工具链(如 RViz 可视化、Gazebo 仿真、导航栈)快速搭建无人机任务,推动了无人机应用的灵活开发与高效迭代。
MAVROS的核心功能包括双向数据传输:一方面,它订阅飞控的传感器数据(如 IMU、GPS、电池状态)并发布至 ROS 话题,供导航、感知等模块使用;另一方面,它接收 ROS 服务或动作指令(如起飞、降落、位姿控制),转换为 MAVLink消息发送至飞控执行。此外,MAVROS支持多种通信接口(串口、UDP、TCP),适配不同硬件场景,并提供参数配置服务,允许动态读写飞控参数(如 PID 调参、飞行模式切换)。

通过以下命令安装 MAVROS
sudo apt-get install ros-noetic-mavros
sudo apt install ros-noetic-mavros-extras
GeographicLib是一个开源的地理计算库,专门用于处理地球表面的高精度地理坐标计算,例如:
MAVROS在处理无人机导航和地理空间数据时需要依赖 GeographicLib提供的高精度地理计算功能,因此需安装相关数据集:
wget https://raw.githubusercontent.com/mavlink/mavros/master/mavros/scripts/install_geographiclib_datasets.sh
sudo chmod +x ./install_geographiclib_datasets.sh
sudo ./install_geographiclib_datasets.sh
MAVROS中涉及到以下坐标系:
global系:一般由 GPS 定义,例如经纬高坐标系(WGS84)local系:
ENU坐标系,一般是由 MAVROS发布的 map坐标系,其坐标原点是 MAVROS收到里程计信息时飞控所在的位置,并规定 x轴朝东、y轴朝北、z轴朝天,此时机体方向朝东;NED坐标系;body系:
FLU坐标系,即前左上,一般是由 MAVROS发布的 base_link坐标系FRD坐标系,即前右下具体关系如下图所示:

以下面的场景为实例,map系和 Gazebo里的坐标系方向一致。机身前方定义为东,即 map系的 x轴正方向,机身前进方向同时为 base_link系的 x轴正方向。所以从方向来看,ROS 端的 map系和 base_link系一致:

/mavros/stateconnected:检测无人机与地面站的物理连接状态armed:监控无人机电机是否解锁,只有 armed=true时表示电机已解锁,无人机可飞行mode:常用模式有:
MANUAL:完全手动模式POSCTL:位置控制模式ALTCTL:高度控制模式OFFBOARD:板外模式,ROS 主机控制无人机需要切换到这个模式MISSION:自动任务模式LOITER:自动悬停模式RTL:自动返航模式LAND:自动降落模式TAKEOFF:自动起飞模式manual_input:检测是否有人工遥控器输入system_status:无人机整体系统状态,分为未初始化、系统启动中、待机模式、任务执行中和紧急状态数据类型:mavros_msgs/State
std_msgs/Header header
uint32 seq
time stamp
string frame_id
bool connected
bool armed
bool guided
bool manual_input
string mode
uint8 system_status
/mavros/setpoint_position/localposition生效,不控制姿态 orientation。position是相对于 ROS 端 local坐标系的坐标数据类型:geometry_msgs/PoseStamped
std_msgs/Header header
uint32 seq
time stamp
string frame_id
geometry_msgs/Pose pose
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
/mavros/local_position/odomlocal坐标系的坐标,速度信息是相对于 ROS 端 body坐标系的坐标数据类型:nav_msgs/Odometry
std_msgs/Header header
uint32 seq
time stamp
string frame_id
string child_frame_id
geometry_msgs/PoseWithCovariance pose
geometry_msgs/Pose pose
geometry_msgs/Point position
float64 x
float64 y
float64 z
geometry_msgs/Quaternion orientation
float64 x
float64 y
float64 z
float64 w
float64[36] covariance
geometry_msgs/TwistWithCovariance twist
geometry_msgs/Twist twist
geometry_msgs/Vector3 linear
float64 x
float64 y
float64 z
geometry_msgs/Vector3 angular
float64 x
float64 y
float64 z
float64[36] covariance
/mavros/setpoint_raw/localcoordinate_frame:飞控端采用的坐标系,一般设置为 FRAME_LOCAL_NED,但是该话题数据都是在 ROS 端坐标系下,MAVROS会自动进行一次坐标变换type_mask:类型掩码,例如只控制加速度需要将位置、速度、角速度等标志为置为忽略数据类型:mavros_msgs::PositionTarget
std_msgs/Header header
uint8 coordinate_frame
uint8 FRAME_LOCAL_NED = 1
uint8 FRAME_LOCAL_OFFSET_NED = 7
uint8 FRAME_BODY_NED = 8
uint8 FRAME_BODY_OFFSET_NED = 9
uint16 type_mask
uint16 IGNORE_PX = 1 # Position ignore flags
uint16 IGNORE_PY = 2
uint16 IGNORE_PZ = 4
uint16 IGNORE_VX = 8 # Velocity vector ignore flags
uint16 IGNORE_VY = 16
uint16 IGNORE_VZ = 32
uint16 IGNORE_AFX = 64 # Acceleration/Force vector ignore flags
uint16 IGNORE_AFY = 128
uint16 IGNORE_AFZ = 256
uint16 FORCE = 512 # Force in af vector flag
uint16 IGNORE_YAW = 1024
uint16 IGNORE_YAW_RATE = 2048
geometry_msgs/Point position
geometry_msgs/Vector3 velocity
geometry_msgs/Vector3 acceleration_or_force
float32 yaw
float32 yaw_rate
/mavros/setpoint_raw/attitude数据类型:mavros_msgs::AttitudeTarget
std_msgs/Header header
uint8 type_mask
uint8 IGNORE_ROLL_RATE = 1 # body_rate.x
uint8 IGNORE_PITCH_RATE = 2 # body_rate.y
uint8 IGNORE_YAW_RATE = 4 # body_rate.z
uint8 IGNORE_THRUST = 64
uint8 IGNORE_ATTITUDE = 128 # orientation field
geometry_msgs/Quaternion orientation
geometry_msgs/Vector3 body_rate
float32 thrust
/mavros/cmd/arming数据类型:mavros_msgs/CommandBool
bool value // true 解锁,false 上锁
---
bool success
uint8 result
/mavros/set_modeOFFBOARD模式数据类型:mavros_msgs/SetMode
string custom_mode
uint8 base_mode
uint8 MAV_MODE_PREFLIGHT=0
uint8 MAV_MODE_STABILIZE_DISARMED=80
uint8 MAV_MODE_STABILIZE_ARMED=208
uint8 MAV_MODE_MANUAL_DISARMED=64
uint8 MAV_MODE_MANUAL_ARMED=192
uint8 MAV_MODE_GUIDED_DISARMED=88
uint8 MAV_MODE_GUIDED_ARMED=216
uint8 MAV_MODE_AUTO_DISARMED=92
uint8 MAV_MODE_AUTO_ARMED=220
uint8 MAV_MODE_TEST_DISARMED=66
uint8 MAV_MODE_TEST_ARMED=194
---
bool mode_sent
this->arm_client_ = this->nh_.serviceClient<mavros_msgs::CommandBool>("mavros/cmd/arming");
this->set_mode_client_ = this->nh_.serviceClient<mavros_msgs::SetMode>("mavros/set_mode");
mavros_msgs::SetMode offboardMode;
offboardMode.request.custom_mode = "OFFBOARD";
mavros_msgs::CommandBool armCmd;
armCmd.request.value = true;
ros::Time lastRequest = ros::Time::now();
while(ros::ok()){
if(this->mavros_state_.mode != "OFFBOARD" && (ros::Time::now() - lastRequest > ros::Duration(5.0))){
if(this->set_mode_client_.call(offboardMode) && offboardMode.response.mode_sent){
cout << "Offboard mode enabled." << endl;
}
lastRequest = ros::Time::now();
} else {
if(!this->mavros_state_.armed && (ros::Time::now() - lastRequest > ros::Duration(5.0))){
if(this->arm_client_.call(armCmd) && armCmd.response.success){
cout << "Vehicle armed." << endl;
}
lastRequest = ros::Time::now();
}
}
r.sleep();
}
假设要飞到 1m 的高度
this->position_pub_ = this->nh_.advertise<geometry_msgs::PoseStamped>("/mavros/setpoint_position/local", 1000);
geometry_msgs::PoseStamped ps;
ps.header.frame_id = "map";
ps.header.stamp = ros::Time::now();
ps.pose.position.x = this->odom_.pose.pose.position.x;
ps.pose.position.y = this->odom_.pose.pose.position.y;
ps.pose.position.z = 1.0;
ps.pose.orientation = this->odom_.pose.pose.orientation;
this->position_pub_.publish(ps);
this->odom_sub_ = this->nh_.subscribe<nav_msgs::Odometry>("/mavros/local_position/odom", 1000, &flightBase::odomCB, this);
void flightBase::odomCB(const nav_msgs::Odometry::ConstPtr &odom){
this->odom_ = *odom;
this->curr_position_(0) = this->odom_.pose.pose.position.x;
this->curr_position_(1) = this->odom_.pose.pose.position.y;
this->curr_position_(2) = this->odom_.pose.pose.position.z;
Eigen::Vector3d curr_vel_body(this->odom_.twist.twist.linear.x, this->odom_.twist.twist.linear.y, this->odom_.twist.twist.linear.z);
Eigen::Vector4d orientation_quat(this->odom_.pose.pose.orientation.w, this->odom_.pose.pose.orientation.x, this->odom_.pose.pose.orientation.y, this->odom_.pose.pose.orientation.z);
Eigen::Matrix3d orientation_rot = quat2RotMatrix(orientation_quat);
this->curr_vel_ = orientation_rot * curr_vel_body;
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online