Merge pull request #576 from BackwardsMonday/main

Space Dino Hackpad
This commit is contained in:
Taran Mittal 2025-10-12 22:57:16 +11:00 committed by GitHub
commit 4b37bd9774
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 47684 additions and 0 deletions

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,83 @@
{
"board": {
"active_layer": 0,
"active_layer_preset": "",
"auto_track_width": true,
"hidden_netclasses": [],
"hidden_nets": [],
"high_contrast_mode": 0,
"net_color_mode": 1,
"opacity": {
"images": 0.6,
"pads": 1.0,
"tracks": 1.0,
"vias": 1.0,
"zones": 0.6
},
"ratsnest_display_mode": 0,
"selection_filter": {
"dimensions": true,
"footprints": true,
"graphics": true,
"keepouts": true,
"lockedItems": true,
"otherItems": true,
"pads": true,
"text": true,
"tracks": true,
"vias": true,
"zones": true
},
"visible_items": [
0,
1,
2,
3,
4,
5,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
32,
33,
34,
35,
36
],
"visible_layers": "fffffff_ffffffff",
"zone_display_mode": 0
},
"git": {
"repo_password": "",
"repo_type": "",
"repo_username": "",
"ssh_key": ""
},
"meta": {
"filename": "hackapad.kicad_prl",
"version": 3
},
"project": {
"files": []
}
}

View file

@ -0,0 +1,586 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.1,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": false,
"text_position": 0,
"units_format": 1
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.15,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.762,
"height": 1.524,
"width": 1.524
},
"silk_line_width": 0.15,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.15,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_near_hole": "error",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_dangling": "warning",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_clearance": 0.0,
"solder_mask_min_width": 0.0,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpadsmd": true,
"td_onroundshapesonly": false,
"td_ontrackend": false,
"td_onviapad": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"conflicting_netclasses": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"lib_symbol_issues": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"similar_labels": "warning",
"simulation_model_issue": "ignore",
"unannotated": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "hackapad.kicad_pro",
"version": 1
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.25,
"via_diameter": 0.8,
"via_drill": 0.4,
"wire_width": 6
}
],
"meta": {
"version": 3
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "hackapad.step",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"name": "Grouped By Value",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"29248ad5-3b64-4638-a2f8-7c818c5b281d",
"Root"
]
],
"text_variables": {}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,58 @@
# You import all the IOs of your board
import board
# These are imports from the kmk library
from kmk.kmk_keyboard import KMKKeyboard
from kmk.scanners.keypad import KeysScanner
from kmk.keys import KC
from kmk.modules.macros import Press, Release, Tap, Macros
from kmk.scanners import DiodeOrientation
from kmk.modules.encoder import EncoderHandler
from kmk.extensions.media_keys import MediaKeys
from kmk.extensions.RGB import RGB
# This is the main instance of your keyboard
keyboard = KMKKeyboard()
# Add the macro extension
encoderHandler = EncoderHandler
macros = Macros()
rgb = RGB(pixel_pin = board.D0, num_pixels = 12)
keyboard.extensions.append(rgb, MediaKeys())
keyboard.modules.append(macros, encoderHandler)
rgb.animation_mode("rainbow")
# Define your pins here!
keyboard.col_pins = (board.D26, board.D27, board.D28)
keyboard.row_pins = (board.D3, board.D4, board.D2, board.D1)
keyboard.diode_orientation = DiodeOrientation.COL2ROW
encoderHandler.pins = ((board.D29, board.D7, board.D6))
DocString = '"""desc\nParameters:\n var1 (type): desc\n var2 (type): desc\nReturns:\n out1 (type): desc\n"""'
commentAndCopy = KC.MACRO(
Tap(KC.HOME),
Tap(KC.LSFT(KC.END)),
Tap(KC.LCTL(KC.C)),
Tap(KC.LCTL(KC.SLASH)),
Tap(KC.LCTL(KC.ENT)),
Tap(KC.LCTL(KC.V))
)
# Here you define the buttons corresponding to the pins
# Look here for keycodes: https://github.com/KMKfw/kmk_firmware/blob/main/docs/en/keycodes.md
# And here for macros: https://github.com/KMKfw/kmk_firmware/blob/main/docs/en/macros.md
keyboard.keymap = [
[[KC.LCTL(KC.LSFT(KC.C)), KC.LCTL(KC.LSFT(KC.V)),KC.LCTL(KC.F5)],
[KC.LCTL(KC.C), KC.LCTL(KC.V),KC.F5],
[KC.MACRO("#TODO: "), KC.MACRO(DocString), commentAndCopy],
[KC.LCTL(KC.GRV), KC.NO, KC.NO]]
]
encoderHandler.map = [[[KC.VOLU, KC.VOLD, KC.MUTE]]]
# Start kmk!
if __name__ == '__main__':
keyboard.go()

File diff suppressed because it is too large Load diff

Binary file not shown.

View file

