пятница, 26 августа 2016 г.

14. Пишем парсер g-code средствами Arduino

  Что же такое G-код?  G-код — условное именование языка программирования устройств с числовым программным управлением (ЧПУ), был создан в 60-х годах прошлого столетия. В 80-х стал отраслевым стандартом ISO 6983-1:2009 на западе, в СССР это - ГОСТ 20999-83. Грубо говоря g-код это - список инструкций для ЧПУ станка, что бы он перемещал инструмент (сверло, фреза, печатающая головка) в нужной последовательности и в нужном направлении. Выглядит он примерно так: 

G0 X  47.585 Y  38.795
M3 M8
G0 Z   3.000
F150
G1 Z  -1.500
F400
G1 X  47.552 Y  38.836
G1 X  47.521 Y  38.879
G1 X  47.491 Y  38.923
G1 X  47.462 Y  38.969
G1 X  47.435 Y  39.017
G1 X  47.409 Y  39.066
G1 X  47.385 Y  39.117
G1 X  47.362 Y  39.171
G1 X  47.340 Y  39.226
G1 X  47.320 Y  39.284
G1 X  47.302 Y  39.343


   Получить управляющую программу для ЧПУ можно при помощи специальных CAM программ. CAM системы переводят 2d и 3d, разработанные в системах автоматизированного проектирования САПР (у буржуев это - CAD). Примером CAD может служить SolidWorks, AutoCAD и др. Какие я буду использовать CAD/CAM системы пока не знаю. В идеале хотелось бы иметь мощный инструмент с открытым исходным кодом. Но я точно знаю какие буду использовать программы sender.
   Sender - это программа которая выполняет функцию передачи g-кода с персонального компьютера на станок по COM порту (в моем случае COM-порт). Мне понравились Universal Gcode Sender и Grbl Controller. Достаточно простые программы, есть версии под linux.



   Итак вернемся к g-коду. Для того чтобы станок передвинул инструмент по осям X,Y необходимо в него передать команду:


 G1 X  47.552 Y  38.836

, где G1 - Команда, линейная интерполяция
X  47.552 - смещение по оси Х
Y  38.836 - смещение по оси Y

   Не смотря на то что g-код стандартизирован, я видел много его вариантов, например вместо G1 G01 или X47 и X 47 (с пробелом). Или вообще жесть типа:
