news 2026/10/27 14:55:15

text-to-cad实战:用Python和CadQuery自动生成STEP与URDF模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
text-to-cad实战:用Python和CadQuery自动生成STEP与URDF模型

1. 从一段文字到三维实体:text-to-cad 到底在解决什么问题

第一次听到 "text-to-cad" 这个词,很多人会下意识觉得它是个噱头——用一句话生成一个 CAD 模型,听起来像是把设计师的活儿直接交给机器。但真正在机械设计、机器人仿真、工业建模这些圈子里待过的人,会立刻意识到它戳中的是一个长期存在的痛点:从需求描述到可用的三维几何文件,中间那段手工建模的路太长了。

传统流程是这样的:你脑子里有一个零件或者一个结构,先要把它翻译成尺寸、约束、特征,然后在 SolidWorks、Fusion 360、中望 CAD 这类软件里一步步拉伸、旋转、倒角,最后导出成 STEP 或者 STL。这个过程对于熟练工程师来说可能只要十几分钟,但如果是批量生成、参数化变体、或者需要跟代码流水线打通,手工操作就成了瓶颈。text-to-cad 想做的事情,就是把"自然语言描述"或者"结构化文本"直接映射成 CAD 能识别的几何数据,输出 STEP、URDF 这类标准格式,让整个链路可以脚本化、自动化。

这里要先把概念理清楚。text-to-cad 不是一个具体的软件,而是一类方法的统称。它的核心链路大致是:文本输入 → 语义解析 → 几何参数提取 → 建模指令生成 → 几何内核执行 → 文件导出。关键词里出现的 STEP 和 URDF 就是两个典型的输出目标:STEP 是通用三维交换格式,几乎所有 CAD 软件都认;URDF 是机器人领域描述连杆和关节的 XML 格式,常用于仿真环境。Python 则是把这条链路串起来最顺手的语言,因为几何内核大多提供了 Python 绑定。

那它适合谁?我总结下来是三类人。第一类是做参数化设计或者批量建模的工程师,手里有一堆规格表,想批量生成模型而不是一个个画。第二类是机器人方向的研究者和开发者,需要快速生成 URDF 描述去做仿真验证。第三类是想把 CAD 能力嵌进自己工具链的开发者,比如做一个在线配置器,用户选完参数就能下载 STEP 文件。如果你属于这三类中的任何一类,这套思路值得花时间研究。

需要提前说明的是,text-to-cad 目前的能力边界很清楚:它擅长处理规则明确、参数可枚举的几何体,比如法兰、支架、齿轮毛坯、简单的连杆结构。对于自由曲面、复杂装配体、需要大量工程判断的设计,它替代不了人。把它当成一个"参数化建模的加速器"而不是"全自动设计师",心态就对了。

2. 几何内核选型:为什么 Python 生态里绕不开这几个库

动手之前,选型是第一个绕不过去的坎。text-to-cad 的底层必须有一个几何内核来真正执行建模操作,Python 这边能用的方案其实不多,各有各的脾气。我把常见的几个列出来对比一下,这些都是我在实际项目里踩过或者调研过的。

方案建模方式输出格式上手难度适用场景
CadQuery代码脚本,基于 OCCTSTEP、STL、DXF中等参数化零件、批量生成
build123d代码脚本,基于 OCCTSTEP、STL中等偏上复杂参数化、上下文建模
FreeCAD Python API脚本驱动 GUI 内核STEP、IGES、STL偏高需要 GUI 交互的自动化
OpenSCAD描述式脚本STL、CSG低简单几何、快速原型
trimesh网格处理STL、OBJ、PLY低网格操作、可视化

CadQuery 是我最推荐的起点。原因很直接:它的 API 设计贴近工程直觉,写出来的代码读起来像在描述零件本身,而且底层用的是 OpenCASCADE(OCCT)这个成熟的 B-rep 内核,导出的 STEP 质量可靠,能被主流 CAD 软件正常打开。它的安装也相对干净,pip install cadquery就能跑起来,不需要额外配置一堆环境变量。

