Страница 1 из 7

Пример как можно генерировать шаги для ШД

Добавлено: 13 янв 2013, 18:37
wldev
Решил написать оч. простой пример как генерировать шаги для управления ШД.

Код: Выделить всё

/*Здравствуйте!
Хотел немного рассказать о генерации импульсов для ШД.
Есть задача произвести движение на заданное расстояние.

Нам понадобится структура WLDrive
*/
struct WLDrive
{
float t_st;  //время торможения, сек
float t_fi;  //время остановки, сек

float v_st;  //начальная скорость, ед/сек
float v_ma;  //скорость перемещения, ед/сек

float v_now;   //текущая скорость

float v_decel_ch; //скорость с которой начали тормозить

float dim;  //единица одного шага (дискрета перемещения)

long  step_mov;    //счётчик сделанных шагов
long  step_now;    //текущее положение

//флаги
bool readyF; //готов к перемещению
bool busyF;  //занят
bool startF; //пуск
bool accelF; //разгон
bool decelF; //торможение

bool breakF;//остановка по требованию

bool outStep;
bool outDir;

int T1ch;  //период
int T1;    //счётчик периода

long tickMov; //счётчик единиц времени


WLDrive()
 {
 t_st=t_fi=0.1; //устанавливаем начальные значения, время разгона и торможения = 0.1с
 
 v_st=10;
 v_fi=100;

 readyF=busyF=startF=false;
 accelF=decelF=breakF=false;

 freq=1000;
 dim=1;

 step_mov=step_now;
 }

void reset()
 {
 readyF=busyF=startF=false;
 accelF=decelF=breakF=false;
 } 

void break() //остановка
 {
 breakF=true;
 } 

bool setMovInc(float distance);  //задаём перемещение на заданное расстояние
  { 
  if(busyF
   ||startF) return false; 

  readyMov=true;
  step_mov=distance/dimm

  if(step_mov!=0) 
	  return true; 
  else 
	  return false;
  }

bool setMovAbs(float position);  //задаём перемещение в заданную позицию
  { 
  return setMovInc(step_now*dimm+position);
  }

bool start() //пуск
  {
  if(busyF
  ||!readyF) return false; //если привод не готов или находится в работе 

  startF=true;
  }

float Velocity()
{
float ch_delta=tickMov/freq; //сколько времени прошло
float ret;                   //скорость которая была расчитана
if(accelF)
  {
  if(t_st<=0) t_st=0.001;

  ret=v_st+(v_fi-v_st)*(ch_delta/t_st);  //T

  if(ch_delta>t_st)  return v_fi;
  if(ch_delta<=0)    return v_st;
  
  return ret;
  }
if(decelF)
  {
  if(t_fi<=0) t_fi=0.001;

  ret=v_st+(v_decel_ch-v_st)*((t_fi-ch_delta)/t_fi); //T

  if(ch_delta>t_fi)  return v_st;
  if(ch_delta<=0)    return v_decel_ch;

  return ret;
  }
return -1;
}



void redirect()  //пересчёт 
  {
  if(!busyF)//если двигатель не занят
    {
    if(startF   //если он был запущен и он готов к перемещению
	 &&readyF) 
		{
		busyF=true;     //устанавливаем флаг занятости
		startF=false    //сбрасываем флаг пуска

		if(step_mov>0)        //устанавливаем бит направления
			outDir=true;
		else
			outDir=false;

		tickMov=0;

		decelF=false;
		accelF=true;

		v_now=Velocity();

		T1ch=(long)((freq)*dim)/v_now; //длительность периода
		T1=0;

		return;
	    }
    }
  else
    {
    tickMov++;
	
	if(++T1>(T1ch>>1))     //если меньше пол периода то выводим 0 если болше 1
		outStep=true; 
	else 
		outStep=false;
	
	if(T1<T1ch) return;//если не сделали весь период то выходим
	 
	if(step_mov*dim>=(v_now*t_fi+(v_en-v_now)*t_fi/2)  //если оставшаяся дистанция меньше либо равна дистанции для остановки то начинаем остановку
        ||breakF)
		{
		accelF=false;
 	    decelF=true;
        
		v_decel_ch=v_now;

		tickMov=0;
	    }
	
	v_now=Velocity();

	T1ch=(long)((freq)*dim)/v_now; //длительность периода
	T1=0;

	if(step_mov>0)
	  {
	  step_mov--;
      step_now++;
	  }
	else
	  {
	  step_mov++;
      step_now--;
	  }
	
	if(step_mov==0 //если сделали все шаги
    ||(breakF&&decelF&&v_now==v_st)) //если остановка по требованию и мы замедлились 
	   {
	   busyF=false;
	   }
    }

  }

}



