OpenSCAD для пионеров и пенсионеров: целый день для знакомства

в 18:57, , рубрики: diy или сделай сам, OpenSCAD, Работа с 3D-графикой
image

Постоянно видел на Thingiverse модели с исходниками на OpenSCAD. Даже пытался загружать этот код — но, похоже, тормозная жидкость залита в OpenSCAD при разработке в изобилии, при отображении более-менее сложной модели компьютер подвисает на десятки минут. В итоге — не вдохновило.

Обычно я пользуюсь древним Sketchup — еще гугловским, той античной версией, когда гугл врал, что Sketchup — это навсегда, и его бесплатная версия в усеченном варианте будет всегда доступна даже для коммерческого использования. Я, будучи по натуре легковерным, даже с Ruby слегка разобрался, автоматически прорисовывал профиля крыльев игрушечных самолетиков в Sketchup и генерировал код для пенорезки, чтобы их вырезать. Почти вчера было — но Ruby я уже абсолютно не помню.
Нарисовать в Sketchup что-то очень сложное и мелкое, чтобы можно было распечатать — это головная боль. Нарисовать-то можно, но он потеряет маленькие кусочки изображения, если их и удастся преобразовать в STL, то сгенерировать код для печати ни один слайсер не сможет.

Вот примерно такая моделька и понадобилась. Я даже нашел готовый STL файл.

image

Не знаю, что курил автор, но все отверстия были неправильных размеров, и использовать не получилось. А исходник автор положить не посчитал нужным. Проектировать такую модель с помощью Sketchup как-то не захотелось — плавали, знаем.

Вроде модель должна быть не сложная для OpenSCAD, но изучать его как-то не хотелось — пока дочитаешь до конца описание, забудешь, что было вначале. Все-таки не очень молодой, склероз крепчает и приходит альтернативная одаренность. Короче, решил, что изучать я ничего не буду. Буду искать подходящие решения в описании OpenSCAD по мере потребности.

И таки сработало — за один день я нарисовал эту детальку. Напечатать уже не успел — поставил на печать на второй день.
Так что предупреждаю — то, что сделано, сделано не от большого ума и знаний, а как уж карта легла. Может быть можно лучше и быстрее — но для одного дня должно быть не очень плохо, цель достигнута.
Если что описал неправильно, то это не по злому умыслу, а исключительно по незнанию — проект-то однодневка.

Со вступлением хватит, как повторял Остап Бендер за Мопассаном, ближе к телу.

Основание для крепления вентилятора — хотелось бы квадрат с закругленными краями. В элементарных функциях такой не нашелся. Но зато найдена не менее интересная вещь — на нарисованные элементы можно натянуть поверхность.
Пробуем — рисуем по углам цилиндрики с радиусом, который хотим иметь для закругления. Рисовать каждый отдельно — дурной вкус, используем циклы, благо они имеются.

$fn= 48;

FanBase();

module FanBase()
{
  height = 4;
  radius = 3;
  width = 41;
  union()
  {
    for(x = [0:1])
    {
      for(y = [0:1])
      {
        translate([(width-radius)*x-(width-radius)/2, (width-radius)*y-(width-radius)/2, 0])
          cylinder(r = radius, h = height, center = false);
      }
    }
  }    
}

image

Теперь просто меняем объединение union() на поверхность hull() — и все готово!

image

Это бы все это свести на конус. Натянется ли поверхность на 8 цилиндриков на разных высотах? Причем квадрат должен перейти в прямоугольник — диаметр у радиатора ведь меньше его высоты.

image

Без проблем — и код теперь выглядит так:

$fn= 48;

FanBase();

module FanBase()
{
  height = 4;
  radius = 3;
  width = 41;
    
  height_s = 1;
  radius_s = 2;
  length_s = 32;
  width_s = 27.5;    
    
  skirt1_height = 13;
  skirt2_height = 12.5;    

  hull()
  {
    for(x = [0:1])
    {
      for(y = [0:1])
      {
        translate([(width-radius)*x-(width-radius)/2, (width-radius)*y-(width-radius)/2, 0])
          cylinder(r = radius, h = height, center = false);
          
        translate([(length_s-radius_s)*x-(length_s-radius_s)/2, (width_s-radius_s)*y-(width_s-radius_s)/2, skirt1_height-height-height_s])
          cylinder(r = radius_s, h = height_s, center = false);          
          
      }
    }
  }    
}

image

Теперь бы юбку поднять повыше (гусары, молчать!) — нам нужно до половины диаметра закрыть радиатор. Делаем еще 4 цилиндра и натягиваем поверхность на них.

image

Вроде еще не сильно утомились, а картинка уже такая:

image

код тоже еще не напрягает:

$fn= 48;

FanBase();

module FanBase()
{
  height = 4;
  radius = 3;
  width = 41;
    
  height_s = 1;
  radius_s = 2;
  length_s = 32;
  width_s = 27.5;    
    
  skirt1_height = 13;
  skirt2_height = 12.5;    
  union()
  {
    hull()
    {    
      for(x = [0:1])
      {
        for(y = [0:1])
        {
          translate([(length_s-radius_s)*x-(length_s-radius_s)/2, (width_s-radius_s)*y-(width_s-radius_s)/2, skirt1_height])
            cylinder(r = radius_s, h = skirt2_height, center = false);   
        }      
      }
    }
    hull()
    {
      for(x = [0:1])
      {
        for(y = [0:1])
        {
          translate([(width-radius)*x-(width-radius)/2, (width-radius)*y-(width-radius)/2, 0])
            cylinder(r = radius, h = height, center = false);
          
          translate([(length_s-radius_s)*x-(length_s-radius_s)/2, (width_s-radius_s)*y-(width_s-radius_s)/2, skirt1_height-height_s])
            cylinder(r = radius_s, h = height_s, center = false);          
        }
      }
    }
  }    
}

