Gehäuse-Design und 3D-Druck mit OpenSCAD: RFID-Reader
In der Sparte Mikrocontroller / Arduino meiner Website habe ich bereits mein letztes Projekt, den RFID-Reader mit OLED-Anzeige und Protokollierung auf SD-Karte vorgestellt.Nur befindet sich noch alles im Entwicklungsstadium und alle Verbindungen sind auf einem Breadboard gesteckt und die Module liegen lose daneben.
So soll das natürlich nicht bleiben, sondern die Einzelteile sollen in ein kompaktes Gehäuse wandern, damit die Schaltung nicht einstaubt, alles an seinem Platz ist und ich nicht doch ausversehen mal ein Kabel rausrupfe. Außerdem kann ich meine Schaltung im Gehäuse viel einfacher mit irgendwohin nehmen.
Bei meinem letzten, größeren Gehäuseprojekt mit dem Countdown-Wecker habe ich die ganzen Verbindungen direkt an die Blue Pill angelötet.
Diesmal will ich einen anderen Weg gehen und ohne das Löten für die Verbindungen auskommen und stattdessen Dupont-Kabel verwenden. Dafür will ich die Steckerleiste so auf die Blue Pill löten, dass die Pins nach oben schauen. Dann kann icf Female-to-Female-Jumperkabel verwenden, um die Module mit dem Mikrocontroller zu verbinden.
Ansonsten ist mein Vorgehen wieder:
- Einzelne Module ausmessen und Bumper dafür drucken
- Die Schaltung vom Breadboard lösen und statt der dortigen M/F (Male to Female) Kabel dann F/F-Jumperkabel (Female to Female) benutzen
- Die Schaltung noch einmal testen, ob alles funktioniert und richtig verdrahtet ist
- Gehäuse-Basis designen mit Ausschnitten, in den die Module samt Bumper passen
- Module einbauen und Schaltung testen
- Gehäuse-Oberteil bzw. Front designen, evtl. mehrfach als Folie drucken und anpassen, denn hier kommt es auf Genauigkeit an, weil direkt im Blickfeld.
- Basis und Oberteil lose zusammenbauen
- Fertiges Projekt testen
- Basis und Oberteil fest zusammenbauen
Bumper für die Module ausdrucken
Damit die Pins der Module nicht den Tisch verkratzen, um die Modulunterseiten zu isolieren und um Kurzschlüsse zu vermeiden und um die Module besser im Gehäuse verbauen zu können, drucke ich mir für jedes Modul einen sogenannten Bumper. Das ist ein kleiner Rahmen, in den das Modul gesteckt werden kann.
Meist drucke ich den Bumper mit einem Boden aus, so dass ich das Modul samt Bumper irgendwo mit doppelseitigem Klebeband oder Klebeknete hin kleben kann. Damit das Modul nicht aus dem Bumper herausfallen kann, auch nicht bei Überkopfmontage, muss es straff im Bumper stecken. Damit, den Bumper 0.1 bis 0.15 mm breiter zu drucken als das Modul eigentlich ist, habe ich hier gute Erfahrungen gemacht.
Für das Designen meiner Gehäuse nutze ich die Software OpenSCAD. OpenSCAD ist eine kostenlose 3D-Design Software und für Windows, Linux und Mac OS verfügbar. Allerdings verfolgt sie einen etwas anderen Ansatz als die klassischen Design-Tools wie Autodesk Fusion 360, DesignSpark Mechanical, FreeCad, Tinkercad und wie sie alle heißen - bei OpenSCAD wird ein 3D-Objekt nicht mit der Maus gezeichnet, sondern mit einer eigenen Beschreibungssprache umschrieben.
Es handelt sich also um so eine Art Programmiersprache. Man braucht schon ein gerüttelt Maß räumliches Vorstellungsvermögen, um mit OpenSCAD klarzukommen und es darum eher nur für einfachere Objekte zu gebrauchen - zumindest für Anfänger.
Dann hat es aber viele Vorteile: Man kann z. B. Teilobjekte in For-Schleifen wiederholt clonen und in bestimmten Abstand positionieren, anstatt diese einzeln per Maus in einem gewöhnlichen CAD-Programm zu positionieren.
Und da man alles per Text eingibt, muss man bei ähnlichen Objekte nur ein paar Parameter anpassen, um super schnell ein angepasstes Objekt zu rendern.
Genau das habe ich für meine Bumper gemacht. Werfen wir einen Blick auf den OpenSCAD-Code dazu:
// genereller Bumper für Platinen.
// mit 100% infill drucken
breite=23.2; // Breite der Platine
laenge=53.7; // Länge der Platine
hoehe=1.7; // Dicke der Platine
pinhoehe=3; // wieviel stehen unten die Pins über?
wandstaerke=1.6; // wie stark sollen die Außenwände sein?
auflagebreite=1.5; // wie breit soll die Auflagefläche für die Platine sein?
boden=0.4; // 0.0, wenn kein Boden gewünscht
union() {
difference(){
translate([0,0,0]) { // Außenmaße = Platinenmaße + 5mm auf jeder seite
//cube( [54.9, 61.5, 4.0]);
cube( [breite+wandstaerke*2, laenge+wandstaerke*2, hoehe+pinhoehe]);
}
translate([wandstaerke,wandstaerke,pinhoehe]) { // hier wird die Platine reingesteckt (platinenhöhe 1.6 mm)
cube( [breite, laenge, hoehe]);
}
translate([wandstaerke+auflagebreite,wandstaerke+auflagebreite,0]) { // hier ist noch Platz unter der Platine für die Pins bis zum boden = ergibt einen rahmen
cube( [breite-auflagebreite*2, laenge-auflagebreite*2, pinhoehe]);
}
translate([breite/2-4.5+wandstaerke,0,pinhoehe]) { // aussparung für USB an der langen Seite
cube( [9, 6, 10]);
}
}
//boden
translate([0,0,0]) { // Außenmaße = Platinenmaße + 5mm auf jeder seite
cube( [breite+wandstaerke*2, laenge+wandstaerke*2, boden]);
}
}
Die hier verwendeten Anweisungen sind:
- union: erstelle die Elemente im Codeblock (zwischen den geschweiften Klammern) und verbinden sie miteinander.
- difference: erstelle das erste Element des Blocks und schneide daraus die weiteren Elemente des Blocks aus
- translate ( [x,y,z] ]: zeichne das Element des Blocks an angegebener Position
- cube ( [x,y,z] ]: zeichne einen Quader mit angegebener Breite, Länge, Höhe
Verbinden der Einzelteile ohne Breadboard
Diesmal wollte ich nicht löten, sondern die Kabel stecken. Die Jumperkabel sind eh sehr billig und die Löterei doch immer ein Aufwand. Besonders, wenn man sich mal vertut, ist es dann einfacher ein Kabel umzustecken statt eine Lötverbindung zu trennen und woanders wiederherzustellen.Dazu habe ich die Header-Leisten auf der Blue Pill einfach mit den Pins nach oben eingelötet, so dass ich hier die Module mit F/F-Jumperkabeln anschließen kann:
Bei der Kabellänge muss man natürlich aufpassen, dass die Kabel nicht zu kurz sind und die Komponenten in das Gehäuse passen. Zu lange Kabel hingegen sind auch nicht gut, weil diese erstens auch irgendwo untergebracht werden wollen, es also unübersichtlich wird und zweitens, weil es dann eher zu Störungen kommt. Wobei das Zweitens wohl nicht so ins Gewicht fällt. Ich glaube, wenn ich überall 20 cm lange Kabel benutzt hätte, kämen es nicht zu Störungen in der Schaltung.
Apropos Störung: Da hatte ich ein sehr seltsames Phänomen: Außerhalb des Gehäuses (und natürlich auch auf dem Breadboard) funktionierte die Schaltung tadellos, aber als ich sie dann eingebaut hatte, dehnten sich die Sekunden der Echtzeituhr ins Unglaubliche: während einer angezeigten Sekunde vergingen 2 oder 3 echte Sekunden. Der STM32 arbeitete wie in Zeitlupe. Die Fehlersuche später ergab, dass es sich hier wohl um ein nicht richtig aufgestecktes Kabel handelte - womit auch gleich der Nachteil der Kabelage klar wird: die Verbindungen sind nicht so gut wie gelötet.
Design der Gehäuse-Basis
Nachdem die Schaltung noch einmal auf Funktion getestet wurde, geht es an das Design der Gehäuse Basis. Das ist im Prinzip ein großer Block, aus dem Blöcke in der Größe der Module geschnitten werden. Dazu werden die Module samt Bumper ausgemessen und wieder 0.1 bis 0.15 mm Toleranz addiert. Das ermöglicht es, die Module von oben hineinzuschieben, wobei diese mit einem Ritsch bis zum Boden hinuntergedrückt werden und da eigentlich von alleine halten. Evtl. muss die Toleranz hier größer gewählt werden. Das kommt auf die Genauigkeit des eingesetzten 3D-Drucker an. Bei meinem Anycubic i3 Mega haben sich 0.1 bis 0.15 mm aber als sehr guter Wert herausgestellt.Für jedes Modul wird ein Block ausgeschnitten, in den es ganz genau hineinpasst. Zwischen den Modulen sollte man immer ein bisschen Wand lassen, damit der Halt gegeben ist. Natürlich muss man auf die Orientierung der Module achten und darf auch nicht vergessen, interne Kabelkanäle auszuschneiden.
Es ist sehr wichtig, alles genau auszumessen und sorgfältig zu arbeiten, denn der Druck der Basis hat in diesem Fall über 5 Stunden gedauert. Da möchte man ungern weitere fünf Stunden auf den Ausdruck warten.
Das bliebt mir allerdings nicht erspart. Im ersten Durchgang hatte ich die Breite und Länge des OLED vertauscht und nicht genug Platz für die OLED-Header nach unten gelassen. Das zweite Exemplar (5 Stunden später) sah dann erst sehr gut aus, aber beim Kopfüber-Einbau des RFID-Readers habe ich dann gesehen, dass es zu eng wurde. Der Deckel hätte nicht mehr draufgepasst. Also ein dritter Ausdruck, diesmal 1.4 cm höher und in schwarz (weil durchsichtig doch keine so gute Idee war, denn der RFID-Reader deckte die LED sowieso ab). Der hat dann gepasst und ich konnte alles verstauen.
Zwischendurch war dann noch Fehlersuche in der Schaltung angesagt, warum die Sekunden so langsam vergingen. Als der Fehler dann gefunden war, wollte noch ein passender Deckel (in der Grafik oben über der Basis schwebend) designt werden. Den Source-Code für die Basis ist ganz ähnlich wie der bei meiner Anleitung für ein Gehäuse für meinen Countdown-Wecker. Dort könnt ihr genau nachlesen, wie man OpenSCAD zum Design der Basis benutzt. Ich gehe hier nicht noch einmal detailliert darauf ein.
Beim Deckel allerdings habe ich ein neues OpenSCAD-Element, das module eingeführt, dass ich im nächsten Abschnitt etwas näher beleuchte.
Design des Gehäuse-Deckels
Nun braucht es natürlich noch ein hübsches Oberteil zur Abdeckung. Dafür habe ich in der Basis extra 1.6 mm Platz nach oben und zu den Seiten freigelassen, um einen Deckel mittig und kantenabschließend einsetzen zu können. Da das OLED und der RFID-Reader minimal überstehen und wohl ein bisschen Klebeknete zwischen Basis und Deckel nötig sein werden, habe ich dafür mal 0.2 mm eingerechnet, so dass der Deckel "in Wahrheit nur" 1.4 mm hoch sein wird.Bei der OLED-Aussparung kommt es auf Präzision an, den auf dieses Teil wird man die ganze Zeit schauen. Darum soll es möglichst schön werden.
Ganz genau sehen, ob es passt, kann man nur, wenn man es wirklich ausdruckt. Ich bediene mich da gerne des Trickes, erstmal eine dünne Folie zu drucken - hier mit dem Durchbruch für das OLED. Die Folie ist schnell ausgedruckt, spart Filament und es lässt sich schnell sehen, ob es passt.
Wenn man dabei auch nur noch einen Teil der gesamten Folie druckt (wie rechts auf dem Foto zu sehen), dann spart man noch mehr Zeit und Geld (Filament).
Ist die Position des OLED-Durchbruchs überprüft, kann dann der ganze Deckel gedruckt werden.
Außer dem Fenster für das OLED soll der Deckel nur zwei Kanten zum Anlegen einer RFID-Karte haben und ein RFID-Logo in Höhe der RFID-Antenne, die sich ja direkt unter dem Deckel in Form des RC522-Moduls befindet. So weiß man, wo man die Karte bzw. das Tag anlegen muss.
Das RFID-Logo soll ganz ähnlich dem auf dem RFID-Modul sein: kreisförmig sollen sich Wellen von einem Zentrum wegbewegen. Das Logo möchte ich nur "eingraviert" haben, sprich: es soll nur der oberste Layer fehlen.
Um das Logo mit OpenSCAD zu entwerfen, habe ich ein bisschen tiefer in die Trickkiste gegriffen als bisher. Den Code dafür möchte ich jetzt vorstellen und erläutern.
Das Logo besteht aus Ringen, die vom Außendruchmesser (40 mm) in 5 mm Schritten im Durchmesser kleiner werden und jeweils 1 mm breit sind. Die Ringe werden danach wieder durchbrochen, indem ich zwei Quadrate um 45° drehe und dort den Deckel wieder komplett aufbaue.
Das sieht jetzt auf der OpenSCAD-Vorschau komisch aus, aber die zwei Quadrate und die Deckeloberseite sind auf genau der gleichen Ebene, so dass man später keine Quadrate sieht, sondern nur die Wellen, die einen Layer tief in den Deckel eingraviert sind.
Der Code für den Deckel sieht wie folgt aus:
// Deckel //////////////////////////////////////////////////////////////////////////
// RFID-Zeichen
dmMark=40;
xMark=xxGes/2+16;
yMark=80;
tMark=0.2; // wie tief soll die Marke graviert werden?
// zum gucken, wie es übereinander passt zusammen mit Basis
zDeckel=0; //zzGes+20; // 0;
zzDeckel=1.4; // 0.2 mm Platz lassen für Klebeknete
difference() {
union() {
translate ( [wand, wand, zDeckel] ) {
cube( [xxGes-2*wand, yyGes-2*wand, zzDeckel] );
}
// Rahmen/Vertiefung Kreditkarte (norm 85.6x54.0, +.5 = 86.1x54.5)
// vom rechten Rand (wo USB Port) einschiebbar, damit leichter entnehmbar
translate ( [wand, yyGes-60-wand, zDeckel+zzDeckel ] ) {
cube( [xxGes-wand*2, 60, 1]);
}
}
// Rahmen/Vertiefung Kreditkarte (norm 85.6x54.0, +.5 = 86.1x54.5)
translate ( [wand, yyGes-60-wand+wand, zDeckel+zzDeckel ] ) {
cube( [xxGes-wand*3, 60, zzDeckel]);
}
// Aussparung Display (nur Anzeigefläche 14.4x26.0
translate ( [xOLED+6.0+.5, yOLED+2.9, zDeckel] ) {
cube( [14.4, 26.6-.8, zzDeckel]);
}
// Markierung, wo die Mitte der Antenne ist
// ein Kreis, wo der RFID-Reader kopfüber mit Bumper eingeklebt ist
translate ( [xMark, yMark, zDeckel+zzDeckel] ) {
for (i= [dmMark:-5:2]) {
ring( dm=i, wi=1, hi=tMark*2);
}
}
} // end diff
difference () {
// Dreiecke wieder füllen für RFID-Zeichen
translate ( [xMark, yMark, zDeckel] ) {
rotate ( [0,0,-45] ) {
cube ( [20, 20, zzDeckel] );
}
rotate ( [0,0,135] ) {
cube ( [20, 20, zzDeckel] );
}
}
// Zipfel unten weg
translate ( [xxGes-2, 50, 0] ) { cube ( [200, 200, 200] ); }
}
module ring (dm, wi, hi) { // dm=diameter, wi=width, hi=height
difference () {
cylinder ( d=dm, h=hi, center = true); // $fn=72 $fn=36
cylinder ( d=dm-wi, h=hi, center = true);
}
}
Und wenn wir mal etwas am Modul ändern müssen, dann müssen wir nur einmal die Zeilen im Modul ändern und schwupp-di-wupp passen auch alle Stellen, die das Modul aufrufen. Das spart uns also jede Menge Arbeit und macht das Ganze übersichtlicher.
Einem Modul kann man (muss man aber nicht) Parameter mitgeben, damit es weiß, was er wie tun soll. Bei uns ist das für das Modul ring der Durchmesser dm, die Breite wi und die Höhe hi. Wie sagen also: Mach uns einen Ring mit 1 mm Breite und 1 cm Durchmesser bei 2 mm Höhe durch den Aufruf ring (1, 10, 2). Das erzeugt einen Körper, der an Ort und Stelle eingefügt wird.
Das Modul macht nichts anderes als einen großen Zylinder zu erzeugen, in dessen Mitte ein um die Breite wi Zylinder wieder abgezogen wird (difference). Übrig bleibt ein Ring.
Wenn wir im aufrufenden Teil (wie es bei uns der Fall ist) gerade in einem Difference-Abschnitt sind, dann wird der Ring abgezogen, also ausgestanzt.
translate ( [xMark, yMark, zDeckel+zzDeckel] ) {
for (i= [dmMark:-5:2]) {
ring( dm=i, wi=1, hi=tMark*2);
}
}
Mit translate haben wir einen Mittelpunkt festgelegt, der für alles innerhalb der geschweiften Klammern gilt. Alle unsere Ringe haben also denselben Mittelpunkt.das i in der For Schleife nimmt nacheinander die Werte 40, 35, 30, 25, 20, 15, 10 und 5 an und graviert und 8 konzentrische Ringe.
So ist die Aufgabe mit ein paar Zeilen erledigt und wie müssen uns nicht x-mal mit leicht anderen Parametern wiederholen.
Großer Vorteil von dem Modul-Aufruf hier ist der Folgende. Wir befinden uns gerade im Difference-Modus, es wird also alles abgezogen. Man könnte jetzt für einen Ring einen großen Zylinder abziehen - aber wie stellt man dann wieder den etwas kleineren Zylinder innen her? Wir wollen ja schließlich einen Ring. Hier müsste wir schon außerhalb einen Union erstellen. Das wird sehr kompliziert und unübersichtlich. Mit dem Modul bekomme wir einen fertigen Ring, der einfach innerhalb des Difference-Modus abgezogen wird.
Wenn wir mehrere Module wie ring haben, die wir immer wieder gebrauchen, können wir uns eine eigene, kleine Library bauen, die wir mit include einbinden können. Die OpenSCAD-Sprache sozusagen um unseren eigenen Befehle erweitern.
Module können noch mehr. Ganz genau nachzulesen im OpenSCAD-Wiki.
Hochzeit von Basis und Deckel
Bevor der Deckel dann fest mit der Basis verklebt wird, teste ich natürlich noch einmal alle Funktionen. Dann kommt der Deckel drauf und der RFID-Reader ist fertig. Im abschließenden Funktionstest wird noch einmal überprüft, ob die RFID-Tag auch gut durch das Plastikgehäuse gelesen werden gut - funktioniert wunderbar.Videos
Ich habe zwei Videos gemacht: Einmal eines über die Progammierung mit OpenSCAD, sozusagen die Theorie und eines, wie ich die Schaltung ins Gehäuse einbaue, sozusagen die Praxis.Eventuell ist es ganz praktisch, mit der Theorie anzufangen. Wenn es da zu abstrakt wird, kann man das zweite Video starten und dort nachschauen, wie das Ganze in echt später aussehen wird - und danach wieder mit der Theorie weitermachen. Oder auch anders. Jeder wie er es mag und am besten klarkommt. Das ist der Vorteil, dass ich das auf zwei Videos aufgeteilt habe.
Die "Theorie": Vorstellung der Schaltung, Design/Programmierung des Gehäuses in OpenSCAD: