YAOTU INSIGHTS

RflySim自定义三维模型可信仿真:单位、碰撞、参数与多机优化

RflySim自定义三维模型可信仿真:单位、碰撞、参数与多机优化
1. 这一篇到底要解决什么从看见模型到飞得像那么回事系列写到第三篇前面两篇把自定义三维模型从建模软件里搬进了 RflySim 的三维显示环境能加载、能旋转、能在场景里摆着很多人到这一步就觉得成了——模型显示出来了嘛。但真正跑起来才知道能看见和能用于仿真中间隔着一条不浅的沟。模型尺寸大了一圈、贴图一片惨白、机头指错方向、旋翼不转、撞上去直接穿模、多机集群一开帧率掉到个位数这些问题全都是模型进来了之后才会暴露出来的。这一篇就专门啃这块硬骨头把三维模型在 RflySim 中实现可信仿真的完整链路讲透材质与单位的对齐、碰撞体与物理属性的设置、动力学参数与飞行数据的一致性、以及多机场景下的性能与排查。RflySim这套环境本质上是把PX4飞控固件、Simulink控制算法和基于Unreal Engine的三维视景揉在一起三维模型在这里承担的角色不只是好看它还参与位置姿态数据可视化、碰撞检测、载荷与传感器挂载点的定义。所以自定义三维模型能不能实现仿真判断标准不是屏幕上有没有东西而是姿态对不对、尺寸准不准、旋翼转不转、碰撞有没有、多机卡不卡。这五条任何一条不过关仿真数据就没法当参考飞出来的曲线只能当动画看。适合读这篇的人我大致分两类。一类是已经跟着前两篇把模型导进去了、但卡在细节上出不来的另一类是想跳过前面直接拿现成模型改的那我建议至少回头把坐标系和网格原点那节补一下否则后面每走一步都要返工。下面的内容尽量按动手顺序排前面的没做完别急着往后翻尤其是单位对齐和原点设置这两步做错了后面全部白搭。说明文中涉及的具体配置文件名称、蓝图节点名称以你手上平台版本的官方说明为准不同版本会有出入。我给的是通用做法和判断逻辑不是死参数。2. 模型落地的第一道坎单位、材质与朝向的三种对齐2.1 厘米和米的战争导入缩放到底该填多少几乎所有人第一次导入自定义模型都会遇到同一个场景模型进场景后不是像芝麻就是像怪兽缩放到合适大小一看位置又飞了。根因在于两套单位体系打架。绝大多数建模软件如常见的三维建模工具默认按1 单位 1 米组织数据而 Unreal Engine 内部默认1 单位 1 厘米也就是 1 UU 1 cm。你在建模软件里画了一个翼展 0.5 米的四旋翼导出 FBX 时如果不做任何处理UE 会把它理解成 0.5 厘米——小了整整一百倍。正确的处理方式是三条路选一条不要混用方案操作位置适用场景风险导出时乘 100建模软件 FBX 导出面板的单位缩放单模型、一次性导入容易忘批量时易错导入时设 ScaleUE 导入对话框的 Transform 缩放批量导入、需要统一单位设置被继承改一次影响全部建模时就按厘米建模软件里直接把场景单位改成厘米长期维护的项目老的资产库全要重做我个人的习惯是走第二条模型文件保持1 单位 1 米的干净状态导入时在 Import 对话框里把缩放统一设成 100并且勾选Apply Transform之类把变换烘焙进网格的选项。这么做的好处是源文件永远是标准尺寸换平台、换引擎都不会乱坏处是每次导入都要盯一眼那个输入框。踩过一次坑之后我给自己定了个死规矩导入完成后的第一件事拿场景里自带的参照物量一遍尺寸比如标准跑道宽度、默认多旋翼模型的轴距量出来对不上就说明缩放错了别急着往下做。还有一层更隐蔽的问题缩放错了但你没发现因为模型看起来比例是对的。曾经有个模型整体放大了一百倍但它是个球形飞行器没有明显特征尺寸视觉上完全看不出来一直到做避障仿真的时候才发现碰撞范围大得离谱——碰撞体是按网格生成的网格大了一百倍碰撞体自然也大了一百倍两架飞机隔着一米就撞上了。所以别靠眼睛靠数值。实操心得先把默认的多旋翼模型加载出来作为尺子把自定义模型并排放在旁边轴距、桨盘直径、机体高度三项对得上基本就能确认缩放正确。三项里任何一项偏差接近 100 倍或 0.01 倍回去查单位。2.2 材质丢失与贴图路径为什么你的模型是一身灰模型导进来了尺寸也对但整个机体是灰白色的界面上看不出任何涂装和标识。这不是渲染坏了是材质没有正确关联。FBX 这类格式本身是可以携带材质信息的但携带的只是引用它会告诉引擎这个面的材质叫某某名字、贴图在同目录下的某个文件名引擎导入器会尝试用这个引用去重建材质实例。一旦路径变了、贴图文件名改了、或者贴图格式引擎不认重建就会失败引擎退回到默认材质看起来就是一身灰。排查顺序我一般这么走先看贴图文件有没有跟着模型一起走很多人导出时只导了模型本体贴图留在原地没带过来再看贴图格式常见图片格式一般都没问题但某些专业格式和特殊位深的图会读不出来最后看材质命名如果模型里用了大量中文名或者带特殊符号的材质名重建过程容易出岔子。这三个排查完八成问题能定位。如果重建一直失败别死磕自动关联手工建材质更稳。做法是在引擎的材质目录里新建一个材质把贴图挂到基础颜色的输入上然后把这个材质赋给网格体的对应插槽。听着麻烦但好处是完全可控后续想加自发光、想加透明、想换涂装都不用回建模软件重导。尤其是做集群仿真几十架飞机需要不同颜色区分编队用材质实例动态改颜色比准备几十套模型高效得多。关于材质对帧率的影响这里给个提醒。很多人喜欢给模型加一大堆高分辨率贴图、法线贴图、自发光单机看着漂亮一上集群就崩。我的经验是机体主材质控制在一张 1K 或 2K 的基础色贴图法线贴图有就用、没有不强求自发光尽量砍掉透明材质能不用就不用——透明材质在渲染管线里要单独排序几十个透明物体叠在一起帧率掉得肉眼可见。2.3 机头朝向与网格原点姿态数据对不上的元凶这是最容易被忽略、也是最致命的一步。仿真里飞行器位置姿态是靠数据包实时驱动的数据包里的姿态是相对某个坐标系定义的如果模型的机头朝向和这个坐标系定义不一致你会看到飞机在侧着飞、倒着飞、横着飞甚至原地打转。这类现象非常迷惑人因为模型本身很漂亮视角一转就以为是自己看错了。要先搞清楚两件事数据侧用的是什么坐标系模型侧的原点在哪、朝向哪。数据侧常见的两种约定一种是航空常用的机体坐标系X 轴指向机头、Y 轴指向右侧、Z 轴指向下方另一种是机器人领域更常见的X 轴向前、Y 轴向左、Z 轴向上。而三维引擎大多是左手坐标系X 轴向前、Y 轴向右、Z 轴向上。你看除了 Z 轴方向可能一致Y 轴的正负往往是反的。这意味着如果你的模型是按Y 轴向左建的直接导入引擎而不做处理整机会左右镜像外观上不那么容易发现但机臂、桨的旋向、传感器位置全反了。所以我的做法是固定一套流程建模阶段就把模型摆成机头朝世界坐标的正前方垂直方向朝上机体的几何中心尽量对齐世界坐标原点如果建模软件的坐标系和引擎不一致在导出前用一个空物体做旋转校正把旋转烘焙进去不要留到引擎里再转导入引擎后用引擎的坐标轴显示功能核对一遍确认模型本地坐标的正前方就是视觉上的机头方向最后把模型拖到场景原点检查它是不是悬在半空或者陷在地里。这里还有一个细节网格原点不一定等于几何中心。有些模型设计师为了好看把原点放在了机体底部或者某个角上这种模型一旦被位置数据驱动就会出现绕着一个奇怪的支点旋转的现象姿态一变化整机就大幅晃动。解决办法是在建模软件里把原点重设到质心附近重新导出。如果你没法改源文件那就在引擎里给模型套一个父级组件用父级组件承担位置姿态驱动模型作为子级做固定的偏移补偿这样也能绕开原点不对的问题。3. 让模型不只是个壳碰撞体与物理属性的设置逻辑3.1 简单碰撞与复杂碰撞什么时候该省什么时候该花三维模型在引擎里默认只有视觉网格没有碰撞几何。也就是说两架飞机互相穿过去什么都不会发生。碰撞检测在仿真里有两个用途一是视觉层面的干涉判断比如编队飞行时判断会不会撞上二是物理层面的响应比如撞地、撞墙之后的表现。要不要做碰撞取决于你的仿真目的不是所有场景都需要。引擎里的碰撞体分两类。简单碰撞是用盒子、球、胶囊、凸包这类基本形体近似出来的计算开销极小一个物体几十个三角面都用不满复杂碰撞直接用视觉网格的三角面做精确碰撞精度高但开销巨大一个精细的多旋翼模型动辄几万个面几十架一起跑帧率立刻崩。所以在集群仿真场景里简单碰撞几乎是唯一选择复杂碰撞只在极少数单机精细分析时才考虑。简单碰撞的生成方式有两种。一种是自动生成导入网格体时在碰撞设置里选择自动生成凸包引擎会根据网格形状自动拼出若干凸包来近似另一种是手工指定在建模软件里单独做一套极简的碰撞网格命名时加特定前缀导入时引擎会自动识别为碰撞体。手工指定的方式可控性高得多我一般推荐这种做法机臂用细长盒子机身用一到两个凸包桨盘用一个扁圆柱或者干脆不要碰撞。四个机臂加一个机身总共五六个碰撞体开销可以忽略形状也够用。注意碰撞体不是越精确越好是越够用越好。做编队避障你需要的是两机能感知到彼此靠近未必需要精确到毫米的接触判定。碰撞体做太细除了吃性能还会带来另一个麻烦——数值抖动两架飞机轻微接触时由于浮点误差反复触发和解除碰撞表现为模型高频抖动。3.2 质量、惯量与质心三个必须和参数文件对齐的数字很多人的自定义模型只关注了外观参数文件里还是默认值结果仿真出来的响应和真实飞行器差得远。质量、转动惯量、质心位置这三个物理量直接决定动力学响应的快慢和耦合程度必须和你的真实平台或者你想仿真的目标平台对齐。质量好办称一下就知道。转动惯量麻烦一点理想情况是从 CAD 软件里直接导出大多数三维建模软件都能根据材质密度自动算出惯量张量。如果没有这个条件可以用近似公式估算。把机体近似成一个长方体长宽高分别为 a、b、c质量 m那么绕三个主轴的转动惯量大致是绕 X 轴滚转Ixx m(b² c²) / 12绕 Y 轴俯仰Iyy m(a² c²) / 12绕 Z 轴偏航Izz m(a² b²) / 12注意这是均匀长方体近似实际机器人的电池、电机、机载设备分布不均会有偏差。不过对于多数控制算法的验证来说这个量级的估算已经够用。如果你手上有真实的辨识数据当然优先用辨识出来的值公式估算只作为兜底。质心位置更容易被忽略。质心偏离几何中心会引入额外的力矩耦合表现出来就是悬停时总有一点残余的俯仰或滚转趋势控制器得靠积分项慢慢压下去。所以模型建模时尽量把质心画在几何中心附近电池、载荷这些重的部件在建模阶段就摆到实际位置。如果仿真里需要模拟挂载不同载荷的影响那就得准备几套参数或者用可变参数的方式动态调整质心偏移。这里有个实用的自检方法把仿真跑起来给一个小的姿态阶跃指令看响应的超调量和振荡周期是不是和你预期的一致。如果响应明显比预期迟钝或者暴躁先怀疑惯量填错了量级比如把 0.01 填成了 0.1或者把 g·cm² 当成 kg·m² 填了。3.3 旋翼绑定让桨叶跟着转速数据转起来一个多旋翼模型如果桨不转视觉上就永远是悬停状态看不出它在加速还是在爬升这对调试来说损失很大信息。所以自定义模型导入后一般还要做旋翼的绑定把每个桨叶拆成独立的网格体组件挂到机体的相应位置上然后把这些组件和仿真数据里的电机转速信号关联起来让它们的旋转速度随数据变化。具体做法在引擎的蓝图编辑环境里把机体网格作为根组件四个或更多桨叶各做一个子组件位置按实际的电机安装位置填。电机位置要填准因为有些平台的旋转动画是依据位置来匹配信号的位置填错会出现信号给了一号电机转的却是三号桨的情况。桨叶的形状最好做成扁平的一片绕自身轴旋转时视觉上更接近真实的桨盘。旋转轴的方向也要注意。不同的旋转方向从上方看是顺时针还是逆时针直接对应反扭矩的方向。仿真里如果桨的旋向显示反了虽然不影响数据但会让人产生误判尤其在做故障注入演示的时候看到反桨还在正常转会怀疑信号是不是没发出去。实操心得绑定完旋翼先别急着上控制算法用最简单的方式验证一遍——手动发一个固定转速四个桨应该同时转起来单独给某一个通道加速度看是不是对应位置的桨变快。这一步验证通过后面再上闭环才不会被到底是模型问题还是算法问题绕晕。4. 参数一致性从模型文件到控制回路的完整链路核对4.1 模型参数与控制参数的对应关系三维模型、参数文件、控制算法这三者是三份独立的数据但它们描述的必须是同一架飞机。我见过太多案例模型是按 450 轴距做的参数文件里还是默认的小轴距参数控制增益也是默认的跑出来的曲线看着挺像回事实际这个仿真结论一点参考价值都没有。核对清单我自己是这么定的参数项模型侧的来源参数文件中的字段一致性检查方式轴距建模软件量取机臂长度 / 电机位置数值对比误差控制在几个百分点内质量称重或者CAD统计质量参数直接比对转动惯量CAD导出或公式估算三个轴向惯量检查数量级是否合理电机安装位置模型中的桨叶组件位置电机位置向量坐标数值逐一核对旋向模型桨叶旋转方向电机转向配置视觉验证最大拉力实测或电机手册拉力系数悬停油门验证最后一条悬停油门验证是我觉得最有效的整体验证方式。参数对齐之后让飞机在仿真里悬停看稳态油门大概在什么位置。真实的四旋翼悬停油门一般在百分之五十上下浮动如果你的仿真悬停油门到了百分之八十或者百分之二十说明拉力系数或者质量其中至少一个填错了。这是一个非常灵敏的整体校验比逐项核对效率高得多。4.2 位置姿态数据的驱动链路怎么走通数据从控制算法到三维显示中间是有好几跳的控制算法算出期望姿态飞控或者仿真里的动力学模型积分出实际位姿位姿被打包通过通信链路发出去三维显示端接收解析再把数值映射到场景里对应模型的位置和朝向上。这条链上任何一环出问题现象都是模型不动或者模型乱动。排查的时候从后往前推更高效。先确认三维显示端有没有在收数据——多数平台会有数据监视窗口或者日志能看到收包计数在涨。收包正常但模型不动问题多半出在模型与数据通道的绑定关系上多机仿真时每架飞机有独立的编号模型在场景里也要有对应的编号或者标签编号对不上数据就发给了空气。这个坑非常常见尤其是复制粘贴配置文件的时候忘了改编号十架飞机全绑到同一个通道上画面上只有一架在动。收包正常、绑定也对模型还是不动那就要看数据包里的位姿是不是恒为零。这时候把数据打印出来看如果姿态四元数一直是单位四元数、位置一直不动那问题回到控制侧可能是算法没输出、可能是模型没被激活。反过来如果数值在剧烈跳变模型在场景里疯狂抽搐那就是数据频率或者数值范围有问题比如单位搞错了弧度当成了度米当成了厘米。提示链路排查别靠猜靠日志。养成在关键节点打印一行的习惯——算法输出打一行、发出去打一行、收到打一行、映射后打一行。四行日志一摆问题卡在哪一段一目了然比盯着屏幕看模型省太多时间。4.3 多机场景下的命名与编号规范单机跑通了下一步基本都是集群。集群仿真最容易翻车的地方不是算法是命名混乱。每架飞机至少涉及这些东西三维模型实例、数据通道编号、参数文件、控制器实例。这四个东西如果命名不统一改一处忘一处调起来就是灾难。我的做法是建立一套固定的编号规则比如统一用两位数编号从 01 到 N。模型在场景里的标签、配置文件里的通道号、参数文件名后缀全部用同一套编号。批量生成配置文件的时候用脚本生成不要手工复制粘贴手工复制是编号错乱的最大来源。生成完做一次自检把所有编号列出来排序看有没有重复、有没有断号。场景摆放也有讲究。多机初始位置如果摆得太近起飞瞬间就会互相碰撞仿真直接崩。如果摆得太整齐又容易掩盖掉一些由初始条件引起的耦合问题。我的经验是初始位置按编队队形摆但每架飞机的高度稍微错开一点避免完全共面间距至少留出两个机身长度给控制器的初始收敛留余量。还有一点模型实例化。集群场景里如果每个模型都是独立的完整网格体显存和绘制调用会成倍增长。引擎提供了实例化渲染的机制同一套网格体可以在场景里出现多次而只占一份资源。如果你的平台支持尽量用实例化的方式部署多机这个优化对帧率的影响是数量级的。5. 性能优化与常见问题实录那些文档里不会写的坑5.1 帧率暴跌的五个典型原因三维显示跑得流畅不流畅直接决定了你能不能一边仿真一边观察。帧率掉下来的时候人的第一反应是电脑不行了其实多数情况是场景配置的问题。按我遇到过的情况排个序网格面数过高。一个精细模型几十万面单机看着没事十架一起就是几百万面。解决办法是做减面仿真用的模型不需要和展示用的模型一样精细能看清形状和姿态就够了面数砍到原来的十分之一通常没什么视觉损失。材质过于复杂。前面说过透明材质、大量高分辨率贴图、复杂着色器都是性能杀手。仿真场景优先用最简单的材质。阴影与后处理。动态阴影、环境光遮蔽、抗锯齿这些在展示场景里是加分项在仿真里是纯负担。仿真跑起来第一件事就是把阴影关掉、后处理调到最低。碰撞体过多。每一帧都要做碰撞检测碰撞体数量直接线性影响开销。前面强调过碰撞体越少越好。数据频率不匹配。如果三维显示端的更新频率远高于数据发送频率大部分帧都在做无意义的重复渲染反过来如果显示频率低于数据频率又会丢帧。两边频率尽量匹配。我用过的判断方法是二分法定位先把场景里的模型删到只剩一架看帧率恢复没有恢复了就是模型数量问题删到一架还是卡那就是单模型本身太重。这样两三轮就能锁定方向比一项项改配置快得多。5.2 常见问题速查表下面这张表是我这几年攒下来的基本覆盖了自定义模型仿真时八成以上的异常现象。遇到问题先对照查一遍能省不少时间。现象最可能的原因排查与处理模型整体巨大或极小导入缩放与单位不一致与默认模型并排比对尺寸检查缩放是否差 100 倍模型一身灰白无贴图材质重建失败检查贴图是否随模型一起导入手工重建材质模型侧着飞或倒着飞机头朝向与数据坐标系不一致核对坐标系约定导入前做旋转烘焙模型绕奇怪支点旋转网格原点不在质心附近重设原点或加父级组件做偏移补偿模型在场景里不动绑定编号错误或数据未发出检查通道编号打印收发日志模型高频抖动碰撞频繁触发解除或数据频率不匹配简化碰撞体匹配数据与渲染频率两机隔着距离就撞碰撞体按放大后的网格生成重做碰撞体或重新校准缩放桨叶不转或转错位旋翼组件未绑定或位置填错逐一核对电机位置与信号通道悬停油门明显偏离常规值拉力系数或质量参数填错用悬停油门作为整体校验点反查集群一开就卡模型面数、材质、碰撞体未优化减面、简化材质、关闭阴影、实例化渲染5.3 几条我觉得最值钱的经验第一条建模阶段就把仿真需求考虑进去别等导入了再改。具体说模型分开建视觉网格一套碰撞网格一套桨叶独立成组件原点放在质心机头朝正前方尺寸以米为单位。这套规范一旦定下来后面每一个模型都这么做导入环节就几乎不需要返工。我早期没有这套规范一个模型导入折腾两三天是常事后来规范固定了半小时搞定。第二条保留一个可用的参照模型。手里始终留一个经过验证的、各项参数都对的默认模型遇到任何异常先把它加载出来对比。是只有自定义模型出问题还是所有模型都出问题这个对比一步就能把问题范围缩小一半。我见过太多人拿着自己的模型死磕磕了两天发现是平台配置被人改过换个模型也一样。第三条参数改动留记录。模型、参数文件、控制增益这三样东西任何一样改了都要记一笔改了什么、为什么改、改完效果如何。仿真最怕的就是改花了——一圈优化下来参数面目全非回头想复现某个好结果都复现不出来。我的习惯是每个版本打个标签配上当时的参数文件和截图出问题可以随时回退。第四条也是我最近才真正重视起来的不要追求一次到位。很多人想让自定义模型一上来就承担高保真的仿真任务结果每个环节都要抠到极致进度拖得极慢。更实际的做法是分级推进——第一级只要求模型显示正确、姿态正确用它跑通闭环第二级把质量和惯量对上让动力学响应可信第三级再补碰撞、补旋翼动画、补视觉细节。每一级都能出可用的中间结果哪一级出问题就在哪一级停下解决不会因为一个细节卡死整个项目。第五条关于时间成本。自定义模型的完整落地从建模到能在集群里稳定跑我这边一个熟练的人大概是两到三个工作日。如果超过五天还在打转基本可以判断是方向错了要么是单位和坐标系这类基础问题没排干净要么是平台版本和文档对不上。这时候最好的选择是退回去用一个已知可用的最小场景重新走一遍而不是在复杂场景里继续挣扎。最后说个我觉得挺有意思的延伸模型做扎实之后很多原本麻烦的事情会变简单。比如想验证不同机型的控制效果只要换模型换参数就行算法一行不用改想做故障注入演示把某个桨叶的转速信号人为置零视觉上立刻能看到不对称比看曲线直观得多想做载荷影响分析把载荷模型挂上去、更新质心和惯量剩下的交给仿真。这些用法能不能顺滑地跑起来取决于前面那些看起来枯燥的细节有没有做到位——单位、原点、朝向、惯量、碰撞体这五样东西扎实了模型就不再是个摆设而是真正能参与仿真的一个部件。