Теперь займемся отверстиями для винтиков и гаечек. Имеем в виду, что когда пластик наплавляется, диаметр отверстия уменьшается на 0.2...0.4 мм. Если отверстие окажется чуть больше нужного — беда небольшая, а вот шестиугольное отверстие рассверлить, если оно окажется меньше нужного — у меня лично шестиугольных сверл нет.
При ближайшем рассмотрении оказывается, что цилиндр — это далеко не обязательно цилиндр, число граней можно указать. Чем больше граней — тем он больше будет похож на цилиндр. А для гаечек 6 граней — это то, что нам надо.

image

Код


FanScrewHoles();

module FanScrewHoles()
{
  width = 32;
  height = 4;
  height2 = 12;
  diam = 3.2;
  hex_nut = 6.6;
  union()
  {
    for(x = [0:1])
    {
      for(y = [0:1])
      {
        hull()
        {
          translate([width*x - width/2,width*y - width/2, height])
            cylinder(h=height2, r=hex_nut/2, center=false, $fn=6);
          translate([width*x - width/2,width*y - width/2, height+height2])
            cylinder(h=2, r=1, center=false);            
          
        }
        translate([width*x - width/2,width*y - width/2, -0.1])
          cylinder(h=height+0.2, r=diam/2, center=false);
      }
    }
  }
}

Теперь вычитаем отверстия из юбки

difference()
{
 FanBase();
 FanScrewHoles();
}

image

Надо бы заняться отверстием для воздуха — идем по накатанной дорожке, рисуем дырку наоборот.

image

image

Соединяем все вместе:

difference()
{ 
  FanBase();
  FanScrewHoles();
  AirHole();
}

image

Теперь нужна упрощенная модель печатающей головки. Опять не забываем, что готовое пластиковое изделие не будет точно соответствовать спроектированной модели, уменьшаем/увеличиваем где надо.

Тут я расслабился и переменные не вынес в отдельные строки.

Код

module HotEnd()
{
  union()
  {
    cylinder(r = 25/2, h = 32, center = false);
    translate([0,0,32]) cylinder(r = 16/2, h = 3.5, center = false);

    translate([0,0,32]) cylinder(r1 = 25/2, r2=16.4/2, h = 6.5, center = false);

    translate([0,0,35.5]) cylinder(r = 9/2, h = 2, center = false);
    translate([0,0,37.5]) cylinder(r = 16.4/2, h = 3.3, center = false);
    translate([0,0,40.8]) cylinder(r = 12.4/2, h = 5.2, center = false);
    translate([0,0,46]) cylinder(r = 16.4/2, h = 3.8, center = false) ;
  }
}

Пристраиваем головку к нашему поделию:

union()
{
  translate([-17,0,26])
    rotate([0, 90, 0])
      HotEnd();    
    
  difference()
  {
   FanBase();
   FanScrewHoles();
   AirHole();
  }
}

image

Теперь осталось нарисовать шейку-поддержку, желательно так, чтобы при печати обойтись без поддержек, извините за тафталогию. Дело вкуса, но я их не люблю.

Код

module Mount()
{
  width=29.5;
  union()
  {     
    difference()
    {        
      union()
      {  
        translate([0,-width/2,0])  
          rotate([-90,-90,0])
             linear_extrude(height = width, center = false, convexity = 10)
               polygon(points=[[10,1],[21.5,1],[21.5,18],[10,18],[0,8]]);                      
      }
      union()
      {
        translate([12.6, 22/2, 14.2])
          cylinder(h=10, r=3.2/2, center=false);      
        translate([12.6, 22/2, -0.1])  
          cylinder(h=14, r=6.6/2, center=false);   
        translate([12.6, -22/2, 14.2])
          cylinder(h=10, r=3.2/2, center=false);      
        translate([12.6, -22/2, -0.1])  
          cylinder(h=14, r=6.6/2, center=false);   
      }
    }
  }
}

image

В конце концов складываем, что положено складывать, вычитаем остальное:

module MainFan()
{
  difference()   
  {
    union() 
    { 
      FanBase();          
      translate([14,0,4])
        Mount();            
    }
    union()
    {
      FanScrewHoles();
      AirHole();
      translate([-17,0,26])
        rotate([0, 90, 0])
          HotEnd();
    }
  } 
}

image

Можно запускать слайсер.

image

Имеем то, что имеем.

image

После этого поправить все размеры в готовом файле второй детальки было минутным делом.

image

В заключение кое-какие мои проектики, нарисованные в Sketchup.
Вот такой станочек нарисовать за пару-тройку дней, даже в Sketchup, смогут не только лишь все.

Ну а когда появилось, чем фрезеровать, сделал второй — на вид не такой эффектный, но работать с ним удобно, ромбы из квадратов уже не получаются.

Станки делал, когда уже заработал инвалидность — без дела сидеть мне лень, а с дикой атаксией что-то ровно отпилить было невозможно. Пилки по металлу просто ломались. Пришлось искать выход — голова, хоть и частично, но еще работает. Теперь станками пилю :) — было бы что пилить.

Прочая 3D мелочь пузатая, которую я не поленился выложить, здесь.
Может, кто для себя полезное что найдет.

Автор: Владимир

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js