From 561427774a3178cc00936ea86a74fd239739a866 Mon Sep 17 00:00:00 2001 From: Nettika Date: Sun, 5 Oct 2025 03:17:17 +0000 Subject: [PATCH] Improve modularity of cartridge --- cartridge.scad | 346 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 252 insertions(+), 94 deletions(-) diff --git a/cartridge.scad b/cartridge.scad index ba98c78..d19f507 100644 --- a/cartridge.scad +++ b/cartridge.scad @@ -1,123 +1,281 @@ -$fn = $preview ? 32 : 64; +$fn = $preview ? 32 : 128; -*rotate([0, -90, -90]) import("/home/nettika/Downloads/8_Track.STL"); -*translate([0, 98.6, 21.8]) rotate([-90, 0, -90]) import("/home/nettika/Downloads/Track_Lid.STL"); - -cartridge_length = 133; +// Cartridge base dimensions cartridge_width = 102; +cartridge_length = 133; cartridge_height = 21; -wedge_width = 6; -wedge_depth = 16; -track_inset = 6; -foot_inset = 8; + +// Tape guide dimensions +tape_guide_width = 6; +tape_guide_depth = 16; +tape_guide_slope = tape_guide_width / tape_guide_depth; + +// Track dimensions +track_front_inset = 8; +track_back_inset = 4; +track_side_inset = 6; +track_radius = 1; +track_taper_length = 12; + +// Foot dimensions +foot_width = 2.5; +foot_height = 1; +foot_front_inset = 8; +foot_back_inset = 4; +foot_side_inset = 6; + +// Fillets +back_vertical_fillet_radius = 4; +side_vertical_fillet_radius = 16; +front_vertical_fillet_radius = 5; +horizontal_fillets_radius = 1; + +// Windows on front wall +window_vertical_inset = 2; +window_side_inset = 14; +window_depth = 6; // 13 +left_window_width = 20; +right_window_width = 20; +window_gap = 5; +roller_window_depth = 8; +roller_window_offset = 3.5; + +// Emulated gap between top and bottom half gap_height = 1; gap_depth = 0.3; -gap_elevation = 9; +gap_elevation = 14; -module base_body() { - minkowski() { - translate([0, 0, 1]) linear_extrude(cartridge_height - 2) offset(-1) footprint(); - sphere(1); +// Grips +grip_wedge_width = 2.5; +grip_count = 5; + +// Tape +roller_inset = 0; +roller_radius = 0; +roller_position = [12, 79.5]; +tape_line_position = [2, 14]; +tape_height = 6.4; + +// NFC Coin +nfc_coin_depth = 1; +nfc_coin_diameter = 25; +nfc_coin_tolerance = 0.1; + +cartridge(); + +module cartridge() { + difference() { + base(); + windows(); + grips(); + gap(); + undercut(); + nfc_coin(); } - translate([wedge_depth-8, 0, cartridge_height]) { - translate([0, track_inset]) track(cartridge_length-wedge_depth+4); - translate([0, cartridge_width-track_inset]) track(cartridge_length-wedge_depth+4); + tape(); +} + +module base() { + translate([0, 0, horizontal_fillets_radius]) minkowski() { + linear_extrude(cartridge_height - 2 * horizontal_fillets_radius) + offset(-horizontal_fillets_radius) + footprint(); + sphere(horizontal_fillets_radius); } - translate([wedge_depth, foot_inset, -0.5]) foot(); - translate([wedge_depth, cartridge_width-foot_inset, -0.5]) foot(); + tracks(); + feet(); } -module track(l, r=1, taper=12) rotate([0, 90, 0]) { - cylinder(r1=0, r2=r, h=taper); - translate([0, 0, taper]) cylinder(r=r, h=l-2*taper); - translate([0, 0, l-taper]) cylinder(r1=r, r2=0, h=taper); +module windows() { + rectangular_windows(); + roller_window(); } -module foot(w=2.5) { - cube([cartridge_length-wedge_depth-2, w, 2]); - translate([cartridge_length-wedge_depth-2, w, 1]) rotate([90, 90]) cylinder(r=1, h=w); - translate([0, w, 1]) rotate([90, 90]) cylinder(r=1, h=w); +module rectangular_windows() { + translate([ + 0, + window_side_inset, + window_vertical_inset + ]) { + window_height = cartridge_height - 2 * window_vertical_inset; + cube([window_depth, left_window_width, window_height]); + translate([ + 0, + left_window_width + window_gap, + ]) + cube([window_depth, right_window_width, window_height]); + } } -color("salmon") -difference() { - base_body(); - let(inset=2, d=6/*13*/) { - translate([0, 0, inset]) { - translate([0, 14]) cube([d, 20, cartridge_height-inset*2]); - translate([0, 40]) cube([d, 22, cartridge_height-inset*2]); +module roller_window() { + translate([ + -roller_window_depth, + roller_position.y - roller_window_offset, + ]) + cylinder(h=cartridge_height, r=12); +} + +module grips() { + for(i=[0:grip_count-1]) { + translate([cartridge_length - i * grip_wedge_width - back_vertical_fillet_radius, 0]) { + grip_wedge(); + translate([0, cartridge_width]) mirror([0, 1]) grip_wedge(); } } - translate([0, 0, gap_elevation-(gap_height/2)]) - linear_extrude(cartridge_height-gap_elevation+gap_height) { - for(i=[0:2.5:12.5]) { - polygon([ - [cartridge_length-5-i, 0], - [cartridge_length-5-i, 1+gap_depth], - [cartridge_length-7.5-i, gap_depth], - [cartridge_length-7.5-i, 0] - ]); - polygon([ - [cartridge_length-5-i, cartridge_width], - [cartridge_length-5-i, cartridge_width-1-gap_depth], - [cartridge_length-7.5-i, cartridge_width-gap_depth], - [cartridge_length-7.5-i, cartridge_width] - ]); - } - } - translate([0, 0, gap_elevation-(gap_height/2)]) linear_extrude(gap_height) { +} + +module grip_wedge() { + linear_extrude(gap_elevation) + polygon([ + [0, 0], + [0, 1 + gap_depth], + [-grip_wedge_width, gap_depth], + [-grip_wedge_width, 0] + ]); +} + +module gap() { + translate([0, 0, gap_elevation]) + linear_extrude(gap_height) difference() { - offset(10) footprint(); + footprint(); offset(-gap_depth) footprint(); } - } - translate([0, 0, -gap_height/2 - 2]) linear_extrude(gap_elevation+2) translate([53, cartridge_width-7]) rotate(45) offset(3) square([16, 16]); } -color("teal") -let(h=6.4) { - translate([12, 79.5, (cartridge_height-h)/2]) cylinder(r=10, h); - translate([2, 14, (cartridge_height-h)/2]) cube([10, 65.5, h]); +module undercut() { + translate([53, cartridge_width - 7, -foot_height]) + linear_extrude(gap_elevation + foot_height) + rotate(45) + offset(3) + square([16, 16]); } +module tape() { + translate([0, 0, (cartridge_height - tape_height) / 2]) { + roller(); + tape_line(); + } +} + +module roller() { + translate(roller_position) + cylinder( + h=tape_height, + r=10, + ); +} + +module tape_line() { + translate(tape_line_position) + cube([ + window_depth - tape_line_position.x, + roller_position.y - tape_line_position.y, + tape_height + ]); +} + +module nfc_coin() { + translate([ + cartridge_length / 2, + cartridge_width / 2, + cartridge_height - nfc_coin_depth + ]) + cylinder( + h=nfc_coin_depth + nfc_coin_tolerance, + d=nfc_coin_diameter + 2 * nfc_coin_tolerance, + ); +}; + module footprint() { - difference() { - polygon([ - [0, wedge_width], - [0, cartridge_width - wedge_width], - [wedge_depth, cartridge_width], - [cartridge_length, cartridge_width], - [cartridge_length, 0], - [wedge_depth, 0], - ]); - let(r=4) { - translate([cartridge_length - r, 0]) { - translate([0, r]) fillet(r, a1=90, a2=180); - translate([0, cartridge_width - r]) fillet(r, a1=0, a2=90); - } + hull() { + translate([ + cartridge_length - back_vertical_fillet_radius, + back_vertical_fillet_radius, + ]) { + circle(back_vertical_fillet_radius); + // translate([0, cartridge_width - back_vertical_fillet_radius]) + // circle(back_vertical_fillet_radius); } - let(m=wedge_width/wedge_depth, r=20) { - translate([wedge_depth + r * tan(atan(m)/2), 0]) { - translate([0, r]) fillet(r, a1=180, a2=180+atan(m)); - translate([0, cartridge_width - r]) fillet(r, a1=0, a2=-atan(m)); - } - } - let(m=wedge_depth/wedge_width, r=5) { - translate([r, 0]) { - translate([0, wedge_width + r * tan(atan(m)/2)]) fillet(r, a1=180+atan(1/m), a2=270); - translate([0, cartridge_width - wedge_width - r * tan(atan(m)/2)]) fillet(r, a1=270, a2=360-atan(1/m)); - } - } - translate([-8, 76]) circle(r=12); + translate([ + cartridge_length - back_vertical_fillet_radius, + cartridge_width - back_vertical_fillet_radius, + ]) circle(back_vertical_fillet_radius); + translate([ + tape_guide_depth + side_vertical_fillet_radius * tan(0.5 * atan(tape_guide_slope)), + side_vertical_fillet_radius, + ]) circle(side_vertical_fillet_radius); + translate([ + tape_guide_depth + side_vertical_fillet_radius * tan(0.5 * atan(tape_guide_slope)), + cartridge_width - side_vertical_fillet_radius, + ]) circle(side_vertical_fillet_radius); + translate([ + front_vertical_fillet_radius, + tape_guide_width + front_vertical_fillet_radius * tan(0.5 * atan(1 / tape_guide_slope)), + ]) circle(front_vertical_fillet_radius); + translate([ + front_vertical_fillet_radius, + cartridge_width - tape_guide_width - front_vertical_fillet_radius * tan(0.5 * atan(1 / tape_guide_slope)), + ]) circle(front_vertical_fillet_radius); } } -module fillet(r, d, a1=0, a2=360, p=10) { - difference() { - polygon([ - [0, 0], - each [for (a=[a1:a2]) [p * sin(a) * r, p * cos(a) * r]], - ]); - circle(r, d); +module tracks() { + track_interval = cartridge_width - 2 * track_side_inset; + translate([track_front_inset, track_side_inset, cartridge_height]) + rotate([0, 90, 0]) { + track(); + translate([0, track_interval]) track(); + } +} + +module track() { + track_length = cartridge_length - track_front_inset - track_back_inset; + cylinder( + h=track_taper_length, + r1=0, + r2=track_radius, + ); + translate([0, 0, track_taper_length]) cylinder( + h=track_length - 2 * track_taper_length, + r=track_radius, + ); + translate([0, 0, track_length - track_taper_length]) cylinder( + h=track_taper_length, + r1=track_radius, + r2=0, + ); +} + +module feet() { + foot_interval = cartridge_width - 2 * foot_side_inset - foot_width; + translate([foot_front_inset, foot_side_inset, -foot_height]) { + foot(); + translate([0, foot_interval, 0]) foot(); } -} \ No newline at end of file +} + +module foot() { + foot_length = cartridge_length - foot_front_inset - foot_back_inset; + translate([foot_height, 0]) + cube([ + foot_length - foot_height * 2, + foot_width, + foot_height, + ]); + intersection() { + cube([ + cartridge_length, + foot_width, + foot_height, + ]); + union() { + translate([foot_height, foot_width, foot_height]) + rotate([90, 90, 0]) + cylinder(h=foot_width, r=foot_height); + translate([foot_length - foot_height, foot_width, foot_height]) + rotate([90, 90, 0]) + cylinder(h=foot_width, r=foot_height); + } + } +}