Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion .claude/skills/cad/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,27 @@ and `docs/hardware/cad-workflow.md`. Update this skill once D8 is resolved.
- switch centre-to-centre spacings (measured in CAD once the panel body exists).
- the control inventory (what cutouts/mounts the panel needs).

## Panel blank + plate stack (CockpitPanels workbench)

Panel bases come from the **Cockpit Panels** FreeCAD 1.1+ workbench, a separate repo:
`OpenSkyHawk/CockpitPanels` (LGPL-2.1+; install via Addon Manager → custom repository,
branch `main`). Its README is the reference. Three tools, in order:

- **Panel Blank**: Dzus-grid outline + mount points + clearance holes, centred on the origin
on XY, driven by the `PanelBlank` sheet. No ControlPoints sketch: the user makes their own.
- **Plate Stack**: one Body per layer (default `FacePlate` 1/16″, `Diffuser` 1/8″,
`BackPlate` 1/8″), front face at z = 0, each with `<Layer>_Outline/_Pad/_Cut/_Pocket` and a
per-layer fastener cut (Clearance / Recess / Slot / Slot (open ends)); faceplate insets.
- **Export Layers**: one DXF per plate Body, on a layer named after the Body.

Published overview: `docs/hardware/cad-workflow.md` → *Panel base blank*.

## Cutout library

Reusable panel cutouts live in `CAD/Shared/Cutouts/` and are linked into panels with
Sub-Shape Binders, then pocketed. Docs: `docs/_source/cad-cutout-library/`. Start at
Sub-Shape Binders, then pocketed inside the Plate Stack layer Bodies, after each layer's
`<Layer>_Pocket`. Library parts carry one sketch per layer, named exactly like the layers
(`FacePlate`, `Diffuser`, `BackPlate`). Docs: `docs/_source/cad-cutout-library/`. Start at
`index.md` (method choice), then `library-part.md` plus one method page:

- `lcs-placement.md`: ControlPoints → one LCS per control → binder per plate layer →
Expand Down
33 changes: 25 additions & 8 deletions docs/_source/cad-cutout-library/array-placement.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,38 @@ the [overview](index.md).
Build the [library part](library-part.md) first.

The screenshots come from a small demo: an `LED5` library part (FacePlate Ø5.2, BackPlate
Ø6.0) and a 100 × 30 mm panel with a row of five LEDs.
Ø6.0) and a 100 × 30 mm panel with a row of five LEDs. The demo predates Plate Stack and has
only those two layers. On a Plate Stack panel, give the library a `Diffuser` sketch too and
repeat B2–B4 for the Diffuser Body.

## How the pieces fit

```
CAD/Shared/Cutouts/LED5.FCStd ← library part
└── Body
├── FacePlate (sketch: Ø5.2 hole)
├── Diffuser (sketch: the Diffuser hole)
└── BackPlate (sketch: Ø6.0 hole)

<panel>.FCStd
├── LED_Points (sketch: one point per LED, nothing else)
├── Panel Blank (group, from Panel Blank)
├── Plate Stack (group, from Plate Stack)
├── LED_Points (your sketch on XY: one point per LED, nothing else)
├── LEDs_FacePlate (Draft PointArray over LED_Points)
│ └── LED5_FacePlate (root binder → LED5 FacePlate sketch)
├── LEDs_Diffuser (Draft PointArray over LED_Points)
│ └── LED5_Diffuser (root binder → LED5 Diffuser sketch)
├── LEDs_BackPlate (Draft PointArray over LED_Points)
│ └── LED5_BackPlate (root binder → LED5 BackPlate sketch)
├── FacePlate (Body)
│ └── … LEDsCutFacePlate (Pocket) ← LEDsBinderFacePlate (binder → LEDs_FacePlate)
│ └── FacePlate_Outline … FacePlate_Pocket (from Plate Stack)
│ → LEDsCutFacePlate (Pocket) ← LEDsBinderFacePlate (binder → LEDs_FacePlate)
├── Diffuser (Body)
│ └── Diffuser_Outline … Diffuser_Pocket
│ → LEDsCutDiffuser (Pocket) ← LEDsBinderDiffuser (binder → LEDs_Diffuser)
└── BackPlate (Body)
└── … LEDsCutBackPlate (Pocket) ← LEDsBinderBackPlate (binder → LEDs_BackPlate)
└── BackPlate_Outline … BackPlate_Pocket
→ LEDsCutBackPlate (Pocket) ← LEDsBinderBackPlate (binder → LEDs_BackPlate)
```

Each layer uses two binders:
Expand All @@ -42,7 +54,9 @@ Each layer uses two binders:

### B1. Points sketch

