Portable Vector Network Analyzer: NanoVNA zum LoRa 868 MHz Antennen vermessen einsetzen

Ich habe mich ja schon länger mit Meshnetzwerken beschäftigt. Seit über einem Jahr hatte ich einen Solarknoten für Meshtastic auf dem Dach (mittlerweile bin ich aber auf MeshCore migriert mit allen Geräten). Was mich jedoch die ganze Zeit über wirklich genervt hat, war, dass ich keine Möglichkeiten hatte als Normalsterblicher mal zu überprüfen, ob die Antennen die ich für das Meshnetz einsetze überhaupt funktionieren.

VNA

Stellt sich raus, dafür braucht man einen Vector Network Analyzer bzw. ein SWR Meter bzw. ein Stehwellenmeßgerät.

Wenn man so ein Teil hat, kann man die Parameter die ausschlaggebend sind für das Aussenden und den Empfang von Radiowellen, selber überprüfen. Das ist kein Mal-eben-so-Prozess, aber es geht. Wenn man nicht zufällig zuviel geld rumliegen hat, dann landet man bei einem Low-Budget-Meßgerät und nicht bei dem „Porsche“ ZVA 40 von Rohde&Schwarz.

NanoVNA-H

Ich hab mir also den NanoVNA-H zugelegt. Das „H“ steht für die Screengröße, es gibt auch den „H4“, der hat einen 4 Zoll Screen. Meiner ist nicht größer als eine Zigarettenschachtel. Das ist ein kleines Gerät mit zwei Standardanschlüssen für sogenannte SMA-Schraub-Stecker-Verbindungen.

Bevor man mit dem Ding irgendwas sinnvolles tun kann, muss man es kalibrieren, dann erstmal rausfinden was die ganzen Menüs alles sind… rausfinden, was man davon alles ignorieren kann, weil man es gar nicht benötigt und dann braucht man eine Antenne zum messen.

Ich hab sehr suchen müssen, bis ich was vernünftiges fand, was mir den NanoVNA in der Benutzung nachvollziehbar erklären konnte. Gefunden habe ich bislang zwei Webseiten die etwas Hilfe hatten für mich als Laien. Die Webseite bzw. das github Repository für die Firmware meines Gerätes war da leider nicht sonderlich hilfreich. Die hatte aber hilfreiche Software, um mit Python Screenshots von dem Gerät zu holen.

Die zwei Webseiten die ich fand waren:

Anwendungskurs Netzwerkanalisator (NanoVNA)

In einer Seite werden verschiedene Aspekte des NanoVNA der mini Vektor Netzwerkanalysator in einem Anwendungskurs in 11 Teilen vorgestellt.
URL: https://www.darc.de/der-club/distrikte/n/ortsverbaende/01/technik/nanovna/

NanoVNA Praxisguide für echte Messungen

Zitat von der Webseite:

Wenn du dir einen NanoVNA gekauft hast, um „mal eben SWR zu checken“, bist du schon auf dem richtigen Weg – aber ein NanoVNA kann deutlich mehr als nur eine einzelne SWR-Zahl anzeigen.

Ja, ist aber auch nicht so einfach die einzelne SWR-Zahl auf den Screen zu bekommen. Und die ist ausschlaggebend!
URL: https://nexttechworld.com/de/amateurfunk/nanovna-praxisguide/

Des weiteren habe ich dann später nochmal intensiver nach PDF-Dokumenten das Web durchsucht und bin dabei auf folgende Exemplare gestoßen:

NANO NANOVNA V2 USER MANUAL (NanoVNA_V2_UserManual.pdf) und THE MISSING MANUAL by BILL RUGGIRELLO (TheMissingManualForThe_NanoVNA_V2Plus4.pdf) und Der NanoVNA (Nano_H_Deutsch_2020.pdf).

Messen, gar nicht so einfach!

Was ist OPEN, was ist SHORT, was ist LOAD? Ich musste erstmal neues Vokabular lernen. Spoiler: Das bezeichnet die abgebildeten Steckeraufsätze, die man auf den Meßanschluss schrauben muss, um einen Kurzschluss, ein offenes Ende und einen Widerstand mit 50 Ohm zu messen. Und genau das muss man zuerst messen, um das Gerät zu kalibrieren. Ohne kalibrierung geht nichts!

Hier mal ein Screen, der den SWR-Wert misst für die bei meinem LilyGo-T-Echo mitgelieferte Stummelantenne. Spoiler, für die 868MHz (für die die Antenne angeblich ausgelegt ist) ist der Wert (Siehe Meßpunkt M1) relativ schlecht. Hingegen ist die Antenne offenbar für 760Mhz viel besser geeignet (siehe Meßpunkt M2) oder aber für 1GHz (siehe Meßpunkt M3).