//Если для C
void main(void)
{
WLDrive Drive;//Создаём переменную

Drive.t_st=0.1;
Drive.t_fi=0.2;

Drive.v_st=1;
Drive.v_fi=5;

Drive.freq=1000;//максимальная частота вывода в порт
Drive.dim=1;

Drive.setMovInc(100);//переместится на 100
Drive.start();

do
{
Drive.redirect();
//берём биты направления и шага из Drive
/*
например как для аннруино
digitalWrite(OutStep1,Drive.outStep);
digitalWrite(OutDir1,Drive.outDir);
*/
}
while(Drive.busyF)//если Drive в работе то продолжаем цикл

}
Это сильно упрощённый код, от рабочего кода моей программы.
Если что могу пояснить...

Re: Пример как можно генерировать шаги для ШД

Добавлено: 13 янв 2013, 19:18
aftaev
Буду пробовать :)

Re: Пример как можно генерировать шаги для ШД

Добавлено: 13 янв 2013, 22:32
aftaev
Bender писал(а):Нам понадобится структура WLDrive
Это что такое? Ардуино на эт ругается :)

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 08:03
wldev
Переделал для андруино:

Копируем папку WLDrive(в архиве) в \Arduino\Dev\libraries.

Далее в редакторе добавляем библиотеку WLDrive

вот примерный главный код

Код: Выделить всё

#include <WLDrive.h>

WLDrive Drive1(1,2); //выход 1 - шаги 2 направление
int runPin = 13; 

void setup()
{
Drive1.setDim(0.1);
Drive1.setFreq(1000);
Drive1.setParam(1,5,0.1,0.1);

pinMode(runPin, INPUT);
}

void moving()
{
do                         //цикл движения
 {
 Drive1.redirect();
 }
while(Drive1.isBusy());

}

void loop()
{

if(digitalRead(runPin))
     {
     Drive1.setMovInc(100); 
     Drive1.start(); 
     moving();
     }
}
Интересно заработает ли?

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 09:08
aftaev
Bender писал(а):Интересно заработает ли?
А ты пробовал в Ардуино компилировать?

Вечером буду пробовать.

Нашел какие то библиотеки под Ардуину
Мои проекты на Ардуино #148

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 09:31
wldev
aftaev писал(а):А ты пробовал в Ардуино компилировать?
Да, специально скачивал...

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 09:52
wldev
aftaev писал(а):Нашел какие то библиотеки под Ардуину
Мои проекты на Ардуино #148
Посмотрел... Не увидел у них разгона и торможения...
А что я написал.... если заработает)), то можно и S разгон поставить...

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 10:08
aftaev
Bender писал(а):то можно и S разгон поставить...
ардуино не надорвется :)

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 12:49
wldev
aftaev писал(а):ардуино не надорвется
Смотря как они считают косинус..

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 13:37
aftaev
Откомпилировалось без ошибок :)
Bender, напиши комментарии к коду что за что отвечает/делает.

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 14:34
wldev
aftaev писал(а):Bender, напиши комментарии к коду что за что отвечает/делает.

Код: Выделить всё


