ArduCopter——ArduPilot——航点导航WPNav(一)

2023-05-16

版权声明:本文为博主原创博文,未经允许不得转载,若要转载,请说明出处并给出博文链接 

 

       现如今,四旋翼飞行器已经从几年前的遥控航模变成真正可以超视距操控的无人机,离不开伟大的通信协议mavlink和最近几年大火的4G与5G。但是这些都要依托一个强大的飞控,开源飞控项目ArduPilot的分支ArduCopter就是一个非常优秀的多旋翼飞控,但是要真正实现无人机的航线规划而后自主飞行,就要着实学习下本博客涉及的航点导航的内容,另外还有一篇ArduCopter——ArduPilot——航点导航WPNav(二)——Spline Navigation

 

../_images/copter-navigation-wpnav-path.png

①下边代码是航点导航的具体实现,被用于上层结构的调用。我们这里不关心上层如何调用,只看如何实现

/// update_wpnav - run the wp controller - should be called at 100hz or higher
bool AC_WPNav::update_wpnav()
{
    bool ret = true;

    // calculate dt
    float dt = _pos_control.time_since_last_xy_update();
    if (dt >= 0.2f) {
        dt = 0.0f;
    }

    // allow the accel and speed values to be set without changing
    // out of auto mode. This makes it easier to tune auto flight
    _pos_control.set_accel_xy(_wp_accel_cmss);
    _pos_control.set_accel_z(_wp_accel_z_cmss);

    // advance the target if necessary
    if (!advance_wp_target_along_track(dt)) {   //航点导航的关键函数
        // To-Do: handle inability to advance along track (probably because of missing terrain data)
        ret = false;
    }

    // freeze feedforwards during known discontinuities
    if (_flags.new_wp_destination) {
        _flags.new_wp_destination = false;
        _pos_control.freeze_ff_z();
    }

    _pos_control.update_xy_controller(1.0f);
    check_wp_leash_length();

    _wp_last_update = AP_HAL::millis();

    return ret;
}

②函数advance_wp_target_along_track是航点导航实现的关键函数,主要是添加目标航点与origin航线中的中间航点还有track_leash的一些限制。

