跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

PX4 无人机 MID360 结合 FAST_LIO 实现室内自主定位与定点

介绍基于 PX4 固件与 MID360 激光雷达,利用 FAST_LIO 算法实现无人机室内自主定位与定点悬停的配置流程。主要步骤包括:设置 PX4 飞控参数将定位源改为视觉模式并关闭磁力计;编写 Python 节点将 Fast-LIO 位姿发布至 MAVROS 话题;调整雷达扫描频率;运行 Mavros 及定位程序。最后通过 QGC 验证坐标系方向与运动数据一致性。

林间仙子发布于 2026/4/6更新于 2026/10/25120 浏览
PX4 无人机 MID360 结合 FAST_LIO 实现室内自主定位与定点

PX4 无人机 MID360 结合 FAST_LIO 实现室内自主定位与定点

环境准备

  • PX4 固件版本:1.15.4
  • QGroundControl (QGC) 地面站版本:4.4.5
  • 飞控:微空科技 MicoAir743V2
  • 机载电脑:12 代 i5, Ubuntu 20.04
  • 安装位置:MID360 接口对应飞机后方

建议参考官方文档:Using Vision or Motion Capture Systems for Position Estimation | PX4 Guide

一、PX4 飞控设置

1. 将 PX4 定位数据源设置为 Vision

  • 参数 EKF2_EV_CTRL:可保持默认或按需配置。
  • 参数 EKF2_HGT_REF:设置为 Vision。

2. 关闭罗盘

注意: 完成上述飞控设置后,机头上电后会指向北。但在后续程序运行后,由于罗盘已关闭,上电后无人机机头可能指向东方。

此外,加一个激光测距融合好处多多。

二、程序部署

注意: 雷达频率可调至 30Hz,但实测定位精度在 30Hz 下仅为 10Hz 的 60% 不到,请慎重选择频率。

1. 代码实现

创建发布 /mavros/vision_pose/pose 话题的功能包。主要功能是将转化后的位姿信息以该话题发布。

#!/usr/bin/env python3
import rospy
from nav_msgs.msg import Odometry
from geometry_msgs.msg import PoseStamped
import tf
import numpy as np
from collections import deque
import math

class SlidingWindowAverage:
    def __init__(self, window_size):
        self.window_size = window_size
        self.data_queue = deque()
        self.window_sum = 0.0

    def add_data(self, new_data):
        if self.data_queue and abs(new_data - self.data_queue[-1]) > 0.01:
            self.data_queue.clear()
            self.window_sum = 0.0
        self.data_queue.append(new_data)
        self.window_sum += new_data
        if len(self.data_queue) > self.window_size:
            self.window_sum -= self.data_queue.popleft()
        return self.window_sum / len(self.data_queue)

class FastLIOToMavros:
    def __init__(self):
        rospy.init_node('fastlio_to_mavros', anonymous=True)
        self.p_lidar_body = np.zeros(3)
        self.q_mav = [0, 0, 0, 1]
        self.q_px4_odom = [0, 0, 0, 1]
        self.window_size = 8
        self.swa = SlidingWindowAverage(self.window_size)
        self.init_flag = False
        self.init_q = tf.transformations.quaternion_from_euler(0, 0, 0)
        
        rospy.Subscriber('/Odometry', Odometry, self.vins_callback)
        rospy.Subscriber('/mavros/local_position/odom', Odometry, self.px4_odom_callback)
        self.vision_pub = rospy.Publisher('/mavros/vision_pose/pose', PoseStamped, queue_size=10)
        self.rate = rospy.Rate(30.0)
        self.run()

    def from_quaternion_to_yaw(self, q):
        euler = tf.transformations.euler_from_quaternion(q)
        return euler[2]

    def vins_callback(self, msg):
        self.p_lidar_body = np.array([
            msg.pose.pose.position.x,
            msg.pose.pose.position.y,
            msg.pose.pose.position.z
        ])
        self.q_mav = [
            msg.pose.pose.orientation.x,
            msg.pose.pose.orientation.y,
            msg.pose.pose.orientation.z,
            msg.pose.pose.orientation.w
        ]

    def px4_odom_callback(self, msg):
        self.q_px4_odom = [
            msg.pose.pose.orientation.x,
            msg.pose.pose.orientation.y,
            msg.pose.pose.orientation.z,
            msg.pose.pose.orientation.w
        ]
        yaw = self.from_quaternion_to_yaw(self.q_px4_odom)
        self.swa.add_data(yaw)

    def run(self):
        while not rospy.is_shutdown():
            if self.swa.get_size() == self.window_size and not self.init_flag:
                init_yaw = self.swa.get_avg()
                self.init_q = tf.transformations.quaternion_from_euler(0, 0, init_yaw)
                self.init_flag = True
            
            if self.init_flag:
                rot_matrix = tf.transformations.quaternion_matrix(self.init_q)[:3, :3]
                p_enu = np.dot(rot_matrix, self.p_lidar_body)
                
                vision = PoseStamped()
                vision.header.stamp = rospy.Time.now()
                vision.header.frame_id = "map"
                vision.pose.position.x = p_enu[0]
                vision.pose.position.y = p_enu[1]
                vision.pose.position.z = p_enu[2]
                vision.pose.orientation.x = self.q_mav[0]
                vision.pose.orientation.y = self.q_mav[1]
                vision.pose.orientation.z = self.q_mav[2]
                vision.pose.orientation.w = self.q_mav[3]
                
                self.vision_pub.publish(vision)
                rospy.loginfo(
                    "\nPosition in ENU:\n x: {:.3f}\n y: {:.3f}\n z: {:.3f}\nOrientation of LiDAR:\n x: {:.3f}\n y: {:.3f}\n z: {:.3f}\n w: {:.3f}".format(
                        p_enu[0], p_enu[1], p_enu[2], self.q_mav[0], self.q_mav[1], self.q_mav[2], self.q_mav[3]
                    )
                )
            self.rate.sleep()

