mavros和PX4中的海拔高与椭球高转换
飞控高度传感器中一般有两种高度:
- 海拔高。也称AMSL(Above Mean Sea Level)height或者geoid height或者正高,顾名思义就是指高于当地平均海平面的高度。我猜气压计测得的高度应当就是与海平面相关的。
- 椭球高。也称ellipsoid height或者大地高。顾名思义就是指相对于WGS84地球标准椭球模型的高度。GPS定位系统普遍采用的WGS84坐标系,给出的高度就是ellipsoid高度。
同一个位置的两种高度值一般可以相差几十米,这是因为当地平均海平面是和地形有关的,凹凸不平没有规律。而ellipsoid height采用的基准是地球标准椭球模型,它的高度值和地形没有关系,只和到地心的距离有关。
下文的mavros指ros1 noetic版本的,ros2版本的我还没研究。
Mavros
mavros/global_position/global话题
此话题发布经纬高,其中高度是ellipsoid height椭球高。其实px4的GLOBAL_POSITION_INT mavlink消息发布的高度是geoid height海拔高度,但是mavros做了转换后再发布到global话题,具体这个转换在:
https://github.com/mavlink/mavros/blob/master/mavros/src/plugins/global_position.cpp#L144-L150
template<typename MsgT>inline void fill_lla(MsgT &msg, sensor_msgs::NavSatFix::Ptr fix){fix->latitude = msg.lat / 1E7; // degfix->longitude = msg.lon / 1E7; // degfix->altitude = msg.alt / 1E3 + m_uas->geoid_to_ellipsoid_height(fix); // in meters}
geoid_to_ellipsoid_height()就是海拔高转换为椭球高的函数。要进行这个转换,需要知道地球所有地点的平均海拔高,这是一个相当大的数据集。还记得安装mavros的时候需要执行一个install_geographiclib_datasets.sh脚本吗,其实这就是在安装egm96_5库,这个库存放了地球所有地点的平均海拔高模型,并提供每个经纬度点的海拔高和椭球高的差值。实测导入egm96_5库需要额外的18MB内存。
顺便一提,这个话题发布的经纬度只有七位小数精度,因为PX4的GLOBAL_POSITION_INT mavlink消息stream的时候,将经纬度乘了1e7变成了整型,mavros接收mavlink消息后再除了1e7,因此损失了经纬度七位小数之后的精度(大概相当于几厘米)。
下面这段c++代码可以用于海拔高转换为椭球高:
#include <GeographicLib/Geoid.hpp>
#include <memory> // for std::shared_ptr
std::shared_ptr<GeographicLib::Geoid> egm96_5; // This class loads egm96_5 dataset to RAM, it is about 24 MiB.
egm96_5 = std::make_shared<GeographicLib::Geoid>("egm96-5", "", true, true); // Using smallest dataset with 5' grid, // From default location, // Use cubic interpolation, Thread safe
alt_ellipsoid = alt_amsl + GeographicLib::Geoid::GEOIDTOELLIPSOID * (*egm96_5)(lat, lon); // AMSL TO WGS84 altitude
执行代码需要安装egm96,这里借用安装mavros时的脚本:
wget https://gitee.com/shu-peixuan/px4mocap/raw/85b46df9912338f775949903841160c873af4a1d/ROS-install-command/install_geographiclib_datasets.sh
sudo chmod a+x ./install_geographiclib_datasets.sh
sudo ./install_geographiclib_datasets.sh # this step takes some time
rm install_geographiclib_datasets.sh
mavros/global_position/local话题
这个话题发布的是ENU东北天坐标。但它和mavros/local_position/pose还不一定一样。它是由ECEF地球坐标系中的坐标相对于地图原点map origin转换到ENU东北天坐标系。这个地图原点的选取可能是当前点,或者地图点,或者设置的map origin。看看mavros源码吧:
https://github.com/mavlink/mavros/blob/master/mavros/src/plugins/global_position.cpp#L330-L365
/*** @brief Checks if the "map" origin is set.* - If not, and the home position is also not received, it sets the current fix as the origin;* - If the home position is received, it sets the "map" origin;* - If the "map" origin is set, then it applies the rotations to the offset between the origin* and the current local geocentric coordinates.*/
// Current fix to ECEF
map.Forward(fix->latitude, fix->longitude, fix->altitude,map_point.x(), map_point.y(), map_point.z());// Set the current fix as the "map" origin if it's not set
if (!is_map_init && fix->status.status >= sensor_msgs::NavSatStatus::STATUS_FIX) {map_origin.x() = fix->latitude;map_origin.y() = fix->longitude;map_origin.z() = fix->altitude;ecef_origin = map_point; // Local position is zerois_map_init = true;
}
}
catch (const std::exception& e) {
ROS_INFO_STREAM("GP: Caught exception: " << e.what() << std::endl);
}// Compute the local coordinates in ECEF
local_ecef = map_point - ecef_origin;
// Compute the local coordinates in ENU
tf::pointEigenToMsg(ftf::transform_frame_ecef_enu(local_ecef, map_origin), odom->pose.pose.position);/*** @brief By default, we are using the relative altitude instead of the geocentric* altitude, which is relative to the WGS-84 ellipsoid*/
if (use_relative_alt)
odom->pose.pose.position.z = relative_alt->data;odom->pose.pose.orientation = m_uas->get_attitude_orientation_enu();
这里面的odom就是发布到mavros/global_position/local话题的消息。可以看到它的高度默认是相对高度relative_alt。这个相对高度是由px4的GLOBAL_POSITION_INT mavlink消息发布的,是px4飞控内部对于相对地面/起飞点高度的一个估计。
可以看出,mavros/global_position/local话题没什么用,还不如用mavros/local_position/pose。
mavros/setpoint_raw/global话题
这个话题用于向飞控发布期望的经纬高setpoint,我在四旋翼利用mavros进行GPS坐标指点飞行_/mavros/setpoint_raw/local-CSDN博客一文中已经指出,尽量不要直接用这个话题发送GPS目标位置点,可以用mavros/setpoint_raw/local代替。
如果你非要用这个话题,那么我们看看发送的经纬高setpoint中的高度是什么:
https://github.com/mavlink/mavros/blob/master/mavros/src/plugins/setpoint_raw.cpp#L205-L234
void global_cb(const mavros_msgs::GlobalPositionTarget::ConstPtr &req)
{Eigen::Vector3d velocity, af;float yaw, yaw_rate;tf::vectorMsgToEigen(req->velocity, velocity);tf::vectorMsgToEigen(req->acceleration_or_force, af);// Transform frame ENU->NEDvelocity = ftf::transform_frame_enu_ned(velocity);af = ftf::transform_frame_enu_ned(af);yaw = ftf::quaternion_get_yaw(ftf::transform_orientation_aircraft_baselink(ftf::transform_orientation_ned_enu(ftf::quaternion_from_rpy(0.0, 0.0, req->yaw))));Eigen::Vector3d ang_vel_enu(0.0, 0.0, req->yaw_rate);auto ang_vel_ned = ftf::transform_frame_ned_enu(ang_vel_enu);yaw_rate = ang_vel_ned.z();set_position_target_global_int(req->header.stamp.toNSec() / 1000000,req->coordinate_frame, //代表经纬高采用的坐标系(主要针对高度)req->type_mask,req->latitude * 1e7,req->longitude * 1e7,req->altitude, //直接通过SET_POSITION_TARGET_GLOBAL_INT mavlink消息发给px4了velocity,af,yaw, yaw_rate);
}
这里的经纬高是直接通过SET_POSITION_TARGET_GLOBAL_INT mavlink消息发给px4了,经纬度还乘了1e7变成整型,所以损失了第七位小数之后的经纬值(大概相当于几厘米)。
PX4中是怎么处理SET_POSITION_TARGET_GLOBAL_INT mavlink消息的呢,让我们看看px4 v1.13.3(2023年底)中mavlink_receiver.cpp的代码:
https://github.com/PX4/PX4-Autopilot/blob/v1.13.3/src/modules/mavlink/mavlink_receiver.cpp#L1135-L1256
if (target_global_int.coordinate_frame == MAV_FRAME_GLOBAL_INT) {setpoint.z = local_pos.ref_alt - target_global_int.alt; // setpoint.z就是px4具体track的local高度} else if (target_global_int.coordinate_frame == MAV_FRAME_GLOBAL_RELATIVE_ALT_INT) {home_position_s home_position{};_home_position_sub.copy(&home_position);if (home_position.valid_alt) {const float alt = home_position.alt - target_global_int.alt;setpoint.z = alt - local_pos.ref_alt; // setpoint.z就是px4具体track的local高度} else {// home altitude requiredreturn;}} else if (target_global_int.coordinate_frame == MAV_FRAME_GLOBAL_TERRAIN_ALT_INT) {vehicle_global_position_s vehicle_global_position{};_vehicle_global_position_sub.copy(&vehicle_global_position);if (vehicle_global_position.terrain_alt_valid) {const float alt = target_global_int.alt + vehicle_global_position.terrain_alt;setpoint.z = local_pos.ref_alt - alt; // setpoint.z就是px4具体track的local高度} else {// valid terrain alt requiredreturn;}}
原来是和mavlink消息中的coordinate_frame有关,可能是global高度、相对高度或者对地高度。不过这些高度含义其实不那么清晰,具体代表什么还得深挖px4源码。所以再次强调,尽量不要直接用这个话题发送GPS目标位置点。
参考:geoid 理解_egm2008大地水准面模型-CSDN博客
相关文章:
mavros和PX4中的海拔高与椭球高转换
飞控高度传感器中一般有两种高度: 海拔高。也称AMSL(Above Mean Sea Level)height或者geoid height或者正高,顾名思义就是指高于当地平均海平面的高度。我猜气压计测得的高度应当就是与海平面相关的。椭球高。也称ellipsoid heig…...
洛谷刷题-【入门2】分支结构
目录 1.苹果和虫子 题目描述 输入格式 输出格式 输入输出样例 2.数的性质 题目描述 输入格式 输出格式 输入输出样例 3.闰年判断 题目描述 输入格式 输出格式 输入输出样例 4.apples 题目描述 输入格式 输出格式 输入输出样例 5.洛谷团队系统 题目描述 …...
文件包含技术总结
开发人员一般会把重复使用的函数写到单个文件中,需要使用某个函数时直接调用此文件,而无需再次编写,这中文件调用的过程一般被称为文件包含。 allow_url_fopen On(是否允许打开远程文件) allow_url_include On&…...
Docker搭建私有仓库
Docker搭建私有仓库 下载docker registry镜像 docker pull docker.io/registry2.registry镜像下载完成后,先创建一个存放镜像的目录。 mkdir -p /data/registry3.启动registry容器 docker run -itd -p 5000:5000 -v /data/registry:/var/lib/registry docker.io…...
【计算机网络】【练习题】【新加坡南洋理工大学】【Computer Control Network】
说明: 仅供学习使用。 一、题目描述 该题目描述一个网络中传播时延(Transmission Delay)的例子。题目如下: 二、问题解答(个人) 笔者第3问采用均值不等式求解。标答中采用求导数的方法求极值。似乎均值…...
【学习笔记】CF1349F2 Slime and Sequences (Hard Version)
多项式工业警告!!! 点击看题意 思路来自 这位大佬 。 为什么这么好的题解没人评论。 Part 1 前置知识:拉格朗日反演(多项式复合),分式域(引入负整数次项)。 条件&a…...
HarmonyOS 鸿蒙应用开发( 六、实现自定义弹窗CustomDialog)
自定义弹窗(CustomDialog)可用于广告、中奖、警告、软件更新等与用户交互响应操作。开发者可以通过CustomDialogController类显示自定义弹窗。具体用法请参考自定义弹窗。 在应用的使用和开发中,弹窗是一个很常见的场景,自定义弹窗…...
# Java NIO(一)FileChannel
Java NIO 1.BIO与NIO的区别 BIO为阻塞IO,NIO为非阻塞IO。 BIONIOJAVA1.4之前Java 1.4之后面向流:以byte为单位处理数据面向块:以块为单位处理数据同步阻塞同步非阻塞无选择器(Selector) 1.1NIO的核心组成部分 Cha…...
[嵌入式软件][启蒙篇][仿真平台] STM32F103实现串口输出输入、ADC采集
上一篇:[嵌入式软件][启蒙篇][仿真平台] STM32F103实现LED、按键 文章目录 一、串口输出(1) 简介(2) 示例代码(3) 仿真效果 二、串口输入(1) 简介(2) 示例代码(3) 仿真效果 三、ADC采集(1) 简介(2) 采集电压(3) 示例代码(电压)(4) 仿真效果 …...
Deepin基本环境查看(四)【硬盘/分区、文件系统、硬连接/软连接】
Linux操作系统(Deepin、Ubuntu)操作系统中,硬盘分区的管理与Windows操作系统不同; 在Linux系统中维护着一个统一的文件目录体系,而硬盘和分区是以资源的形式由操作系统挂接和调度;此外Linux系统中连接(硬连…...
JS之打地鼠案例
需要素材的同学可以私信我 效果图: 上代码: <!DOCTYPE html> <html> <head><meta charset"utf-8"><title></title><style>* {margin: 0;padding: 0;}.box {position: relative;width: 320px;heigh…...
Kubernetes入门
k8s相关基础知识 文章目录 k8s相关基础知识1、Container2、PodPod 与 Container 的不同Pod 其它命令 3、Deployment扩容升级版本Rolling update(滚动更新)存活探针(livenessProb)就绪探针(readiness) 4、ServiceClusterIPNodePortLoadBalancer 5、Ingres…...
EtherNet/IP开发:C++搭建基础模块,EtherNet/IP源代码
这里是CIP资料的协议层级图,讲解协议构造。 ODVA(www.ODVA.org)成立于1995年,是一个全球性协会,其成员包括世界领先的自动化公司。结合其成员的支持,ODVA的使命是在工业自动化中推进开放、可互操作的信息和…...
Django(九)
1. 用户登录-Cookie和Session 什么是cookie和session? 发送HTTP请求或者HTTPS请求(无状态&短连接) http://127.0.0.1:8000/admin/list/ https://127.0.0.1:8000/admin/list/http无状态短连接:一次请求响应之后断开连接,再发请求重新连…...
解决Android Studio Unexpected tokens (use ; to separate expressions on the same line)
[TOC](Unexpected tokens (use ; to separate expressions on the same line)) 问题描述:Unexpected tokens (use ; to separate expressions on the same line) 原因:Android Studio 更新到最新的版本之后,gradle工程目录结构发生改变 问…...
【云原生】Docker网络模式和Cgroup资源限制
目录 一、Docker 网络实现原理 二、Docker 的网络模式 #网络模式详解: 第一种:host模式 第二种:bridge模式 第三种:container模式 第四种:none模式 第五种:自定义网络 三、Cgroup资源控制 第一种&a…...
实战:加密传输数据解密
前言 下面将分享一些实际的渗透测试经验,帮助你应对在测试中遇到的数据包内容加密的情况。我们将以实战为主,技巧为辅,进入逆向的大门。 技巧 开局先讲一下技巧,掌握好了技巧,方便逆向的时候可以更加快速的找到关键…...
前端开发提高效率的两大工具
一、浏览器中的开发者工具 怎么启动开发者工具? 在浏览器中按下F12或者鼠标右键点击检查 怎么利用(常用的几点)? 1、元素 点击标红的图标可以用于在页面选择元素,同时右侧会找到元素在前端代码中的位置 点击下方红…...
探索设计模式的魅力:深入理解面向对象设计的深层原则与思维
如何同时提高一个软件系统的可维护性 和 可复用性是面向对象对象要解决的核心问题。 通过学习和应用设计模式,可以更加深入地理解面向对象的设计理念,从而帮助设计师改善自己的系统设计。但是,设计模式并不能够提供具有普遍性的设计指导原则。…...
【Py/Java/C++三种语言详解】LeetCode每日一题240122【贪心】LeetCode670、最大交换
文章目录 题目链接题目描述解题思路为什么是贪心一个带图的例子 代码pythonjavacpp时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目链接 LeetCode670、最大交换 题目描述 给定一个非负整数数组 nums 和一个整数 k ,你需要将这个数组分成 k 个非空的连…...
Android 离线语音合成技术选型指南:从MaryTTS到TensorFlowTTS
1. 为什么需要离线语音合成技术? 最近几年,越来越多的应用开始集成语音合成功能。你可能见过导航软件里实时播报路况的电子女声,或者听书App里流畅朗读小说的AI配音。这些场景背后,都离不开TTS(Text-To-Speech&#x…...
从取证到防御:实战解析BadUSB攻击与USB流量异常检测(Wireshark实战)
从取证到防御:实战解析BadUSB攻击与USB流量异常检测(Wireshark实战) 在企业内网安全防护中,USB设备带来的威胁往往被低估。去年某金融机构遭遇的供应链攻击事件中,攻击者通过伪装成键盘的BadUSB设备,在3分钟…...
ROS Noetic下用Python脚本在Gazebo里动态生成障碍物(附完整代码和常见报错解决)
ROS Noetic下Python脚本动态生成Gazebo障碍物的工程实践 在机器人仿真测试中,动态生成环境障碍物是验证导航算法鲁棒性的关键手段。传统手动拖拽方式效率低下且难以复现特定测试场景,而通过编程控制Gazebo仿真环境则能实现测试流程的自动化与标准化。本文…...
Cursor Pro免费激活终极指南:如何突破试用限制重新获得AI编程体验
Cursor Pro免费激活终极指南:如何突破试用限制重新获得AI编程体验 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reach…...
算法模拟类题目解析
前言:最近开始偏系统的从简单到难一步步刷算法题,先从模拟题开始,下边附带题目与连接,感兴趣可刷刷也可看看我的思路。 一.字符串展开 链接:https://ac.nowcoder.com/acm/problem/16644 来源:牛客网 题意…...
开发者的第二曲线:2026年最赚钱的5个技术副业
在技术范式加速重构的2026年,软件质量保障的重要性已从“成本中心”跃升为“价值中心”。对于敏锐的软件测试从业者而言,这不仅是职业的深化,更是将专业壁垒转化为财富增长的绝佳契机。传统的“接私活”模式正在被更具复利效应和杠杆价值的“…...
海康MVS软件从下载到实时预览:MV-CA013-21UC工业相机5分钟极速上手教程
海康MVS软件从下载到实时预览:MV-CA013-21UC工业相机5分钟极速上手教程 工业视觉系统正成为智能制造的核心组件,而海康威视MV-CA013-21UC工业相机凭借其高帧率、低噪声和稳定性能,在自动化检测、机器人引导等领域广受欢迎。本文将带您从零开…...
从ULN2803芯片内部拆解,聊聊三极管“黄金搭档”达林顿管到底强在哪?
ULN2803芯片拆解:达林顿管如何成为三极管的“黄金搭档”? 当我们需要用单片机的微弱IO口信号(通常只有几毫安)驱动继电器、电机这类“大胃王”负载时,就像试图用一根吸管给游泳池注水——理论可行,实际效率…...
Fish-Speech-1.5在短视频生产的应用:批量生成多语种配音方案
Fish-Speech-1.5在短视频生产的应用:批量生成多语种配音方案 1. 引言 短视频内容创作正面临着一个普遍痛点:多语言配音成本高、周期长。传统方式下,一个MCN机构要为一条短视频制作中文、英文、日文三种语言的配音,需要分别联系不…...
5步释放游戏潜能:面向玩家的原神帧率解锁完全指南
5步释放游戏潜能:面向玩家的原神帧率解锁完全指南 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 一、问题发现:为什么你的高端显卡在原神中无法全力奔跑…...