Hier sieht man wie ich das ganze Zeug auf dem Tisch liegen habe. So hab ich die Antenne aber nicht gemessen. Ich habe die Antenne senkrecht hochgehalten und ausschließlich an den isolierten Bereichen des Koaxialkabels gehalten, um nicht mit der Schirmung (blanke/messingfarbene Metallflächen der SMA-Konnektoren) in Berührung zu kommen, denn das verfälscht das Meßergebnis sehr.

Messen, messen, messen, … Stummel Antenne

Hier sieht man mal verschiedene Screens, die ich beim Messen konfiguriert habe.

  1. SWR: Zeigt den Verlauf der Meßwerte um den Wert 868MHz mit einer Spannweite von 500MHz an. Der Marker M1 markiert die Frequenz 868MHz, da sollte der SWR-Wert im idealen Falle am geringsten sein. Wie man sieht ist er das nicht.
  2. LOGMAG: Das LOGMAG Diagramm mit einer dB Achse
  3. Smith: Ein Smith Diagramm. Ich hab ehrlich gesagt keine Ahnung was das anzeigt.
  4. Resistance: Das Diagramm für Resistance. Es zeigt Wiederstand in Abhängigkeit von der Frequenz an… hmmmm… bloss was bedeutet das?
  5. Alle Diagramme gleichzeitig.
  6. Mit dem DISPLAY Menü bestimmt man, welche Kurven gezeigt werden sollen (4 Farben)
  7. Pro Kurve (aka TRACE) legt man das FORMAT (was man messen will) fest und die SCALE. Es hilft bei der SCALE einfach mal AUTOSCALE zu tippen.
  8. Für das FORMAT wählt man SWR, um den wesentlichen Wert für die Antenne zu bestimmen.
  9. Um überhaupt einen Frequenzbereich festzulegen der einen interessiert, ruft man das STIMULUS Menü auf
  10. Im STIMULUS Menü kann man die Frequenz wählen, die CENTER sein soll (die also im Fokus der Untersuchung steht)
  11. Man tippt dort 8, 6, 8 und dann M, um 868 MHz festzulegen
  12. Das letzte Diagramm zeigt, wie man mit den Markern M1-M3 verschiedene Stellen der Kurve im Blick behalten kann, und dafür dann di Werte oben eingeblendet bekommt.

Fazit, die Stummel-Antenne, die eigentlich für 868MHz funktionieren soll, funktioniert besser im Bereich 1GHz oder im Bereich 763MHz, ist somit eher billiger China-Schrott, als eine gute Antenne. Mal gut, dass wir das mal ausmessen konnten.

Sleeve Antenne (Selbstbau)

Dieses hier ist dann schon die fortgeschrittene Version meiner Meßversuche. Ich messe meine selbstgebaute Sleeve-Antenne ein. Die ist auf keinen Fall perfekt, aber sie ist deutlich besser. Danke an der Stelle an Elektra! Denn ohne sie wüßte ich gar nicht von der Möglichkeit einer Sleeve Antenne.

Das Bild zeigt die noch nicht richtig fixierte (Die Abschirmung kann sich noch verschieben) Antenne. Mit Hilfe des NanoVNA habe ich diese Antenne nun soweit verändert, bis ich richtig gute Werte hatte für die SWR-Messung.

Vergleich: Stummel vs. Sleeve

Un hier sieht man den gravierenden Unterschied. Ich habe einmal die Messungen beider Antennen gegenübergestellt. Die selbstgebaute Antenne schlägt das China-Produkt im Handumdrehen aus dem Feld. Und das ist noch die schlecht gebaute Sleeve Antenne. Ich werde eine weitere bauen und dann erneut messen.

Der „Pro“-Meßstand!?

Damit ich die Antennen in absolut vergleichbaren Positionen halten konnte, habe ich mir meine Halteklammern von meinem Werkstatt-Tisch geholt. Das funktioniert tatsächlich richtig gut. Da die Halteklammern selbst mit Silikon überzogen sind, sind sie somit auch gut isoliert. Eventuelle Effekte wegen des Metalls vom Arm der Klammer wirken sich auf alle Antennen im Prüfstand aus, somit kann ich das mal vernachlässigen denke ich.

Mit dem Zwischenergebnis bin ich ganz zufrieden.

Why do I blog this? Ich habe nicht wirklich einfach Infos zu dem NanoVNA finden können, die einem systematisch das Vorgehen zeigen. Hier möchte ich die gefunden Dokumente und Anleitungen für mich selbst archivieren und auch meine Erfahrungen dazu gerne teilen. So ein NanoVNA ist sehr hilfreich die Funktionalität einer Antenne zu beurteilen. Ich habe mittlerweile auch eine andere Antenne, die mit meinem Meshcore Solar-Node mit kam vermessen und die hat Werte mit einer „1“ vor dem Komma für den SWR. Das ist also kein Schrott und ich kann es jetzt selbst beurteilen.

