Здравствуйте меня зовут Дмитрий. Недавно мне попалась на глаза программа OpenSCAD и я хочу сделать небольшой обзор и ещё мы немного порисуем.

Итак OpenSCAD это как вы наверно догадались CAD программа но рисовать в ней нужно не мышкой, а по средствам встроенного скриптового языка. То есть проектирование в ней напоминает програмирование.

И вы спросите, а зачем это нужно не проще-ли рисовать по старинке мышкой. Но я похоже разгадал замысел авторов программы. Дело в том что существует определенный круг деталей внешняя форма которых определяется формулами. И как раз для проектирования подобных деталей OpenSCAD подходит как нельзя лучше.

Шестерня с внешним зацеплением.

И первой подобной деталью является шестерня. Вот пример который я написал:

Скрытый текст
// To activate animation, select "View->Animate" from the
// menu; this will cause three fields to appear
// underneath the Preview console: Time, FPS & Steps.
// To commence animation, enter values into the FPS and Steps input
//Example FPS = 60 Steps = 120
// For set initial position uncomment
//$t=0;

//Fist gear...............................................
Teath = 20;
M = 1;
PressAng = 20;
C = 0.25;

DPeatch = Teath * M;
RPeatch = DPeatch/2;
DMain = DPeatch * cos(PressAng);

St = PI * M/2; // Teeth thickness by diameter
Stx = DPeatch * sin(St*(180/PI)/DPeatch); // Teeth thickness by chord

DIn = DPeatch - (2 + C)* M;
DOut = DPeatch + 2 * M;
ROut = DOut / 2;
d = sqrt(RPeatch^2 - (Stx/2)^2);

Steps = 90;

function ToRad(T) = T * (PI/180);
function Evolv_X(T, MD) = MD/2 * (cos(T) + ToRad(T) * sin(T));
function Evolv_Y(T, MD) = MD/2 * (sin(T) - ToRad(T) * cos(T));


FistEvolv_temp = [ for (a = [0 : Steps]) 
	if (sqrt((Evolv_X(a, DMain) + RPeatch - Evolv_X(20, DMain))^2 + (Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2)^2) < ROut)  // Cut pionts outside gear
		[Evolv_X(a, DMain) + RPeatch - Evolv_X(20, DMain), Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2]];

FistEvolv = concat([[d - (2 + 2)* M/2 , - Stx/2]], FistEvolv_temp);
	
SecondEvolv = [ for(variable = FistEvolv)  [variable.x, -variable.y]];

FistEvolvB = [ for(a =[0 : (len(FistEvolv) - 1)])  a];
	
SecondEvolvB = [ for(a =[0 : (len(SecondEvolv) - 1)])
	2 * len(SecondEvolv) - a - 1];


rotate ([0, 0, $t*360])
linear_extrude(height = 2 * M, center = true, convexity = 10, twist = 0) 
	union() 
	{
		for (i = [0 : (Teath - 1)])
			rotate([0,0,(360/Teath) * i]) 
				polygon(concat(FistEvolv, SecondEvolv),[concat(FistEvolvB, SecondEvolvB)]); 
			circle(d = DIn);
	}

//Second Gear.........................................................

Teath_2 = 30;

DPeatch_2 = Teath_2 * M;
RPeatch_2 = DPeatch_2 / 2;
DMain_2 = DPeatch_2 * cos(PressAng);


Stx2 = DPeatch_2 * sin(St*(180/PI)/DPeatch_2); // Teeth thickness by chord

DIn2 = DPeatch_2 - (2 + C)* M;
DOut2 = DPeatch_2 + 2 * M;
d2 = sqrt(RPeatch_2^2 - (Stx2/2)^2);

FistEvolv_temp2 = [ for (a = [0 : Steps]) 
	if (sqrt((Evolv_X(a, DMain_2)+ RPeatch_2 - Evolv_X(20, DMain_2))^2 + (Evolv_Y(a, DMain_2) - Evolv_Y(20, DMain_2) - Stx2/2)^2) < DOut2 / 2)  // Cut pionts outside gear
		[Evolv_X(a, DMain_2)+ RPeatch_2 - Evolv_X(20, DMain_2), Evolv_Y(a, DMain_2) - Evolv_Y(20, DMain_2) - Stx2/2]];