WLDrive Drive1(1,2); //Создали двигатель и назначили выходные сигналы,выход 1 - шаги 2 направление
int runPin = 13; 

void setup()
{
Drive1.setDim(0.1);   //установка размера одного шага допустим 0.1мм или 0.1градус
Drive1.setFreq(1000);//установили частоту нашей системы. Это частота характеризующая быстродействие работы нашего генератора
                                 //если частота будет задана неверно, то будет расхождение между реальной скоростью перемещения и заданной.

Drive1.setParam(1,5,0.1,0.1);//Установили режим движения соотв.  (начальная скорость,конечная скорость,время разгона(с),время торможения(с))

pinMode(runPin, INPUT); //установили вход по которому будут события
}

void moving()
{
do                         //цикл движения(пересчёта) должен выполняться до тех пор пока* (см.ниже)
{
Drive1.redirect(); 
}
while(Drive1.isBusy()); //*-наш двигатель не освободиться

}

void loop()
{

if(digitalRead(runPin)) //Считываем runPin и если он в 1 (нажали кнопку)
     {
     Drive1.setMovInc(100);  //устанавливаем что нам нужно подвинуться на 100мм / 100градусов
     Drive1.start();   ///взводим
     moving();        //запускаем цикл движения
     }
}
можно сделать и по другому

Код: Выделить всё


WLDrive Drive1(1,2); //Создали двигатель и назначили выходные сигналы,выход 1 - шаги 2 направление
int runPin = 13; 

void setup()
{
Drive1.setDim(0.1);   //установка размера одного шага допустим 0.1мм или 0.1градус
Drive1.setFreq(1000);//установили частоту нашей системы. Это частота характеризующая быстродействие работы нашего генератора
                                 //если частота будет задана неверно, то будет расхождение между реальной скоростью перемещения и заданной.

Drive1.setParam(1,5,0.1,0.1);//Установили режим движения соотв.  (начальная скорость,конечная скорость,время разгона(с),время торможения(с))

pinMode(runPin, INPUT); //установили вход по которому будут события
}


void loop()
{

if(digitalRead(runPin)) //Считываем runPin и если он в 1 (нажали кнопку)
     {
     Drive1.setMovInc(100);  //устанавливаем что нам нужно подвинуться на 100мм / 100градусов
     Drive1.start();   ///взводим
     }

Drive1.redirect();
}

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 15:06
aftaev
Bender писал(а):Это частота характеризующая быстродействие работы нашего генератора
                                 //если частота будет задана неверно, то будет расхождение между реальной скоростью перемещения и заданной.
Как ее расчитывать? Или просто нельзя завышать, но можно ставить меньше значение?
Bender писал(а):начальная скорость,конечная скорость
как понять начальная скорость? Двиг стоит = 0 и остановиться должен 0
Bender писал(а)://цикл движения(пересчёта) должен выполняться до тех пор пока* (см.ниже)
//*-наш двигатель не освободиться
Как быть если нужно экстренный останов ЕСТОП? Будет тормозить плавно или резко и пропустит шаги?

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 16:45
wldev
aftaev писал(а):Как ее расчитывать? Или просто нельзя завышать, но можно ставить меньше значение?
Не завышать...
Лучше всего подобрать, но можно ещё дописать на авторасчёт...
aftaev писал(а):как понять начальная скорость? Двиг стоит = 0 и остановиться должен 0
Тогда и ставь 0, просто у меня на станке все двигатели начинают работать с не нулевой скорости, тогда время позиционирования меньше
aftaev писал(а):Как быть если нужно экстренный останов ЕСТОП? Будет тормозить плавно или резко и пропустит шаги?

Код: Выделить всё

WLDrive Drive1(1,2); //Создали двигатель и назначили выходные сигналы,выход 1 - шаги 2 направление
int runPin = 13; 
int emgPin = 14; 
int stopPin = 15; 

