3.2 从 STEP 到零件 STL:cascadio 自动化导出

3.2 从 STEP 到零件 STL:cascadio 自动化导出

上下文回顾 :3.1 我们理清了 STEP → GLB → STL → MJCF 的数据流。本节聚焦前半段------如何把 ElectronBot.step 里的几百个实体,自动拆成一个个独立的 STL 网格。
一个重要澄清 :本节文件名沿用了老教程的「FreeCAD 命令行导出」,但当前仓库的实际做法并不依赖 FreeCAD 。项目已改用 cascadio + trimesh 的纯 Python 流水线(scripts/step_to_mjcf.py),一条命令跑完,无需打开 FreeCAD。assets/cad/ 里的 .FCStd / .FCMacro 是早期人工建模阶段的产物,仅作结构参考。


1. 为什么放弃手工 FreeCAD 导出?

✗ 手工 FreeCAD 导出 300+ 零件逐个手工导出 坐标 / 命名难对齐脚本 换图纸就要重来(不可复现) ✓ 全自动 cascadio + trimesh STEP 进 → 零件 STL 出 中间零人工、可复现 一条命令跑完 图 3.2-1 手工 FreeCAD 导出 vs 全自动流水线:数量大、不可复现是根本矛盾。

早期方案是:在 FreeCAD 里打开工程 → 手动选中零件 → 一个个 Export STL。缺点很明显:

  • 300+ 个零件手工导出不现实;
  • 每个零件的坐标、命名难以和后续脚本对齐;
  • 无法复现------换一版图纸就要重来一遍。

所以现在改成全自动:STEP 进,零件 STL 出,中间零人工。


2. 核心依赖:cascadio 与 trimesh

cascadio OpenCASCADE · STEP→GLB trimesh 读 GLB · 遍历场景图 numpy 坐标 / 变换矩阵 图 3.2-2 三个核心依赖各司其职:三角化、场景图遍历、矩阵计算。

作用
cascadio 基于 OpenCASCADE 的 STEP → GLB 转换器,负责把 B-Rep 实体三角化
trimesh 读取 GLB,遍历其场景图(scene graph),逐节点导出网格
numpy 坐标 / 变换矩阵计算

安装(若未装):

bash 复制代码
pip install cascadio trimesh numpy

3. 第一步:STEP → GLB

ElectronBot.step STEP 输入 cascadio.step_to_glb 三角化(仅首次) ElectronBot_scene.glb 缓存 + trimesh.load 产物 = 场景图:每个零件是一个带 4×4 变换矩阵的节点 图 3.2-3 STEP 经 cascadio 三角化为 GLB 并缓存,trimesh 加载后得到带节点层级的场景图。

step_to_mjcf.py 首先调用 cascadio 把整份 STEP 转成一个 GLB,并缓存下来,避免每次重跑都做一次耗时的三角化:

python 复制代码
import cascadio, trimesh

glb_path = "assets/meshes/ElectronBot_scene.glb"
if not os.path.exists(glb_path):
    cascadio.step_to_glb(step_path, glb_path)   # 仅首次执行
scene = trimesh.load(glb_path)                  # 得到一个 trimesh.Scene

得到的 scene 是一个场景图:每个零件是图里的一个节点,节点上挂着该零件的三角网格,以及它相对父节点的 4×4 变换矩阵。这层「节点 + 变换」信息,正是后面重建关节树和摆正零件位置的关键。


4. 第二步:遍历场景图,逐件导出 STL

scene.graph 遍历 每个几何节点 apply_transform 世界坐标网格 平移到质心原点 -centroid step_*.stl (世界) 校验对齐 step_*_local.stl MJCF 引用 图 3.2-4 遍历场景图 → 每个零件导出两份 STL(世界坐标用于校验、本地坐标供 MJCF 引用)。

脚本遍历 scene.graph 里的每个几何节点,把它作为独立零件导出:

