第05章-装配体与约束系统

第05章:装配体与约束系统

5.1 装配体概述

5.1.1 什么是装配体

装配体(Assembly)是CadQuery中用于组合多个零件的功能模块。在实际产品设计中,产品往往由多个零件组成,装配体功能允许你:

  • 将多个零件组合在一起
  • 定义零件之间的相对位置关系
  • 使用约束自动定位零件
  • 支持层次化组装
import cadquery as cq

# 创建两个简单零件
base = cq.Workplane("XY").box(50, 50, 10)
pillar = cq.Workplane("XY").cylinder(30, 10)

# 创建装配体
assembly = cq.Assembly()
assembly.add(base, name="base", color=cq.Color("blue"))
assembly.add(pillar, name="pillar", color=cq.Color("red"), 
             loc=cq.Location(cq.Vector(0, 0, 10)))

# 导出装配体
assembly.save("assembly.step")

5.1.2 装配体的组成

一个CadQuery装配体包含以下元素:

元素 说明
零件(Parts) 单独的3D模型
名称(Names) 零件的唯一标识
位置(Locations) 零件的空间位置和方向
颜色(Colors) 零件的显示颜色
约束(Constraints) 零件间的几何关系
子装配体 嵌套的装配体

5.1.3 装配体的应用场景

  • 机械设计:齿轮箱、发动机组件
  • 电子产品:外壳与内部组件
  • 家具设计:桌子、椅子的组装
  • 建筑模型:房屋结构件组合
  • 3D打印准备:多部件打印预览

5.2 创建装配体

5.2.1 基本创建方法

import cadquery as cq

# 方法1:使用空构造函数
assy = cq.Assembly()

# 方法2:使用根对象构造
root_part = cq.Workplane("XY").box(50, 50, 10)
assy = cq.Assembly(root_part, name="root")

5.2.2 添加零件

import cadquery as cq

# 创建零件
plate = cq.Workplane("XY").box(100, 60, 5)
cylinder = cq.Workplane("XY").cylinder(20, 15)
screw = cq.Workplane("XY").cylinder(3, 8).faces(">Z").workplane().circle(5).extrude(2)

# 创建装配体
assy = cq.Assembly()

# 添加零件(无位置偏移)
assy.add(plate, name="base_plate", color=cq.Color("gray"))

# 添加零件(指定位置)
assy.add(
    cylinder, 
    name="cylinder", 
    color=cq.Color("red"),
    loc=cq.Location(cq.Vector(0, 0, 5))  # Z方向偏移5mm
)

# 添加多个相同零件
for i, pos in enumerate([(-30, -20), (-30, 20), (30, -20), (30, 20)]):
    assy.add(
        screw, 
        name=f"screw_{i}",
        color=cq.Color("silver"),
        loc=cq.Location(cq.Vector(pos[0], pos[1], 5))
    )

assy.save("multi_parts.step")

5.2.3 层次化装配体

import cadquery as cq

# 创建子装配体1:电机组件
motor_body = cq.Workplane("XY").cylinder(30, 50)
motor_shaft = cq.Workplane("XY").cylinder(60, 5)

motor_assy = cq.Assembly()
motor_assy.add(motor_body, name="body", color=cq.Color("blue"))
motor_assy.add(motor_shaft, name="shaft", color=cq.Color("silver"),
               loc=cq.Location(cq.Vector(0, 0, 5)))

# 创建子装配体2:齿轮组件
gear1 = cq.Workplane("XY").circle(20).extrude(10).faces(">Z").workplane().hole(5)
gear2 = cq.Workplane("XY").circle(30).extrude(10).faces(">Z").workplane().hole(5)

gear_assy = cq.Assembly()
gear_assy.add(gear1, name="pinion", color=cq.Color("orange"))
gear_assy.add(gear2, name="gear", color=cq.Color("yellow"),
              loc=cq.Location(cq.Vector(50, 0, 0)))

# 主装配体
main_assy = cq.Assembly()
main_assy.add(motor_assy, name="motor")
main_assy.add(gear_assy, name="gears", 
              loc=cq.Location(cq.Vector(0, 0, 70)))