Meine erste 3D Konstruktion mit OpenSCAD

Durch die Verfügbarkeit eines 3D Druckers im Hackerspace, habe ich in der Vergangenheit bereits einige Dinge für meinen Alltag gedruckt. Oftmals bin ich dafür auf einschlägige Webseiten gegangen, die 3D Modelle in einer Art Library vorhalten. Da hab ich dann solange gesucht, bis ich was fand, was mir hilft und habe es runtergeladen, ge-slice’d und gedruckt (mit einem ANYCUBIC Kobra II Max).

DIY

Doch bei einigen dieser Dinge blieb das Gefühl zurück, dass es zwar schon eine Lösung ist, aber halt nur so eine 70-Prozent-Lösung. Schöner wäre es, wenn man die Sachen selbst konstruieren könnte, so dass sie eine 90 bis 99-Prozent-Lösung ergeben. Doch dafür muss man sich mit 3D-Konstruktionsprogrammen beschäftigen. Da hatte ich Bammel vor, bis ich ich dann OpenSCAD genauer angeschaut habe.

3D Konstruktion für Programmierer

OpenSCAD (gesprochen „Open-Ess-Kat“) ist ein Werkzeug, mit dem man seine Konstruktion in Programmcode erzeugt. Und wow, hat das meine Weltsicht auf 3D Konstruktion verändert.

OpenSCAD is software for creating solid 3D CAD objects. It is free software and available for Linux/UNIX, MS Windows and Mac OS X.

Auf Deutsch:

OpenSCAD ist ein freies Modellierungswerkzeug, das 3D-Modelle nicht durch Mausinteraktion, sondern durch textbasierte Skripte beschreibt. Die Sprache folgt funktionalen Prinzipien: Variablen sind unveränderlich, und jeder Entwurf ist reproduzierbar und leicht automatisierbar. Sie ermöglicht so einen präzisen, programmatischen Ansatz für den Modellaufbau.

Ich hatte irgendwann mal Blender probiert (ich denke deren Sculpting Funktionen kommen dem was man hier braucht noch am nächsten), war aber von den Möglichkeiten einfach überwältigt. Die Lernkurve schien mir gewaltig steil zu sein. Nicht so bei OpenSCAD, denn da muss ich nicht in einem Editor mir die Maushand bis zu echten Handproblemen kaputt navigieren. Ich beschreibe einfach was ich benötige mit primitiven geometrischen Grundformen mathematisch in Programmcode.

Was ist die OpenSCAD Scripting Language

Die OpenSCAD-Skriptsprache ist eine funktionale, domänenspezifische Sprache zur Erzeugung von 2D- und 3D-Modellen, die vor allem im Bereich des Computer-Aided-Design (CAD) und 3D-Drucks eingesetzt wird.[1][7]

Möglichkeiten für Nutzer

  1. Skriptgesteuerte Modellierung: Nutzer schreiben Skripte, die geometrische Grundformen (z.B. cube, sphere, cylinder, polygon) definieren und diese durch Transformationen oder Boolesche Operationen (Vereinigung, Differenz, Schnittmenge, Minkowski-Summe) kombinieren.[7]
  2. Parametrisches Design: Wichtige Maße oder Eigenschaften lassen sich über Variablen steuern. Ein einzelnes Skript kann so viele Varianten desselben Objekts generieren, indem nur Parameterwerte angepasst werden.[7]
  3. Funktionale und modulare Struktur: OpenSCAD unterstützt Funktions- und Moduldarstellung, wodurch sich wiederverwendbare Komponenten und Abstraktionsebenen bilden lassen.[1]
  4. Transformationen und Stilmittel: Mit Befehlen wie translate, rotate, scale oder mirror werden Objekte verschoben, gedreht und skaliert. Farb- und Transparenzattribute erlauben visuelle Gestaltung.[2]
  5. Dateiausgabe: Modelle können in Formate wie STL oder DXF exportiert werden – ideal für Slicer-Programme und 3D-Drucker.[1]
  6. Automatisierte Workflows: Durch seine Textbasiertheit lässt sich OpenSCAD leicht in Versionsverwaltungssysteme oder generative Design-Pipelines integrieren.[7]

