Files
feather-case/README.md
T
2026-08-04 12:27:31 -07:00

9.3 KiB
Raw Blame History

Parametric Feather Case

An OpenSCAD enclosure generator for the Adafruit ESP32 Feather V2, stacked FeatherWings, an optional protected 18650 pack, and an optional 1/4-20 camera mount. It produces a body, removable lid, OLED button plungers, and fit calibration coupons.

Interactive Ruby wizard

The HighLine wizard asks the project-specific questions, saves the answers in YAML, and builds a self-contained case directory with OpenSCAD source, STL and/or 3MF geometry, and rendered previews.

Install the Ruby dependency into this repository:

bundle install

Then run:

bin/feather-case

The menu can create a case, reopen one for dimensional tuning after a test print, or rebuild an existing case. Generated definitions live under cases/<name>/; exports, previews, revision history, and vendor/bundle are ignored by Git.

OpenSCAD, Blender, and Python 3 must be available on PATH. On Ubuntu:

sudo apt-get install openscad blender python3

Set OPENSCAD=/path/to/openscad, BLENDER=/path/to/blender, or PYTHON=/path/to/python3 when a program is installed elsewhere. The wizard checks all three tools before replacing an existing package.

The wizard can add clearance beyond either short end of the Feather PCB for right-angle headers, plug housings, and wire bends. Front clearance moves the board and its standoffs away from the USB-C wall; rear clearance extends the opposite end of the case.

USB programming access can be omitted for a closed front wall or paired with an enclosed plug guide. The guide runs from the wall toward the connector and automatically stops short based on the configured connector overhang and end gap. New cases default to a 2 mm USB connector overhang, an enabled wall opening, and an enabled guide; with the standard 2 mm front clearance the guide has no inward length and behaves as the normal wall opening.

Each generated directory contains a dependency-free build.rb. After copying that directory to another Ubuntu machine, run ruby build.rb to reproduce its exports and previews. The saved generator source is used by default so a fine-tuning pass cannot silently pick up later geometry changes.

OpenSCAD's 3MF output contains portable model geometry. It does not contain a Bambu printer, filament, plate, or process profile; select those settings after opening the files in Bambu Studio.

The design targets support-free FDM printing with a 0.6 mm nozzle. PLA and PETG are suitable for general use; ASA is the preferred starting material for outdoor exposure. The enclosure is not weather-sealed.

Reference geometry

All dimensions are millimetres. Board coordinates come from Adafruit's source files:

The board origin is its USB edge at (0, 0). The case uses X from the USB wall toward the rear, Y from the plain side toward the battery/JST side, and Z up from the exterior bottom.

Generate parts

Open feather_case.scad in OpenSCAD and use the Customizer, or override values from the command line:

# Generic one-Wing case
openscad -o body.stl -D 'part="body"' feather_case.scad
openscad -o lid.stl -D 'part="lid"' feather_case.scad

# Three-Wing GPS case with battery and camera mount
openscad -o gps-body.stl \
  -D 'part="body"' \
  -D 'top_profile="gps"' \
  -D 'wing_count=3' \
  -D 'battery_enabled=true' \
  -D 'tripod_insert_enabled=true' \
  feather_case.scad
openscad -o gps-lid.stl \
  -D 'part="lid"' \
  -D 'top_profile="gps"' \
  -D 'wing_count=3' \
  -D 'battery_enabled=true' \
  -D 'tripod_insert_enabled=true' \
  feather_case.scad

# 128x64 OLED lid and all four captive buttons
openscad -o oled-lid.stl \
  -D 'part="lid"' \
  -D 'top_profile="oled128x64"' \
  -D 'button_reset=true' \
  feather_case.scad
openscad -o oled-buttons.stl \
  -D 'part="buttons"' \
  -D 'top_profile="oled128x64"' \
  -D 'button_reset=true' \
  feather_case.scad

The standard stack height is wing_count * wing_pitch, with a 12.25 mm default pitch. Set stack_height_override to the measured distance from the top surface of the Feather PCB to the top surface of the uppermost FeatherWing PCB when using unusual headers. Do not include components on the Wing; profile-specific component heights and top gaps are added separately. The measured override takes precedence over the computed height.

