
Здравствуйте меня зовут Дмитрий. Недавно мне попалась на глаза программа 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(PressAng, DMain))^2 + (Evolv_Y(a, DMain) - Evolv_Y(PressAng, DMain) - Stx/2)^2) < ROut) // Cut pionts outside gear [Evolv_X(a, DMain) + RPeatch - Evolv_X(PressAng, DMain), Evolv_Y(a, DMain) - Evolv_Y(PressAng, 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(PressAng, DMain_2))^2 + (Evolv_Y(a, DMain_2) - Evolv_Y(PressAng, DMain_2) - Stx2/2)^2) < DOut2 / 2) // Cut pionts outside gear [Evolv_X(a, DMain_2)+ RPeatch_2 - Evolv_X(PressAng, DMain_2), Evolv_Y(a, DMain_2) - Evolv_Y(PressAng, 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(PressAng, DMain))^2 + (Evolv_Y(a, DMain) - Evolv_Y(PressAng, DMain) - Stx/2)^2) < ROut) // Cut pionts outside gear [Evolv_X(a, DMain)+ RPeatch - Evolv_X(PressAng, DMain), Evolv_Y(a, DMain) - Evolv_Y(PressAng, 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(PressAng, DMain2))^2 + (Evolv_Y(a, DMain2) - Evolv_Y(PressAng, DMain2) - Stx_2/2)^2) < DOut_2 / 2) // Cut pionts outside gear [Evolv_X(a, DMain2)+ (DPeatch_2/ 2) - Evolv_X(PressAng, DMain2), Evolv_Y(a, DMain2) - Evolv_Y(PressAng, 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 программы похожие друг на друга как две капли, рекомендую попробовать. Это как глоток свежего воздуха.
Комментарии (8)

LAutour
13.11.2026 03:16В Openscad очень нехватает отстутствие изменяемых переменных (они у него все одноразовые), помимо счетчика в циклах. Из-за этого например, когда надо автоматом расставить фигуры с разным размером через одиниковые промежутки, приходится извращатся при рассчетах смещения каждой фигуры.

naky
13.11.2026 03:16А мне норм, размер/положение/etc без проблем вычисляются из счётчика цикла/размеров объектов/whatever.

DJP
13.11.2026 03:16А не подскажите, есть ли шестеренки для сцепления под 90 градусов, типа корончатых?

deema35 Автор
13.11.2026 03:16Вы наверно имели ввиду конические шестерни. Корончатые шестерни использовались в мельницах девятнадцатого века.

DJP
13.11.2026 03:16ну, наверное, вам видней :)
я хотел узнать, есть ли для OpenSCAD программа моделирования шестерен (как бы они не назывались :) которые позволяют передавать усилие под углом 90 градусов (и которые не сложно бы было самому напечатать на 3D принтере) ... как-то так...
shaggyone
Openscad хорош, основы можно изучить за пару часов, т.к. весь синтаксис умещается на один небольшой chetsheet.
Но, увы, моделер помирает на такой интуитивной вещи как сделать фаску или скругление. А сама программа на современном железе нескольких тысячах полигонов. Впрочем, этого хватило, чтобы всю третью Прюшу в нём нарисовать.
Для всяких математически определяемых объектов -- самое оно.
af754125
Это да но есть BOSL и minkovski() вам в помощь.