2. Computer aided design (CAD)#
Designing “support” module with OpenSCAD#
First, I designed the code of a “support” : a simple element that can attach to lego :
module support (r_hole, w_support, h_support, n_holes, ir_holes) {
// this module is making a bar support for lego, with the parameters :
//r_hole = radius of the holes
// w_support = with of the support
// h_support = height of the support
// n_holes = number of holes
// ir_holes = inter-radius between holes
difference(){
hull(){
for(i=[0:n_holes-1]) {
translate([0, ir_holes*i, 0]) cylinder(h = h_support, r = w_support/2, center = true);
}
}
for(i=[0:n_holes-1]) {
translate([0, ir_holes*i, 0]) cylinder(h=h_support+1, r=r_hole, center=true);
}
}
};
So when the module is loaded I can generate different kind of support parametrically, for example :
support (4, 15, 5, 5, 12);
will generate :
support (4, 10, 5, 15, 20);
will generate :
Spiral spring#
I watched videos about compliant a mechanism and I found a nice idea : a kind of spring made of three spirals.
The stl is avaible on printables and it look like this :
I found it was a good challenge to code it with OpenSCAD and make it parametric (size, height, space between spirals).
Draw a (Archemdian) spiral#
First I needed to know how to code a spiral in OpenSCAD :
I found a tutorial on the website openhome.cc to draw a spiral.
© Since 2003 Justin Lin, All Rights Reserved
It used two modules : line and polyline, that can draw lines between a set of points :
module line(point1, point2, width = 1, cap_round = true) {
// draw a line between to points with a specified width
// if cap_round = true, the angle will be smoothed with a circle
angle = 90 - atan((point2[1] - point1[1]) / (point2[0] - point1[0]));
offset_x = 0.5 * width * cos(angle);
offset_y = 0.5 * width * sin(angle);
offset1 = [-offset_x, offset_y];
offset2 = [offset_x, -offset_y];
if(cap_round) {
translate(point1) circle(d = width, $fn = 24);
translate(point2) circle(d = width, $fn = 24);
}
polygon(points=[
point1 + offset1, point2 + offset1,
point2 + offset2, point1 + offset2
]);
}
module polyline(points, width = 1) {
// recursive function : draw lines between a set of points
module polyline_inner(points, index) {
n_width = width;
if(index < len(points)) {
n_width = width;
line(points[index - 1], points[index], n_width);
polyline_inner(points, index + 1);
}
}
polyline_inner(points, 1);
}
Further explainations of this modules here
And then a code that generate points in an Archemedian spiral with the formula r = a + bθ : (arm_len beign the “space” between to turn of spiral)
PI = 3.14159;
step = 0.25;
circles = 5;
arm_len = 10;
b = arm_len / 2 / PI;
// one radian is almost 57.2958 degrees
points = [for(theta = [0:step:2 * PI * circles])
[b * theta * cos(theta * 57.2958), b * theta * sin(theta * 57.2958)]
];
polyline(points, 1);
There was an issued with the code outlined by the author : as the dots are far from the center they are more and more spaced.
This conduct to a resolution lower at the edges of the spiral then at the center, and we dont want that.
The author of the website proposed a solution but I found it not nice.
I found a simpler way to resolve this problem : incremanting the steps of the square of the theta angle (instead of the theta angle) :
angle_max = 2 * PI * circles;
angle_max_square = angle_max*angle_max;
points = [for(theta_carre = [0:step:angle_max_square])
[b * sqrt(theta_carre) * cos(sqrt(theta_carre) * 57.2958), b * sqrt(theta_carre) * sin(sqrt(theta_carre) * 57.2958)]
The points are not perfectly equally distributed but it is working well enough for what i need.
Points distribution with incremanting theta:
Points distribution with incremanting theta square:
Adaptating the code#
From this code I added several things :
- I draw the spiral three time with rotations to have the three spirals
- I added a support in the center and on the edges
- I added an outer ring (activable with a boolean)
- I made it paramtrable with different variables in the heading of the code :
- To define the diameter of the spirals and the inter-spiral distance
- To define the size and shape of the supports , and if there is simple or double support on the edges
- To have supports that fits well with legos I followed the recommandations of Victor from a previous year.
Making the connexions between the spiral and the supports stronger#
I found that the connexion between the ruban of the spiral and support (in the center and on the edges) looked really weak. So I decided to try to reinforce it.
To do so I modified the code of the polyline module so it makes incrementing (or decrementing) thinckness of
the ruban on the center (or on the edges) - cf. the code under.
I added two booleans in the begining of the code to activate/desactivate this progressive thickening.
Whithout thickening | With thickening |
---|---|
![]() |
![]() |
.
Code of the v1#
The .scad file is avaible here : FBZ-SPIRAL_SPRING-v1.scad .
The complete code is as follows :
// Flexi-spiral v1 © 2024 by Simon Hanin is licensed under CC BY-SA 4.0. To view a copy of this license,
// visit https://creativecommons.org/licenses/by-sa/4.0/
$fn=100; //global resolution
// Variable to modify the parameters of the object
// Variables defining size and shape of the spiral
diam = 30; // diameter of the spiral, in centimeter
inter_spir = 10; // distance between two spires of one spiral
rb_width = 0.6; //ruban width
rb_height = 20; //ruban height
res = 100; // resolution of the spiral in a range to 100 very good resolution
// Variables defining size and shape of the supports
double_supp = false; // boolean, if true : support with two holes
supp_height=20; // height of the supports
r_hole=2.55; // radius of holes for lego insertion
inter_r=8; // inter radius for lego
r_supp_end=3.6; // radius of the support at the ends of the spiral
r_supp_center=5; // radius of the support ain the center of the spiral
n_width = 0;
// Variables defining the length of the transition region (thickening in the center and in the edges)
thick_c = false; // if true : center of the spiral will be thicker
thick_e = false; // if true : edges of the spiral will be thicker
l_trans = 1.5; // length of trans region (aribtrary units, not mm)
k_trans = 1/5; //trans factor
// General variable
bool_contour = true;
bool_center = false; // to determine if object are centred around the axes or not
s_trim = 1.1; // adjust to put edges supports "a fleur" du ruban
// Variables used for calculation
circles = floor(diam/inter_spir); // number of circles made by spiral ( floor is used to have an integer)
angle_max = 2*PI*circles; // angle_max in radian
angle_max_square = angle_max*angle_max; // the same squared
b = inter_spir / 2 / PI; // variable used for tracing the spiral (distance between to rounds of one spiral)
step = 100/res; // steps for spiral
PI = 3.14159;
n_trans = l_trans*res/4; // number of segment of spiral in trans
module line(point1, point2, width = 1, cap_round = true) {
// trace line of a defined width between two points
// if cap_round = true, the angle will be smoothed with a circle
angle = 90 - atan((point2[1] - point1[1]) / (point2[0] - point1[0]));
offset_x = 0.5 * width * cos(angle);
offset_y = 0.5 * width * sin(angle);
offset1 = [-offset_x, offset_y];
offset2 = [offset_x, -offset_y];
if(cap_round) {
translate(point1) circle(d = width, $fn = 24);
translate(point2) circle(d = width, $fn = 24);
}
polygon(points=[
point1 + offset1, point2 + offset1,
point2 + offset2, point1 + offset2
]);
}
module polyline(points, width = 1) {
// trace a serie of lines of a defined width between a serie of points
module polyline_inner(points, index) {
n_width = width;
if(index < len(points)) {
if(index < n_trans && thick_c) { // thicker zone of the spiral on the center
n_width=width+(n_trans-index)*k_trans;
line(points[index - 1], points[index], n_width);
}
if(index > len(points)-n_trans && thick_e ) { // thicker zone of the spiral on the edges
n_width=width+(n_trans-len(points)+index)*k_trans;
line(points[index - 1], points[index], n_width);
}
else {
n_width = width;
line(points[index - 1], points[index], n_width);
}
polyline_inner(points, index + 1);
}
}
polyline_inner(points, 1);
}
points = [for(theta_carre = [0:step:angle_max_square])
// generating a serie of point in the shape of the spiral
[b * sqrt(theta_carre) * cos(sqrt(theta_carre) * 57.2958), b * sqrt(theta_carre) * sin(sqrt(theta_carre) * 57.2958)]
];
difference()
// difference between the first "union" that is all the solid parts and the second "union" that is the holes in the supports
{
union(){ // union of the spirals and the supports
linear_extrude (rb_height, center=bool_center) { // extrudaction of the the three spirals
polyline(points, rb_width); // tracing of the first spiral
rotate([0,0,120]) polyline(points, rb_width); // second spiral rotated
rotate([0,0,-120]) polyline(points, rb_width); // third spiral rotated
}
if(bool_contour){ // trace an outside ring
difference() {
cylinder(h = supp_height, r = diam, center = bool_center);
cylinder(h = supp_height*4, r = diam-(1.2/20)*diam, center = true);
}
}
cylinder(h = supp_height, r = r_supp_center, center = bool_center); // center support
hull(){ // first edge support (can be simple or double)
translate([b*angle_max+r_supp_end-s_trim,0,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
}
}
rotate([0,0,120]) { // second edge support (can be simple or double), rotated
hull(){
translate([b*angle_max+r_supp_end-s_trim,0,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
}
}
}
rotate([0,0,-120]) { // third edge support (can be simple or double), rotated
hull(){
translate([b*angle_max+r_supp_end-s_trim,0,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height, r = r_supp_end, center = bool_center);
}
}
};
}
union() { // union of the holes
cylinder(h = rb_height*4, r = r_hole, center = true); // hole of the center
translate([b*angle_max+r_supp_end-s_trim,0,0]) // first edge hole
cylinder(h = supp_height*4, r = r_hole, center = true);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height*4, r = r_hole, center = true);
}
rotate([0,0,120]) { // second edge hole
translate([b*angle_max+r_supp_end-s_trim,0,0])
cylinder(h = supp_height*4, r = r_hole, center = true);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height*4, r = r_hole, center = true);
}
}
rotate([0,0,-120]) { // third edge hole
translate([b*angle_max+r_supp_end-s_trim,0,0])
cylinder(h = supp_height*4, r = r_hole, center = true);
if(double_supp){
translate([b*angle_max+r_supp_end-s_trim,inter_r,0])
cylinder(h = supp_height*4, r = r_hole, center = true);
}
}
}
}
Exemples of models that can be generate from the code#
By changing the parameters of the code you can generate this variety of models :
Notes about the SCAD code#
- There is still some stuff to improve this code :
- Make it shorter by making a module for support
Useful openscad tips#
To debug your code it is very usefull to use the command echo("some text");
or echo(some_variable);
to print values in console.
Licensing#
Licensing my work#
I choosed a creative commons license. I choose those two parameters : - BY: Credit must be given to you, the creator. - SA: Adaptations must be shared under the same terms.
There is a simple tool to generate the license on the website, so I get :
// Flexi-spiral © 2024 by Simon Hanin is licensed under CC BY-SA 4.0. To view a copy of this license,
// visit https://creativecommons.org/licenses/by-sa/4.0/
What about the tutorial I followed?#
As explained in the beginging, part of my code (line and polyline modules) is from the website “OpenHome.cc”. There is no licensing informations on the pages explaining the code. But on the main page you can find : * © Since 2003 Justin Lin, All Rights Reserved * So I don’t know how illegal I am by using this code.