Намоточный станок на ардуино с шаговыми двигателями

Делаем машину для намотки тороидальных катушек на базе Arduino

Всем привет, представляю вам изготовленную мною машину для намотки тороидальных катушек на базе Arduino. Машина автоматически наматывает проволоку и поворачивает тороид. В качестве интерфейса я использовал энкодер и ЖК-экран 16×2. Пользователь может вводить такие параметры, как диаметр катушки, количество оборотов и угол намотки.

В данной статье я расскажу, как построить эту машину и дам подробности её работы.

Комплектующие

Подробности сборки

Намоточное кольцо

Кольцо я изготовил из фанеры 12 мм. Внешний диаметр – 145 мм, внутренний – 122 мм. Имеется углубление длиной 43 мм и глубиной 5 мм для катушки.

В кольце я сделал один разрез и замок для его открывания. Открыв замок, мы размещаем тороидальную катушку внутри кольца.

Также у кольца есть углубление по внешней стороне, 8 мм шириной и 4 мм глубиной, в котором размещается ремень шириной 6 мм.

Катушка

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

Материал выбран потому, что нейлон, во-первых, легче алюминия, во-вторых, его легко точить на станке. Кроме того, когда машина работает, он не колеблется так сильно.

Корпус машины

Корпус также сделан из фанеры 12 мм. На нём закреплены три направляющих ролика, расставленные примерно в 120° друг от друга.

Ролики сделаны из подшипников 626Z, гаек и болтов. На них будет вращаться наше деревянное намоточное кольцо.

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

Ролики-держатели тороида

Это ролик, вращающий катушку, и одновременно удерживающий её. Я выточил их из нейлонового стержня на моём токарном мини-станке. Все размеры приведены на фото.

Ролики я снабдил поролоновой лентой, она хорошо держит катушку и та не проскальзывает. Важно использовать барашковые гайки для закрепления направляющих – обычные от вибрации откручиваются.

Сверху и снизу каждого ролика я поставил по фланцевому подшипнику.

Крепление шагового двигателя

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

Двигатель постоянного тока

Этот мотор вращает намоточное кольцо. Я использовал Orange Jhonson 12v Dc Motor 300 RPM. Вам советую взять мотор на 600 RPM или 1000 RPM.

Ремень имеет 600 мм в длину и 6 мм в ширину. Держатель мотора, крепящийся к алюминиевому профилю, также сделан из фанеры.

Инфракрасный датчик

Я использовал датчик от SeedStudio. Он отправляет сигнал на контакт обработки прерываний Arduino – таким образом Arduino может подсчитывать количество оборотов кольца.

Я закрепил датчик на алюминиевом профиле так, чтобы замок кольца заодно работал и отражающей поверхностью, на которую реагирует датчик.

Данный датчик выдаёт по 2 сигнала за один поворот кольца – когда дерево сменяется металлом, сигнал меняется с низкого напряжения на высокое, а потом наоборот. Обработчик прерываний регистрирует два изменения состояния. Поэтому для подсчёта реального количества поворотов мне пришлось делить количество срабатываний пополам.

Основание аппарата

Основание тоже сделано из фанеры 12 мм, имеет размеры 300х200 мм. Четыре резиновых ножки будут прочно и хорошо держать машину, и помогут избежать ненужной вибрации.

Для установки компонентов я закрепил на основании алюминиевый профиль. Обожаю его за гибкость в использовании. Все компоненты можно легко устанавливать на профиле и двигать вдоль него. Позволяет легко выравнивать компоненты относительно друг друга.

Корпус контроллера

Коробочка распечатана на 3D-принтере, внутрь установлены плата, ЖК-дисплей и энкодер. Корпус придаёт профессиональный вид всему проекту, а также обеспечивает удобную настройку аппарата. Корпус закреплён на основании при помощи металлической скобы.

Схема подключения

ЖК-дисплей используется для вывода информации, а энкодер – для ввода.

Первый экран с приветствием.

На втором экране нужно ввести внешний диаметр катушки – аппарат поддерживает катушки разных диаметров.

На третьем экране нужно ввести количество витков.

На четвёртом экране нужно ввести угол покрытия катушки. 360° означает, что катушка будет покрыта проволокой целиком. 720° означает, что катушка будет обмотана проволокой дважды по окружности.

На 5-м экране можно проверить все входные данные пред тем, как запустить машину. Если всё верно, нажимаете на энкодер, и машина стартует.

6-й экран демонстрирует количество витков в реальном времени.

Источник

Намоточный станок на ардуино с шаговыми двигателями