build123d 是 CadQuery 团队后来推出的新库,思路更现代,支持上下文管理器和更灵活的布尔运算组织方式。如果你要做的模型逻辑比较复杂,build123d 的表达能力会更强,但学习曲线也陡一些。我的建议是:先用 CadQuery 把流程跑通,遇到表达瓶颈再考虑迁移到 build123d,两者底层都是 OCCT,迁移成本可控。

OpenSCAD 值得单独说一句。它是纯描述式的,用 CSG(构造实体几何)的方式堆叠基本体,语法简单到几乎像伪代码。但它的短板也很明显:没有真正的 B-rep 内核,导出的是网格,STEP 支持要靠额外转换,精度和后续可编辑性都打折扣。如果你的目标只是快速出个 STL 去打样,OpenSCAD 够用;但如果要输出 STEP 给下游 CAD 用,还是老老实实上 OCCT 系的库。

这里有个容易忽略的细节:OCCT 的版本兼容性。CadQuery 对 OCCT 版本有要求,如果你在 Linux 上通过系统包管理器装了 OCCT,再 pip 装 CadQuery,有时候会出现版本冲突导致导入报错。稳妥的做法是用 conda 环境,或者直接用官方推荐的安装方式,别自己手动拼。我在一台 Ubuntu 机器上就遇到过ImportError: libTKernel.so找不到的问题,折腾了半天发现是系统里装了个旧版 OCCT 抢了动态库路径,最后用 conda 隔离环境才解决。

提示:如果你只是想做 URDF 相关的连杆描述,其实不一定需要完整 CAD 内核。URDF 描述的是连杆的几何形状(通常是简单的基本体)和关节关系,用 Python 直接拼 XML 加上基本几何参数就够了,没必要为了生成一个圆柱连杆去装一整套 OCCT。

3. 文本到参数的映射:把一句话拆成可计算的几何量

选好内核之后,真正体现 text-to-cad 价值的地方来了:怎么把文本变成几何参数。这一步是整个链路里最"软"的部分,也是最容易做得花哨但不好用的部分。我的经验是,别一上来就想着接大语言模型做自由文本解析,先把结构化文本这条路走扎实。

什么叫结构化文本?举个例子,用户输入可能长这样:

法兰盘,外径 120mm,内径 60mm,厚度 15mm,螺栓孔 6 个,孔径 8mm,分布圆直径 100mm

这句话里,每一个数值都对应一个明确的几何参数。解析它的方式有两种:正则表达式提取,或者用键值对格式让用户直接填。正则的好处是用户输入自由,坏处是容错差,稍微换个说法就匹配不上。键值对的好处是稳定,坏处是用户得按格式来。

我实际项目里的做法是两者结合:先用一层轻量的规则匹配把常见表述归一化,比如"外径""直径""D"都映射到outer_diameter,然后再用正则抽数值。这样既保留了一定的自然度,又保证了稳定性。下面是一段我常用的解析骨架:

import re # 同义词映射表,把各种说法归一到标准参数名 SYNONYMS = { "outer_diameter": ["外径", "外圆直径", "大径", "D"], "inner_diameter": ["内径", "内圆直径", "小径", "d"], "thickness": ["厚度", "高", "t"], "hole_count": ["螺栓孔", "孔数", "孔个数"], "hole_diameter": ["孔径", "孔直径"], "bolt_circle": ["分布圆", "节圆", "中心圆"], } def normalize_text(text): for std_name, aliases in SYNONYMS.items(): for alias in aliases: text = text.replace(alias, std_name) return text def extract_params(text): text = normalize_text(text) params = {} # 匹配 "参数名 数值 单位" 的模式 pattern = r"(\w+)\s*[::]?\s*([\d.]+)\s*(mm|个)?" for match in re.finditer(pattern, text): key, value = match.group(1), float(match.group(2)) params[key] = value return params

