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

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

介绍基于大疆 MSDK 实现无人机视觉引导自适应降落的功能。通过虚拟摇杆替代不支持的 FlyTo 功能进行导航,利用视觉识别计算位置偏移量。采用高度自适应策略,在不同高度段动态调整下降速度与定位精度阈值,并在低空关闭下视避障以确保安全着陆。代码包含方位角计算、距离监测、虚拟摇杆控制及云台调整逻辑。

安卓系统发布于 2026/4/6更新于 2026/5/2129 浏览

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

概述

最初需求:想要无人机在执行完航线任务后,一键落到一个指定的位置,简化人工控制。

实现一套完整的无人机自主降落功能,通过虚拟摇杆控制使无人机飞向指定位置,再利用视觉识别引导无人机精确降落到具体位置。本文中采用自适应降落策略,根据高度动态调整精度要求和下降速度,以实现安全、精确的降落。

核心点:

  • 虚拟摇杆导航替代 FlyTo 功能
  • 双轴 (X/Y) 位置偏移实时调整
  • 高度自适应降落策略
  • 视觉识别引导定位
  • 智能避障管理

系统架构

整体流程
  1. 用户触发 Return to Vehicle 指令。
  2. 获取无人机 GPS 位置并计算与目标点距离。
  3. 启动虚拟摇杆导航,以 5m/s 速度飞向目标位置。
  4. 当距离小于 10m 时,停止导航,开始自适应降落。
  5. 视觉识别系统计算 X/Y 偏移量并更新 ViewModel。
  6. 进入自适应降落循环,根据高度分段判断(高空/中空/低空/极低空)。
  7. 根据偏移量和高度计算调整速度和下降速度。
  8. 若偏移大于阈值 2 倍则停止下降只调整;若超出阈值 1 倍则慢速边调整边下降。
  9. 高度小于 5m 时关闭下视避障。
  10. 高度小于等于 0.1m 时着陆完成并清理资源。

技术实现思路

第一步:让无人机飞到目标位置?
问题分析

遥控器控制的无人机在执行完航线任务之后,飞到给定降落点(汽车或其他载具上)。最初的想法是使用 DJI SDK 提供的 FlyTo 功能,直接指定目标 GPS 坐标让无人机飞过去。但在实际测试中,发现部分机型(如 M3E)并不支持 FlyTo 功能。

解决方案:虚拟摇杆导航

既然 FlyTo 功能不可用,那就用虚拟摇杆功能进行模拟。

思路:

  1. 计算当前位置到目标位置的方位角(bearing)
  2. 将方位角转换为速度分量(南北/东西)
  3. 持续发送虚拟摇杆指令,让无人机朝目标飞行
  4. 实时监测距离,接近目标时停止

方位角计算:

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)
     bearing = Math.toDegrees(Math.atan2(y, x))
    bearing = (bearing + ) %  
     bearing 
}
var
360
360
// 归一化到 0-360 度
return
// 0°=正北,90°=正东,180°=正南,270°=正西

速度分量计算:

val bearing = calculateBearing(currentLat, currentLon, targetLat, targetLon)
val bearingRad = Math.toRadians(bearing)
// 使用 GROUND 坐标系 (地面坐标系)
val navParam = VirtualStickFlightControlParam().apply {
    rollPitchCoordinateSystem = FlightCoordinateSystem.GROUND
    verticalControlMode = VerticalControlMode.POSITION
    yawControlMode = YawControlMode.ANGLE
    rollPitchControlMode = RollPitchControlMode.VELOCITY
    // 将速度分解为南北和东西分量
    pitch = NAVIGATION_SPEED * Math.cos(bearingRad) // 南北分量 (5m/s)
    roll = NAVIGATION_SPEED * Math.sin(bearingRad) // 东西分量 (5m/s)
    yaw = bearing // 让机头指向目标
    verticalThrottle = targetAlt
}
  • GROUND 坐标系是绝对方向,不受无人机朝向影响
  • pitch 控制南北,roll 控制东西。

第二步:判断何时到达目标点上方附近
持续监测距离

每 100ms 检查一次当前位置与目标的距离,距离小于预期值 ARRIVAL_THRESHOLD,就认为无人机已到达目标点上方附近,停止导航,开始降落:

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)
        }
    }
}

第三步:精确降落到指定点