1. In the panel, create a sketch (here `LED_Points`) with one **Point** per LED.
1. In the panel, create a sketch on the **XY plane** (here `LED_Points`) with one
**Point** per LED, dimensioned from the origin (the panel centre). Panel Blank doesn't
make one for you; keep it outside the `Panel Blank` group.
2. Put **only** this array's points in it. The array places a copy on every vertex in the
sketch, so a shared ControlPoints sketch would also put LEDs on your toggles.

Expand Down Expand Up @@ -71,16 +85,19 @@ Each layer uses two binders:

### B4. Bind and cut

1. Back in Part Design, double-click the plate Body so it's active, then select nothing.
1. Back in Part Design, double-click the layer Body so it's active, then select nothing.
Its Tip should be `<Layer>_Pocket` (or a later feature of yours), so the binder and
pocket land after the stack's own features.
2. Create a sub-shape binder, then drag the **array** (`LEDs_FacePlate`) onto it.
3. With the binder selected, run **Pocket**: Mode **Symmetric**, Type **Through all**.

![Body binder LEDsBinderFacePlate: Support is the point array, claimed by the pocket](array-05-body-binder.png)

![Pocket on the array binder: Symmetric + Through all, all five holes previewed](array-06-pocket.png)

Repeat B2–B4 for the BackPlate layer, with a second root binder on the library's
`BackPlate` sketch and a second array over the same `LED_Points`.
Repeat B2–B4 for the Diffuser and BackPlate layers, each with its own root binder on the
library's `Diffuser` or `BackPlate` sketch and its own array over the same `LED_Points`.
**Export Layers** then writes one DXF per layer Body, holes included.

![Result: five Ø5.2 holes in the FacePlate and five Ø6.0 holes in the BackPlate](array-07-result.png)

Expand Down
38 changes: 28 additions & 10 deletions docs/_source/cad-cutout-library/index.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# CAD Cutout Library (FreeCAD)

> **Status:** verified in FreeCAD 1.1.1. CAD tooling (D8) is still open, so these are
> internal reference pages. Once D8 lands they get promoted into
> `docs/hardware/cad-workflow.md`.
> **Status:** verified in FreeCAD 1.1.1, on a panel built with the
> [Cockpit Panels](https://github.com/OpenSkyHawk/CockpitPanels) workbench (Panel Blank →
> Plate Stack). CAD tooling (D8) is still open, so these are internal reference pages. Once
> D8 lands they get promoted into `docs/hardware/cad-workflow.md`.

Draw each control's cutout **once**, in a small library file, and link it into every panel
that uses it. Edit the library and every panel picks up the change.