Typische Leistungsmerkmale

  1. Konstruktive Festkörpergeometrie / Constructive Solid Geometry (CSG): Modelle entstehen aus Kombinationen bzw. Subtraktionen fester Körper mittels Boolescher Operationen.[3]
  2. Funktionaler Programmierstil: Unveränderliche Variablen, rekursive Ausdrücke und modulare Strukturen fördern klare, fehlerresistente Konstruktionen.[1]
  3. Spezialvariablen: Mit reservierten Variablen (z.B. $fn, $fa, $fs) kann der Detailgrad von Rundungen oder die Auflösung von Oberflächen beeinflusst werden.[2]
  4. Vektoren, Felder und Bereiche: Über dynamische Listen und Wertebereiche lassen sich Schleifen und Array-Operationen zur effektiven Geometrieerzeugung verwenden.[2]
  5. Rekursion und Iteration: Auch wenn OpenSCAD nicht Turing-vollständig ist, ermöglichen rekursive Module und Schleifen die Erstellung komplexer, wiederholter Strukturen.[2]
  6. String-Unterstützung und Unicode: Textausgabe und Beschriftungen können mit Unicode-Zeichen realisiert werden, was für parametrische Gravuren oder Skript-Debugging nützlich ist.[1]
  7. Bibliotheken und Erweiterbarkeit: Nutzer können eigene Module oder Community-Bibliotheken importieren. Dadurch entstehen hochgradig konfigurierbare Modelle.[3]

Dank dieser Eigenschaften ist OpenSCAD besonders beliebt bei Ingenieuren, Entwicklern und Makern, die programmatische Präzision, Wiederholbarkeit und vollständige Kontrolle über Konstruktionen bevorzugen.[7][1]

Quellen: 1, 2, 3, 4, 5, 6, 7, 8, 9 (Diese Erklärung wurde mit Hilfe von perplexity.ai erstellt & gegengelesen.)

Jeder Topf braucht ’nen Deckel: Die 90-Prozent-Lösung

Fangen wir mit dem Ergebnis zuerst an. Ich brauchte einen Deckel für eine Metallschale, die ich in der Küche immer für organischen Bioabfall benutze. Da die Schale bislang immer offen rumstand, hat sich gerade im Sommer schnelle eine Population Fruchtfliegen gebildet, die ich kaum mehr in den Griff bekommen habe. Wenn ich doch bloss einen Deckel für diese Schale…

…nun, einige Monate NACH der Feststellung des Problems und einer Lösungsidee und nach ca. 6 Stunden Basteln mit OpenSCAD, dann nochmal ca. 15 Minuten Druck des Griffs und ca. 3 Stunden Druck des Deckels an sich, gibt es eine passende Lösung. Im Bild sieht man die Schale und den Deckel. Der Deckel besteht aus zwei Komponenten Griff und eigentliche Abdeckung, die mit zwei Schrauben verbunden wurden. Griff und Abdeckung habe ich noch mit einem schwarzen Lack aus der Sprühdose lackiert.

Wie kam es aus dem 3D Drucker?

Hier nochmal die etwas detailliertere Sicht auf das fertige Produkt. (Bereits lackiert)

Wie wurde es konstruiert?

Hier sieht man die Abdeckung einmal von unten und einmal von oben. In der Unterseite habe ich versucht eine hexagonale Öffnung für die Mutter zu den beiden Schrauben umzusetzen. Leider war die Abmessung dann zu end. Was ich also für das nächste mal gelernt habe: Insbesondere Öffnungen die eigentlich Bohrungen sein könnten immer 1-2 Millimeter grösser designen als benötigt.

Alle Abmessungen hatte ich vorher mit einem Messschieber und einem Lineal vorgenommen. Aber gerade bei den Abmessungen der Schraubenöffnungen war ich mir echt unsicher ob das klappt. Notfalls hätte ich die halt gebohrt. Das ursprüngliche Design war eine einzige Konstruktion, Deckel mit Griff in einem. Doch für den 3D-Druck sind vor allem frei schwebende Teile ein grosses Problem, daher habe ich Griff und Deckel in zwei Komponenten aufgeteilt und auf eine Schraubverbindung gesetzt.

Der Quellcode für Deckel und Griff

Hier der Quellcode für den Deckel und den Griff. Ich hab den bereits ein wenig refactored für den Deckel. Die Griff-Konstruktion ist noch nicht so schön.

Die Code-Abschnitte für LABEL und LOGO sind Experimente gewesen ein SVG-file als Logo einzubinden und das LABEL war ein Experiment Text mit einem spezifischen Font einzubinden. Beides hat funktioniert, aber leider hätte es den 3D-Druck arg verkompliziert weil ich dann Supportmaterial hätte drucken müssen. Das wollte ich absolut vermeiden.

//  AUTHOR: blazr
//    DATE: OCT 2025
// VERSION: 1.5

// INITIALIZATION
echo( "---------------------------------" );
echo( "INITIALIZING" );
/* [BUILD/ADD] */
// CAP
USE_CAP = true;
// GRIP/HANDLE
USE_GRIP = true;
// LOGO
USE_LOGO = false;
// LABELS
USE_LABELS = false;

