Господа, подскажите. Как реализовать следующую проект.

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

SU-27-16 пишет:

давайте будем ШД крутить.... паукист уже в другой ветке....


Дык а что его крутить то, 2.54 импульса автора устраивают. Тоже хочу научиться принимать .54 импульса. Но автор наверное не раскроет секрет. :(

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Puhlyaviy пишет:
Дадада. Мы тут не добрые. Мы тут садисты, хотим что бы люди научились думать, а не копировать.

согласен... но можно и подсказать - в какую сторону идтить ( кроме на ........ ), а то на пЫво перекинется...

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

Puhlyaviy пишет:
SU-27-16 пишет:

давайте будем ШД крутить.... паукист уже в другой ветке....

Дык а что его крутить то, 2.54 импульса автора устраивают. Тоже хочу научиться принимать .54 импульса. Но автор наверное не раскроет секрет. :(

да всё он уже понял..... нехорошо, мне кажется, здесЯ спрашивать, всех ругать в неоказании помощи - а когда прозрел - покидать тему молча, без результатов своих ( про ПАСИБО и речи нет )

cactous
Offline
Зарегистрирован: 18.11.2013

Результат будет после тестирования. А спасибо где-то говорил выше:)  Ну могу еще сказать спасибо. Мне не жалко. 

 

На счет .54 импульса.  Не понятно что именно обьяснять. 

Собираю принтер. Планшетник.  Задача согласовать  вращение вала принтера (донора) и привод стола. Вот   и все.  Теперьзадача решена. Получился электронный "редуктор", который может вращать ШД с заданным К относительно основного вала. Синхронность пока устраивает. После тестов будет понятно, то ил это чт нужно или дальше думать.

cactous
Offline
Зарегистрирован: 18.11.2013
void setup()
{
  attachInterrupt(1, schet, FALLING);
 // здесь еще много всего но самое главное прерывание все переменные обьявлены, все пина обозначены, ничего не забыл.
}

void schet() // функция обработки сигнала с энкодера
{
  if(flagPrint!=0)
    {
      if (digitalRead(encoder2) == digitalRead (3))  // определяем направление
        {
         moved = moved + stpEnc;
        }
    }
   
}

void loop()
{
 if(flagPrint!=0)
  {
    digitalWrite (dir,0); // направление вращения
    while(digitalRead(pinend)==0) // пока датчик не перекроится
  { 
  
  if (moved >stpStepMot)
    { 
      digitalWrite (stp,1); //импульс на step
      digitalWrite (stp,0);//
      moved = moved - stpStepMot;
      delayMicroseconds(20);
      flagPrint=2;//флаг режимов установлен в положение идет печать.
      
     }
   }
   moved=0;
   flagPrint=0;
  }
}

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



cactous
Offline
Зарегистрирован: 18.11.2013

Не хватает производительности ардуино.

Оставил в прерывании только это

  void schet() // функция обработки сигнала с энкодера
{
       moved = moved + stpEnc;    
 }

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

Что можете посоветовать?

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

cactous пишет:

Не хватает производительности ардуино.

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

Что можете посоветовать?

советую, угостить нас кофе, будем угадывать по гуще, каким именно ардуино вы пользуетесь... и советвоать взять ардуину побыстрее

cactous
Offline
Зарегистрирован: 18.11.2013

Я бы с удовольствием:)  Арудино мини про. 16MHZ.  А какие есть побыстрее? Знаю что ест монстры типа megа или Due, но там уж очень много  всего ненужного, да и размеры их далеки от компактности.  

Puhlyaviy
Puhlyaviy аватар
Offline
Зарегистрирован: 22.05.2013

cactous пишет:

Я бы с удовольствием:)  Арудино мини про. 16MHZ.  А какие есть побыстрее? Знаю что ест монстры типа megа или Due, но там уж очень много  всего ненужного, да и размеры их далеки от компактности.  

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

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

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

Что можете посоветовать?

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

Как альтернатива:воспользоваться поиском по форуму. Ветки про проблемы с энкодерами - были далеко не одна.

Я сам в свое время бодался, правда с механическим, ОЧЕНЬ ДОЛГО. И пока из ардуины не сделал простейший логический анализатор и не увидел что-же в РЕАЛЬНОСТИ он мне выдает (а не теория из блогов) - сдвинуться с мертвой точки не мог. У оптических, проблемы "дребезга" по идее быть не должно, но вот опять-таки судя по возникавшим тут веткам, ловить помехи, особенно в случае всяких мотор-шилдов - они тоже полюбляют.

cactous
Offline
Зарегистрирован: 18.11.2013

Arduino Mega рельно быстрее чем Mini Pro или Uno, ведь частота тоже 16MHZ?

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Arduino Mega рельно быстрее чем Mini Pro или Uno, ведь частота тоже 16MHZ?

не реально.

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

cactous
Offline
Зарегистрирован: 18.11.2013

Как же в этом убедиться на сто процентов?  Энкодер вдрял ли дает дребезг и помехи. Потому что в самом начале,  проверял его разрешение, вращал его шаговиком и считал импульсы, все было идеально четко при каждом обороте насчитывал одинаковое количество импульсов 1416 +-1. Увеличивал обороты  пока показания не начали сбиваться. 

Только что проверил, интервал между двумя фронтами импульсов 200мкс.  Много это или мало,  успевает ардуино считать их или нет, как это узнать?

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Как же в этом убедиться на сто процентов?  

Вторая ардуина есть?