python 复制代码
for node_name in scene.graph.nodes_geometry:
    transform, geom_name = scene.graph[node_name]   # 该节点的世界变换 + 几何名
    mesh = scene.geometry[geom_name].copy()
    mesh.apply_transform(transform)                 # 应用世界变换 → 世界坐标网格

    # 1) 世界坐标 STL(用于校验对齐)
    mesh.export(f"assets/meshes/step_parts/step_{safe_name}.stl")

    # 2) 记录质心,做坐标本地化(下一节详解)
    centroid = mesh.centroid
    mesh.apply_translation(-centroid)               # 平移到原点
    mesh.export(f"assets/meshes/step_parts/step_{safe_name}_local.stl")

每个零件因此产生两个 STL:

  • step_<name>.stl:保留在世界坐标里,用来肉眼核对整机装配对不对;
  • step_<name>_local.stl:把网格平移到自身质心原点,MJCF 里 <mesh> 引用的是这一批,零件的实际位置改由 <body pos="..."> 承载。

5. 导出结果

step_parts/ step_*.stl × 369(世界坐标) step_*local.stl × 349 (本地坐标,MJCF 引用) 节点名形如 Open_CASCADE_STEP_translator... → 清洗后作文件名 / mesh name 图 3.2-5 导出目录结构与节点名清洗规则。

跑完后 assets/meshes/step_parts/ 里大约有:

复制代码
step_parts/
├── step_xxx.stl          × 369   (世界坐标)
├── step_xxx_local.stl    × 349   (本地坐标,MJCF 引用)
└── ...

STEP 里由 Open CASCADE 生成的节点名往往形如 Open_CASCADE_STEP_translator_6_8_54_1_1_,脚本会做字符清洗(非法字符替换成 _)后作为文件名和 <mesh name>。所以你在 XML 里会看到一堆这种长名字,属正常现象。


6. 本节小结

STEP cascadio GLB 缓存 trimesh 两份 STL / 零件 世界(校验) + 本地(MJCF) 图 3.2-6 本节收束:cascadio 三角化 + trimesh 遍历,每个零件导出两份 STL。

  • 实际流水线用 cascadio(STEP→GLB)+ trimesh(GLB→逐件 STL),不是 FreeCAD 命令行。
  • GLB 会被缓存到 assets/meshes/ElectronBot_scene.glb,二次运行秒开。
  • 每个零件导出两份 STL:世界坐标(校验用)+ 本地坐标(_local,MJCF 引用)。
  • 坐标本地化的动机是「网格归零、位置交给 body」,具体在 3.4 节展开。

本节涉及的资源文件

  • scripts/step_to_mjcf.pyexport_parts / 场景图遍历部分)
  • assets/cad/ElectronBot.step(输入)
  • assets/meshes/ElectronBot_scene.glb(GLB 缓存)
  • assets/meshes/step_parts/*.stl(输出)

⬅️ 上一节:3.1 三类文件的定位 | ➡️ 下一节:3.3 Mesh 方案选择:外部引用 vs Inline

相关推荐
咩咦3 个月前
C++学习笔记12:类和对象入门
c++·学习笔记·类和对象·封装·struct·class
薛定谔的猫喵喵3 个月前
Spring Boot Jar包修改配置文件和Class中硬编码IP的完整指南
java·spring boot·反编译·class
gc_22993 个月前
学习C#调用OpenXml操作word文档的基本用法(28:学习文本类)
word·文本·text·openxml
core5126 个月前
Vanna实现Text2SQL
sql·openai·text·vanna
Beginner x_u6 个月前
ES6 中的 class 是什么?和ES5构造函数差别是什么?
javascript·es6·class
千里马-horse7 个月前
Rect Native bridging 源码分析--Class.h
javascript·react native·react.js·class
GDAL8 个月前
express.text和fetch配合使用深入全面教程
express·text
I'm Jie8 个月前
Java 字节码工具 ASM,实现类的动态增强
java·spring boot·spring·asm·cglib·class
熊猫钓鱼>_>9 个月前
Java面向对象核心面试技术考点深度解析
java·开发语言·面试·面向对象··class·oop