/// advance_wp_target_along_track - move target location along track from origin to destination
bool AC_WPNav::advance_wp_target_along_track(float dt)
{
    float track_covered;        // distance (in cm) along the track that the vehicle has traveled.  Measured by drawing a perpendicular line from the track to the vehicle.
    Vector3f track_error;       // distance error (in cm) from the track_covered position (i.e. closest point on the line to the vehicle) and the vehicle
    float track_desired_max;    // the farthest distance (in cm) along the track that the leash will allow
    float track_leash_slack;    // additional distance (in cm) along the track from our track_covered position that our leash will allow
    bool reached_leash_limit = false;   // true when track has reached leash limit and we need to slow down the target point

    // get current location
    Vector3f curr_pos = _inav.get_position();

    // calculate terrain adjustments
    float terr_offset = 0.0f;
    if (_terrain_alt && !get_terrain_offset(terr_offset)) {
        return false;
    }

    // calculate 3d vector from segment's origin  计算从origin到当前位置的三维向量
    Vector3f curr_delta = (curr_pos - Vector3f(0,0,terr_offset)) - _origin;

    // calculate how far along the track we are 计算飞机沿着航线到达最近点的距离
    track_covered = curr_delta.x * _pos_delta_unit.x + curr_delta.y * _pos_delta_unit.y + curr_delta.z * _pos_delta_unit.z;

    // calculate the point closest to the vehicle on the segment from origin to destination  将上述距离投射到XYZ三个方向上
    Vector3f track_covered_pos = _pos_delta_unit * track_covered;

    // calculate the distance vector from the vehicle to the closest point on the segment from origin to destination 计算飞机到最近点的距离从origin到目的地
    track_error = curr_delta - track_covered_pos;

    // calculate the horizontal error
    _track_error_xy = norm(track_error.x, track_error.y);

    // calculate the vertical error
    float track_error_z = fabsf(track_error.z);

    // get up leash if we are moving up, down leash if we are moving down
    float leash_z = track_error.z >= 0 ? _pos_control.get_leash_up_z() : _pos_control.get_leash_down_z();

    // use pythagoras's theorem calculate how far along the track we could move the intermediate target before reaching the end of the leash
    //   track_desired_max is the distance from the vehicle to our target point along the track.  It is the "hypotenuse" which we want to be no longer than our leash (aka _track_leash_length)
    //   track_error is the line from the vehicle to the closest point on the track.  It is the "opposite" side
    //   track_leash_slack is the line from the closest point on the track to the target point.  It is the "adjacent" side.  We adjust this so the track_desired_max is no longer than the leash
    // 运用 “勾股定理” 计算飞机在触及leash尾端之前可以移动到的中间目标点的距离
    // track_desired_max 是飞机到目标航点的距离,是最长的斜边
    // track_error 是飞机到最近点的直线,是对边
    // track_leash_slack 是最近点到目标航点的距离,是邻边。我们只需要调整邻边,就可以保证斜边不超过leash
    float track_leash_length_abs = fabsf(_track_leash_length);
    float track_error_max_abs = MAX(_track_leash_length*track_error_z/leash_z, _track_leash_length*_track_error_xy/_pos_control.get_leash_xy());
    track_leash_slack = (track_leash_length_abs > track_error_max_abs) ? safe_sqrt(sq(_track_leash_length) - sq(track_error_max_abs)) : 0;
    track_desired_max = track_covered + track_leash_slack;

    // check if target is already beyond the leash
    if (_track_desired > track_desired_max) {
        reached_leash_limit = true;
    }

    // get current velocity
    const Vector3f &curr_vel = _inav.get_velocity();
    // get speed along track
    float speed_along_track = curr_vel.x * _pos_delta_unit.x + curr_vel.y * _pos_delta_unit.y + curr_vel.z * _pos_delta_unit.z;

    // calculate point at which velocity switches from linear to sqrt
    float linear_velocity = _wp_speed_cms;
    float kP = _pos_control.get_pos_xy_p().kP();
    if (is_positive(kP)) {   // avoid divide by zero
        linear_velocity = _track_accel/kP;  //kP可以理解为1/dt
    }

    // let the limited_speed_xy_cms be some range above or below current velocity along track
    if (speed_along_track < -linear_velocity) {
        // we are traveling fast in the opposite direction of travel to the waypoint so do not move the intermediate point
        _limited_speed_xy_cms = 0; //这里的_limited_speed_xy_cms 可以理解为将中间目标点推向最终航点的速度
    }else{
        // increase intermediate target point's velocity if not yet at the leash limit
        if(dt > 0 && !reached_leash_limit) {
            _limited_speed_xy_cms += 2.0f * _track_accel * dt;
        }
        // do not allow speed to be below zero or over top speed
        _limited_speed_xy_cms = constrain_float(_limited_speed_xy_cms, 0.0f, _track_speed);

        // check if we should begin slowing down
        if (!_flags.fast_waypoint) {
            float dist_to_dest = _track_length - _track_desired;
            if (!_flags.slowing_down && dist_to_dest <= _slow_down_dist) {
                _flags.slowing_down = true;
            }
            // if target is slowing down, limit the speed
            if (_flags.slowing_down) {
                _limited_speed_xy_cms = MIN(_limited_speed_xy_cms, get_slow_down_speed(dist_to_dest, _track_accel));
            }
        }

        // if our current velocity is within the linear velocity range limit the intermediate point's velocity to be no more than the linear_velocity above or below our current velocity
        if (fabsf(speed_along_track) < linear_velocity) {
            _limited_speed_xy_cms = constrain_float(_limited_speed_xy_cms,speed_along_track-linear_velocity,speed_along_track+linear_velocity);
        }
    }
    // advance the current target   向前推进当前的目标
    if (!reached_leash_limit) {
    	_track_desired += _limited_speed_xy_cms * dt;

    	// reduce speed if we reach end of leash  如果已经到达了leash的末端就减速
        if (_track_desired > track_desired_max) {
        	_track_desired = track_desired_max;
        	_limited_speed_xy_cms -= 2.0f * _track_accel * dt;
        	if (_limited_speed_xy_cms < 0.0f) {
        	    _limited_speed_xy_cms = 0.0f;
        	}
    	}
    }

    // do not let desired point go past the end of the track unless it's a fast waypoint
    // 除非是快速航点,否则不准理想的中间点超过最终目的地
    if (!_flags.fast_waypoint) {
        _track_desired = constrain_float(_track_desired, 0, _track_length);
    } else {
        _track_desired = constrain_float(_track_desired, 0, _track_length + WPNAV_WP_FAST_OVERSHOOT_MAX);
    }

    // recalculate the desired position
    Vector3f final_target = _origin + _pos_delta_unit * _track_desired;
    // convert final_target.z to altitude above the ekf origin
    final_target.z += terr_offset;
    _pos_control.set_pos_target(final_target);

    // check if we've reached the waypoint  通过reached_destination标志来判断是否到达了航点
    if( !_flags.reached_destination ) {
        if( _track_desired >= _track_length ) {
            // "fast" waypoints are complete once the intermediate point reaches the destination
            if (_flags.fast_waypoint) {
                _flags.reached_destination = true;
            }else{
                // regular waypoints also require the copter to be within the waypoint radius
                Vector3f dist_to_dest = (curr_pos - Vector3f(0,0,terr_offset)) - _destination;
                if( dist_to_dest.length() <= _wp_radius_cm ) {
                    _flags.reached_destination = true;
                }
            }
        }
    }

    // update the target yaw if origin and destination are at least 2m apart horizontally
    // 如果到达目的地的距离超过2m那么就要更新当前目标航向角
    if (_track_length_xy >= WPNAV_YAW_DIST_MIN) {
        if (_pos_control.get_leash_xy() < WPNAV_YAW_DIST_MIN) {
            // if the leash is short (i.e. moving slowly) and destination is at least 2m horizontally, point along the segment from origin to destination
            set_yaw_cd(get_bearing_cd(_origin, _destination));
        } else {
            Vector3f horiz_leash_xy = final_target - curr_pos;
            horiz_leash_xy.z = 0;
            if (horiz_leash_xy.length() > MIN(WPNAV_YAW_DIST_MIN, _pos_control.get_leash_xy()*WPNAV_YAW_LEASH_PCT_MIN)) {
                set_yaw_cd(RadiansToCentiDegrees(atan2f(horiz_leash_xy.y,horiz_leash_xy.x)));
            }
        }
    }

    // successfully advanced along track
    return true;
}

