/************************************************************************* * Hülle für die u23-Spielekonsole. * * Vorderseite. * * * * Author: Shy * * License: CC0 * *************************************************************************/ include ; /* Höhe wichtiger Bauteile: * * Display: * Z320IT010 * L: 54 mm * B: 77.4 mm * H: 2.4 mm * Davon LCD: * L: 48.6 mm * B: 64.8 mm, mit 3.35 mm Abstand zum rechten Rand * * Kurzhubtaster Pads: * PTS645SL50-2 LFS * H Taster: 5 mm * H Gehäuse: 3.45 mm * D Taster: 3.5 mm * * Kurzhubtaster unten: * PTS645SK43SMTR92 LFS * H Taster: 4.3 mm * H Gehäuse: 4.3 * D Taster: 3.5 mm * * Schalter an der Schulter: * D2FS-FL-N-A * H: 5.8 mm * B: 12.8 mm * * Analog Stick: * Alps RKJXV1224005 * H Gehäuse: 10.8 mm * H bis Gelenk: 12.46 mm * L: 21.3 mm * B: 17.8 mm * Der Kern ist ein Quadrat mit 13.15 mm Kantenlänge. * Anschlag 7 mm von der Platine. */ // Abgerundete Außenkanten. rounded_edges = false; // Abgeschrägte Außenkanten. beveled_edges = true; // Aussparungen für den linken Analog-Stick. analog_stick_l = true; // Aussparungen für den rechten Analog-Stick. analog_stick_r = false; // LEDs am unteren Rand. led_bottom = true; // Y-LED. led_y = true; // LED-Pegel. led_gauge = true; // LED Logo. led_logo = true; // Dicke der Decke. top = 1.0; // Höhe des Innenraumes. space = 7; // Höhe des oberen Randes. border_height = 4; // Höhe der Verstrebungen. struts = 2; // Display (X, Y, Weite, Höhe). display = [42.5, 24, 68.5, 52]; // Durchmesser der Bohrungen. drill = 3.4; // Durchmesser der Bohrschäfte. drill_shaft = 7.4; // Position der Bohrungen. drill_pos = [ [10, 20], [10, 100], [140, 20], [140, 100], ]; // Dicke der Basis der Aktionsbuttons. button_action_base = 1; // Dicke der Basis der Systembuttons. button_system_base = 2; // Tatsächliche Höhe der Taster unter den Aktionsbuttons. button_action_size = 5; // Tatsächliche Höhe der Taster unter den Systembuttons. button_system_size = 4.5; // Spiel der Buttons zwischen Taster und Decke. button_clearance = 0.2; /************************************************************************* * Überprüfe Parameter auf Fehler. * *************************************************************************/ //assert(space >= trigger_switch_height + button_trigger_base, // "Die Höhe reicht nicht für die Schultertasten!"); /************************************************************************* * Einzelteile * *************************************************************************/ // Durchbrüche in der Front. module top_cutouts() { // Display. // Berechne X/Y-Koordinaten vom linken oberen Rand der Platine. translate([150 - display[2]/2 - display.x, 110 - display[3]/2 - display.y, (top + struts)/2]) minkowski() { cube([display[2] - 2, display[3] - 2, 0.01], true); cylinder(top + struts, 2, 1, true, $fn=16); } // LEDs am unteren Rand. if (led_bottom) { linear_extrude(height=top) { import("./svg/front led bottom.svg"); } } // LED-Pegel. if (led_gauge) { linear_extrude(height=top) { import("./svg/front led gauge.svg"); } } // Y-LED. if (led_y) { linear_extrude(height=top) { import("./svg/front led y.svg"); } } // Power LED. if (led_logo) { linear_extrude(height=top) { import("./svg/front led power logo.svg"); } } else { linear_extrude(height=top) { import("./svg/front led power.svg"); } } } // Schaft für die Schrauben. module screw_shaft() { translate([0, 0, top]) cylinder(h = space, r = drill_shaft/2, $fn=32); } // Platzsparendere Stützen für die Bohrungen am oberen Rand. module screw_support(width, length) { translate([0, 0, top + (space / 2)]) cube([width, length, space], center=true); } // Bohrung für die Schrauben. module screw_drill() { // Die "$preview"-Bedingung reduziert Feher bei der Vorschau. cylinder(h=space + top + ($preview ? 0.2 : 0), r=drill/2, $fn=24); } // Maske für Stellen, an denen der Rand nicht ganz auf der Platine aufliegen // kann. module border_pcb_cutouts() { // Vibrator. translate([28, 10 + 1, -1.5]) cube([6, 1, 1.5]); // Batteriefach. translate([47.5 - 2, 10 + 1, -1.5]) cube([4, 1, 1.5]); } // Kleine Streben zwischen Decke und Rand. module border_strut(width, length, height) { x = width/2; y = length/2; polyhedron(points = [ [-x, -y, 0], [x, -y, 0], [x, y, 0], [-x, y, 0], [-x, y, height], [x, y, height] ], faces = [ [0, 1, 2, 3], [1, 5, 2], [2, 5, 4, 3], [3, 4, 0], [0, 4, 5, 1] ]); } // Die äußeren Teile: Front und Ränder. module outer() { // Decke. color(color_top) linear_extrude(height=top) { import("./svg/front top.svg"); } // Oberer Rand. color(color_border1) translate([0, 0, top]) { linear_extrude(height = border_height) { import("./svg/front borders.svg"); } } // Unterer Rand. color(color_border2) translate([0, 0, top + border_height]) { difference() { linear_extrude(height=space - border_height) { import("./svg/front borders lower.svg"); } // Stellen, an denen der Rand nicht ganz auf der Platine aufliegen // kann. translate([0, 0, space - border_height]) border_pcb_cutouts(); } } // Verstrebungen. color(color_struts) translate([0, 0, top]) { linear_extrude(height=struts) { import("./svg/front struts.svg"); } } // Verstrebung um das Display herum. // Berechne X/Y-Koordinaten vom linken oberen Rand der Platine. color (color_struts) translate([150 - display[2]/2 - display.x, 110 - display[3]/2 - display.y, (top + struts)/2]) minkowski() { cube([display[2] - 2, display[3] - 2, 0.01], true); cylinder(top + struts, 4, 3, true, $fn=16); } // Verstärkungen für die Analog-Sticks. if (analog_stick_l) { color(color_struts) translate([0, 0, top]) { linear_extrude(height = struts) { import("./svg/front analog stick l struts.svg"); } } } if (analog_stick_r) { color(color_struts) translate([0, 0, top]) { linear_extrude(height = struts) { import("./svg/front analog stick r struts.svg"); } } } // Zusätzliche Verstrebungen zwischen Decke und Rand. if (rounded_edges || beveled_edges) { color(color_struts) for (pos = [ // [x, y, rotation, länge] [37, 107.5, 0, 3], [45, 107.5, 0, 3], [63, 107.5, 0, 3], [71, 107.5, 0, 3], [79, 107.5, 0, 3], [87, 107.5, 0, 3], [147.5, 85, 270, 3], [148, 78.5, 270, 2], [148, 71.5, 270, 2], [147.5, 65, 270, 3], [147.5, 57, 270, 3], [148, 49, 270, 2], [148, 41, 270, 2], [109, 12.5, 180, 3], [94, 12.5, 180, 3], [56, 12.5, 180, 3], [41, 12.5, 180, 3], [26, 12.5, 180, 3], [5, 36, 90, 2], [5, 44, 90, 2], [5, 52, 90, 2], [5, 60, 90, 2], [2.5, 84, 90, 3], ]) { translate([pos[0], pos[1], top]) rotate([0, 0, pos[2]]) border_strut(1.6, pos[3], pos[3]); } } } // Maske, um angerundete oder abgeschrägte Außenkanten zu schneiden. module edge_cut() { minkowski() { linear_extrude(height=0.1) { import("./svg/front outline.svg"); } $fn = $preview ? 4 : 8; if (beveled_edges) { // Abgeschrägte Kanten. cylinder(h=4, r1=1.5, r2=0); } else { // Abgerundete Kanten. // Dafür generieren wir im folgenden einen konkaven Kegel. union() { curve = [1.34, 1.07, 0.84, 0.63, 0.46, 0.32, 0.2, 0.11, 0.05, 0.01, 0]; for (i = [0:len(curve)-2]) { translate([0, 0, i*0.5]) cylinder(h=0.5, r1=curve[i], r2=curve[i+1]); } } } } } /************************************************************************* * Die Hülle. * *************************************************************************/ module casing_front() { difference() { if (rounded_edges || beveled_edges) { difference() { union () { outer(); } translate([0, 0, -0.1]) edge_cut(); } } else { outer(); } // Vergrößere das zu substrahierende Objekt, um Darstellungsfehler // in der Voransicht zu vermeiden. if ($preview) { translate([0, 0, -0.1]) resize([0, 0, top + struts + 0.4]) top_cutouts(); } else { top_cutouts(); } } // Halterungen für die Aktionsbuttons. // Begrenzung nach oben. color(color_buttons) translate([0, 0, top]) { linear_extrude(height = space - button_action_size - button_action_base - button_clearance) { import("./svg/front button action upper.svg"); } } // Führung für die Aktionsbuttons. color(color_buttons) translate([0, 0, top]) { // Wir ziehen die Führungen zwei Millimeter tiefer, um auf der sicheren // Seite zu sein. linear_extrude(height = space - button_action_size + 2) { import("./svg/front button action lower.svg"); } } // Halterungen für die Systembuttons. // Begrenzung nach oben. color(color_buttons) translate([0, 0, top]) { linear_extrude(height = space - button_system_size - button_system_base - button_clearance) { import("./svg/front button system upper.svg"); } } // Führung für die Systembuttons. color(color_buttons) translate([0, 0, top]) { linear_extrude(height = space - button_system_size) { import("./svg/front button system lower.svg"); } } // Schäfte für die Bohrungen. color(color_drills) for (i = [0:3]) { // Die normalen Bohrungen am unteren Rand. translate([drill_pos[i].x, drill_pos[i].y, 0]) screw_shaft(); } // Schacht für den Lichtsensor. color(color_struts) translate([0, 0, top]) { linear_extrude(height = space) { import("./svg/front well.svg"); } } } // Plazierung der Bohrungen. difference() { casing_front(); // Bedingtes translate um Fehler bei der Vorschau auszubessern. translate([0, 0, $preview ? -0.1 : 0]) union() { for (i = [0:3]) { translate([drill_pos[i][0], drill_pos[i][1], 0]) screw_drill(); } // Die Löcher für die Analog-Sticks. if (analog_stick_l) { linear_extrude(height = space * ($preview ? 1.2 : 1)) { import("./svg/front analog stick l.svg"); } } if (analog_stick_r) { linear_extrude(height = space * ($preview ? 1.2 : 1)) { import("./svg/front analog stick r.svg"); } } } }