这段代码不复杂,但有几个坑要提醒。第一,单位统一。用户可能写 mm,也可能写 cm,甚至有人写"厘米"。解析阶段必须统一到毫米,否则后面建模尺寸全乱。第二,数值和参数名的对应关系要防错位。比如"6 个螺栓孔,孔径 8mm",如果正则贪婪匹配,可能把 6 和孔径绑到一起。我的做法是让参数名紧跟在数值前面,或者用更严格的模式约束。第三,缺省值处理。用户没说的参数,要么给一个合理的默认值,要么直接报错让用户补全,千万别默默用 0 填充,那样生成的模型是废的。

如果你确实想接大语言模型做自由文本解析,我的建议是让模型输出结构化 JSON,而不是直接输出建模代码。原因很简单:模型输出的代码你没法保证正确性,但输出的 JSON 你可以做校验、做范围检查、做单位换算。把"理解语言"和"执行建模"这两件事解耦,系统的可控性会高很多。校验层至少要检查:数值是否为正、孔径是否小于外径、螺栓孔分布圆是否在合理范围内。这些检查能挡掉大部分荒谬输入。

4. 用 CadQuery 把参数变成 STEP:完整建模脚本拆解

参数拿到手,接下来就是真正建模。我以一个法兰盘为例,把完整的 CadQuery 脚本拆开讲,每一步为什么这么写都说清楚。

import cadquery as cq def build_flange(outer_d, inner_d, thickness, hole_count, hole_d, bolt_circle): # 第一步:建立基础圆盘 result = ( cq.Workplane("XY") .circle(outer_d / 2) .extrude(thickness) ) # 第二步:挖中心孔 result = ( result .faces(">Z") .workplane() .hole(inner_d) ) # 第三步:打螺栓孔 if hole_count > 0: result = ( result .faces(">Z") .workplane() .polarArray(bolt_circle / 2, 0, 360, hole_count) .hole(hole_d) ) return result # 生成并导出 flange = build_flange(120, 60, 15, 6, 8, 100) cq.exporters.export(flange, "flange.step")

这段代码看起来简单,但每一行都有讲究。cq.Workplane("XY")定义的是工作平面,XY 平面意味着圆盘躺在水平面上,厚度方向是 Z 轴。这个选择不是随意的——大多数 CAD 软件和仿真工具默认 Z 轴向上,保持一致能省掉后面旋转对齐的麻烦。

.faces(">Z")这个选择器是 CadQuery 的精髓。它的意思是"选中 Z 方向最靠上的那个面"。为什么不用坐标硬编码?因为如果你先挖了中心孔,再想在上表面打螺栓孔,用坐标定位容易出错,而用面选择器,无论模型怎么变,它总能找到正确的面。这是 CadQuery 相比直接调 OCCT API 最大的便利。

polarArray做环形阵列,参数依次是:阵列半径、起始角度、总角度、数量。这里阵列半径是bolt_circle / 2,因为分布圆直径是 100,半径就是 50。起始角度 0 意味着第一个孔在 X 轴正方向上。如果你希望孔避开某个方向,改起始角度就行。

导出 STEP 用cq.exporters.export,一行搞定。生成的 STEP 文件可以直接拖进 SolidWorks、Fusion 360、中望 CAD 里打开,几何是实心的 B-rep,不是网格,可以继续编辑。

这里分享几个实操中总结的注意点。第一,布尔运算的顺序会影响性能和稳定性。先做大的减运算(中心孔),再做小的(螺栓孔),比反过来要稳。因为 OCCT 在处理复杂形状的布尔运算时,如果基础体太碎,容易出拓扑错误。第二,孔的数量和分布要加合理性校验。如果用户输入 100 个孔分布在直径 100 的圆上,孔间距会小到几乎重叠,OCCT 可能直接报错或者生成破面。我的做法是在建模前算一下相邻孔的最小间距,小于孔径的 1.2 倍就拒绝或者警告。第三,导出前做一次几何有效性检查,CadQuery 提供了shape.isValid(),虽然不能查出所有问题,但能挡掉明显的破面。

如果你要批量生成,比如从一张 Excel 规格表里读几十个法兰,把上面的函数放进循环就行。但要注意内存管理:OCCT 的对象在 Python 里如果一直不释放,跑几百个之后内存会涨上去。我的做法是每生成一批就显式清理,或者干脆用多进程,每个进程处理一批,跑完就退出,让操作系统回收。