void setup()
{
Drive1.setDim(0.1);   //установка размера одного шага допустим 0.1мм или 0.1градус
Drive1.setFreq(1000);//установили частоту нашей системы. Это частота характеризующая быстродействие работы нашего генератора
                                 //если частота будет задана неверно, то будет расхождение между реальной скоростью перемещения и заданной.

Drive1.setParam(1,5,0.1,0.1);//Установили режим движения соотв.  (начальная скорость,конечная скорость,время разгона(с),время торможения(с))

pinMode(runPin, INPUT); //установили вход по которому будут события
pinMode(emgPin, INPUT);
pinMode(stopPin, INPUT);
}


void loop()
{

if(digitalRead(runPin)) //Считываем runPin и если он в 1 (нажали кнопку)
     {
     Drive1.setMovInc(100);  //устанавливаем что нам нужно подвинуться на 100мм / 100градусов
     Drive1.start();   ///взводим
     }

if(digitalRead(emgPin)) //экстренная остановка
     {
     Drive1.reset();   
     }

if(digitalRead(stopPin)) //плавная остановка
     {
     Drive1.stop(); 
     }

Drive1.redirect();
}

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 16:46
wldev
Ты главное попробуй, работает или нет? а сервис можно и добавить...

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 17:02
aftaev
Bender писал(а):Ты главное попробуй, работает или нет? а сервис можно и добавить...
уже собираю макетку

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 17:58
aftaev
Код малость подправил. Двиг крутиться :cheesy:
Менял частоту, нач, конечную скорость особо ничего не меняется скорость одна и таже.
Как задавать направление вправо/влево?
Как задавать скорость?

правим этот код, чтоб его не переписывал под свои пины :eat:

Код: Выделить всё

#include <WLDrive.h>
WLDrive Drive1(14,15); //Создали двигатель и назначили выходные сигналы,выход 1 - шаги 2 направление

//кнопки
int adc_key_in; // Пуск

void setup()
{
  //  // НАСТРОЙКА ЭКРАНА
  //  myGLCD.InitLCD(LANDSCAPE); // задаем экран горизонтально 
  //  //myGLCD.InitLCD(); // задаем экран вертикально
  //  myGLCD.clrScr(); // очистка экрана
  Serial.begin(9600);  // Инициализация СОМ порта

  //настраиваем ПИНЫ
//   pinMode(outBeep, OUTPUT);      // устанавливает режим работы - выход
//   pinMode(out2, OUTPUT);      // устанавливает режим работы - выход
//   pinMode(out3, OUTPUT);      // устанавливает режим работы - выход   
//   pinMode(out4, OUTPUT);      // устанавливает режим работы - выход 

   Drive1.setDim(0.1);   //установка размера одного шага допустим 0.1мм или 0.1градус
   Drive1.setFreq(2000);//установили частоту нашей системы. Это частота характеризующая быстродействие работы нашего генератора

    Drive1.setParam(1000,5000,0.1,0.1);//Установили режим движения соотв.  (начальная скорость,конечная скорость,время разгона(с),время торможения(с))
   
}

//--------------------------------------------------------------------------------------------------------------------------------------------------
//                                              ОСНОВНАЯ ПРОГРАММА  
//--------------------------------------------------------------------------------------------------------------------------------------------------
void loop()
{
  adc_key_in = analogRead(0);   // АЦП нажатой кнопки 
  
  if(adc_key_in == 0) //Считываем runPin и если он в 1 (нажали кнопку)
     {
         Drive1.setMovInc(100);  //устанавливаем что нам нужно подвинуться на 100мм / 100градусов
         Drive1.start();   ///взводим
     }
  Drive1.redirect();
}

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 18:14
wldev
aftaev писал(а):Код малость подправил. Двиг крутиться
Ура..
aftaev писал(а):Менял частоту, нач, конечную скорость особо ничего не меняется скорость одна и таже.
Попробуй сильно изменить, просто андруино тяжело с большой частотой работать...
И там во время установки параметров движения, происходит проверка и если он не сможет выдать скорость, то он игнорирует эти параметры.

