尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

text-to-cad实战:从自然语言到STEP/URDF/G-code的参数化建模流水线

text-to-cad实战:从自然语言到STEP/URDF/G-code的参数化建模流水线 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词我脑子里蹦出来的画面是对着电脑敲一行字比如“一个 80x40x20 的铝合金外壳四角带 M4 沉头孔壁厚 3mm”然后软件啪一下吐出一个能直接进加工流程的模型文件。这个画面在几年前还属于科幻范畴但现在它已经是一条能跑通的技术链路了。text-to-cad 本质上是一套把自然语言描述翻译成参数化 CAD 模型的自动化流程最终产物通常是 STEP、URDF 或者 G-code 这类下游能直接消费的格式。它解决的问题很具体传统 CAD 建模是“手工艺”一个熟练的工程师画一个中等复杂度的零件从草图约束到特征建模再到出图少说半小时复杂的结构件能耗掉一整天。而大量重复性、模板化的零件——法兰、支架、外壳、连接件——其实完全可以用参数和规则描述清楚。text-to-cad 要做的就是把这部分“描述性知识”从工程师脑子里抽出来变成可复用、可批量生成的代码逻辑。适合看这篇内容的人有三类。第一类是机械/结构工程师手里有大量相似零件要出图想用脚本替代重复劳动第二类是机器人方向的开发者需要频繁生成 URDF 模型做仿真手工建 link 和 joint 太痛苦第三类是做增材制造或数控加工的技术人员想把设计意图直接映射到 G-code 或 STEP减少中间环节的格式转换损耗。哪怕你只是刚接触 CAD 制图入门理解这套思路也能帮你建立“参数驱动”的建模意识比死记命令强得多。需要先泼一盆冷水text-to-cad 不是“说人话就能出任意模型”的魔法。当前能稳定落地的场景集中在参数明确、拓扑结构相对固定的零件上。你让它生成一个“好看的汽车外形”它大概率给你一堆没法加工的曲面垃圾但你让它生成“100 个不同孔径和长度的圆柱销”它能几秒钟干完。认清这个边界后面的实操才不会跑偏。2. 整体方案设计为什么是“参数化 代码生成”这条路2.1 三条技术路线的取舍逻辑把自然语言变成 CAD 模型业内大致有三条路可走我逐一拆过它们的可行性。第一条是端到端神经网络直接生成比如用大模型直接输出网格顶点或体素。这条路在学术上很热闹但落到工程上问题致命生成的模型没有参数历史改一个尺寸要重新生成而且拓扑质量不可控经常出现自交面、非流形边。你拿这种模型去 STEP 转换转出来的实体根本没法做布尔运算。我实测过几个开源方案生成的支架类零件十个里有六七个需要手工修补效率还不如自己画。第二条是自然语言转中间表示再转 CAD中间表示可以是 DSL领域特定语言或者结构化 JSON。这条路是目前最务实的。核心思路是让语言模型负责“理解意图并输出结构化参数”让确定性的几何内核负责“根据参数生成精确几何”。分工明确各干各擅长的事。语言模型不碰几何计算几何内核不需要理解自然语言两边通过一个约定好的 schema 对接。第三条是检索式生成从模型库里找最接近的模板再微调参数。适合标准化程度极高的场景比如标准件库但灵活性差遇到新结构就歇菜。我最终选择第二条路理由很直接可控性。工程场景里一个尺寸错了可能导致整个装配报废你需要的不是“差不多对”而是“精确可复现”。参数化路线下同样的输入永远得到同样的输出出了问题能定位到具体是哪个参数、哪条规则错了。神经网络那条路你连 debug 都无从下手。2.2 核心架构拆解整套流程我拆成四层从下往上说。几何内核层是最底层负责真正的实体建模。可选的有 OpenCASCADE开源、功能全、STEP 支持好、CGAL偏计算几何、以及各家 CAD 软件自带的 API如中望 CAD、SolidWorks 的二次开发接口。如果目标是输出 STEPOpenCASCADE 基本是首选它对 ISO 10303 标准的支持最完整。如果目标是 URDF那几何精度要求可以放宽用 trimesh 这类轻量库生成网格就够。参数化建模层建立在几何内核之上把常用特征封装成函数拉伸、旋转、打孔、倒角、阵列。这一层的关键是特征顺序的设计。CAD 建模是有历史的先打孔再倒角和先倒角再打孔结果可能完全不同。所以这一层要定义清楚特征的依赖关系不能乱序执行。意图解析层是语言模型的主场。输入一句自然语言输出一个符合 schema 的 JSON里面包含零件类型、尺寸参数、特征列表、约束条件。这里有个坑不能让模型自由发挥输出任意 JSON必须用结构化输出约束比如 JSON schema 校验或者语法引导解码否则它时不时给你加个注释、少个括号下游解析直接崩。接口层负责和用户交互可以是命令行、Web 表单也可以接在聊天工具里。这一层要做输入校验和错误提示比如用户说“直径 -5 的孔”得在进几何内核之前就拦下来。2.3 为什么输出格式选 STEP、URDF、G-code这三种格式对应三类完全不同的下游需求选型逻辑值得说清楚。STEP是 CAD 数据交换的事实标准几乎所有主流 CAD 软件都能读写。它的优势是保留精确的 B-rep边界表示几何圆弧就是圆弧不是多边形逼近。你要把生成的模型导入中望 CAD 或者别的软件继续编辑STEP 是唯一靠谱的选择。注意 STEP 有 AP203、AP214、AP242 等不同应用协议AP242 对颜色、图层、PMI 信息的支持最好优先选它。URDF是机器人描述格式本质是 XML描述的是 link 和 joint 的树状结构几何部分通常用简单的 box、cylinder、mesh 表示。它不追求几何精度追求的是运动学关系的正确性。给 Coppeliasim 这类仿真环境导入模型时URDF 是标配。这里有个热词“urdf导入coppeliasim”实际操作中经常遇到 mesh 路径不对、惯性矩阵缺失导致仿真炸飞的问题后面会专门讲。G-code是数控加工和 3D 打印的指令集是几何模型的“最终消费形态”。从 CAD 到 G-code 中间通常要经过 CAM 工序涉及刀具路径规划、进退刀策略、切削参数。text-to-cad 直接输出 G-code 的场景一般限定在结构极简单的 2.5D 零件或者标准打印件上复杂三维曲面还是得走专业 CAM。3. 核心细节解析从自然语言到几何体的关键环节3.1 意图解析怎么让模型“听懂”工程语言自然语言描述零件和日常聊天完全是两码事。“一个长 100 宽 50 厚 10 的板中间挖个直径 20 的通孔”——这句话里包含了实体类型板、三个尺寸参数、一个特征挖孔、孔的属性和位置。语言模型要做的是把这些信息无损地抽出来映射到 schema。我用的 schema 大致长这样顶层是part_type然后dimensions是个字典存基础尺寸features是个数组每个元素有type、params、position。关键是position的表达工程上孔的位置通常用坐标或者相对基准的偏移不能让模型输出“大概在中间”这种模糊描述。所以我在提示词里强制要求所有位置必须用数值加基准说明比如“以左下角为原点X 方向偏移 50Y 方向偏移 25”。这里有个实测有效的技巧给模型提供 few-shot 示例。我在系统提示里塞了三到五个标准例句和对应的 JSON模型输出的格式准确率从六成提到了九成以上。示例要覆盖常见零件类型和特征组合让模型有样学样。另一个坑是单位。工程描述里“10”可能是毫米也可能是厘米模型不会主动问。我的做法是在 schema 里强制unit字段默认毫米如果用户输入里出现“厘米”“米”就做换算。千万别省这一步我见过因为单位搞错导致整个装配尺寸差十倍的惨案。3.2 参数校验在进几何内核之前拦住错误语言模型输出的参数不能直接喂给几何内核中间必须有一层校验。校验分三类。数值合法性尺寸不能为负孔径不能大于板宽壁厚不能小于某个工艺下限。这些规则用 JSON schema 的minimum、maximum能挡掉一部分但跨字段的约束比如孔径 板宽得写自定义校验函数。几何可行性有些参数单独看合法组合起来无解。比如“在半径 10 的圆板上打一个半径 15 的孔”数学上孔比板还大几何内核会直接报错或者生成空实体。这类要在校验层提前判断给出人话的错误提示“孔径 30mm 超过了板宽 20mm请调整”。工艺合理性这一层偏经验。比如 3D 打印的悬垂角超过 45 度需要支撑CNC 加工的深孔长径比超过 10 需要特殊刀具。这些不是硬性错误但值得给用户一个警告。我在校验层加了个warnings数组不阻断流程只在输出时提示。提示校验层的错误信息一定要具体到“哪个参数、什么范围、为什么不行”不要只抛一个“参数错误”。用户看到“孔径 30 超过板宽 20”才知道怎么改看到“invalid input”只会骂人。3.3 几何生成特征建模的顺序陷阱几何内核拿到校验后的参数开始真正建模。这一步最容易出问题的地方是特征顺序。举个真实例子一个带四个角孔的矩形板如果先做四个角的倒圆角再打孔孔的位置如果靠近角可能会切到圆角面导致布尔运算失败。正确顺序应该是先打孔再倒角让倒角去处理孔边和板边的过渡。这个顺序在手工建模时工程师凭经验自然就做对了但写成代码必须显式定义。我的做法是在 schema 里给 features 加一个order字段或者直接约定数组顺序就是执行顺序。同时在生成逻辑里做依赖检查如果某个特征依赖的面还没生成就报错。比如“在顶面打孔”但顶面是后面某个拉伸操作才产生的那就得调整顺序。另一个细节是坐标系。所有特征的位置都相对于一个基准坐标系这个基准在建模开始时就要定死。我习惯用零件的包围盒左下角或者几何中心作为原点具体选哪个看零件类型。轴类零件用一端面中心板类零件用底面中心这样后续装配时对齐方便。3.4 格式导出STEP、URDF、G-code 的各自门道几何生成完导出成目标格式。三种格式的导出各有各的坑。STEP 导出相对省心OpenCASCADE 的STEPControl_Writer几行代码就能搞定。要注意的是单位STEP 文件内部默认单位是毫米如果你建模时用的是米导出前要缩放。还有精度WriteStep有个精度参数设太小文件巨大设太大圆弧变多边形一般取 0.001mm 到 0.01mm 之间比较平衡。URDF 导出麻烦得多。URDF 描述的是多刚体系统单个零件只是其中一个 link。导出时要处理几件事mesh 文件的路径必须是相对路径或者package://形式绝对路径换台机器就失效每个 link 要有惯性矩阵否则仿真时物体会飘joint 的类型revolute、prismatic、fixed和轴向要明确。我见过太多人 URDF 导入 Coppeliasim 后模型散架或者穿模九成是惯性矩阵没设或者 mesh 路径错了。G-code 导出严格来说不属于 CAD 范畴是 CAM 的活。但如果零件足够简单比如只有平面和通孔可以自己写切片逻辑直接生成。3D 打印的 G-code 核心是分层、路径规划、挤出量计算。这里不展开只提醒一点坐标系原点要和打印机约定一致通常 Z0 是热床表面别搞成模型底部。4. 实操过程手把手跑通一条 text-to-cad 流水线4.1 环境准备与依赖安装我用的技术栈是 Python OpenCASCADE通过pythonocc-core或者cadquery封装 一个大语言模型 API。CadQuery 对 OpenCASCADE 的封装比较友好语法接近自然建模思路推荐新手从它入手。安装 CadQuery 最省事的方式是 condaconda create -n text2cad python3.10 conda activate text2cad conda install -c conda-forge cadquerypip 也能装但 OpenCASCADE 的二进制依赖在 pip 下偶尔会有版本冲突conda 的包管理更稳。装完跑一句import cadquery as cq不报错就成。语言模型这块用哪家都行关键是支持结构化输出或者函数调用。我倾向用支持 JSON mode 的接口省得自己写解析器。API key 通过环境变量注入别硬编码在代码里。4.2 定义零件 schema 与提示词模板schema 我用 Pydantic 定义这样校验和序列化一体from pydantic import BaseModel, Field from typing import List, Literal, Optional class Feature(BaseModel): type: Literal[hole, slot, fillet, chamfer, pocket] params: dict position: Optional[dict] None class PartSpec(BaseModel): part_type: Literal[plate, cylinder, bracket, shaft] unit: Literal[mm, cm, m] mm dimensions: dict features: List[Feature] []提示词模板的核心是角色设定 任务说明 输出格式 示例。角色设定写“你是一名资深机械工程师擅长把设计需求转成精确的参数化描述”。任务说明强调“只输出 JSON不要解释不要 markdown 代码块”。示例给三到五个覆盖板、轴、支架。实测下来示例的质量直接决定输出质量。示例里的参数要具体位置描述要规范别用“居中”这种词用“X 偏移 板宽/2”。4.3 从一句话生成 STEP 文件的完整代码下面是一段能跑的最小实现输入一句描述输出 STEP 文件import cadquery as cq from your_llm_client import call_llm from schema import PartSpec def text_to_step(description: str, output_path: str): # 1. 调模型拿结构化参数 raw call_llm(description) spec PartSpec.model_validate_json(raw) # 2. 单位换算 scale {mm: 1.0, cm: 10.0, m: 1000.0}[spec.unit] dims {k: v * scale for k, v in spec.dimensions.items()} # 3. 根据 part_type 建模 if spec.part_type plate: model ( cq.Workplane(XY) .box(dims[length], dims[width], dims[thickness]) ) # 4. 依次应用特征 for feat in spec.features: if feat.type hole: model ( model.faces(Z) .workplane() .pushPoints([(feat.position[x], feat.position[y])]) .hole(feat.params[diameter]) ) elif feat.type fillet: model model.edges(|Z).fillet(feat.params[radius]) # 5. 导出 STEP cq.exporters.export(model, output_path, exportTypeSTEP) return output_path这段代码里几个关键点。box的尺寸顺序是长宽厚对应 X、Y、Z。faces(Z)选的是 Z 方向最大的面也就是顶面打孔要在顶面建工作平面。pushPoints接受坐标列表可以一次打多个孔。fillet选edges(|Z)是选所有平行于 Z 轴的边也就是竖直边倒圆角通常倒这些。4.4 参数计算实例一个带孔法兰的完整推导拿一个具体零件走一遍看得更清楚。需求“一个外径 100mm、内径 60mm、厚 10mm 的法兰沿圆周均匀分布 6 个直径 8mm 的螺栓孔孔中心圆直径 80mm”。解析出的参数外径 100内径 60厚 10孔数 6孔径 8孔中心圆直径 80。建模逻辑先做一个圆环体外圆柱减内圆柱再在顶面打 6 个孔。孔的位置计算是关键6 个孔均匀分布相邻夹角 360/6 60 度。第 i 个孔的坐标x (80/2) * cos(i * 60°)y (80/2) * sin(i * 60°)i 从 0 到 5。用 Python 算出来就是import math pcd 80 n 6 points [ (pcd/2 * math.cos(math.radians(i * 360/n)), pcd/2 * math.sin(math.radians(i * 360/n))) for i in range(n) ]得到六个坐标点喂给pushPoints一次打完。这里注意角度制转弧度制Python 的三角函数吃弧度忘了转的话孔位全乱。内孔用hole或者cboreHole都行但内孔是通孔直接在外圆柱上打一个直径 60 的孔贯穿即可。顺序上先做外圆柱再打内孔再打螺栓孔最后倒角去毛刺。4.5 URDF 导出与 Coppeliasim 导入实操如果目标是机器人仿真导出 URDF。单个零件转 URDF 意义不大通常是多零件装配。假设一个两轮小车的底盘和两个轮子URDF 结构是 base_link 加两个 wheel_link通过 continuous joint 连接。导出 URDF 时每个 link 的几何用 mesh 文件引用mesh 从 CadQuery 导出成 STL。惯性矩阵用简化公式算圆柱体绕中心轴的转动惯量是0.5 * m * r^2绕径向是(1/12) * m * (3r^2 h^2)。质量随便给个合理值别给零零质量在仿真里会出各种幺蛾子。导入 Coppeliasim 的步骤菜单栏 Add → Robot → Import from URDF选文件。常见问题有三个。一是 mesh 找不到检查 URDF 里的路径是相对路径且 mesh 文件和 URDF 在同一目录或子目录。二是模型位置不对URDF 的 joint origin 要和实际装配关系一致。三是仿真时模型抖动或者飞走八成是惯性矩阵没设或者碰撞体没配。注意Coppeliasim 对 URDF 的解析比较严格XML 格式错误会直接导入失败。用xmllint先校验一遍能省不少事。5. 常见问题与排查技巧实录5.1 语言模型输出不稳定怎么办这是最高频的问题。同一个描述模型这次输出对的 JSON下次多一句解释再下次少个字段。三个应对手段。第一降低温度参数。温度调到 0 或者 0.1输出确定性大幅提升。创意写作需要高温结构化输出恰恰相反。第二用 JSON schema 约束解码。很多模型接口支持传 JSON schema服务端会保证输出符合 schema省得自己写重试逻辑。第三加重试和修复。万一输出不合法把错误信息和原始输出一起塞回去让模型修通常一次就能修好。重试上限设三次超过就报错让用户重新描述。5.2 几何内核报错怎么定位OpenCASCADE 的报错信息出了名的晦涩一个Standard_Failure能对应十几种原因。我的排查顺序是先看是不是参数问题负尺寸、零尺寸再看是不是布尔运算失败面重合、自交最后看是不是精度问题微小特征导致容差冲突。布尔运算失败最常见。两个实体做差集如果面恰好重合内核可能算不出来。解决办法是给个微小偏移比如打孔时孔的深度比板厚多 0.01mm保证穿透。或者用fuse加cut的组合替代直接cut。5.3 STEP 文件导入其他 CAD 软件出问题STEP 是标准格式但各家软件的实现有差异。常见问题和对策整理成表问题现象可能原因解决办法导入后是空文件导出时实体没选中导出前确认 model 非空用model.val()检查圆弧变成多边形导出精度设太低提高 STEP 导出精度到 0.001mm颜色丢失用了 AP203 协议改用 AP242 协议导出单位不对建模单位和 STEP 默认单位不一致导出前统一缩放到毫米导入中望 CAD 报错实体有自交或非流形边导出前跑一遍model.clean()5.4 批量生成的性能优化如果要生成几百上千个零件逐个调模型 API 太慢。两个优化方向。一是批处理。把多个描述打包成一个请求让模型一次输出多个 JSON。注意控制单次请求的 token 量别超上下文窗口。二是缓存。相同的描述直接命中缓存不重复调 API。用描述文本的哈希做 key存本地或者 Redis。实测在参数化零件场景下缓存命中率能到三四成因为很多零件只是尺寸不同描述模板是一样的。几何生成这块CadQuery 单次建模耗时通常在几十毫秒到几百毫秒瓶颈在 API 调用。所以优化重点放在减少 API 调用次数上。5.5 独家避坑清单几条踩过坑才总结出来的经验常规文档里不会写。别信模型的算术。让模型算“6 个孔均匀分布的角度”它可能给你 60 度也可能给你 59.9 度。角度、坐标这类计算让模型输出公式或者参数实际计算在代码里做。文件名别用中文。STEP 和 URDF 文件路径带中文在某些软件里会乱码或者找不到文件。用英文加下划线。版本锁定。CadQuery 和 OpenCASCADE 的版本兼容性偶尔出问题生产环境把版本号写死在 requirements 里别用latest。留日志。每次生成的输入描述、模型输出、校验结果、最终文件路径都记下来。出问题时能回溯是哪一步错了。给用户反馈。生成失败时别只报错把模型原始输出和校验错误一起展示用户能判断是描述不清还是系统问题。6. 能力边界与后续扩展方向text-to-cad 目前能稳定覆盖的是单零件、参数明确、拓扑固定的场景。多零件装配、自由曲面、复杂内部流道这些还差得远。我个人的判断是未来一两年内它会先在标准件库、夹具设计、简单结构件这几个领域落地因为这些场景的参数化程度天然就高。扩展方向上我比较看好两条。一是和现有 CAD 软件的插件化集成比如做成中望 CAD 或者 SolidWorks 的插件用户在软件里直接输入描述生成模型不用切换工具。二是结合约束求解器让生成的模型自动满足装配约束比如“这个孔必须和那个轴同心”这样从单零件生成迈向装配体生成。如果你现在就想动手试建议从一个具体的小场景切入比如“批量生成不同规格的法兰”。把这一条链路跑通、跑稳比一上来就搞通用系统靠谱得多。我自己就是从法兰开始的跑了两百多个规格之后才慢慢扩展到支架和外壳。这个过程里积累的校验规则和避坑经验才是真正值钱的东西。
返回列表