u23-gameconsole-body/front.scad
2024-01-20 18:38:39 +01:00

462 lines
12 KiB
OpenSCAD

/*************************************************************************
* Hülle für die u23-Spielekonsole. *
* Vorderseite. *
* *
* Author: Shy *
* License: CC0 *
*************************************************************************/
include <colors.scad>;
/* 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 abgerundete oder abgeschrägte Außenkanten zu schneiden.
module edge_cut() {
minkowski() {
linear_extrude(height=0.1) {
import("./svg/front outline.svg");
}
$fn = $preview ? 4 : 16;
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.
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");
}
}
}
}