1. box_height = 26.75;
  2. box_wall_thickness = 2;
  3. box_board_spacing = 0.25;
  4. box_connector_spacing = 0.25;
  5. //
  6. // Utilities
  7. //
  8. module mirror_copy(v = [1, 0, 0]) {
  9. children();
  10. mirror(v) children();
  11. }
  12. //
  13. // Board
  14. //
  15. board_thickness = 1.60;
  16. board_size = [57.0, 40.6];
  17. board_hole_dia = 3;
  18. board_hole_spacing = [52.5, 36.5];
  19. led_hole_dia = 3.0;
  20. led_standoff = 1.5;
  21. led_hole_chamfer_dia = led_hole_dia + 2.0;
  22. led_wall_thickness = box_wall_thickness / 2;
  23. led_positions = [
  24. [-board_size[0] / 2 + 20.5, 11.75],
  25. [-board_size[0] / 2 + 20.5, -11.75],
  26. [-board_size[0] / 2 + 4.5, -board_size[1] / 2 + 6.0]
  27. ];
  28. module led() {
  29. color([1, 1, 0]) linear_extrude(0.70) square([3.0, 1.25], center=true);
  30. }
  31. module board() {
  32. color([0.8, 0, 0]) translate([0, 0, -board_thickness]) linear_extrude(board_thickness) {
  33. difference() {
  34. square(board_size, center=true);
  35. mirror_copy([1, 0]) mirror_copy([0, 1])
  36. translate(board_hole_spacing / 2)
  37. circle(d=board_hole_dia, $fn=16);
  38. }
  39. }
  40. }
  41. relay_size = [18.8, 15.0, 15.5];
  42. relay_position = [board_size[0] / 2 - relay_size[0] / 2 - 8.5, relay_size[1] / 2 + 1.0];
  43. module relay() {
  44. color([0.2, 0.4, 0.9])
  45. translate([-relay_size[0]/2, -relay_size[1]/2, 0])
  46. cube(relay_size);
  47. }
  48. usb_connector_size = [16.5, 12.3, 11.0];
  49. usb_connector_overhang = 6.0;
  50. usb_connector_position = [-board_size[0] / 2 + usb_connector_size[0] / 2 - usb_connector_overhang, 0];
  51. module usb_connector() {
  52. color([0.75, 0.75, 0.75])
  53. translate([-usb_connector_size[0]/2, -usb_connector_size[1]/2, 0])
  54. cube(usb_connector_size);
  55. }
  56. terminal_block_size = [7.5, 15];
  57. terminal_block_height = 10.0;
  58. terminal_block_spacing = 1.5;
  59. terminal_block_total_width = terminal_block_size[1] * 2 + terminal_block_spacing;
  60. terminal_block_position = [board_size[0] / 2 - terminal_block_size[0] / 2,
  61. -terminal_block_size[1] / 2 - terminal_block_spacing / 2];
  62. module terminal_block() {
  63. color([0.3, 0.8, 0.2])
  64. translate(-terminal_block_size/2) rotate([0, -90, -90]) linear_extrude(15.0)
  65. polygon([[0, 0], [7.0, 0], [10.0, 2.0], [10.0, 6.5], [7.0, 7.5], [0.0, 7.5]]);
  66. }
  67. module board_assembly() {
  68. board();
  69. mirror_copy([0, 1, 0]) translate(relay_position) relay();
  70. translate(usb_connector_position) usb_connector();
  71. mirror_copy([0, 1, 0]) translate(terminal_block_position) terminal_block();
  72. for (p=led_positions) translate(p) led();
  73. }
  74. //
  75. // Common
  76. //
  77. box_hole_dia = 3.2;
  78. screw_head_dia = 5.7;
  79. screw_head_height = 1.8;
  80. box_inside_width = board_size[1] + box_board_spacing * 2;
  81. module box_inside() {
  82. translate([-board_size[0] / 2 - usb_connector_overhang + box_wall_thickness,
  83. -box_inside_width / 2])
  84. square([board_size[0] + usb_connector_overhang - box_wall_thickness + box_board_spacing,
  85. box_inside_width]);
  86. }
  87. terminal_block_cutout_width = terminal_block_total_width + box_connector_spacing * 2;
  88. terminal_block_cotout_start = terminal_block_position[0] - terminal_block_size[0] / 2 + 2;
  89. module connector_cutouts() {
  90. translate([0, 0, -box_connector_spacing])
  91. linear_extrude(usb_connector_size[2] + box_connector_spacing * 2)
  92. translate([-100, -usb_connector_size[1]/2 - box_connector_spacing])
  93. square([100, usb_connector_size[1] + box_connector_spacing * 2]);
  94. translate([terminal_block_cotout_start, 0, -box_connector_spacing])
  95. linear_extrude(100)
  96. translate([0, -terminal_block_cutout_width/2])
  97. square([100, terminal_block_cutout_width]);
  98. }
  99. module back_pillars() {
  100. mirror([1, 0]) mirror_copy([0, 1])
  101. translate(board_hole_spacing / 2)
  102. children();
  103. }
  104. module pillars() {
  105. mirror_copy([1, 0]) back_pillars() children();
  106. }
  107. //
  108. // Bottom
  109. //
  110. bottom_height = 7.0;
  111. box_lip_height = 2.0;
  112. box_lip_offset = 0.1;
  113. box_base_thickness = 3.0;
  114. bottom_pillar_width = box_inside_width - board_hole_spacing[1];
  115. nut_dia = 5.6 / cos(30);
  116. nut_thickness = 2.5;
  117. module bottom() {
  118. render() difference() {
  119. union() {
  120. difference() {
  121. translate([0, 0, -bottom_height])
  122. linear_extrude(bottom_height + box_lip_height)
  123. offset(box_wall_thickness, $fn=32)
  124. box_inside();
  125. linear_extrude(100)
  126. offset(box_wall_thickness / 2 + box_lip_offset, $fn=16)
  127. box_inside();
  128. translate([0, 0, -bottom_height + box_base_thickness])
  129. linear_extrude(100)
  130. box_inside();
  131. }
  132. translate([0, 0, -bottom_height]) linear_extrude(bottom_height - board_thickness)
  133. pillars() offset(box_wall_thickness / 2, $fn=32)
  134. square([bottom_pillar_width, bottom_pillar_width], center=true);
  135. }
  136. connector_cutouts();
  137. translate([0, 0, -100]) linear_extrude(100) pillars() circle(d=box_hole_dia, $fn=32);
  138. translate([0, 0, -bottom_height]) linear_extrude(nut_thickness) pillars() circle(d=nut_dia, $fn=6);
  139. }
  140. }
  141. //
  142. // Top
  143. //
  144. text_spacing = 5;
  145. text_depth = 0.5;
  146. text_height = 2.5;
  147. text_label_offset = 10;
  148. module relay_label(label) {
  149. rotate([0, 0, 180]) union() {
  150. translate([text_label_offset, 0, 0]) text(label, text_height * 2, font="Arial", valign="center");
  151. translate([0, -text_spacing, 0]) text("NC", text_height, font="Arial", valign="center");
  152. text("COM", text_height, font="Arial", valign="center");
  153. translate([0, text_spacing, 0]) text("NO", text_height, font="Arial", valign="center");
  154. }
  155. }
  156. module labels() {
  157. translate([terminal_block_cotout_start - 2.0, terminal_block_position[1]]) relay_label("1");
  158. translate([terminal_block_cotout_start - 2.0, -terminal_block_position[1]]) relay_label("2");
  159. }
  160. top_height = box_height - bottom_height;
  161. top_pillar_width = box_hole_dia;
  162. module top() {
  163. render() difference() {
  164. union() {
  165. difference() {
  166. minkowski($fn=32) {
  167. linear_extrude(top_height - box_wall_thickness) box_inside();
  168. sphere(box_wall_thickness);
  169. }
  170. linear_extrude(top_height - box_wall_thickness) box_inside();
  171. connector_cutouts();
  172. translate([-50, -50, -100]) cube([100, 100, 100]);
  173. }
  174. mirror_copy([0, 1, 0])
  175. translate([terminal_block_cotout_start - 2.0, terminal_block_cutout_width / 2, 0])
  176. linear_extrude(top_height - box_wall_thickness)
  177. square([
  178. board_size[0] / 2 + box_board_spacing + box_wall_thickness - terminal_block_cotout_start,
  179. (box_inside_width - terminal_block_cutout_width) / 2]);
  180. linear_extrude(top_height - box_wall_thickness)
  181. back_pillars() offset(box_wall_thickness / 2, $fn=32)
  182. translate([-top_pillar_width/2, -top_pillar_width/2])
  183. square([top_pillar_width, top_pillar_width/2 + (box_inside_width - board_hole_spacing[1]) / 2]);
  184. translate([terminal_block_cotout_start, box_inside_width / 2, 0])
  185. rotate([90, 0, 0]) linear_extrude(box_inside_width)
  186. polygon([
  187. [-2.0, terminal_block_height + box_connector_spacing - 3.0],
  188. [-2.0, top_height],
  189. [0.0, top_height],
  190. [0.0, terminal_block_height + box_connector_spacing]]);
  191. for (p=led_positions) {
  192. translate([0, 0, led_standoff])
  193. translate(p) linear_extrude(top_height - led_standoff - box_wall_thickness)
  194. circle(d=led_hole_dia + led_wall_thickness * 2, $fn=32);
  195. }
  196. }
  197. linear_extrude(100) pillars() circle(d=box_hole_dia, $fn=32);
  198. translate([0, 0, top_height - screw_head_height])
  199. linear_extrude(100) pillars() circle(d=screw_head_dia, $fn=32);
  200. difference() {
  201. linear_extrude(box_lip_height) offset(100, $fn=4) box_inside();
  202. linear_extrude(100) offset(box_wall_thickness / 2 + box_lip_offset, $fn=32)
  203. box_inside();
  204. }
  205. translate([0, 0, top_height - text_depth]) linear_extrude(100) labels();
  206. for (p=led_positions) {
  207. translate(p) linear_extrude(100) circle(d=led_hole_dia, $fn=16);
  208. translate([0, 0, top_height - led_hole_chamfer_dia/2])
  209. translate(p) cylinder(h=led_hole_chamfer_dia/2, r1=0, r2=led_hole_chamfer_dia/2, $fn=32);
  210. }
  211. }
  212. }
  213. board_assembly();
  214. bottom();
  215. top();