main_assy.save("hierarchical_assembly.step")

5.3 位置与方向

5.3.1 Location对象

Location对象定义了零件的位置和方向:

import cadquery as cq
from cadquery import Location, Vector

# 仅平移
loc1 = Location(Vector(10, 20, 30))

# 仅旋转(绕Z轴旋转45度)
loc2 = Location(Vector(0, 0, 0), Vector(0, 0, 1), 45)

# 平移+旋转
loc3 = Location(Vector(10, 20, 30), Vector(0, 0, 1), 45)

# 使用元组指定旋转角度(rx, ry, rz)
# 需要使用transformed方法

5.3.2 复合变换

import cadquery as cq
from cadquery import Location, Vector
import math

# 创建一个零件
part = cq.Workplane("XY").box(20, 10, 5)

# 创建装配体
assy = cq.Assembly()

# 添加原始位置
assy.add(part, name="original", color=cq.Color("red"))

# 添加平移后的
loc_translate = Location(Vector(30, 0, 0))
assy.add(part, name="translated", color=cq.Color("green"),
         loc=loc_translate)

# 添加旋转后的
loc_rotate = Location(Vector(60, 0, 0), Vector(0, 0, 1), 45)
assy.add(part, name="rotated", color=cq.Color("blue"),
         loc=loc_rotate)

# 添加平移+旋转
loc_complex = Location(Vector(90, 0, 0), Vector(0, 1, 0), 30)
assy.add(part, name="complex", color=cq.Color("yellow"),
         loc=loc_complex)

assy.save("transformations.step")

5.3.3 动态定位

import cadquery as cq
from cadquery import Location, Vector
import math

# 创建一个螺栓零件
bolt = cq.Workplane("XY").cylinder(10, 3).faces(">Z").workplane().polygon(6, 8).extrude(5)

# 创建底板
plate = cq.Workplane("XY").box(100, 100, 10)

# 创建装配体
assy = cq.Assembly()
assy.add(plate, name="plate", color=cq.Color("gray"))

# 动态添加圆周分布的螺栓
num_bolts = 8
radius = 35

for i in range(num_bolts):
    angle = 2 * math.pi * i / num_bolts
    x = radius * math.cos(angle)
    y = radius * math.sin(angle)
    
    assy.add(
        bolt,
        name=f"bolt_{i}",
        color=cq.Color("silver"),
        loc=Location(Vector(x, y, 10))
    )

assy.save("circular_pattern.step")

5.4 约束系统

5.4.1 约束概述

约束(Constraints)定义了零件之间的几何关系,CadQuery会自动求解这些约束来确定零件位置。

支持的约束类型:

约束类型 说明 参数
Fixed 固定零件位置
Plane 平面共面/平行 可选:间距
Axis 轴线对齐 可选:角度
Point 点重合
PointInPlane 点在平面上 可选:偏移

5.4.2 使用约束定位零件

import cadquery as cq

# 创建基座(带凸台)
base = (
    cq.Workplane("XY")
    .box(50, 50, 10)
    .faces(">Z")
    .workplane()
    .circle(10)
    .extrude(5)
)

# 创建配合件(带孔)
mating_part = (
    cq.Workplane("XY")
    .box(30, 30, 15)
    .faces("<Z")
    .workplane()
    .hole(10.1, 6)  # 稍大的配合孔
)

# 创建装配体
assy = cq.Assembly()

# 添加基座(固定)
assy.add(base, name="base", color=cq.Color("blue"))

# 添加配合件
assy.add(mating_part, name="mating", color=cq.Color("red"))

# 添加约束
# 基座是固定的
assy.constrain("base", "Fixed")

# 配合件的底面与基座的顶面平面约束
assy.constrain("base@faces@>Z", "mating@faces@<Z", "Plane")

# 配合件的孔轴线与基座的凸台轴线对齐
assy.constrain("base@faces@>Z", "mating@faces@<Z", "Axis")

# 求解约束
assy.solve()

assy.save("constrained_assembly.step")

5.4.3 约束路径语法