5. URDF 输出:从 CAD 几何到机器人仿真描述

STEP 是给 CAD 用的,URDF 是给机器人仿真用的,这两条输出路线经常被混在一起谈,其实差别很大。URDF 描述的不是精确几何,而是连杆的简化形状、质量属性、关节类型和运动范围。所以从 text-to-cad 生成 URDF,重点不在几何精度,而在结构关系的正确表达。

一个典型的 URDF 连杆长这样:

<link name="link1"> <visual> <geometry> <cylinder radius="0.05" length="0.3"/> </geometry> <origin xyz="0 0 0.15" rpy="0 0 0"/> </visual> <collision> <geometry> <cylinder radius="0.05" length="0.3"/> </geometry> </collision> <inertial> <mass value="1.0"/> <inertia ixx="0.01" iyy="0.01" izz="0.001" ixy="0" ixz="0" iyz="0"/> </inertial> </link>

用 Python 生成这个结构,最直接的方式是用字符串模板或者xml.etree.ElementTree。我倾向于用模板,因为 URDF 的结构相对固定,模板可读性更好。关键参数是:连杆的几何形状(圆柱、长方体、球)、尺寸、相对关节的偏移、质量、惯性张量。

惯性张量是最容易被忽略的部分。很多人生成 URDF 时随便填个值,结果仿真里机器人行为诡异,要么抖要么飘。对于规则几何体,惯性张量有解析公式。比如一个质量为 m、半径为 r、长度为 L 的实心圆柱,绕自身轴线的转动惯量是0.5 * m * r^2,绕径向轴的是(1/12) * m * (3r^2 + L^2)。这些公式直接算就行,别偷懒填 0。

关节部分要定义类型(revolute、prismatic、fixed 等)、父子连杆、旋转轴、运动范围。如果你的 text-to-cad 输入里包含"这个关节能转 90 度"这类描述,解析出来映射到<limit>标签的lower和upper就行。

这里有个实际经验:URDF 里的几何和 STEP 里的几何不需要一致。STEP 是精确模型,用于制造或者详细分析;URDF 里的几何是给碰撞检测和可视化用的,用简化形状反而更好,因为复杂网格会拖慢仿真。所以我的做法是,同一个零件,导出 STEP 用精确 B-rep,导出 URDF 用包围盒或者简化基本体,两套并行,各取所需。

导入 CoppeliaSim 这类仿真环境时,URDF 的路径引用要注意。如果 URDF 里引用了外部 mesh 文件,路径必须是相对路径或者正确的绝对路径,否则导入会报找不到文件。我一般把 mesh 和 URDF 放在同一个目录下,用相对路径引用,这样整个文件夹拷到哪都能用。

6. 批量生成与自动化流水线:把脚本变成生产力

单个模型生成跑通之后,真正的价值在于批量。我做过一个项目,需要根据客户提供的规格表生成上百个不同尺寸的支架模型,每个都要导出 STEP 和对应的 URDF。手工做根本不可能,全靠脚本流水线。

流水线的结构大致是:输入层(Excel/CSV/JSON)→ 校验层 → 建模层 → 导出层 → 日志层。输入层读规格表,每一行是一个零件的参数。校验层检查参数合理性,不合格的行标记出来跳过。建模层调用前面写的建模函数。导出层负责命名和存放文件。日志层记录每个零件的生成状态,方便追溯。

命名规范很重要。我用的格式是{零件类型}_{关键尺寸}_{序号}.step,比如flange_D120_d60_t15_001.step。这样光看文件名就知道大概是什么,不用打开。序号是为了防止参数完全相同的情况覆盖文件。

批量跑的时候,异常处理必须做。某个零件参数有问题导致建模失败,不能让整个批次挂掉。用 try-except 包住单个零件的生成过程,失败的记录到日志里,继续跑下一个。跑完之后统一看日志,处理失败项。

