Намоточный станок на базе Arduino

Намоточный станок на базе Arduino


Date of publication 25.03.2024



Несмотря на то, что студенческие годы далеко позади, электрогитара и увлечение музыкой остались в моей жизни как хобби. А инженерный бэкграунд и неугасаемое любопытство привели к тому, что несколько месяцев назад я увлёкся темой изготовления звукоснимателей и начал погружаться в этот удивительный мир, изучая и конспектируя литературу. Но теория должна подкрепляться практикой, поэтому в какой-то момент мне понадобился намоточный станок и я решил его изготовить самостоятельно. В наличии имеется 3d-принтер, в Компас 3D работать немного умею и с Arduino факультативно знаком, а вот с ТММ (Теория Машин и Механизмов) уже всё гораздо печальнее, но это не повод сдаваться!

О намотке катушек звукоснимателей

Данная статья именно про изготовление намоточного станка, но так как планируется мотать катушки звукоснимателей для электрогитары, то придётся учитывать определённую специфику при его проектировании.

Для начала разберёмся с типами намотки, их всего 2:

  1. Ручная намотка - двигатель вращает катушку, а оператор контролирует натяжение и укладку провода (провод скользит между пальцев). Повторяемость характеристик при таком методе намотки остаётся весьма условной и зависит от опыта оператора. Отсюда и легенды про гипотетическую "бабу Зину с Фендера", которая в 60-х мотала датчики с "тем самым" звуком :) В наше время, звукосниматели намотанные вручную, называют "бутиковые" - звучит солидно, хоть и сомнительно.
  2. Автоматическая намотка - шаг намотки, натяжение, скорость, паттерн укладки - всё контролируется высокоточным станком с ЧПУ. Тут уже не забалуешь, поэтому повторяемость характеристик остаётся высокой, что на мой взгляд является несомненным преимуществом.

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

Теперь про толщину провода - он очень тонкий. Например если взять тот же AWG 42, то диаметр медной жилы составит всего 0,0635 мм. Мотать такой провод нужно очень осторожно - лишние нагрузки могут привести к его растяжению или обрыву, а ни того, ни другого мне не надо.

Первый неудачный прототип станка

Первый вариант намоточного станка оказался не очень удачным, так как я несколько спешил - уж очень хотелось послушать как звучит "бутиковый" звукосниматель :D

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

Началось всё со сборки макета и написания скетча:

Электронная начинка намоточного станка

За основу я взял Arduino UNO (точнее плату c Aliexpress, внешне напоминающую Arduino UNO), так же заказал джойстик и дисплей 1602 + I2C, чтобы задействовать минимум пинов на плате.

Чтобы было удобно задавать точное число витков, я решил использовать биполярный шаговый двигатель HANPOSE 17HS4401 в форм-факторе Nema 17. Двигатель реально классный, одно удовольствие с ним работать! А вот с драйвером я промахнулся и вначале поставил L298N. Он достаточно быстро нагревается и двигатель начинает пропускать шаги - это уже выяснилось в процессе намотки первых образцов. В последствии я поставил драйвер TB6560, который отлично справляется со своей задачей.

Далее в Компас 3D я спроектировал первые детали станка, в том числе корпус и основание и распечатал, после чего начал сборку:

Сборка намоточного станка

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

Частично собранный станок

Далее был допечатан укладчик и проведены первые испытания:

Прототип намоточного станка

Теперь я расскажу о проблемах данного решения:

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

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

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

Работа над ошибками и итоговый вариант

Я распечатал совершенно новый держатель бобины:

Держатель бобины

Здесь уже 2 точки опоры и запроектирован магнитный тормоз на небольших неодимовых магнитах (5х2 мм). Усилие можно регулировать как количеством магнитов на тормозном диске, так и расстоянием между магнитами, которое регулируется на держателе. Итоговый вариант выглядит так:

Намоточный станок с обновлённой бобиной

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

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

Кроме этого, был случайно проведён незапланированный краш-тест станка, в результате чего уцелели не только лишь все детали. Пришлось в качестве основания взять лист фанеры размером 30х30 см. и смонтировать всё заново.

Вот так выглядит обновлённый укладчик:

Обновлённый укладчик

Конструкция стала более жёсткой, люфты ушли. Вместо прецизионных валов я использовал гладкие мебельные болты DIN603 (8х100 мм) из Леруа Мерлен - по ним прекрасно скользит укладчик. Для станка с автоматической намоткой такой номер не пройдёт - там очень важна точность, а для ручной намотки такое решение очень даже подходит.

В качестве демпфера выступает журавль на пружине и ограничителем хода. Основание журавля установлено на подшипник 688ZZ, чтобы избежать лишних люфтов. Те же подшипники используются в роликах. А вал червячного механизма уже на подшипниках 608ZZ.

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

На заднем плане виден новый драйвер шагового двигателя - TB6560, про который я рассказывал ранее. Он хорошо справляется со своей задачей и не перегревается при долгой работе + в нем присутствует масса настроек (ограничение тока, делитель шагов). Такой драйвер можно использовать и для станка с автонамоткой.

