Files
ft-parts/ft_util.scad
T

276 lines
11 KiB
OpenSCAD

// --------------------------------------------------------------------
// A collection of useful modules to create Fischertechnik parts,
// mainly grooves, holes and pins to be added or substracted
// --------------------------------------------------------------------
// Please be aware that OpenSCAD approximates the size of a hole by
// using a polygon according to the $fn variable. The corner points of
// the polygon are lying on the circle. Thus the resulting hole is
// always smaller than the diameter of the hole! Increasing the $fn
// variable helps but increases calculation time. The best is to try
// out the size and adopt the settings accordingly. It does not help
// to size the final parts in the slicer, because all of the part will
// be resized, not only the hole!
// See https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/Other_Language_Features#Circle_resolution:_$fa,_$fs,_and_$fn
// for details.
// Constants used throughout the fischertechnik files. Although all
// values in OpenSCAD are constants technically spoken, these are some
// kind of special. They define standard values used everywhere and
// changing them might influence how a part is redered and exported
// to the final stl file for printing.
// The standard grid size of fischertechnik parts is 15 mm. Most
// parts fit into that grid.
FT_GRID_SIZE = 15;
// The basic block has the same size as the grid. The constant name
// is just for convinience
BASIC_BLOCK_SIZE = FT_GRID_SIZE;
// Half of the block size is used quite often, so it has its own
// constant
BASIC_BLOCK_HALF = BASIC_BLOCK_SIZE / 2;
//
WALL_THICKNESS = 2;
// The Length of the groove is the same as the grid/basic block size.
GROOVE_LENGTH = FT_GRID_SIZE;
// For values from different people see:
// https://forum.ftcommunity.de/viewtopic.php?f=38&t=3709
// The radius of a groove, makes a diameter of 4.5 mm
// GROOVE_RADIUS = 2.25;
// GROOVE_DIAMETER = GROOVE_RADIUS * 2;
GROOVE_RADIUS = 2.1;
GROOVE_DIAMETER = GROOVE_RADIUS * 2;
GROOVE_CENTER = 2.4;
GROOVE_BREAKTHROUGH = 3.0;
FLAT_GROOVE_OFFSET = 0.6;
PIN_DIAMETER = 4;
PIN_BASE_WIDTH = 3;
// PIN_BASE_LENGTH = 1.2;
PIN_BASE_LENGTH = 1.0;
PLATE_HOLE_DIAMETER = 4.2;
PLATE_BREAKTHROUGH = 3.2;
PLATE_HOLE_CORRECTION = 0.8;
PLATE_CUTOFF_HEIGHT = 2.8;
// those settings work for the U-girder,
// but not for the base plate where
// PLATE_CO_TOP_LENGTH is too long!
PLATE_CO_TOP_WIDTH = 3.0;
PLATE_CO_TOP_LENGTH = 6.0;
PLATE_CO_BOTTOM_WIDTH = 4.3;
PLATE_CO_BOTTOM_LENGTH = 4.3;
PLATE_CO_CIRCLE_DIAMETER = 4.1;
PLATE_CO_CIRCLE_OFFSET = 0.2;
EYELET_HEIGHT = 2.5;
MANIFOLD_CORRECTION = 0.1;
$fn=104;
// --------------------------------------------------------------------
// part for cutting out a clip axle hole
// --------------------------------------------------------------------
module clip_axle_hole(length = BASIC_BLOCK_HALF, diameter = PLATE_HOLE_DIAMETER, thickness = 2.7, hor_cutout = 0)
{
cliplen_without_dome = 5;
intersection() {
cylinder(length + MANIFOLD_CORRECTION, d = diameter, center = true);
cube([diameter, thickness, length + MANIFOLD_CORRECTION], center = true);
}
if (hor_cutout != 0) {
// position the horizontal cutout in a way that it is 5mm from the top
// so that the cone part of the axle can get some grip
translate([0,0, -(length - diameter) / 2 + cliplen_without_dome])
intersection() {
cylinder(diameter + MANIFOLD_CORRECTION, d = hor_cutout, center = true);
cube([hor_cutout + MANIFOLD_CORRECTION, thickness, diameter], center = true);
}
}
}
// --------------------------------------------------------------------
// A round groove to be substracted from other solids
// Optionally with a cube on each end of the groove
// The groove is centered on x and the z axis while it is slightly
// moved to a negative y value
// For the cutout rotate, translate and difference the groove
// --------------------------------------------------------------------
module round_groove(len = GROOVE_LENGTH, endcube=0)
{
// although the union is implicit, it doesn't do any harm and
// handles the groove as an entity
union()
{
// first, the groove itselve
translate([0, GROOVE_CENTER, 0] )
cylinder(r = GROOVE_RADIUS, h = len + 2 * MANIFOLD_CORRECTION, center=true);
// Do we have cubes at either end of the groove?
// Required if we have horzontal and vertical grooves
if (endcube == 1 || endcube == 3)
translate([0, GROOVE_CENTER - 2 * MANIFOLD_CORRECTION, -(len - GROOVE_DIAMETER) / 2 - MANIFOLD_CORRECTION] )
cube([GROOVE_DIAMETER, GROOVE_DIAMETER + 4 * MANIFOLD_CORRECTION, GROOVE_DIAMETER], center=true);
if (endcube == 2 || endcube == 3)
translate([0, GROOVE_CENTER - 2 * MANIFOLD_CORRECTION, (len - GROOVE_DIAMETER) / 2 + MANIFOLD_CORRECTION] )
cube([GROOVE_DIAMETER, GROOVE_DIAMETER + 4 * MANIFOLD_CORRECTION, GROOVE_DIAMETER], center=true);
// now the 3 mm breakthrough for the grooves
translate([0, 0.5, 0] )
cube([GROOVE_BREAKTHROUGH, 1.5, len + 2 * MANIFOLD_CORRECTION], center = true);
}
}
// --------------------------------------------------------------------
// a flat groove to be substracted from other solids
// --------------------------------------------------------------------
module flat_groove(len = GROOVE_LENGTH, endcube=0)
{
difference() {
// make a round groove and cut off the top part
round_groove(len, endcube);
translate([-GROOVE_RADIUS, GROOVE_CENTER + FLAT_GROOVE_OFFSET, -len / 2 - (MANIFOLD_CORRECTION + 0.01)] )
cube([GROOVE_DIAMETER, GROOVE_CENTER - FLAT_GROOVE_OFFSET, len + 2 * (MANIFOLD_CORRECTION + 0.01)]);
}
}
// Apply a size correction to the eyelets which are printed on
// the build plate of the 3D printer?
// On my Ender 3 the eyelets on the build plate are too tall so
// I needed to widen them. The eyelets on the vertical wall of the
// girder are ok, they need no correction.
function apply_correction(val, correctionVal = 0.0, correction=false) = correction == true ? val + correctionVal : val;
// --------------------------------------------------------------------
// a single eyelet for the girders and struts
// --------------------------------------------------------------------
module eyelet(height = EYELET_HEIGHT, radius=2.05,
cube_len = 7.2, cube_width = 3.1,
correctionVal = 0.0)
{
// Currently used only in the lugs.scad file
// See strut_eyelet to decide whether that one can be refactored
// or replaced by this library module.
render()
union()
{
cylinder(h = height, r = radius, center = true);
cube([cube_width, cube_len, height], center = true);
}
}
// --------------------------------------------------------------------
// a row of eyelets
// --------------------------------------------------------------------
module eyelet_row(len = 1, height = EYELET_HEIGHT, eyelet_dist = FT_GRID_SIZE)
{
// removed correction
cnt = len / eyelet_dist;
for (i = [0 : eyelet_dist : (cnt - 1) * eyelet_dist])
{
translate([eyelet_dist / 2, eyelet_dist / 2 + i, 0])
eyelet(height = height);
}
}
// --------------------------------------------------------------------
// The cutout for plates, girders and the like
// --------------------------------------------------------------------
module plate_cutout(w1 = PLATE_CO_TOP_WIDTH, l1 = PLATE_CO_TOP_LENGTH,
w2 = PLATE_CO_BOTTOM_WIDTH, l2 = PLATE_CO_BOTTOM_LENGTH,
r = PLATE_CO_CIRCLE_DIAMETER, o = PLATE_CO_CIRCLE_OFFSET) {
union () {
translate([0,-0.01,0]) {
translate([-w1/2, 0, 0])
cube([w1, r, l1]);
translate([-w2/2, 0, l1])
cube([w2, r, l2]);
translate([0, r / 2 + o, 0])
cylinder(h = l1 + l2, d = r);
}
}
}
// --------------------------------------------------------------------
// A cube with attached cylinder to cut out holes for the pins of the
// basic blocks. Centered on the zero point of the coordinate system.
// Supports the four directions up, down, left and right.
// The build plate must be face down in the coordinate system to cut
// out the holes with this module.
// if the holes are too tall, adjust width (the width and height of
// the larger square hole) or the segment width s (the width of the
// the smaller rectangle)
// Used by u_girder and build_plate.
// --------------------------------------------------------------------
module cube_with_cylinder(w1 = PLATE_CO_TOP_WIDTH, l1 = PLATE_CO_TOP_LENGTH,
w2 = PLATE_CO_BOTTOM_WIDTH, l2 = PLATE_CO_BOTTOM_LENGTH,
r = PLATE_CO_CIRCLE_DIAMETER, o = PLATE_CO_CIRCLE_OFFSET, dir = "up")
{
if (dir == "up")
{
translate([0,(l1+l2)/2,0])
rotate([90,0,0])
plate_cutout(w1, l1, w2, l2, r, o);
}
else if (dir == "down")
{
translate([0,-(l1+l2)/2,0])
rotate([90,0,180])
plate_cutout(w1, l1, w2, l2, r, o);
}
else if (dir == "left")
{
translate([(l1+l2)/2,0,0])
rotate([90,0,270])
plate_cutout(w1, l1, w2, l2, r, o);
}
else if (dir == "right")
{
translate([-(l1+l2)/2,0,0])
rotate([90,0,90])
plate_cutout(w1, l1, w2, l2, r, o);
}
}
// --------------------------------------------------------------------
// Pin which fits into the round and flat grooves.
// The base_length is for pins placed on blocks or plates
// Parameters:
// diameter: the diameter of the hole for the pin
// base_width: the width and length of the pin base
// base_length: the height of the pin base
// The pin is centered at the x and y axis while the z origin is 0
// --------------------------------------------------------------------
module pin(diameter = PIN_DIAMETER, base_width = PIN_BASE_WIDTH, base_length = PIN_BASE_LENGTH) {
// check the whole thing!
rotate([90,0,0])
translate([0, (base_width + base_length) / 2, 0])
union() {
difference() {
// build the rounded part of the pin
intersection() {
cylinder(d = diameter, h = diameter, center = true);
rotate([0, 90, 0])
cylinder(d = diameter, h = diameter, center = true);
}
// cut off the top
translate([0, diameter / 2 + 0.6, 0])
cube([diameter, diameter, diameter], center = true );
}
// add the base below the rounded part
translate([0, -(base_width / 2), 0])
cube([base_width, base_length, base_width], center = true );
}
}