/* [CAP] */
// CAP RESOLUTION/QUALITY
cap_resolution = 300; // [20:Low,50:Medium,300:High,600:Perfect]
// COLOR
cap_color = "Silver"; // [Dimgray,Gray,Slategray,Silver,Lightgray,Gainsboro]
// INNER DIAMETER (CM)
cap_diameter_inner = 20.7; // [10:0.1:100]
// HEIGHT (CM)
cap_height = 2.0;  // [1:0.5:50]
// WALL SIZE (CM)
cap_wall_size = 0.5; // [0.5:0.1:5]
// HOLES DIAMETER (CM)
hole_diameter = 0.55; // .01
// SCREW HEAD HEIGHT (CM)
hole_screw_head_length = 0.3; // .05
// SCREW HEAD DIAMETER (CM)
hole_screw_head_diameter = 1.05; // .01
// HEX NUT RADIUS (CM)
hole_hexa_radius = 0.5; // .05
// HEX NUT DEPTH (CM)
hole_hexa_depth = 0.3; // .1

/* [GRIP] */
// COLOR
grip_color = "Dimgray"; // [Dimgray,Gray,Slategray,Silver,Lightgray,Gainsboro]
// HEIGHT (CM)
grip_height = 2.0; // [1:0.5:15]
// WIDTH (CM)
grip_width = 1.5; // [1:0.1:5]
// LENGTH (CM)
grip_length = 6.0; // [4:0.5:30]
// WALL SIZE (CM)
grip_wall_size = 0.5; // [0.5:0.1:5]

/* [LOGO] */
// COLOR
logo_color = "Fuchsia"; // [Fuchsia,DeepPink,Crimson,DarkOrange,Gold,Yellow,GreenYellow,DarkViolet,Aqua,SandyBrown,Wheat]
// SIZE
logo_scale_size = 0.02;  // [0.0025:Tiny,0.005:Small,0.01:Normal,0.02:Bigger,0.04:Big]
// FILENAME (SVG)
logo_filename = "lightbulb.svg";

/* [LABEL] */
// COLOR
label_color = "Gold"; // [Fuchsia,DeepPink,Crimson,DarkOrange,Gold,Yellow,GreenYellow,DarkViolet,Aqua,SandyBrown,Wheat]
// TEXT
label_text = "blazr";
// FONT NAME
label_fontname = "Data Control";
// FONT HEIGHT (CM)
label_size = 3; // [0.1:0.1:10]

// USED TO STOP FOLLOWINg VARS TO APPEAR In CUSTOMIZER
module __Customizer_Limit__ () {}
 
// MISC VARS
model_version = [1, 5, 0];
openscad_version = version();
flicker_correction = 0.005; // NEEDED TO FIX OPENSCAD FLICKERING ON DIFFS IN PREVIEW-RENDER

/**
* CAP WITH A CERTAIN DEPTH AND WALL THICKNESS
*/
module cap( height, radius, wall_size, color_name, color_name_inner ) {
  difference() {
    // OUTER CYLINDER
    color( color_name )
    cylinder(h = height, r = radius, center = false, $fn=cap_resolution);
    // INNER CYLINDER
    height_inner = height - wall_size;
    translate([0.0, 0.0, -flicker_correction]) {
      color( color_name_inner )
      cylinder(h = height_inner-flicker_correction, r = (radius-wall_size), center = false, $fn=cap_resolution);
    }
  }
}

/**
* POLYGON 2D-SHAPE FOR EXTRUSION
*/
module regular_polygon(order = 3, radius = 1) {
     angles=[ for (i = [0:order-1]) i*(360/order) ];
     coords=[ for (th=angles) [radius*cos(th), radius*sin(th)] ];
     polygon( coords );
 }

/**
* HOLE ROUND
*/
module hole( length, radius, color_name, offset_center_x ) {
   translate( [offset_center_x,0,0] ) {
     color(color_name) cylinder(length, radius, radius, $fn = 50);
   }
}

/**
* HOLE HEXAGON
*/
module hole_hexa(length, radius, color_name, offset_center_x, offset_z) {
  translate( [offset_center_x, 0, offset_z] ) {
    color( color_name ) linear_extrude( length ) regular_polygon( 6, radius );
  } 
}

