diff --git a/3d-model/cube-assembly.scad b/3d-model/cube-assembly.scad index 89260cd..cff23e9 100644 --- a/3d-model/cube-assembly.scad +++ b/3d-model/cube-assembly.scad @@ -39,7 +39,7 @@ SHOW_ELECTRONICS = true; // PCB central + batterie (visualisation) SHOW_PCBS = true; // PCBs anneau + bouchon dans les faces SHOW_SECTION = false; // Coupe en section pour voir l'intérieur -EXPLODE = 0; // 0 = assemblé, 1 = vue éclatée (0 à 1 progressif) +EXPLODE = 1; // 0 = assemblé, 1 = vue éclatée (0 à 1 progressif) // Distance d'éclatement EXPLODE_DIST = 40 * EXPLODE; @@ -60,28 +60,11 @@ module frame() { difference() { union() { - // --- 12 arêtes du cube --- - // Arêtes selon X (4) - for (y = [-1, 1], z = [-1, 1]) { - translate([0, y * (half - edge_d/2), z * (half - edge_d/2)]) - cube([CUBE_SIZE - 2*edge_d, edge_w, edge_d], center=true); - } - // Arêtes selon Y (4) - for (x = [-1, 1], z = [-1, 1]) { - translate([x * (half - edge_d/2), 0, z * (half - edge_d/2)]) - cube([edge_d, CUBE_SIZE - 2*edge_d, edge_w], center=true); - } - // Arêtes selon Z (4) - for (x = [-1, 1], y = [-1, 1]) { - translate([x * (half - edge_d/2), y * (half - edge_d/2), 0]) - cube([edge_d, edge_w, CUBE_SIZE - 2*edge_d], center=true); - } + // --- Squelette arrondi (12 arêtes + 8 coins sphériques) --- + _rounded_frame_skeleton(); - // --- 8 coins --- - for (x = [-1, 1], y = [-1, 1], z = [-1, 1]) { - translate([x * (half - edge_d/2), y * (half - edge_d/2), z * (half - edge_d/2)]) - cube([edge_d, edge_d, edge_d], center=true); - } + // --- Corniches de contact (surface plane pour joint O-ring) --- + _frame_contact_ledges(); // --- Plots de fixation (4 par face, 6 faces) --- // Face +Z (dessus) et -Z (dessous) @@ -231,6 +214,91 @@ module _all_mount_holes() { } } +// Cube arrondi (hull de 8 sphères aux coins) +module _rounded_cube(size, r) { + hull() { + c = size/2 - r; + for (x = [-1, 1], y = [-1, 1], z = [-1, 1]) + translate([x*c, y*c, z*c]) + sphere(r=r); + } +} + +// Squelette arrondi : coque arrondie évidée + ouvertures pour les 6 faces +module _rounded_frame_skeleton() { + half = CUBE_SIZE / 2; + r = CORNER_RADIUS; + edge_d = FRAME_EDGE_DEPTH; + opening = CUBE_SIZE - 2 * edge_d; + + difference() { + // Coque extérieure arrondie + _rounded_cube(CUBE_SIZE, r); + + // Évidement intérieur + cube([opening, opening, opening], center=true); + + // Ouvertures pour les 6 faces (traversées) + cube([opening, opening, CUBE_SIZE + 2], center=true); // ±Z + cube([CUBE_SIZE + 2, opening, opening], center=true); // ±X + cube([opening, CUBE_SIZE + 2, opening], center=true); // ±Y + } +} + +// Corniches plates sur chaque face du squelette +// Surface de contact plane pour l'assise du joint O-ring et la fixation +module _frame_contact_ledges() { + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + lw = FRAME_LEDGE_WIDTH; + lh = FRAME_LEDGE_HEIGHT; + opening = CUBE_SIZE - 2 * edge_d; + outer = opening + 2 * lw; + + // Corniche sur chaque face : anneau plat (outer - opening) + // +Z et -Z + for (z = [-1, 1]) { + translate([0, 0, z * (half - edge_d + (z > 0 ? 0 : -lh))]) + difference() { + linear_extrude(lh) + offset(r=CORNER_RADIUS) + offset(delta=-CORNER_RADIUS) + square([outer, outer], center=true); + translate([0, 0, -0.5]) + linear_extrude(lh + 1) + square([opening, opening], center=true); + } + } + // +Y et -Y + for (y_dir = [-1, 1]) { + translate([0, y_dir * (half - edge_d + (y_dir > 0 ? 0 : -lh)), 0]) + rotate([90, 0, 0]) + difference() { + linear_extrude(lh) + offset(r=CORNER_RADIUS) + offset(delta=-CORNER_RADIUS) + square([outer, outer], center=true); + translate([0, 0, -0.5]) + linear_extrude(lh + 1) + square([opening, opening], center=true); + } + } + // +X et -X + for (x_dir = [-1, 1]) { + translate([x_dir * (half - edge_d + (x_dir > 0 ? 0 : -lh)), 0, 0]) + rotate([0, 90, 0]) + difference() { + linear_extrude(lh) + offset(r=CORNER_RADIUS) + offset(delta=-CORNER_RADIUS) + square([outer, outer], center=true); + translate([0, 0, -0.5]) + linear_extrude(lh + 1) + square([opening, opening], center=true); + } + } +} + // Canaux pour le passage des nappes/câbles JST vers chaque face module _cable_channels() { ch_w = 10; // Largeur du canal @@ -275,18 +343,20 @@ module face_standard() { difference() { union() { - // --- Coque extérieure --- - // Plaque principale + // --- Coque extérieure (coins arrondis) --- difference() { - // Plaque pleine - translate([0, 0, FACE_TOTAL_DEPTH / 2]) - cube([face_size - 2*edge_d + 6, face_size - 2*edge_d + 6, FACE_TOTAL_DEPTH], center=true); - - // Évidement intérieur (laisser les parois) - translate([0, 0, FACE_TOTAL_DEPTH / 2 + WALL_THICKNESS]) - cube([face_size - 2*edge_d + 6 - 2*WALL_THICKNESS, - face_size - 2*edge_d + 6 - 2*WALL_THICKNESS, - FACE_TOTAL_DEPTH], center=true); + // Parois extérieures avec coins arrondis + linear_extrude(FACE_TOTAL_DEPTH) + offset(r=CORNER_RADIUS) + offset(delta=-CORNER_RADIUS) + square([face_size - 2*edge_d + 6, face_size - 2*edge_d + 6], center=true); + // Évidement intérieur + translate([0, 0, WALL_THICKNESS]) + linear_extrude(FACE_TOTAL_DEPTH) + offset(r=max(0.5, CORNER_RADIUS - WALL_THICKNESS)) + offset(delta=-max(0.5, CORNER_RADIUS - WALL_THICKNESS)) + square([face_size - 2*edge_d + 6 - 2*WALL_THICKNESS, + face_size - 2*edge_d + 6 - 2*WALL_THICKNESS], center=true); } // --- Membrane tactile (centre, amincie) --- @@ -321,16 +391,12 @@ module face_standard() { } } -// Plaque extérieure de la face (la surface visible) +// Plaque extérieure de la face (surface visible, coins arrondis) module _face_outer_plate(size) { - // Plaque pleine, épaisseur = WALL_THICKNESS, avec le centre aminci - difference() { - cube([size, size, WALL_THICKNESS], center=true); - // Le centre sera aminci séparément - } - translate([0, 0, -WALL_THICKNESS/2]) linear_extrude(WALL_THICKNESS) - square([size, size], center=true); + offset(r=CORNER_RADIUS) + offset(delta=-CORNER_RADIUS) + square([size, size], center=true); } // Chambre de diffusion annulaire pour les LEDs @@ -381,15 +447,24 @@ module _face_mount_holes() { } } -// Rainure pour joint torique périphérique +// Rainure pour joint torique O-ring +// Gorge rectangulaire continue suivant le contour arrondi de la face +// Dimensions selon norme : largeur ~1.4ר cordon, profondeur ~0.7ר cordon module _seal_groove(size) { w = FACE_SEAL_GROOVE_W; d = FACE_SEAL_GROOVE_D; - offset = size/2 - w - 1; + inset = 3; // Retrait depuis le bord extérieur + linear_extrude(d + 0.1) difference() { - cube([size - 2, size - 2, d], center=true); - cube([size - 2 - 2*w, size - 2 - 2*w, d + 1], center=true); + // Contour extérieur de la gorge (suit l'arrondi des coins) + offset(r=CORNER_RADIUS - inset) + offset(delta=-(CORNER_RADIUS - inset)) + square([size - 2*inset, size - 2*inset], center=true); + // Contour intérieur de la gorge + offset(r=max(0.5, CORNER_RADIUS - inset - w)) + offset(delta=-max(0.5, CORNER_RADIUS - inset - w)) + square([size - 2*inset - 2*w, size - 2*inset - 2*w], center=true); } } diff --git a/3d-model/cube-config.scad b/3d-model/cube-config.scad index 5c2a81f..34baf5c 100644 --- a/3d-model/cube-config.scad +++ b/3d-model/cube-config.scad @@ -20,13 +20,16 @@ FRAME_MOUNT_DIAM = 3.2; // Diamètre des trous de fixation M3 FRAME_MOUNT_HEAD = 5.8; // Diamètre de la tête de vis M3 FRAME_MOUNT_DEPTH = 3; // Profondeur du lamage tête de vis FRAME_SCREWS_PER_FACE = 4; // Nombre de vis par face +FRAME_LEDGE_WIDTH = 5; // Largeur corniche de contact (face ↔ squelette) +FRAME_LEDGE_HEIGHT = 3; // Épaisseur de la corniche plate // --- Faces ------------------------------------------------------------------ FACE_TOTAL_DEPTH = 14; // Profondeur totale d'un module face (du bord ext.) FACE_CENTER_DIAM = 40; // Diamètre de la zone tactile centrale FACE_MEMBRANE_T = 1.0; // Épaisseur de la membrane tactile (centre) -FACE_SEAL_GROOVE_W = 1.5; // Largeur de la rainure joint torique -FACE_SEAL_GROOVE_D = 1.5; // Profondeur de la rainure joint torique +SEAL_CORD_DIAM = 2.0; // Diamètre du cordon torique (joint O-ring) +FACE_SEAL_GROOVE_W = 2.8; // Largeur rainure = ~1.4 × cordon +FACE_SEAL_GROOVE_D = 1.4; // Profondeur rainure = ~0.7 × cordon // --- LEDs (PCB Anneau — Étage B) -------------------------------------------- LED_COUNT = 12; // Nombre de WS2812B par face