
1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 “text-to-cad” 这个说法很多人脑子里浮现的画面大概是对着电脑说一句“给我画个齿轮”屏幕上就自动蹦出一个带参数的三维模型。这个想象方向没错但真正落地到工程实践里它解决的问题比“语音画图”要具体得多也有意思得多。text-to-cad 的核心是把自然语言描述或结构化文本转换成 CAD 软件能够识别的几何模型文件常见的输出格式包括 STEP、STL、URDF 等。它要解决的根本痛点是传统 CAD 建模依赖人工在图形界面里一步步拉伸、旋转、布尔运算一个中等复杂度的零件熟练工程师也要花几十分钟到几个小时。而大量重复性、参数化的建模需求——比如一批尺寸不同但结构相同的支架、法兰、齿轮——完全可以用文本描述驱动自动生成。这个方向适合谁来关注三类人最应该花时间研究一是机械设计工程师手里有大量参数化零件需要批量出图二是机器人方向的开发者需要频繁生成 URDF 模型来做仿真三是做自动化脚本的 Python 玩家想把 CAD 建模纳入自己的代码工作流。哪怕你只是刚接触 CAD 制图入门的新手理解这套思路也能帮你建立“模型即数据”的认知而不是把 CAD 当成纯手工活。我自己的体会是text-to-cad 不是要取代 CAD 工程师而是把工程师从“重复劳动”里解放出来。你描述清楚一个零件的几何逻辑剩下的尺寸计算、特征生成、格式导出交给代码去跑。下面我就把这套东西从思路到实操完整拆一遍。2. 整体设计思路为什么是“文本驱动 代码建模”2.1 传统 CAD 工作流的瓶颈在哪里传统 CAD 建模无论是中望 CAD、AutoCAD 还是其他主流工具本质都是交互式操作你用鼠标点选基准面画草图标注尺寸然后拉伸、倒角、阵列。这套流程对单件、非标件非常友好因为设计师可以随时调整、即时预览。但一旦遇到下面几种情况效率就断崖式下跌。第一种是参数化系列件。比如你要做 20 个内径相同、外径和厚度按等差数列变化的垫圈。手工建模意味着你要重复 20 次几乎一样的操作只是改几个数字。第二种是需要与代码系统集成的场景。机器人仿真里URDF 文件描述的是连杆的几何、质量、关节位置如果每次改结构都要回 CAD 里手动重建再导出整个开发节奏就被拖死了。第三种是批量修改。热词里有个“python 批量对 cad 修改”这恰恰是很多人的真实需求——几百张图纸要统一改图层、改标注样式手工点根本点不完。这些瓶颈的共同点是几何逻辑是确定的、可描述的但操作过程是手工的、不可编程的。text-to-cad 的思路就是把这层“可描述的逻辑”抽出来用文本表达用代码执行。2.2 文本到 CAD 的三条技术路线目前把文本变成 CAD 模型主流有三条路线各有适用场景我按落地难度从低到高排一下。第一条是代码化建模Code-CAD。代表工具是 Python 生态里的 CadQuery、build123d以及 OpenSCAD。你写的不是自然语言而是一段有几何语义的代码比如cq.Workplane(XY).circle(10).extrude(5)就生成一个直径 20、高 5 的圆柱。这条路线的“文本”是代码文本优点是精确、可版本控制、可参数化缺点是要求你会写代码。对于工程师来说这是目前最靠谱、最可控的方案。第二条是参数表驱动。你有一个模板模型把可变尺寸抽成一张表CSV、Excel 或 JSON然后用脚本读表、循环生成模型。这条路线的“文本”是数据表适合系列件批量生产。它通常和第一条路线结合使用模板用代码写数据从表里读。第三条是自然语言大模型生成。你输入一句人话模型输出建模代码或直接输出几何。这条路线的“文本”是真正的自然语言听起来最酷但目前可靠性还不够——大模型容易生成语法正确但几何错误的代码尺寸精度也没法保证。我的建议是把它当成“辅助写代码”的工具而不是“一键出图”的银弹。提示如果你追求的是工程可用性优先走第一条和第二条路线自然语言生成可以作为加速写代码的辅助但最终模型一定要人工校验关键尺寸。2.3 为什么输出格式要区分 STEP 和 URDF热词里同时出现了 STEP 和 URDF这两个格式的用途完全不同选错了会白干。STEP是通用的三维几何交换格式描述的是纯粹的几何形状不带质量、关节、运动学信息。它适合给加工、装配、跨软件协作使用。你用 CadQuery 生成一个零件导出 STEP别人用 SolidWorks 或中望 CAD 都能打开。URDF是机器人领域描述模型的标准格式它不只包含几何还包含连杆之间的关节类型旋转、平移、关节轴、质量、惯性矩阵、碰撞体等信息。热词里“urdf 导入 coppeliasim”说的就是把这个文件导入机器人仿真环境。所以如果你做的是机器人仿真光有 STEP 不够必须生成 URDF。理解这个区别很关键STEP 回答“这个零件长什么样”URDF 回答“这个机器人怎么动”。text-to-cad 项目在设计时就要想清楚最终产物是给谁用的这决定了你选哪条技术路线、导出哪种格式。3. 核心细节解析环境搭建与工具选型3.1 Python 环境准备与依赖安装整套流程跑在 Python 上所以第一步是把环境弄干净。我强烈建议用虚拟环境不要往系统 Python 里直接装否则后面依赖冲突会让你怀疑人生。先确认 Python 版本。CadQuery 目前对 Python 3.8 到 3.11 支持比较稳热词里出现的 “python 3.8” 就是个安全选择。如果你还没装去 Python 官网下载对应版本安装时记得勾选 “Add Python to PATH”省得后面手动配环境变量。# 创建虚拟环境 python -m venv cad_env # 激活Windows cad_env\Scripts\activate # 激活Linux / macOS source cad_env/bin/activate激活之后装核心库。CadQuery 的安装方式这几年变过几次现在推荐用 conda 或者 pip 装官方包pip install cadquery如果你要用 build123dCadQuery 的兄弟项目API 更现代可以pip install build123d做数据处理和批量任务numpy 基本是标配热词里“python 安装 numpy 库的方法”被搜了很多次说明很多人卡在这一步pip install numpy导出 URDF 的话还需要额外的库比如urdfpy或者直接手写 XML。手写其实更可控后面我会讲。注意CadQuery 依赖 OCCTOpen CASCADE几何内核安装包比较大第一次装可能要几分钟。如果 pip 装失败多半是网络或编译环境问题换 conda 装通常能解决。3.2 代码化建模工具对比CadQuery vs OpenSCAD vs build123d选工具这件事我踩过坑直接给结论再解释。工具语言优势劣势适合场景CadQueryPython生态成熟、导出 STEP 方便、文档多API 略啰嗦工程零件、批量生成build123dPythonAPI 更 Pythonic、上下文管理器好用相对新、社区小新项目、复杂装配OpenSCAD自有 DSL语法简单、纯文本不是真 Python、导出 STEP 需转换快速原型、教学CadQuery 的最大优势是它直接基于 OCCT导出的 STEP 是真正的 B-rep边界表示实体精度和主流 CAD 一致。OpenSCAD 用的是 CSG构造实体几何导出的是网格做展示可以做精密加工就不够了。build123d 是 CadQuery 团队后来搞的新项目写起来更顺手但如果你要的是稳定CadQuery 仍然是首选。我的建议新手从 CadQuery 入手熟悉之后可以试试 build123d。两者底层都是 OCCT切换成本不高。3.3 文本描述如何映射到几何参数这是 text-to-cad 最核心的一环怎么把一句描述变成代码里的参数。举个具体例子假设文本是“一个外径 50、内径 30、厚度 10 的垫圈”。拆解逻辑是这样的外径决定外圆半径 25内径决定内孔半径 15厚度决定拉伸高度 10。对应 CadQuery 代码import cadquery as cq outer_r 25.0 inner_r 15.0 thickness 10.0 result ( cq.Workplane(XY) .circle(outer_r) .circle(inner_r) .extrude(thickness) )这里有个细节CadQuery 里连续两个circle会在同一个草图里形成两个圆extrude时外圆和内圆之间的环形区域被拉伸中间自然是空的。这就是“文本到几何”的映射过程——把自然语言里的名词垫圈和数值外径、内径、厚度翻译成几何操作画圆、拉伸和参数。如果文本更复杂比如“带四个均布安装孔的方形法兰”你就要拆出方形边长、孔直径、孔位置半径、孔数量。这些参数一旦确定代码就是机械的循环和布尔运算。提示写映射逻辑时把所有可变尺寸抽成变量放在代码顶部不要散落在各处。这样改一个数字就能重新生成也方便后面接参数表。4. 实操过程从文本到 STEP 再到 URDF 的完整链路4.1 用 CadQuery 生成第一个参数化零件我们从一个实际零件开始一个带中心孔和四个安装孔的方形法兰。文本描述是“边长 80、厚度 8 的方形板中心有直径 30 的通孔四角各有一个直径 6 的安装孔孔中心距边缘 10”。先拆参数边长 80厚度 8中心孔半径 15安装孔半径 3安装孔中心坐标是 (±30, ±30)因为 80/2 - 10 30。import cadquery as cq side 80.0 thickness 8.0 center_hole_r 15.0 mount_hole_r 3.0 mount_offset 30.0 result ( cq.Workplane(XY) .rect(side, side) .extrude(thickness) .faces(Z) .workplane() .hole(center_hole_r * 2) .faces(Z) .workplane() .rect(2 * mount_offset, 2 * mount_offset, forConstructionTrue) .vertices() .hole(mount_hole_r * 2) ) cq.exporters.export(result, flange.step)这段代码的逻辑先画方形草图拉伸成板然后在顶面打中心孔再用一个构造矩形定位四个顶点在每个顶点打安装孔。forConstructionTrue表示这个矩形只是用来定位不参与实体。跑完这段当前目录下就有flange.step了。你可以用中望 CAD 或者任何支持 STEP 的软件打开验证。4.2 参数表驱动批量生成单个零件生成只是热身text-to-cad 真正的威力在批量。假设你要生成 10 个不同尺寸的法兰把参数放进 CSVname,side,thickness,center_hole_d,mount_hole_d,mount_offset flange_a,80,8,30,6,30 flange_b,100,10,40,8,38 flange_c,60,6,20,5,22然后用脚本读表循环生成import csv import cadquery as cq with open(params.csv) as f: reader csv.DictReader(f) for row in reader: side float(row[side]) thickness float(row[thickness]) center_hole_r float(row[center_hole_d]) / 2 mount_hole_r float(row[mount_hole_d]) / 2 mount_offset float(row[mount_offset]) result ( cq.Workplane(XY) .rect(side, side) .extrude(thickness) .faces(Z).workplane() .hole(center_hole_r * 2) .faces(Z).workplane() .rect(2 * mount_offset, 2 * mount_offset, forConstructionTrue) .vertices() .hole(mount_hole_r * 2) ) cq.exporters.export(result, f{row[name]}.step) print(fgenerated {row[name]}.step)这就是“python 批量对 cad 修改”的代码化实现。相比手工在 CAD 里改这套流程改一次参数表就能重跑全部而且结果完全一致不会有人为误差。4.3 从几何模型到 URDF机器人仿真的关键一步如果你做的是机器人方向光有 STEP 不够需要 URDF。URDF 本质是一个 XML 文件描述连杆和关节。一个最简单的单连杆 URDF 长这样?xml version1.0? robot namesimple_link link namebase_link visual geometry box size0.1 0.1 0.1/ /geometry origin xyz0 0 0 rpy0 0 0/ /visual collision geometry box size0.1 0.1 0.1/ /geometry /collision inertial mass value1.0/ inertia ixx0.001 ixy0 ixz0 iyy0.001 iyz0 izz0.001/ /inertial /link /robot注意 URDF 里的几何可以用基本体box、cylinder、sphere也可以引用外部网格文件STL、DAE。如果你用 CadQuery 生成了复杂零件可以导出 STL然后在 URDF 里用mesh filename.../引用。这里有个实操要点URDF 的坐标系和 CAD 的坐标系往往不一致。CAD 里 Z 轴朝上很常见但很多机器人仿真环境默认 Z 轴朝上、X 轴朝前导入时要做旋转。热词里“urdf 导入 coppeliasim”遇到的问题十有八九是坐标系或单位没对齐。CAD 用毫米URDF 用米导出时记得除以 1000。# 导出 STL 时注意单位 cq.exporters.export(result, link.stl, tolerance0.01)然后在 URDF 里引用并设置正确的 scalegeometry mesh filenamelink.stl scale0.001 0.001 0.001/ /geometry这个scale0.001就是把毫米转成米。忘了这一步导入仿真后模型会大 1000 倍看起来像一座山。4.4 质量与惯性参数的计算URDF 里有个容易被忽略但很关键的部分inertial。仿真里如果质量或惯性矩阵不对机器人的动力学表现会完全失真。对于规则几何体可以手算对于复杂形状可以用 Python 算。以长方体为例质量 m、边长 a、b、c惯性矩公式是Ixx m(b² c²) / 12Iyy m(a² c²) / 12Izz m(a² b²) / 12def box_inertia(m, a, b, c): ixx m * (b**2 c**2) / 12 iyy m * (a**2 c**2) / 12 izz m * (a**2 b**2) / 12 return ixx, iyy, izz ixx, iyy, izz box_inertia(1.0, 0.1, 0.1, 0.1) print(ixx, iyy, izz) # 都是 0.0001667 左右对于 CadQuery 生成的复杂实体可以用 OCCT 的能力算体积再乘以密度得到质量。惯性矩阵的精确计算比较麻烦工程上常用近似——把复杂形状近似成包围盒或圆柱。这不是偷懒而是仿真里惯性参数的精度要求本来就没那么高除非你做的是高动态场景。注意URDF 的惯性矩阵单位是 kg·m²质量单位是 kg。如果你的 CAD 模型是毫米体积算出来是 mm³换算成 m³ 要除以 10⁹再乘密度比如钢 7850 kg/m³。这一步算错仿真里的机器人会像纸片一样飘。5. 常见问题与排查技巧实录5.1 环境与安装类问题这类问题占了新手求助的一大半我整理成速查表。问题现象可能原因解决方法pip 装 cadquery 失败网络或编译依赖缺失换 conda 安装或升级 pipimport cadquery 报错虚拟环境没激活确认命令行前缀有 (cad_env)numpy 装不上Python 版本不匹配用 3.8-3.11避免最新版导出 STEP 报错实体不是有效 B-rep检查草图是否闭合、是否有自交热词里“python 安装教程”“python 环境变量配置”被反复搜说明环境这关确实劝退了不少人。我的经验是能用 conda 就用 conda它在处理几何库这种带二进制依赖的包时比 pip 省心太多。5.2 几何生成类问题最常见的坑是草图不闭合。CadQuery 里如果你画的线没有首尾相连extrude会失败或者生成奇怪的东西。排查方法是先把草图单独导出看看或者用sketch的验证方法。第二个坑是布尔运算失败。两个实体做差集时如果面重合或者相切OCCT 有时会算不出来。解决办法是稍微偏移一点比如把孔半径加 0.001避免面和面完全贴合。第三个坑是单位混乱。CadQuery 默认单位是“无单位”你按毫米输入就是毫米。但导出 STL 给 3D 打印时切片软件可能默认按毫米读也可能按米读。养成习惯在代码注释里写清楚单位导出时确认目标软件的预期单位。5.3 URDF 导入仿真环境的排查“urdf 导入 coppeliasim”是热词我专门说下这类问题的排查顺序。第一步用工具验证 URDF 语法。URDF 是 XML语法错了直接加载失败。可以用 Python 的xml.etree.ElementTree解析一遍看有没有标签不闭合。第二步检查 mesh 路径。URDF 里引用的 STL 文件路径是相对路径还是绝对路径仿真环境能不能找到。路径错了模型加载出来是空的。第三步检查坐标系和单位。前面说过scale 忘了设模型大小差 1000 倍rpy 没设对模型朝向不对。第四步检查惯性参数。如果仿真一跑机器人就飞出去或者抖动多半是质量或惯性矩阵有问题。先把惯性参数设成合理值再逐步调。提示调试 URDF 时先用最简单的单连杆模型跑通确认环境没问题再上复杂模型。不要一上来就导入整条机械臂出了问题你根本不知道是哪一环。5.4 批量任务的性能与稳定性批量生成几百个模型时有两个问题会冒出来。一是内存泄漏CadQuery 的 OCCT 对象如果不释放跑久了内存会涨。解决办法是每个模型生成完显式删除对象或者分批跑。二是单个失败导致整批中断用 try-except 包住每个模型的生成失败的记录下来不要让它拖垮整个任务。failed [] for row in reader: try: generate(row) except Exception as e: failed.append((row[name], str(e))) continue这个模式我在实际项目里用了很多次稳得很。跑完看 failed 列表针对性处理比整批重跑高效得多。6. 我踩过的坑和几条实用建议先说一个最容易被忽视的点文本描述的歧义性。你以为“直径 30 的孔”很清楚但代码里到底是半径还是直径是内径还是外径不同人理解不一样。我的做法是在参数命名上强制带单位或语义比如hole_diameter_mm、outer_radius_mm代码里一眼就能看出是什么。这个习惯能省掉大量沟通和返工。第二个坑是过度依赖自然语言生成。我试过让大模型直接根据一句话生成 CadQuery 代码十次里有三次几何是错的还有两次尺寸对不上。后来我改成自己写参数拆解和几何逻辑让模型帮我补 API 用法和语法细节。这样效率高出错率低。自然语言生成适合当“副驾驶”不适合当“自动驾驶”。第三个经验是版本控制。代码化建模最大的好处之一就是模型可以进 Git。每次改参数、改逻辑都有记录出问题能回滚。相比之下手工 CAD 文件的版本管理简直是灾难。我现在所有参数化零件都用 Git 管配合参数表改一个尺寸就是一次 commit清清楚楚。最后分享一个小技巧把常用几何操作封装成函数库。比如“打中心孔”“四角安装孔”“倒角”这些操作写一次封装好后面所有零件复用。我自己的cad_utils.py里攒了几十个这样的函数新零件基本是拼积木几分钟就能出一个。这才是 text-to-cad 真正的效率来源——不是文本本身神奇而是文本背后的代码可以复用、可以组合、可以自动化。如果你刚开始接触建议从一个最简单的零件入手把“文本描述 → 参数拆解 → 代码生成 → 导出验证”这条链路完整跑一遍。跑通之后再往上加参数表、加 URDF、加批量任务。这套东西的门槛不在工具而在你有没有把几何逻辑想清楚。想清楚了代码只是表达。