无人机虽然到了目标附近 (10 米内),但有以下问题:

  1. GPS 精度有限(±3 米),不够精确。
  2. 风力影响,有时候受风的影响,无人机会偏离。
解决方案:视觉识别 + 位置调整

工作原理:

  1. 无人机摄像头识别地面的特定图像(如二维码、标记点)
  2. 视觉算法计算偏移量(X 轴左右,Y 轴前后,Z 轴距图像距离)
  3. 将偏移量传给无人机
  4. 无人机调整位置,边降落边对准

数据结构:

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

外部接口:

// 视觉识别系统调用这些方法更新偏移量 (~1Hz)
fun setXOffset(offset: Double) { xOffset = offset }
fun setYOffset(offset: Double) { yOffset = offset }
fun setZDistance(distance: Double) { zDistance = distance }
采用自适应策略,一边降落一遍调整

关键点:
在不同的高度,我们允许的偏移量阈值不同的,高度较高的时候,偏移量就算比较大也可以下降,随着高度降低,我们允许的偏移量阈值会不断缩小(要求越来越向中间对齐)

真实偏移超出偏移量阈值的 2 倍就停止下降,只进行对齐调整;
真实偏移超出偏移量的 1 倍,就以 0.1m/s 的慢速一边降落一边调整;
在偏移量范围内,且高度> 20m,以 0.5m/s 的速度快速下降;
在偏移量范围内,且高度在 5m-20m 之间,以 0.2m/s 的速度下降;
在偏移量范围内,且高度< 5m,以 0.2m/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 // 极低空:极慢降
    }
}

控制逻辑:

  • 大于 50m / 20-50m / 5-20m / 小于 5m:高度判断
  • 偏移大于阈值的 2 倍:停止下降,只调整
  • 偏移大于阈值:慢降 0.1m/s 并且调整
  • 偏移小于阈值:快降并且微调
  • 高度小于等于 0.1m:着陆完成

第四步:处理避障,降落后停桨。
问题:下视避障会阻止降落

无人机的下视避障系统会将地面识别为障碍物,在接近地面时自动停止下降,我们在高度为 5m 的时候关闭下视避障,落到地面后调用 KeyStartAutoLanding 进行停桨。

低空时关闭下视避障
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) {
        Log.e("Perception", "方向参数为空,无法设置避障")
        return
    }
    PerceptionManager.getInstance().setObstacleAvoidanceEnabled(
        enabled,
        direction,
        object : CommonCallbacks.CompletionCallback {
            override fun onSuccess() {
                toastResult?.postValue(DJIToastResult.success("成功设置【${direction.name}】方向的避障为:${if(enabled)"开启"else"关闭"}"))
                Log.i("Perception", "成功设置【${direction.name}】方向的避障为:${if(enabled)"开启"else"关闭"}")
            }
            override fun onFailure(error: IDJIError) {
                downwardObstacleDisabled = false
                toastResult?.postValue(DJIToastResult.failed("设置【${direction.name}】方向的避障失败:$error"))
                Log.e("Perception", "设置【${direction.name}】方向的避障失败:$error")
            }
        }
    )
}

第五步:降落循环完整逻辑
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 后再次执行 (10Hz)
            virtualStickHandler?.postDelayed(this, 100)
        }
    }
    virtualStickHandler?.post(adjustTask)
}

以上,就实现了一整套视觉引导的自适应降落方案

安全注意事项

WARNING

  1. 必须在空旷、安全环境测试
  2. 建议先用 DJI 模拟器测试
  3. 视觉识别必须持续更新 (~1Hz)
  4. 准备好随时手动接管
代码示例
/**
 * One-key return to vehicle function (using Virtual Stick instead of FlyTo)
 * 1. Get aircraft current location
 * 2. Calculate distance to vehicle using Haversine formula
 * 3. If distance > 500m, reject with error
 * 4. Use Virtual Stick to navigate to vehicle location
 * 5. Switch to precision adjustment when close enough
 */
