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

基于大疆 MSDK 的无人机视觉引导自适应降落方案

采用虚拟摇杆模拟 FlyTo 功能解决机型兼容问题,结合视觉识别计算 X/Y/Z 轴偏移量。系统根据高度动态调整下降速度与位置对齐阈值,低空阶段关闭下视避障防止误触。通过 10Hz 循环控制逻辑实现高精度自适应降落,确保在 GPS 精度不足及风力干扰下的着陆安全。

不羁发布于 2026/4/5更新于 2026/6/1022 浏览

基于大疆 MSDK 实现的无人机视觉引导自适应降落功能

概述

项目初期需求很明确:无人机执行完航线任务后,需要一键降落到指定位置(如汽车顶部),减少人工干预。为了实现这一目标,我们设计了一套完整的自主降落流程:先通过虚拟摇杆控制无人机飞向目标区域,再利用视觉识别系统引导其精确对准落点。

核心策略在于自适应降落——根据当前高度动态调整下降速度和位置对齐精度。高空阶段允许较大偏差以快速接近,低空阶段则严格限制偏移量以确保安全。

关键特性

  • 使用虚拟摇杆导航替代受限的 FlyTo 功能
  • 双轴 (X/Y) 位置偏移实时修正
  • 高度分段式自适应降落策略
  • 视觉识别辅助定位
  • 智能避障管理(低空自动关闭下视避障)

系统架构与逻辑流程

整个降落过程可以划分为几个关键状态,系统会根据高度和距离在不同状态间切换:

  1. 远程导航阶段:当距离目标超过 10 米时,无人机以 5m/s 的速度飞向目标上方。
  2. 进入降落准备:距离小于 10 米后,停止水平导航,启动视觉识别系统。
  3. 自适应下降循环:
    • 高空模式 (>50m):允许 1 米偏移误差,快速下降。
    • 中空模式 (20-50m):允许 0.5 米偏移误差,中速下降。
    • 低空模式 (5-20m):允许 0.3 米偏移误差,慢速下降。
    • 极低空模式 (<5m):要求 0.2 米精度,极慢速下降或悬停调整。
  4. 着陆清理:高度低于 0.1 米时,触发停桨指令并释放资源。

技术实现细节

第一步:解决导航兼容性问题

最初计划直接使用 DJI SDK 的 FlyTo 功能让无人机飞往目标 GPS 坐标。但在实际测试中发现,部分机型(如 M3E)并不支持该功能。

解决方案:虚拟摇杆模拟

既然无法直接飞过去,我们就用虚拟摇杆模拟飞行指令。核心思路是计算当前位置到目标位置的方位角,将其分解为速度分量持续发送。

private fun calculateBearing(latA: Double, lonA: Double, latB: Double, lonB: Double): Double {
    val lat1 = Math.toRadians(latA)
    val lat2 = Math.toRadians(latB)
    val dLon = Math.toRadians(lonB - lonA)
    val y = Math.sin(dLon) * Math.cos(lat2)
    val x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon)
    var bearing = Math.toDegrees(Math.atan2(y, x))
    bearing = (bearing + ) %  
     bearing 
}
360
360
// 归一化到 0-360 度
return
// 0°=正北,90°=正东,180°=正南,270°=正西

有了方位角,就可以设置虚拟摇杆参数。这里使用 GROUND 坐标系(地面坐标系),这样无论机头朝向如何,无人机都能朝目标方向移动。

val bearing = calculateBearing(currentLat, currentLon, targetLat, targetLon)
val bearingRad = Math.toRadians(bearing)
val navParam = VirtualStickFlightControlParam().apply {
    rollPitchCoordinateSystem = FlightCoordinateSystem.GROUND
    verticalControlMode = VerticalControlMode.POSITION
    yawControlMode = YawControlMode.ANGLE
    rollPitchControlMode = RollPitchControlMode.VELOCITY
    
    // 将速度分解为南北和东西分量
    pitch = NAVIGATION_SPEED * Math.cos(bearingRad) // 南北分量
    roll = NAVIGATION_SPEED * Math.sin(bearingRad) // 东西分量
    yaw = bearing // 让机头指向目标
    verticalThrottle = targetAlt
}

第二步:判断到达目标点附近

导航过程中需要实时监测距离。每 100ms 检查一次当前位置与目标的距离,一旦小于预设阈值(例如 10 米),就认为已到达目标点上方,停止导航并开始降落准备。

