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