dumped stuff from old repo
This commit is contained in:
parent
c20787bd33
commit
cf00c83596
6 changed files with 494 additions and 2 deletions
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
*.scad
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv
|
||||
75
README.md
75
README.md
|
|
@ -1,3 +1,74 @@
|
|||
# case
|
||||
# mkbd65 case
|
||||
|
||||
CAD files for the case of mkbd65
|
||||
|
||||
## Generate CAD files
|
||||
|
||||
OpenSCAD Files can be created with the following command:
|
||||
|
||||
```
|
||||
./generate_scad.py
|
||||
```
|
||||
|
||||
You need solidpython installed for it to work. Do that by executing:
|
||||
|
||||
```
|
||||
# creates a virtualenv
|
||||
python -m venv venv
|
||||
# activates it
|
||||
source venv/bin/activate
|
||||
# installs dependencies
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Layout files
|
||||
|
||||
These files define the layoout that gets printed on the keymat. Currently the only file included is `layout_en_us.py`
|
||||
for an english US international layout. you can use that as a template for your layout.
|
||||
|
||||
The file should define a single variable `LAYOUT` which is a list of roaws. These rows are also lists of columns. Each
|
||||
column has keys, which are a list of the strings that should be printed at different positions.
|
||||
|
||||
Example for a one button keyboard with the labels `foo` in the top left corner and `bar` in the bottom left:
|
||||
|
||||
```
|
||||
LAYOUT = [
|
||||
[
|
||||
['foo', 'bar', '', '', ''],
|
||||
],
|
||||
]
|
||||
```
|
||||
|
||||
The label string will be used as `[TopLeft, BottomLeft, TopRight, BottomRight, Middle]`.
|
||||
|
||||
Some strings need special escaping to be used in OpenScad later on. See the en_us layout for examples.
|
||||
|
||||
## Phone config
|
||||
|
||||
Properties for different phones are saved in INI files. Currently the only file included is `oneplus5t.ini` for the
|
||||
Oneplus 5t phone with a english US international layout with the DejaVu Sans font.
|
||||
|
||||
In the config file you can define phone specific aspects and style such as the used font and layout. Here is a list of
|
||||
the possile options:
|
||||
|
||||
| Group | Option | Type | Default | Description |
|
||||
| ------ | --------- | ------ | ---------------------- | ----------------------------- |
|
||||
| keymap | thickness | Number | 0.5 | Thickness of the keymap in mm |
|
||||
| | layout | String | en_us-intl | Layout file used for labels |
|
||||
| key | thickness | Number | 1 | Thickness of the key in mm |
|
||||
| | font | String | DejaVu Sans:style=Bold | Font used for labels |
|
||||
|
||||
|
||||
OpenScad files
|
||||
--------------
|
||||
|
||||
The generator script `generate_scad.py` creates multiple files.
|
||||
|
||||
| File | Material | Description |
|
||||
| --------------------- | -------- | --------------------------------------------------- |
|
||||
| mkbd65_keymat.scad | TPU | Keymat should be printed with a 3D printer |
|
||||
| mkbd65_pcb.scad | - | Just a spacer for the 3D model fitting |
|
||||
| mkbd65_top_plate.scad | Aluminum | Laser cut on a CNC |
|
||||
| mkbd65_internals.scad | ABS/PLA | Inner structure should be printed with a 3D printer |
|
||||
| mkbd65.scad | - | Combination of the above files |
|
||||
|
||||
CAD files for the case of mkbd65
|
||||
322
generate_scad.py
Executable file
322
generate_scad.py
Executable file
|
|
@ -0,0 +1,322 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
mkbd65 openscad generator
|
||||
|
||||
Usage:
|
||||
python3 generate_scad.py <config.ini> [<layout>]
|
||||
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
|
||||
Example:
|
||||
python3 generate_scad.py oneplus5t.ini en_us-intl
|
||||
"""
|
||||
|
||||
import sys
|
||||
from configparser import ConfigParser
|
||||
from importlib import import_module
|
||||
|
||||
from solid import cube, text, union, difference, linear_extrude, scad_render_to_file, OpenSCADObject, translate, color, \
|
||||
polygon, circle
|
||||
from solid.utils import Black, White, Green, Aluminum, Cyan
|
||||
|
||||
|
||||
def roundrect(width, height, radius):
|
||||
"""
|
||||
O/-----\O
|
||||
/ \
|
||||
| |
|
||||
\ /
|
||||
O\_____/O
|
||||
|
||||
:param width:
|
||||
:param height:
|
||||
:param radius:
|
||||
:return:
|
||||
"""
|
||||
return union()(
|
||||
polygon([
|
||||
[0, radius],
|
||||
[0, height - radius],
|
||||
[radius, height],
|
||||
[width - radius, height],
|
||||
[width, height - radius],
|
||||
[width, radius],
|
||||
[width - radius, 0],
|
||||
[radius, 0]
|
||||
]),
|
||||
translate([radius, radius, 0])(
|
||||
circle(r=radius)
|
||||
),
|
||||
translate([radius, height - radius, 0])(
|
||||
circle(r=radius)
|
||||
),
|
||||
translate([width - radius, height - radius, 0])(
|
||||
circle(r=radius)
|
||||
),
|
||||
translate([width - radius, radius, 0])(
|
||||
circle(r=radius)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def key(dx: int, dy: int, label_ltop: str = '', label_lbottom: str = '', label_rtop: str = '', label_rbottom: str = '',
|
||||
label_center: str = '') -> OpenSCADObject:
|
||||
"""
|
||||
Generates a single key
|
||||
|
||||
:param dx: width in mm
|
||||
:param dy: length in mm
|
||||
:param label: List of labels (top, bottom, right, middle)
|
||||
:return:
|
||||
"""
|
||||
def get_size(s: str) -> float:
|
||||
if s in ['⇧', '⏎']:
|
||||
return 5
|
||||
elif s == '⌫':
|
||||
return 3.5
|
||||
elif s in ['Esc', 'Ctrl', 'Alt', 'Fn']:
|
||||
return 3
|
||||
else:
|
||||
return 4
|
||||
|
||||
thickness = config.getfloat('key', 'thickness', fallback=1)
|
||||
font = config.get('key', 'font', fallback='DejaVu Sans:style=Bold')
|
||||
|
||||
return difference()(
|
||||
linear_extrude(height=thickness)(
|
||||
roundrect(width=dx, height=dy, radius=0.5)
|
||||
),
|
||||
|
||||
translate(v=[1, 5.5, 0.8])(
|
||||
linear_extrude(height=0.2)(
|
||||
text(text=label_ltop, size=3, font=font, halign='left', valign='top')
|
||||
)
|
||||
),
|
||||
translate(v=[1, 0.5, 0.8])(
|
||||
linear_extrude(height=0.2)(
|
||||
text(text=label_lbottom, size=3, font=font, halign='left', valign='bottom')
|
||||
)
|
||||
),
|
||||
translate(v=[8.5, 5.5, 0.8])(
|
||||
linear_extrude(height=0.2)(
|
||||
text(text=label_rtop, size=3, font=font, halign='right', valign='top')
|
||||
)
|
||||
),
|
||||
translate(v=[8.5, -1.5 if label_rbottom == '`' else 0.5, 0.8])(
|
||||
linear_extrude(height=0.2)(
|
||||
text(text=label_rbottom, size=3, font=font, halign='right', valign='bottom')
|
||||
)
|
||||
),
|
||||
translate(v=[4.5, 3, 0.8])(
|
||||
linear_extrude(height=0.2)(
|
||||
text(text=label_center, size=get_size(label_center), font=font, halign='center', valign='center')
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def keymat() -> OpenSCADObject:
|
||||
"""
|
||||
Generates keymat
|
||||
|
||||
mat:
|
||||
+---------------------------------------------+
|
||||
| margin |
|
||||
| +-----+ +-----+ +-----+ |
|
||||
|margin| |padding| | ... | |margin|
|
||||
| +-----+ +-----+ +-----+ |
|
||||
| padding |
|
||||
| +-----+ +-----+ +-----+ |
|
||||
| | | | | | | |
|
||||
| +-----+ +-----+ +-----+ |
|
||||
| ... |
|
||||
| +-----+ +-----+ +-----+ |
|
||||
| | | | | | | |
|
||||
| +-----+ +-----+ +-----+ |
|
||||
| margin |
|
||||
+---------------------------------------------+
|
||||
\ thickness
|
||||
key:
|
||||
+-----+
|
||||
| | dy
|
||||
+-----+
|
||||
dx \ thickness
|
||||
|
||||
:return:
|
||||
"""
|
||||
thickness = config.getfloat('keymat', 'thickness', fallback=0.5)
|
||||
cols = 12
|
||||
rows = 5
|
||||
key_dx = 9
|
||||
key_dy = 6
|
||||
padding = 1
|
||||
margin = 2
|
||||
spacebar_x = 5 # nth key from the left
|
||||
spacebar_length = 2 # length in keys
|
||||
|
||||
keys = []
|
||||
for row in range(rows):
|
||||
for col in range(cols):
|
||||
keys.append(
|
||||
translate([
|
||||
col * padding + col * key_dx + margin,
|
||||
row * padding + row * key_dy + margin,
|
||||
thickness
|
||||
])(
|
||||
key(
|
||||
dx=key_dx,
|
||||
dy=key_dy,
|
||||
label_ltop=layout[row][col][0],
|
||||
label_lbottom=layout[row][col][1],
|
||||
label_rtop=layout[row][col][2],
|
||||
label_rbottom=layout[row][col][3],
|
||||
label_center=layout[row][col][4]
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return color(Black)(
|
||||
union()(
|
||||
# mat
|
||||
cube([
|
||||
cols * key_dx + (cols - 1) * padding + 2 * margin,
|
||||
rows * key_dy + (rows - 1) * padding + 2 * margin,
|
||||
thickness
|
||||
]),
|
||||
# keys
|
||||
*keys,
|
||||
# spacebar
|
||||
translate([spacebar_x * key_dx + spacebar_x * padding + margin, margin, thickness])(
|
||||
key(dx=key_dx * spacebar_length + (spacebar_length - 1) * padding, dy=key_dy)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def pcb() -> OpenSCADObject:
|
||||
rows = 5
|
||||
columns = 12
|
||||
hspacing = 4
|
||||
vspacing = 3
|
||||
width = 6
|
||||
height = 4
|
||||
thickness = 0.78
|
||||
switches = []
|
||||
|
||||
for row in range(rows):
|
||||
for col in range(columns):
|
||||
switches.append(
|
||||
translate([3.5 + (hspacing + width) * col, 2 + (vspacing + height) * row, 0.6])(
|
||||
color(White)(
|
||||
linear_extrude(height=thickness)(
|
||||
# 6 +----+ 5
|
||||
# / \
|
||||
# 7 + + 4 | 2mm
|
||||
# 8 + + 3 |
|
||||
# \ 4mm /
|
||||
# 1 +----+ 2
|
||||
polygon(points=[(1, 0), (5, 0), (6, 1), (6, 3), (5, 4), (1, 4), (0, 3), (0, 1)]),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
return union()(
|
||||
color(Green)(cube([123, 49, 0.6])),
|
||||
# ATMEGA32U4
|
||||
translate([13, 36, 0.6])(
|
||||
color(Black)(cube([7, 7, 1]))
|
||||
),
|
||||
# Crystal
|
||||
translate([23, 35.75, 0.6])(
|
||||
color(Black)(cube([2.5, 2, 0.55]))
|
||||
),
|
||||
*switches
|
||||
)
|
||||
|
||||
|
||||
def top_plate() -> OpenSCADObject:
|
||||
thickness = config.getfloat('keymat', 'thickness', fallback=1)
|
||||
w = config.getfloat('phone', 'width')
|
||||
h = config.getfloat('phone', 'height')
|
||||
r = config.getfloat('phone', 'cornerradius')
|
||||
|
||||
return color(Aluminum)(
|
||||
difference()(
|
||||
#cube([123, 49, 0.5]),
|
||||
linear_extrude(height=thickness)(
|
||||
roundrect(width=w, height=h, radius=r)
|
||||
),
|
||||
translate([0, 0, -1 * thickness])(keymat())
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def internals() -> OpenSCADObject:
|
||||
return color(Cyan)(cube([1, 1, 1]))
|
||||
|
||||
|
||||
def mkbd65() -> OpenSCADObject:
|
||||
fr4 = 0.4 # pcb thickness
|
||||
switch = 0.78 # switch height
|
||||
keymat_thickness = config.getfloat('keymat', 'thickness', fallback=1)
|
||||
|
||||
return union()(
|
||||
internals(),
|
||||
pcb(),
|
||||
color(Black)(translate([0, -1, fr4 + switch])(keymat())),
|
||||
color(Aluminum)(translate([0, -1, fr4 + switch + keymat_thickness])(top_plate()))
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
config = ConfigParser()
|
||||
|
||||
if '-h' in sys.argv or '--help' in sys.argv or 2 > len(sys.argv) > 3:
|
||||
sys.exit(__doc__)
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
layoutfile = sys.argv[2]
|
||||
else:
|
||||
layoutfile = 'en_us-intl'
|
||||
|
||||
try:
|
||||
with open(sys.argv[1]) as fd:
|
||||
config.read_file(fd)
|
||||
layout = import_module(f'layout_{ layoutfile }').LAYOUT
|
||||
file_header = '$fn = 16;'
|
||||
scad_render_to_file(
|
||||
keymat(),
|
||||
filepath='./mkbd65_keymat.scad',
|
||||
file_header=file_header,
|
||||
)
|
||||
# TODO: generate mkbd65_pcb.scad
|
||||
scad_render_to_file(
|
||||
pcb(),
|
||||
filepath='./mkbd65_pcb.scad',
|
||||
file_header=file_header,
|
||||
)
|
||||
# TODO: generate mkbd65_top_plate.scad
|
||||
scad_render_to_file(
|
||||
top_plate(),
|
||||
filepath='./mkbd65_top_plate.scad',
|
||||
file_header=file_header,
|
||||
)
|
||||
# TODO: generate mkbd65_internals.scad
|
||||
scad_render_to_file(
|
||||
internals(),
|
||||
filepath='./mkbd65_internals.scad',
|
||||
file_header=file_header,
|
||||
)
|
||||
# TODO: generate mkbd65.scad
|
||||
scad_render_to_file(
|
||||
mkbd65(),
|
||||
filepath='./mkbd65.scad',
|
||||
file_header=file_header,
|
||||
)
|
||||
except FileNotFoundError:
|
||||
sys.exit(f'The config file { sys.argv[1] } could not be found.')
|
||||
except ModuleNotFoundError:
|
||||
sys.exit(f'The layout file `layout_{ layoutfile }.py` could not be found.')
|
||||
80
layout_en_us-intl.py
Normal file
80
layout_en_us-intl.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
# [TopLeft, BottomLeft, TopRight, BottomRight, Middle]
|
||||
|
||||
LAYOUT = [
|
||||
# row 4
|
||||
[
|
||||
['', '', '', '', 'Ctrl'], # Left Control
|
||||
['', '', '', '', 'Fn'], # Function
|
||||
['', '', '', '', '⇧'], # Left Shift
|
||||
['', '', '', '', 'Alt'], # Left Alt (Alt Gr)
|
||||
['', '\\\\', '|', '', ''],
|
||||
['', '', '', '', ''], # Spacebar (won't be visible)
|
||||
['', '', '', '', ''], # Spacebar (won't be visible)
|
||||
['', '-', '_', '', ''],
|
||||
['', '=', '+', '', ''],
|
||||
['', '', '', '', '◀'], # Arrow Left / Home
|
||||
['', '', '', '', '▼'], # Arrow Down / Page Down
|
||||
['', '', '', '', '▶'] # Arrow Right / End
|
||||
],
|
||||
# row 3
|
||||
[
|
||||
['', '', '', '', 'Z'],
|
||||
['', '', '', '', 'X'],
|
||||
['', '', '', '', 'C'],
|
||||
['', '', '', '', 'V'],
|
||||
['', '', '', '', 'B'],
|
||||
['', '', '', '', 'N'],
|
||||
['', '', '', '', 'M'],
|
||||
['', ',', '<', '', ''],
|
||||
['', '.', '>', '', ''],
|
||||
['', '/', '?', '', ''],
|
||||
['', '', '', '', '▲'], # Arrow Up / Page Up
|
||||
['', '', '', '', '⇧'] # Right Shift
|
||||
],
|
||||
# row 2
|
||||
[
|
||||
['', '', '', '', 'A'],
|
||||
['', '', '', '', 'S'],
|
||||
['', '', '', '', 'D'],
|
||||
['', '', '', '', 'F'],
|
||||
['', '', '', '', 'G'],
|
||||
['', '', '', '', 'H'],
|
||||
['', '', '', '', 'J'],
|
||||
['', '', '', '', 'K'],
|
||||
['', '', '', '', 'L'],
|
||||
['', ';', ':', '', ''],
|
||||
['', '\'', '\\"', '`', ''],
|
||||
['', '', '', '', '⏎'] # Return
|
||||
],
|
||||
# row 1
|
||||
[
|
||||
['', '', '', '', 'Q'],
|
||||
['', '', '', '', 'W'],
|
||||
['', '', '', '', 'E'],
|
||||
['', '', '', '', 'R'],
|
||||
['', '', '', '', 'T'],
|
||||
['', '', '', '', 'Y'],
|
||||
['', '', '', '', 'U'],
|
||||
['', '', '', '', 'I'],
|
||||
['', '', '', '', 'O'],
|
||||
['', '', '', '', 'P'],
|
||||
['', '[', '{', '', ''],
|
||||
['', ']', '}', '', '']
|
||||
],
|
||||
# row 0
|
||||
[
|
||||
['','','','','Esc'],
|
||||
['', '1', '!', '', ''],
|
||||
['', '2', '@', '', ''],
|
||||
['', '3', '#', '', ''],
|
||||
['', '4', '$', '', ''],
|
||||
#['', '5', '%', '€', ''],
|
||||
['', '5', '%', '', ''],
|
||||
['', '6', '^', '', ''],
|
||||
['', '7', '&', '', ''],
|
||||
['', '8', '*', '', ''],
|
||||
['', '9', '(', '', ''],
|
||||
['', '0', ')', '', ''],
|
||||
['', '', '', '', '⌫'] # Backspace
|
||||
]
|
||||
]
|
||||
14
oneplus5t.ini
Normal file
14
oneplus5t.ini
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
; mkbd65 config for OnePlus 5t
|
||||
|
||||
[keymat]
|
||||
thickness = 0.5
|
||||
layout = en_us-intl
|
||||
|
||||
[key]
|
||||
thickness = 1
|
||||
font = DejaVu Sans:style=Bold
|
||||
|
||||
[phone]
|
||||
width = 156
|
||||
height = 75
|
||||
cornerradius = 10
|
||||
1
requirements.txt
Normal file
1
requirements.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
solidpython
|
||||
Loading…
Reference in a new issue