cactous пишет:

Энкодер вдрял ли дает дребезг и помехи.

Ну по моим субъективным наблюдениям они чаще дают чем не дают помехи... правда тут скорее было-бы "лишнее", хотя...

cactous пишет:

Потому что в самом начале,  проверял его разрешение, вращал его шаговиком и считал импульсы,

А скорость вращения такая же как у вала была?

cactous пишет:

все было идеально четко при каждом обороте насчитывал одинаковое количество импульсов 1416 +-1. Увеличивал обороты  пока показания не начали сбиваться. 

А шаговиком обороты

cactous пишет:

Только что проверил, интервал между двумя фронтами импульсов 200мкс.  

Не густно, но в принципе "должно вполне хватать шустрости".

А вы вообще уверены что "не хватает шустрости"?  Может ошибка в коде, и вы просто не успеваете выводить, не успеваете шагать, переполнение или еще что-то в этом стиле.

Скажем ваш код в #55 - довольно "не безопасен". Смотрим на строки 27, 31... вы догадываетесь что пока ардуина добежит от 27 до 31 строки, moved уже может 100 раз поменятся?  Даже сама строка 31 не  имеет гарантии правильного выполнения. Пока moved-stpStepMot выполнится и присвоется moved.... хоп. этот момент выполнилось прерывание и moved увеличилось от своего старого значения. В итоге вы думаете что учли этот шаг, а на самом деле - нифига.
 

Или строки 37,38. Думаете обнулили moved?  А не факт. Может да, а может нет. Между ними вполне прерывание может сработать, в результате в следующий раз moved у вас совсем не с нуля начнется.

И это еще не факт что саму переменую moved корректно объявили, вероятность что забыли про volatile - совсем не нулевая.

 

cactous
Offline
Зарегистрирован: 18.11.2013

Спасибо за ваше участи в моей проблеме.

Отвечаю по порядку.

Есть несколько ардуин.

 

По поводу строк 27-31, что в них опасного? Проверяем если moved больше шага шаговика то шагаем, это необходимо чтобы шаговик не убежал быстрее вала и moved не стало меньше нуля. Даже если moved изменится во время выполнения строк 27-31 ничего страшного не прозиойдет, догони в следующем цикле, в том то и смысл что moved "накапливает" изменение положения энкодера,   и шаговик его догоняет, по мере возможности. Не должно пройденное расстояние теряться, а теряется, причем каждый проход по разному. Объясните в чем я не прав.

 

По 31 строке полностью согласен. Подумал и правда, а чтоже делать? Использовать две переменные и сравнивать их?

 

37, 38 тоже не корректно производится обнуление. 

Про volatile не забыл.

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Спасибо за ваше участи в моей проблеме.

Отвечаю по порядку.

Есть несколько ардуин.

Ну тогда берете вторую ардуину и делаете из нее эмулятор. 

for(int i=0;i<1000;i++){
   digitalWrite(pin,HIGH);
   delayMicroseconds(100);
   digitalWrite(pin,LOW);
   delayMicroseconds(100);
}

И ловите это основной ардуиной. Ровно 1000 тиков, с фронтами ~200 мкс. Для повышения точности можно вместо digitalWrite использовать Прямое управления выходами через регистры микроконтроллера Atmega
Аналогично можно и сработку концевика воспроизвести. 

Вообщем двумя ардуинами на столе вы получаете 100% воспроизводимую "тестовую ситуацию". Без необходимости крутить реальные движки и энкодеры. Отлаживаете код, потом уже к реальному железу.... если не заработало, то уже ищите осцилом и лог.анализатором (им может выступить 3-тья ардуина) в чем различие в сигналах между реальным железом и "эмулятором".

Опять-таки вначале убедитесь что "четко ловите" (отдельным скетчем). В котором не будет шаговиков и проч.
Просто подсчет пойманых тиков и вывод в Serial количества..

cactous пишет:

По поводу строк 27-31, что в них опасного?

Ну вот представте, что у вас строка 31 иногда выполняется, а иногда нет. По генератору случайных чисел. Можно сказать что такой код будет иметь предсказуемое поведение?

cactous пишет:

Проверяем если moved больше шага шаговика то шагаем, это необходимо чтобы шаговик не убежал быстрее вала и moved не стало меньше нуля.

Ну и что произойдет если шаговик шагнул, а moved при этом не уменьшился?

 

cactous пишет:

По 31 строке полностью согласен. Подумал и правда, а чтоже делать? Использовать две переменные и сравнивать их?

ну во первых, хоть это и дело вкуса, я бы отказался от while. Стремает он меня в loop() - блокировку получить можно случайно. Зачем он если loop() у нас уже "цикл"?  И всегда можно обойтись в нем if-вами. IMHO if(digitalRead(pinend)==0){все остальное сюда) - будет ничуть не хуже. Зато четко видно, "набор проверк и действий" который мы делаем при одном проходе loop().

Во вторых я полюбляю, если у меня переменная меняется прерыванием, сделать в начале loop() ее копию в какую-нибудь tmpMoved. И дальше в loop() анализировать только tmpMoved. Я как-бы сделал "моментальный снимок состояния" и знаю что до конца loop() она у меня не изменится. Я могу спокойно Serial.prnitln делать, смотреть что там происходит, как она обсчитывается и т.д.

