ARTICLE DETAIL

资讯详情

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

text-to-cad实战:从自然语言到STEP/URDF/G-code的完整链路

text-to-cad实战:从自然语言到STEP/URDF/G-code的完整链路 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词我脑子里蹦出来的画面是对着电脑敲一行字比如“一个 80x60x10 的带四个 M4 沉头孔的安装板”回车之后一个能直接丢进切片软件或者导入仿真环境的模型就出来了。这个画面在几年前还属于科幻范畴但这两年随着大模型能力的爆发它已经变成了一个真实可跑通的技术链路。text-to-cad 本质上是一套把自然语言描述翻译成计算机辅助设计可识别格式的转换系统它的输出通常不是一张图片而是 STEP、URDF、G-code 这类带有精确几何信息或运动学信息的结构化文件。这件事为什么值得单独拿出来讲因为传统 CAD 工作流的门槛实在不低。你得先学会草图约束、拉伸切除、倒角圆角这一整套操作逻辑还得记住各种快捷键和参数面板的位置。对于机械工程师来说这不算什么但对于做机器人仿真、做 3D 打印、做教学演示的人来说为了一个简单的支架去学两周 SolidWorks投入产出比太低了。text-to-cad 瞄准的就是这个缝隙让描述需求的人直接拿到可用的几何文件把中间那层软件操作的门槛抹掉。我最初接触这个方向是因为一个机器人项目。当时需要给一个六足机器人做腿部连杆参数改来改去每次都要手动在 CAD 里重新画一遍烦得不行。后来就想能不能用脚本生成再后来就想能不能用自然语言生成顺着这条线摸下去发现社区里已经有不少人在做类似的事情只是各自的技术路线和输出格式不太一样。有人专注 STEP 这种通用交换格式有人专注 URDF 这种机器人描述格式还有人直接生成 G-code 跳过建模环节。这篇文章就把我踩过的坑、试过的方案、以及目前能稳定跑通的流程完整梳理一遍。适合读这篇内容的人大概有三类一是做机器人仿真、需要快速迭代连杆和底盘的工程师二是做 3D 打印、想跳过建模软件直接出模型的创客三是做教学或 demo、需要批量生成参数化模型的开发者。如果你属于这三类中的任何一类下面的内容应该能帮你省掉不少试错时间。2. 核心思路拆解为什么是“文本→中间表示→CAD 文件”这条链路2.1 直接端到端生成几何为什么走不通最开始我尝试的思路很直接找一个能生成三维模型的大模型输入文字输出网格文件。试了几轮之后发现两个致命问题。第一是几何精度不可控。大模型生成的网格往往是“看起来像”但尺寸是错的孔位是偏的圆角是糊的。对于展示用途可能凑合但对于要装配、要受力、要打印的零件来说尺寸错 0.5 毫米就是废品。第二是格式不通用。生成的网格是 STL 或 OBJ这种格式只有三角面片信息没有特征树、没有参数、没有约束后续想改一个孔的直径等于重新做一遍。所以端到端这条路在需要精确尺寸的场景下基本走不通。你必须让模型输出的不是几何本身而是生成几何的代码或参数。这就是中间表示的价值所在。2.2 中间表示的选择代码即模型目前社区里比较成熟的思路是让大模型输出一段参数化建模脚本再由脚本引擎执行生成 CAD 文件。常见的脚本引擎有 CadQuery、OpenSCAD、build123d 这几类。它们共同的特点是用代码描述几何尺寸是显式参数修改参数就能重新生成模型。大模型擅长写代码不擅长直接输出精确几何所以把“生成几何”转化为“生成代码”正好扬长避短。以 CadQuery 为例一段典型的描述是这样的import cadquery as cq result ( cq.Workplane(XY) .box(80, 60, 10) .faces(Z) .workplane() .rect(60, 40, forConstructionTrue) .vertices() .hole(4.5) )这段代码描述的就是一块 80x60x10 的板上面四个角有直径 4.5 的孔。大模型要做的就是把“一块 80x60x10 的板四角打 M4 孔”翻译成上面这段代码。翻译的准确率取决于提示词设计和后处理校验但整体上比直接生成网格靠谱得多。2.3 输出格式的分叉STEP、URDF、G-code 各管什么中间表示确定之后输出格式的选择取决于你的下游用途。这三类格式我都在项目里用过各自的定位差别很大。STEP是通用三维交换格式几乎所有 CAD 软件都能打开。它的优势是保留了精确的边界表示B-rep圆是真正的圆平面是真正的平面不是三角面片逼近。如果你生成的模型要导入 SolidWorks、Fusion 360、FreeCAD 继续编辑或者要发给加工厂STEP 是首选。CadQuery 和 build123d 都原生支持 STEP 导出一行cq.exporters.export(result, part.step)就搞定。URDF是机器人描述格式它描述的不是单个零件的几何而是多个连杆之间的运动学关系。一个 URDF 文件里包含 link连杆和 joint关节每个 link 可以引用一个网格文件作为视觉和碰撞几何。text-to-cad 在 URDF 场景下的任务通常是根据“一个两轮差速底盘轮距 200轮径 65”这样的描述生成底盘本体和两个轮子的几何再组装成带关节的 URDF。这个链路比单纯生成 STEP 复杂因为涉及坐标系变换和关节轴向的定义。G-code是数控加工指令直接驱动机床或 3D 打印机。跳过建模直接生成 G-code 的场景比较特殊通常用于简单的二维切割路径或者标准化的打印路径。我试过用大模型生成简单的激光切割 G-code对于直线和圆弧组成的轮廓还能应付复杂三维形状就力不从心了。所以 G-code 这条线目前更适合作为 STEP 生成之后的附加步骤而不是替代。输出格式核心用途精度特性生成难度典型下游STEP通用三维交换精确 B-rep中CAD 软件、加工URDF机器人运动学描述引用网格关节参数高仿真环境G-code数控加工指令路径级精度中低机床、3D 打印机STL网格展示/打印三角面片逼近低切片软件、展示2.4 提示词工程在 text-to-cad 里的特殊之处和普通的文本生成不同text-to-cad 的提示词需要同时约束三件事几何语义、代码语法、参数范围。我试过直接说“生成一个支架”出来的代码五花八门有的用 box 堆叠有的用 extrude 拉伸有的甚至用 spline 乱画。后来我把提示词改成固定模板先声明使用 CadQuery再给出几何特征的分解步骤最后限定输出格式为纯 Python 代码不带解释。这样生成的代码可执行率从不到 40% 提升到了 85% 以上。另一个关键是尺寸的显式化。自然语言里“大一点”“厚一些”这种模糊描述必须被翻译成具体数值。我的做法是在提示词里加一条规则如果用户没有给出具体尺寸就按常见工程惯例取整数值并在代码注释里标注假设。这样即使描述不完整生成的模型也有可用的基准尺寸后续改起来方便。3. 核心细节解析从文本到 STEP 的完整实操链路3.1 环境搭建CadQuery 安装与验证CadQuery 是目前我认为最适合做 text-to-cad 后端的引擎原因是它的 API 设计比较符合直觉而且对 STEP 导出的支持很完善。安装方式推荐用 conda因为 CadQuery 依赖 OCCT 这个几何内核pip 直接装有时候会遇到编译问题。conda create -n cadquery python3.10 conda activate cadquery conda install -c conda-forge cadquery装完之后验证一下import cadquery as cq box cq.Workplane(XY).box(10, 10, 10) cq.exporters.export(box, test.step) print(OK)如果这一步能跑通说明几何内核和导出链路都正常。我遇到过在 Windows 上因为 OCCT 版本不匹配导致导出 STEP 时崩溃的情况换成 conda 安装就解决了。所以如果你用 pip 装完发现导出报错别急着调代码先换 conda 试试。注意CadQuery 的版本迭代比较快不同版本之间 API 有细微差异。建议在项目里锁定版本号比如cadquery2.4避免因为升级导致之前跑通的代码突然报错。3.2 提示词模板设计让大模型稳定输出可执行代码提示词的质量直接决定生成代码的可执行率。我经过多轮迭代目前用的模板大致是这样的结构你是一个 CadQuery 代码生成器。根据下面的几何描述输出一段完整的 Python 代码。 要求 1. 只使用 cadquery 库不引入其他依赖。 2. 所有尺寸用变量定义在代码开头方便修改。 3. 如果描述中没有给出具体尺寸按工程惯例取整数值并在注释中说明。 4. 输出格式为纯代码不要包含解释文字。 5. 最后一行必须导出 STEP 文件到 output.step。 几何描述{user_input}这个模板的关键在于第 2 条和第 5 条。把尺寸变量集中定义后续改参数只需要改变量区不用在代码里到处找数字。强制导出 STEP 则保证了每次生成的代码都有明确的输出产物方便批量验证。我实测下来对于“带孔板”“L 型支架”“圆柱法兰”这几类常见零件这个模板的首次可执行率在 80% 到 90% 之间。失败的案例主要集中在需要复杂曲面或者布尔运算顺序敏感的场景比如“一个带螺旋槽的轴”这种就需要人工介入调整。3.3 代码校验与自动修复把可执行率再往上推即使提示词写得再好大模型偶尔还是会生成语法错误或者 API 调用错误的代码。我的做法是在生成之后加一层自动校验先尝试执行代码如果报错把错误信息连同原始代码一起回传给大模型让它修复。这个循环最多跑三次三次还修不好就标记为失败转人工处理。import subprocess import sys def try_execute(code_str): with open(temp_gen.py, w) as f: f.write(code_str) result subprocess.run( [sys.executable, temp_gen.py], capture_outputTrue, textTrue, timeout30 ) return result.returncode 0, result.stderr def generate_with_retry(prompt, max_retry3): code call_llm(prompt) for i in range(max_retry): ok, err try_execute(code) if ok: return code fix_prompt f下面的代码报错了错误信息是{err}\n请修复并输出完整代码\n{code} code call_llm(fix_prompt) return None这段逻辑看起来简单但实际效果很明显。我统计过一批 200 个生成样本首次可执行率 82%经过三轮修复之后提升到了 94%。剩下的 6% 主要是几何逻辑本身有问题比如孔打在了实体外面这种不是语法错误执行不会报错但结果不对需要另外的几何校验手段。3.4 几何合理性检查尺寸、干涉与壁厚代码能跑通不代表模型能用。我踩过的一个坑是生成的支架看起来没问题但导入切片软件之后发现某个位置的壁厚只有 0.3 毫米打印出来一碰就断。这种问题代码层面不会报错但实际使用中就是废品。所以需要在生成之后加一层几何检查。我的检查清单包括三项最小壁厚、孔位是否在实体内部、整体包围盒尺寸是否在预期范围。前两项可以用 CadQuery 的 API 做粗略判断比如遍历所有面计算相邻面的距离。第三项直接读包围盒就行。def check_bounding_box(shape, expected_max): bb shape.val().BoundingBox() size (bb.xlen, bb.ylen, bb.zlen) if any(s expected_max for s in size): return False, f包围盒超限: {size} return True, OK壁厚检查比较麻烦精确计算需要做偏移运算。我的简化做法是如果模型里有薄壁特征在提示词里强制要求最小壁厚不低于 1.5 毫米让大模型在生成代码时就遵守这个约束。这比事后检查更省事。4. 实操过程从零跑通一个“带孔安装板”的完整案例4.1 需求描述与参数确定假设我要做一个安装板自然语言描述是“一块 100x80 的板厚度 8 毫米四个角各有一个 M5 沉头孔孔中心距边缘 10 毫米。” 这段描述里包含了尺寸、特征和位置关系但缺少一些细节沉头孔的沉头直径和深度是多少M5 沉头孔的标准沉头直径是 10 毫米深度 5 毫米这些可以按标准件惯例补全。我把补全后的描述整理成结构化文本再喂给大模型创建一个矩形安装板 - 外形尺寸100mm x 80mm x 8mm - 四个角各有一个 M5 沉头孔 - 孔中心距板边缘 10mm - 沉头孔参数通孔直径 5.5mm沉头直径 10mm沉头深度 5mm - 输出 STEP 文件4.2 生成代码与首次执行大模型返回的代码如下经过格式化import cadquery as cq # 参数区 length 100.0 width 80.0 thickness 8.0 edge_offset 10.0 through_dia 5.5 counter_dia 10.0 counter_depth 5.0 # 创建基板 plate cq.Workplane(XY).box(length, width, thickness) # 计算四个孔的中心坐标 x_pos length / 2 - edge_offset y_pos width / 2 - edge_offset hole_positions [ (x_pos, y_pos), (-x_pos, y_pos), (-x_pos, -y_pos), (x_pos, -y_pos), ] # 打沉头孔 for x, y in hole_positions: plate ( plate.faces(Z).workplane() .center(x, y) .cboreHole(through_dia, counter_dia, counter_depth) ) cq.exporters.export(plate, mounting_plate.step)这段代码逻辑是对的但有一个隐患cboreHole是在Z面上操作的每次循环都会重新选择Z面。如果沉头孔打完之后Z面发生了变化后续的孔位可能会偏移。我实际跑了一遍发现 CadQuery 的cboreHole不会改变面的选择逻辑四个孔都正确打出来了。但为了保险更好的做法是先在所有位置打穿通孔再统一做沉头。4.3 模型验证与导出代码执行之后生成了mounting_plate.step。我用 FreeCAD 打开检查了一下外形尺寸 100x80x8 正确四个沉头孔位置正确沉头直径和深度也符合预期。包围盒检查通过最小壁厚在孔边缘到板边缘之间是 10 毫米减去沉头半径 5 毫米等于 5 毫米远大于 1.5 毫米的安全线。如果你要批量生成类似的板类零件可以把参数区抽出来做成配置表用循环批量生成。我做过一个项目需要生成 20 种不同尺寸的安装板就是把尺寸参数写成 CSV然后逐行替换提示词里的数值批量跑一遍半小时生成了全部 STEP 文件比手动建模快了一个数量级。4.4 从 STEP 到 URDF机器人场景的延伸安装板本身是静态零件不需要 URDF。但如果你做的是机器人底盘就需要把多个零件组装成带关节的 URDF。我以两轮差速底盘为例说明这个流程。首先用 text-to-cad 分别生成底盘本体和两个轮子的 STEP 文件。然后在 URDF 里定义 link 和 jointrobot namediff_drive link namebase_link visual geometry mesh filenamechassis.stl/ /geometry /visual /link link nameleft_wheel visual geometry mesh filenamewheel.stl/ /geometry /visual /link joint nameleft_wheel_joint typecontinuous parent linkbase_link/ child linkleft_wheel/ origin xyz0 0.1 -0.03 rpy0 0 0/ axis xyz0 1 0/ /joint /robot这里的关键是origin的坐标和axis的方向。轮距 200 毫米意味着左右轮中心各偏移 100 毫米所以 y 方向是 0.1 米。轮径 65 毫米意味着轮心比底盘底面低 32.5 毫米所以 z 方向是 -0.03 米左右。这些数值如果手动算容易出错我的做法是在生成 STEP 的同时让大模型一并输出这些关节参数减少人工换算。提示URDF 里的 mesh 文件建议用 STL 而不是 STEP因为大多数仿真环境对 STL 的支持更好。CadQuery 可以同时导出两种格式一行代码的事。5. 常见问题与排查技巧实录5.1 生成代码报错从错误信息反推问题大模型生成的 CadQuery 代码最常见的报错有三类。第一类是API 名称拼写错误比如把cboreHole写成counterBoreHole。这种错误看报错信息就能定位修复也简单。第二类是参数类型错误比如把直径传成了字符串。第三类是选择器失效比如faces(Z)在某个操作之后找不到面了。我的排查顺序是先看报错行号再看那一行调用的 API 签名最后检查选择器的作用对象。如果报错信息里出现StdFail_NotDone或者BRep_API: command not done通常是几何运算失败比如布尔减的时候两个实体没有相交。这种时候需要检查孔位坐标是否真的落在了实体内部。5.2 模型能生成但尺寸不对单位与坐标系陷阱我遇到过一次很诡异的情况生成的模型在 FreeCAD 里打开尺寸显示是 100 毫米但导入切片软件之后变成了 100 英寸。排查了半天发现是 STEP 文件的单位声明问题。CadQuery 默认导出单位是毫米但某些下游软件会按英寸解析。解决办法是在导出时显式指定单位或者在导入端手动设置。另一个常见问题是坐标系朝向。CadQuery 默认的 XY 平面是水平面Z 轴朝上。但有些仿真环境默认 Z 轴朝前或者 Y 轴朝上。如果生成的模型导入之后方向不对不要急着改代码先检查下游环境的坐标系设置。大多数情况下一行旋转就能解决不需要重新生成。5.3 批量生成时的稳定性问题批量跑的时候最怕的是某个样本卡死。我遇到过 CadQuery 在处理复杂布尔运算时卡住超过五分钟的情况。解决办法是给每个生成任务加超时限制超时就跳过并记录不要让整个批次挂掉。另外CadQuery 的某些操作在多次调用之后会有内存泄漏的迹象建议每生成 50 个模型就重启一次进程。问题现象可能原因排查方法解决手段代码执行报错API 拼写/参数类型看报错行号和 API 签名回传错误信息让模型修复几何运算失败布尔运算无交集检查孔位坐标调整坐标或改用其他建模顺序尺寸偏差单位声明不一致对比源文件和导入端单位显式指定导出单位方向不对坐标系定义差异检查下游环境坐标系导入时旋转或重新导出批量卡死复杂运算超时加超时监控跳过并记录分批重启5.4 提示词迭代的经验教训我最初写的提示词很啰嗦把各种约束条件都堆上去结果大模型反而容易混淆。后来发现提示词要分层第一层是角色和输出格式第二层是几何描述第三层是特殊约束。层与层之间用空行隔开让模型能清晰区分。另一个教训是不要在一次提示里塞太多特征。如果一个零件有十几个特征拆成多次生成再合并比一次性生成的成功率高。比如先做基板再做孔再做倒角每一步单独生成代码然后拼接。这样即使某一步失败也不需要全部重来。6. 工具选型与扩展方向什么场景用什么方案6.1 CadQuery vs OpenSCAD vs build123d这三个是我实际用过的参数化建模引擎各有适用场景。OpenSCAD是最老牌的语法简单但它的几何内核是 CGAL对复杂曲面的支持不如 OCCT导出 STEP 需要额外转换。CadQuery基于 OCCTSTEP 导出原生支持API 也比较现代是我目前的主力选择。build123d是 CadQuery 的衍生项目API 更接近面向对象风格适合喜欢用类和方法链的开发者。选型建议如果你只需要做简单的板类、轴类零件OpenSCAD 够用且轻量。如果你需要精确的 STEP 输出和复杂的布尔运算CadQuery 更稳。如果你追求代码的可读性和可维护性build123d 值得一试。6.2 大模型选型本地还是云端text-to-cad 的代码生成环节可以用云端大模型也可以用本地部署的模型。云端模型的代码能力通常更强但需要考虑数据隐私和调用成本。本地模型比如 CodeLlama 或者 DeepSeek Coder在 CadQuery 代码生成上的表现已经可用了尤其是经过少量微调之后。我的做法是开发调试阶段用云端模型快速迭代提示词生产环境如果涉及敏感几何数据就切到本地模型。本地模型的部署成本主要是显卡一张 16G 显存的卡跑 7B 参数的代码模型绰绰有余。6.3 后续扩展从单零件到装配体单零件生成跑通之后下一步自然是装配体。装配体的难点在于零件之间的配合关系。比如“轴插入孔中”这个描述里隐含了同轴约束和端面贴合约束。目前大模型对这种空间关系的理解还不够稳定我的做法是把装配关系拆解成显式的坐标变换让大模型只负责生成单个零件装配逻辑用脚本硬编码。另一个扩展方向是参数化模板库。把常见的零件类型板、轴、法兰、支架做成模板每个模板有固定的参数接口。用户输入自然语言之后先分类到某个模板再提取参数填充。这样比完全自由生成更可控适合批量生产场景。6.4 我踩过的最大的一个坑最后分享一个让我折腾了两天的坑。有一次生成的 STEP 文件在 FreeCAD 里打开正常但导入到某个仿真环境之后碰撞检测一直报错。排查到最后发现是 STEP 文件里的面法线方向不一致。CadQuery 在某些布尔运算之后会生成法线朝内的面FreeCAD 能自动修正但那个仿真环境不会。解决办法是在导出之前加一步shape.fix()或者重新做一次clean()操作。这个坑在文档里基本找不到只能靠实际踩出来。所以如果你做的是仿真相关的应用生成 STEP 之后最好用目标仿真环境实际导入测试一遍不要只在 CAD 软件里检查。不同软件对几何文件的容错程度差别很大CAD 软件能打开的仿真环境不一定能正确处理。
返回列表