From c341de345ab5029abf0ad4f4832d49cc7f781aed Mon Sep 17 00:00:00 2001 From: Julien Holtzer Date: Sun, 8 Feb 2026 12:19:28 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20mod=C3=A8le=203D=20OpenSCAD=20=E2=80=94?= =?UTF-8?q?=20squelette=20+=206=20faces=20modulaires,=20param=C3=A9trique?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3d-model/README.md | 72 ++++ 3d-model/cube-assembly.scad | 648 ++++++++++++++++++++++++++++++++++++ 3d-model/cube-config.scad | 86 +++++ 3 files changed, 806 insertions(+) create mode 100644 3d-model/README.md create mode 100644 3d-model/cube-assembly.scad create mode 100644 3d-model/cube-config.scad diff --git a/3d-model/README.md b/3d-model/README.md new file mode 100644 index 0000000..4eed754 --- /dev/null +++ b/3d-model/README.md @@ -0,0 +1,72 @@ +# Modèle 3D — Companion Cube + +## Architecture : Squelette + 6 Faces Modulaires + +``` + ┌───────────────┐ + /│ /│ + / │ Face 1 / │ Face 1 = Dessus (NFC) + / │ (NFC) / │ Face 2 = Avant + ┌───────────────┐ │ Face 3 = Droite + │ │ │ │ Face 4 = Arrière + │ │ Face 5 │ │ Face 3 Face 5 = Gauche + │ │ (Gauche) │ │(Droite) Face 6 = Dessous (Qi) + │ └───────────│───┘ + │ / Face 4 │ / + │ / (Arrière) │ / + │/ │/ + └───────────────┘ + Face 2 (Avant) + Face 6 (Qi, dessous) +``` + +## Fichiers + +| Fichier | Description | +|---------|-------------| +| `cube-config.scad` | Paramètres dimensionnels (modifier ici pour ajuster) | +| `cube-assembly.scad` | Modèle principal — ouvrir dans OpenSCAD | + +## Utilisation + +1. **Installer OpenSCAD** : https://openscad.org/ +2. **Ouvrir** `cube-assembly.scad` +3. **Prévisualiser** : F5 (aperçu rapide) ou F6 (rendu complet) + +### Contrôles de visualisation + +Dans `cube-assembly.scad`, modifier les variables en haut du fichier : + +```openscad +SHOW_FRAME = true; // Squelette +SHOW_FACE_TOP = true; // Face dessus (NFC) +SHOW_ELECTRONICS = true; // Batterie + PCB central +SHOW_SECTION = false; // Vue en coupe + +EXPLODE = 0; // 0 = assemblé, 1 = vue éclatée +``` + +### Export STL pour impression + +1. Décommenter le module souhaité en bas de `cube-assembly.scad` +2. Commenter `assembly()` +3. F6 → File → Export as STL + +### Pièces à imprimer + +| Pièce | Quantité | Matériau | Notes | +|-------|----------|----------|-------| +| `frame` (squelette) | 1 | PLA/PETG opaque gris | Structurel | +| `face-standard` | 4 | PETG translucide | Diffusion LED | +| `face-nfc` | 1 | PETG translucide | Dessus, membrane fine NFC | +| `face-qi` | 1 | PETG translucide | Dessous, aminci pour Qi | + +## Paramètres clés + +| Paramètre | Valeur | Impact | +|-----------|--------|--------| +| `CUBE_SIZE` | 120 mm | Taille globale | +| `WALL_THICKNESS` | 2.5 mm | Solidité vs poids | +| `FACE_MEMBRANE_T` | 1.0 mm | Sensibilité tactile | +| `RING_SHROUD_HEIGHT` | 6 mm | Qualité de diffusion LED | +| `PRINT_TOLERANCE` | 0.2 mm | Ajuster selon votre imprimante | diff --git a/3d-model/cube-assembly.scad b/3d-model/cube-assembly.scad new file mode 100644 index 0000000..89260cd --- /dev/null +++ b/3d-model/cube-assembly.scad @@ -0,0 +1,648 @@ +// ============================================================================ +// Companion Cube — Modèle 3D Complet +// Version : 0.2.0 +// Architecture : Squelette interne + 6 faces modulaires vissées +// ============================================================================ +// +// STRUCTURE : +// 1. Squelette (frame) — Structure porteuse interne en forme de cube +// 2. Face Standard (x4) — Module face : coque + shroud + emplacements PCB +// 3. Face NFC (dessus) — Comme standard + logement PN532 +// 4. Face Qi (dessous) — Comme standard + logement bobine Qi +// 5. Électronique — PCB central, batterie (visualisation) +// +// ASSEMBLAGE : +// 1. Monter le PCB central + batterie dans le squelette +// 2. Câbler les connecteurs JST vers chaque face +// 3. Assembler chaque module face (PCB Anneau + PCB Bouchon dans la coque) +// 4. Visser chaque module face sur le squelette (4x M3 par face) +// +// UTILISATION : +// - Ouvrir dans OpenSCAD +// - Variable `SHOW_*` pour afficher/masquer les pièces +// - Variable `EXPLODE` pour la vue éclatée +// - Modules individuels exportables en STL pour l'impression +// +// ============================================================================ + +include + +// --- Contrôle de l'affichage ------------------------------------------------ +SHOW_FRAME = true; // Squelette interne +SHOW_FACE_TOP = true; // Face dessus (NFC) +SHOW_FACE_BOTTOM = true; // Face dessous (Qi) +SHOW_FACE_FRONT = true; // Face avant +SHOW_FACE_BACK = true; // Face arrière +SHOW_FACE_LEFT = true; // Face gauche +SHOW_FACE_RIGHT = true; // Face droite +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) + +// Distance d'éclatement +EXPLODE_DIST = 40 * EXPLODE; + +// ============================================================================ +// MODULE : Squelette Interne (Frame) +// ============================================================================ +// Le squelette est constitué des 12 arêtes d'un cube, avec des plots de +// fixation M3 sur chaque face intérieure (4 par face = 24 total). +// Il accueille le PCB central et la batterie en son centre. +// ============================================================================ + +module frame() { + half = CUBE_SIZE / 2; + edge_w = FRAME_EDGE_WIDTH; + edge_d = FRAME_EDGE_DEPTH; + inner = CUBE_SIZE - 2 * edge_d; + + 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); + } + + // --- 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); + } + + // --- Plots de fixation (4 par face, 6 faces) --- + // Face +Z (dessus) et -Z (dessous) + for (z = [-1, 1]) { + for (xy = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xy[0], xy[1], z * (half - edge_d)]) + _mount_post(z); + } + } + // Face +Y (arrière) et -Y (avant) + for (y_dir = [-1, 1]) { + for (xz = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xz[0], y_dir * (half - edge_d), xz[1]]) + rotate([y_dir * 90, 0, 0]) + _mount_post(1); + } + } + // Face +X (droite) et -X (gauche) + for (x_dir = [-1, 1]) { + for (yz = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([x_dir * (half - edge_d), yz[0], yz[1]]) + rotate([0, x_dir * -90, 0]) + _mount_post(1); + } + } + + // --- Support batterie (berceau central) --- + _battery_cradle(); + + // --- Support PCB central --- + _central_pcb_mount(); + } + + // --- Perçages des plots M3 --- + _all_mount_holes(); + + // --- Passages de câbles (JST vers chaque face) --- + _cable_channels(); + } +} + +// Plot de fixation cylindrique (s'élève vers la face) +module _mount_post(direction) { + post_h = 8; + post_d = 7; + translate([0, 0, direction > 0 ? 0 : -post_h]) + cylinder(d=post_d, h=post_h); +} + +// Berceau pour la batterie LiPo +module _battery_cradle() { + bw = BATT_WIDTH + 2 * BATT_TOLERANCE + 4; // +4 pour les parois + bl = BATT_LENGTH + 2 * BATT_TOLERANCE + 4; + bh = BATT_HEIGHT + BATT_TOLERANCE + 2; + wall = 2; + + // Position : centré, décalé vers le bas pour laisser de la place au PCB central au-dessus + translate([0, 0, -10]) + difference() { + cube([bl, bw, bh], center=true); + translate([0, 0, wall]) + cube([bl - 2*wall, bw - 2*wall, bh], center=true); + // Ouverture pour les fils + translate([0, bw/2, 0]) + cube([20, wall*3, bh - wall], center=true); + } +} + +// Supports pour le PCB central (4 entretoises) +module _central_pcb_mount() { + standoff_h = 5; + standoff_d = 6; + hole_d = 2.5; // Pour vis M2.5 ou insert + + pcb_mount_offset = 8; // Au-dessus du centre (batterie en dessous) + + for (x = [-1, 1], y = [-1, 1]) { + translate([ + x * (CENTRAL_PCB_LENGTH/2 - 5), + y * (CENTRAL_PCB_WIDTH/2 - 5), + pcb_mount_offset + ]) + difference() { + cylinder(d=standoff_d, h=standoff_h); + cylinder(d=hole_d, h=standoff_h + 1); + } + } +} + +// Perçage de tous les trous M3 (traversant les plots) +module _all_mount_holes() { + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + + // Face +Z et -Z + for (z = [-1, 1]) { + for (xy = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xy[0], xy[1], z * half]) + cylinder(d=FRAME_MOUNT_DIAM, h=20, center=true); + } + } + // Face +Y et -Y + for (y_dir = [-1, 1]) { + for (xz = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xz[0], y_dir * half, xz[1]]) + rotate([90, 0, 0]) + cylinder(d=FRAME_MOUNT_DIAM, h=20, center=true); + } + } + // Face +X et -X + for (x_dir = [-1, 1]) { + for (yz = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([x_dir * half, yz[0], yz[1]]) + rotate([0, 90, 0]) + cylinder(d=FRAME_MOUNT_DIAM, h=20, center=true); + } + } +} + +// Canaux pour le passage des nappes/câbles JST vers chaque face +module _cable_channels() { + ch_w = 10; // Largeur du canal + ch_h = 6; // Hauteur du canal + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + + // Un canal par face, radial depuis le centre + // +Z / -Z + for (z = [-1, 1]) { + translate([0, 0, z * (half - edge_d/2)]) + cube([ch_w, ch_h, edge_d + 2], center=true); + } + // +Y / -Y + for (y = [-1, 1]) { + translate([0, y * (half - edge_d/2), 0]) + cube([ch_w, edge_d + 2, ch_h], center=true); + } + // +X / -X + for (x = [-1, 1]) { + translate([x * (half - edge_d/2), 0, 0]) + cube([edge_d + 2, ch_w, ch_h], center=true); + } +} + + +// ============================================================================ +// MODULE : Face Standard +// ============================================================================ +// Module face complet comprenant : +// - Coque extérieure avec membrane tactile amincie au centre +// - Rainure pour joint torique (étanchéité visuelle) +// - Ring Shroud (chambre de diffusion LEDs) +// - Emplacements PCB Anneau (étage B) et PCB Bouchon (étage A) +// - Trous de fixation M3 (alignés avec les plots du squelette) +// ============================================================================ + +module face_standard() { + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + face_size = CUBE_SIZE - 2 * PRINT_TOLERANCE; + + difference() { + union() { + // --- Coque extérieure --- + // Plaque principale + 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); + } + + // --- Membrane tactile (centre, amincie) --- + cylinder(d=FACE_CENTER_DIAM + 10, h=FACE_MEMBRANE_T); + + // --- Paroi extérieure pleine (face visible) --- + translate([0, 0, 0]) + _face_outer_plate(face_size - 2*edge_d + 6); + + // --- Ring Shroud (chambre de diffusion) --- + translate([0, 0, WALL_THICKNESS]) + _ring_shroud(); + + // --- Oreilles de fixation M3 --- + _face_mount_ears(); + } + + // --- Zone tactile amincie (creuser pour ne garder que 1mm) --- + translate([0, 0, FACE_MEMBRANE_T]) + cylinder(d=FACE_CENTER_DIAM, h=FACE_TOTAL_DEPTH); + + // --- Rainure joint torique --- + translate([0, 0, FACE_TOTAL_DEPTH - 1]) + _seal_groove(face_size - 2*edge_d + 2); + + // --- Trous de fixation M3 --- + _face_mount_holes(); + + // --- Ouverture d'air centrale (côté intérieur) --- + translate([0, 0, WALL_THICKNESS]) + cylinder(d=AIR_HOLE_DIAM, h=FACE_TOTAL_DEPTH); + } +} + +// Plaque extérieure de la face (la surface visible) +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); +} + +// Chambre de diffusion annulaire pour les LEDs +module _ring_shroud() { + ext = LED_RING_DIAM_EXT + 2 * RING_SHROUD_WALL; + int_ = LED_RING_DIAM_INT - 2 * RING_SHROUD_WALL; + + difference() { + cylinder(d=ext, h=RING_SHROUD_HEIGHT); + translate([0, 0, -0.5]) + cylinder(d=int_, h=RING_SHROUD_HEIGHT + 1); + } +} + +// Oreilles de fixation (dépassent pour atteindre les plots du squelette) +module _face_mount_ears() { + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + ear_size = 10; + + for (xy = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xy[0], xy[1], FACE_TOTAL_DEPTH/2]) + cube([ear_size, ear_size, FACE_TOTAL_DEPTH], center=true); + } +} + +// Trous de fixation dans les oreilles +module _face_mount_holes() { + half = CUBE_SIZE / 2; + edge_d = FRAME_EDGE_DEPTH; + + for (xy = [ + [ (half - edge_d - 10), (half - edge_d - 10)], + [-(half - edge_d - 10), (half - edge_d - 10)], + [ (half - edge_d - 10), -(half - edge_d - 10)], + [-(half - edge_d - 10), -(half - edge_d - 10)] + ]) { + translate([xy[0], xy[1], -1]) + cylinder(d=FRAME_MOUNT_DIAM, h=FACE_TOTAL_DEPTH + 2); + // Lamage tête de vis (côté extérieur) + translate([xy[0], xy[1], -1]) + cylinder(d=FRAME_MOUNT_HEAD, h=FRAME_MOUNT_DEPTH + 1); + } +} + +// Rainure pour joint torique périphérique +module _seal_groove(size) { + w = FACE_SEAL_GROOVE_W; + d = FACE_SEAL_GROOVE_D; + offset = size/2 - w - 1; + + difference() { + cube([size - 2, size - 2, d], center=true); + cube([size - 2 - 2*w, size - 2 - 2*w, d + 1], center=true); + } +} + + +// ============================================================================ +// MODULE : Face NFC (Dessus) +// ============================================================================ +// Identique à la face standard mais avec un logement pour le module PN532 +// à la place du simple PCB Bouchon. +// ============================================================================ + +module face_nfc() { + difference() { + union() { + face_standard(); + + // Logement renforcé pour le PN532 (plus grand que le bouchon standard) + translate([0, 0, WALL_THICKNESS + RING_SHROUD_HEIGHT]) + _nfc_mount(); + } + + // Ouverture pour l'antenne NFC (dans la membrane) + // L'antenne doit être au plus près de la surface pour une bonne lecture + translate([0, 0, -1]) + cylinder(d=NFC_ANTENNA_DIAM, h=FACE_MEMBRANE_T + 2); + } +} + +module _nfc_mount() { + // Support carré pour le module PN532 + wall = 1.5; + size = NFC_PCB_SIZE + 2 * wall + 2 * PRINT_TOLERANCE; + inner = NFC_PCB_SIZE + 2 * PRINT_TOLERANCE; + + difference() { + cube([size, size, NFC_PCB_HEIGHT + 2], center=true); + cube([inner, inner, NFC_PCB_HEIGHT + 3], center=true); + } +} + + +// ============================================================================ +// MODULE : Face Qi (Dessous) +// ============================================================================ +// Identique à la face standard mais avec un logement pour la bobine Qi +// et son PCB récepteur. +// ============================================================================ + +module face_qi() { + difference() { + union() { + face_standard(); + + // Logement bobine Qi + translate([0, 0, WALL_THICKNESS]) + _qi_mount(); + } + + // La bobine Qi doit être au plus près de la surface extérieure + // Amincissement supplémentaire au centre pour la bobine + translate([0, 0, -0.5]) + cylinder(d=QI_COIL_DIAM + 4, h=WALL_THICKNESS - 0.8 + 0.5); + } +} + +module _qi_mount() { + wall = 1.5; + // Anneau de maintien pour la bobine + difference() { + cylinder(d=QI_COIL_DIAM + 2*wall + 2*PRINT_TOLERANCE, h=QI_COIL_HEIGHT + 1); + translate([0, 0, -0.5]) + cylinder(d=QI_COIL_DIAM + 2*PRINT_TOLERANCE, h=QI_COIL_HEIGHT + 2); + } + // Support PCB récepteur Qi (décalé) + translate([0, QI_COIL_DIAM/2 + 5, 0]) + difference() { + cube([QI_PCB_LENGTH + 2*wall, QI_PCB_WIDTH + 2*wall, QI_PCB_HEIGHT + 1], center=true); + cube([QI_PCB_LENGTH + PRINT_TOLERANCE, QI_PCB_WIDTH + PRINT_TOLERANCE, QI_PCB_HEIGHT + 2], center=true); + } +} + + +// ============================================================================ +// MODULE : Électronique (Visualisation uniquement) +// ============================================================================ +// Représentation simplifiée des composants pour vérifier l'encombrement. +// Ne pas exporter en STL. +// ============================================================================ + +module electronics() { + // --- Batterie LiPo --- + color(COLOR_BATTERY) + translate([0, 0, -10]) + cube([BATT_LENGTH, BATT_WIDTH, BATT_HEIGHT], center=true); + + // --- PCB Central --- + color(COLOR_PCB) + translate([0, 0, 8 + 5]) // Au-dessus de la batterie, sur les entretoises + cube([CENTRAL_PCB_LENGTH, CENTRAL_PCB_WIDTH, CENTRAL_PCB_HEIGHT], center=true); + + // --- ESP32-S3 module (sur le PCB central) --- + color([0.15, 0.15, 0.15]) + translate([0, 0, 8 + 5 + CENTRAL_PCB_HEIGHT/2 + 1.5]) + cube([18, 18, 3], center=true); + + // --- TP4056 (sur le PCB central) --- + color(COLOR_PCB) + translate([20, 0, 8 + 5 + CENTRAL_PCB_HEIGHT/2 + 1]) + cube([10, 8, 2], center=true); +} + +// PCB Anneau (visualisation, placé dans une face) +module pcb_ring() { + color(COLOR_PCB) + difference() { + cylinder(d=LED_RING_DIAM_EXT, h=LED_RING_HEIGHT); + translate([0, 0, -0.5]) + cylinder(d=LED_RING_DIAM_INT, h=LED_RING_HEIGHT + 1); + } + + // LEDs WS2812B + color(COLOR_LED) + for (i = [0:LED_COUNT-1]) { + angle = i * 360 / LED_COUNT; + r = (LED_RING_DIAM_EXT + LED_RING_DIAM_INT) / 4; + translate([r * cos(angle), r * sin(angle), LED_RING_HEIGHT]) + cube([5, 5, 1.5], center=true); // WS2812B = 5x5mm + } +} + +// PCB Bouchon (visualisation, placé dans une face) +module pcb_cap() { + color(COLOR_PCB) + cylinder(d=CAP_PCB_DIAM, h=CAP_PCB_HEIGHT); + + // Pad capacitif (cuivre) + color([0.8, 0.6, 0.2]) + translate([0, 0, CAP_PCB_HEIGHT]) + cylinder(d=CAP_PCB_DIAM - 5, h=0.1); +} + +// Module NFC PN532 (visualisation) +module nfc_module() { + color(COLOR_NFC) { + cube([NFC_PCB_SIZE, NFC_PCB_SIZE, NFC_PCB_HEIGHT], center=true); + // Antenne + translate([0, 0, NFC_PCB_HEIGHT/2]) + cylinder(d=NFC_ANTENNA_DIAM, h=0.5); + } +} + +// Bobine Qi (visualisation) +module qi_coil() { + color(COLOR_QI) { + cylinder(d=QI_COIL_DIAM, h=QI_COIL_HEIGHT); + // PCB récepteur + translate([0, QI_COIL_DIAM/2 + 5, 0]) + cube([QI_PCB_LENGTH, QI_PCB_WIDTH, QI_PCB_HEIGHT], center=true); + } +} + + +// ============================================================================ +// ASSEMBLAGE PRINCIPAL +// ============================================================================ + +module assembly() { + half = CUBE_SIZE / 2; + + // --- Squelette --- + if (SHOW_FRAME) + color(COLOR_FRAME) frame(); + + // --- Électronique interne --- + if (SHOW_ELECTRONICS) + electronics(); + + // --- Face Dessus (+Z) — NFC --- + if (SHOW_FACE_TOP) + translate([0, 0, half - FACE_TOTAL_DEPTH + EXPLODE_DIST]) + color(COLOR_FACE) face_nfc(); + + // --- Face Dessous (-Z) — Qi --- + if (SHOW_FACE_BOTTOM) + translate([0, 0, -(half - FACE_TOTAL_DEPTH) - EXPLODE_DIST]) + rotate([180, 0, 0]) + color(COLOR_FACE) face_qi(); + + // --- Face Avant (-Y) --- + if (SHOW_FACE_FRONT) + translate([0, -(half - FACE_TOTAL_DEPTH) - EXPLODE_DIST, 0]) + rotate([90, 0, 0]) + color(COLOR_FACE) face_standard(); + + // --- Face Arrière (+Y) --- + if (SHOW_FACE_BACK) + translate([0, (half - FACE_TOTAL_DEPTH) + EXPLODE_DIST, 0]) + rotate([-90, 0, 0]) + color(COLOR_FACE) face_standard(); + + // --- Face Gauche (-X) --- + if (SHOW_FACE_LEFT) + translate([-(half - FACE_TOTAL_DEPTH) - EXPLODE_DIST, 0, 0]) + rotate([0, -90, 0]) + color(COLOR_FACE) face_standard(); + + // --- Face Droite (+X) --- + if (SHOW_FACE_RIGHT) + translate([(half - FACE_TOTAL_DEPTH) + EXPLODE_DIST, 0, 0]) + rotate([0, 90, 0]) + color(COLOR_FACE) face_standard(); + + // --- PCBs dans les faces (visualisation) --- + if (SHOW_PCBS) { + // Anneau + bouchon dans chaque face (exemple face dessus) + translate([0, 0, half - FACE_TOTAL_DEPTH + WALL_THICKNESS + RING_SHROUD_HEIGHT + EXPLODE_DIST]) { + pcb_ring(); + translate([0, 0, LED_RING_HEIGHT + CAP_CONNECTOR_H]) + pcb_cap(); + } + // NFC module (dessus) + translate([0, 0, half - 8 + EXPLODE_DIST]) + nfc_module(); + // Qi coil (dessous) + translate([0, 0, -(half - 4) - EXPLODE_DIST]) + qi_coil(); + } +} + +// ============================================================================ +// RENDU +// ============================================================================ + +if (SHOW_SECTION) { + difference() { + assembly(); + // Coupe en section (plan YZ, moitié +X) + translate([CUBE_SIZE/2, 0, 0]) + cube([CUBE_SIZE, CUBE_SIZE * 2, CUBE_SIZE * 2], center=true); + } +} else { + assembly(); +} + + +// ============================================================================ +// MODULES D'EXPORT (décommenter pour exporter individuellement en STL) +// ============================================================================ + +// Pour exporter une pièce : décommenter la ligne, commenter assembly(), +// puis Exporter en STL (F6 → File → Export STL) + +// frame(); // → frame.stl +// face_standard(); // → face-standard.stl (x4) +// face_nfc(); // → face-nfc.stl (x1, dessus) +// face_qi(); // → face-qi.stl (x1, dessous) diff --git a/3d-model/cube-config.scad b/3d-model/cube-config.scad new file mode 100644 index 0000000..5c2a81f --- /dev/null +++ b/3d-model/cube-config.scad @@ -0,0 +1,86 @@ +// ============================================================================ +// Companion Cube — Configuration Paramétrique +// Version : 0.2.0 +// ============================================================================ +// Toutes les dimensions sont en millimètres. +// Modifier ce fichier pour ajuster les dimensions sans toucher au modèle. +// ============================================================================ + +// --- Dimensions Générales --------------------------------------------------- +CUBE_SIZE = 120; // Arête extérieure du cube (mm) +WALL_THICKNESS = 2.5; // Épaisseur des parois de la coque/face +CORNER_RADIUS = 6; // Rayon des arrondis extérieurs +CORNER_REINFORCE = 10; // Largeur des renforts de coins + +// --- Squelette Interne (Frame) ---------------------------------------------- +FRAME_EDGE_WIDTH = 12; // Largeur des arêtes du squelette +FRAME_EDGE_DEPTH = 12; // Profondeur des arêtes du squelette +FRAME_FILLET = 2; // Congé sur les arêtes du squelette +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 + +// --- 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 + +// --- LEDs (PCB Anneau — Étage B) -------------------------------------------- +LED_COUNT = 12; // Nombre de WS2812B par face +LED_RING_DIAM_EXT = 70; // Diamètre extérieur de l'anneau LED +LED_RING_DIAM_INT = 40; // Diamètre intérieur (ouverture d'air) +LED_RING_HEIGHT = 1.6; // Épaisseur du PCB anneau +RING_SHROUD_HEIGHT = 6; // Hauteur de la chambre de diffusion +RING_SHROUD_WALL = 1.5; // Épaisseur paroi du shroud + +// --- Capteur (PCB Bouchon — Étage A) ---------------------------------------- +CAP_PCB_DIAM = 35; // Diamètre du PCB bouchon +CAP_PCB_HEIGHT = 1.6; // Épaisseur du PCB bouchon +CAP_CONNECTOR_H = 4; // Hauteur des connecteurs 2.54mm + +// --- NFC (Face du dessus uniquement) ---------------------------------------- +NFC_PCB_SIZE = 43; // Taille du module PN532 (carré) +NFC_PCB_HEIGHT = 5; // Hauteur du module PN532 avec antenne +NFC_ANTENNA_DIAM = 35; // Diamètre de l'antenne NFC + +// --- Charge Qi (Face du dessous uniquement) --------------------------------- +QI_COIL_DIAM = 50; // Diamètre de la bobine Qi réceptrice +QI_COIL_HEIGHT = 3; // Épaisseur de la bobine Qi +QI_PCB_WIDTH = 30; // Largeur du PCB récepteur Qi +QI_PCB_LENGTH = 20; // Longueur du PCB récepteur Qi +QI_PCB_HEIGHT = 2; // Épaisseur du PCB Qi + +// --- Batterie --------------------------------------------------------------- +BATT_LENGTH = 70; // Longueur batterie LiPo +BATT_WIDTH = 50; // Largeur batterie LiPo +BATT_HEIGHT = 10; // Épaisseur batterie LiPo (2500mAh ~) +BATT_TOLERANCE = 1; // Jeu autour de la batterie + +// --- PCB Central (Motherboard) ---------------------------------------------- +CENTRAL_PCB_WIDTH = 60; // Largeur du PCB central (ESP32-S3 + TP4056 + CW2015) +CENTRAL_PCB_LENGTH = 60; // Longueur du PCB central +CENTRAL_PCB_HEIGHT = 1.6; // Épaisseur du PCB +CENTRAL_COMP_H = 8; // Hauteur composants (ESP32-S3 module) + +// --- Aération --------------------------------------------------------------- +AIR_HOLE_DIAM = 30; // Diamètre de l'ouverture d'air centrale (face intérieure) + +// --- Tolérances d'Impression 3D ------------------------------------------- +PRINT_TOLERANCE = 0.2; // Jeu général pour emboîtement +PRINT_LAYER_H = 0.2; // Hauteur de couche standard + +// --- Rendu ------------------------------------------------------------------ +$fn = 60; // Résolution des cercles (augmenter pour le rendu final) + +// --- Couleurs pour la visualisation ---------------------------------------- +COLOR_FRAME = [0.3, 0.3, 0.3]; // Gris foncé — squelette +COLOR_FACE = [0.6, 0.6, 0.6, 0.85]; // Gris clair semi-transparent — faces +COLOR_MEMBRANE = [0.8, 0.8, 0.8, 0.5]; // Blanc translucide — membrane tactile +COLOR_PCB = [0.1, 0.5, 0.1]; // Vert — PCBs +COLOR_LED = [1.0, 0.9, 0.3]; // Jaune — LEDs +COLOR_BATTERY = [0.2, 0.2, 0.6]; // Bleu foncé — batterie +COLOR_NFC = [0.6, 0.1, 0.1]; // Rouge — module NFC +COLOR_QI = [0.8, 0.5, 0.1]; // Orange — bobine Qi