fun returnToVehicle(callback: CommonCallbacks.CompletionCallback) {
    // Get aircraft current location
    val aircraftLocation = getAircraftLocation()
    if (aircraftLocation == null || !isLocationValid(aircraftLocation.latitude, aircraftLocation.longitude)) {
        callback.onFailure(DJICommonError.FACTORY.build("无法获取无人机位置信息"))
        return
    }
    // Vehicle coordinates (hardcoded for now, will be replaced with API later)
    // TODO: Replace with actual vehicle GPS coordinates from API
    val vehicleLatitude = 22.579 // Example coordinates
    val vehicleLongitude = 113.941 // Example coordinates
    // Calculate distance using Haversine formula
    val distance = calculateDistance(
        aircraftLocation.latitude,
        aircraftLocation.longitude,
        vehicleLatitude,
        vehicleLongitude
    )
    // Distance validation: reject if > 500m
    if (distance > 500) {
        callback.onFailure(DJICommonError.FACTORY.build("距离过远:${String.format("%.2f", distance)}m, 超出 500m 限制"))
        return
    }
    // Start virtual stick navigation to vehicle location
    toastResult?.postValue(DJIToastResult.success("开始飞向车辆位置"))
    //TODO 这个 targetAlt 需要后期经过计算算出来。
    navigateToTarget(vehicleLatitude, vehicleLongitude, 100.0, callback)
}

/**
 * Navigate to target location using Virtual Stick
 */
private fun navigateToTarget(
    targetLat: Double,
    targetLon: Double,
    targetAlt: Double,
    callback: CommonCallbacks.CompletionCallback
) {
    VirtualStickManager.getInstance().enableVirtualStick(object : CommonCallbacks.CompletionCallback {
        override fun onSuccess() {
            VirtualStickManager.getInstance().setVirtualStickAdvancedModeEnabled(true)
            isNavigating = true
            startNavigation(targetLat, targetLon, targetAlt, callback)
        }
        override fun onFailure(error: IDJIError) {
            callback.onFailure(error)
        }
    })
}

/**
 * Start navigation loop using Virtual Stick
 */
private fun startNavigation(
    targetLat: Double,
    targetLon: Double,
    targetAlt: Double,
    callback: CommonCallbacks.CompletionCallback
) {
    virtualStickHandler = Handler(Looper.getMainLooper())
    val navTask = object : Runnable {
        override fun run() {
            if (!isNavigating) return
            val currentLoc = getAircraftLocation()
            if (currentLoc == null) {
                virtualStickHandler?.postDelayed(this, 100)
                return
            }
            // Calculate remaining distance
            val remainingDistance = calculateDistance(
                currentLoc.latitude,
                currentLoc.longitude,
                targetLat,
                targetLon
            )
            println("targetLat:" + targetLat + " targetLon:" + targetLon + " currentLoc.latitude:" + currentLoc.latitude + " currentLoc.longitude:" + currentLoc.longitude + " remainingDistance:" + remainingDistance)
            // Check if arrived
            if (remainingDistance < ARRIVAL_THRESHOLD) {
                // Arrived at target, stop navigation
                isNavigating = false
                virtualStickHandler?.removeCallbacksAndMessages(null)
                callback.onSuccess()
                toastResult?.postValue(DJIToastResult.success("已到达车辆位置,开始精确定位"))
                //开始调节云台角度,俯仰角为 -90°,旋转时间 1s
                startGimbalAngleRotation(GimbalAngleRotationMode.ABSOLUTE_ANGLE, -90.0, 0.0, 0.0, 1.0)
                // Start precision adjustment
                startDynamicAdjustment()
            } else {
                // Continue navigation
                val bearing = calculateBearing(
                    currentLoc.latitude,
                    currentLoc.longitude,
                    targetLat,
                    targetLon
                )
                val navParam = VirtualStickFlightControlParam().apply {
                    rollPitchCoordinateSystem = FlightCoordinateSystem.GROUND // Use ground coordinate system
                    verticalControlMode = VerticalControlMode.POSITION
                    yawControlMode = YawControlMode.ANGLE
                    rollPitchControlMode = RollPitchControlMode.VELOCITY
                    // Calculate velocity components based on bearing
                    val bearingRad = Math.toRadians(bearing)
                    pitch = NAVIGATION_SPEED * Math.sin(bearingRad) // North-South component
                    roll = NAVIGATION_SPEED * Math.cos(bearingRad) // East-West component
                    yaw = bearing // Point towards target
                    verticalThrottle = targetAlt // Target altitude
                }
                VirtualStickManager.getInstance().sendVirtualStickAdvancedParam(navParam)
                virtualStickHandler?.postDelayed(this, 100)
            }
        }
    }
    virtualStickHandler?.post(navTask)
}