约束需要指定几何元素的路径,语法如下:

<零件名>@<元素类型>@<选择器>

示例:

  • "base@faces@>Z" - base零件的Z方向最高的面
  • "shaft@edges@%Circle" - shaft零件的圆形边
  • "plate@vertices@<X and <Y" - plate零件的X和Y最小的顶点
# 更多约束路径示例
assy.constrain(
    "part1@faces@>Z",      # part1的顶面
    "part2@faces@<Z",      # part2的底面
    "Plane"                 # 平面约束
)

assy.constrain(
    "shaft@edges@|Z",      # shaft的平行于Z轴的边
    "hole@faces@%Cylinder", # hole的圆柱面
    "Axis"                  # 轴线约束
)

5.4.4 带参数的约束

import cadquery as cq

# 两个盒子
box1 = cq.Workplane("XY").box(30, 30, 10)
box2 = cq.Workplane("XY").box(20, 20, 15)

assy = cq.Assembly()
assy.add(box1, name="box1", color=cq.Color("blue"))
assy.add(box2, name="box2", color=cq.Color("red"))

# 固定box1
assy.constrain("box1", "Fixed")

# 带间距的平面约束(box2放在box1上方5mm处)
assy.constrain("box1@faces@>Z", "box2@faces@<Z", "Plane", param=5)

assy.solve()
assy.save("offset_constraint.step")

5.4.5 复杂约束示例

import cadquery as cq

# 创建铰链两个部分
# 固定部分
fixed_part = (
    cq.Workplane("XY")
    .box(30, 50, 5)
    .faces(">Z")
    .workplane()
    .center(10, 0)
    .cylinder(15, 5, centered=(True, True, False))
)

# 活动部分
moving_part = (
    cq.Workplane("XY")
    .box(30, 50, 5)
    .faces(">Z")
    .workplane()
    .center(10, 0)
    .circle(5.2)
    .cutThruAll()
)

# 销钉
pin = cq.Workplane("XY").cylinder(25, 4.9)

# 装配
assy = cq.Assembly()
assy.add(fixed_part, name="fixed", color=cq.Color("blue"))
assy.add(moving_part, name="moving", color=cq.Color("red"))
assy.add(pin, name="pin", color=cq.Color("silver"))

# 约束
assy.constrain("fixed", "Fixed")

# 销钉与固定部分的孔对齐
assy.constrain("fixed@faces@>Z", "pin@faces@<Z", "Axis")

# 活动部分可以绕销钉旋转
assy.constrain("pin@faces@%Cylinder", "moving@faces@%Cylinder", "Axis")

assy.solve()
assy.save("hinge.step")

5.5 标签在装配中的应用

5.5.1 标记约束面

import cadquery as cq

# 创建带标签的零件
base = (
    cq.Workplane("XY")
    .box(50, 50, 10)
    .faces(">Z").tag("mount_face")
    .end()
    .faces(">Z")
    .workplane()
    .circle(10)
    .extrude(5)
    .faces(">Z").tag("boss_face")
)

cover = (
    cq.Workplane("XY")
    .box(50, 50, 5)
    .faces("<Z").tag("bottom")
    .end()
    .faces("<Z")
    .workplane()
    .hole(10.1)
)

# 装配时使用标签
assy = cq.Assembly()
assy.add(base, name="base", color=cq.Color("blue"))
assy.add(cover, name="cover", color=cq.Color("red"))

# 使用标签进行约束引用更清晰
# 注意:CadQuery的约束系统主要使用选择器语法
assy.constrain("base", "Fixed")
assy.constrain("base@faces@>Z", "cover@faces@<Z", "Plane")

assy.solve()

5.5.2 组织复杂装配

import cadquery as cq

def make_bracket():
    """创建带标签的支架"""
    return (
        cq.Workplane("XY")
        .box(40, 20, 5)
        .faces(">Z").tag("top")
        .faces("<Z").tag("bottom")
        .faces(">X").tag("front")
        .faces("<X").tag("back")
    )