G01 Z[-1.000000*#7+#10] F#4  

квадратные скобки, какие-то звездочки, плюсики. И как прикажите с таким кодом работать? Править вручную? Убирать лишние скобки и пробелы? Вот вам и стандартизация. Хочется максимально все автоматизировать, а значит передо мной стоит нелегкая задача написать универсальный парсер g-кода который будет понимать любой g-код. Мы радиолюбители! В наших жилах течет горячий припой! Мало того это нужно сделать средствами Arduino. В Arduino нет регулярных выражений, а еще он не умеет работать с числами с плавающей запятой. Как вы наверное заметили координаты у нас до трех знаков после запятой. AVR это вам не Intel 8086/8087 так что даже не знаю стоит ли за это браться. Уверен что стоит! «Фигня война! Главное – маневры!».
    В Ардуине есть богатый набор строковых функций. Описание на русском языке можно найти тут. Как известно EEPROM в AVR имеет ограниченное количество циклов записи — 100000 не так уж и много. Так что разработку мы будем проводить не на железе как обычно это делали а с помощью онлайн симулятора https://circuits.io/.  Circuits: виртуальная Arduino в браузере! Обладает богатым функционалом. Позволяет собирать виртуальные схемы на макетной плате, подключать вольтметры, осциллографы. А еще там есть редактор кода и монитор COM-порта как в толстой Arduino IDE. Конкретно за моими разработками можно следить тут



Продолжение следует... 

суббота, 2 апреля 2016 г.

13. Концевики, самодиагностика, установка нулевых точек


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

 

 Эти кнопки достаточно миниатюрны и имеют огромный ресурс - цикл нажатий. Как и любые другие кнопки они не лишены недостатков - так называемого дребезга. Как я с ним борюсь? Да никак. Только в параллель кнопке впаял конденсатор на 1 мкФ.

 

  Конечно это не дает стопроцентной защиты от дребезга контактов но значительно снижает его.
Мной был проведен эксперимент, целью которого была регистрация дребезга. В опытах без конденсатора кнопка меняла свое состояние от трех до семнадцати раз, с конденсатором один- два раза. 
  В принципе в моем случае с дребезгом можно вообще не бороться, это никак не влияет вообще ни на что. Ну вызвалась функция обработки аппаратного прерывания вместо одно раза - десять раз. И что? Да ничего. Функция обработки прерывания меняет только флаг/переменную (F_Nul_X, F_Nul_Y, F_Nul_Z) с 0 на 1 и все. А все остальное обрабатывается в основном цикле программы. Конечно можно было бы сделать задержку скажем на 50-100 миллисекунд для того чтобы прошел переходной процесс в кнопке и установилось устойчивое состояние 0 или 1, но в функции обработки прерывания не работает delay(). Какая досада, а ведь так хочется. Вот и получается что либо бороться с дребезгом контактов только аппаратными методами либо вообще не бороться.
  Ниже представляю код программы в среде Arduino IDE. Постарался все оформить в отдельных функциях и сделать понятные комментарии.
 
  Код программы в среде Arduino IDE:

#include <Stepper.h>

// Количество шагов в одном обороте шпинделя
#define STEPS_X 200
#define STEPS_Y 200
#define STEPS_Z 51

// Скорость вращения ШД
#define XSpeed 300
#define YSpeed 300
#define ZSpeed 200

// Выводы для управления ШД по оси Y
#define Xa 23
#define Xb 25
#define Xc 27
#define Xd 29

#define Ya 31
#define Yb 33
#define Yc 35
#define Yd 37

#define Za 39
#define Zb 41
#define Zc 43
#define Zd 45

// Флаги прерываний по осям
volatile boolean F_Nul_X = 0;
volatile boolean F_Nul_Y = 0;
volatile boolean F_Nul_Z = 0;

// Флаги пройденных тестов
int F_Test_XYZ =0;

boolean F_Test_X = 0;
boolean F_Test2_X = 0;

boolean F_Test_Y = 0;
boolean F_Test2_Y = 0;

boolean F_Test_Z = 0;
boolean F_Test2_Z = 0;

Stepper stepperX(STEPS_X, Xa, Xb, Xc, Xd);
Stepper stepperY(STEPS_Y, Ya, Yb, Yc, Yd);
Stepper stepperZ(STEPS_Z, Za, Zb, Zc, Zd);

void setup() {
  stepperX.setSpeed(XSpeed);
  stepperY.setSpeed(YSpeed);
  stepperZ.setSpeed(ZSpeed);
 
  attachInterrupt(2, X_stop, RISING); // инициализация прерываний
  attachInterrupt(3, Y_stop, RISING); //
  attachInterrupt(4, Z_stop, RISING); //

}

void loop() {
  // Проводим прогон и устанавливаем в нулевое положение все оси
  if (F_Test_XYZ == 0) {
    X_null();
    if (F_Test_X == 1 && F_Test2_X ==1) {
      stepperX.step(400);
      Atermo(Xa, Xb, Xc, Xd);
      F_Test_XYZ = 1;
      delay(2000); //Задержка-спецэфект :-)
    }
  }
  if (F_Test_XYZ == 1) {
    Y_null();
    if (F_Test_Y == 1 && F_Test2_Y ==1) {
      stepperY.step(400);
      Atermo(Ya, Yb, Yc, Yd);
      F_Test_XYZ = 2;
      delay(2000); //Задержка-спецэфект :-)
    }
  }
  if (F_Test_XYZ == 2) {
    Z_null();
    if (F_Test_Z == 1 && F_Test2_Z ==1) {
      stepperZ.step(-102);
      Atermo(Za, Zb, Zc, Zd);
      F_Test_XYZ = 3;
      delay(2000); //Задержка-спецэфект :-)
    }
  }
}

// Защита от перегрева ШД по осям
void Atermo(int A, int B, int C, int D) {
    digitalWrite(A, LOW); //
    digitalWrite(B, LOW); // Устанавливаем 0 по всем
    digitalWrite(C, LOW); // входам управления ШД
    digitalWrite(D, LOW); //
  }

/////////////////////////////////////////
// Установка оси X в нулевое положение //
/////////////////////////////////////////

void X_null()  {
  if (F_Nul_X == 0 && F_Test2_X == 0) {
       stepperX.step(-100);
  }
  else  {
    F_Test2_X = 1;
    Atermo(Xa, Xb, Xc, Xd);
    delay(2000); //Задержка-спецэфект :-)
   
    if (F_Nul_X == 1 && F_Test_X == 0)  { // После достижения нулевого положения каретка движется в обратном направлении
       for (int i=0; i <= 18; i++) {
         stepperX.step(2000);
       }
       F_Nul_X = 0;
       F_Test_X = 1;
       F_Test2_X = 0;
       Atermo(Xa, Xb, Xc, Xd);
       delay(2000); //Задержка-спецэфект :-)
    }
  }
}

/////////////////////////////////////////
// Установка оси Y в нулевое положение //
/////////////////////////////////////////

void Y_null()  {
  if (F_Nul_Y == 0 && F_Test2_Y == 0) {
       stepperY.step(-100);
  }
  else  {
    F_Test2_Y = 1;
    Atermo(Ya, Yb, Yc, Yd);
    delay(2000); //Задержка-спецэфект :-)
   
    if (F_Nul_Y == 1 && F_Test_Y == 0)  { // После достижения нулевого положения каретка движется в обратном направлении
       for (int i=0; i <= 18; i++) {
         stepperY.step(2000);
       }
       F_Nul_Y = 0;
       F_Test_Y = 1;
       F_Test2_Y = 0;
       Atermo(Ya, Yb, Yc, Yd);
       delay(2000); //Задержка-спецэфект :-)
    }
  }
}

/////////////////////////////////////////
// Установка оси Z в нулевое положение //
/////////////////////////////////////////

void Z_null()  {
  if (F_Nul_Z == 0 && F_Test2_Z == 0) {
       stepperZ.step(51);
  }
  else  {
    F_Test2_Z = 1;
    Atermo(Za, Zb, Zc, Zd);
    delay(2000); //Задержка-спецэфект :-)
   
    if (F_Nul_Z == 1 && F_Test_Z == 0)  { // После достижения нулевого положения каретка движется в обратном направлении
       for (int i=0; i <= 22; i++) {
         stepperZ.step(-510);
       }
       F_Nul_Z = 0;
       F_Test_Z = 1;
       F_Test2_Z = 0;
       Atermo(Za, Zb, Zc, Zd);
       delay(2000); //Задержка-спецэфект :-)
    }
  }
}

////////////////////////////////////
// Функции обработчики прерываний //
////////////////////////////////////

void X_stop() {
  F_Nul_X = 1;
}

void Y_stop() {
  F_Nul_Y = 1;
}

void Z_stop() {
  F_Nul_Z = 1;
}


  Видеоролик демонстрирует выполнение кода.


воскресенье, 27 марта 2016 г.

12. Драйвер шагового двигателя (версия 2)

  Наконец-то я доделал драйвер шагового двигателя. Теперь появилась возможность управлять тремя ШД по осям X, Y, и Z с помощью данного изделия. Схематически он мало отличается от предыдущего ШД, который я делал для первоначальных экспериментов. Разница заключается лишь в том, что он стал трехканальным. Для изготовления этого драйвера я впервые в жизни воспользовался специализированными средствами автоматизированного проектирования электронных схем и трассировки печатных плат. Мной был освоен САПР - DipTrace от компании "Новарм".  Теперь можно навсегда отказаться от Paint )).
  DipTrace  - это многофункциональная САПР по разработке электронных печатных плат и схемотехнической документации для проектов любой сложности, от идеи до готового устройства. Обладает богатым набором электронных компонентов. Я остался доволен и планирую ее использовать в будущих проектах.


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

  На рисунках ниже показан вид печатной платы с двух сторон. Особенностью данного драйвера шагового двигателя является то, что с его помощью можно управлять тремя ШД с разным напряжением питания. Для этого на разъем J2 подаются необходимые напряжения и все. А управление с Arduino осушествляется напряжением 5 вольт (разъем J3). Разъем J1 используется для подключения ШД.


 
  

  Файлы проекта DipTrace вы можете скачать - Драйвер ШД_4.dch Драйвер ШД_4.dip
  На фото ниже сам драйвер, как говорится в железе. Установлен на шасси и подключен к другим узлам. Отдельно хочется рассказать про шлейф управления. Его я сделал из старого шлейфа от флоппи дисковода 3,5 дюйма. Если у вас есть такие шлейфы то я вам рекомендую их выкидывать - чрезвычайно полезная вещь!

 
  
  В следующей статье я покажу управляющую программу и видео с автоматической установкой нулевых точек по трем осям.