fun startGimbalAngleRotation(
    mode: GimbalAngleRotationMode,
    pitch: Double,
    yaw: Double,
    roll: Double,
    duration: Double
) {
    val rotation = GimbalAngleRotation().apply {
        setMode(mode)
        setPitch(pitch)
        setYaw(yaw)
        setRoll(roll)
        setDuration(duration)
    }
    KeyManager.getInstance().performAction(
        KeyTools.createKey(GimbalKey.KeyRotateByAngle),
        rotation,
        object : CommonCallbacks.CompletionCallbackWithParam<EmptyMsg> {
            override fun onSuccess(result: EmptyMsg?) {
                toastResult?.postValue(DJIToastResult.success("云台旋转成功"))
                Log.i("Gimbal", "云台旋转成功:yaw:${rotation.yaw},pitch:${rotation.pitch},roll:${rotation.roll}")
            }
            override fun onFailure(error: IDJIError) {
                toastResult?.postValue(DJIToastResult.failed("云台旋转失败,$error"))
                Log.e("Gimbal", "云台旋转失败,$error")
            }
        }
    )
}

/**
 * Start dynamic position adjustment loop with adaptive descent
 * Adjusts position while descending, with stricter requirements at lower altitudes
 */
private fun startDynamicAdjustment() {
    isAdjusting = true
    virtualStickHandler = Handler(Looper.getMainLooper())
    // Send adjustment commands at 10Hz
    val adjustTask = object : Runnable {
        override fun run() {
            if (!isAdjusting) return
            // TODO 获取脚本检测出的 z 轴距离
            val currentAltitude = FlightControllerKey.KeyAltitude.create().get(0.0)
            val currentXOffsetAbs = Math.abs(xOffset)
            val currentYOffsetAbs = Math.abs(yOffset)
            //关闭降落保护,下视避障失效
            if (currentAltitude <= 5 && !downwardObstacleDisabled) {
                downwardObstacleDisabled = true
                setObstacleAvoidanceEnable(false, PerceptionDirection.DOWNWARD)
            }
            // 检查是否落地
            if (currentAltitude <= 0.1) {
                stopLanding()
                return
            }
            // Get adaptive thresholds based on altitude
            val offsetThreshold = getOffsetThreshold(currentAltitude)
            val descentSpeed = getDescentSpeed(currentAltitude, currentXOffsetAbs, currentYOffsetAbs)
            // Log for debugging
            println("自动调整 - 高度:%.2fm, x 偏移:%.2fm,y 偏移:%.2fm, 阈值:%.2fm, 下降速度:%.2fm/s".format(
                currentAltitude,
                currentXOffsetAbs,
                currentYOffsetAbs,
                offsetThreshold,
                descentSpeed
            ))
            // Calculate adjustment parameters
            val adjustParam = VirtualStickFlightControlParam().apply {
                rollPitchCoordinateSystem = FlightCoordinateSystem.BODY
                verticalControlMode = VerticalControlMode.VELOCITY
                yawControlMode = YawControlMode.ANGULAR_VELOCITY
                rollPitchControlMode = RollPitchControlMode.VELOCITY
                // Calculate roll value based on offset
                // Positive offset (need to move forward) -> positive roll
                // Negative offset (need to move backward) -> negative roll
                if (currentXOffsetAbs > offsetThreshold) {
                    // Need adjustment
                    roll = if (xOffset > 0) ADJUSTMENT_SPEED else -ADJUSTMENT_SPEED
                } else {
                    // Within threshold, no adjustment needed
                    roll = 0.0
                }
                if (currentYOffsetAbs > offsetThreshold) {
                    pitch = if (yOffset > 0) ADJUSTMENT_SPEED else -ADJUSTMENT_SPEED
                } else {
                    pitch = 0.0
                }
                yaw = 0.0
                verticalThrottle = -descentSpeed // Descend at adaptive speed
            }
            VirtualStickManager.getInstance().sendVirtualStickAdvancedParam(adjustParam)
            virtualStickHandler?.postDelayed(this, 100)
        }
    }
    virtualStickHandler?.post(adjustTask)
    toastResult?.postValue(DJIToastResult.success("开始动态位置调整"))
}

/**
 * Stop landing and cleanup
 */
