ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

text-to-cad 实战:从自然语言到 STEP/URDF/G-code 的三段式管线

text-to-cad 实战:从自然语言到 STEP/URDF/G-code 的三段式管线 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个词很多人脑子里蹦出来的画面可能是对着电脑说一句“给我画个法兰盘”然后 CAD 软件里就自动生成了一张图纸。这个理解方向没错但实际落地远没有这么简单。text-to-cad 本质上是一套把自然语言描述转换成结构化三维模型数据的技术链路它的输出通常不是一张 DWG 图纸而是 STEP、URDF、G-code 这类可以被下游工具直接消费的中间格式。我接触这个方向是从一个很具体的需求开始的手头有一批参数化零件每次改尺寸都要手动在 CAD 里重新拉伸、打孔、倒角重复劳动太多。后来想能不能用一段文字描述直接驱动模型生成试了几轮之后发现text-to-cad 真正的价值不在于“替代画图”而在于把设计意图变成可复用的数据流。你描述的是“一个外径 80、内径 40、厚度 10 的法兰均布 6 个直径 8 的孔”系统输出的是带完整几何拓扑的 STEP 文件这个文件可以进仿真、可以进切片、可以进机器人仿真环境。它适合谁三类人最值得关注一是做参数化设计的机械工程师二是搞机器人仿真需要批量生成 URDF 的技术人员三是做增材制造想把文字需求直接转成 G-code 的创客。如果你只是偶尔画两张二维图那 text-to-cad 对你的边际收益不大但如果你面对的是成百上千个变体零件这套思路能省掉大量重复操作。需要先明确一点text-to-cad 不是某一个软件的功能按钮而是一条从语义解析到几何生成再到格式导出的完整管线。下面我按自己实际搭过的流程把每个环节拆开讲。2. 整体架构设计为什么是“解析—建模—导出”三段式2.1 核心思路与方案选型我试过两种路线。第一种是端到端生成用大模型直接输出 CAD 脚本或网格数据第二种是分阶段管线先把文字解析成结构化参数再调用几何内核建模最后按目标格式导出。实测下来第一种路线在简单形状上能跑通但一旦涉及孔位阵列、倒角、装配关系生成结果就很不稳定而且出错之后几乎没法调试。所以我最终采用的是三段式架构语义解析层把自然语言拆成“实体类型 尺寸参数 特征操作”的结构化描述几何建模层用参数化建模内核根据结构化描述生成三维实体格式导出层把实体转换成 STEP、URDF、G-code 等目标格式这个设计的核心考量是可调试性。文字解析错了我只需要改解析规则几何生成错了我只需要调建模参数导出格式不对我只需要换导出器。每一层都可以单独验证不会出现“一句话进去、一坨乱码出来、完全不知道哪里错了”的情况。提示如果你刚开始做 text-to-cad强烈建议不要一上来就追求端到端。先把中间的结构化描述定义清楚后面所有工作都会轻松很多。2.2 各层职责与数据流结构化描述我用的是 JSON字段设计参考了常见 CAD 特征的参数组织方式。一个典型的法兰描述长这样{ entity: flange, params: { outer_diameter: 80, inner_diameter: 40, thickness: 10, holes: { count: 6, diameter: 8, pcd: 60 } }, units: mm }这个 JSON 就是整条管线的“合同”。解析层负责产出它建模层负责消费它导出层不关心它怎么来的。这样做的好处是哪天我想换一个更好的语言模型来解析文字只要它还能输出同样结构的 JSON后面两层完全不用动。几何建模层我选的是基于OpenCASCADE的内核因为它对 STEP 格式的支持最成熟布尔运算也稳定。URDF 导出则需要额外处理关节和连杆的层级关系这部分后面单独讲。G-code 导出相对独立本质上是把三维模型切片后生成路径我一般用现成的切片引擎来处理。2.3 为什么不用直接生成网格有人会问现在网格生成模型那么多为什么不直接文字生成 STL我的经验是网格数据不可参数化。你拿到一个 STL想改一个孔的直径只能重新生成整个网格。而 STEP 是边界表示B-rep每个面、每条边都是带参数的改一个尺寸只需要更新对应参数。对于需要反复迭代的设计场景这个差别是致命的。另外URDF 和 G-code 对几何精度的要求不同。URDF 关心的是碰撞体和视觉体的近似G-code 关心的是切片路径两者都需要从精确的 B-rep 模型出发做不同处理。如果中间只有网格很多下游操作会变得很别扭。3. 语义解析层把“人话”变成“机器能懂的参数”3.1 解析策略规则优先还是模型优先我一开始用纯规则做解析写了一大堆正则表达式。简单句还能应付比如“直径 50 的圆盘”但一旦出现“外径 80 内径 40 厚度 10 均布 6 个直径 8 的孔”这种复合描述规则就开始打架。后来改成模型抽取 规则校验的混合策略先用语言模型把句子里的实体、尺寸、数量、位置关系抽出来再用规则检查参数是否完整、单位是否明确、数值是否在合理范围内。这个混合策略的关键在于校验环节。语言模型有时候会把“内径”和“外径”搞反或者漏掉单位。规则校验会检查外径是否大于内径孔的数量是否是整数孔径是否小于壁厚这些检查能拦掉大部分低级错误。3.2 参数完整性检查清单在实际操作中我发现以下几类问题出现频率最高建议在解析层就做好拦截问题类型典型表现处理方式单位缺失“直径 80”没说是 mm 还是 inch默认 mm但在输出中标注假设参数矛盾内径大于外径直接报错要求重新描述特征冲突孔的位置超出实体范围计算孔边距超出则报错数量模糊“几个孔”没有具体数字追问或使用默认值并标注术语歧义“大孔”没有具体尺寸要求补充具体数值注意不要小看单位问题。我踩过一次坑一批零件默认用了 inch结果导出 STEP 之后进仿真尺寸差了 25.4 倍排查了半天才发现是单位没统一。3.3 从描述到 JSON 的实操示例假设输入是“一个长 100 宽 60 高 20 的方块四个角各有一个直径 6 的通孔孔中心距边缘 10。”解析层的工作流程是识别实体类型方块box抽取主尺寸长 100、宽 60、高 20识别特征操作通孔through hole抽取孔参数直径 6、数量 4推断孔位置四角中心距边缘 10生成结构化 JSON对应的 JSON 如下{ entity: box, params: { length: 100, width: 60, height: 20, holes: { type: through, diameter: 6, count: 4, positions: [ {x: 10, y: 10}, {x: 90, y: 10}, {x: 10, y: 50}, {x: 90, y: 50} ] } }, units: mm }这里的位置计算是解析层做的孔中心距边缘 10所以四个角的坐标分别是 (10,10)、(90,10)、(10,50)、(90,50)。这个计算逻辑要写清楚因为不同人对“距边缘”的理解可能不一样——是孔中心到边缘还是孔边到边缘我默认按孔中心算并在文档里注明。4. 几何建模层从参数到实体的关键操作4.1 建模内核的选择与初始化几何建模层我用的 OpenCASCADEPython 绑定用的是 pythonocc。初始化流程大概是from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut from OCC.Core.gp import gp_Pnt, gp_Ax2, gp_Dir # 创建方块 box BRepPrimAPI_MakeBox(100, 60, 20).Shape() # 创建圆柱并做布尔减 for pos in hole_positions: cylinder BRepPrimAPI_MakeCylinder(3, 20, gp_Ax2(gp_Pnt(pos.x, pos.y, 0), gp_Dir(0, 0, 1))).Shape() box BRepAlgoAPI_Cut(box, cylinder).Shape()这段代码的逻辑很直接先建主实体再逐个建特征实体最后用布尔运算把特征从主实体上“挖”掉。但实际操作中有几个细节要注意。4.2 布尔运算的稳定性技巧布尔运算是几何建模里最容易出问题的环节。我遇到过圆柱和方块表面刚好相切导致运算失败的情况也遇到过孔的位置太靠近边缘导致生成薄壁碎片。几个实用技巧留余量做减运算的圆柱高度要比主实体厚度多出一点确保完全穿透。比如方块高 20圆柱高度用 22两端各多 1mm。避免相切孔中心到边缘的距离不要刚好等于孔径的一半稍微错开一点避免相切。分步运算如果有多个孔不要一次性做所有布尔运算逐个做每做一步检查一下实体是否有效。容差设置OpenCASCADE 有默认容差如果模型尺寸很小比如微米级需要手动调整容差参数。提示布尔运算失败时先检查两个实体是否有重叠体积。如果只是面接触运算结果可能为空或报错。4.3 特征顺序对结果的影响建模顺序会影响最终结果尤其是涉及倒角和圆角的时候。我的经验是先做减运算再做倒角。如果先倒角再打孔孔可能会切掉倒角的一部分导致边缘不完整。正确的顺序是创建主实体执行所有减运算孔、槽、腔执行倒角和圆角检查实体有效性这个顺序不是绝对的但大多数情况下能避免特征干涉。如果倒角之后还需要打孔那就要重新评估顺序。4.4 模型有效性检查每次布尔运算之后我都会跑一遍有效性检查from OCC.Core.BRepCheck import BRepCheck_Analyzer analyzer BRepCheck_Analyzer(shape) if not analyzer.IsValid(): print(模型无效需要排查)无效模型导出 STEP 后下游工具可能读不出来或者读出来是破面。与其等到下游报错不如在建模层就拦住。5. 格式导出层STEP、URDF、G-code 的差异化处理5.1 STEP 导出最直接的路径STEP 导出是最成熟的OpenCASCADE 自带导出器from OCC.Core.STEPControl import STEPControl_Writer, STEPControl_AsIs writer STEPControl_Writer() writer.Transfer(shape, STEPControl_AsIs) writer.Write(output.step)这里的关键参数是STEPControl_AsIs表示按原样导出不做额外处理。如果模型有装配关系需要额外处理装配层级。对于单实体零件这样导出就够了。STEP 的好处是通用性强几乎所有 CAD 软件都能读。我试过用 FreeCAD、中望 CAD、SolidWorks 分别打开同一个 STEP 文件几何信息都能正确识别。但要注意STEP 不保留特征树导出的是一堆面片和边想改参数只能回到生成端重新生成。5.2 URDF 导出机器人仿真的特殊需求URDF 是机器人描述格式它关心的不是精确几何而是连杆、关节、碰撞体、视觉体的层级关系。从 text-to-cad 生成 URDF需要额外做几件事定义连杆每个独立运动的部件作为一个 link定义关节link 之间的连接关系包括关节类型旋转、平移、固定和运动范围简化碰撞体URDF 的碰撞体通常用简单几何方块、圆柱、球近似不需要精确 B-rep指定视觉体视觉体可以用网格文件通常导出为 STL 或 DAE我一般的工作流是先用 text-to-cad 生成精确 STEP 模型再根据装配关系手动或半自动地定义 URDF 结构。完全自动从文字生成 URDF 目前还比较困难因为关节类型和运动范围很难从自然语言中准确推断。注意URDF 导入 CoppeliaSim 时路径问题是最常见的坑。建议用相对路径并且把网格文件和 URDF 放在同一个目录下。5.3 G-code 导出从模型到制造路径G-code 导出本质上是切片加路径规划。text-to-cad 生成的模型需要先导出为 STL再进切片引擎。我常用的流程是从 B-rep 模型导出 STL注意设置合适的网格精度用切片引擎如 CuraEngine、PrusaSlicer生成 G-code根据打印机参数调整速度、温度、层高这里的关键是网格精度。STL 是三角网格精度太低会导致圆弧变成多边形精度太高会导致文件过大。我的经验是对于一般零件弦高公差设 0.01mm角度公差设 0.5 度能在文件大小和精度之间取得平衡。格式主要用途精度要求导出难度STEPCAD 交换、仿真高B-rep低URDF机器人仿真中简化碰撞体中G-code增材制造中切片路径中STL3D 打印、可视化中三角网格低6. 实操全流程从一句话到可用的 STEP 文件6.1 环境准备与依赖安装我用的环境是 Python 3.10 pythonocc-core numpy。安装 pythonocc 在 Windows 上稍微麻烦一点推荐用 condaconda install -c conda-forge pythonocc-core如果不用 condapip 安装可能会缺依赖。Linux 下相对简单apt 装好 OpenCASCADE 开发库之后 pip 装 pythonocc 基本能跑通。6.2 完整代码示例下面是一个从文字描述到 STEP 导出的最小可运行示例import json from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Cut from OCC.Core.gp import gp_Pnt, gp_Ax2, gp_Dir from OCC.Core.STEPControl import STEPControl_Writer, STEPControl_AsIs from OCC.Core.BRepCheck import BRepCheck_Analyzer # 假设解析层已经产出结构化描述 spec { entity: box, params: { length: 100, width: 60, height: 20, holes: { type: through, diameter: 6, count: 4, positions: [ {x: 10, y: 10}, {x: 90, y: 10}, {x: 10, y: 50}, {x: 90, y: 50} ] } }, units: mm } # 建模 p spec[params] shape BRepPrimAPI_MakeBox(p[length], p[width], p[height]).Shape() hole_r p[holes][diameter] / 2 hole_h p[height] 2 # 留余量 for pos in p[holes][positions]: cyl BRepPrimAPI_MakeCylinder( hole_r, hole_h, gp_Ax2(gp_Pnt(pos[x], pos[y], -1), gp_Dir(0, 0, 1)) ).Shape() shape BRepAlgoAPI_Cut(shape, cyl).Shape() # 有效性检查 if not BRepCheck_Analyzer(shape).IsValid(): raise RuntimeError(模型无效) # 导出 STEP writer STEPControl_Writer() writer.Transfer(shape, STEPControl_AsIs) writer.Write(output.step) print(STEP 文件已生成)这段代码跑通之后你会得到一个带四个通孔的方块 STEP 文件。用 FreeCAD 打开应该能看到完整的几何。6.3 参数计算的实际案例再举一个法兰的例子说明参数计算过程。输入描述“外径 120内径 60厚度 15均布 8 个直径 10 的孔孔中心圆直径 90。”计算过程外半径 120 / 2 60内半径 60 / 2 30孔半径 10 / 2 5孔中心圆半径 90 / 2 45孔中心坐标角度间隔 360 / 8 45 度第 i 个孔的角度 i * 45 度x 45 * cos(角度)y 45 * sin(角度)这些计算在解析层完成建模层直接消费坐标。这样做的好处是如果以后要改孔的数量只需要改解析层的计算逻辑建模层不用动。7. 常见问题与排查技巧实录7.1 布尔运算失败怎么办这是最高频的问题。表现是BRepAlgoAPI_Cut返回空形状或者抛异常。排查顺序检查两个实体是否有实际重叠体积而不只是面接触检查实体是否有效用BRepCheck_Analyzer验证尝试调整容差BRepAlgoAPI_Cut可以设置模糊容差如果还不行把减运算的实体稍微移动一点避开相切位置我遇到过一次圆柱和方块的一个面刚好共面导致布尔运算结果不稳定。把圆柱沿轴向移动 0.01mm 之后就正常了。7.2 STEP 导出后下游读不出来通常是模型本身有问题。先用BRepCheck_Analyzer检查如果模型有效但下游还是读不出来可能是 STEP 版本问题。OpenCASCADE 默认导出 AP214有些老软件只支持 AP203。可以在导出时指定协议writer.Transfer(shape, STEPControl_AsIs) # 或者尝试其他协议另外文件名不要用中文和特殊字符有些下游工具对路径编码支持不好。7.3 URDF 导入仿真环境后位置不对URDF 的坐标系定义和 CAD 的坐标系定义可能不一致。CAD 通常 Z 轴向上URDF 通常也是 Z 轴向上但有些仿真环境默认 Y 轴向上。导入之后如果发现模型躺倒了检查一下坐标系约定。还有一个常见问题是单位。URDF 默认用米CAD 默认用毫米。导出 URDF 时要把尺寸除以 1000否则模型会大 1000 倍。7.4 G-code 路径异常G-code 路径异常通常出在切片参数上。检查层高是否合理一般 0.1-0.3mm喷嘴直径是否和切片参数匹配模型是否封闭非封闭模型切片会出问题模型是否在打印平台范围内我踩过一次坑模型导出 STL 时精度设得太低圆弧变成了明显的多边形切片后路径抖动很厉害。把弦高公差从 0.1mm 调到 0.01mm 之后就顺滑了。7.5 常见问题速查表问题现象可能原因排查方向布尔运算返回空实体无重叠或相切检查位置关系留余量STEP 导出失败模型无效或路径含特殊字符检查模型有效性换路径URDF 导入后尺寸不对单位不一致毫米转米URDF 导入后姿态不对坐标系约定不同检查轴向定义G-code 路径抖动STL 精度太低提高网格精度模型面数过多网格精度太高降低弦高公差孔位置偏移坐标计算错误检查解析层计算逻辑8. 工具链选型与扩展思路8.1 建模内核对比内核优势劣势适用场景OpenCASCADE开源STEP 支持好学习曲线陡通用 CAD 生成CGAL几何算法丰富偏学术工程化弱研究性项目FreeCAD API上手快Python 友好依赖 FreeCAD 环境快速原型CadQuery语法简洁参数化强底层还是 OCC参数化零件我目前主力用 OpenCASCADE因为可控性最强。如果只是做简单零件CadQuery 的语法更友好写起来快很多。8.2 从单零件到装配体单零件跑通之后下一步自然是装配体。装配体的 text-to-cad 需要额外处理零件间的位置关系配合、对齐、距离装配层级子装配和总装配的关系干涉检查零件之间是否有碰撞这部分我还在摸索目前的做法是先用文字分别生成每个零件再手动或半自动地定义装配关系。完全自动的装配体生成难点在于自然语言中的位置描述往往很模糊比如“把轴插进孔里”到底插多深、什么配合都需要额外推断。8.3 批量生成的工程化考虑如果要做批量生成比如一次生成 100 个不同尺寸的法兰需要考虑模板化把常用零件做成模板只改参数队列处理生成任务排队避免内存爆掉错误重试某个零件生成失败时自动重试或跳过日志记录每个零件的生成参数和结果都要记录方便追溯我用 Python 的 concurrent.futures 做并行生成但要注意 OpenCASCADE 不是线程安全的每个线程需要独立的建模上下文。简单做法是用多进程每个进程独立初始化。9. 我踩过的坑与实操心得第一个坑是单位不统一。前面提过一批零件默认用了 inch导出 STEP 后进仿真尺寸差了 25.4 倍。后来我在解析层强制要求标注单位没标注的一律按 mm 处理并在输出中打印警告。第二个坑是布尔运算的顺序。有一次先倒了角再打孔结果孔切掉了倒角的一部分边缘出现了薄壁碎片。后来改成先打孔再倒角问题消失。这个顺序不是绝对的但大多数情况下先减后倒更安全。第三个坑是URDF 的碰撞体简化。一开始我直接把精确模型作为碰撞体导出结果仿真时碰撞检测特别慢。后来改成用简单几何近似碰撞体视觉体用精确模型仿真速度提升了一个数量级。第四个坑是G-code 的模型封闭性。有一个模型因为布尔运算出了一个小破面肉眼看不出来但切片时路径直接乱掉。后来每次导出 STL 之前都跑一遍封闭性检查不通过就不切片。提示text-to-cad 的产出物最终是要给下游用的所以下游能读、能用比生成得快更重要。宁可多花几秒做有效性检查也不要生成一堆废文件。10. 这个方向后续还能怎么扩展目前我跑通的链路是“文字 → 结构化参数 → 单零件 STEP/URDF/G-code”。下一步想尝试的是从装配描述直接生成装配体比如“一个减速箱输入轴和输出轴平行中心距 80”系统自动推断齿轮参数和箱体尺寸。这个难度不小因为涉及工程计算的推断不只是几何生成。另一个方向是反向链路从现有 STEP 文件反推出结构化描述再用文字描述去修改。这样就能实现“打开一个现有模型说一句‘把孔径改成 12’模型自动更新”。这个在参数化设计场景下很有用技术上也比正向生成容易一些因为几何信息是现成的只需要做特征识别和参数提取。还有一个实用扩展是和现有 CAD 软件集成。比如生成 STEP 之后自动导入中望 CAD 或 FreeCAD 做后续处理或者把 G-code 直接推送到打印机。这些集成本身不难主要是接口适配的工作量。我个人在实际操作中的体会是text-to-cad 目前最适合的场景是参数化变体生成而不是从零开始的全新设计。你给它一个明确的参数化模板它能快速生成大量变体但你让它凭空设计一个复杂零件它还很吃力。把预期放在“提效工具”而不是“替代设计师”心态会好很多落地也会顺利很多。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表