性能方面,OCCT 的建模是 CPU 密集型的,多进程能明显提速。我用multiprocessing.Pool把批次拆成几份并行跑,在 8 核机器上大概能提速 5 到 6 倍。但要注意,CadQuery 的对象不能跨进程传递,每个进程要独立导入和建模,输入输出都通过文件或者简单的可序列化数据结构。

还有一个容易被忽视的点:临时文件清理。OCCT 在建模过程中可能会产生临时文件,批量跑的时候如果不清理,磁盘会被占满。我的做法是在每个进程结束时清理自己产生的临时文件,或者把临时目录指向一个专门的位置,跑完统一删。

7. 踩过的坑:从环境配置到几何报错的排查链路

这部分是我最想写的,因为前面讲的是"应该怎么做",这里讲的是"实际会怎么翻车"。text-to-cad 这条链路,坑主要集中在环境和几何两个层面。

环境层面的坑,首当其冲是 Python 版本和依赖冲突。CadQuery 对 Python 版本有要求,太新或者太旧都可能装不上。我有一次在一台机器上用 Python 3.12,装 CadQuery 时 OCCT 的 wheel 还没适配,折腾半天最后降到 3.10 才顺利。所以我的建议是:用 conda 创建一个独立的 Python 3.10 或 3.11 环境,专门跑 CAD 相关的脚本,别跟其他项目的依赖混在一起。

第二个环境坑是动态库路径。前面提过,系统里如果装了旧版 OCCT,可能会跟 pip 装的版本冲突。排查方法是:导入 CadQuery 报ImportError时,用ldd看一下它链接的.so文件路径,如果指向系统目录而不是虚拟环境目录,就是这个问题。解决办法是确保虚拟环境的库路径优先级最高,或者干脆用 conda 装 OCCT。

几何层面的坑更隐蔽。最常见的是布尔运算失败,表现为生成的模型有破面,或者isValid()返回 False。原因通常是两个形状的接触面完全重合,OCCT 在计算交线时出现数值退化。解决办法是给一个微小的偏移,比如挖孔时孔的深度比板厚多 0.01mm,让布尔运算有明确的内外关系,而不是刚好切穿。

第二个几何坑是自相交。如果参数不合理,比如螺栓孔分布圆太小导致孔之间重叠,生成的形状会自相交,导出 STEP 时可能报错或者生成无效几何。前面说的合理性校验就是防这个的。我的校验规则里有一条:相邻孔中心距必须大于孔径的 1.5 倍,否则拒绝生成。

第三个坑是单位混乱。STEP 文件本身不强制单位,但大多数 CAD 软件默认按毫米解读。如果你的脚本里用了米,导出的模型在 CAD 里会小 1000 倍。我的做法是全程用毫米,在参数入口处就统一,绝不让米混进来。

排查几何问题的通用思路是:先简化,再定位。如果复杂模型报错,先把它拆成最简单的部分,逐个测试哪个操作失败。CadQuery 支持把中间结果导出成 STL 用网格查看器看,能直观看到哪一步出了问题。我常用的是把每一步的result都导出一次,对比看形状在哪一步变异常。

8. 这套方法还能往哪走:几个我实际验证过的扩展方向

把基础链路跑通之后,我试过几个扩展方向,有些效果不错,有些还在摸索,一并分享出来。

第一个方向是接一个简单的 Web 界面。用 FastAPI 或者 Flask 包一层,前端放几个输入框,用户填完参数点生成,后端跑建模脚本,返回 STEP 文件下载链接。这个做起来很快,适合做内部工具或者给客户做配置器。要注意的是并发控制,OCCT 建模吃 CPU,同时来十几个请求会把机器打满,加个队列或者限制并发数就行。

第二个方向是参数模板化。把常见的零件类型(法兰、支架、连杆、齿轮毛坯)做成模板,每个模板定义好参数列表和默认值,用户只需要填数值。这样比自由文本解析稳定得多,也更容易做校验。模板可以用 JSON 或者 YAML 定义,加载后动态生成输入表单。