③最后这段代码就是根据位置控制器里面输出的是否需要重新计算leash长度,如果不需要就返回,需要就将位置控制器计算好的leash_xy和leash_z,与根据_pos_delta_unit的水平xy与高度z的相比较的最小数值来计算leash

// check_wp_leash_length - check if waypoint leash lengths need to be recalculated
//  should be called after _pos_control.update_xy_controller which may have changed the position controller leash lengths
void AC_WPNav::check_wp_leash_length()
{
    // exit immediately if recalc is not required
    if (_flags.recalc_wp_leash) {
        calculate_wp_leash_length();
    }
}

/// calculate_wp_leash_length - calculates horizontal and vertical leash lengths for waypoint controller
void AC_WPNav::calculate_wp_leash_length()
{
    // length of the unit direction vector in the horizontal
    float pos_delta_unit_xy = norm(_pos_delta_unit.x, _pos_delta_unit.y);
    float pos_delta_unit_z = fabsf(_pos_delta_unit.z);

    float speed_z;
    float leash_z;
    if (_pos_delta_unit.z >= 0.0f) {
        speed_z = _wp_speed_up_cms;
        leash_z = _pos_control.get_leash_up_z();
    }else{
        speed_z = _wp_speed_down_cms;
        leash_z = _pos_control.get_leash_down_z();
    }

    // calculate the maximum acceleration, maximum velocity, and leash length in the direction of travel
    if(is_zero(pos_delta_unit_z) && is_zero(pos_delta_unit_xy)){
        _track_accel = 0;
        _track_speed = 0;
        _track_leash_length = WPNAV_LEASH_LENGTH_MIN;
    }else if(is_zero(_pos_delta_unit.z)){
        _track_accel = _wp_accel_cmss/pos_delta_unit_xy;
        _track_speed = _wp_speed_cms/pos_delta_unit_xy;
        _track_leash_length = _pos_control.get_leash_xy()/pos_delta_unit_xy;
    }else if(is_zero(pos_delta_unit_xy)){
        _track_accel = _wp_accel_z_cmss/pos_delta_unit_z;
        _track_speed = speed_z/pos_delta_unit_z;
        _track_leash_length = leash_z/pos_delta_unit_z;
    }else{
        _track_accel = MIN(_wp_accel_z_cmss/pos_delta_unit_z, _wp_accel_cmss/pos_delta_unit_xy);
        _track_speed = MIN(speed_z/pos_delta_unit_z, _wp_speed_cms/pos_delta_unit_xy);
        _track_leash_length = MIN(leash_z/pos_delta_unit_z, _pos_control.get_leash_xy()/pos_delta_unit_xy);
    }

    // calculate slow down distance (the distance from the destination when the target point should begin to slow down)
    calc_slow_down_distance(_track_speed, _track_accel);

    // set recalc leash flag to false
    _flags.recalc_wp_leash = false;
}

