ARTICLE DETAIL

资讯详情

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

text-to-cad 实战:从自然语言到 STEP 与 URDF 三维模型生成

text-to-cad 实战:从自然语言到 STEP 与 URDF 三维模型生成 1. 从一句话到三维模型text-to-cad 到底在解决什么问题第一次听到 text-to-cad 这个词我的反应是这不就是把“用嘴画图”这件事工程化了吗。干过机械设计或者机器人仿真的朋友都清楚从需求描述到能用的三维模型中间隔着一整套繁琐的手工建模流程。客户说“我要一个 200 毫米见方、带四个安装孔的底板”你得打开 CAD 软件画草图、拉伸、打孔、倒角一套下来十几分钟没了。如果需求稍微复杂一点比如“一个两自由度的机械臂连杆”那建模时间直接按小时算。text-to-cad 要干的事情就是把这套流程压缩成“输入一段文字描述输出一个标准格式的三维模型文件”。这里的“标准格式”通常指STEP用于 CAD 交换和URDF用于机器人仿真。前者是工业界通用的三维模型交换格式后者是机器人操作系统里描述连杆和关节的标准格式。换句话说text-to-cad 不是一个单纯的“文字生成图片”玩具它瞄准的是工程落地——生成的模型要能直接导入 CAD 软件继续编辑或者丢进仿真环境里跑起来。这个方向适合谁来关注三类人最应该花时间研究。第一类是机械设计工程师日常有大量重复性建模需求想用脚本和自动化手段提效。第二类是机器人方向的开发者和研究者需要快速生成 URDF 模型做仿真验证不想每次都手动写 XML。第三类是Python 工具链爱好者对 CAD 的二次开发、参数化建模感兴趣想找一个能串起“自然语言—代码—三维模型”的完整项目来练手。我自己的判断是text-to-cad 目前还处在“能用但不够稳”的阶段它的价值不在于完全替代人工建模而在于把那些结构清晰、参数明确、重复度高的建模任务自动化掉。你描述得越规范它生成的结果越靠谱。下面我会从整体设计思路、核心技术点、实操流程、常见坑四个维度把这个项目拆开讲透。2. 整体设计思路为什么是 Python STEP URDF 这套组合2.1 核心链路拆解文字怎么变成三维模型text-to-cad 的完整链路我把它拆成四段文本解析 → 参数提取 → 几何构建 → 格式导出。每一段都有明确的输入和输出段与段之间通过结构化数据传递。文本解析这一段核心任务是把自然语言里的建模意图识别出来。比如“一个长 100、宽 50、高 20 的长方体中心开一个直径 10 的通孔”解析后要得到的是基础形状是长方体尺寸参数是 100/50/20附加特征是通孔孔径 10位置在中心。这一步通常用大语言模型来做意图识别和参数抽取因为规则匹配很难覆盖所有表达方式。参数提取之后进入几何构建阶段。这里的选择很关键是用OpenCASCADE这类专业几何内核还是用CadQuery这种基于 Python 的参数化建模库。我的实践结论是CadQuery 更适合 text-to-cad 这个场景。原因很简单CadQuery 的 API 是链式调用风格代码可读性极强而且它底层就是 OpenCASCADE导出的 STEP 文件质量有保障。你写cq.Workplane(XY).box(100, 50, 20).faces(Z).workplane().hole(10)就能得到一个带通孔的长方体这种表达方式非常适合从结构化参数自动生成。格式导出是最后一步。STEP 用于 CAD 交换URDF 用于机器人仿真。STEP 的导出在 CadQuery 里是一行代码的事URDF 则需要额外处理连杆坐标系、关节类型、惯性矩阵这些机器人特有的信息。这也是为什么 text-to-cad 项目里URDF 的生成往往比 STEP 复杂得多。2.2 为什么选 Python 作为主语言Python 在这个项目里的地位不可替代原因有三层。第一层是生态完整。CadQuery、trimesh、numpy、lxml 这些库覆盖了几何计算、网格处理、XML 生成的全部需求。你要做参数计算numpy 直接上你要写 URDF 的 XMLlxml 帮你格式化你要做几何布尔运算CadQuery 底层搞定。换成其他语言光是找齐这些库就要花不少时间。第二层是大语言模型的 Python 亲和性。现在主流的大语言模型在生成 Python 代码方面的准确率明显高于其他语言这对 text-to-cad 这种“模型生成代码、代码生成模型”的链路来说至关重要。你让模型生成 CadQuery 代码比让它直接生成 STEP 文件的二进制内容靠谱得多。第三层是调试和迭代效率。text-to-cad 的生成结果不可能一次就对你需要反复调整参数、修改描述、重新生成。Python 的交互式环境让这个过程变得非常顺畅你可以在 Jupyter Notebook 里一步步验证每个环节的输出定位问题到底出在文本解析还是几何构建。2.3 STEP 与 URDF 的分工与取舍很多人会问既然都是三维模型为什么还要分 STEP 和 URDF 两种格式直接用一个不行吗答案是两者服务的目标完全不同。STEP 是给 CAD 软件用的它描述的是精确的边界表示几何关注的是尺寸、公差、曲面质量。URDF 是给机器人仿真用的它描述的是连杆之间的运动学关系关注的是关节类型、旋转轴、坐标系变换。一个 URDF 文件里的连杆几何可以用简单的立方体代替仿真照样能跑因为仿真关心的是运动学而不是外观精度。所以在 text-to-cad 的设计里STEP 导出和 URDF 导出是两条并行的路径。STEP 路径重点保证几何精度URDF 路径重点保证运动学参数正确。如果你的目标是“生成一个能导入 SolidWorks 继续编辑的模型”那就走 STEP如果你的目标是“生成一个能在仿真环境里跑起来的机器人模型”那就走 URDF。两者可以同时导出但不要指望一个文件解决所有问题。3. 核心细节解析文本解析、几何构建与格式导出的关键要点3.1 文本解析怎么让模型“听懂”工程语言文本解析是整条链路里最不确定的一环因为自然语言的表达太灵活了。同样是描述一个孔有人写“开一个直径 10 的孔”有人写“中心打一个 10 毫米的通孔”还有人写“中间挖个洞直径 10”。如果只靠关键词匹配维护成本会高到无法接受。我的做法是用大语言模型做结构化抽取而不是做自由生成。具体来说给模型一个明确的 JSON Schema让它把描述填充进去。比如{ shape_type: box, dimensions: {length: 100, width: 50, height: 20}, features: [ {type: hole, diameter: 10, position: center, through: true} ] }这样做的好处是后续的几何构建代码只需要处理结构化数据不需要再关心自然语言的多样性。模型抽取错了你改描述重新抽几何构建有问题你改代码。两个环节解耦排查问题的时候思路清晰得多。注意给模型的 Schema 要尽量简单字段不要超过十个。字段越多模型填错的概率越大。我试过用二十多个字段的 Schema结果模型经常把尺寸单位搞混后来精简到八个字段准确率明显提升。3.2 几何构建CadQuery 的链式调用与参数化技巧CadQuery 的核心优势在于它的链式调用风格这让从结构化参数生成几何体变得非常自然。但实际用下来有几个细节必须注意。第一个细节是工作平面的选择。CadQuery 默认在 XY 平面上操作如果你要在一个已经有几何体的面上继续操作需要用workplane()切换。比如在一个长方体的顶面打孔代码是box(100, 50, 20).faces(Z).workplane().hole(10)。这里的faces(Z)是选择 Z 方向最大的面workplane()把工作平面切到这个面上hole(10)在这个面上打一个直径 10 的孔。如果忘了切工作平面孔就会打在默认的 XY 平面上位置完全不对。第二个细节是布尔运算的顺序。CadQuery 的布尔运算是按调用顺序执行的先做的运算先生效。如果你先打孔再倒角倒角可能会把孔的边缘也倒掉反过来先倒角再打孔孔的边缘就是锐利的。这个顺序没有绝对的对错取决于你的设计意图但一定要心里有数。第三个细节是参数的单位。CadQuery 默认使用毫米作为单位这和绝大多数机械设计场景一致。但如果你从文本解析拿到的参数是厘米或者英寸一定要在构建之前统一换算成毫米。我踩过一次坑客户给的描述是“2 厘米厚的板”模型直接按 2 毫米生成了差了十倍。3.3 URDF 导出连杆、关节与坐标系的处理URDF 的导出比 STEP 复杂得多因为它不只要几何信息还要运动学信息。一个典型的 URDF 文件包含link和joint两类元素。link描述连杆的几何形状和惯性参数joint描述关节的类型、位置和旋转轴。从 text-to-cad 的角度看生成 URDF 的难点在于坐标系变换。每个连杆都有自己的局部坐标系关节连接两个连杆时需要指定关节在父连杆坐标系中的位置以及子连杆相对于关节的变换。这些变换如果搞错了模型在仿真里就会散架或者穿模。我的经验是先用简单的几何体验证运动学关系再替换成精确几何。比如一个两连杆的机械臂先用两个立方体作为连杆确认关节旋转轴和坐标系变换都正确再把立方体替换成实际的连杆形状。这样做的好处是运动学问题在简单几何下更容易暴露不会被复杂的几何形状干扰判断。提示URDF 里的惯性矩阵可以用简化公式计算。对于一个质量为 m、尺寸为 (x, y, z) 的长方体惯性矩阵的对角元素是m/12 * (y² z²)、m/12 * (x² z²)、m/12 * (x² y²)。如果懒得算很多仿真环境允许你把惯性设为一个很小的值仿真照样能跑只是物理真实性差一些。4. 实操过程从零搭建一个 text-to-cad 流程4.1 环境准备与依赖安装先把环境搭起来。Python 版本建议用 3.8 以上我实测 3.10 和 3.11 都没问题。CadQuery 的安装稍微特殊一点推荐用 conda 而不是 pip因为 CadQuery 依赖 OpenCASCADE 的二进制库conda 能自动处理这些依赖。conda create -n text2cad python3.10 conda activate text2cad conda install -c conda-forge cadquery pip install lxml numpy如果你坚持用 pip也可以但可能会遇到 OpenCASCADE 库找不到的问题。我试过在 Ubuntu 上用 pip 装 CadQuery需要先手动安装libocct-*系列的系统包比较折腾。conda 省事得多。验证安装是否成功跑一段最简单的代码import cadquery as cq result cq.Workplane(XY).box(10, 10, 10) cq.exporters.export(result, test.step) print(STEP 文件导出成功)如果当前目录下出现了test.step说明环境没问题。4.2 文本解析模块的实现文本解析模块的核心是调用大语言模型的 API把自然语言转成结构化 JSON。这里我不绑定具体的模型服务只讲实现思路。import json def parse_description(description: str) - dict: prompt f 你是一个 CAD 建模助手。请把下面的描述转成 JSON 格式。 描述{description} 输出格式 {{ shape_type: box 或 cylinder 或 sphere, dimensions: {{length: 数值, width: 数值, height: 数值}}, features: [ {{type: hole, diameter: 数值, position: center 或坐标, through: true/false}} ] }} 只输出 JSON不要输出其他内容。 # 这里调用你常用的大语言模型 API response call_llm(prompt) return json.loads(response)这段代码的关键在于Prompt 的设计。我试过很多版本最后发现最有效的策略是给出明确的输出格式示例并且强调“只输出 JSON”。如果不强调这一点模型经常会在 JSON 前后加一些解释性文字导致json.loads失败。注意模型返回的 JSON 里数值可能是字符串类型比如100而不是100。在后续使用之前一定要做类型转换和校验。我写了一个validate_params函数专门检查每个字段的类型和范围把不合法的值拦在几何构建之前。4.3 几何构建与 STEP 导出拿到结构化参数之后几何构建就是按部就班的代码生成了。下面是一个完整的例子从参数到 STEP 文件import cadquery as cq def build_model(params: dict): shape_type params[shape_type] dims params[dimensions] if shape_type box: result cq.Workplane(XY).box( dims[length], dims[width], dims[height] ) elif shape_type cylinder: result cq.Workplane(XY).cylinder( dims[height], dims[radius] ) else: raise ValueError(f不支持的形状类型{shape_type}) for feature in params.get(features, []): if feature[type] hole: result result.faces(Z).workplane().hole(feature[diameter]) return result params { shape_type: box, dimensions: {length: 100, width: 50, height: 20}, features: [ {type: hole, diameter: 10, position: center, through: True} ] } model build_model(params) cq.exporters.export(model, output.step)这段代码跑完你会得到一个 100×50×20 的长方体顶面中心有一个直径 10 的通孔导出为 STEP 文件。用 FreeCAD 或者任何支持 STEP 的软件打开都能看到这个模型。4.4 URDF 生成与仿真验证URDF 的生成需要额外处理连杆和关节。下面是一个两连杆机械臂的 URDF 生成示例from lxml import etree def build_urdf(link_params: list, joint_params: list) - str: robot etree.Element(robot, nametext2cad_robot) for link in link_params: link_elem etree.SubElement(robot, link, namelink[name]) visual etree.SubElement(link_elem, visual) geometry etree.SubElement(visual, geometry) box etree.SubElement(geometry, box) box.set(size, f{link[length]} {link[width]} {link[height]}) inertial etree.SubElement(link_elem, inertial) mass etree.SubElement(inertial, mass) mass.set(value, str(link[mass])) for joint in joint_params: joint_elem etree.SubElement(robot, joint, namejoint[name], typejoint[type]) parent etree.SubElement(joint_elem, parent) parent.set(link, joint[parent]) child etree.SubElement(joint_elem, child) child.set(link, joint[child]) axis etree.SubElement(joint_elem, axis) axis.set(xyz, joint[axis]) return etree.tostring(robot, pretty_printTrue, encodingunicode) links [ {name: base_link, length: 100, width: 50, height: 20, mass: 1.0}, {name: arm_link, length: 200, width: 30, height: 30, mass: 0.5} ] joints [ {name: joint1, type: revolute, parent: base_link, child: arm_link, axis: 0 0 1} ] urdf_str build_urdf(links, joints) with open(robot.urdf, w) as f: f.write(urdf_str)生成的 URDF 文件可以直接导入支持 URDF 的仿真环境进行验证。如果关节旋转轴设错了模型在仿真里会往奇怪的方向转这时候回去检查axis字段就行。5. 常见问题与排查技巧实录5.1 文本解析阶段的典型问题问题一模型返回的 JSON 格式不合法。这是最常见的问题表现是json.loads直接抛异常。排查方法是先把模型返回的原始字符串打印出来看看是不是有多余的文字或者缺少引号。解决办法是在 Prompt 里加一句“不要输出任何解释性文字”并且在代码里加一个容错逻辑尝试从返回文本中提取第一个{到最后一个}之间的内容。问题二尺寸单位混乱。模型有时候会把“毫米”理解成“米”导致生成的模型尺寸差了一千倍。解决办法是在 Prompt 里明确要求“所有尺寸统一使用毫米”并且在参数校验阶段加一个范围检查比如长度超过 10000 毫米的模型直接拒绝提示用户确认单位。问题三特征描述丢失。比如描述里说了“四个角各打一个孔”模型只提取出一个孔。这种情况通常是 Prompt 里的 Schema 不够明确模型不知道“四个角”应该对应四个特征。解决办法是在 Schema 里增加一个count字段并且在 Prompt 里举例说明“四个角各打一个孔”应该生成四个 hole 特征。5.2 几何构建阶段的典型问题问题一布尔运算失败。CadQuery 在做布尔运算时如果两个几何体没有正确相交可能会报错或者生成空结果。排查方法是把每一步的中间结果都导出成 STEP 文件用 CAD 软件打开看看几何体是否正常。常见原因是工作平面选错了导致孔打在了几何体外面。问题二导出的 STEP 文件打不开。这种情况通常是几何体有自相交或者非流形边。解决办法是在导出之前调用model.val().isValid()检查几何有效性如果返回 False说明几何体有问题需要回去检查构建逻辑。问题三URDF 导入仿真环境后模型散架。这是坐标系变换搞错了。排查方法是把 URDF 里的每个连杆单独可视化确认每个连杆的局部坐标系原点在正确的位置。常见错误是关节的origin字段没有设置导致子连杆直接叠在父连杆的原点上。5.3 常见问题速查表问题现象可能原因排查方法解决方案JSON 解析失败模型返回了多余文字打印原始返回内容Prompt 强调只输出 JSON代码加容错提取模型尺寸差千倍单位理解错误检查参数数值范围Prompt 明确单位加范围校验孔的位置不对工作平面未切换导出中间结果查看在打孔前调用workplane()STEP 文件打不开几何体无效调用isValid()检查检查布尔运算顺序和几何相交情况URDF 模型散架坐标系变换错误单独可视化每个连杆检查 joint 的 origin 和 axis 字段仿真中关节转向错误旋转轴设置错误对比设计意图和 axis 值修改 axis 字段为正确的方向向量提示我习惯在每一步操作之后都把中间结果导出成文件虽然麻烦一点但排查问题的时候非常有用。你可以建一个debug目录每次运行都生成带时间戳的中间文件出问题了直接对比哪一步开始不对。6. 我在这条路上踩过的坑和总结的经验text-to-cad 这个方向我从最初的好奇到实际跑通一个可用的流程前后花了大概两个月。最大的体会是不要指望一步到位要把整条链路拆成可独立验证的环节。文本解析、参数校验、几何构建、格式导出每个环节都要有明确的输入输出和验证方法。哪个环节出问题就单独调试哪个环节不要混在一起查。另一个体会是Prompt 工程在 text-to-cad 里的重要性被严重低估了。很多人觉得随便写个 Prompt 让模型抽参数就行实际上 Prompt 的措辞、示例、格式约束直接决定了抽取的准确率。我现在的做法是每遇到一种新的描述方式导致抽取失败就把这个案例加到 Prompt 的示例里慢慢积累成一个覆盖各种表达方式的示例库。最后分享一个小技巧如果你要生成的模型有多个特征不要一次性让模型抽取所有特征而是分步抽取。先抽基础形状和尺寸确认无误后再抽第一个特征再抽第二个特征。这样做虽然多调用几次模型但每次的准确率都高得多总体返工成本反而更低。这个思路在参数化建模里很常见就是“分步构建、逐步验证”用在 text-to-cad 上同样有效。
返回列表