val navTask = object : Runnable {
    override fun run() {
        val currentLoc = getAircraftLocation()
        val remainingDistance = calculateDistance(
            currentLoc.latitude, currentLoc.longitude,
            targetLat, targetLon
        )
        
        if (remainingDistance < ARRIVAL_THRESHOLD) {
            // 10 米内,到达目标,停止导航,开始降落
            isNavigating = false
            startDynamicAdjustment()
        } else {
            // 继续飞行
            sendNavigationCommand()
            virtualStickHandler?.postDelayed(this, 100)
        }
    }
}

第三步:视觉引导与自适应降落

GPS 精度有限(±3 米),且受风力影响,仅靠 GPS 无法精确降落在车辆等小目标上。我们需要引入视觉识别系统来计算相对于标记点的 X/Y/Z 偏移量。

数据结构:

private var xOffset: Double = 0.0 // X 轴偏移 (米), 正=右,负=左
private var yOffset: Double = 0.0 // Y 轴偏移 (米), 正=前,负=后
private var zDistance: Double = 0.0 // Z 轴距离 (米), 距降落点高度

自适应策略核心: 不同高度对精度的要求不同。高度越高,允许的误差越大;随着高度降低,必须越来越严格地对准中心。

  • 偏移 > 阈值 2 倍:停止下降,只进行水平调整。
  • 偏移 > 阈值 1 倍:慢速下降 (0.1m/s) 并调整。
  • 偏移在范围内:根据高度决定下降速度 (0.2m/s ~ 0.5m/s)。
// 1. 根据高度动态计算允许的误差
private fun getOffsetThreshold(altitude: Double): Double {
    return when {
        altitude > 50.0 -> 1.0 // 高空:允许 1 米偏移误差
        altitude > 20.0 -> 0.5 // 中空:允许 0.5 米偏移误差
        altitude > 5.0 -> 0.3 // 低空:允许 0.3 米偏移误差
        else -> 0.2 // 极低空:要求 0.2 米精度
    }
}

// 2. 根据高度和偏移量动态计算下降速度
private fun getDescentSpeed(altitude: Double, xOffset: Double, yOffset: Double): Double {
    val threshold = getOffsetThreshold(altitude)
    return when {
        xOffset > threshold * 2 || yOffset > threshold * 2 -> 0.0 // 偏移太大:停止下降
        xOffset > threshold || yOffset > threshold -> 0.1 // 偏移较大:慢降
        altitude > 20.0 -> 0.5 // 中高空:快降
        altitude > 5.0 -> 0.2 // 低空:慢降
        else -> 0.2 // 极低空:极慢降
    }
}

第四步:避障处理与停桨

无人机的下视避障系统在接近地面时会将地面识别为障碍物,导致无法触地。因此,我们在高度低于 5 米时主动关闭下视避障。

var downwardObstacleDisabled = false

// 高度<5m 时关闭下视避障
if (currentAltitude <= 5.0 && !downwardObstacleDisabled) {
    downwardObstacleDisabled = true
    setObstacleAvoidanceEnable(false, PerceptionDirection.DOWNWARD)
}

private fun setObstacleAvoidanceEnable(enabled: Boolean, direction: PerceptionDirection) {
    if (direction == null) return
    PerceptionManager.getInstance().setObstacleAvoidanceEnabled(
        enabled, direction,
        object : CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                Log.i("Perception", "成功设置【${direction.name}】方向的避障为:${if(enabled)"开启"else"关闭"}")
            }
            override fun onFailure(error: IDJIError) {
                Log.e("Perception", "设置失败:$error")
            }
        }
    )
}

着陆完成后,调用 KeyStartAutoLanding 进行停桨操作。

第五步:完整控制循环

将上述逻辑整合到一个高频循环中(10Hz),确保响应及时。

