Compare commits

67 Commits

Author SHA1 Message Date
4037ac4a1a comment 2023-03-01 16:15:05 -03:00
b3f813eaf1 lint 2023-03-01 16:13:57 -03:00
576edc839b Massive refactor that changes nothing in the shape of the case :-) 2023-03-01 15:47:06 -03:00
120638f50f Remove dead code 2023-02-24 16:00:29 -03:00
d9f7d7f7a9 Tweaks in screen mount so it has some rounder edges and slightly smaller viewport 2023-02-24 15:59:01 -03:00
0dd1c858e1 lint 2023-02-24 10:46:19 -03:00
6ea773109b Fix minor issues with holes positions and shapes 2023-02-24 10:44:35 -03:00
b5deb70cbd Rearrange right side to put USB plug in the back and audio on the side 2023-02-23 13:20:49 -03:00
7fbf323e45 CPU and battery stands with holes for screws 2023-02-23 10:08:57 -03:00
84f5978454 USB hub holder + parametrization 2023-02-22 18:17:02 -03:00
a894e8319c Adjust battery holder parameters 2023-02-22 15:02:10 -03:00
af3e1824f4 Integrate pogo plug receptacle into base 2023-02-22 14:17:29 -03:00
67db8765d8 lint 2023-02-22 12:20:36 -03:00
e307750c8d New audio plug holes, moved USB hub plug so that's doable 2023-02-22 11:25:50 -03:00
804f012b19 Fix size in pogo plug 2023-02-17 17:59:02 -03:00
2baebe8895 Added pogo plug connector 2023-02-17 17:55:20 -03:00
8d962eba14 Cadquery 2 2023-02-17 14:32:01 -03:00
d4e309f081 Battery and CPU holder adjustments 2023-02-17 10:08:05 -03:00
424396a266 Adjust battery holder dimensions 2023-02-16 15:58:30 -03:00
9840e6ad70 Make base taller so battery fits 2023-02-16 15:08:21 -03:00
ccb3220b1b Tweak battery positioning 2023-02-16 15:00:40 -03:00
31630ab1b0 lint 2023-02-16 14:57:51 -03:00
64db220a46 Integrated Battery holder 2023-02-16 14:57:32 -03:00
4624a2531f Integrated CPU holder 2023-02-16 14:42:31 -03:00
be6245aa3b Removed cable hole in screen mount
This cut is not needed with the lower keyboard position.
2023-02-01 10:28:58 -03:00
4b0cf1cfa0 Cleanup and adjustments for rev2
* Removed holes that make no sense anymore
* Made case shorter to avoid unsightly gap between screen and keyboard
* Added comments
2023-02-01 10:21:29 -03:00
6eb3eba4f2 Re-add back strip so mounting pillars print easier 2023-01-30 18:01:50 -03:00
dbaa9832f8 Move USB hole up a little 2023-01-30 16:09:48 -03:00
76af86ac70 Added 6th screen mounting pillar, improved kbd cable hole placement and screen mounting code 2023-01-30 10:57:33 -03:00
6cbd7e2b15 Tweaks 2023-01-27 17:01:37 -03:00
459021ff83 Playing with screen mount parameters, angle to 20 degrees 2023-01-27 16:11:28 -03:00
4f2c1e35f6 Redesigned screen holder for 30 degree screen 2023-01-27 15:43:54 -03:00
1e89b41995 Redesigned screen holder for 30 degree screen 2023-01-27 15:32:04 -03:00
37d96b0e4f Bring the keyboard 1.5 mm lower INTO the case 2023-01-27 13:16:09 -03:00
b85ba1f3e1 2-level kbd mounting pillars 2023-01-27 11:23:04 -03:00
a6d3f32797 larger hole for kbd mounting screws 2023-01-27 11:16:40 -03:00
92291013c6 Smaller kbd pillars, fix base splitting 2023-01-26 15:11:16 -03:00
d048e19cec Starting rev 2
* Adjusted sizes and other parameters for the new 65% keyboard
* Commented battery holder (waiting on the 18650 charger)
2023-01-26 11:08:58 -03:00
bebc4d5729 Move keyboard cable hole 6mm to the left 2022-12-02 11:26:52 -03:00
26dc83baf9 Larger kbd cable hole makes shape simpler 2022-12-02 10:05:27 -03:00
29e2464bef Bring back missing screen mounting pillar 2022-12-02 10:04:23 -03:00
4386b1c017 Split the screen mount so it needs fewer supports 2022-12-01 15:20:57 -03:00
8058118491 Slightly larger hole for power switch 2022-12-01 12:29:33 -03:00
4279547773 Refactor screen_mount script a bit 2022-11-30 14:29:42 -03:00
e4a011f5bd Single mounting beam at the back 2022-11-30 07:43:14 -03:00
a2932a4e49 Screw heads are a bit bigger than expected 2022-11-29 09:27:15 -03:00
2a48edb3cf Mounting pillars and screwholes to join top and bottom cases 2022-11-28 15:09:49 -03:00
f549fb32b0 Thicker walls 2022-11-28 12:19:56 -03:00
db5e874d91 Fix screen holder split, add cutout for kbd cable 2022-11-28 11:26:23 -03:00
f01e5a92ee bump 2022-11-28 10:36:18 -03:00
59882af24f Shorter screen holder, rounded top, screen slightly slower 2022-11-25 18:15:42 -03:00
6e8869363e Refactor, comments 2022-11-25 17:11:31 -03:00
bf1f0cc4ce Missing files, screen mount simplified 2022-11-25 14:46:30 -03:00
e9b3a42564 More work on the screen mount 2022-11-25 12:28:39 -03:00
b8d902ea11 Basic screen bezels 2022-11-24 17:45:59 -03:00
8534d25e4b Make the stand a bit taller to allow cable to pass below 2022-11-24 14:45:43 -03:00
8b152fc844 Make the stand a bit taller to allow cable to pass below 2022-11-24 14:44:17 -03:00
c5b2d68518 Prototype CPU holder 2022-11-24 11:24:38 -03:00
18a8e9a904 Add power switch hole 2022-11-24 10:30:05 -03:00
85d4fb661f Built 2022-11-24 09:55:09 -03:00
c127e5f34b Thicker walls in the battery holder 2022-11-24 09:54:11 -03:00
f9987f43e9 kbd width was wrong 2022-11-24 09:51:53 -03:00
6f15cd32d5 battery holder tweak 2022-11-24 09:51:40 -03:00
6e01b44b52 USB inlet port 2022-11-23 10:25:10 -03:00
897e314f9e * Round stands
* Battery holder
* Power cable cutoff
* Dimensional fixes
2022-11-22 15:41:47 -03:00
df1ee0d425 Make it fit in the printer 2022-11-15 16:04:54 -03:00
4114adb49a Split in cadquery 2022-11-15 16:01:20 -03:00
22 changed files with 553 additions and 42711 deletions

