ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Text-to-CAD实战:从自然语言到STEP/DXF/URDF的自动化生成流水线

2026/10/7 17:32:04 拓冰建站 浏览量
Text-to-CAD实战:从自然语言到STEP/DXF/URDF的自动化生成流水线 CAD 这行当有个特别拧巴的地方脑子里想清楚一个零件只要几秒钟把它变成能加工、能仿真、能出图的文件却要花上几十分钟甚至几个小时。画一个法兰、一根支架、一套齿轮箱重复劳动占了大头。text-to-cad 这个方向说白了就是想把“脑子里那几秒”直接翻译成机器能读的几何文件跳过中间那段枯燥的手工建模。我最近花了不少时间在这条链路上折腾从自然语言解析到几何生成再到 STEP、DXF、URDF 这几种格式的落地踩的坑比想象中多得多。这篇文章不讲空泛的概念只讲我实际跑通的流程、参数怎么定、哪些地方容易翻车以及不同格式到底该在什么场景下用。不管你是刚接触 CAD 制图的新手还是已经在用 Python 批量改图纸的老手应该都能从里面找到能直接抄作业的东西。1. 整体设计思路与格式选型逻辑1.1 为什么不是“一句话直接出图”那么简单很多人对 text-to-cad 的第一印象是我打一句“画一个直径 80、厚 10 的法兰”软件就吐出一个三维模型。这个愿景没问题但真正落地时会发现自然语言和几何内核之间隔着好几层翻译。第一层是语义理解得把“直径 80”识别成外径参数把“厚 10”识别成拉伸高度第二层是几何构造得决定用旋转体、拉伸体还是布尔运算来生成第三层是格式序列化得把内部几何数据写成 STEP、DXF 或 URDF 能读的结构。我一开始也想一步到位直接让语言模型输出几何代码结果发现模型对坐标系、单位、拓扑关系的理解极不稳定。同一个描述跑两次一次给你一个实体一次给你两个分离的面。后来我改成“分阶段流水线”先解析成结构化的参数 JSON再由确定性的几何代码去消费这个 JSON。这样即使语言层有波动几何层也是可复现的。这个思路的代价是多写一层解析逻辑但换来的是稳定性非常值。提示不要指望语言模型直接输出可用的几何文件。让它输出参数和意图几何生成交给确定性代码这是目前最稳的工程做法。1.2 STEP、DXF、URDF 到底各管什么这三个格式经常被混在一起提但它们的定位完全不同选错了后面全是麻烦。格式本质典型用途是否含装配关系是否含运动学STEP三维实体边界表示加工、3D 打印、跨软件交换部分支持否DXF二维矢量图纸激光切割、钣金、平面加工否否URDF机器人描述 XML仿真、运动学、关节定义是是STEP 是三维实体的通用交换格式ISO 10303 标准几乎所有 CAD 软件都能读写。它的核心是 B-rep边界表示记录的是面、边、顶点的拓扑关系所以精度高、体积也大。DXF 是二维的本质是图层上的线段、圆弧、多段线集合激光切割和钣金下料基本都用它。URDF 则是机器人领域的描述文件它不关心你长什么样只关心连杆怎么连、关节怎么转、坐标系怎么摆。我踩过的一个坑是拿 STEP 去喂仿真软件做运动学结果发现它根本没有关节信息只能当静态模型看。后来才明白要做仿真必须走 URDF而且 URDF 里的几何通常用简单的碰撞体近似不是精细的加工模型。所以选型的第一原则是先问这个文件拿去干什么再决定格式。1.3 流水线的整体架构我最终跑通的架构分四段输入解析、参数校验、几何生成、格式导出。输入解析负责把自然语言变成结构化参数参数校验负责检查数值范围、单位一致性、必填项几何生成调用几何内核构造实体格式导出把实体写成目标格式。这个架构的关键在于“参数校验”这一层很多人会跳过它。我一开始也跳过了结果出现过“直径 -5”这种输入直接把几何内核搞崩的情况。加了校验之后所有非法输入在进入几何层之前就被拦下来报错信息也清晰得多。校验层还负责单位换算比如用户说“80 毫米”内部统一用毫米但如果用户说“3 英寸”就得在这里转成 76.2 毫米。2. 核心细节解析与实操要点2.1 自然语言到参数的映射规则把一句话拆成参数核心是识别“实体类型 尺寸 位置 约束”这四类信息。我用的做法是定义一套参数模板每种实体类型对应一个模板然后用规则加模型混合的方式去填充。以法兰为例模板大概是这样的{ type: flange, outer_diameter: 80, inner_diameter: 30, thickness: 10, bolt_holes: { count: 6, diameter: 8, circle_diameter: 60 }, unit: mm }解析的时候先匹配实体类型关键词法兰、支架、齿轮、轴套等再从句子里抽取数值和单位。数值抽取看起来简单其实坑很多。“直径 80”和“80 直径”都得认“M8 的孔”要理解成直径 8 的孔“6 个均布”要理解成 6 个孔均匀分布在分度圆上。我一开始用纯正则遇到“六个”这种中文数字就歇菜了后来加了一层中文数字归一化才解决。注意单位是重灾区。用户可能说“80”、“80mm”、“8 厘米”、“0.08 米”内部必须统一。我的做法是默认单位设为毫米遇到其他单位立即换算并且在返回结果里显式标注单位避免下游误读。2.2 几何生成的关键参数计算几何生成这一步很多参数不是用户直接给的而是要根据约束算出来。比如“6 个孔均布在分度圆上”分度圆直径用户可能给了也可能只给了外径和边距需要反推。再比如齿轮用户说“模数 2、齿数 20”分度圆直径就是模数乘齿数等于 40齿顶圆和齿根圆还要按标准公式算。我拿法兰的螺栓孔举例。假设外径 80用户要求孔中心到外缘留 8 毫米边距那么分度圆直径就是 80 减去两倍边距等于 64。如果用户直接给了分度圆直径 60那就以用户给的为准。孔的位置角度按 360 除以孔数均分第一个孔通常放在 0 度方向也就是正右方。这些计算看着简单但如果不写清楚不同人实现出来的孔位可能差一个角度装配时就对不上。import math def bolt_hole_positions(count, circle_diameter, start_angle_deg0): positions [] radius circle_diameter / 2.0 for i in range(count): angle math.radians(start_angle_deg i * 360.0 / count) x radius * math.cos(angle) y radius * math.sin(angle) positions.append((round(x, 4), round(y, 4))) return positions这段代码我用了很久唯一要注意的是浮点数精度。round 到四位小数是为了避免 1.2246e-16 这种科学计数法尾巴导出 DXF 的时候如果坐标带这种尾巴有些老软件会读出错。2.3 格式导出的技术要点STEP 导出依赖几何内核我用的是开源的 OpenCASCADE 系通过 Python 绑定调用。它的优势是 B-rep 精度高导出的 STEP 能被主流 CAD 软件读取。要注意的是导出前必须确保实体是“闭合”的如果有未缝合的面STEP 文件会变成一个空壳或者报错。我遇到过拉伸体因为草图没闭合导致导出失败排查了半天才发现是草图里有个微小的缺口。DXF 导出相对简单本质是把二维轮廓写成组码。但 DXF 的版本很多R12、R14、2000、2007 各有差异。激光切割机通常吃 R12 或 R14太新的版本反而不认。我一般导出 R12兼容性最好。另外 DXF 里的图层要规划好轮廓线、中心线、标注分不同图层方便下游筛选。URDF 导出是另一套逻辑。它需要你先定义连杆和关节的树状结构每个连杆挂一个几何体通常是 STL 或简单几何每个关节定义类型旋转、平移、固定、轴向、限位。URDF 本身是 XML手写也行但连杆多了容易乱。我的做法是用脚本生成把连杆和关节定义成数据结构再序列化成 XML。robot namesimple_arm link namebase_link visual geometry cylinder radius0.05 length0.1/ /geometry /visual /link joint namejoint1 typerevolute parent linkbase_link/ child linkarm_link/ axis xyz0 0 1/ limit lower-1.57 upper1.57 effort10 velocity1/ /joint /robot这段 URDF 里单位是米不是毫米这是 URDF 的惯例很多人第一次写会栽在这里。导入仿真环境时如果发现模型大了 1000 倍八成就是单位没换。3. 实操过程与核心环节实现3.1 环境搭建与依赖选择我用的主力语言是 Python原因是几何库和解析库生态最全。核心依赖有三个几何内核绑定做实体构造和 STEP 导出、ezdxf做 DXF 读写、以及一个 XML 库做 URDF 生成标准库的 xml.etree 就够。安装几何内核绑定的时候要注意版本匹配。不同版本的绑定 API 有差异尤其是布尔运算和倒角相关的接口。我建议锁定一个稳定版本不要追最新。另外 Windows 上编译几何内核有时候会遇到 C 运行库的问题如果安装时报运行库错误先装对应的 Visual C Redistributable这是最常见的原因。pip install ezdxf pip install cadquerycadquery 是我比较推荐的几何层方案它把 OpenCASCADE 封装得比较友好写起来接近“描述式建模”。比如画一个带孔的法兰几行代码就能搞定比直接调底层 API 舒服得多。3.2 从一句话到 STEP 文件的完整流程我拿“画一个外径 80、内径 30、厚 10 的法兰6 个直径 8 的孔均布在直径 60 的分度圆上”这句话走一遍完整流程。第一步解析。识别出实体类型是法兰外径 80内径 30厚度 10孔数 6孔径 8分度圆直径 60单位默认毫米。这一步输出结构化 JSON。第二步校验。检查外径大于内径厚度为正孔径小于分度圆半径减内径半径孔数在合理范围比如 2 到 24。如果外径 80、内径 30那么壁厚是 25分度圆直径 60 意味着孔中心在半径 30 处孔半径 4孔外缘到外径的距离是 40 减 30 减 4 等于 6 毫米够用。校验通过。第三步几何生成。先画外圆拉伸成圆柱再画内圆挖空最后在分度圆上打 6 个孔。用 cadquery 写大概是这样import cadquery as cq import math outer_d 80 inner_d 30 thickness 10 hole_count 6 hole_d 8 circle_d 60 result ( cq.Workplane(XY) .circle(outer_d / 2) .circle(inner_d / 2) .extrude(thickness) ) for i in range(hole_count): angle math.radians(i * 360.0 / hole_count) x (circle_d / 2) * math.cos(angle) y (circle_d / 2) * math.sin(angle) result ( result.faces(Z).workplane() .center(x, y) .hole(hole_d) ) cq.exporters.export(result, flange.step)这里有个细节.faces(Z)是选中顶面作为打孔的工作平面如果不选孔可能打错方向。另外.hole()默认是通孔如果要盲孔得指定深度。第四步导出。STEP 文件生成后我会用另一个 CAD 软件打开验证一遍确认实体是闭合的、孔位正确、尺寸无误。这一步不能省自动化生成的模型一定要人工抽检。3.3 DXF 二维图纸的生成与图层规划很多加工场景其实不需要三维模型只要二维轮廓。比如激光切割一块钣金你给它 STEP 它还得自己投影不如直接给 DXF。从同一个参数 JSON 生成 DXF思路是把三维实体的投影轮廓提取出来或者干脆用二维绘图 API 直接画。我倾向于直接画二维因为可控性更强。用 ezdxf 画法兰的俯视图import ezdxf import math doc ezdxf.new(R12) msp doc.modelspace() doc.layers.add(OUTLINE, color7) doc.layers.add(HOLES, color1) doc.layers.add(CENTER, color3) msp.add_circle((0, 0), 40, dxfattribs{layer: OUTLINE}) msp.add_circle((0, 0), 15, dxfattribs{layer: OUTLINE}) for i in range(6): angle math.radians(i * 60) x 30 * math.cos(angle) y 30 * math.sin(angle) msp.add_circle((x, y), 4, dxfattribs{layer: HOLES}) msp.add_line((-45, 0), (45, 0), dxfattribs{layer: CENTER}) msp.add_line((0, -45), (0, 45), dxfattribs{layer: CENTER}) doc.saveas(flange.dxf)图层规划是 DXF 的灵魂。轮廓一个层、孔一个层、中心线一个层下游的切割软件可以按层设置不同的加工参数比如轮廓走外切、孔走内切、中心线不加工只做参考。如果不分层所有线混在一起操作员得手动挑效率极低还容易出错。提示DXF 的 R12 版本不支持某些新特性但兼容性最好。如果你的下游设备比较老优先出 R12。如果确定设备支持新版本可以用 R2000 以上图层和线型支持更丰富。3.4 URDF 生成与仿真导入URDF 的生成逻辑和前面两个完全不同它关注的是“结构”而不是“形状”。我拿一个简单的两连杆机械臂举例用户描述“一个底座上面接一根 200 毫米的臂臂末端接一个 150 毫米的前臂两个关节都能转”。第一步是确定连杆树base_link 接 arm_linkarm_link 接 forearm_link。第二步是确定每个连杆的几何底座用圆柱臂用长方体或圆柱。第三步是确定关节两个都是旋转关节轴向通常是 Z 轴或 Y 轴限位按实际行程给。from xml.etree import ElementTree as ET robot ET.Element(robot, nametwo_link_arm) base ET.SubElement(robot, link, namebase_link) visual ET.SubElement(base, visual) geom ET.SubElement(visual, geometry) ET.SubElement(geom, cylinder, radius0.05, length0.1) arm ET.SubElement(robot, link, namearm_link) visual ET.SubElement(arm, visual) geom ET.SubElement(visual, geometry) ET.SubElement(geom, box, size0.04 0.04 0.2) joint1 ET.SubElement(robot, joint, namejoint1, typerevolute) ET.SubElement(joint1, parent, linkbase_link) ET.SubElement(joint1, child, linkarm_link) ET.SubElement(joint1, axis, xyz0 0 1) ET.SubElement(joint1, limit, lower-1.57, upper1.57, effort10, velocity1) tree ET.ElementTree(robot) ET.indent(tree, space ) tree.write(arm.urdf, encodingutf-8, xml_declarationTrue)生成之后导入仿真环境验证重点看三件事模型尺寸对不对单位问题、关节能不能动轴向和类型问题、连杆之间的相对位置对不对origin 问题。origin 是最容易错的它定义了子连杆相对父连杆的位姿包括平移和旋转。如果 origin 没写对模型会散架或者重叠。4. 常见问题与排查技巧实录4.1 几何生成阶段的典型故障几何生成阶段的问题往往最隐蔽因为报错信息经常很模糊。我整理了几个高频故障和排查思路。现象可能原因排查方法STEP 导出后打开是空文件实体未闭合或布尔运算失败检查草图是否闭合布尔运算前确认实体有效孔位偏移坐标系或角度起始点不一致打印孔位坐标和预期对比模型尺寸差 1000 倍单位混用米/毫米检查输入解析和导出环节的单位设置倒角失败倒角半径大于相邻边长度减小倒角半径或调整顺序布尔运算结果异常实体自相交或法线方向错误用几何内核的检查工具验证实体有效性我印象最深的一次是布尔运算失败排查了两个小时最后发现是两个实体刚好共面导致内核无法判断内外。解决办法是把其中一个实体偏移 0.001 毫米避开共面。这种问题在文档里基本找不到只能靠经验积累。4.2 DXF 导出的兼容性问题DXF 的兼容性问题主要集中在版本和编码上。老设备读 R12 最稳但 R12 不支持 Unicode 图层名如果图层名用了中文导出后可能乱码。我的做法是图层名一律用英文大写比如 OUTLINE、HOLES、CENTER避免编码问题。另一个坑是坐标精度。有些设备对坐标的小数位数敏感太多位会读错太少位精度不够。我一般保留三位小数兼顾精度和兼容性。如果发现切割出来的零件尺寸有偏差先检查 DXF 里的坐标精度。还有一点DXF 里的多段线LWPOLYLINE和普通线段LINE在有些软件里处理方式不同。多段线是连续的线段是离散的。如果轮廓是闭合的用多段线更好下游软件能识别成一条闭合路径。如果是一堆离散线段软件可能认为是开放的导致切割路径不闭合。4.3 URDF 导入仿真的常见报错URDF 导入仿真环境报错八成是这几个原因XML 格式错误、连杆或关节名称重复、parent 和 child 引用不存在的连杆、单位不对、mesh 文件路径错误。XML 格式错误最常见的是标签没闭合或者属性引号缺失。我建议生成后用 XML 校验工具过一遍别直接扔进仿真环境。名称重复的问题在连杆多了之后容易出现尤其是复制粘贴改的时候忘了改名。parent 和 child 引用错误通常是改名后没同步更新。mesh 文件路径是另一个大坑。URDF 里引用 STL 或 DAE 文件时路径可以是相对路径也可以是绝对路径。相对路径是相对于 URDF 文件所在目录但不同仿真环境对相对路径的解析方式可能不同。我一般用 package:// 开头的路径配合功能包结构或者干脆用绝对路径省得折腾。注意URDF 里的惯性参数质量、转动惯量如果乱填仿真时会出现奇怪的抖动或者直接飞出去。如果只是做运动学验证可以把质量设小一点转动惯量设成合理值。如果要做动力学仿真惯性参数必须准确最好从 CAD 软件里导出。4.4 参数校验的边界条件清单参数校验这层我总结了一份边界条件清单每次新增实体类型都对照检查尺寸必须为正数直径、半径、长度、厚度都不能小于等于零内径必须小于外径否则壁厚为负孔的分度圆直径必须大于内径且小于外径孔不能超出实体范围孔数必须是正整数且均布角度要能整除 360倒角半径必须小于相邻边的最小长度拉伸高度必须为正且不能大到超出合理范围单位必须明确默认毫米其他单位立即换算这份清单帮我拦下了大量低级错误。尤其是孔位超出实体范围这种如果不校验几何内核可能生成一个破面实体导出后才发现问题排查成本很高。5. 批量处理与自动化扩展5.1 用 Python 批量修改 CAD 文件的思路单个文件生成跑通之后下一步自然是批量。实际工作中经常遇到“把这一百个 DXF 的图层名统一改掉”或者“给这批 STEP 文件统一加个倒角”这种需求。手动改不现实必须脚本化。批量处理 DXF 用 ezdxf 很顺手。遍历目录下的所有 DXF打开、修改、保存。比如统一图层名import ezdxf import os src_dir ./dxf_files for filename in os.listdir(src_dir): if not filename.endswith(.dxf): continue path os.path.join(src_dir, filename) doc ezdxf.readfile(path) for layer in doc.layers: if layer.dxf.name 0: layer.dxf.name DEFAULT doc.saveas(path)批量处理 STEP 要复杂一些因为 STEP 是实体模型修改需要几何内核支持。简单的操作比如平移、旋转、缩放可以批量做复杂的比如改孔位得重新生成。我的经验是如果修改涉及几何拓扑变化重新生成比修改现有实体更可靠。5.2 参数化模板库的建立批量生成的效率瓶颈往往不在代码而在参数整理。我后来建了一个参数模板库把常用零件法兰、支架、轴套、齿轮、钣金件的参数结构固化下来每次生成只需要填参数不用重新定义结构。模板库的好处是复用和一致性。同一个法兰模板这次生成外径 80 的下次生成外径 120 的结构完全一样只是数值不同。这样下游的加工程序、检验标准都能复用不用每个新零件都重新走一遍流程。模板库的维护要注意版本管理。参数结构一旦定了尽量不要改因为改了之后所有依赖它的脚本都得跟着改。如果确实要改做好向后兼容比如新增字段给默认值不要直接删字段。5.3 与下游流程的衔接生成的 CAD 文件最终要进入下游流程可能是加工、仿真、出图或者入库。衔接做得好不好直接决定这套自动化有没有实际价值。对接加工的话重点是文件格式和图层规范。激光切割要 DXFCNC 要 STEP3D 打印要 STL。图层和命名要符合加工厂的惯例不然对方还得手动处理。我一般会随文件附一份说明写清楚单位、图层含义、材料厚度假设。对接仿真的话重点是 URDF 的完整性和惯性参数。如果仿真环境需要 mesh 文件记得把 STL 一起打包路径用相对路径并保持目录结构。对接出图的话重点是视图和标注。自动生成的二维图往往缺少标注需要额外补。这块我目前还是半自动自动生成轮廓人工补标注全自动的标注逻辑太复杂投入产出比不高。6. 实操心得与避坑经验6.1 我踩过的三个印象最深的坑第一个坑是单位。早期我没做单位归一化用户说“80”我默认毫米结果有人输入“3 英寸”生成出来的零件小了 25 倍。后来强制所有输入都带单位解析没带单位的按默认毫米处理并且在输出里显式标注。第二个坑是浮点精度。DXF 导出时坐标带科学计数法尾巴导致某些老软件读取失败。解决办法是导出前统一 round 到合理位数一般三到四位小数够用。第三个坑是 URDF 的 origin。我一开始没写 origin以为默认就行结果导入仿真后所有连杆都堆在原点。origin 必须显式定义平移和旋转都要写清楚否则仿真环境不知道子连杆该放在哪。6.2 提升生成质量的两个实用技巧第一个技巧是加一层“几何有效性检查”。生成实体后用几何内核的检查工具验证实体是否闭合、是否有自相交、法线方向是否正确。这一步能拦下大部分会导致下游出问题的模型。检查不通过的直接报错不要导出。第二个技巧是保留中间参数 JSON。每次生成都存一份参数 JSON文件名和输出文件对应。这样出了问题可以追溯也能基于同一份参数重新生成不同格式的文件。我现在的流程是参数 JSON 是源头STEP、DXF、URDF 都是它的衍生物。6.3 关于工具选型的个人建议几何内核这块cadquery 适合快速上手API 友好文档也还行。如果要做更底层的控制可以直接用 OpenCASCADE 的 Python 绑定但学习曲线陡。DXF 处理 ezdxf 基本是唯一选择成熟稳定。URDF 生成用标准库的 XML 就够了没必要上额外的库。语言模型这块如果要用建议只用来做自然语言到参数的解析不要让它碰几何。解析结果一定要经过校验层不能直接信任。模型对数值的提取有时候会出错尤其是复杂句子里的多个数值容易张冠李戴。最后说一句text-to-cad 这个方向目前还远没到“一句话出成品”的程度但“一句话出参数化草模”已经能跑通了。把重复性的建模工作自动化掉把精力留给真正需要判断力的设计决策这才是现阶段最实际的用法。我现在的做法是标准件和常用结构走自动生成复杂曲面和装配关系还是手工做两者结合效率提升很明显。