FistEvolv2 = concat([[d2 - (2 + 2)* M/2 , - Stx2/2]],FistEvolv_temp2);
	
SecondEvolv2 = [ for(variable = FistEvolv2)
	[variable.x, -variable.y]];

FistEvolvB2 = [ for(a =[0 : (len(FistEvolv2) - 1)]) a];
	
SecondEvolvB2 = [ for(a =[0 : (len(SecondEvolv2) - 1)])
	2 * len(SecondEvolv2) - a - 1];

k = Teath / Teath_2;
offset = (360/(2*Teath_2));

color( "Lime", 1.0 )
translate([DPeatch/2 + DPeatch_2/2, 0, 0])
	rotate([0,0,k * (-$t*360) + offset])
		linear_extrude(height = 2 * M, center = true, convexity = 10, twist = 0) 
			union() 
			{
				for (i = [0 : (Teath_2 -1)])
					rotate([0,0,(360/Teath_2) * i]) 
						polygon(concat(FistEvolv2, SecondEvolv2),[concat(FistEvolvB2, SecondEvolvB2)]); 
					circle(d = DIn2);
			}

Код нужно вставить в программу. Если выбрать "View->Animate" то можно увидеть анимацию. Правда чтобы она запустилась нужно в поля FPS и Steps ввести значения.

Любую шестерню можно задать всего тремя параметрами это модуль, количество зубьев и угол контакта. Все остальные размеры выражаются через эти три.

Самая главная поверхность шестерни это конечно-же эвольвента, которая получается прокатыванием отрезка по цилиндру без скольжения. Вот её формула:

Steps = 90;

function ToRad(T) = T * (PI/180);
function Evolv_X(T, MD) = MD/2 * (cos(T) + ToRad(T) * sin(T));
function Evolv_Y(T, MD) = MD/2 * (sin(T) - ToRad(T) * cos(T));


FistEvolv_temp = [ for (a = [0 : Steps]) 
	if (sqrt((Evolv_X(a, DMain) + RPeatch - Evolv_X(20, DMain))^2 + (Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2)^2) < ROut)  // Cut pionts outside gear
		[Evolv_X(a, DMain) + RPeatch - Evolv_X(20, DMain), Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2]];

FistEvolv = concat([[d - (2 + 2)* M/2 , - Stx/2]], FistEvolv_temp);

Мы прокатываем наш воображаемый отрезок от нуля до 90. Чтобы избавится от лишней части эвольвенты. Я использую условный оператор который отсекает все точки, лежащие за внешним диаметром шестерни.

Эвольвента начинается от главного диаметра шестерни и уходит в бесконечность. Но нам нужно 2 эвольвенты, и чтобы получить вторую нужно отразить все точки. Но для этого нужно опустить эвольвенту вниз на половину толщины зуба по главному диаметру. А мы знаем толщину зуба только по делительному. И чтобы сдвинуть делительный диаметр эвольвенты в ноль я нахожу координаты эвольвенты при 20 градусах и вычитаю их. После этого остается только сдвинуть эвольвенту вниз на половину толшины зуба Stx.

Ну а вторую эвольвенту мы получаем просто изменив знак у координаты y.

SecondEvolv = [ for(variable = FistEvolv)  [variable.x, -variable.y]];

Шестерня с внутренним зацеплением.

Ну а если мы создали шестерню с внешним зацепление. То сделать шестерню с внутренним зацеплением не представляет большого труда. Надо просто из цилиндра вырезать форму шестерни. Вот код:

Скрытый текст
// To activate animation, select "View->Animate" from the
// menu; this will cause three fields to appear
// underneath the Preview console: Time, FPS & Steps.
// To commence animation, enter values into the FPS and Steps input
//Example FPS = 60 Steps = 120
// For set initial position uncomment
//$t=0;