def make_shaft():
    """创建带标签的轴"""
    return (
        cq.Workplane("XY")
        .cylinder(50, 8)
        .faces(">Z").tag("end1")
        .faces("<Z").tag("end2")
        .edges("%Circle and >Z").tag("chamfer_edge")
    )

# 使用工厂函数创建零件
bracket = make_bracket()
shaft = make_shaft()

# 组装
assy = cq.Assembly()
assy.add(bracket, name="bracket")
assy.add(shaft, name="shaft")

5.6 导出与可视化

5.6.1 导出装配体

import cadquery as cq

# 创建简单装配体
base = cq.Workplane("XY").box(50, 50, 10)
top = cq.Workplane("XY").box(30, 30, 20)

assy = cq.Assembly()
assy.add(base, name="base", color=cq.Color("blue"))
assy.add(top, name="top", color=cq.Color("red"),
         loc=cq.Location(cq.Vector(0, 0, 10)))

# 导出为STEP格式(保持装配结构)
assy.save("assembly.step")

# 导出为其他格式
assy.save("assembly.stl")  # STL(会合并所有零件)
assy.save("assembly.gltf") # glTF(支持Web显示)

5.6.2 导出选项

# 导出时的选项
assy.save(
    "assembly.step",
    exportType="STEP"
)

# 分别导出每个零件
for name, part in assy.traverse():
    if part.obj is not None:
        cq.exporters.export(part.obj, f"{name}.step")

5.6.3 在CQ-editor中可视化

# CQ-editor中显示装配体
import cadquery as cq

base = cq.Workplane("XY").box(50, 50, 10)
top = cq.Workplane("XY").sphere(15)

assy = cq.Assembly()
assy.add(base, name="base", color=cq.Color("blue"))
assy.add(top, name="top", color=cq.Color("red"),
         loc=cq.Location(cq.Vector(0, 0, 25)))

# 在CQ-editor中使用show_object显示
show_object(assy)

5.7 实战案例

5.7.1 简单机械装配

import cadquery as cq
from cadquery import Location, Vector
import math

# 创建底板
base_plate = (
    cq.Workplane("XY")
    .box(100, 80, 10)
    .faces(">Z")
    .workplane()
    .rarray(80, 60, 2, 2)
    .hole(6)
)

# 创建立柱
pillar = cq.Workplane("XY").cylinder(40, 10)

# 创建顶板
top_plate = (
    cq.Workplane("XY")
    .box(80, 60, 8)
    .faces(">Z or <Z")
    .shell(-3)
)

# 创建螺栓
bolt = (
    cq.Workplane("XY")
    .cylinder(15, 3)
    .faces(">Z")
    .workplane()
    .polygon(6, 8)
    .extrude(5)
)

# 组装
assy = cq.Assembly(name="machine_assembly")

# 添加底板
assy.add(base_plate, name="base", color=cq.Color("silver"))

# 添加四个立柱
positions = [(-30, -20), (-30, 20), (30, -20), (30, 20)]
for i, (x, y) in enumerate(positions):
    assy.add(
        pillar,
        name=f"pillar_{i}",
        color=cq.Color("blue"),
        loc=Location(Vector(x, y, 10))
    )

# 添加顶板
assy.add(
    top_plate,
    name="top",
    color=cq.Color("green"),
    loc=Location(Vector(0, 0, 50))
)

# 添加螺栓
bolt_positions = [(-40, -30), (-40, 30), (40, -30), (40, 30)]
for i, (x, y) in enumerate(bolt_positions):
    assy.add(
        bolt,
        name=f"bolt_{i}",
        color=cq.Color("darkgray"),
        loc=Location(Vector(x, y, -5))
    )

assy.save("machine_assembly.step")

5.7.2 齿轮传动装配

import cadquery as cq
from cadquery import Location, Vector
import math

def make_gear(teeth, module=2, thickness=10, bore=8):
    """创建简化齿轮"""
    pitch_radius = module * teeth / 2
    outer_radius = pitch_radius + module
    
    return (
        cq.Workplane("XY")
        .circle(outer_radius)
        .extrude(thickness)
        .faces(">Z")
        .workplane()
        .hole(bore)
        .edges("|Z")
        .fillet(1)
    )