④ 这里给出pos_delta_unit的由来,其实就是目的地与origin距离的三维向量与该距离的比值

    Vector3f pos_delta = _destination - _origin;

    _track_length = pos_delta.length(); // get track length
    _track_length_xy = safe_sqrt(sq(pos_delta.x)+sq(pos_delta.y));  // get horizontal track length (used to decide if we should update yaw)

    // calculate each axis' percentage of the total distance to the destination
    if (is_zero(_track_length)) {
        // avoid possible divide by zero
        _pos_delta_unit.x = 0;
        _pos_delta_unit.y = 0;
        _pos_delta_unit.z = 0;
    }else{
        _pos_delta_unit = pos_delta/_track_length;
    }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

ArduCopter——ArduPilot——航点导航WPNav(一) 的相关文章

  • ArduPilot飞控之DIY-F450计划

    ArduPilot飞控之DIY F450计划 1 历史2 源由3 计划3 1 硬件3 2 软件 4 动手4 1 接线4 1 1 ELRS nano接收机4 1 2 BN880 GPS模块4 1 3 Radio Telemetry 4 2 配
  • ArduPilot之开源代码Library&Sketches设计

    ArduPilot之开源代码Library amp Sketches设计 1 简介1 1 Core libraries1 2 Sensor libraries1 3 Other libraries 2 源由3 Library Sketche
  • Ardupilot之Mavros实现Ros节点控制(一)

    Ardupilot之Mavros实现Ros节点控制 Mavros安装修改Mavros运行Mavros 这部分ros发布的命令话题参考的是PX4固件最基本的Offboard node节点 xff0c 命令发布后 xff0c 能够连接并解锁 x
  • APM_ArduCopter源码解析学习(一)——ArduCopter主程序

    ArduCopter源码解析学习 xff08 一 xff09 ArduCopter主程序 前言一 准备工作二 Copter cpp解析 2 1 scheduler table2 2 scheduler get scheduler tasks
  • 【Ardupilot (APM)】 Benewake(北醒) TFmini-i CAN 基于PixHawk的运用说明

    目录 一 前言二 TFmini i CAN 配置三 接线四 飞控参数设定4 1 避障的常用设置4 2 避障测试4 3 定高的常用设置4 4 定高测试 五 常见问题 一 前言 TFmini i CAN PixHawk1 CAN 端口或任何已刷
  • ArduPilot Kakute F7 AIO DIYF450 without GPS配置

    ArduPilot Kakute F7 AIO DIYF450 without GPS配置 1 源由2 配置2 1 Kakute F7 AIO相关配置2 1 1 串口规划2 1 2 电传配置2 1 3 GPS配置2 1 4 CRSF接收机配
  • ArduPilot飞控启动&运行过程简介

    ArduPilot飞控启动 amp 运行过程简介 1 源由2 Copter飞控2 1 入口2 3 运行 main loop 3 Ardunio编程3 1 setup AP Vehicle setup3 2 loop AP Vehicle l
  • ardupilot 最优化算法

    目录 文章目录 目录 摘要 1 最小二乘法 1 1定义 1 2 基本思想 1 3 基本原理 1 4举例子 1 5最小二乘法和梯度法区别 2 梯度下降法 2 1 什么是梯度 2 2 什么是梯度下降 3 牛顿迭代法 3 0 牛顿迭代 3 1 牛
  • ardupilot 位置控制(POSHOLD)分析

    目录 文章目录 目录 摘要 0 简介 1 POSHOLD初始化过程 1 刹车增益的计算 2 位置保持不同阶段状态机对应的类型 2 POSHOLD运行过程 2 1 获取需要的飞行输入信息 2 2POSHOLD模式状态机 2 3获取当前的横滚俯
  • Ubuntu给Pix2.4.8刷Ardupilot固件

    全文基于waf编译器使用 waf命令 xff0c APM官网对于waf的使用描述 xff1a https github com ArduPilot ardupilot blob master BUILD md 前提 xff1a 已经在ubu
  • UAV-5--链接飞控以及配置SITL以及ardupilot环境

    linux系统链接飞控以及配置SITL以及ardupilot环境 先更改本机host到对象的ip 再进行ssh的链接 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img meuTGFrN 1651933771950
  • ardupilot之mavlink消息--从飞控发出--单向

    飞控采用mavlink消息进行数据的传输 普遍说法是 xff0c 现有的mavlink消息几乎已经涵盖了所有你的能想象到的内容 xff0c 完全可以覆盖多处需求 无奈科研总是要定义一些新鲜玩意 xff0c 所以总是有无法完全满足需求 xff
  • Ardupilot与T265配置

    摘自 xff1a https www jianshu com p ce91fdec7235 我现在发现这篇文章的原文在这 https www cnblogs com hellocxz p 12104290 html Ardupilot与T2
  • ardupilot & px4 书写自己的app & drivers (二)

    新建任务列表任务 打印时间 任务列表 const AP Scheduler span class hljs tag Task span Copter span class hljs tag scheduler tasks span span
  • Arducopter Yaw角分析

    Arducopter Yaw 现梳理一遍Poshold模式下的yaw的情况 xff1a 首先从 Copter fast loop gt update flight mode gt Copter ModePosHold run span cl
  • Ardupilot添加自定义日志(AP_LOG)

    1 在libraries AP Logger LogStructure h中添加自定义的结构体 span class token keyword struct span span class token class name PACKED
  • 解决多个Ardupilot运行仿真环境冲突问题

    情况说明 分别安装了4 2和4 3两个版本的ardupilot工作环境 xff0c 出现运行4 3版本sim vehicle py时路径链接到4 2版本工作路径 解决 为防止文件识别错误 xff0c 更改sim vehicle py文件名为
  • Ardupilot-SITL仿真模拟调试

    1 配置SITL仿真调试 span class token punctuation span span class token operator span waf configure span class token operator sp
  • 在ubuntu20.4下安装ardupilot 4.3.6

    这次重新安装真的是遇到了好多坑啊 xff01 从github上靠过来按照之前的那篇文章流程做完之后 xff0c 还会有一些别的问题 首先是module里面的包都没有拷过来 xff0c 所以需要用git add将文件都添加过来 之后进行编译时
  • 25B无人直升机调试(Tuning)

    要知道的直升机原理 首先要掌握的5个飞行模式 本文首先调试自稳模式 Stabilize 自稳模式 Alt Hold 定高模式 Loiter OF loiter 悬停模式 RTL Return to Launch 返航模式 Auto 自动模式