/**
* MAIN MODULE TO CONSTRUCT CAP & GRIP
*/
module main(cap_diameter,cap_height,cap_wall_size,label_text,gh,gw,gs,gl) {
  cap_radius_inner = cap_diameter / 2.0;
  cap_radius_outer = (cap_diameter + (2*cap_wall_size)) / 2.0;
  // HOLE CALCULATIONS
  hole_radius = hole_diameter/2.0;
  hole_spacing = 0.5;      
  hole_length = (2*hole_spacing)+hole_diameter;
  bar_length = (2*hole_length) + gl;
  hole_grip_offset_center = (bar_length/2.0)-(hole_spacing+hole_radius);
  hole_through_length = gs;  
  rotate([0.0, 180.0, 0.0]) { // CONSTRUCTION ALL
    if( USE_CAP ) {
    translate([0,0,-cap_height]) { // CAP CONSTRUTION
      cap_radius = cap_radius_outer;
      difference() { // HOLES HEXAGON
        // DECKEL
        difference() { // HOLES ROUND
          // CAP (BUILD WITH INNER & OUTER CYLINDER)
          cap(
            cap_height,
            cap_radius,
            cap_wall_size,
            cap_color,
            "gray"
          );
          
          // HOLES ROUND THROUGH
          hole_offset_center = hole_grip_offset_center;
          hole_length = cap_height+flicker_correction;
          hole_diameter = 0.5;          
          hole_radius = hole_diameter/2.0;
          // HOLE 1
          hole( hole_length, hole_radius, "yellow", -hole_offset_center );
          // HOLE 2
          hole( hole_length, hole_radius, "yellow", hole_offset_center );
          
      } // difference HOLES ROUND
    
      // HOLES HEXAGON SURFACE
      hole_hexa_offset_center = hole_grip_offset_center;
      hole_hexa_offset_z = cap_height-cap_wall_size-(3*flicker_correction);
      hole_hexa_length = hole_hexa_depth;
      // HOLE HEXA 1
      hole_hexa(
        hole_hexa_length,
        hole_hexa_radius,
        "blue",
        hole_hexa_offset_center,
        hole_hexa_offset_z
      );
      // HOLE HEXA 2
      hole_hexa( 
        hole_hexa_length,
        hole_hexa_radius,
        "blue",
        -hole_hexa_offset_center,
        hole_hexa_offset_z
      );
    } // difference HOLES HEXAGON
        
    // OPTIONAL LABELS ON TOP OF CAP (PROBLEMATIC FOR PRINTING)
    if( USE_LABELS ) {
      label_height = 0.1;
      label_offset_to_center = cap_radius_outer/2.3;
      // LABEL LOWER
      translate([0.0, +(label_offset_to_center-(label_size/2.0)), cap_height]) {
        color(label_color) linear_extrude(label_height) text(label_text, size=label_size,halign="center",font=label_fontname, $fn=300);
      }
      
      // LABEL UPPER
      rotate( [0, 0, 180] ) {
        translate( [0.0, +(label_offset_to_center-(label_size/2.0)), cap_height] ) {
          color(label_color) linear_extrude(label_height) text(label_text, size=label_size,halign="center",font=label_fontname, $fn=300);
        }
      }
    } // if
  } // translate CAP CONSTRUTION
  } // if
  // END OF CAP CONSTRUCTION
  
  // BEGIN GRIP CONSTRUCTION (DEACTIVATED)
  if( USE_GRIP ) {
  difference() {
    translate( [0,0,(gh/2.0)] ) {
      // HANDLE UNION
      union() {
        // UPPER PART WITH HOLE
        difference() {
            color(grip_color)
            cube([gl, gw, gh], center = true);
            translate( [0,0,-gs] ) {
              color(grip_color)
              cube([gl-(gs*2), (2.0*gw), (gh)], center = true);
            }
        }
        // LOWER PART
        translate( [0,0,-((gh-gs)/2.0)] ) {
          color(grip_color)
          cube([bar_length, gw, gs], center = true);
        }
      }
    }
    // HOLES
    translate( [-hole_grip_offset_center,0,-flicker_correction] ) {
      color("yellow") cylinder(hole_through_length+(2*flicker_correction),hole_radius,hole_radius, $fn = 50);
    }
    translate( [hole_grip_offset_center,0,-flicker_correction] ) {
      color("yellow") cylinder(hole_through_length+(2*flicker_correction),hole_radius,hole_radius, $fn = 50);
    }
    // HOLES HEAD
    hole_screw_head_radius = hole_screw_head_diameter/2.0;        
    translate( [-hole_grip_offset_center,0,(hole_through_length-hole_screw_head_length+flicker_correction)] ) {
      color("crimson") cylinder(hole_screw_head_length,hole_screw_head_radius,hole_screw_head_radius, $fn = 100);
    }
    translate( [hole_grip_offset_center,0,(hole_through_length-hole_screw_head_length+flicker_correction)] ) {
      color("crimson") cylinder(hole_screw_head_length,hole_screw_head_radius,hole_screw_head_radius, $fn = 100);
    }        
  } // difference
  }

  // OPTIONAL LOGO
  if( USE_LOGO ) {
    // ADDITIONAL STUFF
    color(logo_color) linear_extrude(0.1)
    translate( [-7.3,0, 0] ) {
      scale([logo_scale_size,logo_scale_size,logo_scale_size]) {
          import(file = logo_filename, center = true, $fn = 100);
        }
      }
      mirror( [0,1,0] ) {
        color(logo_color) linear_extrude(0.1)
        translate( [7.3,0, 0] ) {
          scale([logo_scale_size,logo_scale_size,logo_scale_size]) {
            import(file = logo_filename, center = true, $fn = 100);
          }
        }
      }
    }    
  } // rotation CONSTRUCTION ALL
} // END MAIN MODULE

