diff --git a/.claude/skills/cad/SKILL.md b/.claude/skills/cad/SKILL.md index 7d7a70ff..6d4f3a50 100644 --- a/.claude/skills/cad/SKILL.md +++ b/.claude/skills/cad/SKILL.md @@ -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 `_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 +`_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 → diff --git a/docs/_source/cad-cutout-library/array-placement.md b/docs/_source/cad-cutout-library/array-placement.md index 9a43f001..cf5a22b6 100644 --- a/docs/_source/cad-cutout-library/array-placement.md +++ b/docs/_source/cad-cutout-library/array-placement.md @@ -9,7 +9,9 @@ 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 @@ -17,18 +19,28 @@ The screenshots come from a small demo: an `LED5` library part (FacePlate Ø5.2, CAD/Shared/Cutouts/LED5.FCStd ← library part └── Body ├── FacePlate (sketch: Ø5.2 hole) + ├── Diffuser (sketch: the Diffuser hole) └── BackPlate (sketch: Ø6.0 hole) .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: @@ -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. @@ -71,7 +85,9 @@ 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 `_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**. @@ -79,8 +95,9 @@ Each layer uses two binders: ![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) diff --git a/docs/_source/cad-cutout-library/index.md b/docs/_source/cad-cutout-library/index.md index b106a592..7ed7fec0 100644 --- a/docs/_source/cad-cutout-library/index.md +++ b/docs/_source/cad-cutout-library/index.md @@ -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. @@ -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 | @@ -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 + `_Outline`, `_Pad`, `_Cut` and `_Pocket` (the fastener cut). + Add your binders and pockets after `_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 diff --git a/docs/_source/cad-cutout-library/lcs-placement.md b/docs/_source/cad-cutout-library/lcs-placement.md index 79512c6d..59b12ab3 100644 --- a/docs/_source/cad-cutout-library/lcs-placement.md +++ b/docs/_source/cad-cutout-library/lcs-placement.md @@ -8,7 +8,9 @@ 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 @@ -16,32 +18,42 @@ BackPlate with two controls, SW1 and SW2. SW2 is rotated 90°. 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) .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 + `_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 | @@ -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) @@ -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) @@ -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) diff --git a/docs/_source/cad-cutout-library/library-part.md b/docs/_source/cad-cutout-library/library-part.md index cb0fcea7..c47ed8b1 100644 --- a/docs/_source/cad-cutout-library/library-part.md +++ b/docs/_source/cad-cutout-library/library-part.md @@ -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 | @@ -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) diff --git a/docs/hardware/cad-workflow.md b/docs/hardware/cad-workflow.md index 78a60800..e5504210 100644 --- a/docs/hardware/cad-workflow.md +++ b/docs/hardware/cad-workflow.md @@ -14,3 +14,45 @@ status: stub of the project. This page will be updated once a tool is selected. The file management policy (source files committed, STL/STEP exports gitignored and published via GitHub Releases) applies regardless of tool choice. + +## Panel base blank + +Every side-console panel starts from the same base: a 5¾″-wide outline, a whole number of +⅜″ Dzus units tall, with fasteners on the rail grid (see +[Dzus rail mounting](mechanical-standards.md#dzus-rail-mounting-mil-f-25173a)). You don't +draw that base by hand. The **Cockpit Panels** workbench for FreeCAD 1.1+ builds it, then +turns it into the plates you cut. It lives in its own repository, +[OpenSkyHawk/CockpitPanels](https://github.com/OpenSkyHawk/CockpitPanels), because the +panel grid is common to many aircraft, not only the A-4. + +To install it, open **Tools → Addon Manager → ⚙ → Custom repositories**, add +`https://github.com/OpenSkyHawk/CockpitPanels` with branch `main`, then install +**Cockpit Panels** and restart FreeCAD. Updates arrive through the Addon Manager like any +other addon. Everything the workbench creates is a plain FreeCAD object, so a panel file +opens and recomputes on any FreeCAD 1.1+, with or without the workbench installed. + +The workbench has three tools, used in order. Their buttons sit on the Cockpit Panels +toolbar and also on the Sketcher and Part Design toolbars. + +**Panel Blank** draws the base, centred on the origin on the XY plane: the outline, a mount +point at every fastener position and a clearance hole at each one. Give it the height in +units (or a measured height, which it rounds to the nearest unit), any extra fastener rows, +the fastener and an optional corner radius. All of it is driven by a small spreadsheet, so +editing a cell moves everything. Running Panel Blank again updates the same objects in +place, and anything built on them keeps working. + +**Plate Stack** turns the blank into one Part Design Body per layer. The default stack is a +1/16″ FacePlate, a 1/8″ Diffuser and a 1/8″ BackPlate, and you can rename, add or remove +layers and change their thicknesses. The faceplate's front face sits at z = 0, and each +layer sits directly behind the one before, so the Top view shows the panel as it looks in +the cockpit. Each layer gets its own fastener cut: a plain clearance hole, a recess that +lets the screw head sit down in the layer, or a slot that opens through the side edge (and +optionally through the top and bottom edges). The faceplate can also be inset from the +panel's edges so it sits back from the plates behind it. + +**Export Layers** writes the laser-cut files: one DXF per plate, named after the plate's +Body and drawn on a layer of the same name. Each file holds the plate's outline and every +hole that goes all the way through it. + +Control cutouts go into the plate Bodies after Plate Stack has built them. Draw each +control's cutout once, in a shared library part, and link it into every panel that uses it.