ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

text-to-cad:从自然语言到STEP/URDF的自动化建模实践

text-to-cad:从自然语言到STEP/URDF的自动化建模实践 CAD 这行当有个特别拧巴的地方设计师脑子里的东西是三维的但落到电脑上第一步永远是打开软件、选基准面、画草图、拉伸、倒角。这套动作重复十年闭着眼都能做可一旦要批量出图、参数化改型或者让程序自动生成结构件手工建模就成了瓶颈。text-to-cad这个方向说白了就是想把“画图”这件事变成“说话”——你用自然语言描述一个零件系统直接吐出可用的 CAD 文件。它解决的不是“画得好不好看”而是“能不能不画”。适合谁看如果你写过脚本批量改图纸、折腾过参数化建模、或者被 URDF 和 STEP 之间的转换折磨过这篇就是给你准备的。1. 从文字到模型text-to-cad 到底在解决什么问题1.1 传统 CAD 工作流的三个死结先说说为什么会有text-to-cad这个念头。我做了十几年结构设计和工装夹具手工建模的痛点总结下来就三个。第一个死结是重复劳动无法沉淀。一个法兰盘DN50 到 DN300 十几个规格每个都要重新画草图、打孔、加筋。你说用配置配置能解决尺寸变化但解决不了拓扑变化——比如小口径不需要加强筋大口径必须加。这种“结构随尺寸变”的逻辑配置表根本表达不了。第二个死结是跨工具链的数据断层。做机器人仿真的朋友最清楚在 SolidWorks 里建好模型导出 URDF 给 CoppeliaSim 用结果关节坐标系全乱了。改一次模型URDF 要重新导、重新对、重新调。STEP 文件倒是通用但 STEP 里没有运动学信息URDF 里没有精确几何两边各缺一半。第三个死结是非专业人员的参与门槛。做钣金件的师傅想改个折弯半径得找绘图员做电气柜的想挪个安装孔得等结构工程师排期。CAD 软件的操作复杂度把大量“只需要微调”的需求挡在了门外。text-to-cad要干的事就是把这三种场景统一成一句话“给我一个 DN100 的法兰盘PN16带加强筋中心孔 80螺栓孔 8 个均布。”系统理解这句话直接输出 STEP 或者 URDF。1.2 为什么是现在三个前置条件成熟了这个想法不新鲜十年前就有人尝试用脚本生成模型。但那时候做不成因为缺三样东西。参数化建模的普及是第一个条件。现在主流 CAD 都支持特征树和参数驱动OpenCASCADE、FreeCAD 的 Part 模块、CadQuery 这些库把“建模操作”变成了可编程的 API。没有这层抽象文字到模型就是空中楼阁。大语言模型的语义理解能力是第二个条件。以前用正则表达式解析“DN100 法兰盘”稍微换个说法就崩。现在模型能理解“一百的管子配的法兰”“4 寸法兰”“DN100 盘”说的是同一个东西。这种容错性是工程可用的前提。STEP 和 URDF 的生态成熟是第三个条件。STEP 是 ISO 标准几乎所有 CAD 都认URDF 是机器人领域的通用格式ROS 生态里到处都是。有了这两个出口生成的模型不愁没地方用。1.3 核心关键词拆解STEP、URDF、G-code 各管什么这三个词经常被混在一起说但它们的职责完全不同搞混了会走弯路。STEP管的是“精确几何”。它是边界表示法记录的是实体的面、边、顶点精度到小数点后很多位。你拿 STEP 去加工中心师傅能直接编程。但 STEP 里没有“这是什么零件”“它怎么动”的信息它就是一坨几何。URDF管的是“运动学结构”。它描述的是连杆、关节、坐标系之间的关系。一个 URDF 文件里几何可以用简单形状代替重点是关节类型旋转、平移、固定、关节轴、父子链接。做仿真、做运动规划URDF 是入口。G-code管的是“加工指令”。它是给机床看的一行一行告诉刀具怎么走。G-code 不关心你的模型长什么样只关心刀路。从 text 到 G-code中间必须经过 CAM 环节不是直接生成的。理解这三者的分工才能想清楚text-to-cad的输出到底该是什么。我的经验是结构件出 STEP机器人出 URDF加工件出 STEP 再转 G-code。别指望一个格式通吃。2. 技术路线选型从文字到模型的三条路2.1 路线一模板填充 参数替换这是最稳妥、最容易落地的方案。核心思路是预先做好参数化模板文字只负责提取参数值。具体做法用 CadQuery 或者 FreeCAD 的 Python API 写一个法兰盘生成函数输入是公称直径、压力等级、螺栓孔数量这些参数。然后用大语言模型解析用户输入输出一个 JSON比如{type: flange, dn: 100, pn: 16, bolt_count: 8}。最后把 JSON 喂给生成函数输出 STEP。这条路的优势是可控。模板是你写的参数范围是你定的生成结果不会跑偏。缺点是覆盖面有限每加一种零件类型就要写一个新模板。我实测下来对于标准件、常用结构件这条路能覆盖 80% 的需求。而且因为模板是参数化的改一个尺寸整个模型自动更新比手工改图快十倍不止。2.2 路线二代码生成 沙箱执行这条路更激进让大语言模型直接生成 CadQuery 或 OpenSCAD 代码然后在沙箱里执行输出模型文件。比如用户说“一个 100x60x10 的板四角打 M6 通孔孔中心距边 10mm”模型生成这样的代码import cadquery as cq result ( cq.Workplane(XY) .box(100, 60, 10) .faces(Z) .workplane() .rect(80, 40, forConstructionTrue) .vertices() .hole(6.6) )这段代码执行后直接导出 STEP。听起来很美好但坑也不少。模型可能生成语法错误的代码可能用了不存在的 API可能生成了自相交的几何。所以沙箱执行 几何校验是必须的。执行完要用 OpenCASCADE 检查实体是否有效体积是否为正有没有零厚度面。这条路的优势是灵活理论上能生成任意形状。缺点是不稳定同样的描述两次生成可能不一样工程上很难接受。2.3 路线三多模态直接生成这是最前沿的方向用三维生成模型直接输出网格或体素再转成 B-rep。但目前精度和拓扑质量还达不到工程要求生成的模型往往有自相交、非流形边这些问题。做概念设计可以做加工不行。我的建议是现阶段以路线一为主路线二为辅路线三观望。标准件走模板非标件走代码生成加人工校验别一上来就追求全自动。2.4 三条路线的对比与选型建议维度模板填充代码生成多模态生成稳定性高中低灵活性低高极高开发成本中低高几何质量高中低适合场景标准件、系列件非标结构件概念设计落地难度低中高选型逻辑很简单先问你的需求是不是标准化的。如果是螺栓、法兰、型材这些有国标的老老实实做模板。如果是“一个异形支架左边高 50右边高 80中间挖个腰形孔”这种代码生成更合适。3. 实操用 CadQuery 搭一个文字到 STEP 的流水线3.1 环境准备与依赖安装先把工具链搭起来。我用的组合是 Python 3.10 CadQuery 2.4 OpenCASCADE 7.7。CadQuery 封装了 OCCT 的建模能力API 比直接调 OCCT 友好太多。pip install cadquery2.4 pip install ocp装完之后验证一下import cadquery as cq box cq.Workplane(XY).box(10, 10, 10) cq.exporters.export(box, test.step)如果这一步报错多半是 OCCT 的动态库没找到。Linux 下用ldconfig -p | grep TK查一下Windows 下检查 PATH 里有没有 OCCT 的 bin 目录。注意CadQuery 2.x 和 1.x 的 API 差异很大网上很多老教程用的是 1.x 的写法直接抄会报错。认准 2.x 的文档。3.2 定义参数化模板以法兰盘为例法兰盘是个好例子因为它有明确的国标参数体系。我写一个生成函数输入公称直径、压力等级、螺栓孔数量输出 STEP。import cadquery as cq import math def make_flange(dn, pn, bolt_count, thicknessNone): # 根据 DN 和 PN 查表得到外径、螺栓孔中心圆直径、螺栓孔径 # 这里简化处理实际项目应该查国标表 flange_od dn * 1.8 40 bolt_circle dn * 1.5 30 bolt_hole 18 if dn 100 else 22 if thickness is None: thickness 20 if pn 16 else 28 # 主体圆盘 result ( cq.Workplane(XY) .circle(flange_od / 2) .extrude(thickness) ) # 中心通孔 result result.faces(Z).workplane().hole(dn) # 螺栓孔 result ( result.faces(Z).workplane() .polarArray(bolt_circle / 2, 0, 360, bolt_count) .hole(bolt_hole) ) return result这段代码的关键点在于polarArray它负责把螺栓孔沿圆周均布。参数bolt_circle / 2是阵列半径bolt_count是数量。实测下来polarArray的起始角度是 0 度也就是正 X 方向如果你需要错开半个孔距把起始角度改成360 / bolt_count / 2就行。3.3 文字解析层把自然语言转成参数字典模板有了接下来要把“DN100 的法兰16 公斤压力8 个螺栓孔”变成{dn: 100, pn: 16, bolt_count: 8}。我用的是大语言模型的 function calling 能力。定义一个 schema{ name: make_flange, parameters: { type: object, properties: { dn: {type: integer, description: 公称直径单位 mm}, pn: {type: integer, description: 压力等级单位 bar}, bolt_count: {type: integer, description: 螺栓孔数量} }, required: [dn, pn, bolt_count] } }然后把用户输入和这个 schema 一起发给模型模型会返回结构化的参数。这里有个经验在 prompt 里给出几个例子解析准确率会明显提升。比如告诉模型“4 寸对应 DN100”“10 公斤对应 PN10”它就能处理“4 寸的管子配的法兰10 公斤的”这种口语化输入。3.4 几何校验与 STEP 导出生成完模型不能直接给用户必须过一遍校验。我通常检查这几项实体有效性result.val().isValid()返回 True体积为正result.val().Volume() 0包围盒合理外径、厚度在预期范围内面数不为零len(result.faces().vals()) 0def validate_and_export(model, filepath): solid model.val() if not solid.isValid(): raise ValueError(生成的实体无效) if solid.Volume() 0: raise ValueError(体积异常) bbox solid.BoundingBox() print(f包围盒: {bbox.xlen:.1f} x {bbox.ylen:.1f} x {bbox.zlen:.1f}) cq.exporters.export(model, filepath)导出 STEP 的时候注意版本。cq.exporters.export默认导出 AP214这个版本支持颜色和层信息。如果你只需要几何AP203 更小更干净。在 CadQuery 里可以通过opt参数指定但 2.4 版本的接口不太稳定我一般直接用默认的。4. URDF 与 G-code两个容易被忽略的出口4.1 从 CAD 到 URDF坐标系对齐是最大的坑做机器人仿真的朋友对 URDF 又爱又恨。爱的是它是 ROS 生态的标准恨的是从 CAD 导 URDF 经常对不上。核心问题在于坐标系定义不一致。CAD 里你习惯把零件放在世界坐标系的原点但 URDF 里每个 link 有自己的局部坐标系joint 的 origin 是相对于父 link 的。如果你在 CAD 里建了一个机械臂导出 URDF 时每个连杆的坐标系都要重新定义。我的做法是在 CAD 里就把坐标系建好。每个连杆单独建一个零件文件原点放在关节旋转中心Z 轴指向关节轴向。导出 STEP 后用urdfdom或者yourdfpy这样的库组装 URDF手动指定 joint 的 origin 和 axis。from yourdfpy import URDF import numpy as np # 手动构造 URDF 的 XML 结构 urdf_str robot namearm link namebase_link visual geometry mesh filenamebase.step/ /geometry /visual /link joint namejoint1 typerevolute parent linkbase_link/ child linklink1/ origin xyz0 0 0.1 rpy0 0 0/ axis xyz0 0 1/ limit lower-3.14 upper3.14 effort10 velocity1/ /joint /robot 这里origin的xyz是子 link 原点在父 link 坐标系里的位置rpy是姿态。axis是旋转轴。这三个参数对不上仿真里机械臂就会乱飞。提示URDF 里的 mesh 文件路径是相对于 package 的用绝对路径在 CoppeliaSim 里可能加载不了。建议把 STEP 转成 STL 或 DAE放在meshes/目录下用相对路径引用。4.2 G-code 生成别跳过 CAM 环节有人问能不能从 text 直接生成 G-code。技术上可以但工程上不推荐。因为 G-code 依赖刀具、夹具、材料、机床参数这些信息文字描述里往往没有。正确的做法是text-to-cad输出 STEP然后走 CAM 软件生成 G-code。如果你非要自动化可以用 FreeCAD 的 Path 模块它支持用 Python 脚本定义加工操作。import FreeCAD import Path import Path.Op.Profile as Profile # 假设已经有一个 3D 模型 doc FreeCAD.ActiveDocument job Path.Job.Create(Job, doc.Model) tool Path.Tool.create(EndMill, 6.0) job.Tools [tool] op Profile.Create(Profile, job) op.ToolController tool这段代码只是示意实际用起来要配置的东西很多进给速度、主轴转速、下刀方式、安全高度。我的经验是批量简单的零件可以自动化复杂的还是交给 CAM 工程师。G-code 撞刀不是闹着玩的。4.3 三种输出的适用场景对照输出格式适用场景关键参数常见坑STEP结构件、加工件几何精度、单位单位搞错mm vs inchURDF机器人、仿真关节轴、坐标系坐标系不对齐G-code数控加工刀具、进给撞刀、过切5. 踩坑实录那些文档里不会写的问题5.1 单位问题毫米和英寸的百年战争CAD 领域最经典的坑就是单位。STEP 文件本身是无单位的但导出时如果不指定不同软件会按自己的默认值解释。SolidWorks 默认英寸FreeCAD 默认毫米两边一倒腾零件尺寸差 25.4 倍。我的做法是在生成模型时就显式指定单位。CadQuery 默认是毫米导出 STEP 时会在文件头写入单位信息。但如果你用 OpenSCAD 生成 STLSTL 是无单位的导入到别的软件里要手动缩放。注意URDF 里所有长度单位都是米不是毫米。从 CAD 导出的模型如果是毫米在 URDF 里要缩放 0.001。这个坑我踩过机械臂在仿真里大了 1000 倍找了半天才发现是单位问题。5.2 几何有效性自相交和零厚度面代码生成的模型经常有几何问题。最常见的是自相交——两个特征重叠了但布尔运算没处理干净。还有零厚度面——拉伸了一个闭合草图但草图本身有重合边。排查方法用 OCCT 的BRepCheck_Analyzer检查。CadQuery 里可以这样from OCP.BRepCheck import BRepCheck_Analyzer analyzer BRepCheck_Analyzer(solid.wrapped) if not analyzer.IsValid(): print(几何无效)如果无效通常是草图有问题。检查草图是否闭合、是否有重合点、是否有自相交。我的经验是用Workplane的close()方法显式闭合草图能避免大部分问题。5.3 大模型解析的边界情况文字解析层也不是万能的。用户说“一个法兰”没给尺寸模型可能瞎猜一个。用户说“大一点的法兰”模型不知道“大一点”是多少。处理策略是给参数设默认值并在返回结果里标注哪些是默认值。比如用户没说螺栓孔数量默认给 4 个但在返回信息里写“螺栓孔数量未指定已使用默认值 4”。这样用户知道哪里需要确认。还有一种情况是用户描述矛盾比如“DN100 的法兰外径 150”。DN100 的法兰外径通常在 200 左右150 明显不对。这时候要么报错让用户确认要么按标准值生成并提示冲突。5.4 常见问题速查表问题现象可能原因排查方法解决方案导出的 STEP 打不开几何无效用 BRepCheck 检查修复草图重新生成模型尺寸差 25.4 倍单位不一致检查导出设置显式指定毫米URDF 里模型乱飞坐标系不对检查 joint origin在 CAD 里对齐坐标系螺栓孔位置不对阵列起始角检查 polarArray 参数调整起始角度大模型解析出错输入太模糊看返回的 JSON加默认值提示用户6. 扩展方向从单件生成到装配体6.1 装配体的文字描述与约束求解单件生成跑通之后下一步是装配体。用户说“一个减速机输入轴在左边输出轴在右边底座四个安装孔”系统要生成多个零件并装配在一起。这比单件难得多因为涉及配合约束。轴和孔要同轴底面要贴合齿轮要啮合。目前的做法是预定义装配模板文字只负责选型和参数。比如“减速机”模板里已经定义好了轴、齿轮、箱体的配合关系文字只需要指定速比和安装方式。6.2 批量生成与版本管理工程上经常需要生成一系列模型比如 DN50 到 DN300 的所有法兰。这时候要批量跑并且管理版本。我的做法是用一个 YAML 文件定义所有规格flanges: - dn: 50 pn: 16 bolt_count: 4 - dn: 80 pn: 16 bolt_count: 4 - dn: 100 pn: 16 bolt_count: 8然后写个循环批量生成每个文件按flange_DN{dn}_PN{pn}.step命名。版本管理用 git每次生成打一个 tag。6.3 与现有 CAD 软件的集成生成的 STEP 最终要回到 CAD 软件里用。SolidWorks、中望 CAD、FreeCAD 都能导入 STEP。但导入之后是死实体没有特征树改不了。如果需要可编辑的模型得用 FreeCAD 的 Python API 直接生成.FCStd文件这样特征树是完整的。或者用 CadQuery 生成代码让用户在 CadQuery 里改代码重新生成。后者更适合参数化程度高的场景。7. 我的实操体会这套东西我断断续续搞了大半年最大的体会是别追求全自动追求半自动。文字到模型能省掉 70% 的重复劳动就是胜利剩下 30% 的人工确认和调整是必要的质量保障。另一个体会是模板的质量决定一切。模板写得糙生成一百个模型九十个要返工。模板写得细参数范围、默认值、校验规则都考虑进去生成的东西直接能用。我现在的做法是每加一个模板先手工画三个典型规格确认无误后再写成代码。还有一点STEP 和 URDF 的转换别自己写。网上有现成的工具比如step2urdf、phobos虽然不完美但比自己从零写强。把精力放在文字解析和模板设计上那才是text-to-cad的核心价值。最后分享一个小技巧如果你用大模型解析参数在 prompt 里加上“如果用户没有指定某个参数返回 null不要猜测”。这样模型不会瞎填你可以在代码里统一处理默认值。我试过不加这句话模型会给一堆莫名其妙的默认值反而增加排查成本。
返回列表