第三个方向是跟优化算法结合。比如给定一个受力条件,让脚本自动调整尺寸参数,生成多个候选模型,再用仿真或者简单计算评估,选最优的。这个方向我试过一个简化版,用网格搜索加简单的强度估算,能跑出一些有意思的结果,但离实用还有距离,主要是评估环节不够准。

第四个方向是逆向:从现有的 STEP 文件提取参数,反推出文本描述。这个对做零件库管理有用,但实现难度不小,因为 STEP 里的几何是 B-rep,要识别出"这是一个法兰"需要做特征识别,目前没有特别成熟的 Python 方案,得自己写不少逻辑。

最后说一个我个人的判断:text-to-cad 这类工具的价值,不在于"用一句话生成模型"这个噱头,而在于把重复性的参数化建模工作自动化。真正好用的场景,是那些参数明确、变体多、需要跟其他系统打通的场合。如果你的工作里有大量"改几个尺寸重新画一遍"的活儿,那这套东西值得投入时间搭起来。搭好之后,原来一下午的活儿可能几分钟就跑完了,省下来的时间可以去做真正需要判断力的设计工作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/27 14:54:20

微电网与虚拟电厂低碳优化调度模型解析

1. 项目背景与核心价值 在能源结构转型与"双碳"目标背景下&#xff0c;微电网和虚拟电厂作为新型电力系统的重要组成单元&#xff0c;其优化调度直接影响着能源利用效率和减排效果。传统调度模型往往只考虑单一的经济性目标&#xff0c;而忽略了碳排放成本和需求侧资…

作者头像 李华
网站建设 2026/10/27 14:54:15

C#编写RTF文档编辑器:基于RichTextBox的实用指南与避坑要点

简介&#xff1a;一份基于C#语言编写的RTF文档编辑器完整工程&#xff0c;面向C#初学者、Windows桌面应用开发者及需要处理复杂富文本格式的学员。项目基于Windows Forms实现&#xff0c;支持打开、保存与另存为RTF格式文件&#xff0c;涵盖文件I/O、RichTextBox控件应用、事件…

作者头像 李华
网站建设 2026/10/27 14:53:53

FR58L4M32-2020S(A)毫米波雷达在智能仓储与智慧路灯中的应用

1. FR58L4M32-2020S(A)雷达模组核心特性解析 这款型号为FR58L4M32-2020S(A)的毫米波雷达传感器&#xff0c;是专为工业级智能感知场景设计的微波探测装置。其型号命名本身就透露着关键信息&#xff1a;FR代表Frequency Modulated Continuous Wave&#xff08;调频连续波&#x…

作者头像 李华
网站建设 2026/10/27 14:52:52

QQ聊天记录恢复全攻略:从官方方案到数据抢救

1. 为什么我们需要QQ聊天记录恢复&#xff1f;QQ作为国内最主流的即时通讯工具之一&#xff0c;承载着大量重要对话记录。我遇到过太多用户因为误操作、设备损坏或系统升级导致聊天记录丢失的案例。上周就有一位设计师客户&#xff0c;因为手机进水导致3年的客户沟通记录全部消…

作者头像 李华
网站建设 2026/10/27 14:52:51

端到端测试实战:从e2e profile1到CI集成的完整指南

1. 当“e2e”不再只是三个字母&#xff1a;从热词到落地场景的拆解第一次看到“e2e”这个词&#xff0c;很多人脑子里蹦出来的可能是“端到端”这三个字&#xff0c;然后就没有然后了。但如果你最近在技术社区、产品群或者招聘 JD 里频繁刷到它&#xff0c;尤其是“e2e profile…

作者头像 李华
网站建设 2026/10/27 14:52:36

EvoMap邀请制系统设计与实现解析

1. 项目背景与核心价值 最近在技术社区发现一个挺有意思的现象&#xff1a;不少开发者都在讨论EvoMap这个平台&#xff0c;但获取注册资格却需要邀请码。刚好看到有渠道可以通过后台留言领取&#xff0c;这让我想起早期GitHub等平台的邀请制运营模式。作为经历过多个平台从封闭…

作者头像 李华