Итоговый результат

Так выглядит готовый станок целиком. На этом фото уже намотана первая тысяча витков на катушку звукоснимателя:

Готовый намоточный станок для ручной намотки звукоснимателей

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

Общая схема электронной начинки станка выглядит так:

Схема намоточного станка

Ну и конечно же сам скетч:

#include <AccelStepper.h>
#include <LiquidCrystal_I2C.h>

// пин подключения контакта VRX
#define PIN_VRX A0
// пин подключения контакта VRY
#define PIN_VRY A1
// пин подключения кнопки
#define PIN_START_STOP_BUTTON 7
const int DIR_PIN = 2;
const int ENABLE_PIN = 3;
const int STEP_PIN = 5;

// ограничение по максимальному числу оборотов в минуту
const long MAX_RPM = 600;
// ограничение по минимальному числу оборотов в минуту
const long MIN_RPM = 60;
// ограничение по максимальному числу витков
const long MAX_TURNS = 20000;
// ограничение по максимальному числу витков
const long MIN_TURNS = 100;
// количество шагов за одну итерацию (200 шагов = 1 оборот)
const long STEPS_PER_REV = 200;

// пункты меню
const int MENU_WINDING_STATUS = 0;
const int MENU_SET_SPEED = 1;
const int MENU_SET_TURNS = 2;

// пункт меню
int menu = MENU_SET_SPEED;
// число оборотов в минуту
long speedRpm = MAX_RPM;
// число витков для намотки
long targetNumberOfTurns = 100;
// фактически намотанное количество витков
long currerntNumberOfTurns = 0;
// состояние намотки (true - намотка идёт, false - намотка остановлена)
boolean winding = false;

// Определение тип интерфейса двигателя
#define motorInterfaceType 1
// Создаем экземпляр
AccelStepper stepper(motorInterfaceType, STEP_PIN, DIR_PIN);

LiquidCrystal_I2C lcd(0x27,16,2);

void setup() {
  Serial.begin(9600);

  lcd.init();
  lcd.backlight(); // включение подсветки дисплея

  stepper.setPinsInverted(true, false, false);
  disableStepper();
}

void loop() {  
  if (winding) {  
    stepper.runToPosition();
    currerntNumberOfTurns = stepper.currentPosition()/200;

    Serial.println("currerntNumberOfTurns = "  + String(currerntNumberOfTurns));
    Serial.println("targetNumberOfTurns = "  + String(targetNumberOfTurns));

    if (stepper.distanceToGo() == 0) {
      winding = false;
      disableStepper();
    }
  } 
  
  checkAndHandleStartStopButton();
  checkAndHandleVRX();
  checkAndHandleVRY();

  switch (menu) {
    case MENU_WINDING_STATUS:
      lcd.setCursor(0,0);
      if (winding) {
        lcdPrint("WINDING...");
      } else {
        lcdPrint("COMPLETED!");
      }

      lcd.setCursor(0, 1);
      lcdPrint(String(currerntNumberOfTurns));
      break;
    case MENU_SET_SPEED:
      lcd.setCursor(0, 0);
      lcdPrint("SPEED:");
  
      lcd.setCursor(0, 1);
      lcdPrint(String(speedRpm) + " RPM");
      break;
    case MENU_SET_TURNS:
      lcd.setCursor(0,0);
      lcdPrint("NUMBER OF TURNS:");

      lcd.setCursor(0, 1);
      lcdPrint(String(targetNumberOfTurns));
      break;
  }
  lcd.display();
}

/**
 * Обработка нажатия кнопки старт/стоп
 */
void checkAndHandleStartStopButton() {
  boolean startStopButtonState = digitalRead(PIN_START_STOP_BUTTON);
  startStopButtonState = debounce(startStopButtonState, PIN_START_STOP_BUTTON);
  if (startStopButtonState == HIGH) {
    return;
  }
  if (!winding) {
    enableStepper();
    
    winding = true;
    menu = 0;
    currerntNumberOfTurns = 0;
    long stepperSpeed = (speedRpm * STEPS_PER_REV) / 60;
    
    stepper.setMaxSpeed(stepperSpeed);
    stepper.setAcceleration(100);
    stepper.setSpeed(stepperSpeed);
    stepper.move(targetNumberOfTurns * STEPS_PER_REV); 
    
    Serial.println("Start winding");
    delay(1000);
  } else {
    winding = false;
    disableStepper();
    Serial.println("Stop winding");
    delay(1000);
  }
}

/**
 * Управление пунктами меню с помощью джойстика
 */
void checkAndHandleVRX() {   
  if (winding) {
    return;
  }
  int x = analogRead(PIN_VRX);
  Serial.print("X = ");
  Serial.println(x);
  if (x > 700) {
    if (menu > 1) {
      menu--;
    } else {
      menu = MENU_SET_TURNS;
    }
    delay(100);
  } else if (x < 300) {
    if (menu < 2) {
      menu++;
    } else {
      menu = MENU_SET_SPEED;
    }
    delay(100);
  }
}