private fun startDynamicAdjustment() {
    isAdjusting = true
    virtualStickHandler = Handler(Looper.getMainLooper())
    val adjustTask = object : Runnable {
        override fun run() {
            if (!isAdjusting) return
            
            // 1. 获取当前状态
            val currentAltitude = FlightControllerKey.KeyAltitude.create().get(0.0)
            val currentXOffsetAbs = Math.abs(xOffset)
            val currentYOffsetAbs = Math.abs(yOffset)
            
            // 2. 检查是否着陆
            if (currentAltitude <= 0.1) {
                stopLanding()
                return
            }
            
            // 3. 低空时关闭下视避障
            if (currentAltitude <= 5.0 && !downwardObstacleDisabled) {
                downwardObstacleDisabled = true
                setObstacleAvoidanceEnable(false, PerceptionDirection.DOWNWARD)
            }
            
            // 4. 计算自适应参数
            val offsetThreshold = getOffsetThreshold(currentAltitude)
            val descentSpeed = getDescentSpeed(currentAltitude, currentXOffsetAbs, currentYOffsetAbs)
            
            // 5. 构建虚拟摇杆指令
            val adjustParam = VirtualStickFlightControlParam().apply {
                rollPitchCoordinateSystem = FlightCoordinateSystem.BODY
                verticalControlMode = VerticalControlMode.VELOCITY
                rollPitchControlMode = RollPitchControlMode.VELOCITY
                
                // 水平调整
                roll = if (currentXOffsetAbs > offsetThreshold) {
                    if (xOffset > 0) ADJUSTMENT_SPEED else -ADJUSTMENT_SPEED
                } else 0.0
                
                pitch = if (currentYOffsetAbs > offsetThreshold) {
                    if (yOffset > 0) ADJUSTMENT_SPEED else -ADJUSTMENT_SPEED
                } else 0.0
                
                // 垂直下降
                verticalThrottle = -descentSpeed
            }
            
            // 6. 发送指令
            VirtualStickManager.getInstance().sendVirtualStickAdvancedParam(adjustParam)
            
            // 7. 100ms 后再次执行
            virtualStickHandler?.postDelayed(this, 100)
        }
    }
    virtualStickHandler?.post(adjustTask)
}

安全注意事项

  1. 环境要求:必须在空旷、安全的环境下进行测试。
  2. 模拟器验证:建议先用 DJI 模拟器充分测试逻辑后再实机运行。
  3. 视觉更新:视觉识别系统必须保持持续更新(约 1Hz),否则数据会滞后。
  4. 手动接管:准备好随时切断控制权,确保人员设备安全。

注意:代码中的坐标示例仅为演示,实际部署时需替换为真实的车辆 GPS 坐标接口。

目录

  1. 基于大疆 MSDK 实现的无人机视觉引导自适应降落功能
  2. 概述
  3. 关键特性
  4. 系统架构与逻辑流程
  5. 技术实现细节
  6. 第一步:解决导航兼容性问题
  7. 第二步:判断到达目标点附近
  8. 第三步:视觉引导与自适应降落
  9. 第四步:避障处理与停桨
  10. 第五步:完整控制循环
  11. 安全注意事项
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • K-近邻算法(KNN)原理、实战与工程优化指南
  • 大厂 AI 人才争夺战:哪些技术职位最火爆?
  • 户外机器人 GNSS 仿真测试:双天线定向与 RTK 高精度定位实战
  • 递归、搜索与回溯算法实战:从决策树到经典题目解析
  • 拒绝等距透视手绘地狱!AIGC联动2D图像巨头:2.5D次世代废墟建筑极速量产
  • Agent 在提示工程中的应用:从思维链到 ReAct
  • 小米 miclaw 手机智能体落地,重构智能家居底层逻辑
  • C++ 模板编程入门:从零理解泛型核心
  • 米家 API 使用指南:智能家居设备控制
  • 金仓 KingbaseES 融合架构实践:从多库并存到一库多能
  • AIGC Fooocus 部署实践:本地配置与云端启用对比
  • 模拟退火算法原理与多语言实现
  • C++ STL 容器详解与选型指南
  • MiniMax 海螺 AI 视频:图文生视频功能与 API 接入指南
  • 数据结构初阶:树的概念、术语与表示方法
  • SheetJS JavaScript 电子表格数据处理与转换方案
  • AIGC 在日常生活中的应用与挑战
  • 基于 Java SSM 框架的线上学习网站设计与实现
  • MiniMax 海螺 AI 视频:图片与文本生成高质量视频
  • OpenCLaw Web UI 无法访问 Not Found 问题排查与解决

相关免费在线工具

  • 加密/解密文本

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

  • RSA密钥对生成器

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

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • Mermaid 预览与可视化编辑

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

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online