# 创建不同大小的齿轮
gear1 = make_gear(20)
gear2 = make_gear(40)
gear3 = make_gear(15)

# 创建轴
shaft = cq.Workplane("XY").cylinder(80, 4)

# 创建轴承座
bearing_block = (
    cq.Workplane("XY")
    .box(30, 30, 20)
    .faces(">Z or <Z")
    .hole(8.2)
)

# 组装齿轮系统
assy = cq.Assembly(name="gear_train")

# 输入轴和齿轮
assy.add(shaft, name="input_shaft", color=cq.Color("silver"))
assy.add(gear1, name="input_gear", color=cq.Color("orange"),
         loc=Location(Vector(0, 0, 20)))

# 中间轴和齿轮
m = 2  # 模数
center_distance = m * (20 + 40) / 2  # 齿轮1和齿轮2的中心距
assy.add(shaft, name="inter_shaft", color=cq.Color("silver"),
         loc=Location(Vector(center_distance, 0, 0)))
assy.add(gear2, name="inter_gear", color=cq.Color("yellow"),
         loc=Location(Vector(center_distance, 0, 20)))

# 轴承座
assy.add(bearing_block, name="bearing1", color=cq.Color("gray"),
         loc=Location(Vector(0, 0, 0)))
assy.add(bearing_block, name="bearing2", color=cq.Color("gray"),
         loc=Location(Vector(0, 0, 60)))
assy.add(bearing_block, name="bearing3", color=cq.Color("gray"),
         loc=Location(Vector(center_distance, 0, 0)))
assy.add(bearing_block, name="bearing4", color=cq.Color("gray"),
         loc=Location(Vector(center_distance, 0, 60)))

assy.save("gear_train.step")

5.8 最佳实践

5.8.1 装配体设计原则

  1. 模块化设计

    # 将重复使用的零件定义为函数
    def make_mounting_plate(length, width, thickness, hole_pattern):
        # ...
        pass
    
  2. 合理的命名约定

    # 使用描述性名称
    assy.add(part, name="left_side_bracket_01")
    
    # 而不是
    assy.add(part, name="part1")
    
  3. 层次化组织

    # 将相关零件组织到子装配体
    wheel_assy = cq.Assembly(name="front_left_wheel")
    wheel_assy.add(tire, name="tire")
    wheel_assy.add(rim, name="rim")
    wheel_assy.add(hub, name="hub")
    
    car_assy.add(wheel_assy, name="FL_wheel")
    

5.8.2 性能优化

  1. 复用零件对象

    # 创建一次,多次使用
    bolt = make_bolt()
    
    for i in range(100):
        assy.add(bolt, name=f"bolt_{i}", loc=...)
    
  2. 简化约束

    # 尽可能使用简单约束
    # 避免过度约束
    

5.8.3 调试技巧

# 分步构建装配体
assy = cq.Assembly()
assy.add(base, name="base")
assy.save("debug_step1.step")  # 检查中间结果

assy.add(part2, name="part2")
assy.save("debug_step2.step")  # 继续检查

5.9 本章小结

本章详细介绍了CadQuery的装配体与约束系统:

  1. 装配体基础

    • Assembly对象创建
    • 添加零件和位置
    • 层次化组织
  2. 位置与方向

    • Location对象使用
    • 复合变换
    • 动态定位
  3. 约束系统

    • 约束类型:Fixed、Plane、Axis、Point
    • 约束路径语法
    • 约束求解
  4. 导出与可视化

    • 多种格式导出
    • CQ-editor显示
  5. 实战案例

    • 机械装配
    • 齿轮传动系统

通过本章学习,您应该能够:

  • 创建和管理复杂装配体
  • 使用约束自动定位零件
  • 导出装配体供其他软件使用
  • 应用最佳实践组织装配结构

下一章我们将学习数据导入导出功能,包括STEP、STL等格式的处理。


posted @ 2026-01-10 13:15  我才是银古  阅读(37)  评论(0)    收藏  举报