Уважаемые форумчане, прошу оценить идею и реализацию намоточного приспособления на базе контроллера ATmega328.
Сейчас думаю что улучшить в этом проекте.
Электроника в целом устраивает, хотя если есть дельные предложения то слушаю.
Механика требует доработки в плане перехода на типовые узлы типа муфты, резьбовые валы и т.д.
То есть стандартные детали которые применяются в 3D принтерах и различных дешевых ЧПУ.
Цель повысить надежность и уменьшить влияние сборки.
Код требует доработки в плане понятности, а так же есть моменты по управлению ШД через прерывания которые мне не нравятся.
Возможно кто скажет как такое управление реализуется в 3Д принтерах, граверах и т.д.
В целом интересны все Ваши предложения и замечания.


/* Name: Winding machine
Description: Arduino ATmega 328P + Stepper motor control CNC Shield v3 DRV8825 + 1602 LCD I2C menu + Encoder KY-040
Author: TDA
Ver: 1.0
Date: 07/07/2018

Arduino pinout diagram:
_______________
| USB |
| AREF|
| GND|
| 13| DIR A
|RESET 12| STEP A
|3V3 #11|
|5V #10|
|GND #9|
|VIN 8| EN STEP
| |
| 7| DIR Z
| #6|
|A0 #5| ENCODER DT
|A1 4| STEP Z
|A2 INT1 #3| ENCODER SW
|A3 INT0 2| ENCODER CLK
I2C LCD |A4 SDA TX 1|
I2C LCD |A5 SCL RX 0|
|_______________|
*/
#include
#include
#include
#include

#define ENC_CLK 2 // Деректива #define дает имя константе
#define ENC_SW 3
#define STEP_Z 4
#define ENC_DT 5
#define DIR_Z 7
#define EN_STEP 8
#define STEP_A 12
#define DIR_A 13

volatile int Encoder_Dir; // Направление вращения энкодера
volatile boolean Push_Button, Var_Set, DC, AutoWindStart; // Нажатие кнопки; режим установки значения; формирование сигнала STEP; работает подпрограмма автонамотки
volatile boolean Pause; // Флаг паузы в режиме автонамотка
volatile int i; // Счетчик кол-ва заходов в прерывание таймера
char Str_Buffer[22]; // Буфер для функции sprintf
byte LCD_Column, LCD_Row, Symbol_Code, Motor_Num; // Номер столбца и строки LCD; код символа https://i.stack.imgur.com/oZhjJ.gif; номер шагового двигателя
long int ActualShaftPos, ActualLayerPos; // Текущие позиции двигателей вала и укладчика
int Actual_Turn = 0, Actual_Layer = 0; // Текущий виток и слой при автонамотке
int Shaft_Pos, Lay_Pos, Set_Turns, Set_Step, Set_Speed=1, Set_Layers, Step_Mult=1; // Переменные изменяемые на экране
byte Menu_Index = 0; // Переменная хранит номер текущей строки меню

struct MenuType < // Структура описывающая меню
byte Screen; // Индекс экрана
byte string_number; // Номер строки на экране
char format[22]; // Формат строки
char format_Set_var[6]; // Формат значения при вводе переменной
int *param; // Указатель на адрес текущей переменной изменяемой на экране
int var_Min; // Ограничение значения переменной снизу
int var_Max; // Ограничение значения переменной сверху
byte param_coef;>; // Размерный коэффициент значения переменной

LiquidCrystal_I2C lcd(0x3F,16,2); // 0x3F I2C адрес для PCF8574AT, дисплей 16 символов 2 строки

void setup() <
pinMode(ENC_CLK, INPUT); // Инициализация входов/выходов
pinMode(ENC_SW, INPUT);
pinMode(STEP_Z, OUTPUT);
pinMode(ENC_DT, INPUT);
pinMode(DIR_Z, OUTPUT);
pinMode(EN_STEP, OUTPUT);
pinMode(STEP_A, OUTPUT);
pinMode(DIR_A, OUTPUT);
digitalWrite(EN_STEP, HIGH); // Запрет управления двигателями

lcd.init(); // Инициализация LCD
lcd.backlight(); // Включение подсветки LCD
lcd.createChar(0, up); // Записываем символ ⯅ в память LCD
lcd.createChar(1, down); // Записываем символ ⯆ в память LCD