随机推荐

  • cmake编译c++程序

    当在Linux系统下编写程序时候 xff0c 如果没有类似于visual studio vs code等IDE 集成开发环境 时 xff0c 如何编译 运行程序呢 xff1f 一种方法是编写makefile文件 xff0c 用makefil
  • #if 0 /#if 1用法介绍(屏蔽代码块)

    当屏蔽掉大块代码时 xff0c 使用 34 if 0 34 比使用 34 34 要好 xff0c 因为用 34 34 做大段的注释要防止被注释掉的代码中有嵌套的 34 34 这会导致注释掉的代码区域不是你想要的范围 xff0c 当被注释掉的
  • 调试工具之UDP/TCP网络调试助手NetAssist

    参考文章列表 xff1a https blog csdn net zhzht19861011 article details 4545260 https blog csdn net qq 29350001 article details 7
  • idea第一次新建SpringBoot项目报错 Error:(3, 32) java: 程序包org.springframework.boot不存在

    跟着网上的教程第一次创建SpringBoot xff0c 创建好之后他们都可以直接写Controller类 xff0c 然后运行就能从localhost访问hello word了 但是我再第一次创建之后 xff0c 出现下面的情况 Erro
  • 本地socket的select用法

    学习socket的select用法 xff0c 下面代码大部分是从网上借鉴的 xff0c 只不过把网络部分的socket改为了本地socket xff0c 并加了一些自己测试用的语句 xff0c 如果有冒犯之处请联系我 xff0c 我立马删
  • C/C++程序编译过程详解

    C C 43 43 程序编译过程详解 C语言的编译链接过程要把我们编写的一个c程序 xff08 源代码 xff09 转换成可以在硬件上运行的程序 xff08 可执行代码 xff09 xff0c 需要进行编译和链接 编译就是把文本形式源代码翻
  • realsense435i运行vins-mono,标定部分

    相机标定 1 安装kalibr xff1b 参考 xff1a https blog csdn net wangbaodong070411209 article details 112248834 https blog csdn net we
  • TX2入门教程软件篇-安装python3.6+

    sudo add apt repository ppa jonathonf python 3 6 sudo apt get update sudo apt get install python3 6 增加python3两个版本的优先级 su
  • Ubuntu 16.04使用Wireshark 抓包分析USB Audio Class 设备流程

    0 前言 为了分析usb麦克风的交互流程 xff0c 需要进行usb抓包 1 安装相关插件 安装usbmon sudo addgroup usbmon sudo gpasswd a USER usbmon echo 39 SUBSYSTEM
  • QT5.5实现串口通信

    QT5 1以上版本自带QtSerialPort集成库 xff0c 只要在头文件中集成 include lt QtSerialPort QSerialPort gt include lt QtSerialPort QSerialPortInf
  • “JTAG Warning: T-bit of XPSR is 0 but should be 1. Changed to 1.” 解决方案

    最近在调试一块GD32F107RCT6 xff0c 无法进行下载 错误提示 xff1a JTAG Warning T bit of XPSR is 0 but should be 1 Changed to 1 1 判断BOOT0 BOOT1
  • Windows无法访问Ubuntu Samba 解决方案

    好久没用Windows访问Ubuntu的共享文件 xff0c 忘记了密码 xff0c 重装Samba后提示Windows无法访问 可以打开文件但是无法访问 查看log var log samba log 192 168 1 39 smbd
  • keil C数组声明问题

    C语言中 xff0c 我们声明一个一维数组 xff0c 可以用以下几种方法 int buf 3 int buf 61 0 int buf 3 61 1 2 3 但是今天在keil中 使用int buf 61 0 这种方式进行声明 xff0c
  • 初学QML之qmlRegisterType

    qmlRegisterType 是一个可以将C 43 43 实现的类在QML中调用的 xff0c 连接C 43 43 和QML的一个工具 首先来看QtAssistant的介绍 int qmlRegisterType const char u
  • 在IDEA中引入jQuery无效

    在idea开发前端页面中 xff0c 引入jQuery后 xff0c 使用 会出现下划线 xff0c 提示未定义 虽然不影响使用 xff0c 运行后可以得到正常结果 xff0c 但还是看的很不爽 解决办法 xff1a Preferences
  • Asterisk WebRTC 搭建指南

    1 WebRTC简介 WEBRTC是一个开源项目 xff0c 其宗旨是让WEB浏览器通过简单的JavaScript具备实时通信 Real Time Communications RTC 的能力 WEBRTC目前支持JS和HTML5 xff0
  • UDP三种通讯方式

    单播 xff1a 单播用于两个主机之间的端对端通信 组播 xff1a 组播用于对一组特定的主机进行通信 广播 xff1a 广播用于一个主机对整个局域网上所有主机上的数据通信 单播实现 发送端 public class SendDemo pu
  • ArduPilot——如何对飞控LOG进行简易振动分析

    版权声明 xff1a 本文为博主原创博文 xff0c 未经允许不得转载 xff0c 若要转载 xff0c 请说明出处并给出博文链接 首先 xff0c 你得先有一架可以飞的且刷的是ArduPilot飞控代码的无人机和地面站Misson Pla
  • SITL Simulator —— ArduPilot —— Windows

    版权声明 xff1a 本文为博主原创博文 xff0c 未经允许不得转载 xff0c 若要转载 xff0c 请说明出处并给出博文链接 参考网页 xff1a http ardupilot org dev docs sitl native on
  • ArduCopter——ArduPilot——航点导航WPNav(一)

    版权声明 xff1a 本文为博主原创博文 xff0c 未经允许不得转载 xff0c 若要转载 xff0c 请说明出处并给出博文链接 现如今 xff0c 四旋翼飞行器已经从几年前的遥控航模变成真正可以超视距操控的无人机 xff0c 离不开伟大