У тебя стои частота 2000 т.е. это максимальная частота сигнала степ. 10101010...
тогда максимальная скорость при дискрете 0.1(мм) будет 0,1(мм)*2000(1/м)=200 (мм/с)

забыл сказать скорости в ед/секунду
aftaev писал(а):Как задавать направление вправо/влево?
Условно
Вперёд Drive1.setMovInc(100);
Обратно Drive1.setMovInc(-100);

Код: Выделить всё


bool lastRot;//запомним прошлое направление вращения

void setup()
{
  //  // НАСТРОЙКА ЭКРАНА
  //  myGLCD.InitLCD(LANDSCAPE); // задаем экран горизонтально 
  //  //myGLCD.InitLCD(); // задаем экран вертикально
  //  myGLCD.clrScr(); // очистка экрана
  Serial.begin(9600);  // Инициализация СОМ порта

  //настраиваем ПИНЫ
//   pinMode(outBeep, OUTPUT);      // устанавливает режим работы - выход
//   pinMode(out2, OUTPUT);      // устанавливает режим работы - выход
//   pinMode(out3, OUTPUT);      // устанавливает режим работы - выход   
//   pinMode(out4, OUTPUT);      // устанавливает режим работы - выход 

   Drive1.setDim(0.1);   //установка размера одного шага допустим 0.1мм или 0.1градус
   Drive1.setFreq(2000);//установили частоту нашей системы. Это частота характеризующая быстродействие работы нашего генератора

   if(!Drive1.setParam(10,200,0.1,0.1))//Установили режим движения соотв.  (начальная скорость,конечная скорость,время разгона(с),время торможения(с))
       {
       Serial.Print("Moving parametr is wrong!"); //я точно незнаю как печатать но вроде так
       }

   lastRot=true;
   
}

//--------------------------------------------------------------------------------------------------------------------------------------------------
//                                              ОСНОВНАЯ ПРОГРАММА  
//--------------------------------------------------------------------------------------------------------------------------------------------------



void loop()
{
  adc_key_in = analogRead(0);   // АЦП нажатой кнопки 
  
   if(adc_key_in == 0 //Считываем runPin и если он в 1 (нажали кнопку)
 &&!Drive1.isBusy()) //И двигатель не в работе
     {
         if(lastRot)
               Drive1.setMovInc(100);  //устанавливаем что нам нужно подвинуться на 100мм / 100градусов
          else
               Drive1.setMovInc(-100);  //устанавливаем что нам нужно подвинуться на -100мм / -100градусов

         lastRot=!lastRot;

         Drive1.start();   ///взводим
     }
  Drive1.redirect();
}
Теперь должен:
1. писать ошибку если параметры движения некорректны.
2. по первому нажатию едет вперёд, по второму назад и т.д.

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 18:29
aftaev
Bender писал(а):if(!Drive1.setParam(10,200,0.1,0.1))//Установили режим движения соотв.  (начальная скорост
Bender писал(а):if(!Drive1.setParam(200,10,0.1,0.1))//Установили режим движения соотв.  (начальная скорост
Нажимаю Пуск -вперед едит медленно, Нажимаю еще раз - назад едит быстро
Если делаю так
if(!Drive1.setParam(10,10,0.1,0.1))//Установили режим движения соотв.
Туда и обратно едит с одинаковой скоростью!

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 18:36
wldev
aftaev писал(а):Нажимаю Пуск -вперед едит медленно, Нажимаю еще раз - назад едит быстро
Если делаю так
Щас посмотрим...

Re: Пример как можно генерировать шаги для ШД

Добавлено: 14 янв 2013, 18:44
wldev
исправил

добавил

Установить текущую позицию
Drive1.setPosition(150);

Взять текущую позицию
float curPos=Drive1.getPosition(150);