В третьих,  я бы стараюсь, что-бы переменная действительно менялась только из одного места. Если она апдейтиться в прерывании, в loop - ее лучше не менять. Невозможно получить однозначное поведения. Всегда есть риск "одновременно пытаются менять". Можно конечно запретить, на момент апдейта  прерыния через Arduino - NoInterrupts  (или cli()/sei() - что вообщем-то одно и тоже если DUE не планируете использовать). Но.. там тоже бока могут вылезти.

Поэтому я сделал бы такие переменные:

encPosition - позиция энкодера. Меняется только в прерывании (и только она в прерывании меняется, все остальное в loop() вычисляется)
encPrevPosition - позиция энкодера при прошлом проходе loop()
encDiff - ну собственно разница между двумя предыдущими. узнаем на сколько энкодре успел повернутся за это время
stepDiff - на сколько нужно степер повернуть, высчитываем его из encDiff через ваше "передаточное число".
stepCurrent - текущая позиция шаговика. Обновляем ее после каждого шага (за один проход loop() шагаем только на один шаг).
stepTarget- а эта поция шаговика к которой он "стремится". Вот ее мы и увеличиваем на stepDiff

Сама логика шаговика получается такой:
если stepCurrent==stepTarget - ничего не делаем
если stepCurrent<stepTarget - делаем шаг по часовой стрелки (и увеличиваем stepCurrent).
если stepCurrent>stepTarget - делаем шаг против часовой (и уменьшаем stepCurrent)

Ну и от delayMicroseconds желательно отказаваться. Интервал между шагами лучше обеспечивать по принципу Мигаем светодиодом без delay()

 

 

 

cactous
Offline
Зарегистрирован: 18.11.2013

Протестировал скорость второй ардуиной, скорости хватает. Считает ровно 1000импульсов. Это на специально написаном скетче в котором есть прерывание инкрементирующее переменную. И вывод через компорт в loop. Успевает считать даже если delay 10мкс и пины дергаются управление портом.

А вот в рабочем скетче с множеством циклов  подобное не сработало.  Выдает ахинею разную. 

cactous
Offline
Зарегистрирован: 18.11.2013

Наверное я что-то не понимаю, обьясните пожалуйста по прерываниям.  Во время исполнения прерывания, основная программа не выполняется, правильно? А когда прерывание выполнено, то основная программа выполняется ровно с того места где была прервана?  Просто какие то чудеса происходят. Не могу уже понять куда копать.

 

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Наверное я что-то не понимаю, обьясните пожалуйста по прерываниям.  Во время исполнения прерывания, основная программа не выполняется, правильно? А когда прерывание выполнено, то основная программа выполняется ровно с того места где была прервана?  

Все верно. Причем основная может быть "остановлена/продолжена" не обязательно "между строчками" которые вы видите. Но и в любом месте, любой строки. В любом выражении. И если в этом выражении использовалась переменная, которую поменяло прервыание - результат предсказать невозможно.

cactous пишет:

Просто какие то чудеса происходят. Не могу уже понять куда копать.

Ну я вам выше расписал "общую идею" ("я сделал бы такие переменные..."), как избавиться от необходимости менять переменную из двух конкурирующих мест и привнести однозначность в основной loop()

cactous
Offline
Зарегистрирован: 18.11.2013

Я уже изменил алгоритм, и теперь у меня одна переменная меняется в прерывании, вторая motPos меняется в loop. 

int pinend=13; // концевик конца стола.
int pinstart=14;// концевик начала.
int ledblue=A4;
int ledred=A5;
int PaperSensor=15;
int button=A7;
int stp=12;// step
int dir=11;// dir
int sleep=4;
int reset=5;
int enable=9; //если единица то все работает, если 0 то все сигалы игнор.
int ms1=8;//-------------------
int ms2=7;//  пины размер шага
int ms3=6;//-------------------
int encoder2=10;
long c=0;
float stpEnc= 0.01791;
float stpMot= 0.01250;
volatile float encPos =0.0;
float motPos=0.0;
int b=0;// добавлена временно для проверки


long lastStep=0;

int flagPrint=0; // состояние принтера "0" сервис,
                 //"1" готов к печати, "2" идет печать.
int Speed=50;    // скорость вращения шд, чем больше число, тем медленнее.

void setup()
{
  pinMode (pinstart, INPUT);
  pinMode (pinend, INPUT);
  pinMode (ledblue, OUTPUT);
  pinMode (ledred, OUTPUT);
  pinMode (button, INPUT_PULLUP);
  digitalWrite(14, 1);
  pinMode (enable,OUTPUT);
  pinMode (sleep,OUTPUT);
  pinMode (reset,OUTPUT);
  digitalWrite(enable, 0);
  digitalWrite(reset, 1);
  digitalWrite(sleep,1);
  pinMode (ms1, OUTPUT);
  pinMode (ms2, OUTPUT);
  pinMode (ms3, OUTPUT);
  pinMode (stp, OUTPUT);
  pinMode (dir, OUTPUT);
  pinMode (PaperSensor, OUTPUT);
  pinMode (encoder2, INPUT);
  digitalWrite (PaperSensor, 1);
  digitalWrite (ms1, 1);//--------------
  digitalWrite (ms2, 1);//  1/16 шага
  digitalWrite (ms3, 1);//--------------
  attachInterrupt(1, schet, RISING);
  Serial.begin(9600);
}
 
  
  void schet() // функция обработки сигнала с энкодера
{
     encPos = encPos + stpEnc;
     b++;
}
   