Start the panel with the workbench: **Panel Blank** draws the outline and fastener grid,
centred on the origin, and **Plate Stack** builds one Part Design Body per layer
(`FacePlate`, `Diffuser`, `BackPlate` by default). The cutouts in these guides go into those
Bodies. See [CAD workflow → Panel base blank](../../hardware/cad-workflow.md#panel-base-blank)
for installing and using the workbench.

A panel places library cutouts in one of two ways. Both link the same library files, and
one panel can use both.

Expand All @@ -21,7 +28,7 @@ one panel can use both.
| | Method A: LCS per control | Method B: Point array |
|---|---|---|
| Rotation | Each control has its own | All copies share one orientation |
| Objects for N controls, 2 layers | N LCS + 2N binders + 2N pockets | 2 arrays + 4 binders + 2 pockets, whatever N is |
| Objects for N controls, 3 layers | N LCS + 3N binders + 3N pockets | 3 arrays + 6 binders + 3 pockets, whatever N is |
| Add a control | Add a point, an LCS, then a binder and pocket per layer | Add a point |
| Remove a control | Delete its objects, but **keep** its point (LCSs bind by index) | Delete the point |
| KiCad reference in the tree | Yes (the LCS label) | No, the points are anonymous |
Expand All @@ -34,15 +41,26 @@ unrotated controls: LED rows, annunciator lamps, push-button banks.

## Shared building blocks

- **Plate layers.** A panel is a stack of plate Bodies (FacePlate, BackPlate, …). The
library holds one sketch per layer, because each plate needs a different hole.
- **Plate layers.** A panel is a stack of plate Bodies, one per Plate Stack layer:
`FacePlate`, `Diffuser` and `BackPlate` by default. The library holds one sketch per
layer, named exactly after the layer, because each plate needs a different hole.
- **Your own points sketch.** Panel Blank draws the outline and the fastener grid but no
control positions. Make your own points sketch on the XY plane, outside the `Panel Blank`
group, and dimension the points from the origin, which is the panel centre.
- **Sub-Shape Binder.** A live, cross-file copy of a library sketch. Both methods pocket a
binder directly (Through all, Symmetric), so you don't need an External-Geometry cut
sketch.
- **Cutouts stay at the control points.** A binder inside a Body compensates for that
Body's Placement. You can stack plates by moving a Body in Z, and the Through-all pocket
still cuts. Don't move a plate Body in X or Y: the plate slides while its holes stay
where they were.
- **Cutouts go after the stack's own features.** Each layer Body already holds
`<Layer>_Outline`, `<Layer>_Pad`, `<Layer>_Cut` and `<Layer>_Pocket` (the fastener cut).
Add your binders and pockets after `<Layer>_Pocket`, and leave those four alone: running
Plate Stack or Panel Blank again updates them in place.
- **Cutouts stay at the control points.** Plate Stack leaves every Body at the origin and
sets each layer's depth on its outline binder instead, so a Through-all pocket cuts
whatever the layer's depth. Don't move a plate Body's Placement: the plate slides while
its holes stay where they were.
- **Cut files.** Export Layers flattens each plate to one DXF, drawn on a single layer named
after the Body (`FacePlate.dxf` on layer `FacePlate`, …). Only features that go all the
way through the plate appear, which the Through-all pockets here always do.

## Related

Expand Down
51 changes: 34 additions & 17 deletions docs/_source/cad-cutout-library/lcs-placement.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,40 +8,52 @@ KiCad reference visible in the tree. For rows of identical, unrotated controls,
Build the [library part](library-part.md) first.

The screenshots come from a small demo: a Toggle12-style library part and a 100 × 50 mm
BackPlate with two controls, SW1 and SW2. SW2 is rotated 90°.
BackPlate with two controls, SW1 and SW2. SW2 is rotated 90°. The demo predates Plate Stack
and has fewer layers, but every step is the same in each layer Body that Plate Stack
builds.

## How the pieces fit

```
CAD/Shared/Cutouts/Toggle12.FCStd ← library part
└── Body
├── FacePlate (sketch: Ø12.6 hole)
├── Diffuser (sketch: Ø12.6 hole)
└── BackPlate (sketch: Ø12.6 hole + anti-rotation tab)

<panel>.FCStd
├── Panel Blank (group)
│ └── ControlPoints (sketch: one point per control)
├── Panel Blank (group, from Panel Blank)
├── Plate Stack (group, from Plate Stack)
├── ControlPoints (your sketch on XY: one point per control)
├── Controls (group)
│ ├── SW1 (LCS on ControlPoints:Vertex1)
│ └── SW2 (LCS on ControlPoints:Vertex2, rotated 90°)
├── FrontPlate (Body)
│ └── … SW1_Face (binder → FacePlate) → Pocket, SW2_Face → Pocket
├── FacePlate (Body)
│ └── FacePlate_Outline, _Pad, _Cut, _Pocket (from Plate Stack)
│ → SW1_Face (binder → FacePlate) → Pocket, SW2_Face → Pocket
├── Diffuser (Body)
│ └── Diffuser_Outline … _Pocket
│ → SW1_Diff (binder → Diffuser) → Pocket, SW2_Diff → Pocket
└── BackPlate (Body)
└── … SW1_Back (binder → BackPlate) → Pocket, SW2_Back → Pocket
└── BackPlate_Outline … _Pocket
→ SW1_Back (binder → BackPlate) → Pocket, SW2_Back → Pocket
```

- **ControlPoints**: the *where*. One plain sketch point per control. Move a point and the
control moves on every plate.
- **ControlPoints**: the *where*. One plain sketch point per control, which you create
yourself: Panel Blank doesn't make one. Move a point and the control moves on every
plate.
- **One LCS per control**: the *which way*. The LCS is pinned to its point and carries the
control's rotation. Its label is the KiCad reference (`SW1`).
- **One binder per control per plate layer**: a live, cross-file copy of the library
sketch for that layer, placed by the control's LCS.
- **Pocket the binder directly** (Through all, Symmetric).
- **Pocket the binder directly** (Through all, Symmetric), after the layer's own
`<Layer>_Pocket`.

## Panel conventions

| Rule | Why |
|---|---|
| ControlPoints is your own sketch on the XY plane, outside the `Panel Blank` group | Panel Blank draws no control points, and running it again only updates its own objects |
| ControlPoints uses ordinary (non-construction) points | The LCS attaches to `Sketch:VertexN` |
| Never delete and re-add points in ControlPoints. Move them instead | The LCS binds by vertex **index**, so deleting a point renumbers the rest |
| LCS label = KiCad reference (`SW1`, `S3`, …) | Ties CAD to schematic and firmware |
Expand All @@ -52,8 +64,10 @@ CAD/Shared/Cutouts/Toggle12.FCStd ← library part

### A1. Control positions

1. In the panel, open the `ControlPoints` sketch (Sketcher workbench).
2. Add one **Point** per control and dimension it from the origin.
1. In the panel, create a sketch on the **XY plane** (Sketcher workbench) and rename it
`ControlPoints`. Leave it outside the `Panel Blank` group.
2. Add one **Point** per control and dimension it from the origin, which is the panel
centre. Use numbers or `PanelBlank` cell references rather than External Geometry.
3. Close the sketch.

![ControlPoints sketch: one point per control, dimensioned from the origin](02-control-points.png)
Expand All @@ -74,12 +88,13 @@ CAD/Shared/Cutouts/Toggle12.FCStd ← library part

### A3. Bind and cut (per control, per plate)

1. Make the **panel** the active document. Double-click the plate Body (e.g. FrontPlate)
so it's active, and select **nothing**.
1. Make the **panel** the active document. Double-click the layer Body (e.g. FacePlate)
so it's active, and select **nothing**. Its Tip should be `FacePlate_Pocket` (or a
later feature of yours), so the new features land after the stack's own.
2. Part Design → **Create a sub-object(s) shape binder**. An empty binder appears inside the
body.
3. In the tree, **drag** the library's layer sketch (`FacePlate` or `BackPlate`) onto
the new binder. Both documents appear in the same tree.
3. In the tree, **drag** the library's sketch for this layer (`FacePlate`, `Diffuser` or
`BackPlate`) onto the new binder. Both documents appear in the same tree.