//Fist gear...............................................
Teath = 30;
M = 1;
PressAng = 20;
C = 0.25;

DPeatch = Teath * M;
RPeatch = DPeatch/2;
DMain = DPeatch * cos(PressAng);

St = PI * M/2; // Teeth thickness by diameter
Stx = DPeatch * sin(St*(180/PI)/DPeatch); // Teeth thickness by chord

DIn = DPeatch - 1 * M;
DOut = DPeatch + (2 + C) * M;
ROut = DOut / 2;
d = sqrt((DPeatch/2)^2 - (Stx/2)^2);

steps = 90;

function ToRad(T) = T * (PI/180);
function Evolv_X(T, MD) = MD/2 * (cos(T) + ToRad(T) * sin(T));
function Evolv_Y(T, MD) = MD/2 * (sin(T) - ToRad(T) * cos(T));


FistEvolv_temp = [ for (a = [0 : steps]) 
	if (sqrt((Evolv_X(a, DMain) + RPeatch  - Evolv_X(20, DMain))^2 + (Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2)^2) <  ROut)  // Cut pionts outside gear
	[Evolv_X(a, DMain)+ RPeatch - Evolv_X(20, DMain),
	Evolv_Y(a, DMain) - Evolv_Y(20, DMain) - Stx/2]];

FistEvolv = concat([[d - (2 + 2)* M/2 , - Stx/2]],FistEvolv_temp);
	
SecondEvolv = [ for(variable = FistEvolv)
	[variable.x, -variable.y]];

FistEvolvB = [ for(a =[0 : (len(FistEvolv) - 1)])  a];
	
SecondEvolvB = [ for(a =[0 : (len(SecondEvolv) - 1)])
	len(SecondEvolv) - a - 1 + len(SecondEvolv)];

rotate ([0, 0, $t*360])
linear_extrude(height = 2 * M, center = true, convexity = 10, twist = 0)
	difference() 
	{
		circle(d = DPeatch + 5 * M);
		for (i = [0 : (Teath -1)])
			rotate([0,0,(360/Teath) * i]) 
				polygon(concat(FistEvolv, SecondEvolv),[concat(FistEvolvB, SecondEvolvB)]); 
		circle(d = DIn);
	}

//Second Gear.........................................................

Teath_2 = 10;

DPeatch_2 = Teath_2 * M;
RPeatch_2 = DPeatch_2 / 2;
DMain2 = DPeatch_2 * cos(PressAng);


Stx_2 = DPeatch_2 * sin(St*(180/PI)/DPeatch_2); // Teeth thickness by chord

DIn_2 = DPeatch_2 - (2 + C)* M;
DOut_2 = DPeatch_2 + 2 * M;  
ROut_2 = DOut_2 / 2;
d2 = sqrt((DPeatch_2/2)^2 - (Stx_2/2)^2);

FistEvolv_temp_2 = [ for (a = [0 : steps]) 
	if (sqrt((Evolv_X(a, DMain2)+ (DPeatch_2/ 2) - Evolv_X(20, DMain2))^2 + (Evolv_Y(a, DMain2) - Evolv_Y(20, DMain2) - Stx_2/2)^2) < DOut_2 / 2)  // Cut pionts outside gear
	[Evolv_X(a, DMain2)+ (DPeatch_2/ 2) - Evolv_X(20, DMain2), Evolv_Y(a, DMain2) - Evolv_Y(20, DMain2) - Stx_2/2]];

FistEvolv_2 = concat([[d2 - (2 + 2)* M/2 , - Stx_2/2]],FistEvolv_temp_2);
	
SecondEvolv_2 = [ for(variable = FistEvolv_2)
	[variable.x, -variable.y]];

FistEvolvB_2 = [ for(a =[0 : (len(FistEvolv_2) - 1)]) a];
	