// EXECUTE PROGRAM
echo( "EXECUTING" );
main( 
  cap_diameter_inner,
  cap_height,
  cap_wall_size,
  label_text,
  grip_height,
  grip_width,
  grip_wall_size,
  grip_length
);

echo( str( "MODEL VERSION: ", model_version[0],".",model_version[1],".",model_version[2] ) )
echo( str( "BINARY VERSION: ", openscad_version[0],".",openscad_version[1],".",openscad_version[2]) );
echo( "COMPLETE" );
echo( "---------------------------------" );

Code als ZIP-Archiv cap_and_grip_1_5_0.zip download.

Mit etwas Zeit, werde ich das noch ein wenig schöner machen, den Code. Ich hätte gerne ein vollständig parametrisierbaren Deckel mit Griff, so dass ich für jedes Gefäß von sagen wie einem Durchmesser von 5 bis 60 Zentimeter einen Deckel konstruieren kann.

UPDATE 1.4.0
Ich hab die Parameter jetzt nach der Dokumentation refactored so dass man eine schöne Ansicht im „Customizer“ hat. Das ist eine optionale Einblendung in OpenSCAD, bei der man die Variablen die die Konstruktion beeinflussen, im GUI verstellen kann und die Änderung sofort sieht.

UPDATE 1.5.0
Jetzt sind alle Parameter über den Customizer wunderbar anpassbar.

UPDATE 1.6.0
Erster Release auf Thingiverse für mich. Bin noch nicht damit zufrieden, dass man die handlebar noch manuell drehen müsste für den Druck. Es fehlen noch die Daten für die eingesetzten Metallschrauben und Muttern. Ich hab da einfach Zeug gegriffen das noch in meiner Werkzeugkiste vorrätig war.

UPDATE 1.7.0
Jetzt auch bei Printables veröffentlicht.

UPDATE 1.8.0
Support für transparente Farben hinzugefügt, einige ASSERT statements hinzugefügt, um Grenzwerte zu prüfen, das Rendersystem zu Beginn sauber initialisiert, die aktuelle Viewport Konfiguration (Kamerasicht und Ausschnitt) per ECHO statement ausgegeben.
Code als ZIP-Archiv universal_cap_1_8_0.zip download.

Customizer Default GUI Customizer Easy GUI

Man kann in dem Customizer sich die Arbeit noch schöner machen, indem man „Description only“ wählt bei der Anzeige der Parameter. Das hängt natürlich davon ab wieviel Arbeit sich der Autor gemacht hat, ob das nützlich ist.

Fazit: Augen auf bei den Einheiten und beim Slicing

Es war nicht so schwer wie gedacht. Es hat Spass gemacht. Man sollte bei der Konstruktion bereits permanent einbeziehen, ob der 3D-Druck ohne Supportstrukturen auskommen wird. Es ist leicht möglich ein grosses Konstrukt in zwei Teile zu teilen. Ich habe mit Hilfe von Translation und Rotation beide Konstrukte abschliessend in die Lage im Raum gebracht, die dann auch auf dem Druckbett des 3D-Druckers verwendet werden sollte. Das hat die Weiterverarbeitung im Slicer vereinfacht.

Beim Slicing musste ich dann nur noch eine einzige Korrektur vornehmen, nämlich das Modell skalieren. Offenbar interpretiert der Slicer die OpenSCAD Masseinheiten als Millimeter. Ich hatte jedoch in Zentimetern gerechnet und kalkuliert. Anfängerfehler.

Weiterer Nachtrag: Wie man in den Fotos sieht, ist die innere Oberflaeche nicht so toll gedruckt worden. Woran es genau lag, kann ich nicht sagen, jedoch hat das Slicing mit dem ANYCUBIC Next Slicer (und der zugehoerigen Druckerkonfiguration) das Problem behoben. Der eingesetzte Prusa Slicer hatte offenbar nicht die richtige Konfiguration beim Druck.

Nachtrag

Ich hab hier nur an der Oberfläche der Fähigkeiten von OpenSCAD gekratzt. Es steht einem letztlich das volle Spektrum der Mathematik zur Verfügung, um sich auszudrücken. Das ist mir beim Lesen der Dokumentation aufgefallen. Das bedeutet, man ist „nur“ durch die eigenen Kenntnisse in Mathematik begrenzt.\