@ -0,0 +1,58 @@
# You import all the IOs of your board
import board
# These are imports from the kmk library
from kmk.kmk_keyboard import KMKKeyboard
from kmk.scanners.keypad import KeysScanner
from kmk.keys import KC
from kmk.modules.macros import Press, Release, Tap, Macros
from kmk.scanners import DiodeOrientation
from kmk.modules.encoder import EncoderHandler
from kmk.extensions.media_keys import MediaKeys
from kmk.extensions.RGB import RGB
# This is the main instance of your keyboard
keyboard = KMKKeyboard()
# Add the macro extension
encoderHandler = EncoderHandler
macros = Macros()
rgb = RGB(pixel_pin = board.D0, num_pixels = 12)
keyboard.extensions.append(rgb, MediaKeys())
keyboard.modules.append(macros, encoderHandler)
rgb.animation_mode("rainbow")
# Define your pins here!
keyboard.col_pins = (board.D26, board.D27, board.D28)
keyboard.row_pins = (board.D3, board.D4, board.D2, board.D1)
keyboard.diode_orientation = DiodeOrientation.COL2ROW
encoderHandler.pins = ((board.D29, board.D7, board.D6))
DocString = '"""desc\nParameters:\n var1 (type): desc\n var2 (type): desc\nReturns:\n out1 (type): desc\n"""'
commentAndCopy = KC.MACRO(
Tap(KC.HOME),
Tap(KC.LSFT(KC.END)),
Tap(KC.LCTL(KC.C)),
Tap(KC.LCTL(KC.SLASH)),
Tap(KC.LCTL(KC.ENT)),
Tap(KC.LCTL(KC.V))
)
# Here you define the buttons corresponding to the pins
# Look here for keycodes: https://github.com/KMKfw/kmk_firmware/blob/main/docs/en/keycodes.md
# And here for macros: https://github.com/KMKfw/kmk_firmware/blob/main/docs/en/macros.md
keyboard.keymap = [
[[KC.LCTL(KC.LSFT(KC.C)), KC.LCTL(KC.LSFT(KC.V)),KC.LCTL(KC.F5)],
[KC.LCTL(KC.C), KC.LCTL(KC.V),KC.F5],
[KC.MACRO("#TODO: "), KC.MACRO(DocString), commentAndCopy],
[KC.LCTL(KC.GRV), KC.NO, KC.NO]]
]
encoderHandler.map = [[[KC.VOLU, KC.VOLD, KC.MUTE]]]
# Start kmk!
if __name__ == '__main__':
keyboard.go()

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,86 @@
# Space Dino Hackpad
The Space Dino Hackpad is a 12 key macropad. It also contains a rotary encoder, and 12 leds, one under each key.
It uses KMK firmware, designed to make programming easier.
## Features List
- 2 part 3d printed case
- EC11 Rotary Encoder
- 12 keys
- 12 rgb leds
## Case
The case is fully 3d printed, and contains two parts. The two parts are attached with 4 M3 bolts and heatset inserts. It was designed in FreeCad.
![20250217_14h36m06s_grim](https://github.com/user-attachments/assets/1d0431aa-5ae7-4c66-aa22-69fda548ad19)
## PCB
The PCB was designed in KiCad. It uses a switch matrix to attach all the keys. The LED's are reverse mounted, and simply wired in a line.
Schematic
![20250220_13h25m19s_grim](https://github.com/user-attachments/assets/e606b22d-887a-4b61-bd81-80d79b3cb136)
The PCB is 2 layers, and contains a ground plane. The silkscreen art was drawn by me.
PCB
![20250220_13h31m59s_grim](https://github.com/user-attachments/assets/95e4db66-8a4e-430e-8b67-852bf64f5dd9)
## Firmware
The firmware was written in python using KMK.
### Rotary Encoder
The rotary encoder simply controls volume. Pressing the switch mutes volume.
### LEDs
The LEDs are set to run a "rainbow" animation
### Keys
The keys are all linked to various functions useful when programming.
#### Copy Paste
The first two keys on the top row are routed to Ctrl+Shift+C and Ctrl+Shift+V. This allows for copying and pasting in the terminal on most Linux systems.
The two keys below these are routed to Ctrl+C and Ctrl+V for copy pasting in most IDEs and text editors
#### Run
On the first row the rightmost key is routed to F5. This is the shortcut in VS Code to start debugging.
The key below this is routed to Ctrl+F5, which runs without debugging in VS Code.
#### Macros
The third row is dedicated to useful macros for programming. The first key inserts a TODO comment.
The second inserts a formatedd docstring with spots to insert a function description, info on parameters, and info on returns.
The last key copies the current line, pastes it on a new line below, and comments the original. This is useful for testing alternative parameters, without deleting the original.
These are all setup to use python formatting, and the last one uses VS Code shortcuts.
#### Terminal shortcut
The first key on the fourth row is routed to Ctrl+ `. In VS Code, this switches between the code editor and the terminal.
#### Blank Keys
The last two keys currently have no function. Functions will likely be added in the future. For now, they serve as keys to fidget with while thinking.
## Challenges
This was my first time using both KiCad and 3d design software, meaning I had to learn the ins and outs of the software. I also attempted to use FreeCad on a pi 4, which in hindsight wasn't the best of ideas. It led to long loading times, slow software, and many crashes. It wasn't too bad, as these problems were minimized for most of the design process, and mostly caused problems when the PCB was loaded into the software.
## BOM
- 12x Cherry MX Switches
- 12x DSA Keycaps(assorment of colors prefered)
- 12x SK6812 MINI-E LEDs
- 12x Through hole 1N4148 Diodes
- 1x EC11 Roatary Encoder
- 1x Seeed XIAO RP2040
- 4x M3 screws
- 4x M3 heatset inserets
- 1x 3d printed case(2 parts)