cli(); // Глобальный запрет прерываний
EICRA = (1 » на 0,0 LCD

void loop() <
if (Encoder_Dir != 0) < // Проверяем изменение позиции энкодера
switch (Menu_Index) < // Если позиция энкодера изменена то меняем Menu_Index и выводим экран
case Autowinding: Menu_Index = constrain(Menu_Index + Encoder_Dir, Autowinding, PosControl); break;
case PosControl: Menu_Index = constrain(Menu_Index + Encoder_Dir, Autowinding, PosControl); break;
case TurnsSet: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case StepSet: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case SpeedSet: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case LaySet: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case Start: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case Cancel: Menu_Index = constrain(Menu_Index + Encoder_Dir, TurnsSet, Cancel); break;
case ShaftPos: Menu_Index = constrain(Menu_Index + Encoder_Dir, ShaftPos, PosCancel); break;
case LayPos: Menu_Index = constrain(Menu_Index + Encoder_Dir, ShaftPos, PosCancel); break;
case StepMul: Menu_Index = constrain(Menu_Index + Encoder_Dir, ShaftPos, PosCancel); break;
case PosCancel: Menu_Index = constrain(Menu_Index + Encoder_Dir, ShaftPos, PosCancel); break;>
Encoder_Dir = 0; PrintScreen();>

if (Push_Button == true) < // Проверяем нажатие кнопки
switch (Menu_Index) < // Если было нажатие то выполняем действие соответствующее текущей позиции курсора
case Autowinding: Menu_Index = TurnsSet; break;
case PosControl: Menu_Index = ShaftPos; break;
case TurnsSet: SetQuote(9,13); Push_Button=false; Var_Set=true; while(!Push_Button) Var_Set=false; ClearQuote(9,13); break;
case StepSet: SetQuote(7,14); Push_Button=false; Var_Set=true; while(!Push_Button) Var_Set=false; ClearQuote(7,14); break;
case SpeedSet: SetQuote(9,13); Push_Button=false; Var_Set=true; while(!Push_Button) Var_Set=false; ClearQuote(9,13); break;
case LaySet: SetQuote(9,12); Push_Button=false; Var_Set=true; while(!Push_Button) Var_Set=false; ClearQuote(9,12); break;
case Start: Push_Button = false; AutoWindStart = true; AutoWindingPrg(); AutoWindStart = false; break;
case Cancel: Menu_Index = Autowinding; break;
case ShaftPos: SetQuote(9,14); Push_Button=false; Var_Set=true; digitalWrite(EN_STEP, LOW); Motor_Num = 1;
while(!Push_Button)
Var_Set=false; digitalWrite(EN_STEP, HIGH); ClearQuote(9,14); break;
case LayPos: SetQuote(9,14); Push_Button=false; Var_Set=true; digitalWrite(EN_STEP, LOW); Motor_Num = 2;
while(!Push_Button)
Var_Set=false; digitalWrite(EN_STEP, HIGH); ClearQuote(9,14); break;
case StepMul: SetQuote(9,13);Push_Button=false;Var_Set=true; while(!Push_Button) Var_Set=false; ClearQuote(9,13); break;
case PosCancel: Menu_Index = Autowinding; Shaft_Pos = 0; Lay_Pos = 0; Step_Mult = 1; ActualShaftPos = 0; ActualLayerPos = 0; break;>
Push_Button = false; PrintScreen();>>

ISR(INT0_vect) < // Вектор прерывания от энкодера
byte Enc_Temp; // Временная переменная для хранения состояния порта
Enc_Temp = PIND & 0b00100100; // Маскируем все пины порта D кроме PD2 и PD5
if (Enc_Temp == 0b00000100 || Enc_Temp == 0b00100000) // +1 — шаг по часовой
else if (Enc_Temp == 0b00000000 || Enc_Temp == 0b00100100) // -1 — шаг против часовой
else // Если случайно(?!) вошли в прерывание то выходим
if (Var_Set == true && Encoder_Dir != 0) < // Если находимся в режиме изменения переменной
*Menu[Menu_Index].param += Encoder_Dir; Encoder_Dir = 0; // то меняем ее сразу и
*Menu[Menu_Index].param = constrain(*Menu[Menu_Index].param, Menu[Menu_Index].var_Min, Menu[Menu_Index].var_Max);> // ограничиваем в диапазоне var_Min ÷ var_Max
if (AutoWindStart == true && Encoder_Dir != 0) > // Если повернуть энкодер во время автонамотки
// то меняем значение скорости
ISR(INT1_vect) < // Вектор прерывания от кнопки энкодера
Push_Button = true;
if (AutoWindStart == true) // Если нажать кнопку энкодера во время автонамотки то выставляем флаг паузы
else return;>

ISR(TIMER1_COMPA_vect) < // Вектор прерывания от таймера/счетчика 1
i++; // Счетчик кол-ва заходов в прерывание
DC =! DC; // Первое прерывание устанавливает STEP следующее — сбрасывает
if (Motor_Num == 1) <
if (DC == true) // STEP_Z
else >
else if (Motor_Num == 2) <
if (DC == true) // STEP_A
else >>

Источник

Adblock
detector