if __name__ == '__main__':
    try:
        FastLIOToMavros()
    except rospy.ROSInterruptException:
        pass

自行创建 fastlio_to_mavros 节点的 launch 文件。

2. 运行 MID360 和 FAST_LIO 程序

修改 livox_ros_driver2 中的 msg_MID360.launch,使其频率达到 30Hz(默认也能用)。

roslaunch livox_ros_driver2 msg_MID360.launch
# 在另一个终端中执行
roslaunch fast_lio mapping_mid360.launch

3. 运行 MAVROS

roslaunch mavros px4.launch

必须运行上述指令后马上运行下面的 fastlio_to_mavros。

4. 运行自定义 Launch 文件

运行自己创建的 fastlio_to_mavros 节点的 launch 文件。

三、验证

推荐用官方的仿真来理解坐标系。

你会发现一运行 fastlio_to_mavros 节点,无人机机头突然从指向北变成指向东方(确保罗盘已经被关了)。

在 Ubuntu 上位机看输入 rostopic echo /mavros/local_position/pose,机头所指的方向为正 X。X 在前,Y 朝向左,Z 朝向下。

打开 QGC,点左上角 Analyze Tools -> MAVlink 检测,出现了 LOCAL_POSITION_NED 数据。坐标系看法如下:NED 坐标系,X 为北,Y 为东,Z 为下。机头指向东,那么向东运动(机头方向),Y 会增大。向北运动(飞机左方向),X 会增大。那么向上运动,Z 会是负数,且越来越负。

实机向前方运动

会发现 QGC 的 LOCAL_POSITION_NED 的 Y 增大,/mavros/local_position/pose 的 X 增大。

实机向右方运动

会发现 QGC 的 LOCAL_POSITION_NED 的 X 变小为负数,/mavros/local_position/pose 的 Y 变小为负数。

当飞机向上运动

会发现 QGC 的 LOCAL_POSITION_NED 的 Z 变成负数并且不断减小。

四、总结

建议调试 PID 后再起飞,本文已验证定点飞行功能。

目录

  1. PX4 无人机 MID360 结合 FAST_LIO 实现室内自主定位与定点
  2. 环境准备
  3. 一、PX4 飞控设置
  4. 1. 将 PX4 定位数据源设置为 Vision
  5. 2. 关闭罗盘
  6. 二、程序部署
  7. 1. 代码实现
  8. 2. 运行 MID360 和 FAST_LIO 程序
  9. 在另一个终端中执行
  10. 3. 运行 MAVROS
  11. 4. 运行自定义 Launch 文件
  12. 三、验证
  13. 实机向前方运动
  14. 实机向右方运动
  15. 当飞机向上运动
  16. 四、总结

更多推荐文章

查看全部
  • 知识库问答机器人:基于 SpringAI+RAG 的实现
  • 基于 C++ 手写 HTTP 服务器:从请求解析到响应构建
  • 贪心算法进阶:摆动序列、递增三元组及股票买卖实战
  • 直流无刷电机 FOC 控制算法详解
  • Java equals() 与 hashCode() 契约详解及容器类(List/Set/Map)核心整理
  • Linux 进程信号入门:软中断机制与实战
  • 存储扇区分配表:NAND Flash 与 SD NAND 架构差异
  • Web Bluetooth API 实战指南:从设备连接到数据交互
  • DeerFlow 2.0 开源:字节跳动超级智能体架构详解
  • CentOS 安装 Python 3.12 实战记录
  • SD-XL 1.0 Refiner 图像优化工具使用指南
  • 基于 DeepFace 和 OpenCV 的情绪分析器
  • PyTorch 强化学习实战:策略梯度算法详解
  • 无人机 RemoteID 合规实战:基于 ArduRemoteID 的开源方案解析
  • Python OCR 技术入门与验证码识别实战
  • Python 调用 Anthropic API 的两种方式
  • 基于迁移学习的个性化 AKI 预测模型开发与验证
  • OpenClaw 新手指南:环境搭建、模型配置与远程访问
  • 大模型时代人形机器人感知:视觉 - 语言模型应用
  • Coze 智能体核心资源详解:插件、知识库与数据库实战

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online