ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

无人直升机任务规划与控制系统教案:从航点到串级PID实践

无人直升机任务规划与控制系统教案:从航点到串级PID实践 简介这份《无人直升机任务规划与控制系统学习教案》以PPT形式面向无人机相关专业的教师、学生及工程技术人员解决从系统架构到实操控制的整体认知问题适合教学备课、课程自学与岗位培训等场景。压缩包内仅1个PPTX演示文稿约262KB以图文分页形式编排逐节梳理概念、组成与设计原则便于课堂演示与快速查阅。目前已有95人学习。内容围绕控制站这一核心展开先讲指挥调度、任务规划、操纵控制与显示记录四大功能再拆解指挥处理中心、无人机控制站、载荷控制站与单收站的组成关系及一站一机、一站多机等操控模式随后给出通用化系列化的设计要求与人机工程布置原则。操纵与控制部分覆盖起降操纵、舵面遥控、姿态遥控、指令控制、自主飞行与组合控制等方式并延伸至任务设备控制与数据链管理显示章节介绍参数综合显示、告警等级与地图航迹显示。全篇共25页层次清晰可帮助读者建立系统级概念框架并理解关键操作流程。1. 无人直升机任务规划与控制系统的教案为什么不能只讲框图带过一轮无人机课程的老师大概都遇到过同一个场景PPT 里把任务规划、姿态控制、串级 PID 讲得条理分明学生点头如捣蒜一旦要求他们自己写代码让一架无人直升机从起飞点依次飞过三个航点再稳稳悬停教室里就集体卡壳。问题往往不在学生而在教案的切法——框图回答的是系统长什么样学生缺的是我这段代码该写在哪儿、参数该改成几。无人直升机任务规划与控制系统这门课真正难的不是某个算法而是三层之间的接口任务规划层给出航点与航迹控制层要把它翻译成总距、周期变距和尾桨距验证层再回过头判断到底飞得合不合格。这三层各自都能找到教材但拼在一起的教案很少学生于是学了一堆孤立的框图。适合读下去的人有三类给高年级本科生或研究生上飞控、自动控制课程的老师带飞控方向毕业设计的指导老师以及做过基于 STM32 的环境温湿度监测控制系统的设计这类单回路课题、想往多回路飞控跨的工程师。从单回路到串级回路台阶比想象中平缓缺的只是一条能跑起来的路径。2. 教案骨架从能力矩阵倒推无人直升机任务规划与控制系统的章节2.1 从能力矩阵倒推目录教案的第一张表绝大多数教案是照着教材目录写的第一章绪论第二章建模第三章控制……这种顺序对老师友好对学生不友好因为学生看不到学完这一章我能做什么。我的做法是先写一张能力矩阵把每一块能力对应的验证方式和学时定死再倒推章节顺序。矩阵写不出来说明这门课的产出还没想清楚。模块能力目标验证方式建议学时坐标系与建模能在 WGS84 / ENU / NED 间转换写出简化六自由度方程手推 单元测试4任务规划把一组航点转成满足最小转弯半径的可飞航迹处理禁飞区航迹图 约束检查脚本8控制系统整定串级 PID理解总距/周期变距/尾桨距的耦合阶跃响应曲线10仿真验证搭 SIL 回路注入风扰、噪声与舵机限幅轨迹重合度报告6这张表最大的价值在于它逼着教案回答一个问题任务规划和控制这两块到底谁先讲。我的选择是规划先讲、控制后讲但第一节课就把完整的仿真回路跑给学生看一遍让他们先知道终点长什么样。反过来先讲控制的教案学生往往到学期末还不知道自己调的这组参数最后被谁用。2.2 最小可跑环境三行命令搭起任务规划与控制系统的实验台第一节课最忌讳的是花三天配环境。ROS、Gazebo、飞控固件源码这套组合对研究生都算门槛对本科生就是劝退。我的教案里前四周只用 Python 加三个库第三周再引入 MAVLink 报文层面的内容。python -m venv .venv source .venv/bin/activate # Windows 用 .venv\Scripts\activate pip install numpy scipy matplotlib # 需要解析飞控报文、生成航点文件时再装 pip install pymavlink环境越小学生改一行参数就能立刻在曲线上看到变化这种即时反馈才是教学效率的来源。numpy 负责矩阵运算和控制器里的向量化scipy 提供solve_continuous_are这类求解器LQR 章节直接调用不用自己写 Riccati 迭代matplotlib 负责把航迹和姿态曲线画出来学期末的实验报告基本靠它出图。提示教案里要明确写死不依赖任何在线仿真平台。学生宿舍网络条件参差不齐一旦环境配置失败第一次作业就会有人掉队后面几周补不回来。2.3 坐标系约定NED、ENU 与 WGS84 的转换必须先统一教这门课踩过的最大坑是学生把 NED 的 z 轴当成高度用结果规划出来的航点全在地下仿真时直升机一头扎进地面。坐标系必须在第二节就讲透而且要配代码不能只画一张三轴图。import numpy as np def enu_to_ned(v_enu): ENU(东,北,天) - NED(北,东,地)纯旋转 e, n, u v_enu return np.array([n, e, -u]) def geodetic_to_ned(lat, lon, alt, lat0, lon0, alt0): 小范围10 km 内用等距圆柱近似把经纬高转成局部 NED单位 m R 6378137.0 # WGS84 长半轴 north np.radians(lat - lat0) * R # 纬度 1 度约 111.3 km east np.radians(lon - lon0) * R * np.cos(np.radians(lat0)) down -(alt - alt0) # NED 的天向下所以取负 return np.array([north, east, down])R取长半轴是近似纬度方向上的误差在几公里范围内可以忽略cos(lat0)是经度收缩因子没有它在高纬度地区东西向的距离会被高估几倍这一点在课堂上要拿北京和广州两个纬度各算一遍给学生看。down取负号是最容易写反的地方教案里最好安排一次故意写错的演示让学生亲眼看到航迹怎么翻到地面以下。坐标系统一之后后面所有模块都有了共同语言任务规划吐出的航点是 WGS84 经纬高控制层用的是局部 NED 的位置和速度两者之间就靠这个函数来回换。3. 任务规划模块从航点表到可飞航迹的无人直升机实现路径3.1 MAVLink 航点字段任务规划层的最小指令集讲任务规划抽象的路径规划四个字很难落地最好直接落到航点数据结构上。MAVLink 的MISSION_ITEM字段不多但每一个都能牵出一类教学点。字段含义无人直升机上的注意点seq航点序号从 0 递增序号跳号会被飞控拒绝教案里专门做一次错误示范frame坐标系如 GLOBAL_RELATIVE_ALT用相对高度还是海拔直接决定会不会撞地command动作码NAV_TAKEOFF 起飞、NAV_WAYPOINT 过点、NAV_LOITER_TIME 盘旋等待param1~4动作参数悬停时间、转弯半径、到达后的偏航角x, y, z经纬度与高度z 单位是米且为正别和 NED 的 down 混autocontinue是否自动执行下一条演示时置 1学生单步调试时置 0把动作码收敛到四五个学生就能拼出一条起飞—过点—盘旋—返航—降落的完整航线任务规划层的最小指令集就建立起来了。这一步不要求他们理解协议栈只需要知道航点表长什么样、错一个字段会怎样。3.2 最小转弯半径约束用圆弧过渡把折线航点拉成可飞航迹航点表给出来的是折线折线对无人直升机是不可飞的它不能原地拐直角。转弯受最大偏航角速率限制最小转弯半径R v / ω_max。巡航速度 10 m/s、最大偏航角速率 0.5 rad/s对应的 R 就是 20 m小于这个半径的转弯飞控要么切圆超调要么直接退出航点模式。import numpy as np def corner_arc(p_prev, p_cur, p_next, R, n20): 在 p_cur 拐角处插入半径 R 的圆弧过渡返回替代折角的采样点 v1 p_cur - p_prev; v1 v1 / np.linalg.norm(v1) # 入方向 v2 p_next - p_cur; v2 v2 / np.linalg.norm(v2) # 出方向 theta np.arccos(np.clip(np.dot(-v1, v2), -1.0, 1.0)) # 转角 if theta 1e-3: # 近似直线不用插 return np.array([p_cur]) tan_d R / np.tan(theta / 2.0) # 切点到角点的距离 a p_cur - v1 * tan_d # 入切点 b p_cur v2 * tan_d # 出切点 bis v2 - v1; bis bis / np.linalg.norm(bis) # 角平分线方向 center p_cur bis * (R / np.sin(theta / 2.0)) # 圆心 ang_a np.arctan2(a[1] - center[1], a[0] - center[0]) ang_b np.arctan2(b[1] - center[1], b[0] - center[0]) ang np.linspace(ang_a, ang_b, n) # 短弧方向采样 return np.column_stack([center[0] R * np.cos(ang), center[1] R * np.sin(ang)])tan_d决定圆弧从哪里开始切入转角越小、半径越大切点回退得越远所以大半径的圆弧会把整条航迹撑开。bis是角平分线方向圆心一定在这条线上距离角点R / sin(θ/2)这个关系课堂上可以用几何法推一遍学生自己推过一遍就不会再写错圆心的正负号。左右转弯用同一个公式即可因为bis的方向会随出方向自动翻转。教学上最有价值的操作是让学生把 R 从 5 m 一路改到 50 m把几组航迹画在同一张图上R 太小航迹尖锐但飞控跟不上R 太大航迹明显偏离原航点、可能压到禁飞区。这个膨胀过程一画出来参数与约束的关系就不用再解释了。3.3 禁飞区、爬升与调度代价函数与三个规划层级的分工几何可飞只解决了一半问题另一半是约束。栅格 A* 是教案里最合适的起点因为代价函数可以写得非常直白学生一眼就能看出每一项管什么。def step_cost(p, q, no_fly, w(1.0, 50.0, 0.5, 0.3)): 栅格 A* 单步代价w (距离, 禁飞区, 爬升, 转弯) wd, wn, wh, wt w d np.linalg.norm(q[:2] - p[:2]) c wd * d if any(np.linalg.norm(q[:2] - c0) r0 for c0, r0 in no_fly): c wn # 禁飞区写成极高代价的软约束 c wh * abs(q[2] - p[2]) # 高度变化惩罚抑制频繁爬升 return c禁飞区写成 50 倍的高代价而不是无穷大是为了让 A* 在无解时还能给出最不坏的航迹课堂上正好借这个差异讨论硬约束和软约束的取舍。wh抑制爬升不是随手给的无人直升机爬升阶段的功率需求远高于平飞爬升惩罚偏小规划器就爱走翻山越岭的路线实际续航直接崩掉。任务规划其实分三个层级教案里最好用一张表把它们钉死免得学生把算法和层级混为一谈。层级输出典型算法时间尺度教学重点任务级航点序列与动作状态机、任务调度分钟级交通灯控制系统那套有限状态机思路几乎可直接搬用航迹级几何可飞曲线A*、Dubins、RRT秒级约束如何进入代价函数轨迹级带时间的状态序列多项式、MPC毫秒至秒级与控制器接口的时间对齐任务级的调度逻辑换个对象就是资源分配把航点看成车位、航线看成车道PLC 停车场车位控制系统里那套先到先服务加就近分配的策略套到多机任务分配上完全能用学生有过 PLC 或单片机课程背景的话这一节的接受度会高得多。4. 控制系统章节无人直升机串级回路怎么讲、参数怎么整定4.1 直升机与多旋翼的操纵差异一张表讲清耦合很多人把无人直升机当成竖起来的四旋翼来教这是控制章节最容易翻车的地方。多旋翼靠转速差产生力矩直升机靠总距、周期变距和尾桨距操纵量与姿态之间的耦合强得多悬停时俯仰几度就能带来明显的前飞速度而且改变总距会同时改变反扭矩、进而改变航向。操纵量直接影响主要耦合课堂演示总距主旋翼升力、垂速反扭矩增大需尾桨补偿悬停时加油门会不会掉高度横向周期变距滚转、侧向速度与偏航耦合侧飞时航向缓慢漂移纵向周期变距俯仰、前飞速度与垂速耦合前飞瞬间掉高度尾桨距偏航与垂速耦合蹬舵引起高度变化这张表的作用是提前给学生打预防针单回路那套一个输入对一个输出的直觉在这里会失效。做过风力摆控制系统的人在这里反而有优势因为风力摆本质就是单轴姿态环的极简版把它扩成三轴再补上耦合项思路是连续的。4.2 串级 PID 的实现与从内到外的整定顺序控制器章节的核心不是 PID 公式而是回路结构和整定顺序。位置环输出速度设定值速度环输出姿态角设定值姿态角环输出角速率设定值角速率环直接输出舵量——四层串级一层套一层。整定必须从内向外外层整定的时候内层要么已经闭环且足够快要么干脆给固定设定值。import numpy as np class PID: def __init__(self, kp, ki, kd, limit): self.kp, self.ki, self.kd kp, ki, kd self.limit limit # 同时用于输出限幅和积分限幅 self.i 0.0 self.prev_e None def __call__(self, sp, x, dt): e sp - x self.i np.clip(self.i e * dt, -self.limit, self.limit) # 抗积分饱和 d 0.0 if self.prev_e is None else (e - self.prev_e) / dt self.prev_e e return np.clip(self.kp * e self.ki * self.i self.kd * d, -self.limit, self.limit)抗积分饱和是必须写进代码的不是可选优化。舵机行程有限位置环长时间存在偏差时积分项会一直累积等偏差反向时输出需要很久才能退出饱和表现出来就是过点后大幅超调再慢慢绕回来这个现象在课堂上演示一次比讲十遍理论管用。整定的量级参考如下教案里必须同时注明单位和适用条件。回路输入到输出Kp 量级Ki 量级Kd 量级主要看什么角速率 p/q/r角速率误差到舵量1~50~0.50.01~0.1超调小于 10%相位滞后可接受姿态角 φ/θ角度误差到角速率设定2~80~0.20~0.05稳态误差与振荡频率垂速 w垂速误差到总距0.5~20.1~0.50~0.05与总距限幅的配合水平位置位置误差到速度设定0.3~1.50~0.050~0.1航迹跟踪误差注意这些量级跟机型、角度单位弧度还是度、舵机行程强相关。教案里要写明以本课样例模型为准换机型必须重新标定别让学生背成通用常数。4.3 LQR 与 MPC 的引入时机Q、R 怎么给讲到位置环学生一定会问多变量耦合怎么办这就是 LQR 的切入点。前提是先有一个在悬停点线性化的模型教案配套一个模型导出脚本把 A、B 矩阵落成 CSV课堂上直接读。import numpy as np from scipy.linalg import solve_continuous_are # 悬停点线性化x [u, v, w, p, q, r, phi, theta, psi] A np.loadtxt(A_hover.csv, delimiter,) B np.loadtxt(B_hover.csv, delimiter,) Q np.diag([1, 1, 2, 0.5, 0.5, 0.5, 10, 10, 5]) # 角度权重给大姿态优先收敛 R np.diag([1.0, 1.0, 1.0, 0.5]) # 四个操纵量的代价 P solve_continuous_are(A, B, Q, R) # 代数 Riccati 方程 K np.linalg.inv(R) B.T P print(LQR 增益 K:\n, np.round(K, 3))Q里位置项给 1、角度项给 10是因为姿态是内环必须比位置收敛得快一个量级否则外环还没等到姿态稳定就开始发新指令整个回路会互相打架。R越大越省舵面、响应越慢调小则响应快但舵机动作频繁和 4.4 的速率限幅直接相关。这个例子里状态是九维、输入是四维K 是 4×9 的矩阵课堂上让学生改Q的某一个对角元观察闭环极点在复平面上怎么移动比让他们推导 Riccati 方程有意义得多。4.4 混控矩阵与限幅控制器输出到舵机的最后一步控制器算出的是力矩或姿态指令落到执行机构前还要过混控和限幅。混控矩阵在教案里可以给一个简化版重点是让学生看清哪一路被谁影响。import numpy as np # 输入顺序 [滚转, 俯仰, 偏航, 总距]输出四通道舵量 MIX np.array([ [0.0, 0.0, 0.0, 1.0], # 总距 [0.0, 1.0, 0.0, 0.1], # 纵向周期变距随总距略微联动 [1.0, 0.0, 0.0, 0.0], # 横向周期变距 [0.0, 0.0, 1.0, 0.2], # 尾桨距补偿总距带来的反扭矩 ]) def mix_and_limit(u, rate_max2.0, dt0.01, prevNone): ch MIX np.asarray(u, dtypefloat) ch np.clip(ch, -1.0, 1.0) # 位置限幅 if prev is not None: # 速率限幅模拟舵机跟不上 ch prev np.clip(ch - prev, -rate_max * dt, rate_max * dt) return np.clip(ch, -1.0, 1.0)矩阵第四列的两个小系数表示总距变化会带动纵向和尾桨通道做补偿真机上的混控远比这复杂教案里不必追求一致重点是让学生看到解耦不是免费的。速率限幅是最容易被跳过、结果在真机上最致命的一环控制器算出来的舵量变化率超过舵机实际能力时回路表现就会和仿真里完全对不上学生调出来的参数拿到实机上直接失效。5. 仿真验证与故障注入让教案的分数有据可依5.1 SIL 回路与三类故障注入验证环节最省事的做法是复用同一套控制器代码只把被控对象从真实动力学换成讲义的简化模型也就是软件在环。这样学生不用改控制器就能把注意力放在什么条件下它会崩上面。故障注入按三类安排就够了传感器噪声与延迟、舵机饱和与速率限制、风扰与定位丢失。import numpy as np rng np.random.default_rng(0) wind np.array([2.0, -1.0, 0.3]) # 常值风NED 下单位 m/s def disturb(t): gust 0.5 * np.sin(2 * np.pi * 0.2 * t) # 0.2 Hz 阵风 gyro_noise rng.normal(0, 0.02, size3) # 角速率陀螺噪声rad/s return wind np.array([gust, 0.0, 0.0]), gyro_noise常值风用来考位置环的稳态误差0.2 Hz 的阵风用来考姿态环的恢复速度陀螺噪声则专门用来暴露微分项的问题——Kd给大了噪声会被放大成舵机的高频抖动学生看到那条毛刺曲线自然就明白低通滤波为什么要放在微分之前。常见做法是把每类故障做成开关让学生自己组合最后交一份故障组合表。5.2 评分量规把飞得好不好变成可测的数教学最难的是给分。定一张量规表学生按指标交报告老师按指标打分争议会少很多。指标合格良好优秀怎么测航迹跟踪 RMS小于 8 m小于 4 m小于 2 m与参考航迹逐点求差姿态超调小于 25%小于 15%小于 8%阶跃响应峰值阵风恢复时间小于 6 s小于 3 s小于 1.5 s偏差回到 5% 带内的时间参数鲁棒性±10%±25%±40%质量与惯量扰动后是否仍合格具体技巧是让学生把同一套控制器分别跑在理想模型和带噪声加限幅的模型上两条航迹叠在同一张图里输出再把参数和指标落盘成 CSV。这种做法有个额外好处学期末学生手上的不是几张漂亮截图而是一组自己产生的对照数据报告里能直接拿出我把Kd从 0.02 提到 0.08 之后恢复时间缩短了 1.2 s但舵机抖动幅度翻了四倍这样的结论。把带扰动的曲线压在理想曲线下面哪一环先崩学生自己一眼就看出来。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进