For the 128×64 OLED profile, oled_component_height is the height of the tallest board feature (the switch tops), while oled_display_height controls the display-face reference shown in the assembly preview. The defaults are 2.4 mm and 1.5 mm above the Wing PCB, respectively. The enclosure ceiling remains based on the taller switches plus oled_face_gap, placing the display face about 1.7 mm below the lid's inner plane. The default 0.7 mm captive-button contact extension spans most of the 0.8 mm switch-to-lid gap.

When the battery compartment and tripod insert are both enabled, the generator adds board-side clearance to keep the insert centered across the case width and moves it 5 mm toward the USB wall to clear the nearest Feather standoff. The battery partition defaults to three 0.6 mm extrusion lines and can be adjusted with battery_partition_thickness.

Two-color lid artwork

Set lid_label to a device name and/or enable lid_logo_enabled to add flush second-color artwork to non-OLED lids. Choose lid_art_orientation from usb_left, usb_front, usb_right, or usb_rear; it describes where the USB edge sits when the exterior artwork is upright. OLED profiles reject lid artwork until a window/button-safe layout is defined.

Generated artwork packages include separate lid_base and lid_accent meshes, a complete single-color lid, and lid_multicolor.3mf. The multicolor file is one aligned multipart object with its base assigned to filament 1 and its logo and title assigned to filament 2. Print the lid exterior-face-down.

Custom wire egress

extra_cutouts accepts any number of entries:

// [face, shape, u, z, width, height, radius]
extra_cutouts = [
    ["left",  "circle",    35, 10, 8,  8, 4],
    ["rear",  "roundrect", 20, 12, 14, 7, 2],
    ["right", "slot",      28, 15, 18, 5, 2.5]
];

Faces are front (the USB-C short wall), rear (the opposite short wall), left (the plain/non-JST long wall), and right (the JST/battery long wall). For front/rear faces, u is the global Y coordinate; for left/right faces it is global X. The wizard presents this as distance from the selected wall's left edge while viewing it from outside. The Z value is the opening centre. Shapes are circle, rect, roundrect, and slot. Cutouts that enter the floor or lid-lip keepout, approach another opening too closely, or overlap the USB opening or guide keepout raise an assertion instead of silently weakening those features.

Calibration

Heat-set insert holes vary significantly by insert brand, filament, nozzle, temperature, and printer calibration. Treat the supplied values as starting points.

  1. Export and print part="insert_coupon" in the intended material.
  2. Test both M2.5 and 1/4-20 inserts in the five stepped holes.
  3. Set m25_insert_hole_diameter and tripod_insert_hole_diameter to the best coupon values. These parameters are the finished pilot diameters in the model; hole_compensation is not added to heat-set pockets. The coupon uses the same tapered pocket geometry as the cases.
  4. Print part="switch_coupon" and choose the best rounded-rectangle opening for the actual KCD1-101 rocker-switch batch.
  5. Print part="fit_coupon" and tune fit_clearance before committing to the complete lid and body.

For ASA, tune dimensional compensation with coupons rather than applying an assumed global shrink percentage. Start with four or more walls, good chamber temperature control, and the same extrusion settings intended for the case.

Assembly

  1. Heat-set the optional 1/4-20 insert from inside the case. Its threaded opening faces the exterior bottom.
  2. Heat-set four M2.5 inserts into the board standoffs.
  3. Fasten the ESP32 Feather V2, then install the stacking headers and Wings.
  4. For battery builds, place the protected 69 x 18 mm pack in the cradle and route its lead through the combined front partition/JST opening and beneath the Feather PCB.
  5. Snap the KCD1-101 rocker switch into the rear lid opening, connect its bent quick-connect terminals or low-profile wiring, and lower the wired lid onto the case.
  6. Heat-set the four lid inserts downward into the corner bosses.
  7. For OLED builds, insert each enabled printed plunger through the lid from the inside. The elongated flange stays in the internal recess.
  8. Engage the lid rim and fasten four standard M2.5 socket-head screws into the 2.5 mm-deep counterbores.

Confirm the USB plug, switch, battery, insert, and lid fits without force before leaving a lithium-ion battery installed. The battery cradle is intended for Adafruit's protected pack, not an unprotected loose cell.