Damit halte ich OpenSCAD für ein wunderbares Werkzeug, um Begleitend Konzepte der Mathematik zu lernen und zu begreifen. Und dabei meine ich „begreifen“ im Sinne von „Begreifen“ es anfassen können. Ich würde mir wünschen dieses Werkzeug (exemplarisch für die Kategorie dieser Werkzeuge) würde Eingang finden in die mathematische Grundbildung junger Menschen. Ich lönnte mir das super im Mathematikunterricht vorstellen und halte das Werkzeug für geeignet spielerisch Mathematik auszuprobieren und zu verstehen.

Basis Template

Da ich nun des öfteren ein neues Projekt mit OpenSCAD begonnen habe, hab ich mir ein kleines Basis Template gebaut, so dass ich nicht immer wieder beu Null beginnen muss.

Mit dem Template werden einige Variablen, die man immer gut brauchen kann definiert. Auch wird der Customizer sofort benutzt. Das Template unterstuetzt zwei Konstruktionen, die einzeln, oder kombiniert ausgegeben werden können.

Basis Template zum runterladen: openscad_base_template_0_1_0.zip

Why do I blog this? Ich hatte ein wenig Spass dran. Und ich hab eine Menge gelernt. Vor allem hab ich den Schrecken vor 3D Konstruktionen verloren. Es kostet zwar einiges an Überlegungen, bis das was man sieht auch den eigenen Vorstellungen entspricht, aber man kann es programmieren. Und DAS ist VIEL besser als es zu konstruieren per Hand.

Was ist wirklich schwierig fand, war das Denken in geschweiften Klammern. Welche Translation bezieht sich jetzt nochmal auf welche Objekte? Ich finde es schade, dass man das Ergebns einer „Action“ (so nennt man eine Zeile die eine graphische Primitive umsetzt) nicht in einer Variablen speichern kann. Da muss ich nochmal schauen, ob das über „Module“ besser geht. Denn wenn ich eine gleiche Bohrung nicht nur einmal verwende, dann moechte ich das ungern per Copy & paste tun. Vermutlich ist der richtige Weg hier ein neue „Module“ zu definieren.

Das neue Horner Bad in Bremen

Es ist soweit… nach langer Zeit war ich endlich mal wieder ordentlich Schwimmen. Nicht, dass ich jetzt 2 Jahre keine Lust gehabt hätte, aber wir hatten einerseits Covid-19 und dann wurde mein Lieblingsfreibad (Das Horner Bad) leider abgerissen.

ABER… es wurde abgerissen, um ein neues viel cooleres Freibad zu bauen PLUS ein wettkampftaugliches 10 x 50m Hallenbad mit allem Schnick und Schnack. Und am Samstag den 4. Juno 2022 war Eröffnung. Leider konnte ich an diesem Tag nicht hingehen, aber eine Woche später dann ist es mir gelungen.

Fotos

Wettkampfbad (Indoor)

Freibad (Outdoor)

Fazit

Ich bin schwer begeistert. Vor allem aber bin ich erleichtert, dass es die Halle mit den 10 x 50m Bahnen gibt. Ein weiteres Planschbad braucht niemand. Echten Sport machen zu können ist so wichtig. Und dass neue Bad erfüllt diese Bedürfnisse. Klasse gemacht kann man da nur sagen! Danke an die Baufirmen und Bauleitung die da tatsächlich verantwortungsvoll mit unserem Steuergeld ein neues Highlight für Bremengeschaffen haben.

Update: 13.5.2023

Das Bad hat eine echt schoene Bepflanzung bekommen. Der Fruehling laesst gruessen. Auch sonst ist das Bad nach wie vor nice.

Die Belegungsplaene fuer die Bahnen sind nun auch so beschrieben, dass man klar erkennen kann, wann 50m und wann 25m Betrieb ist und wann Flachwasser und wann Normaltiefe. Sie verbessern also auch! Toll.

Aktueller belegungsplan Stand 13.5.2023

Why do I blog this? Ich bin eine Wasserratte. Ich liebe Schwimmen. Nirgends fühle ich mich mehr mit der Natur verbunden als wenn ich tief ins Wasser eines Sees oder eines Schwimmbades eintauchen kann und lautlos durch das Wasser gleiten darf. Für mich ist das magisch. Das neue Horner Bad (vor allem das Hallenbad) erlauben vor allem sportliches Schwimmen. Das war meiner Ansicht nach überfällig. Denn Spassbäder haben wir genug, wer aber mal ein paar Bahnen richtig Vollgas geben möchte, der muss lange suchen, oder im Werdersee, der alten Weser oder im Stadtwaldsee schwimmengehen. Das ginge schon klar, aber gerade im Winter ist das halt eher schwierig. Ich hab zwar einen Neopren-Shorty, aber eher für’s Windsurfen und nicht zum Schwimmen.