![Empty binder in the plate body, with the library sketch to drag](05-empty-binder.png)

Expand All @@ -99,11 +114,13 @@ CAD/Shared/Cutouts/Toggle12.FCStd ← library part
**Through all**. OK.

![Pocket on the binder: Symmetric + Through all](07-pocket.png)
6. Rename the binder `SW1_Face` (or `SW1_Back` on the BackPlate).
6. Rename the binder `SW1_Face` (`SW1_Diff` on the Diffuser, `SW1_Back` on the
BackPlate).
7. Save. When you're asked "Save dependent files?", answer **No** unless you edited the
library on purpose.

Repeat for every control and every plate layer. In the result below, SW2 is rotated 90°:
Repeat for every control and every plate layer. When the panel is done, **Export
Layers** writes one DXF per layer Body, with every cutout that goes through that plate. In the result below, SW2 is rotated 90°:
its tab sits to the side, while SW1's points down.

![Result: SW1 at 0°, SW2 at 90°; SW2 selected, showing its Translate attachment and 90° offset](08-result.png)
Expand Down
13 changes: 8 additions & 5 deletions docs/_source/cad-cutout-library/library-part.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,22 @@ link these files. Back to the [overview](index.md).
CAD/Shared/Cutouts/Toggle12.FCStd
└── Body
├── FacePlate (sketch: Ø12.6 hole)
├── Diffuser (sketch: Ø12.6 hole)
└── BackPlate (sketch: Ø12.6 hole + anti-rotation tab)
```

The library holds one sketch per **plate layer**, because the plates need different holes.
In Toggle12, for example, the BackPlate layer carries the anti-rotation tab and the
FacePlate layer doesn't.
The layers are the Bodies that Plate Stack builds: `FacePlate`, `Diffuser` and `BackPlate`
by default. In Toggle12, for example, the BackPlate layer carries the anti-rotation tab and
the other layers don't. Give every layer its own sketch, even when two layers cut the same
hole.

## Conventions

| Rule | Why |
|---|---|
| One file per part, one Body, one sketch per plate layer | Binders link to a sketch by name, so each layer must be its own sketch |
| Label sketches by layer: `FacePlate`, `BackPlate` | Tells you which binder points where |
| Label sketches exactly like the Plate Stack layers: `FacePlate`, `Diffuser`, `BackPlate` | Tells you which binder goes in which layer Body. If you rename or add layers in Plate Stack, name the sketches to match |
| Centre the cutout on the sketch origin (0,0) | Both methods place the origin, so (0,0) is the control's centre |
| Edit sketches in place: never delete and recreate them | The binder links to the sketch's internal name. A recreated sketch breaks every panel |
| Save the library in its final folder **before** linking it | Links store a relative path. Moving or renaming the file later breaks them |
Expand All @@ -29,8 +32,8 @@ FacePlate layer doesn't.

1. New file, saved in `CAD/Shared/Cutouts/` (e.g. `Toggle12.FCStd`).
2. Part Design → Create body, then one sketch per layer on the XY plane.
3. Draw each layer's cutout, centred on the origin. Rename the sketches `FacePlate` and
`BackPlate`.
3. Draw each layer's cutout, centred on the origin. Rename the sketches `FacePlate`,
`Diffuser` and `BackPlate`.
4. Save.

![Library BackPlate sketch: Ø12.6 hole plus anti-rotation tab, centred on the origin](01-library-sketch.png)
Expand Down
Loading
Loading