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 /* Side thicknesses. */ 82 83 front = 2; 84 back = 3.5; 85 top = 3; 86 front_left = 1; 87 front_right = 1; 88 back_left = 2; 89 back_right = 2; 90 bottom = 2; 91 92 /* Extra internal features. */ 93 94 pcb_back_support_width = 1.0; 95 pcb_back_support_depth = back_depth - 96 edge_connector_cutout_back_depth; 97 pcb_back_support_height = height - bottom_from_base - top - bottom; 98 99 pcb_front_support_width = 1.0; 100 pcb_front_support_depth = front_depth; 101 pcb_front_support_height = pcb_back_support_height; 102 103 /* 104 Features measured from the Stardot Advanced Battery Backed RAM 105 cartridge board dimensional diagram. 106 */ 107 108 pcb_back_support_bump_width = pcb_front_support_width; 109 pcb_back_support_bump_depth = 1.0; 110 pcb_back_support_bump_height = 14.3; 111 pcb_back_support_bump_offset_from_bottom = 26.0; 112 113 translate([0, -20, 0]) 114 difference() { 115 116 /* The cartridge surfaces. */ 117 118 union() { 119 120 /* Front portion. */ 121 122 translate([0, -front_depth + front / 2, 0]) 123 cube([width, front, height], center = true); 124 translate([-width / 2 + front_left / 2, -front_depth / 2, 0]) 125 cube([front_left, front_depth, height], center = true); 126 translate([width / 2 - front_right / 2, -front_depth / 2, 0]) 127 cube([front_right, front_depth, height], center = true); 128 translate([0, -front_depth / 2, height / 2 - top / 2]) 129 cube([width, front_depth, top], center = true); 130 difference() { 131 translate([0, -front_depth / 2, 132 -height / 2 + bottom / 2 + bottom_from_base]) 133 cube([width, front_depth, bottom], center = true); 134 translate([-width / 2 + edge_connector_cutout_front_offset + 135 edge_connector_cutout_front_width / 2, 136 -edge_connector_cutout_front_depth / 2, 137 -height / 2 + bottom / 2 + bottom_from_base]) 138 cube([edge_connector_cutout_front_width, 139 edge_connector_cutout_front_depth, 140 bottom + extra], center = true); 141 translate([width / 2 - edge_connector_cutout_front_offset - 142 edge_connector_cutout_front_width / 2, 143 -edge_connector_cutout_front_depth / 2, 144 -height / 2 + bottom / 2 + bottom_from_base]) 145 cube([edge_connector_cutout_front_width, 146 edge_connector_cutout_front_depth, 147 bottom + extra], center = true); 148 } 149 150 /* PCB supports. */ 151 152 translate([-edge_connector_cutout_back_width / 2 + 153 pcb_front_support_width / 2, 154 -pcb_front_support_depth / 2, 155 -height / 2 + bottom + bottom_from_base + 156 pcb_front_support_height / 2]) 157 cube([pcb_front_support_width, pcb_front_support_depth, 158 pcb_front_support_height], center = true); 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 169 /* Label insets. */ 170 171 union() { 172 173 /* Front label. */ 174 175 translate([-front_label_width / 2, -front_depth, 176 front_label_offset_from_bottom - height / 2]) 177 cube([front_label_width, front_label_depth, 178 front_label_height]); 179 180 /* Top label. */ 181 182 translate([-top_label_width / 2, 183 -front_depth + top_label_offset_from_front, 184 height / 2 - top_label_depth]) 185 cube([top_label_width, top_label_height, 186 top_label_depth]); 187 } 188 189 /* Inner front edge cavity. */ 190 191 translate([inner_front_edge_width / 2, 192 -front_depth + inner_front_edge_offset, -height / 2]) 193 rotate([0, -90, 0]) 194 linear_extrude(height = inner_front_edge_width) 195 polygon([ 196 [-extra, 0], 197 [0, 0], 198 [inner_front_edge_height, inner_front_edge_depth], 199 [-extra, inner_front_edge_depth], 200 ]); 201 202 /* Inner top cutout for the top of the back portion. */ 203 204 translate([0, -inner_top_front_cutout_depth / 2, height / 2 - 205 inner_top_front_cutout_offset - 206 inner_top_front_cutout_depth / 2]) 207 cube([inner_top_front_cutout_width, 208 inner_top_front_cutout_depth, 209 inner_top_front_cutout_depth], center = true); 210 211 /* Fillets to round off the edges. */ 212 213 union() { 214 215 /* Top left and right rounding. */ 216 217 translate([-width / 2 + ro, -front_depth / 2, height / 2 - ro]) 218 rotate([0, 0, 180]) 219 rotate([90, 0, 0]) 220 fillet(rr, front_depth); 221 translate([width / 2 - ro, -front_depth / 2, height / 2 - ro]) 222 rotate([90, 0, 0]) 223 fillet(rr, front_depth); 224 225 /* Top front rounding. */ 226 227 translate([0, -front_depth + ro, height / 2 - ro]) 228 rotate([0, 0, 180]) 229 rotate([0, -90, 0]) 230 fillet(rr, width); 231 232 /* Edge rounding. */ 233 234 translate([-width / 2 + ro, -front_depth + ro, 0]) 235 rotate([0, 0, 180]) 236 fillet(rr, height); 237 translate([width / 2 - ro, -front_depth + ro, 0]) 238 rotate([0, 0, 270]) 239 fillet(rr, height); 240 } 241 } 242 243 difference() { 244 245 /* The cartridge surfaces. */ 246 247 union() { 248 249 /* Back portion. */ 250 251 translate([0, back_depth - back / 2, 0]) 252 cube([width, back, height], center = true); 253 translate([-width / 2 + back_left / 2, back_depth / 2, 0]) 254 cube([back_left, back_depth, height], center = true); 255 translate([width / 2 - back_right / 2, back_depth / 2, 0]) 256 cube([back_right, back_depth, height], center = true); 257 translate([0, back_depth / 2, height / 2 - top / 2]) 258 cube([width, back_depth, top], center = true); 259 difference() { 260 translate([0, back_depth / 2, 261 -height / 2 + bottom / 2 + bottom_from_base]) 262 cube([width, back_depth, bottom], center = true); 263 translate([0, edge_connector_cutout_back_depth / 2, 264 -height / 2 + bottom / 2 + bottom_from_base]) 265 cube([edge_connector_cutout_back_width, 266 edge_connector_cutout_back_depth, 267 bottom + extra], center = true); 268 } 269 270 /* PCB supports. */ 271 272 translate([-edge_connector_cutout_back_width / 2 + 273 pcb_back_support_width / 2, 274 edge_connector_cutout_back_depth + 275 pcb_back_support_depth / 2, 276 -height / 2 + bottom + bottom_from_base + 277 pcb_back_support_height / 2]) 278 union() { 279 cube([pcb_back_support_width, pcb_back_support_depth, 280 pcb_back_support_height], center = true); 281 translate([0, 282 -pcb_back_support_depth / 2 - 283 pcb_back_support_bump_depth / 2, 284 -pcb_back_support_height / 2 + 285 pcb_back_support_bump_offset_from_bottom]) 286 cube([pcb_back_support_bump_width, 287 pcb_back_support_bump_depth, 288 pcb_back_support_bump_height], center = true); 289 } 290 291 translate([edge_connector_cutout_back_width / 2 - 292 pcb_back_support_width / 2, 293 edge_connector_cutout_back_depth + 294 pcb_back_support_depth / 2, 295 -height / 2 + bottom + bottom_from_base + 296 pcb_back_support_height / 2]) 297 union() { 298 cube([pcb_back_support_width, pcb_back_support_depth, 299 pcb_back_support_height], center = true); 300 translate([0, 301 -pcb_back_support_depth / 2 - 302 pcb_back_support_bump_depth / 2, 303 -pcb_back_support_height / 2 + 304 pcb_back_support_bump_offset_from_bottom]) 305 cube([pcb_back_support_bump_width, 306 pcb_back_support_bump_depth, 307 pcb_back_support_bump_height], center = true); 308 } 309 } 310 311 /* Label insets. */ 312 313 union() { 314 315 /* Top label. */ 316 317 translate([-top_label_width / 2, 318 -front_depth + top_label_offset_from_front, 319 height / 2 - top_label_depth]) 320 cube([top_label_width, top_label_height, 321 top_label_depth]); 322 } 323 324 /* Top and side grooves, positioned in the back portion. */ 325 326 union() { 327 328 /* Left groove. */ 329 330 translate([-width / 2 + groove_depth / 2, groove_width / 2, 0]) 331 cube([groove_depth, groove_width, height], 332 center = true); 333 334 /* Right groove. */ 335 336 translate([width / 2 - groove_depth / 2, groove_width / 2, 0]) 337 cube([groove_depth, groove_width, height], 338 center = true); 339 340 /* Top grooves. */ 341 342 translate([0, groove_width / 2, height / 2 - groove_depth / 2]) 343 cube([width, groove_width, groove_depth], 344 center = true); 345 346 translate([0, top_groove_width / 2, 347 height / 2 - top_groove_depth / 2]) 348 cube([width, top_groove_width, top_groove_depth], 349 center = true); 350 } 351 352 /* Back cavity. */ 353 354 intersection() { 355 356 /* From the bottom upwards. */ 357 358 translate([0, back_depth, -height / 2]) 359 linear_extrude(height = back_cavity_height) 360 translate([-width / 2, 0, 0]) 361 polygon([ 362 [back_cavity_offset_from_left, 0], 363 [back_cavity_inner_offset_from_left, 364 -back_cavity_depth], 365 [back_cavity_inner_offset_from_left + 366 back_cavity_inner_width, 367 -back_cavity_depth], 368 [back_cavity_offset_from_left + 369 back_cavity_width, 0] 370 ]); 371 372 /* From left to right. */ 373 374 translate([back_cavity_width / 2, back_depth, -height / 2]) 375 rotate([0, -90, 0]) 376 linear_extrude(height = back_cavity_width) 377 polygon([ 378 [-extra, -back_cavity_depth], 379 [back_cavity_inner_height, 380 -back_cavity_depth], 381 [back_cavity_height, 0], 382 [-extra, 0] 383 ]); 384 } 385 386 /* Inner back cavities. */ 387 388 translate([0, back_depth - inner_back_cavity_offset, -height / 2]) 389 linear_extrude(height = bottom_from_base) 390 translate([-width / 2, 0, 0]) 391 polygon([ 392 [inner_back_cavity_offset_from_left, 0], 393 [inner_back_slope_offset_from_left, 0], 394 [inner_back_slope_offset_from_left + 395 inner_back_slope_width, 396 -inner_back_slope_depth], 397 [inner_back_cavity_offset_from_left, 398 -inner_back_slope_depth] 399 ]); 400 401 translate([0, back_depth - inner_back_cavity_offset, -height / 2]) 402 linear_extrude(height = bottom_from_base) 403 translate([-width / 2, 0, 0]) 404 polygon([ 405 [width - inner_back_slope_offset_from_left, 0], 406 [width - inner_back_cavity_offset_from_left, 0], 407 [width - inner_back_cavity_offset_from_left, 408 -inner_back_slope_depth], 409 [width - inner_back_slope_offset_from_left - 410 inner_back_slope_width, 411 -inner_back_slope_depth] 412 ]); 413 414 /* Inner back edge cavity. */ 415 416 translate([inner_back_edge_width / 2, 417 back_depth - inner_back_edge_offset, -height / 2]) 418 rotate([0, -90, 0]) 419 linear_extrude(height = inner_back_edge_width) 420 polygon([ 421 [-extra, -inner_back_edge_depth], 422 [inner_back_edge_height, -inner_back_edge_depth], 423 [0, 0], 424 [-extra, 0] 425 ]); 426 427 /* Fillets to round off the edges. */ 428 429 union() { 430 431 /* Top left and right rounding. */ 432 433 translate([-width / 2 + ro, back_depth / 2, height / 2 - ro]) 434 rotate([0, 0, 180]) 435 rotate([90, 0, 0]) 436 fillet(rr, back_depth); 437 translate([width / 2 - ro, back_depth / 2, height / 2 - ro]) 438 rotate([90, 0, 0]) 439 fillet(rr, back_depth); 440 441 /* Top back rounding. */ 442 443 translate([0, back_depth - ro, height / 2 - ro]) 444 rotate([0, -90, 0]) 445 fillet(rr, width); 446 447 /* Edge rounding. */ 448 449 translate([width / 2 - ro, back_depth - ro, 0]) 450 fillet(rr, height); 451 translate([-width / 2 + ro, back_depth - ro, 0]) 452 rotate([0, 0, 90]) 453 fillet(rr, height); 454 } 455 } 456 } 457 458 cartridge(); 459