Back to Home

Domain Specific Language for Sheet Metal

Computational Design, DSLs, Fabrication

DSL Folded Structure Hero
  • What I built: An embedded Python DSL for designing folded sheet metal structures (e.g., enclosures).
  • Why it matters: Automates the tedious translation from 3D design intent to 2D fabrication patterns.
  • Proof: Automatically generates laser-ready SVGs from high-level Python code.

Problem / Goal

Designing complex folded sheet metal structures (like electronics enclosures or origami-inspired robots) manually in CAD is often tedious and prone to error, especially when calculating unfold patterns.

The goal was to create a Domain Specific Language (DSL) embedded in Python to automate this process, allowing users to define structures logically (as a hierarchy of tabs) rather than geometrically drafting every edge.

My Contribution

I built the core logic and interpreter for the DSL:

  • Embedded DSL: Implemented as a Python library where tabs are objects and relationships are defined via function calls.
  • Tree-Based Traversal: Designed the interpreter to traverse the component tree recursively to compute global coordinates from local relative transformations.
  • Fabrication Export: Automatically built the unfolded 2D geometry and exported it as an SVG for laser cutting, ensuring physical connectivity.

Technical Approach

1. The Tab Logic (Embedded DSL)

The `Tab` class is the fundamental primitive. The `generate_child_tab` function handles the complexity of attaching a new geometric piece to a parent edge, managing spatial offsets and bend angles.

@dataclass
class Tab:
    """ A structure that represents a tab and a bend with respect to the parent tab. """
    parent: Optional["Tab"]
    children: list["Tab"]
    position: np.ndarray        # Root position
    bend_angle: Optional[float] # Angle for 3D folding

def generate_child_tab(parent, side, offset, width, length, angle=0.0, bend_angle=np.pi/2):
    """
    Generate a child tab attached to a parent tab.
    side: 0=top, 1=right, 2=bottom, 3=left
    """
    tab = Tab(
        parent=parent,
        children=[],
        width=0.0,      # Computed from geometry
        side=side,
        offset=offset,
        child_width=width,
        child_length=length,
        bend_angle=bend_angle
    )
    parent.children.append(tab)
    return tab

2. Usage Example: Defining a Structure

Users can define complex, nested geometries with just a few lines of code. This script defines a root base and attaches walls to create a box-like structure. The semantic clarity improves maintainability over raw coordinate lists.

# Define the base of the structure
root = generate_root_tab(width=50, length=50)

# Attach four walls to the base
north_wall = generate_child_tab(root, side=0, offset=0, width=50, length=30, bend_angle=np.radians(90))
east_wall  = generate_child_tab(root, side=1, offset=0, width=50, length=30, bend_angle=np.radians(90))
south_wall = generate_child_tab(root, side=2, offset=0, width=50, length=30, bend_angle=np.radians(90))
west_wall  = generate_child_tab(root, side=3, offset=0, width=50, length=30, bend_angle=np.radians(90))

# Export the flat pattern for laser cutting
draw_svg(root, "output_pattern.svg")

Validation / Results

The system was validated by generating laser-cut patterns for physical prototypes. The folded structures perfectly matched the digital 3D visualization, confirming the accuracy of the unfolding algorithm.

Lessons + Next Steps

Key Insight: Recursion is a natural fit for physical assemblies that branch out from a core component. However, managing relative coordinate frames (local-to-global) requires careful matrix transformations.

Next Steps: Adding collision detection to prevent the user from designing physically impossible folds (self-intersection).

Links

Code/Repository available upon request.