Commit | Line | Data |
---|---|---|
ee49ff3d CE |
1 | // arcade controller thing |
2 | // Copyright (c) 2017 Clinton Ebadi <clinton@unknownlamer.org> | |
3 | // GPLv3 or (at your option) any later version | |
4 | // .. insert license text here ... | |
5 | ||
9571d749 CE |
6 | // todo: |
7 | // - hinge | |
8 | // - screw holes + captive nut to mount | |
9 | // - internal mount for mcu and battery | |
10 | // - hole for usb panel mount | |
11 | // - bevel lid | |
12 | ||
13 | // maybe/wishlist: | |
14 | // - wire routing clips on panel? | |
15 | // - buttons on side for pinball? | |
16 | // - vent under mcu/battery? | |
17 | // - slant panel toward player? | |
18 | ||
19 | // bugs: | |
20 | // - hinge is not aligned -- either male arm length or connector placement is wrong | |
21 | ||
ee49ff3d | 22 | use <obiscad/bcube.scad> |
ccdc6bcd | 23 | use <obiscad/bevel.scad> |
c3a57278 | 24 | use <obiscad/attach.scad> |
7db674d2 CE |
25 | use <joints.scad> |
26 | ||
c3a57278 | 27 | // PREVIEW |
7db674d2 | 28 | preview(); |
9571d749 | 29 | |
7db674d2 | 30 | module preview () { |
f6620219 | 31 | rotate ([-10, 0, 0]) translate ([0, 0, box_depth+20]) panel (); |
c3a57278 | 32 | case (); |
f6620219 | 33 | for (i = [2 ,4]) translate ([panel_width+hinge_joint_width*i, 0, 0]) hinge_male (); |
c3a57278 | 34 | |
9571d749 | 35 | } |
c3a57278 CE |
36 | |
37 | // CONFIGURATION | |
38 | ||
f6620219 CE |
39 | panel_width = 250; |
40 | panel_height = 130; | |
ccdc6bcd | 41 | panel_bevel = 2; // fixme: calculate based on box_base_thickness? |
c3a57278 | 42 | |
f6620219 | 43 | box_depth = 80; |
c3a57278 | 44 | box_wall = 2; |
f6620219 | 45 | box_base_thickness = 5; |
c3a57278 | 46 | |
9571d749 | 47 | $button_d = 30; // I think this should be special |
ee49ff3d | 48 | |
f6620219 CE |
49 | joystick_width = 85; |
50 | joystick_height = 40; | |
c3a57278 | 51 | |
ccdc6bcd CE |
52 | hinge_arm_width = 6; |
53 | hinge_arm_thickness = 6; | |
9571d749 CE |
54 | hinge_arm_length = 50; |
55 | ||
ccdc6bcd CE |
56 | // size of block to cut female connector from |
57 | hinge_base_size = [hinge_arm_width * 2, hinge_arm_thickness * 2, hinge_arm_thickness * 2]; | |
58 | ||
59 | hinge_x_offset = 15; // distance from side of case | |
60 | ||
9571d749 CE |
61 | |
62 | // gunk that should be elsewhere... | |
63 | // bcube parameters, clean up | |
64 | cr = box_wall*2; | |
65 | cres = 0; | |
7db674d2 | 66 | |
ccdc6bcd CE |
67 | // switch to hide panel in previews |
68 | _hide_panel = false; | |
69 | ||
c3a57278 | 70 | // PANEL COMPONENTS |
ee49ff3d CE |
71 | |
72 | module button (bezel = $button_d+4) { | |
73 | circle (d=$button_d); | |
74 | %circle(d=bezel); | |
75 | } | |
76 | ||
ee49ff3d CE |
77 | module joystick () { |
78 | bolt_d = 8; | |
79 | center_hole_d = 24; | |
80 | ||
f6620219 | 81 | for (x = [-joystick_width/2, joystick_width/2], y = [-joystick_height/2, joystick_height/2]) { |
ee49ff3d CE |
82 | translate ([x, y, 0]) circle (d=bolt_d); // need slot instead |
83 | } | |
c3a57278 | 84 | circle (d=center_hole_d); |
f6620219 | 85 | %square ([joystick_width, joystick_height], center=true); // not right... |
ee49ff3d CE |
86 | } |
87 | ||
ee49ff3d | 88 | |
c3a57278 | 89 | // CASE |
ee49ff3d | 90 | |
ccdc6bcd CE |
91 | module case_base (width=panel_width, height=panel_height, d=box_base_thickness) { |
92 | bcube([width, height, d], cr, cres); | |
ee49ff3d CE |
93 | } |
94 | ||
c3a57278 | 95 | module case_walls () { |
9571d749 CE |
96 | difference () { |
97 | union () { | |
98 | difference() { | |
f6620219 | 99 | bcube([panel_width, panel_height, box_depth-box_base_thickness], cr, cres); |
ccdc6bcd | 100 | bcube([panel_width-box_wall*2, panel_height-box_wall*2, box_depth+1], cr, cres); // FIXME: does this accidentally cut some of the bottom out? |
9571d749 | 101 | } |
ccdc6bcd CE |
102 | attach (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_base (support=true); |
103 | attach (case_connector_wall ([-panel_width/2+hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_base (support=true); | |
9571d749 | 104 | } |
ccdc6bcd CE |
105 | attach (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_cut (); |
106 | attach (case_connector_wall ([-panel_width/2+hinge_x_offset, -box_wall+0.01, box_depth/2]), hinge_connector_back (h=hinge_base_size[2]+(hinge_arm_thickness+panel_bevel)/2)) hinge_female_cut (); | |
ee49ff3d | 107 | } |
ccdc6bcd | 108 | %connector (case_connector_wall ([panel_width/2-hinge_x_offset, -box_wall+0.01, box_depth/2])); |
ee49ff3d CE |
109 | } |
110 | ||
c3a57278 CE |
111 | module case () { |
112 | case_base (); | |
f6620219 | 113 | translate ([0, 0, box_depth/2]) case_walls (); |
7db674d2 CE |
114 | } |
115 | ||
116 | ||
117 | // todo: | |
9571d749 CE |
118 | // specify which wall (rear, front, left, right). vector addition may help... |
119 | // offset from center of wall, as vector (and use vector subtraction!) | |
7db674d2 | 120 | // optional: inside/outside |
ccdc6bcd CE |
121 | CASE_WALL_BACK = [0, panel_height/2, -box_base_thickness/2]; |
122 | ||
123 | function case_connector_wall (offset=[0,0,0], wall=CASE_WALL_BACK) = [ wall + offset, [0, -1, 0], 0 ]; | |
7db674d2 CE |
124 | |
125 | // HINGE | |
126 | ||
9571d749 | 127 | // hinge todo: |
ccdc6bcd | 128 | // allow override of global base dimensions |
9571d749 | 129 | |
ccdc6bcd CE |
130 | // maybe: add connector for pin to socket so that can easily be test |
131 | // fit in software for a nicer preview | |
9571d749 | 132 | |
ccdc6bcd CE |
133 | function hinge_connector_back (th=hinge_arm_thickness*2, h=hinge_base_size[2]) = [ [0, th/2, h/2], [0,1, 0], 0 ]; |
134 | function hinge_connector_bottom (th=hinge_arm_thickness*2, h=hinge_base_size[2]) = [ [0, 0, -h/2], [0, 0, 1], 0 ]; | |
7db674d2 | 135 | |
9571d749 | 136 | // todo: |
ccdc6bcd CE |
137 | // gusset support underneath (with argument to toggle) |
138 | ||
139 | module hinge_female_base (support=false) { | |
140 | // %connector (hinge_connector_back ()); | |
141 | // %connector (hinge_connector_bottom ()); | |
142 | color ([0.5,0.3,0.1, 0.3]) cube (hinge_base_size, center=true); | |
143 | ||
144 | if (support) { | |
145 | corner = [ [ 0, hinge_base_size[1]/2, -hinge_base_size[2]/2], [ 0, -1, -1 ], 0]; | |
146 | base_a = [ [0, hinge_base_size[1]/2, -hinge_base_size[2]/2], [1, 0, 0], 0]; | |
147 | connector (corner); | |
148 | connector (base_a); | |
149 | // fixme: calculate actual radius | |
150 | color ([0.5,0.7,0.1, 0.3]) bconcave_corner_attach(base_a, corner , l=hinge_base_size[1], cr=hinge_base_size[0],cres=0, ext_corner=false, th=0); | |
151 | } | |
9571d749 CE |
152 | } |
153 | ||
154 | module hinge_female_cut () { | |
ccdc6bcd CE |
155 | joint_male_negative (male_joint_width=hinge_arm_width, |
156 | male_joint_thickness=hinge_arm_thickness, | |
157 | forward_rom=90, | |
158 | backward_rom=90, | |
159 | male_joint_height=hinge_arm_length); | |
9571d749 | 160 | } |
7db674d2 | 161 | |
ccdc6bcd | 162 | module hinge_female (support=false) { |
7db674d2 | 163 | difference () { |
ccdc6bcd | 164 | hinge_female_base (support); |
9571d749 | 165 | hinge_female_cut (); |
7db674d2 | 166 | } |
ee49ff3d CE |
167 | } |
168 | ||
9571d749 CE |
169 | module hinge_male () { |
170 | for (i=[0,1]) mirror ([0, i, 0]) translate ([0, -hinge_arm_length/4, 0]) | |
ccdc6bcd CE |
171 | joint_male (male_joint_width=hinge_arm_width, |
172 | male_joint_thickness=hinge_arm_thickness, | |
173 | male_joint_height=hinge_arm_length/2, | |
174 | side=true); | |
9571d749 CE |
175 | } |
176 | ||
177 | ||
c3a57278 | 178 | // PANEL |
ee49ff3d | 179 | |
ccdc6bcd CE |
180 | // fixme: when attachment axis is [0, 0, -1] something makes the math |
181 | // go funky and the connector is facing upward, adding very slight y | |
182 | // misalignment "fixes" it... | |
183 | PANEL_BOTTOM = [ [ 0, 0, -box_base_thickness/2+0.01 ], [ 0, 0.000000000001, -1 ] ]; | |
184 | PANEL_TOP = [ [ 0, 0, box_base_thickness/2-0.01 ], [ 0, 0, 1 ] ]; | |
9571d749 | 185 | |
ccdc6bcd | 186 | function panel_connector (offset=[0,0,0], wall=PANEL_BOTTOM) = [ wall[0]+offset, wall[1], 0 ]; |
9571d749 | 187 | |
ee49ff3d CE |
188 | module panel () { |
189 | difference () { | |
ccdc6bcd CE |
190 | union () { |
191 | // bevel | |
192 | translate ([0, 0, panel_bevel/2]) { | |
193 | case_base (d=box_base_thickness-panel_bevel); | |
194 | } | |
195 | case_base (width=panel_width-box_wall*2-0.1, height=panel_height-box_wall*2-0.1); | |
196 | } | |
197 | if (!_hide_panel) { | |
198 | linear_extrude (box_base_thickness*2,center=true) panel_layout (); | |
199 | } | |
ee49ff3d | 200 | } |
ccdc6bcd CE |
201 | |
202 | attach (panel_connector (offset=[panel_width/2-hinge_x_offset, panel_height/2-hinge_arm_length, 0]), | |
203 | hinge_connector_bottom ()) hinge_female (); | |
204 | attach (panel_connector (offset=[-panel_width/2+hinge_x_offset, panel_height/2-hinge_arm_length, 0]), | |
205 | hinge_connector_bottom ()) hinge_female (); | |
ee49ff3d CE |
206 | } |
207 | ||
c3a57278 CE |
208 | module panel_attach (position, angle=0) { |
209 | x = position[0]; | |
210 | y = position[1]; | |
f6620219 | 211 | c1 = [ [x, y, box_base_thickness/2], [0,0,1], angle ]; |
c3a57278 | 212 | a1 = [ [0,0, 0], [0,0,0], 0 ]; |
7db674d2 | 213 | // %connector (c1); // fixme: don't use 2d for layout |
c3a57278 CE |
214 | attach (c1, a1) children (); |
215 | } | |
ee49ff3d | 216 | |
c3a57278 | 217 | // panel layout inspired by the Neo Geo layout |
ee49ff3d | 218 | module panel_layout () { |
f6620219 | 219 | translate ([-panel_width/2 + 40, 0, 0]) { |
c3a57278 CE |
220 | panel_attach ([0, 0], 90) joystick (); |
221 | ||
222 | // p1, coin (floating off in the distance...) | |
9571d749 | 223 | translate ([140, 0, 0]) { |
7db674d2 | 224 | $button_d=16; |
c3a57278 | 225 | for (x = [0, $button_d+10]) { |
7db674d2 | 226 | panel_attach ([x, 42]) button (); |
c3a57278 CE |
227 | } |
228 | } | |
ee49ff3d | 229 | |
c3a57278 | 230 | // a, b, c, d |
7db674d2 CE |
231 | translate ([60, -20, 0]) { |
232 | panel_attach ([0, 0]) button (); | |
c3a57278 | 233 | for (i = [ 1 : 3 ]) { |
7db674d2 | 234 | panel_attach ([i*($button_d+10)-10, $button_d]) button (); |
c3a57278 | 235 | } |
ee49ff3d CE |
236 | } |
237 | } | |
238 | } |