/**
 * Настройка параметров станка с помощью джойстика
 */
void checkAndHandleVRY() {   
  if (winding) {
    return;
  }
  int y = analogRead(PIN_VRY);
  Serial.print("Y = ");
  Serial.println(y);
  if (y < 200) {
    switch(menu) {
      case MENU_SET_SPEED:
        speedRpm = speedRpm + 10;
        if (speedRpm > MAX_RPM) {
          speedRpm = MAX_RPM;
        }
        break;
      case MENU_SET_TURNS:
        targetNumberOfTurns = targetNumberOfTurns + 100;
        if (targetNumberOfTurns > MAX_TURNS) {
          targetNumberOfTurns = MAX_TURNS;
        }
        break;
    }
  } else if (y > 800) {
    switch(menu) {
      case MENU_SET_SPEED:
        speedRpm = speedRpm - 10;
        if (speedRpm < MIN_RPM) {
          speedRpm = MIN_RPM;
        }
        break;
      case MENU_SET_TURNS:
        targetNumberOfTurns = targetNumberOfTurns - 100;
        if (targetNumberOfTurns < MIN_TURNS) {
          targetNumberOfTurns = MIN_TURNS;
        }
        break;
    }
  }
}

/**
 * Считывание значения кнопки с поправкой на дребезг контактов
 */
boolean debounce(boolean last, int pin) {
  boolean current = digitalRead(pin);
  if (last != current) {
    delay(100);
    current = digitalRead(pin);
  }
  return current;
}

/**
 * Вывод информации на дисплей
 */
void lcdPrint(String str) {
  while (str.length() < 16) {
    str = str + " ";
  }
  lcd.print(str);
}

/**
 * Отключение питания на управляющих контактах двигателя
 */
void disableStepper() {
    digitalWrite(ENABLE_PIN, LOW);
}

void enableStepper() {
    digitalWrite(ENABLE_PIN, HIGH);
}

Как видно из кода выше, в меню станка есть 2 настройки: число витков и скорость намотки. Запуск двигателя происходит плавно с ускорением, а остановка с замедлением, что исключает возникновение ударной нагрузки на провод. После того, как заданное число витков намотано - двигатель останавливается, а намотанное количество запоминается - это позволяет мотать катушку в несколько этапов и по завершении каждой итерации на экране будет высвечиваться точное число намотанных витков на катушке.

Метод runToPosition() является блокирующим, так что подсчёта витков в режиме реального времени нет. Данный метод не рекомендуется вызывать в цикле, как сделано у меня - в библиотеке AccelStepper есть асинхронные методы, которые предназначены для вызова в цикле, но нужно обеспечить при этом быструю работу самого цикла. В моём случае такой возможности нет, так как та же операция обновления экрана не очень быстрая, а ещё нужно проверять состояние кнопок с поправкой на дребезг контактов. Можно добавить ещё одну плату Arduino только для управления двигателем и обеспечить уже там быстрый цикл, а первую плату оставить на пользовательский интерфейс и настроить обмен информацией между ними, тогда должно получится отображать число намотанных витков уже в процессе намотки без ущерба скорости вращения двигателя, но в данном станке такую доработку выполнять я не планирую.

Результат работы намоточного станка

С помощью данного намоточного станка я успешно изготовил первые образцы звукоснимателей и теперь они проходят испытания:

Звукосниматель

Он же в одной из моих электрогитар:

Звукосниматель в электрогитаре

Про сами звукосниматели рассказывать пока рано - ещё предстоит много экспериментов, измерений и доведений до ума. Но если будет интересно, в будущем напишу статью и на эту тему.

Заключение

Все необходимые stl-файлы я выложил в общий доступ, может кому-то пригодится: https://www.thingiverse.com/thing:6547604

Список дополнительных компонентов:

  1. Винты разной длины М3 и М4.
  2. Болт мебельный DIN603 с гайкой 8х100 мм, 2 шт.
  3. Подшипники: 608ZZ - 4 шт., 688ZZ - 4 шт.
  4. Пружина растяжения (подобрать по длине и усилию)
  5. Неодимовые магниты 5х2 мм (20 штук на держателе катушки, и 1-2 штуки на тормозных дисках, ставить по одному и проверять усилие вращения катушки)
  6. Arduino UNO
  7. LCD 1602 + i2c
  8. Джойстик для Arduino
  9. Драйвер шагового двигателя TB6560.
  10. Шаговый двигатель биполярный 17HS4401 (Nema 17)
  11. Фанера 30х30.
  12. Мебельные войлочные диски диаметром 15мм, для натяжителя - 2 шт.

Скетч доступен на GitHub: https://github.com/AlexeyKutepov/winding-machine/blob/main/winder.ino

Так же приглашаю всех желающих подписаться на мой Telegram-канал, в котором я делюсь большим количеством полезной информации о разработке программного обеспечения (в том числе и своими новыми статьями): https://t.me/akutepov