View File

@ -0,0 +1,16 @@
# Hole to expose a USB audio card (YMMV)
# The hole is for a USB-A plug, y is measured in the hub
# (from the bottom face to middle of the hole)
# Consumers should set proper offsets for the hole
holes = [
# 2-jack plug
{
"x": 0,
"y": 4,
"height": 6,
"width": 17,
"fillet": 2,
},
]

View File

@ -0,0 +1,73 @@
import cadquery as cq
stand_positions = [(0, 0), (58, 0), (58, 49), (0, 49)]
stands = (
cq.Sketch().push(stand_positions).circle(3, mode="a").circle(2.65 / 2, mode="s")
)
pillar_height = 7
# This is a holder for DuPont cables so they connect to this
# things' pogo pins which are used to power the CPU
pin_positions = [(3.5, 0), (4 * 2.54 + 3.5, 0)]
pin_holder_width = 25
pin_holder_height = 15
pin_holder = (
cq.Sketch()
.polygon(
[
(0.5, 0),
(pin_holder_width, 0),
(pin_holder_width, pin_holder_height),
(0, pin_holder_height),
(0.5, 0),
],
mode="a",
)
.push(pin_positions)
.polygon(
[(0, 0), (2.6, 0), (2.6, pin_holder_height), (0, pin_holder_height), (0, 0)],
mode="s",
)
)
elements = [
# Battery holder stands
{
"x": 0,
"y": 0,
"shape": stands,
"height": pillar_height,
},
# Pogo pin connector channels
{
"x": 0,
"y": 40,
"shape": pin_holder,
"height": 3,
},
]
# Hole distances are relative to the rightmost pillar
# seen from the back of the case, that's why they are negative
# Heights are relative to base of pillars
# All distances are measured to the CENTER of the hole
holes = [
# Power inlet
{
"x": -15,
"y": -1 + pillar_height,
"height": 6.5,
"width": 12,
"fillet": 1,
},
# Power button
{
"x": -67,
"y": 5.5 + pillar_height,
"height": 7,
"width": 7,
"fillet": 1,
},
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
notebook_nueva/model.stl Normal file

Binary file not shown.

View File

@ -1,43 +1,108 @@
import cadquery2 as cq import cadquery as cq
from cadquery2 import exporters from cadquery import exporters
import audio_plug
import battery_holder
import usb_hub
import zero_holder as cpu_holder
from utils import extrude_shape, punch_hole
# Base for the notebook. Basically a kbd base that extends back # Base for the notebook. Basically a kbd base that extends back
# as much as possible # as much as possible
# Size of the whole object
width = 295
height = 165
thickness = 25
kbd_height = 100
kbd_angle = 6
# Thickness of the outer material # Thickness of the outer material
shell_t = 3 shell_t = 3
# Size of the kbd board
kbd_height = 95.5
kbd_width = 305
kbd_angle = 5
# Size of the whole object
width = kbd_width + 2 * shell_t
height = 159
thickness = 27 + shell_t # 27 inside
# Insert Positions # Insert Positions
ti_radius = 2.35 ti_radius = 2.35
ti_depth = 6.25 ti_depth = 6.25
pillars = ( # Positions are determined by measuring the keyboard
kbd_pillar_positions = [
(18.25, -16),
(142.5, -25.5),
(kbd_width - 20, -16),
(23.5, -79.5),
(145.5, -82.5),
(kbd_width - 19, -79.5),
]
# 2-level mounting pillars for the kbd
# Width of these need to be tweaked for
# each specific keyboard
kbd_pillars = (
cq.Sketch() cq.Sketch()
.push( .push(kbd_pillar_positions)
[ .circle(2.2, mode="a")
(19, -16.5), # Holes for self-tapping screws
(133, -16.5), .circle(1.1, mode="s")
(247.5, -16.5),
(24, -86),
(142.5, -91),
(261.5, -86),
]
)
.trapezoid(12, 12, 90, mode="a")
.circle(ti_radius, mode="s")
) )
kbd_lower_pillars = (
cq.Sketch()
.push(kbd_pillar_positions)
.circle(4, mode="a")
# Holes for self-tapping screws
.circle(1.1, mode="s")
)
# These are placed where convenient, and are used to join the top and bottom
# parts of the case.
# Measured from top-left corner OUTSIDE
mounting_pillar_positions = [
(6, -6),
(6, -40),
(120, -6),
(170, -6),
(width - 6, -6),
(width - 6, -30),
]
mounting_pillars = (
cq.Sketch()
.push(mounting_pillar_positions)
.trapezoid(12, 12, 90, mode="a")
.circle(1.8, mode="s")
)
screw_holes = cq.Sketch().push(mounting_pillar_positions).circle(3, mode="a")
# Thing to "grab" the hub so it stays in place
# Distance from edge to center of USB plug
usb_offset = 48
# CPU holder position from back-left corner of the case
cpu_offset_x = 160
cpu_offset_y = 25
# Battery holder position from back-left corner of the case
battery_offset_x = 22
battery_offset_y = 8
# Offset for the USB port from back-right corner of the case
usb_offset = 48
def model(): def model():
return ( # Create the basic shape of the case bottom.
# Currently also adds keyboard stuff and things to connect
# to the screen case, but that should be refactored
# out (FIXME)
model = (
cq.Workplane("XY") cq.Workplane("XY")
.workplane(offset=thickness / 2) .workplane(offset=thickness / 2)
.tag("mid_height") .tag("mid_height")
@ -50,10 +115,18 @@ def model():
# Slanted mounting pillars on the kbd top # Slanted mounting pillars on the kbd top
.faces(">Z") .faces(">Z")
.workplane(centerOption="CenterOfBoundBox") .workplane(centerOption="CenterOfBoundBox")
.center(-width / 2, 17) # Top-left kbd corner inside the box
.center(-width / 2 + shell_t, kbd_height - height / 2 + shell_t)
.transformed(rotate=cq.Vector(kbd_angle, 0, 0)) .transformed(rotate=cq.Vector(kbd_angle, 0, 0))
# These two offsets push the keyboard "down" into the case
# and need to be adjusted per-keyboard
.tag("sloped") .tag("sloped")
.placeSketch(pillars) .workplane(offset=-2.5)
.placeSketch(kbd_pillars)
.extrude(-1000)
.workplaneFromTagged("sloped")
.workplane(offset=-5.5)
.placeSketch(kbd_lower_pillars)
.extrude(-1000) .extrude(-1000)
# Remove the excess extrusion # Remove the excess extrusion
.workplaneFromTagged("mid_height") .workplaneFromTagged("mid_height")
@ -62,41 +135,144 @@ def model():
# Slope for the beyboard # Slope for the beyboard
.workplaneFromTagged("sloped") .workplaneFromTagged("sloped")
.split(keepBottom=True) .split(keepBottom=True)
# Pillars to join with top half
.workplaneFromTagged("mid_height")
.workplane(offset=-thickness / 2, centerOption="CenterOfBoundBox")
.center(-width / 2, height / 2)
.placeSketch(mounting_pillars)
.extrude(thickness)
# Holes to insert screws from the bottom
.workplaneFromTagged("mid_height")
.workplane(offset=-thickness / 2, centerOption="CenterOfBoundBox")
.center(-width / 2, height / 2)
.placeSketch(screw_holes)
# 13 is 20-7 (screw thread length - threaded insert depth)
.cutBlind(thickness - 13)
) )
top_right = ( # Now the basic box shape is in place, start adding things
model() # and cutting holes.
.faces(">Y")
.workplane(offset = -120).split(keepTop=True)
.faces(">X")
.workplane(offset=-135).split(keepTop=True)
)
exporters.export(top_right, "top_right.stl")
top_left = ( # Holes in the back of the case for battery holder
model() for hole in battery_holder.holes:
.faces(">Y") model = punch_hole(
.workplane(offset = -120).split(keepTop=True) model=model,
.faces(">X") face=">Y",
.workplane(offset=-135).split(keepBottom=True) w=width,
) h=thickness,
exporters.export(top_left, "top_left.stl") x_offset=width - battery_offset_x,
y_offset=shell_t,
hole=hole,
depth=shell_t,
)
bottom_right = ( # Hole for USB hub in the back
model() for hole in usb_hub.holes:
.faces(">Y") model = punch_hole(
.workplane(offset = -120).split(keepBottom=True) model=model,
.faces(">X") face=">Y",
.workplane(offset=-165).split(keepTop=True) w=width,
) h=thickness,
exporters.export(bottom_right, "bottom_right.stl") x_offset=usb_offset + shell_t + usb_hub.holes[0]["width"] / 2,
y_offset=shell_t,
hole=hole,
depth=shell_t,
)
bottom_left = ( # USB hub holder
model() for element in usb_hub.elements:
.faces(">Y") model = extrude_shape(
.workplane(offset = -120).split(keepBottom=True) model=model,
.faces(">X") face="<Z",
.workplane(offset=-165).split(keepBottom=True) w=width,
) h=height,
exporters.export(bottom_left, "bottom_left.stl") x_offset=width - usb_offset - shell_t - +usb_hub.holes[0]["width"] / 2,
y_offset=shell_t + element["y"],
shape=element["shape"],
height=-(element["height"] + shell_t),
)
# Hole for audio in right side
for hole in audio_plug.holes:
model = punch_hole(
model=model,
face=">X",
w=height,
h=thickness,
x_offset=height - shell_t - 34.5 - audio_plug.holes[0]["width"] / 2,
y_offset=shell_t,
hole=hole,
depth=shell_t,
)
# Battery holder stands and pogo pin holder
for element in battery_holder.elements:
model = extrude_shape(
model=model,
face="<Z",
w=width,
h=height,
x_offset=battery_offset_x + element["x"],
y_offset=shell_t + battery_offset_y + element["y"],
shape=element["shape"],
height=-(element["height"] + shell_t),
)
# CPU holder stands
for element in cpu_holder.elements:
model = extrude_shape(
model=model,
face="<Z",
w=width,
h=height,
x_offset=cpu_offset_x + element["x"],
y_offset=shell_t + cpu_offset_y + element["y"],
shape=element["shape"],
height=-(element["height"] + shell_t),
)
return model
if __name__ == "__main__":
left_cutout = cq.Sketch().polygon(
[(0, 0), (width / 2, 0), (width / 2, -height), (0, -height), (0, 0)],
mode="a",
)
right_side = (
model()
.faces("<Z")
.workplaneFromTagged("mid_height")
.transformed(offset=cq.Vector(0, 0, -thickness / 2))
.center(-width / 2, height / 2)
.placeSketch(left_cutout)
.cutBlind(100)
)
exporters.export(right_side, "right_side.stl")
right_cutout = cq.Sketch().polygon(
[
(width / 2, 0),
(width, 0),
(width, -height),
(width / 2, -height),
(width / 2, 0),
],
mode="a",
)
left_side = (
model()
.faces("<Z")
.workplaneFromTagged("mid_height")
.transformed(offset=cq.Vector(0, 0, -thickness / 2))
.center(-width / 2, height / 2)
.placeSketch(right_cutout)
.cutBlind(100)
)
exporters.export(left_side, "left_side.stl")
exporters.export(model(), "model.stl")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,154 @@
import cadquery as cq
from cadquery import exporters
from modelo import (
kbd_height,
kbd_width,
mounting_pillar_positions,
shell_t,
ti_depth,
ti_radius,
)
# Size of the whole object
width = kbd_width + 2 * shell_t
height = 66
height_bottom = 59
thickness = 48 # Will be shorter after construction
# Visible screen size
vis_w = 219
vis_h = 55
viewport_cutout = cq.Sketch().trapezoid(vis_w, vis_h, 90, mode="a").vertices().fillet(2)
# Whole screen size
scr_w = 231
scr_h = 65
scr_thickness = 5.5
screen_cutout = cq.Sketch().trapezoid(scr_w, scr_h, 90, mode="a")
# Screen angle
scr_angle = 20
# Circuit board and cable hole.
# This is in the back of the screen, and is a bit shorter in height than the
# screen. It's wider so it removes enough material to make the shape simpler.
board_cutout = cq.Sketch().trapezoid(
scr_w + 5,
scr_h - 10,
90,
mode="a",
)
kbd_cable_hole = cq.Sketch().trapezoid(20, 9, 90, mode="a").vertices().fillet(1)
mounting_pillars = (
cq.Sketch()
.push(mounting_pillar_positions)
.trapezoid(-12, 12, 90, mode="a")
.circle(ti_radius, mode="s")
.clean()
)
def model():
return (
cq.Workplane("XY")
.workplane()
.tag("mid_height")
.box(width, height, thickness)
# The screen goes rotated
.faces(">Z")
.transformed(rotate=(scr_angle, 0, 0))
# Move the screen "lower" so it doesn't interfere
# so much with the back
.center(0, -2)
.tag("slanted")
# Arbitrary huge trapezoid to cut off the material *in front*
# of the inclined screen
.placeSketch(cq.Sketch().trapezoid(1000, 1000, 90, mode="a"))
.cutBlind(1000)
# Trim the top
.workplaneFromTagged("mid_height")
.workplane(offset=21)
.placeSketch(cq.Sketch().trapezoid(1000, 1000, 90, mode="a"))
.cutBlind(100)
# Make bottom smaller to fit with base
.faces(">X")
.workplane(centerOption="CenterOfBoundBox")
.center(-height / 2, -thickness / 2)
.placeSketch(
cq.Sketch()
.polygon(
[
(height_bottom, 0),
(height_bottom, thickness / 3),
(height, thickness - 21),
(height, thickness),
(height + 5, thickness + 5),
(height + 5, 0),
(height_bottom, 0),
]
)
.vertices()
.fillet(3)
)
.cutBlind(-1000)
# Fillet top of the object
.edges("|X and >Z")
.fillet(3)
# Cut off viewport hole so we can see the screen
.workplaneFromTagged("slanted")
.placeSketch(viewport_cutout)
.cutBlind(-shell_t)
# Make hole for screen assembly so the whole screen fits
.workplaneFromTagged("slanted")
.workplane(offset=-shell_t, centerOption="CenterOfBoundBox")
# Left bezel is wider than right one, so this hole is displaced to the left
.center(-3, 0)
.placeSketch(screen_cutout)
.cutBlind(-scr_thickness)
# Make it hollow
.faces("<Z")
# Can't be exactly shell_t because cq fails
.shell(-shell_t + 0.01)
# Cut hole for the screen board and cables
.workplaneFromTagged("slanted")
.workplane(offset=-scr_thickness, centerOption="CenterOfBoundBox")
.placeSketch(board_cutout)
.cutBlind(-6)
.workplaneFromTagged("mid_height")
.workplane(offset=-thickness / 2, centerOption="CenterOfBoundBox")
.center(-width / 2, height_bottom - height / 2)
.placeSketch(mounting_pillars)
.extrude(10)
# Fillet the front edge of the screen case so it looks softer
.edges(">(0, -10, 5)")
.fillet(2)
)
if __name__ == "__main__":
print("Exporting")
exporters.export(model(), "screen_mount.stl")
offset_width = -width / 2
right_side = (
model()
.faces(">X")
.workplane(centerOption="CenterOfBoundBox", offset=offset_width)
.split(keepTop=True)
)
exporters.export(right_side, "right_screen_mount.stl")
left_side = (
model()
.faces(">X")
.workplane(centerOption="CenterOfBoundBox", offset=offset_width)
.split(keepBottom=True)
)
exporters.export(left_side, "left_screen_mount.stl")

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

33
notebook_nueva/usb_hub.py Normal file
View File

@ -0,0 +1,33 @@
import cadquery as cq
# Measurements for my USB hub, YMMV
# The hole is for a USB-A plug, y is measured in the hub
# (from the bottom face to middle of the hole)
# Consumers should set proper offsets for the hole
holes = [
# USB-A port
{
"x": 0,
"y": 4,
"height": 5.5,
"width": 13,
"fillet": 2,
},
]
elements = [
# Thing to grab the hub
{
"x": 0,
"y": 5,
"shape": (
cq.Sketch()
.trapezoid(22, 10, 90, mode="a")
.trapezoid(17, 10, 90, mode="s")
.clean()
),
"height": 8,
}
]

26
notebook_nueva/utils.py Normal file
View File

@ -0,0 +1,26 @@
import cadquery as cq
# TODO make API of extrude_shape and punch_hole more consistent
def extrude_shape(*, model, face, w, h, x_offset, y_offset, shape, height):
return (
model.faces(face)
.workplane(centerOption="CenterOfBoundBox")
.center(-w / 2 + x_offset, -h / 2 + y_offset)
.placeSketch(shape)
.extrude(height)
)
def punch_hole(*, model, face, w, h, x_offset, y_offset, hole, depth):
return (
model.faces(face)
.workplane(centerOption="CenterOfBoundBox")
.center(-w / 2 + x_offset + hole["x"], -h / 2 + y_offset + hole["y"])
.placeSketch(
cq.Sketch()
.trapezoid(hole["width"], hole["height"], 90, mode="a")
.vertices()
.fillet(hole["fillet"])
)
.cutBlind(-depth)
)

View File

@ -0,0 +1,16 @@
import cadquery as cq
positions = [(0, 0), (0, 23), (58, 23), (58, 0)]
stands = cq.Sketch().push(positions).circle(3, mode="a").circle(2.65 / 2, mode="s")
pillar_height = 7
elements = [
# CPU holder stands
{
"x": 0,
"y": 0,
"shape": stands,
"height": pillar_height,
}
]

View File

@ -1 +1 @@
cadquery cadquery2