SecondEvolvB_2 = [ for(a =[0 : (len(SecondEvolv_2) - 1)])
	2 * len(SecondEvolv_2) - a - 1];

k = Teath / Teath_2;
offset = 0;

color( "Lime", 1.0 )
translate([DPeatch/2 - DPeatch_2/2, 0, 0])
	rotate([0,0,k * ($t*360) + offset])
		linear_extrude(height = 2 * M, center = true, convexity = 10, twist = 0) 
			union() 
			{
				for (i = [0 : (Teath_2 -1)])
					rotate([0,0,(360/Teath_2) * i]) 
						polygon(concat(FistEvolv_2, SecondEvolv_2),[concat(FistEvolvB_2, SecondEvolvB_2)]); 
				circle(d = DIn_2);
			}

Циклоидный редуктор

Мне так понравилось проектировать в этой программе, что я начал искать другие детали которые тоже как и шестерни строятся по формулам. И одним из подобных примеров является циклоидный редуктор. Вот код:

Скрытый текст
// To activate animation, select "View->Animate" from the
// menu; this will cause three fields to appear
// underneath the Preview console: Time, FPS & Steps.
// To commence animation, enter values into the FPS and Steps input
//Example FPS = 60 Steps = 120
// For set initial position uncomment
//$t=0;

D = 100;
R = D/2;
Dout = 5;
Drol = 5;
Rrol = Drol/2;
E = 0.75;
I = 39;
N = I + 1;
DHols = 65;
H = 5;


Steps = 360;

function Cycloyd_X(T) = (R * cos(T)) - (Rrol * cos(T + atan(sin((1 - N) * T) / ((R / (E * N)) - cos((1 - N) * T))))) - (E * cos(N * T));
function Cycloyd_Y(T) = (-R * sin(T)) + (Rrol * sin(T + atan(sin((1 - N) * T) / ((R / (E * N)) - cos((1 - N) * T))))) + (E * sin(N * T));

//Cycloyd body.........................................

Cycloyd = [ for (a = [0 : Steps]) 
		[Cycloyd_X(a), Cycloyd_Y(a)]];

translate([E, 0, 0])
rotate([0,0,($t*360)])
linear_extrude(height = H, center = true, convexity = 10, twist = 0)
difference() 
{
    polygon(Cycloyd); 
    circle(d = 20);
    translate([DHols/2, 0, 0])
        circle(d = Dout + 2 * E);
    
    rotate([0,0,120])
        translate([DHols/2, 0, 0])
            circle(d = Dout + 2 * E);

    rotate([0,0,240])
        translate([DHols/2, 0, 0])
            circle(d = Dout + 2 * E);
}

//Rollers body.............................................................
k = I/N;
rotate([0,0, k * ($t*360)])
color( "Lime", 1.0 )
linear_extrude(height = H, center = true, convexity = 10, twist = 0)
union() 
{
    difference() 
    {
        circle(d = D  + 20);
        circle(d = D);
    }
    for (i = [0 : I])
        rotate([0,0,i * 360/N])
            translate([D/2, 0, 0])
                circle(d = Drol);
};

//Vodilo........................................
color( "Aqua", 1.0 )
rotate([0,0,($t*360)])
union() 
{
    hull() 
    {
        translate([0,0,-20]) cylinder(h = 5, d= 15);
        translate([DHols/2,0,-20])cylinder(h = 5, d= 15);
    }
    rotate([0,0,120])
    hull() 
    {
        translate([0,0,-20]) cylinder(h = 5, d= 15);
        translate([DHols/2,0,-20])cylinder(h = 5, d= 15);
    }

    rotate([0,0,240])
    hull() 
    {
        translate([0,0,-20]) cylinder(h = 5, d= 15);
        translate([DHols/2,0,-20])cylinder(h = 5, d= 15);
    }

    translate([DHols/2, 0, -20])
        cylinder(h = 20 + H,d = Dout);
    
    rotate([0,0,120])
        translate([DHols/2, 0, -20])
        
            cylinder(h = 20 + H,d = Dout );