void loop()
{
  
  if(flagPrint!=0)
    {
    digitalWrite(ledblue,1);
    digitalWrite(ledred,0);
    }
  else
    {
    digitalWrite(ledblue,0);
    digitalWrite(ledred,1);
    }
  
  
  if(flagPrint!=0)
  { b=0;
    encPos=0;
    motPos=0;
    digitalWrite (dir,0); //крутим мотор вперед

    while(digitalRead(pinend)==0)// пока не перекроется датчик конца
  { 
  if((encPos+stpMot)>motPos)
  { motPos = motPos+stpMot;
    if (encPos > 75)
      {
        digitalWrite(PaperSensor, 0);
      }
    if (encPos >171)
      { 
        digitalWrite (stp,1);//делаем шаг
        digitalWrite (stp,0);// мотором
        flagPrint=2;//флаг режимов установлен в положение идет печать.
      
     }
   }
  }Serial.println(b);
   b=0;
   encPos=0;
   flagPrint=0;
   digitalWrite(PaperSensor,1);
  
  }
  
  int c=analogRead(button);

  
  if (c<30)                //--------------------------       
  {                                  //
    digitalWrite(dir,1);             //
    while(c<30)           //     Обработка нажатия 
    {    c=analogRead(button);
        if(digitalRead(pinstart)==0)
          {                           //     кнопки  "Назад"
            digitalWrite(stp,1);           //     Стол едет в сторону 
            digitalWrite(stp,0);           //     начала печати.
            delayMicroseconds(50);        //
            c=analogRead(button);
          }                                 //                 
    } 
  }                                   //--------------------------
  
   if (470<c && c<510)                 //--------------------------
  {                                  //
    digitalWrite(dir,0);             // 
    while(470<c && c<510)              //     Обработка нажатия 
    {     c=analogRead(button);         
        if(digitalRead(pinend)==0)
          {                          //     кнопки "Вперед"
             digitalWrite(stp,1);    //     Стол едет в направлении
             digitalWrite(stp,0);           //     печати.
             delayMicroseconds(200);        //
             
          }
    }                                //
  }                                  //--------------------------
  
   if (310<c && c<340)               //--------------------------
  {                                  //  Нажата кнопка "Готовность"
    if(digitalRead(pinstart)==0)     //  Проверяем концевик, если перекрыт,
    {                                //  то двигаем стол в сторону
     digitalWrite(dir,1);            //  начала печати
     while (digitalRead(pinstart)==0)//---------------------------
      {                              //  пока не будет перекрыт датчик
        digitalWrite(stp,1);         //  начала.
        digitalWrite(stp,0);         //
        delayMicroseconds(200);      //
      }                              //----------------------------
    }   
       digitalWrite(dir,0);
       delay(100);
    for(int i=0; i<=1000; i++)
       {
        digitalWrite(stp,1); 
        delayMicroseconds(350);        
        digitalWrite(stp,0);         
        delayMicroseconds(350);
       }    
       delay(100);
       digitalWrite(dir,1);            
     while (digitalRead(pinstart)==0)
      {                              
        digitalWrite(stp,1);
        delayMicroseconds(350);
        digitalWrite(stp,0);
        delayMicroseconds(350);
      }                       
     
     flagPrint=1;
     encPos=0;
     motPos=0;
     digitalWrite(PaperSensor,1);
  }
  
  //if (580<c && c<610)
  //{ 
      
  //}
  }

Для проверки один пин второй ардуины подключаю к прерыванию вместо энкодера.  Второй имитирует концевик. Посылаю 1000 импульсов, но подопытный иногда насчитывает 1000 иногда 2000, 4000, 5000, 3000. Не понятно как и почему пропускается срабатывание концевика.

 

 

скетч на втром контроллере следующий

int pin=7;
int konch=5;

void setup()
{
  pinMode (pin, OUTPUT);
  pinMode (konch, OUTPUT);
  digitalWrite(5,0);
  
}

void loop()
{ 
  digitalWrite(5,0);
  delay(10000); // ;ждем так долго чтобы наверняка начать подавать импульсы когда первая ардуина готова их считать.
  for(int b=0; b<20; b++)
  { 
  for(int i=0; i<50; i++)
 {
   PORTD = B10000000;
   delayMicroseconds(10);
   PORTD = B00000000;
   delayMicroseconds(10);   
 } delay(200);
  }
 
 
 digitalWrite(5,1);

}

 

leshak
Offline
Зарегистрирован: 29.09.2011

Простите, но в этой переделке я не вижу, ни "целевой позиции мотора", ни "на сколько повернулся энкодер с прошлого прохода loop", ни сколько нужно повернурнуть мотор и т.д. и т.п. Вообщем лично мне не видно что-бы ве переделали "как я советовал".
Зато вижу кучу while блокирующих (кстати тоже говорил что лучше отказаться от подобных конструкций), да еще внутри которых delay() и висят. Соотвественно куча шансов/способов застрять где-нибудь еще... и выяснить где именно "оно застряло" - можно до морковкиного заговения.
Да и вообще - куча логики которая к текущей проблеме не имеет отношения. Ну зачем вы пытаетесь разобраться сразу "со всем винигретом"?   Добейтесь вначале работы на простейшем. Просто "передаточное число". Потом добавитье "Обработку концевика", потом еще что-то.... по одной фишке за раз. Всегда отталкиваясь от "работающего варианта" (пусть и не полно фунционального).

Кстати вместо

if(flagPrint!=0)

вполне можно писать 

if(flagPrint)

Или вообще выкнитуть эти if-фы и показывать текущие состояние светиками так:

digitalWrite(ledblue,flagPrint);
digitalWrite(ledred,!flagPrint);

true/false, high/low, 1/0 - это все синонимы.

cactous
Offline
Зарегистрирован: 18.11.2013

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

 

К сожалению проверить наличие поммех нечем, осцилографа нет.   

leshak
Offline
Зарегистрирован: 29.09.2011

Погодите, то есть на "эмуляторе" у вас все работает корректо, а на реально железе нет?

Значит либо на эмуляторе вы все-таки, что-то упростили, либо ... действительно помехи.
Но мне кажется, все-таки, что "работают как надо.." - иллюзия. И ошибка именно где-то в алгоритме. Где-то происходит задержка, попадаете в какой-то из своих while... и пропускаете где-то импульсы.
Ну не верю я что алгоритм с явными блокировками может нормально следить за энкодеорм, кнопками, концевиком и шагать мотором :)

Да и сама вся "портянка loop" - явно говорит о том что ее нужно переписывать. Какую-то простейшую машину состояний делать. Тогда и разные части независимо гораздо проще писать, отлаживать.

Если хотите... можем попрбовать с нуля, весь ваш loop(), по маленьким частям, вашими руками :), переписать.... отложить текущий скетч куда-то в сторону и начать с

encPosition - позиция энкодера. Меняется только в прерывании (и только она в прерывании меняется, все остальное в loop() вычисляется)
encPrevPosition - позиция энкодера при прошлом проходе loop()
encDiff - ну собственно разница между двумя предыдущими. узнаем на сколько энкодре успел повернутся за это время

 

cactous
Offline
Зарегистрирован: 18.11.2013

Завтра займусь этим. 

Опять проверял энкодер. Показывает погоду на марсе.:)

Так как разрешение у него очень высокое 1440 на оборот, то малейшее дрожжание вызывает прерывание. Не понял механизм, но результаты тестирования печальны,  погрешность около 10%. Буду искать другой, проверять. Но скетч перепишу по новой, с вашей помощью:)

 

cactous
Offline
Зарегистрирован: 18.11.2013
void schet()
{
 long moment=micros();
  if((moment-prevmicros)>20)
  {
    encPos = encPos + stpEnc;
     b++;
    prevmicros=moment;
  }
}

У меня небольшая победа.  Теперь прерывание выглядит так и количество тико считается +-1. Что и требовалось.

 Может быть это особенности шагового двигателя.

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

теперь буду отлаживать всю простыню.  

leshak
Offline
Зарегистрирован: 29.09.2011

Ну примерно аналогично я боролся с шумом механического (была тут ветка - описывал).
Но, вы уверен что это именно шум? Вы же сами писали что "разрешение высокое". Возможно это как раз и есть фиксация "что в реальности происходит". И... если ловить, все-таки направление, то "дрожание туда/сюда" в принципе должно компенсироваться само по себе.

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

cactous
Offline
Зарегистрирован: 18.11.2013

Не хоечтся сильно усложнять программу.  Но если будет необходимо буду делать.

Помехи по питанию? Проводил такой эксперимент.  Откручивал двигатель, который вращает энкодер. При этом он крутился, подносил его к оптопаре энкодера, ниодного импульса контроллер не зафиксировал. Природа этих посторонних импульсов механическая. Никаких помех, наводок,  нет.  Нужно все же подумать  о направлении. Скорости однозначно хватит.  На счет прямого обращения к портам, я всеже не понял как считать определенных бит с порта. Состояние всего порта вроде не сложно. Если ли такой способ, не прибегая if и тд?

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Не хоечтся сильно усложнять программу.  Но если будет необходимо буду делать.

Как на меня, то это будет не усложнение, а упрощение... (я имею ввиду архитектуру которую я вам описывал в виде "я бы вот такие переменные" объявлял).

Один бит считать... конечно можно... читаем & и Arduino Playground - BitMath
 

cactous
Offline
Зарегистрирован: 18.11.2013
float encPosition;
float encPrevPosition;
float encDiff;
float stepDiff;
float stepCurrent;
float stepTarget;
float encTick=0.0213;
float stepMot=0.0125;
float u =enc


