1 module cartridge() 2 { 3 $fn = 50; 4 5 /* Rounding/fillet radius and additional margin of subtracted 6 material. The additional margin helps avoid geometry 7 problems. */ 8 9 rr = 1; 10 ro = rr; 11 extra = 0.1; 12 13 module fillet(r, h) { 14 translate([0, 0, -h/2]) 15 difference() { 16 cube([r + extra, r + extra, h + extra]); 17 cylinder(r = r, h = h); 18 } 19 } 20 21 /* 22 Justify an object of the given dimensions, according to the given 23 factors (where 1 indicates moving the object to the positive side of an 24 axis, and -1 indicates moving it to the negative side of an axis). 25 26 NOTE: child should eventually be replaced by children. 27 */ 28 module justify(width, depth, height, wdir, ddir, hdir) { 29 translate([ 30 wdir * width / 2, 31 ddir * depth / 2, 32 hdir * height / 2]) 33 child(); 34 } 35 36 /* 37 Make a cuboid of the given dimensions, justifying it according to the given 38 factors, and moving it to the specified coordinates. 39 40 NOTE: Usage of justify within this module will not work due to recursion 41 NOTE: limitations in openscad, potentially removed in more recent 42 NOTE: releases. Thus, the justify transform is merged in here. 43 */ 44 module cube_at(width, depth, height, wdir, ddir, hdir, x, y, z) { 45 translate([ 46 x + wdir * width / 2, 47 y + ddir * depth / 2, 48 z + hdir * height / 2]) 49 cube([width, depth, height], center = true); 50 } 51 52 /* Cartridge dimensions. */ 53 54 width = 89.0; 55 height = 68.5; 56 depth = 16.5; 57 front_depth = 6.5; 58 back_depth = 11.0; 59 60 /* Label details. */ 61 62 front_label_width = 83.0; 63 front_label_height = 46.0; 64 front_label_depth = 1.0; 65 front_label_offset_from_bottom = 19.5; 66 67 top_label_width = front_label_width; 68 top_label_height = 11.5; /* the height as seen from above */ 69 top_label_depth = front_label_depth; 70 top_label_offset_from_front = 2.5; 71 72 /* The groove around the sides and top. */ 73 74 groove_width = 2.5; /* how much the groove cuts out of the back */ 75 groove_depth = 1.0; /* how deep the groove goes into each side */ 76 77 /* Additional cutting to mate the back and front. */ 78 79 top_groove_width = 1.0; 80 top_groove_depth = 2.0; 81 82 /* Space for the back inside the front. */ 83 84 inner_top_front_cutout_width = 87.0; 85 inner_top_front_cutout_depth = 1.0; 86 inner_top_front_cutout_offset = 2.0; 87 88 back_cavity_width = 68.0; 89 back_cavity_inner_width = 65.0; 90 back_cavity_offset_from_left = 10.5; 91 back_cavity_inner_offset_from_left = 12.0; 92 back_cavity_height = 13.5; 93 back_cavity_inner_height = 12.0; 94 back_cavity_depth = 1.5; 95 96 inner_back_cavity_offset = 1.0; 97 inner_back_cavity_offset_from_left = 2.0; 98 inner_back_slope_offset_from_left = 10.0; 99 inner_back_slope_width = 2.5; 100 inner_back_slope_depth = 2.5; 101 102 inner_back_edge_offset = 2.0; 103 inner_back_edge_width = 69.0; 104 inner_back_edge_height = 3.0; 105 inner_back_edge_depth = 1.5; 106 107 inner_front_edge_offset = 0.5; 108 inner_front_edge_width = 87.0; 109 inner_front_edge_height = 3.0; 110 inner_front_edge_depth = 1.5; 111 112 bottom_from_base = 13.5; 113 114 edge_connector_cutout_front_offset = 1.0; 115 edge_connector_cutout_front_depth = 1.0; 116 edge_connector_cutout_front_width = 15.0; 117 edge_connector_cutout_back_depth = 3.0; 118 edge_connector_cutout_back_width = 57.0; 119 120 /* 121 Edge connectors are themselves 0.05" or approximately 1.27mm in 122 thickness according to the Acorn Electron Cartridge Interface Specification 123 (Acorn Support Application Group Note 014). 124 */ 125 126 /* Side thicknesses. */ 127 128 front = 2; 129 back = 3.5; 130 top = 3; 131 front_left = 1; 132 front_right = 1; 133 back_left = 2; 134 back_right = 2; 135 bottom = 2; 136 137 /* Extra internal features. */ 138 139 pcb_back_support_width = 1.0; 140 pcb_back_support_depth = back_depth - 141 edge_connector_cutout_back_depth; 142 pcb_back_support_height = height - bottom_from_base - top - bottom; 143 144 pcb_front_support_width = 1.0; 145 pcb_front_support_depth = front_depth; 146 pcb_front_support_height = pcb_back_support_height; 147 148 /* 149 Features measured from the Stardot Advanced Battery Backed RAM 150 cartridge board dimensional diagram. 151 */ 152 153 pcb_back_support_bump_width = pcb_front_support_width; 154 pcb_back_support_bump_depth = 1.5; 155 pcb_back_support_left_bump_height = 14.3; 156 pcb_back_support_right_bump_height = 11.7; 157 pcb_back_support_left_bump_offset_from_bottom = 26.0 - 11.8; 158 pcb_back_support_right_bump_offset_from_bottom = 28.6 - 11.8; 159 160 translate([-width * 0.6, 0, 0]) 161 difference() { 162 163 /* The cartridge surfaces. */ 164 165 union() { 166 167 /* Front portion. */ 168 169 translate([0, -front_depth + front / 2, 0]) 170 cube([width, front, height], center = true); 171 translate([-width / 2 + front_left / 2, -front_depth / 2, 0]) 172 cube([front_left, front_depth, height], center = true); 173 translate([width / 2 - front_right / 2, -front_depth / 2, 0]) 174 cube([front_right, front_depth, height], center = true); 175 translate([0, -front_depth / 2, height / 2 - top / 2]) 176 cube([width, front_depth, top], center = true); 177 difference() { 178 179 /* Floor of cartridge. */ 180 181 cube_at(width, front_depth, bottom, 182 0, -1, 1, 183 0, 0, -height / 2 + bottom_from_base); 184 185 /* Left cutout. */ 186 187 cube_at(edge_connector_cutout_front_width, 188 edge_connector_cutout_front_depth, 189 bottom, 190 1, -1, 1, 191 -width / 2 + edge_connector_cutout_front_offset, 192 0, 193 -height / 2 + bottom_from_base); 194 195 /* Right cutout. */ 196 197 cube_at(edge_connector_cutout_front_width, 198 edge_connector_cutout_front_depth, 199 bottom, 200 -1, -1, 1, 201 width / 2 - edge_connector_cutout_front_offset, 202 0, 203 -height / 2 + bottom_from_base); 204 } 205 206 /* PCB supports. */ 207 208 cube_at(pcb_front_support_width, 209 pcb_front_support_depth, 210 pcb_front_support_height, 211 1, -1, 1, 212 -edge_connector_cutout_back_width / 2, 213 0, 214 -height / 2 + bottom + bottom_from_base); 215 216 cube_at(pcb_front_support_width, 217 pcb_front_support_depth, 218 pcb_front_support_height, 219 -1, -1, 1, 220 edge_connector_cutout_back_width / 2, 221 0, 222 -height / 2 + bottom + bottom_from_base); 223 } 224 225 /* Label insets. */ 226 227 union() { 228 229 /* Front label. */ 230 231 translate([-front_label_width / 2, -front_depth, 232 front_label_offset_from_bottom - height / 2]) 233 cube([front_label_width, front_label_depth, 234 front_label_height]); 235 236 /* Top label. */ 237 238 translate([-top_label_width / 2, 239 -front_depth + top_label_offset_from_front, 240 height / 2 - top_label_depth]) 241 cube([top_label_width, top_label_height, 242 top_label_depth]); 243 } 244 245 /* Inner front edge cavity. */ 246 247 translate([inner_front_edge_width / 2, 248 -front_depth + inner_front_edge_offset, -height / 2]) 249 rotate([0, -90, 0]) 250 linear_extrude(height = inner_front_edge_width) 251 polygon([ 252 [-extra, 0], 253 [0, 0], 254 [inner_front_edge_height, inner_front_edge_depth], 255 [-extra, inner_front_edge_depth], 256 ]); 257 258 /* Inner top cutout for the top of the back portion. */ 259 260 translate([0, -inner_top_front_cutout_depth / 2, height / 2 - 261 inner_top_front_cutout_offset - 262 inner_top_front_cutout_depth / 2]) 263 cube([inner_top_front_cutout_width, 264 inner_top_front_cutout_depth, 265 inner_top_front_cutout_depth], center = true); 266 267 /* Fillets to round off the edges. */ 268 269 union() { 270 271 /* Top left and right rounding. */ 272 273 translate([-width / 2 + ro, -front_depth / 2, height / 2 - ro]) 274 rotate([0, 0, 180]) 275 rotate([90, 0, 0]) 276 fillet(rr, front_depth); 277 translate([width / 2 - ro, -front_depth / 2, height / 2 - ro]) 278 rotate([90, 0, 0]) 279 fillet(rr, front_depth); 280 281 /* Top front rounding. */ 282 283 translate([0, -front_depth + ro, height / 2 - ro]) 284 rotate([0, 0, 180]) 285 rotate([0, -90, 0]) 286 fillet(rr, width); 287 288 /* Edge rounding. */ 289 290 translate([-width / 2 + ro, -front_depth + ro, 0]) 291 rotate([0, 0, 180]) 292 fillet(rr, height); 293 translate([width / 2 - ro, -front_depth + ro, 0]) 294 rotate([0, 0, 270]) 295 fillet(rr, height); 296 } 297 } 298 299 translate([width * 0.6, 0, 0]) 300 rotate([0, 0, 180]) 301 difference() { 302 303 /* The cartridge surfaces. */ 304 305 union() { 306 307 /* Back portion. */ 308 309 translate([0, back_depth - back / 2, 0]) 310 cube([width, back, height], center = true); 311 translate([-width / 2 + back_left / 2, back_depth / 2, 0]) 312 cube([back_left, back_depth, height], center = true); 313 translate([width / 2 - back_right / 2, back_depth / 2, 0]) 314 cube([back_right, back_depth, height], center = true); 315 translate([0, back_depth / 2, height / 2 - top / 2]) 316 cube([width, back_depth, top], center = true); 317 difference() { 318 319 /* Floor of cartridge. */ 320 321 cube_at(width, back_depth, bottom, 322 0, 1, 1, 323 0, 0, -height / 2 + bottom_from_base); 324 325 /* Edge connector cutout. */ 326 327 cube_at(edge_connector_cutout_back_width, 328 edge_connector_cutout_back_depth, 329 bottom, 330 0, 1, 1, 331 0, 0, -height / 2 + bottom_from_base); 332 } 333 334 /* PCB supports. */ 335 336 translate([-edge_connector_cutout_back_width / 2, 337 edge_connector_cutout_back_depth, 338 -height / 2 + bottom + bottom_from_base]) 339 justify(pcb_back_support_width, 340 pcb_back_support_depth, 341 pcb_back_support_height, 342 1, 1, 1) 343 union() { 344 cube([pcb_back_support_width, 345 pcb_back_support_depth, 346 pcb_back_support_height], center = true); 347 cube_at(pcb_back_support_bump_width, 348 pcb_back_support_bump_depth, 349 pcb_back_support_left_bump_height, 350 0, -1, 1, 351 0, 352 -pcb_back_support_depth / 2, 353 -pcb_back_support_height / 2 + 354 pcb_back_support_left_bump_offset_from_bottom); 355 } 356 357 translate([edge_connector_cutout_back_width / 2, 358 edge_connector_cutout_back_depth, 359 -height / 2 + bottom + bottom_from_base]) 360 justify(pcb_back_support_width, 361 pcb_back_support_depth, 362 pcb_back_support_height, 363 -1, 1, 1) 364 union() { 365 cube([pcb_back_support_width, 366 pcb_back_support_depth, 367 pcb_back_support_height], center = true); 368 cube_at(pcb_back_support_bump_width, 369 pcb_back_support_bump_depth, 370 pcb_back_support_right_bump_height, 371 0, -1, 1, 372 0, 373 -pcb_back_support_depth / 2, 374 -pcb_back_support_height / 2 + 375 pcb_back_support_right_bump_offset_from_bottom); 376 } 377 } 378 379 /* Label insets. */ 380 381 union() { 382 383 /* Top label. */ 384 385 translate([-top_label_width / 2, 386 -front_depth + top_label_offset_from_front, 387 height / 2 - top_label_depth]) 388 cube([top_label_width, top_label_height, 389 top_label_depth]); 390 } 391 392 /* Top and side grooves, positioned in the back portion. */ 393 394 union() { 395 396 /* Left groove. */ 397 398 translate([-width / 2 + groove_depth / 2, groove_width / 2, 0]) 399 cube([groove_depth, groove_width, height], 400 center = true); 401 402 /* Right groove. */ 403 404 translate([width / 2 - groove_depth / 2, groove_width / 2, 0]) 405 cube([groove_depth, groove_width, height], 406 center = true); 407 408 /* Top grooves. */ 409 410 translate([0, groove_width / 2, height / 2 - groove_depth / 2]) 411 cube([width, groove_width, groove_depth], 412 center = true); 413 414 translate([0, top_groove_width / 2, 415 height / 2 - top_groove_depth / 2]) 416 cube([width, top_groove_width, top_groove_depth], 417 center = true); 418 } 419 420 /* Back cavity. */ 421 422 intersection() { 423 424 /* From the bottom upwards. */ 425 426 translate([0, back_depth, -height / 2]) 427 linear_extrude(height = back_cavity_height) 428 translate([-width / 2, 0, 0]) 429 polygon([ 430 [back_cavity_offset_from_left, 0], 431 [back_cavity_inner_offset_from_left, 432 -back_cavity_depth], 433 [back_cavity_inner_offset_from_left + 434 back_cavity_inner_width, 435 -back_cavity_depth], 436 [back_cavity_offset_from_left + 437 back_cavity_width, 0] 438 ]); 439 440 /* From left to right. */ 441 442 translate([back_cavity_width / 2, back_depth, -height / 2]) 443 rotate([0, -90, 0]) 444 linear_extrude(height = back_cavity_width) 445 polygon([ 446 [-extra, -back_cavity_depth], 447 [back_cavity_inner_height, 448 -back_cavity_depth], 449 [back_cavity_height, 0], 450 [-extra, 0] 451 ]); 452 } 453 454 /* Inner back cavities. */ 455 456 translate([0, back_depth - inner_back_cavity_offset, -height / 2]) 457 linear_extrude(height = bottom_from_base) 458 translate([-width / 2, 0, 0]) 459 polygon([ 460 [inner_back_cavity_offset_from_left, 0], 461 [inner_back_slope_offset_from_left, 0], 462 [inner_back_slope_offset_from_left + 463 inner_back_slope_width, 464 -inner_back_slope_depth], 465 [inner_back_cavity_offset_from_left, 466 -inner_back_slope_depth] 467 ]); 468 469 translate([0, back_depth - inner_back_cavity_offset, -height / 2]) 470 linear_extrude(height = bottom_from_base) 471 translate([-width / 2, 0, 0]) 472 polygon([ 473 [width - inner_back_slope_offset_from_left, 0], 474 [width - inner_back_cavity_offset_from_left, 0], 475 [width - inner_back_cavity_offset_from_left, 476 -inner_back_slope_depth], 477 [width - inner_back_slope_offset_from_left - 478 inner_back_slope_width, 479 -inner_back_slope_depth] 480 ]); 481 482 /* Inner back edge cavity. */ 483 484 translate([inner_back_edge_width / 2, 485 back_depth - inner_back_edge_offset, -height / 2]) 486 rotate([0, -90, 0]) 487 linear_extrude(height = inner_back_edge_width) 488 polygon([ 489 [-extra, -inner_back_edge_depth], 490 [inner_back_edge_height, -inner_back_edge_depth], 491 [0, 0], 492 [-extra, 0] 493 ]); 494 495 /* Fillets to round off the edges. */ 496 497 union() { 498 499 /* Top left and right rounding. */ 500 501 translate([-width / 2 + ro, back_depth / 2, height / 2 - ro]) 502 rotate([0, 0, 180]) 503 rotate([90, 0, 0]) 504 fillet(rr, back_depth); 505 translate([width / 2 - ro, back_depth / 2, height / 2 - ro]) 506 rotate([90, 0, 0]) 507 fillet(rr, back_depth); 508 509 /* Top back rounding. */ 510 511 translate([0, back_depth - ro, height / 2 - ro]) 512 rotate([0, -90, 0]) 513 fillet(rr, width); 514 515 /* Edge rounding. */ 516 517 translate([width / 2 - ro, back_depth - ro, 0]) 518 fillet(rr, height); 519 translate([-width / 2 + ro, back_depth - ro, 0]) 520 rotate([0, 0, 90]) 521 fillet(rr, height); 522 } 523 } 524 } 525 526 cartridge(); 527