    rotate([0,0,240])
        translate([DHols/2, 0, -20])
            cylinder(h = 20 + H ,d = Dout);
}

Здесь необходимо создать циклоиду. В обычной CAD программе это было-бы сделать очень проблематично, а в OpenSCAD нет никаких проблем.

Циклойдный редуктор с промежуточными телами качения.

Ну и конечно-же после того как мы создали редуктор с внешней циклоидой. Возникает вопрос. А существуют-ли редукторы с внутренней циклоидой. И на удивление я нашел такой редуктор, называется он циклоидный редуктор с промежуточными телами качения. Вот видео, там автор подробно расписывает все преимущества этого редуктора над просто циклоидным. Ну а мы приступаем к рисованию:

Скрытый текст
// To activate animation, select "View->Animate" from the
// menu; this will cause three fields to appear
// underneath the Preview console: Time, FPS & Steps.
// To commence animation, enter values into the FPS and Steps input
//Example FPS = 60 Steps = 120
// For set initial position uncomment
//$t=0;

Dball = 6;
Rball = Dball/2;
I = 17;
Rout = 38;
E = 0.2 * Dball;
ZG = I + 1; //gear ratio
Rin = Rout - 2 * E; 
HC = 2.2 * E; //Separator thickness
Dex = (Rin + E - Dball) * 2;
Dsep = Dex + Dball; //Separator diameter
Dcyclbody = 2 * Rout + 20;
Dsepm = Dex + Dball;
k = (I + 1)/I;
H = 5;

function S(T) = sqrt((Rball + Dex/2) ^ 2 - (E  * cos(ZG * T)) ^ 2);
function L(T) = E * cos(ZG * T) + S(T);
function XI(T) = atan2(E * ZG *  sin(ZG *T),S(T));

function Cycloyd_X(T) = L(T) * sin(T) + Rball * sin(T + XI(T));
function Cycloyd_Y(T) = L(T) * cos(T) + Rball * cos(T + XI(T));

//Cycloyd body.........................................
Steps = 360;

Cycloyd = [ for (a = [0 : Steps]) 
		[Cycloyd_X(a), Cycloyd_Y(a)]];

rotate([0,0,($t*360)])
linear_extrude(height = H, center = true, convexity = 10, twist = 0)
difference() 
{
    circle(d = Dcyclbody);
    polygon(Cycloyd);
}

//Excenric...................................................

color( "Blue", 1.0 )
translate([0, E, 0])

rotate([0,0, k * ($t*360)])
    cylinder( h = H, d = Dex);

//Balls...................................................
color( "Aqua", 1.0 )
translate([0, E, 0])
rotate([0,0, k * ($t*360)])
for (i = [0 : I - 1])
    rotate([0,0,i * 360/I])
        translate([0, Dsepm/2, 0])
            sphere(d = Dball);

//Seporator.........................................................
color( "Lime", 1.0 )
translate([0, E, 0])
rotate([0,0, k * ($t*360)])
linear_extrude(height = H, center = true, convexity = 10, twist = 0)
difference() 
{
    circle(d = Dsep + HC);
    circle(d = Dsep - HC);
    for (i = [0 : I - 1])
        rotate([0,0,i * 360/I])
            translate([0, Dsepm/2 , 0])
                square(Dball,true);
}

Вывод

Конечно есть за что программу поругать. У неё ужасный текстовый редактор. Из-за окна предпросмотра для него остается только пол экрана, поэтому работать в нем невозможно. Я все скрипты писал в VSCodium. Кроме того неудобная работа с массивами. Это проявилось при создании шестерни. Чтобы добавить точку с координатой основания зуба в начало массива пришлось создать новый массив. Кроме того хотелось-бы иметь инструмент для измерения размеров, но все что есть это сетка с координатами.

Но если не смотреть на эти недостатки, то программа просто огонь. Если вас утомили однообразные CAD программы похожие друг на друга как две капли, рекомендую попробовать. Это как глоток свежего воздуха.