1 /* 2 Copyright (C) 2014 Paul Boddie 3 4 This program is free software; you can redistribute it and/or modify it under 5 the terms of the GNU General Public License as published by the Free Software 6 Foundation; either version 3 of the License, or (at your option) any later 7 version. 8 9 This program is distributed in the hope that it will be useful, but WITHOUT 10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12 more details. 13 14 You should have received a copy of the GNU General Public License along with 15 this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 module cartridge() 19 { 20 $fn = 50; 21 22 /* Configure the generated shapes. */ 23 24 BACK_CAVITY = 1; 25 FRONT_LABEL_INSET = 1; 26 TOP_LABEL_INSET = 1; 27 GROOVE = 1; 28 29 /* 30 Options for checking. Some useful combinations... 31 32 Check feature alignment: APART = 0; BACK_SURFACE = 0; FRONT_SURFACE = 0; 33 Check PCB alignment: PCB = 1; BACK_SURFACE = 0; 34 */ 35 36 BACK = 1; BACK_SURFACE = 1; 37 FRONT = 1; FRONT_SURFACE = 1; 38 39 /* For printing: APART = 1; PCB = 0; */ 40 41 APART = 1; 42 PCB = 0; 43 44 /* 45 Rounding/fillet radius and additional margin of subtracted 46 material. The additional margin helps avoid geometry problems. 47 */ 48 49 rr = 2; 50 ro = rr; 51 extra = 0.1; 52 53 module fillet(r, h) { 54 translate([0, 0, -h/2]) 55 difference() { 56 cube([r + extra, r + extra, h + extra]); 57 cylinder(r = r, h = h); 58 } 59 } 60 61 /* 62 Justify an object of the given dimensions, according to the given 63 factors (where 1 indicates moving the object to the positive side of an 64 axis, and -1 indicates moving it to the negative side of an axis). 65 66 NOTE: child should eventually be replaced by children. 67 */ 68 module justify(width, depth, height, wdir, ddir, hdir) { 69 translate([ 70 wdir * width / 2, 71 ddir * depth / 2, 72 hdir * height / 2]) 73 child(); 74 } 75 76 /* 77 Make a cuboid of the given dimensions, justifying it according to the given 78 factors, and moving it to the specified coordinates. 79 80 NOTE: Usage of justify within this module will not work due to recursion 81 NOTE: limitations in openscad, potentially removed in more recent 82 NOTE: releases. Thus, the justify transform is merged in here. 83 */ 84 module cube_at(width, depth, height, wdir, ddir, hdir, x, y, z) { 85 translate([ 86 x + wdir * width / 2, 87 y + ddir * depth / 2, 88 z + hdir * height / 2]) 89 cube([width, depth, height], center = true); 90 } 91 92 /* Internal dimensions. */ 93 94 int_width = 86.0; 95 int_depth = 11.0; 96 int_payload_height = 50.8; /* space between the top and the floor */ 97 int_connector_height = 13.5; /* vertical offset of bottom/floor of payload area */ 98 99 /* Side thicknesses. */ 100 101 front = 2; 102 back = 3.5; 103 top = 3; 104 side = 2; /* increased from 1.5 for 3D printing reliability */ 105 bottom = 1; /* thickness of floor of payload area */ 106 107 /* How much extra depth the back provides for mating with the front. */ 108 109 groove_width_extra = 1.0; 110 front_back_overlap = 1.0; 111 groove_width_overlap = front_back_overlap + groove_width_extra; 112 113 /* Division of pieces into front and back, defining the extents. */ 114 115 int_front_depth = 4.5; 116 front_depth = int_front_depth + front; 117 int_back_depth = int_depth - int_front_depth + front_back_overlap; 118 back_depth = int_back_depth + back; 119 120 /* Cartridge dimensions. */ 121 122 width = int_width + side + side; 123 height = top + int_payload_height + bottom + int_connector_height; 124 depth = int_depth + front + back; 125 int_payload_upper_extent = height / 2 - top; 126 int_payload_lower_extent = -height / 2 + int_connector_height + bottom; 127 128 /* Cartridge surfaces. */ 129 130 front_side = side; 131 front_left = front_side; 132 front_right = front_side; 133 back_side = side; 134 back_left = back_side; 135 back_right = back_side; 136 137 /* Label details. */ 138 139 front_label_width = 83.0; 140 front_label_height = 46.0; 141 front_label_depth = 1.0; 142 front_label_offset_from_bottom = 19.5; 143 144 top_label_width = front_label_width; 145 top_label_height = 11.5; /* the height as seen from above */ 146 top_label_depth = front_label_depth; 147 top_label_offset_from_front = 2.5; 148 149 /* 150 The groove around the sides and top. This is extended to allow the 151 pieces to fit together, and this extension is generated regardless of 152 whether the visible groove is enabled or not. 153 */ 154 155 groove_width_exposed = GROOVE ? 1.5 : 0; 156 groove_width = groove_width_exposed + groove_width_overlap; 157 groove_depth = 1.0; /* how deep the groove goes into each side */ 158 159 /* Additional cutting to mate the back and front. */ 160 161 top_groove_width = groove_width_overlap; 162 top_groove_depth = 2.0; 163 164 /* 165 Space for the inner edge of the back inside the front. 166 Offsets are measured from the outside surfaces. 167 */ 168 169 inner_top_front_cutout_width = int_width; 170 inner_top_front_cutout_depth = top_groove_width; 171 inner_top_front_cutout_height = top - top_groove_depth; 172 173 inner_side_front_cutout_height = height - top_groove_depth; 174 inner_side_front_cutout_width = front_side - groove_depth; 175 inner_side_front_cutout_depth = groove_width_overlap; 176 177 /* 178 The back cavity is the indented part at the bottom of the back of the 179 cartridge. It appears to be mechanically superfluous, just making the 180 shape of the cartridge look a bit fancier. 181 */ 182 183 back_cavity_width = 68.0; 184 back_cavity_inner_width = 65.0; 185 back_cavity_offset_from_inner_left = 9.0; 186 back_cavity_inner_offset_from_inner_left = 10.5; 187 back_cavity_height = 13.5; 188 back_cavity_inner_height = 12.0; 189 back_cavity_depth = 1.5; 190 191 /* 192 The effect of the cavity on the inside of the case. The most important 193 measurement is the maximum offset since it defines the width of the 194 internal space that should accommodate the plastic guides of the Plus 1 195 socket. 196 */ 197 198 inner_back_slope_depth = 2.5; 199 inner_back_slope_width = inner_back_slope_depth; 200 inner_back_slope_max_offset = 10.5; 201 inner_back_slope_min_offset = inner_back_slope_max_offset - inner_back_slope_width; 202 203 /* The tapering off of the inner back edge. */ 204 205 inner_back_edge_width = 69.0; 206 inner_back_edge_height = 3.0; 207 inner_back_edge_depth = 1.5; 208 209 /* The tapering off of the inner front edge. */ 210 211 inner_front_edge_width = width - front_side * 2; 212 inner_front_edge_height = 3.0; 213 inner_front_edge_depth = 1.5; 214 215 /* 216 The cutouts in the floor of the front of the cartridge that produce a 217 kind of tab that guides the edge connector into place in the back cutout. 218 */ 219 220 edge_connector_cutout_front_offset = 1.0; 221 edge_connector_cutout_front_depth = front_back_overlap; 222 edge_connector_cutout_front_width = 15.0; 223 224 /* 225 The cutout in the floor of the back of the cartridge that accommodates 226 the edge connector. 227 */ 228 229 edge_connector_cutout_back_depth = 3.0; 230 edge_connector_cutout_back_width = 57.5; 231 232 /* 233 Edge connectors are themselves 0.05" or approximately 1.27mm in 234 thickness according to the Acorn Electron Cartridge Interface Specification 235 (Acorn Support Application Group Note 014). 236 */ 237 238 /* Extra internal features. Depths include front and back surfaces. */ 239 240 pcb_back_support_width = 1.2; 241 pcb_back_support_depth = back_depth - 242 edge_connector_cutout_back_depth; 243 pcb_back_support_height = height - int_connector_height - top - bottom; 244 245 pcb_front_support_width = 1.2; 246 pcb_front_support_depth = int_front_depth; 247 pcb_front_support_height = pcb_back_support_height; 248 249 /* 250 Features measured from the Stardot Dual ROM Adaptor cartridge board 251 dimensions diagram. Offsets are from inside the bottom "floor". 252 */ 253 254 pcb_back_support_bump_width = pcb_front_support_width; 255 pcb_back_support_bump_depth = 1.5; 256 pcb_back_support_left_bump_height = 13.2; 257 pcb_back_support_right_bump_height = 10.7; 258 pcb_back_support_left_bump_offset_from_bottom = 15.1; 259 pcb_back_support_right_bump_offset_from_bottom = 17.6; 260 pcb_back_support_top_bump_height = 3.8; 261 262 /* Move the PCB support towards the centre. */ 263 pcb_support_margin = 1.75; 264 pcb_support_offset_from_centre = edge_connector_cutout_back_width / 2 265 - pcb_support_margin; 266 267 pcb_lug_depth = pcb_back_support_depth + 268 pcb_back_support_bump_depth; 269 pcb_lug_inner_radius = 1.0; 270 pcb_lug_outer_radius = 5.5 / 2; 271 pcb_lug_offset_from_bottom = 14.35; 272 pcb_lug_offset_from_inside = 5.55; 273 274 pcb_lug_cross_width = 6.7; 275 pcb_lug_cross_depth = pcb_back_support_depth; 276 pcb_lug_cross_height = 1.4; 277 278 pcb_front_lug_depth = pcb_back_support_bump_depth + 279 pcb_front_support_depth; 280 pcb_front_lug_inner_radius = pcb_lug_outer_radius; 281 pcb_front_lug_outer_radius = pow( 282 pow(pcb_lug_cross_width / 2, 2) + 283 pow(pcb_lug_cross_height / 2, 2), 284 0.5); 285 286 /* Repeated constructs. */ 287 288 module pcb_support(xdir, bump_height, bump_offset) { 289 290 /* 291 Translate the support in the stated direction. 292 Since the support is already justified in the direction, the translation 293 moves the inner edge of the support to alignment with the end of the 294 edge connector cutout and then back by the PCB support margin. 295 */ 296 297 translate([xdir * 298 pcb_support_offset_from_centre, 299 edge_connector_cutout_back_depth, 300 int_payload_lower_extent]) 301 justify(pcb_back_support_width, 302 pcb_back_support_depth, 303 pcb_back_support_height, 304 xdir, 1, 1) 305 union() { 306 307 /* Underlying support strut. */ 308 309 cube([pcb_back_support_width, 310 pcb_back_support_depth, 311 pcb_back_support_height], center = true); 312 313 /* Middle bump. */ 314 315 cube_at(pcb_back_support_bump_width, 316 pcb_back_support_bump_depth, 317 bump_height, 318 0, -1, 1, 319 0, 320 -pcb_back_support_depth / 2, 321 -pcb_back_support_height / 2 + bump_offset); 322 323 /* Top bump. */ 324 325 cube_at(pcb_back_support_bump_width, 326 pcb_back_support_bump_depth, 327 pcb_back_support_top_bump_height, 328 0, -1, 1, 329 0, 330 -pcb_back_support_depth / 2, 331 pcb_back_support_height / 2 - 332 pcb_back_support_top_bump_height); 333 } 334 } 335 336 module pcb_lug(xdir) { 337 translate([xdir * 338 (int_width / 2 - pcb_lug_offset_from_inside), 339 back_depth, 340 int_payload_lower_extent + pcb_lug_offset_from_bottom 341 ]) 342 rotate([90, 0, 0]) 343 difference() { 344 union() { 345 cylinder(h=pcb_lug_depth, r=pcb_lug_outer_radius); 346 cube_at(pcb_lug_cross_width, 347 pcb_lug_cross_height, pcb_lug_cross_depth, 348 0, 0, 1, 349 0, 0, 0); 350 cube_at(pcb_lug_cross_height, 351 pcb_lug_cross_width, pcb_lug_cross_depth, 352 0, 0, 1, 353 0, 0, 0); 354 } 355 cylinder(h=pcb_lug_depth, r=pcb_lug_inner_radius); 356 } 357 } 358 359 module pcb_front_lug(xdir) { 360 translate([xdir * 361 (int_width / 2 - pcb_lug_offset_from_inside), 362 -int_front_depth + pcb_front_lug_depth, 363 int_payload_lower_extent + pcb_lug_offset_from_bottom 364 ]) 365 rotate([90, 0, 0]) 366 difference() { 367 cylinder(h=pcb_front_lug_depth, 368 r=pcb_front_lug_outer_radius); 369 cylinder(h=pcb_front_lug_depth, 370 r=pcb_front_lug_inner_radius); 371 } 372 } 373 374 /* The actual shapes. */ 375 376 front_displacement = APART ? -width * 0.6 : 0; 377 378 if (FRONT) 379 translate([front_displacement, 0, 0]) 380 difference() { 381 382 /* The cartridge surfaces. */ 383 384 union() { 385 386 /* Front portion. */ 387 388 if (FRONT_SURFACE) { 389 cube_at(width, front, height, 390 0, -1, 0, 391 0, -int_front_depth, 0); 392 cube_at(front_left, front_depth, height, 393 -1, -1, 0, 394 -int_width / 2, 0, 0); 395 cube_at(front_right, front_depth, height, 396 1, -1, 0, 397 int_width / 2, 0, 0); 398 cube_at(width, front_depth, top, 399 0, -1, 1, 400 0, 0, int_payload_upper_extent); 401 } 402 403 difference() { 404 405 /* Floor of cartridge. */ 406 407 cube_at(int_width, int_front_depth, bottom, 408 0, -1, 1, 409 0, 0, -height / 2 + int_connector_height); 410 411 /* Left cutout. */ 412 413 cube_at(edge_connector_cutout_front_width, 414 edge_connector_cutout_front_depth, 415 bottom, 416 1, -1, 1, 417 -width / 2 + edge_connector_cutout_front_offset, 418 0, 419 -height / 2 + int_connector_height); 420 421 /* Right cutout. */ 422 423 cube_at(edge_connector_cutout_front_width, 424 edge_connector_cutout_front_depth, 425 bottom, 426 -1, -1, 1, 427 width / 2 - edge_connector_cutout_front_offset, 428 0, 429 -height / 2 + int_connector_height); 430 } 431 432 /* PCB supports. */ 433 434 cube_at(pcb_front_support_width, 435 pcb_front_support_depth, 436 pcb_front_support_height, 437 -1, -1, 1, 438 -pcb_support_offset_from_centre, 439 0, 440 int_payload_lower_extent); 441 442 cube_at(pcb_front_support_width, 443 pcb_front_support_depth, 444 pcb_front_support_height, 445 1, -1, 1, 446 pcb_support_offset_from_centre, 447 0, 448 int_payload_lower_extent); 449 450 /* Circular "lugs" to hold PCBs in place. */ 451 452 pcb_front_lug(-1); 453 pcb_front_lug(1); 454 } 455 456 /* Label insets. */ 457 458 union() { 459 460 /* Front label. */ 461 462 if (FRONT_LABEL_INSET) 463 translate([-front_label_width / 2, -front_depth, 464 front_label_offset_from_bottom - height / 2]) 465 cube([front_label_width, front_label_depth, 466 front_label_height]); 467 468 /* Top label. See also the back piece. */ 469 470 if (TOP_LABEL_INSET) 471 translate([-top_label_width / 2, 472 -front_depth + top_label_offset_from_front, 473 height / 2 - top_label_depth]) 474 cube([top_label_width, top_label_height, 475 top_label_depth]); 476 } 477 478 /* Inner front edge cavity. */ 479 480 translate([inner_front_edge_width / 2, -int_front_depth, -height / 2]) 481 rotate([0, -90, 0]) 482 linear_extrude(height = inner_front_edge_width) 483 polygon([ 484 [-extra, -inner_front_edge_depth], 485 [0, -inner_front_edge_depth], 486 [inner_front_edge_height, 0], 487 [-extra, 0], 488 ]); 489 490 /* Inner top cutout for the top and sides of the back portion. */ 491 492 cube_at(inner_top_front_cutout_width, 493 inner_top_front_cutout_depth, 494 inner_top_front_cutout_height, 495 0, -1, 1, 496 0, 0, int_payload_upper_extent); 497 498 cube_at(inner_side_front_cutout_width, 499 inner_side_front_cutout_depth, 500 inner_side_front_cutout_height, 501 1, -1, 0, 502 int_width / 2, 0, -inner_top_front_cutout_height); 503 504 cube_at(inner_side_front_cutout_width, 505 inner_side_front_cutout_depth, 506 inner_side_front_cutout_height, 507 -1, -1, 0, 508 -int_width / 2, 0, -inner_top_front_cutout_height); 509 510 /* Fillets to round off the edges. */ 511 512 union() { 513 514 /* Top left and right rounding. */ 515 516 translate([-width / 2 + ro, -front_depth / 2, height / 2 - ro]) 517 rotate([0, 0, 180]) 518 rotate([90, 0, 0]) 519 fillet(rr, front_depth); 520 translate([width / 2 - ro, -front_depth / 2, height / 2 - ro]) 521 rotate([90, 0, 0]) 522 fillet(rr, front_depth); 523 524 /* Top front rounding. */ 525 526 translate([0, -front_depth + ro, height / 2 - ro]) 527 rotate([0, 0, 180]) 528 rotate([0, -90, 0]) 529 fillet(rr, width); 530 531 /* Edge rounding. */ 532 533 translate([-width / 2 + ro, -front_depth + ro, 0]) 534 rotate([0, 0, 180]) 535 fillet(rr, height); 536 translate([width / 2 - ro, -front_depth + ro, 0]) 537 rotate([0, 0, 270]) 538 fillet(rr, height); 539 } 540 } 541 542 /* 543 Place the back piece next to the front, with the internals facing out 544 the same way, if APART is defined. 545 */ 546 547 back_displacement = APART ? width * 0.6 : 0; 548 back_rotation = APART ? 180 : 0; 549 550 if (BACK) 551 translate([back_displacement, 0, 0]) 552 rotate([0, 0, back_rotation]) 553 difference() { 554 555 /* The cartridge surfaces. */ 556 557 union() { 558 559 /* Back portion. */ 560 561 if (BACK_SURFACE) { 562 cube_at(width, back, height, 563 0, 1, 0, 564 0, int_back_depth, 0); 565 cube_at(back_left, back_depth + groove_width_extra, height, 566 -1, 1, 0, 567 -int_width / 2, -groove_width_extra, 0); 568 cube_at(back_right, back_depth + groove_width_extra, height, 569 1, 1, 0, 570 int_width / 2, -groove_width_extra, 0); 571 cube_at(width, back_depth + groove_width_extra, top, 572 0, 1, 1, 573 0, -groove_width_extra, int_payload_upper_extent); 574 } 575 576 difference() { 577 578 /* Floor of cartridge. */ 579 580 cube_at(int_width, int_back_depth, bottom, 581 0, 1, 1, 582 0, 0, -height / 2 + int_connector_height); 583 584 /* Edge connector cutout. */ 585 586 cube_at(edge_connector_cutout_back_width, 587 edge_connector_cutout_back_depth, 588 bottom, 589 0, 1, 1, 590 0, 0, -height / 2 + int_connector_height); 591 } 592 593 /* PCB supports. */ 594 595 pcb_support(-1, pcb_back_support_left_bump_height, 596 pcb_back_support_left_bump_offset_from_bottom); 597 pcb_support(1, pcb_back_support_right_bump_height, 598 pcb_back_support_right_bump_offset_from_bottom); 599 600 /* Circular "lugs" to hold PCBs in place. */ 601 602 pcb_lug(-1); 603 pcb_lug(1); 604 } 605 606 /* Label insets. */ 607 608 union() { 609 610 /* Top label. See also the front piece. */ 611 612 if (TOP_LABEL_INSET) 613 translate([-top_label_width / 2, 614 -front_depth + top_label_offset_from_front, 615 height / 2 - top_label_depth]) 616 cube([top_label_width, top_label_height, 617 top_label_depth]); 618 } 619 620 /* Top and side grooves, positioned in the back portion. */ 621 622 union() { 623 624 /* Left groove. */ 625 626 cube_at(groove_depth, groove_width, height, 627 1, 1, 0, 628 -width / 2, -groove_width_extra, 0); 629 630 /* Right groove. */ 631 632 cube_at(groove_depth, groove_width, height, 633 -1, 1, 0, 634 width / 2, -groove_width_extra, 0); 635 636 /* Top grooves. */ 637 638 cube_at(width, groove_width, groove_depth, 639 0, 1, -1, 640 0, -groove_width_extra, height / 2); 641 642 cube_at(width, top_groove_width, top_groove_depth, 643 0, 1, -1, 644 0, -groove_width_extra, height / 2); 645 } 646 647 /* Back cavity. */ 648 649 if (BACK_CAVITY) 650 intersection() { 651 652 /* From the bottom upwards. */ 653 654 translate([0, back_depth, -height / 2]) 655 linear_extrude(height = back_cavity_height) 656 translate([-int_width / 2, 0, 0]) 657 polygon([ 658 [back_cavity_offset_from_inner_left, 0], 659 [back_cavity_inner_offset_from_inner_left, 660 -back_cavity_depth], 661 [back_cavity_inner_offset_from_inner_left + 662 back_cavity_inner_width, 663 -back_cavity_depth], 664 [back_cavity_offset_from_inner_left + 665 back_cavity_width, 0] 666 ]); 667 668 /* From left to right. */ 669 670 translate([back_cavity_width / 2, back_depth, -height / 2]) 671 rotate([0, -90, 0]) 672 linear_extrude(height = back_cavity_width) 673 polygon([ 674 [-extra, -back_cavity_depth], 675 [back_cavity_inner_height, 676 -back_cavity_depth], 677 [back_cavity_height, 0], 678 [-extra, 0] 679 ]); 680 } 681 682 /* Inner back cavities. */ 683 684 translate([0, int_back_depth, -height / 2]) 685 linear_extrude(height = int_connector_height) 686 translate([-int_width / 2, 0, 0]) 687 polygon([ 688 [0, 0], 689 [inner_back_slope_max_offset, 0], 690 [inner_back_slope_min_offset, 691 inner_back_slope_depth], 692 [0, inner_back_slope_depth] 693 ]); 694 695 translate([0, int_back_depth, -height / 2]) 696 linear_extrude(height = int_connector_height) 697 translate([int_width / 2, 0, 0]) 698 polygon([ 699 [0, 0], 700 [-inner_back_slope_max_offset, 0], 701 [-inner_back_slope_min_offset, 702 inner_back_slope_depth], 703 [0, inner_back_slope_depth] 704 ]); 705 706 /* Inner back edge cavity. */ 707 708 translate([inner_back_edge_width / 2, 709 int_back_depth + inner_back_edge_depth, -height / 2]) 710 rotate([0, -90, 0]) 711 linear_extrude(height = inner_back_edge_width) 712 polygon([ 713 [-extra, -inner_back_edge_depth], 714 [inner_back_edge_height, -inner_back_edge_depth], 715 [0, 0], 716 [-extra, 0] 717 ]); 718 719 /* Fillets to round off the edges. */ 720 721 union() { 722 723 /* Top left and right rounding. */ 724 725 translate([-width / 2 + ro, back_depth / 2, height / 2 - ro]) 726 rotate([0, 0, 180]) 727 rotate([90, 0, 0]) 728 fillet(rr, back_depth); 729 translate([width / 2 - ro, back_depth / 2, height / 2 - ro]) 730 rotate([90, 0, 0]) 731 fillet(rr, back_depth); 732 733 /* Top back rounding. */ 734 735 translate([0, back_depth - ro, height / 2 - ro]) 736 rotate([0, -90, 0]) 737 fillet(rr, width); 738 739 /* Edge rounding. */ 740 741 translate([width / 2 - ro, back_depth - ro, 0]) 742 fillet(rr, height); 743 translate([-width / 2 + ro, back_depth - ro, 0]) 744 rotate([0, 0, 90]) 745 fillet(rr, height); 746 } 747 } 748 749 /* PCB for checking. */ 750 751 pcb_width = 84.85; pcb_height = 62.5; pcb_depth = 1; 752 edge_connector_width = 56.5; edge_connector_height = 11.85; 753 pcb_position_y = int_payload_lower_extent; 754 755 pcb_left_hole_offset = pcb_back_support_left_bump_offset_from_bottom 756 + 0.55; 757 pcb_left_hole_width = 2.2; 758 pcb_left_hole_height = pcb_back_support_left_bump_height - 0.55 * 2; 759 pcb_left_hole_offset_from_centre = pcb_support_offset_from_centre + 760 pcb_back_support_width / 2 - pcb_left_hole_width / 2; 761 762 pcb_right_hole_offset = pcb_back_support_right_bump_offset_from_bottom 763 + 0.55; 764 pcb_right_hole_width = pcb_left_hole_width; 765 pcb_right_hole_height = pcb_back_support_right_bump_height - 0.55 * 2; 766 pcb_right_hole_offset_from_centre = -pcb_left_hole_offset_from_centre; 767 768 pcb_hole_depth = pcb_depth + 0.2; 769 pcb_hole_start_depth = -0.1; 770 pcb_lug_hole_radius = 3.75; 771 772 if (PCB) 773 translate([back_displacement, 0, 0]) 774 translate([0, 0, pcb_position_y]) 775 difference() { 776 777 /* Mock PCB. */ 778 779 union() { 780 cube_at(pcb_width, pcb_depth, 781 pcb_height - edge_connector_height, 782 0, 1, 1, 783 0, 0, 0); 784 cube_at(edge_connector_width, pcb_depth, 785 edge_connector_height, 786 0, 1, -1, 787 0, 0, 0); 788 } 789 790 /* Holes for mounting. */ 791 792 union() { 793 cube_at(pcb_left_hole_width, 1, pcb_left_hole_height, 794 1, 1, 1, 795 pcb_left_hole_offset_from_centre, 0, pcb_left_hole_offset); 796 translate([pcb_left_hole_offset_from_centre + 797 pcb_left_hole_width / 2, pcb_hole_start_depth, pcb_left_hole_offset]) 798 rotate([-90, 0, 0]) 799 cylinder(h=pcb_hole_depth, r=pcb_left_hole_width / 2); 800 translate([pcb_left_hole_offset_from_centre + 801 pcb_left_hole_width / 2, pcb_hole_start_depth, 802 pcb_left_hole_offset + pcb_left_hole_height]) 803 rotate([-90, 0, 0]) 804 cylinder(h=pcb_hole_depth, r=pcb_left_hole_width / 2); 805 } 806 807 union() { 808 cube_at(pcb_right_hole_width, 1, pcb_right_hole_height, 809 -1, 1, 1, 810 pcb_right_hole_offset_from_centre, 0, pcb_right_hole_offset); 811 translate([pcb_right_hole_offset_from_centre - 812 pcb_right_hole_width / 2, pcb_hole_start_depth, pcb_right_hole_offset]) 813 rotate([-90, 0, 0]) 814 cylinder(h=pcb_hole_depth, r=pcb_right_hole_width / 2); 815 translate([pcb_right_hole_offset_from_centre - 816 pcb_right_hole_width / 2, pcb_hole_start_depth, 817 pcb_right_hole_offset + pcb_right_hole_height]) 818 rotate([-90, 0, 0]) 819 cylinder(h=pcb_hole_depth, r=pcb_right_hole_width / 2); 820 } 821 822 /* Holes for lugs. */ 823 824 translate([ 825 -int_width / 2 + pcb_lug_offset_from_inside, 826 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 827 rotate([-90, 0, 0]) 828 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 829 830 translate([ 831 int_width / 2 - pcb_lug_offset_from_inside, 832 pcb_hole_start_depth, pcb_lug_offset_from_bottom]) 833 rotate([-90, 0, 0]) 834 cylinder(h=pcb_hole_depth, r=pcb_lug_hole_radius); 835 } 836 } 837 838 cartridge();