Здравствуйте!
В прошлом уроке мы успешно разделили наш монолитный корпус на две части: основание (base) и крышку (lid). Однако, если их сейчас напечатать, крышка будет просто лежать на основании, ничем не удерживаемая от бокового смещения. Это не очень надежно.
Цель этого урока — спроектировать выступ-фальц (lip/groove). Это простой и эффективный механизм, который обеспечит точное позиционирование крышки относительно основания и предотвратит её соскальзывание.
1. Что такое выступ-фальц (Lip/Groove)?
Идея очень проста: на одной из частей корпуса мы создаем тонкий выступ (lip), а на другой — соответствующий ему по форме паз (groove). При сборке выступ входит в паз, образуя соединение "в замок".

Такое соединение не только выравнивает части корпуса, но и помогает защитить внутреннее пространство от пыли и брызг.
2. Стратегия проектирования
Мы будем использовать уже знакомые нам инструменты: создание 2D-эскизов (Sketch) и их последующее выдавливание (extrude) с применением булевых операций.
Наш план:
- Создать на верхней кромке основания (
base) тонкостенный прямоугольный выступ (lip). - Создать в нижней кромке крышки (
lid) ответный паз (groove), который будет немного шире выступа для обеспечения легкой сборки.
Ключевым моментом здесь является зазор (tolerance). В реальном мире, особенно в FDM 3D-печати, детали никогда не получаются с идеальными размерами. Чтобы выступ физически смог войти в паз, паз должен быть немного больше.
3. Реализация в коде
Давайте создадим копию файла enclosure_v3.py и назовем ее enclosure_v4.py. Мы будем работать с ней.
Шаг 1: Добавляем новые параметры
В начало файла, в секцию ПАРАМЕТРЫ, добавим параметры, которые будут управлять геометрией нашего соединения:
# ... предыдущие параметры ...
# ================== ПАРАМЕТРЫ ФАЛЬЦА (LIP/GROOVE) ==================
# Высота выступа/глубина паза
lip_height = 2.0
# Толщина стенки выступа
lip_thickness = 1.0
# Зазор для 3D-печати. Паз будет шире выступа на эту величину.
# Типичное значение для FDM-принтера — 0.2-0.4 мм.
tolerance = 0.3
Шаг 2: Создание выступа (Lip) на основании
Выступ мы создадим как отдельный объект, а затем "приклеим" его к основанию (base) с помощью булевой операции сложения.
Эскиз для выступа мы будем рисовать на той же плоскости, которой мы разрезали корпус.
Добавьте новый блок кода после разделения корпуса на base и lid.
# ... код до извлечения base и lid ...
base = sorted_solids[0]
lid = sorted_solids[1]
# ================== ПРОЕКТИРОВАНИЕ ФАЛЬЦА (LIP/GROOVE) ==================
# 7. Создаем выступ (Lip)
# Определяем внутренние размеры корпуса, где будет располагаться выступ
inner_length = enclosure_length - 2 * wall_thickness
inner_width = enclosure_width - 2 * wall_thickness
# Создаем эскиз на плоскости разреза
with BuildSketch(cutting_plane) as lip_sketch:
# Внешний контур выступа
Rectangle(inner_length, inner_width)
# Вырезаем внутреннюю часть, чтобы получить тонкую стенку
Rectangle(
inner_length - 2 * lip_thickness,
inner_width - 2 * lip_thickness,
mode=Mode.SUBTRACT
)
# Выдавливаем эскиз вверх, чтобы получить 3D-объект выступа
lip = extrude(lip_sketch.sketch, amount=lip_height)
# Добавляем выступ к основанию
base_with_lip = base + lip
Мы создали BuildSketch на cutting_plane. Внутри него мы нарисовали один прямоугольник по внутренним размерам корпуса, а затем вычли из него второй, чуть меньший. В результате получился эскиз тонкой прямоугольной рамки. Эту рамку мы выдавили вверх на lip_height и добавили к base.
Шаг 3: Создание паза (Groove) в крышке
Создание паза происходит почти так же, но с двумя ключевыми отличиями:
- Эскиз паза должен быть шире эскиза выступа на величину
tolerance. - Полученный 3D-объект мы будем не добавлять, а вычитать из крышки (
lid).
Продолжим наш код:
# 8. Создаем паз (Groove)
# Толщина стенки "инструмента" для вырезания паза
groove_cutter_thickness = lip_thickness + tolerance
with BuildSketch(cutting_plane) as groove_sketch:
# Внешний контур паза (такой же, как у выступа)
Rectangle(inner_length, inner_width)
# Внутренний контур, учитывающий зазор
Rectangle(
inner_length - 2 * groove_cutter_thickness,
inner_width - 2 * groove_cutter_thickness,
mode=Mode.SUBTRACT
)
# Создаем "режущий инструмент", выдавливая эскиз паза
groove_cutter = extrude(groove_sketch.sketch, amount=lip_height)
# Вычитаем "режущий инструмент" из крышки.
# Обратите внимание, что паз "врезается" в крышку с ее нижней стороны.
# Крышка находится выше плоскости XY, поэтому для вырезания паз нужно сместить
# на ту же высоту, на которой находится ее нижняя грань.
# В нашем случае объекты уже находятся в правильных позициях после split,
# поэтому дополнительное смещение не нужно.
lid_with_groove = lid - groove_cutter
Вместо того, чтобы выдавливать эскиз прямо из крышки (extrude(target=lid, ...)), мы создали отдельный "режущий инструмент" groove_cutter и вычли его. Это делает код более наглядным и показывает симметрию в создании выступа и паза.
Шаг 4: Итоговый код и визуализация
Теперь обновим секцию визуализации, чтобы отобразить наши новые детали: base_with_lip и lid_with_groove. Сместим крышку повыше, чтобы хорошо рассмотреть получившееся соединение.
Полный код файла enclosure_v4.py:
# enclosure_v4.py
from build123d import *
# ================== ПАРАМЕТРЫ ==================
# Внешние габариты
enclosure_length = 100.0
enclosure_width = 70.0
enclosure_height = 35.0
# Толщина стенок
wall_thickness = 2.0
# Высота основания
base_height = 15.0
# ================== ПАРАМЕТРЫ ФАЛЬЦА (LIP/GROOVE) ==================
# Высота выступа/глубина паза
lip_height = 2.0
# Толщина стенки выступа
lip_thickness = 1.0
# Зазор для 3D-печати
tolerance = 0.3
# ================== ПРОЕКТИРОВАНИЕ ==================
# 1-3. Создание полой коробки
solid_block = Box(enclosure_length, enclosure_width, enclosure_height, align=(Align.CENTER,) * 3)
top_face = solid_block.faces().filter_by(Axis.Z).last
hollow_box = solid_block.thicken(amount=-wall_thickness, faces=top_face)
# 4-6. Разделение на основание и крышку
split_z = -enclosure_height / 2 + base_height
cutting_plane = Plane.XY.offset(split_z)
split_parts = split(hollow_box, bisect_by=cutting_plane, keep=Keep.BOTH)
all_solids = split_parts.solids()
sorted_solids = sorted(all_solids, key=lambda s: s.center().Z)
base = sorted_solids[0]
lid = sorted_solids[1]
# ================== ПРОЕКТИРОВАНИЕ ФАЛЬЦА (LIP/GROOVE) ==================
# 7. Создаем выступ (Lip)
inner_length = enclosure_length - 2 * wall_thickness
inner_width = enclosure_width - 2 * wall_thickness
with BuildSketch(cutting_plane) as lip_sketch:
Rectangle(inner_length, inner_width)
Rectangle(
inner_length - 2 * lip_thickness,
inner_width - 2 * lip_thickness,
mode=Mode.SUBTRACT
)
lip = extrude(lip_sketch.sketch, amount=lip_height)
base_with_lip = base + lip
# 8. Создаем паз (Groove)
groove_cutter_thickness = lip_thickness + tolerance
with BuildSketch(cutting_plane) as groove_sketch:
Rectangle(inner_length, inner_width)
Rectangle(
inner_length - 2 * groove_cutter_thickness,
inner_width - 2 * groove_cutter_thickness,
mode=Mode.SUBTRACT
)
groove_cutter = extrude(groove_sketch.sketch, amount=lip_height)
lid_with_groove = lid - groove_cutter
# ================== ВИЗУАЛИЗАЦИЯ ==================
if "show_object" in locals():
show_object(base_with_lip, name="Base with Lip")
# Смещаем крышку вверх, чтобы рассмотреть соединение
show_object(lid_with_groove.moved(Location(Vector(0, 0, 15))), name="Lid with Groove")
Запустите этот код. В окне OCP CAD Viewer вы увидите основание с аккуратным выступом и крышку с соответствующим пазом. Поздравляю, вы создали ключевой элемент, обеспечивающий качественную сборку корпуса!
Проверьте себя!
Представьте, что по дизайну вам нужно, чтобы выступ (lip) был на крышке, а паз (groove) — в основании. Это может быть полезно, например, для защиты от попадания воды (крышка с выступом будет накрывать основание сверху, как шляпка гриба).
Задание: Какие строки кода в блоке ПРОЕКТИРОВАНИЕ ФАЛЬЦА нужно изменить, чтобы поменять выступ и паз местами?
Показать решение
Нужно поменять местами булевы операции и направления выдавливания.
-
Объект
lipтеперь нужно добавить к крышке (lid). Так как паз должен "смотреть" вниз, его нужно выдавливать на отрицательную высоту:# Выдавливаем эскиз вниз lip = extrude(lip_sketch.sketch, amount=-lip_height) # Добавляем выступ к крышке lid_with_lip = lid + lip -
Объект
groove_cutterтеперь нужно вычесть из основания (base).# Вычитаем "режущий инструмент" из основания base_with_groove = base - groove_cutter
Итого, нужно поменять всего две строки с булевыми операциями и знак у amount в extrude для lip:
# Было:
# base_with_lip = base + lip
# lid_with_groove = lid - groove_cutter
# Стало:
lip_on_lid = extrude(lip_sketch.sketch, amount=-lip_height) # Выдавливаем вниз
lid_with_lip = lid + lip_on_lid
base_with_groove = base - groove_cutter
Это еще раз демонстрирует гибкость параметрического подхода: для изменения логики сборки достаточно поменять несколько строк, а не перерисовывать все с нуля.
Ключевые выводы
- Мы спроектировали соединение типа "выступ-фальц" (lip/groove) для точного позиционирования и фиксации частей корпуса.
- Мы научились создавать сложные эскизы (рамки) путем вычитания одной 2D-фигуры из другой.
- Мы применили булевы операции (
+и-) для добавления и вычитания геометрии из наших основных деталей. - Мы ввели в нашу модель параметр
tolerance(зазор), который критически важен при проектировании деталей для 3D-печати.
Что дальше?
Наш корпус обретает форму! У нас есть две идеально подогнанные друг к другу части. Но пока что внутри он пустой. В следующем уроке мы сделаем первый шаг к размещению электроники внутри: мы создадим параметрическую модель печатной платы (PCB) на основе ее реальных размеров. Это позволит нам в дальнейшем точно спроектировать для нее крепежные элементы.