private fun stopLanding() {
    virtualStickHandler?.removeCallbacksAndMessages(null)
    //调用 KeyStartAutoLanding 进行停桨
    FlightControllerKey.KeyStartAutoLanding.create().action(
        {
            toastResult?.postValue(DJIToastResult.success("桨叶动力关闭"))
            Log.i("stopLanding", "桨叶动力关闭成功")
        },
        {
            toastResult?.postValue(DJIToastResult.failed("桨叶动力关闭失败"))
            Log.i("stopLanding", "桨叶动力关闭失败!!")
        }
    )
    cleanupVirtualStick()
    toastResult?.postValue(DJIToastResult.success("降落完成"))
}

/**
 * Get offset threshold based on current altitude
 * Higher altitude allows larger offset, lower altitude requires stricter precision
 */
private fun getOffsetThreshold(altitude: Double): Double {
    return when {
        altitude > HIGH_ALTITUDE -> 1.0 // High altitude: allow 1m offset
        altitude > MID_ALTITUDE -> 0.5 // Mid altitude: allow 0.5m offset
        altitude > LOW_ALTITUDE -> 0.4 // Low altitude: allow 0.3m offset
        else -> 0.3 // Very low altitude: require 0.2m precision
    }
}

/**
 * Get descent speed based on current altitude and offset
 * Larger offset or lower altitude results in slower descent
 */
private fun getDescentSpeed(altitude: Double, xOffset: Double, yOffset: Double): Double {
    val threshold = getOffsetThreshold(altitude)
    return when {
        xOffset > threshold * 2 || yOffset > threshold * 2 -> 0.0 // Offset too large: stop descending
        xOffset > threshold || yOffset > threshold -> 0.1 // Offset large: slow descent
        altitude > MID_ALTITUDE -> 0.5 // Mid-high altitude: fast descent
        altitude > LOW_ALTITUDE -> 0.2 // Low altitude: slow descent
        else -> 0.1 // Very low altitude: very slow descent
    }
}

目录

  1. 基于大疆 MSDK 实现的无人机视觉引导自适应降落功能
  2. 概述
  3. 系统架构
  4. 整体流程
  5. 技术实现思路
  6. 第一步:让无人机飞到目标位置?
  7. 问题分析
  8. 解决方案:虚拟摇杆导航
  9. 第二步:判断何时到达目标点上方附近
  10. 持续监测距离
  11. 第三步:精确降落到指定点
  12. 解决方案:视觉识别 + 位置调整
  13. 采用自适应策略,一边降落一遍调整
  14. 第四步:处理避障,降落后停桨。
  15. 问题:下视避障会阻止降落
  16. 低空时关闭下视避障
  17. 第五步:降落循环完整逻辑
  18. 安全注意事项
  19. 代码示例
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • Python 中文分词利器:jieba 库快速入门与实战指南
  • Web 应用全栈开发实践:从前端到后端
  • Stable Diffusion 3.5 工业设计实战:产品草图生成系统
  • FPGA 工程应用经验解析:软件程序与通信协议
  • 现代 C++ constexpr 特性演进:从 C++11 到 C++20
  • AIGC 技术在元宇宙与虚拟世界中的应用与实现
  • 机器学习模型评估:8 种算法对比实战
  • CogVideoX-2b 一键 WebUI 使用体验
  • 解决浏览器可访问但 Git 无法克隆的问题
  • Java Web 蛋糕商城系统设计与实现
  • 使用 OVITO-Python 进行 LAMMPS 后处理:统计 Type=1 原子沿 X 方向密度分布
  • FastDFS 分布式存储系统入门详解
  • Python 数据分析全流程指南:从数据获取到可视化分析
  • Z-Image-Turbo 驱动虚拟现实场景资产自动化生成路径
  • 前端函数防抖详解:原理、手写实现与 Lodash 应用
  • QUEST 一体机 SideQuest 安装 APK 与 OBB 数据包教程
  • OpenClaw Secure DM Pairing:构建 AI 机器人安全私信访问机制
  • 嵌入式 CAN 通信:C++ 与 SocketCAN 的现代封装实践
  • 数据结构实战:顺序表原理与 C/C++ 实现
  • Delphi 程序与 AI 大模型交互实践

相关免费在线工具

  • 加密/解密文本

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

  • RSA密钥对生成器

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

  • Mermaid 预览与可视化编辑

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

  • 随机西班牙地址生成器

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

  • Gemini 图片去水印

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

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online