void encoder()
{
  if(digitalRead(enc2)==0)
  {

  }
  else 
  {
    encPosition-encTick;
  }
}  
  void loop()
  {
    encDiff=encPosition-encPrevPosition;
    stepDiff=encDiff*u;  // пока не понятно что это за передаточное число
    stepTarget=stepCurrent+stepDiff;
    float a=stepCurrent-stepTarget;
    if((a!=0)
    {
     if(a<0)
     {
       //шагаем -->>     
     }
     else
     {
       // шагаем <<--
     }
     encPrevPosition=encPosition;
    }
  }

Все попытки добиться синхронности вращения энкодера и шаговика пока ни  к чему не привели.  Причину понять не могу. Есть подозрения что шаговик просто пропускает шаги из-за того что импульсы степ подаются с хаотическими интервалами. 

Решил писать по Вашему алгоритму уже набросал кое-что, остановился на том, что не понимаю что значит позиция энкодера в вашем понимании и в каких единицах мы измеряем encPosition , в мм в градусах, в тиках?

leshak
Offline
Зарегистрирован: 29.09.2011

Хм... не вижу setup(), обработчика прервания..... вы явно перестарались с "убрать за кадр лишние".

Загадочная строка:

  encPosition-encTick;

Она же ничего не делает...
В другой ветке - тоже if-а ничего не делается...

void encoder() - это что, обработчик прервыния?

encPosition - это что "текущие положение энкодера"? Тогда почему он "float"? Разве возможно получить "дробное количество щелчков"?
При этом вы на какое-то дробное число еще и уведичивать его пытались (похоже). encPosition - это текущая позиция энкодера. В его тиках. Каждый импульс по часовой стрелке - увеличивает его на единицу, каждый тик против - уменьшает.
И все... не нужно пытаться это делать "в градусах" (вала, шаговика и т.д. и т.п.). Вначале просто "читаем состояние энкодера". В самых простых и "родных для него" единицах. "Щелчках". Которые всегда целые. И которые за раз всегда могут поменяться только либо на +1, либо -1. В зависимости от направления вращения.

И в loop(), пока, раз запутались, значит еще больше упрощайте. Оствте, пока в Loop() вообще что-то типа

void loop(){
  Serial.println(encPosition);
  delay(500);
}

И все. Убедитесь для начала что вы четко ловите вращение энкодера в оба направления. Дали десять импульсов АBABABAB...., в сериале цифра увеличилась на 10-ть...., дали BABABABA... - уменьшилась.

Вот тут есть объяснения как идут импульсы с энкодера:

AVR. Учебный Курс. Инкрементальный энкодер. | Электроника для всех

Если "на пальцах", то получается что-то такое:
Вешаем обработчик прерывания не один его выход. скажем A. attachInterrupt. (вешаемся или на RISING, или на FALLING, но не на CHANGE).
Когда обработчик "сработал", значит энкодер повернулся на одно деление. Теперь осталось выяснить "в какую сторону".
В обработчике делаем чтение выхода B  (через digitalRead() или напрямую из порта, для быстроты). Ну и в зависимосте от того HIGH там или LOW, добавляем или отнимаем единицу от encPosition.

Если "шума нет", энкодер все выдает "как по учебнику", то вот получается такая примитивная логика... ловим тики по одному выходу энкодера, вторых выход в этот момент говорит "направление".

 

cactous
Offline
Зарегистрирован: 18.11.2013

  Да я мало здесь еще написал. 

Но логика такова, Если прерывание вызывется по фронту, то логично что enc1 сейчас единица. 

Значит зачем считывать еще и в прерывании  состояние пина? Считываем только второй пин и сравниваем его либо с нулем, либо с единицей.  Это вообще не важно.  И делаем выводы о направлении. Как понять есть шумы или нет? У энкодера 1150 линий на оборот.

 

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

  Да я мало здесь еще написал. 

Но логика такова, Если прерывание вызывется по фронту, то логично что enc1 сейчас единица. 

Значит зачем считывать еще и в прерывании  состояние пина? Считываем только второй пин и сравниваем его либо с нулем, либо с единицей.

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

cactous пишет:

Как понять есть шумы или нет? У энкодера 1150 линий на оборот.

ну вот если оборот дал вам в итоге изменение encPosition с нуля до  1150 - значит шумов нет. И в обратную сторону с 1150 до нуля спустились. И если никаких движений нет, то и encPosition не меняется.
Или взяли и подергали энкодер. Шаговиком. Туда 5 шагов, обратно 5-ть шагов. И так "тысяча раз". Если в итоге мы не получили постоянного "наростания" encPostion (или постоянного убывания). Значит у нас все ловиться нормально. И "туда" и "сюда" ловим от энкодера одинаковое количество тиков.
Если у энкодера рукой чувствуются "щелчки" (хотя вряд ли, конечно 1150 почувствовать можно), то смотрим сходится ли то что "мы нащелкали", с тем что насчиталось в encPosition.

cactous
Offline
Зарегистрирован: 18.11.2013

Написал вот такой скетч

//**********пины**********//
int pinend=13; // концевик конца стола.
int pinstart=14;// концевик начала.
int ledblue=A4;
int ledred=A5;
int PaperSensor=15;
int button=A7;
int button_reset=2;
int stp=12;// step
int dir=11;// dir
int sleep=4;
int reset=5;
int enable=9; //если единица то все работает, если 0 то все сигалы игнор.
int ms1=8;//-------------------
int ms2=7;//  пины размер шага
int ms3=6;//-------------------
int enc2=10; // второй сигнал энкодера

//**********переменные*********//
float stpEnc= 0.0202; //сколько мм за тик энкодере
float stpMot= 0.0125; //сколько мм за шаг мотора
volatile long encPos =0; //  счетчик энкодера
float motPos=0.0000; // реальная позиция стола с учетом пройденого пути
int b=0;// добавлена временно для проверки
int c=0; // переменная опроса кнопки
long prevmoment=0;

boolean flagPrint=0;// состояние принтера "0" сервис,
                    //"1" готов к печати, "2" идет печать.
long currentMoment=0; //будет использоваться для перевода в sleep                
long lastAction=0;    //время последней активности(вращение ШД, нажатие кнопок и тд.)
void setup()
{
  pinMode (pinstart, INPUT);
  pinMode (pinend, INPUT);
  pinMode (ledblue, OUTPUT);
  pinMode (ledred, OUTPUT);
  pinMode (button, INPUT_PULLUP);
  digitalWrite(14, 1);
  pinMode (enable,OUTPUT);
  pinMode (sleep,OUTPUT);
  pinMode (reset,OUTPUT);
  digitalWrite(enable, 0);
  digitalWrite(reset, 1);
  digitalWrite(sleep,1);
  pinMode (ms1, OUTPUT);
  pinMode (ms2, OUTPUT);
  pinMode (ms3, OUTPUT);
  pinMode (stp, OUTPUT);
  pinMode (dir, OUTPUT);
  pinMode (PaperSensor, OUTPUT);
  pinMode (enc2, INPUT);
  digitalWrite (PaperSensor, 1);
  digitalWrite (ms1, 1);//--------------
  digitalWrite (ms2, 1);//  1/16 шага
  digitalWrite (ms3, 1);//--------------
  Serial.begin(9600);
  attachInterrupt(1, counter, RISING);
  pinMode(3,INPUT);
  pinMode(button_reset,INPUT);
}


void counter()
{
 if((PINB & B00000100)==0)
 {
   encPos++;
 }
 else
 {
   encPos--;
 }
}

void loop()
{
  for(int i=0; i<50; i++)
  {
    for(int n=0; n<1000; n++)
    { 
      digitalWrite (dir,0);
      digitalWrite(stp,1); 
      delayMicroseconds(50);     
      digitalWrite(stp,0);      
      delayMicroseconds(50);   
  }
  delay(200);
  for(int k=0; k<1000; k++)
    { 
      digitalWrite (dir,1);
      digitalWrite(stp,1); 
      delayMicroseconds(50);     
      digitalWrite(stp,0);    
      delayMicroseconds(50); 
  }
  Serial.println(encPos);
  delay(200);
  }
  encPos=0;
}

Погонял его,и выяснилось что на 2000шагов (1000 в одну, 1000 в другую ) набегает от 30 до 75 тиков лишних.  Откуда они берутся?

leshak
Offline
Зарегистрирован: 29.09.2011

Круть.И что?  Нужно радоваться или плакать?
Ну вы хотя-бы какой-то коментарий дали что в итоге выводится.... что куда подключили.

Кстати, после первого for я бы тоже Serial.println(encPos) воткнул... что-бы видеть как он "туда" насчитал. Что-бы различать ситуации "все правильно считается" и "вообще ничего не считает".

И это... 100-тая строка.... нафига?  Сколько раз говорили что "encPos меняем только в самом обработчике". 
Зачем вам вообще его обнулять? Что-бы опять вернутся к тем проблемам с которых начинали?
Мы же, потом, будем, из него, вычислять "на сколько он изменился". А поменялся он от 0 до 300, или от 300 до 600, или от -600 до -300 - разницы не нет. В любом случае encPos-prevEncPos дас там "300 по часовой".

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Погонял его,и выяснилось что на 2000шагов (1000 в одну, 1000 в другую ) набегает от 30 до 75 тиков лишних.  Откуда они берутся?

А если за раз крутить не на 1000, а на 10000?  Столько же "лишних" получается? Или от 300 до 750?
Поставте маркером какую-то засечку, физически шаговик действительно возвращается, в итоге в изначальную позицию?

leshak
Offline
Зарегистрирован: 29.09.2011

Следующие, что-бы я делал...

поробовал крутить толкьо в одну сторону. Скажем "в положительную".

и сделал какую-то перменную bool antiDetected;

В обработчик, там где encPos-- добавил-бы antiDetected=true  (там где encPos++ - ничего не добавлять).
В loop(), перед тем как крутить "по часовой", сделал бы antiDetected=false;
И после кручение, посмотрел что стало с этой переменной.
Наблюдалось ли, пока мы крутили по часовой импульсы "против" или нет.

А еще, опробуйте вот такое: отсоедините энкодер от шаговика..., но какую-то "нагрузку" на шаговик, все-таки дайте. Что-бы усилие от него требовалось. Энкодер можно вообще "физически зафиксировать". И постепать шаговиком. Теоретически мы не должны увидить ни одного импульса от энкодера... а вот если "таки что-то было", то значит шаговик, все-таки дает нам помехи.

cactous
Offline
Зарегистрирован: 18.11.2013

Не правильно я написал. 35-75 тиков набегает на за 2000, а за 100000шагов. 

Попробовал куртить сериями по 10000, аналогично набегает. Похоже что эти лишние  тики появляются при остановка и стартах. 

cactous
Offline
Зарегистрирован: 18.11.2013

Энкодер от шаговика отключал, ни чего не насчитывает.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

давно не читал.... перечитаю... первая мысль - это разбег в точности шаговика и точности энкодера... в этом случае будет постоянно набегать ошибка - при малых ( N тиков ) она примерно равна нулю, при гораздо больших N тиков - ошибка растёт пропорционально ( N тиков  ), надо подумать....

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ну, ввести коэффициент компенсации неточности сопряжения ШД и ЭК.... и учитывать показания ЭК с учётом этого Козфф.... должны взаимнокомпенсировацца ошибки... НЕТ ?

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

бла-бла-бла....

если измерять длину НОРМАЛЬНОЙ рулеткой  - то всё нормально....

если измерять НЕНОРМАЛЬНОЙ рулеткой с шагом ( не миллиметр ) , а 0,998, или 1,002 - то при измерении 1....5 метров на это можно закрыть глаза, а при замере 900.....5000 метров эта ошибка уже икнётся....

cactous
Offline
Зарегистрирован: 18.11.2013

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

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

Не правильно я написал. 35-75 тиков набегает на за 2000, а за 100000шагов. 

Попробовал куртить сериями по 10000, аналогично набегает. Похоже что эти лишние  тики появляются при остановка и стартах. 

Ну так проверте это... сделайте открутите 10000 в одноу сторону, с паузой через каждую тысячу. Посмотрите "увеличится ли ошибка".

Самое главное понять... с увеличением количества ошибка у нас увеличивается пропорционально или нет?
Если ошибка, в итоге, все время та же самая, то это уже скорее "погрешность механики". Люфты и проч.
35-75 тиков, это сколько в градусах?   Хм.... от 10,95 до 23.48... трудновато такое "списать" на люфты и неточность шаговика.

А если маркером поставить засечки?  После 10K "туда" и 10K "обратно", возвращаемся мы в исходное положение или нет? В ком именно у нас набегает ошибка. В шаговике-механике, или в энкодере/подсчете?

И... вот то "обнуление" ваше меня смущает.
Cдалайте в начале loop(), Serial.println("Start") и Serial.println("Finish"). И лог сюда. Что-бы было видно как же именно вы определили что "набежало лишние".

 

leshak
Offline
Зарегистрирован: 29.09.2011

cactous пишет:

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

Если он "колеблется", то при учете направления оно, по идее, должно "взаимокомпенсироваться".
Или вы имеете ввиду что колеблется в пределах "достаточно что-бы на энкодере поменялся канал A", но не достаточно что-бы поменялся канал B?
Хм.. это реально должны быть "очень малые колебания", прчием реально ну вот ровно на границе смены канала A.

IMHO более вероятно, что он на старте "проскальзывает" или на финише чуток прокручивается по иннерции.
Особенно если мы стартуем сразу "на максимальной скорости". Без плавного разгона-торможения.

Тогда, по идее, снижение скорости вращения должно убрать ошибку (по крайней мере что-бы "проверить это").

Или.. вот если открутить 10K в одну строну. с остановками через каждый 100. А в обратную сторону 10K без остановок. Тогда если "инерция" нам дает проблемы, мы должны увидеть увеличение ошибки.

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

cactous пишет:

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

 выловите систематическую ошибку и убейте её программно.... "настолько мала, что не позволяет детектировать напраление" - пока мала - и не позволит, при шагах более N=500 - позволит и заодно компенсирует

leshak
Offline
Зарегистрирован: 29.09.2011

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

cactous
Offline
Зарегистрирован: 18.11.2013

Вобщем так.  Открутил я шаговик. Стал вручную крутить энкодер от риски нарисаованой маркером. И у меня получилось вручную крутить его с точностью 1тик. Если на этом энкодере 1440 рисок то у меня всегда получалось 1442, 1441 не зависимо от скорости и пауз во вращении. Крутил его и без остановки, и рывками, правда всегда очень медленно подводил в конце к риске. Всегда один результат плюс минус.  И в одну и в другую сторону.  И если я кручу его периодически вперед назад. но останавливаю все равно на риске то сумма всегда 1440 +-1.

Подозреваю что все таки это виноват шаговик. Ну и ладно. Это ведь тестовая система. На принтере тоже стоит шаговик, он крутит вал с энкодером. Расхождения есть и там. 

Не понимаю. Если принтер печатает на листе который крутит  ШД принтера. Все норм. Все линии в тестовом файле совпадают. А когда я использую уже свой ШД то все гуляет. Причем не линейно. а хаотически. Отклонение на 300мм бывает до 2мм.  

 

leshak
Offline
Зарегистрирован: 29.09.2011

Ну, по описанному, значит "энкодеру можно верить" (по крайней мере временно).
Версию с 10000 с остановами после каждой сотни проверяли?  Действительно старты/стопы дают погрешность?  Лишние "стопы" натыкиваем только при кручении в одну сторону. Мы специально сейчас пытаемся "сделать хуже", что-бы причина поярче проявилась.

Снизить скорость шаговика пробовали? (увеличить задержки между степами, в разы. даже на порядок можно).

Если оба пункта дадут ответ "да" (остановки - увеличат погрешность, а снижение скорости - уберет), то.... еще не все потерянно.

Тогда бороться можно (возможно ваш принтер это и делает) путем плавного увеличения скорости на старте, и плавного снижения...
Либо "самому" эти заниматься, либо смотреть в сторону библиотеки AccelStepper. Ей можно задавать "ускорение/торможение" (правда память она жрет..). И еще нужно посмотреть получится ли ее заставить с вашим шилдом работать.... ну то таке. при желании "что угодно заставить можно". 
Вообщем с тем "как правильно крутить степпер" - потом можно будет разбиратся. Вначале убедится что проблема действительно именно в инерции шаговика.

 

SU-27-16
SU-27-16 аватар
Offline
Зарегистрирован: 13.08.2012

ещё раз про ошибку...

энКод за оборот даёт1440 тиков, ШД для одного оборота нужно 1420 тиков, НАПРИМЕР....

и как вы это учитываете в коде ? 

...нужна коррекция :)

leshak
Offline
Зарегистрирован: 29.09.2011

SU-27-16 пишет:

ещё раз про ошибку...

энКод за оборот даёт1440 тиков, ШД для одного оборота нужно 1420 тиков, НАПРИМЕР....

и как вы это учитываете в коде ? 

...нужна коррекция :)

Какая коррекция? О чем вы?
Сделали тысячу шагов шаговиком по часовой стрелке (фиг его знает сколько там оборотов он накрутил).
В процессе этого шагания от энкодера пришло NNN тиков.

Теперь сделали тысячу шаг шаговиком против часово. Вопрос: сколько должно прийти тиков от энкодера? И причем тут коррекция?