Оптические энкодеры

AlexTeos
AlexTeos аватар
Offline
Зарегистрирован: 09.05.2014

Приобрел вот такие оптические энкодеры, что бы контролировать передвижения робота

Подключил к 2 и 3 пину для работы с помощью прерываний (драйвер двигателя ни к чему не подключен)


volatile int enc_l_count,enc_r_count;
volatile boolean changed;

void l_inc(){
  enc_l_count++;
  changed = true;
}

void r_inc(){
  enc_r_count++;
  changed = true;
}

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

  enc_l_count = 0;
  enc_r_count = 0;
  //Encoders
  attachInterrupt(0, r_inc, RISING);
  attachInterrupt(1, l_inc, RISING);

  changed = false;
}

bool write(){
  Serial.print("Left: ");
  Serial.print(enc_l_count);
  Serial.print("  Right: ");
  Serial.println(enc_r_count);
}

void loop() {
  if (changed){
    write();
    changed = false;
  }
}

В итоге получаются такие результаты:

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

Kлапаyций 99.99
Offline
Зарегистрирован: 11.10.2014

http://www.pjrc.com/teensy/td_libs_Encoder.html

*с прерываниями по двум/одному пину, без прерываний - нормальная штука.

AlexTeos
AlexTeos аватар
Offline
Зарегистрирован: 09.05.2014

Но эта библиотека только для "двойных" энкодеров

trembo
trembo аватар
Offline
Зарегистрирован: 08.04.2011

Вообще-то это не энкодер, а счётчик импульсов. Поищите примеры со словом " тахометр"

Kлапаyций 99.99
Offline
Зарегистрирован: 11.10.2014

AlexTeos пишет:

Но эта библиотека только для "двойных" энкодеров

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

Doozeronir
Offline
Зарегистрирован: 22.10.2015

Удалось победить???

Столкнулся с такой-же проблемой, с таким же оборудованием.  

#define R_ENCODER          0      // прерывание int 0 на pin 2
#define L_ENCODER          1      // прерывание int 0 на pin 3

volatile int RTotalCount ;
volatile int LTotalCount;

void RTotalCountInc()
  {
    RTotalCount++;
    Serial.println(RTotalCount);
  }

void LTotalCountInc()
  {
    LTotalCount++;
    Serial.println(LTotalCount);
  }  

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

  pinMode(R_ENCODER, INPUT);
  pinMode(L_ENCODER, INPUT);

   attachInterrupt(R_ENCODER, RTotalCountInc, CHANGE);
  attachInterrupt(L_ENCODER, LTotalCountInc, CHANGE);
}
 

void loop()
{

}

Обработчик прерываний - инкрементный счетчик, настроен на изменение (CHANGE) состояния пина. И тут - мистика... Глухо прикрываешь оптопару - инкремент изменяется дважды на единицу, причем состояние пина показывает, как будто не изменилось. Открываю оптопару - инкремент снова изменяется дважды на единицу, состояние пина опять не изменилось. Причем, состояние LED на плате с оптопарой однозначно сигнализирует о состоянии т.е. открыто - LED светится, закрыто - LED тухнет. Если используем мотор и колесико с прорезями - то тут вообще....

Если подход основываем не на прерываниях, а на периодическом (раз в 10 мс) сканировании состояния пинов и инкременте, если состояние изменилось на противоположное - то все работает как надо, кашерно и по феншую!!!

#define ENCODER    18

  byte EncoderLastState;
  byte EncoderState;
  long currentTime;
  int n;

void setup() {
    pinMode(ENCODER, INPUT);
    Serial.begin(9600);

}

void loop() {
  currentTime = millis();
  if(currentTime % 5 ==0){
    EncoderState = digitalRead(ENCODER);
    if (EncoderState != EncoderLastState) {
      n++;
      EncoderLastState = EncoderState; 
      Serial.print(n);
     }
   }   

Если есть решения, то прошу помощи!

AlexTeos
AlexTeos аватар
Offline
Зарегистрирован: 09.05.2014

К сожалению ничего не вышло, я даже попробовал другие энкодеры:

Результат остался тем же, что поставило крест на моем проекте автономной машинки

Doozeronir
Offline
Зарегистрирован: 22.10.2015

To AlexTeos жаль конечно!

Интересно получилось - заказывал комплектуху не сильно заморачиваясь, не изучая, что народ устанавливает. Когда столкнулся с проблемами программной реализации начал брожение по форумам, наехал на Ваше решение и удивился - все тоже самое))) И моторредукторы и колеса и драйвер и датчики и сама реализация платформы и программная идея - совпали 100%))) только у меня МЕГА. В общем я пока не здаюсь, попробую на прерывании по таймеру. Об итогах отпишусь. Кстати, есть еще комплексное решение

http://robocraft.ru/shop/index.php?route=product/product&path=18_56&prod...

Doozeronir
Offline
Зарегистрирован: 22.10.2015

To AlexTeos

Если инт

#include <TimerOne.h>


#define R_ENCODER          2          
#define L_ENCODER          3          

#define WHEEL_DIAMETER     66
#define BASE_SIZE          297
#define ENCODER_COUNT      40

volatile int REncoderState;
volatile int REncoderLastState;

volatile int LEncoderState;
volatile int LEncoderLastState;

volatile int RTotalCount = 0;
volatile int LTotalCount = 0;


void TotalCountInc()
  {
    REncoderState = digitalRead(R_ENCODER);
    if (REncoderState != REncoderLastState)
      {
        REncoderLastState = REncoderState; 
        RTotalCount++;
        Serial.println(RTotalCount);
      }
      
    LEncoderState = digitalRead(L_ENCODER);
    if (LEncoderState != LEncoderLastState)
      {
        LEncoderLastState = LEncoderState; 
        LTotalCount++;
        Serial.println(LTotalCount);
      }      
  }

void setup() {
  Serial.begin(9600);
  Timer1.initialize(10000);
  Timer1.attachInterrupt(TotalCountInc);
  
  pinMode(R_ENCODER, INPUT);
  pinMode(L_ENCODER, INPUT);
}
  

void loop()
{

}

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

AlexTeos пишет:

К сожалению ничего не вышло, я даже попробовал другие энкодеры:

Результат остался тем же, что поставило крест на моем проекте автономной машинки

Я вот тоже купил пару очень похожих внешне датчиков, думая, что это энкодеры (валкодеры).

Оказалось - обычные однофазные датчики скорости, только зачем-то (подозреваю, именно, чтобы обмануть покупателя) на них выведен сигнал с одного датчика в цифровой и аналоговой форме. Т.е. направление вращаения по нему определить нельзя - только скорость.

Doozeronir
Offline
Зарегистрирован: 22.10.2015

Именно так!

Тот, что я использую, вобще назвал бы оптопарой с логическим выходом, пинов всего-то - VCC, GND, OUT, умеет только читать факт вращения (change логических состояний), а определять напрвление и частоту вращения нужно программно + реализовывать стабилизацию частоты вращения электромоторов, т.к. планирую ставить на унифицированную двухколесную платформу, изначально для пылесоса, а там уж видно будет. Механика не самая большая трудность, хай-тек))) весь в программной реализации, в простом лаконичном коде, в идеале, исключительно  в процедурных инструкциях - типа едь вперед 5 метров или до препятствия, развернись направо на 40 радусов, едь по спирали, едь на базу заряжать батарею и т.д. Тут два дня бился как адекватно читать состояния выхода датчика, пока получилось только на прерывании по таймеру, но этого я думаю достаточно. Сейчас едут ко мне УЗ датчики расстояния, думаю как дальше программить, ардуиной занялся всего как неделю назад, незнаю ЧЕ дальше будет)))))) Думаю как платформу назад на базу возвращять, если есть что по делу буду рад. Всем мира, всем добра!

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Doozeronir пишет:

Именно так!

Тот, что я использую, вобще назвал бы оптопарой с логическим выходом, пинов всего-то - VCC, GND, OUT,

У моих 4 контакта, подписаны VCC, GND, DO и AO, подразумевается, что DO - это цифровой выход, а АO - анеалоговый.

Цитата:

умеет только читать факт вращения (change логических состояний), а определять напрвление и частоту вращения нужно программно

Программно определять частоту и направление, думаю, принципиально невозможно. Частота, наверное, все-таки определяется по датчику, а направление считается известным.

Цитата:

планирую ставить на унифицированную двухколесную платформу ... пылесоса

Это интересно. Что за платформа? Попытался набрать в гугле строку "унифицированная двухколесная платформа для пылесоса", ничего вразумительного не находит.

Цитата:

Сейчас едут ко мне УЗ датчики расстояния

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

Doozeronir
Offline
Зарегистрирован: 22.10.2015

Конечно парвильнее было сказать - не определять частоту и направление, а назначать и контролировать программно. Унифицированная, в смысле, для моих нужд унифицированная, т.е. платформа с подобранными размерами, контроллер с набором библиотек - останется только задать тип (алгоритм) поведения. Заказал еще и IR датчики, эмпирически определю какой для чего оптимален. Ну в общем, прокачиваю свой программистский скилл))) Спс, всем мира, всем добра!

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

trembo пишет:

Вообще-то это не энкодер, а счётчик импульсов. Поищите примеры со словом " тахометр"


http://www.chipdip.ru/product/ktir0521ds/
только считает перепады ( или импульсы )
как энкодер - если помнить куда крутим и считать импульсы - то как энкодер программный подойдёт

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

я себе на автобота поставил такие таходатчики,  все работает отлично, но я не использовал attachinterrupt , и если еще актуально могу выложить код

Doozeronir
Offline
Зарегистрирован: 22.10.2015

Конечно актуально! Будем благодарны

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

Doozeronir пишет:

Конечно актуально! Будем благодарны

вот код, если хотите определять большие скорости , не используйте delay(); нигде в скетче

#define tlsens 6
#define trsens 7


long previousMillis_tx = 0;
long interval_tx = 1000; //за какое время нужен результат

int tl = 0; //левый датчик
int tr = 0;  //правый датчик
int tll = 0; // временные переменые
int tlll = 0; // кол-во импульсов левого датчика
int trr = 0; // временные переменые
int trrr = 0; // кол-во импульсов правого датчика
int txd = 0; // разница в скорости


void setup() {
  pinMode( tlsens, INPUT );
  pinMode( trsens, INPUT );
}

void loop() {
  unsigned long currentMillis = millis();
  tl = digitalRead(tlsens);
  tr = digitalRead(trsens);
  if (tl == 1 && tll == tlll) {
    tlll = tll + 1;
  }
  else if (tl == 0) {
    tll = tlll;
  }
  if (tr == 1 && trr == trrr) {
    trrr = trr + 1;
  }
  else if (tr == 0) {
    trr = trrr;
  }
  if (currentMillis - previousMillis_tx > interval_tx) {
    previousMillis_tx = currentMillis;
    if (tlll > trrr) {
      txd = 1;
    }
    else if (tlll < trrr) {
      txd = -1;
    }
    else {
      txd = 0;
    }
    tlll = 0;
    trrr = 0;
  }
}

 

Doozeronir
Offline
Зарегистрирован: 22.10.2015

Valera Alf!!! Благодарим. Идея кода понятна. Первая реализация была аналогичная, с определенной периодичностью сканировать пины и копить количество срабатываний оптрона, а там уже управлять электромоторами для движения вперед или назад или поворот. Но мне хотелось в основном цикле оперировать только понятными процедурами, точнее одной - движение с заданием типа (прямо, разворот, назад и т.п.), скорости, прерывания (срабатывание датчика расстояния или удара). Например так, если правильно объявим функцию move, тот код такого вида:

void loop{
   move(forvard, 100, 3);
   move(turn, 45,0);
   move(back, 100, 0);
}

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

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

 

bonny
Offline
Зарегистрирован: 20.02.2019

Valera19701, Привет, это вы код для какого датчика сделали? У меня датчик что у автора...

vvadim
Offline
Зарегистрирован: 23.05.2012

bonny пишет:

Valera19701, Привет, это вы код для какого датчика сделали? У меня датчик что у автора...

я вы не обратили внимания, что последнее сообщение в теме было  4 года назад.

bonny
Offline
Зарегистрирован: 20.02.2019

vvadim пишет:

bonny пишет:

Valera19701, Привет, это вы код для какого датчика сделали? У меня датчик что у автора...

я вы не обратили внимания, что последнее сообщение в теме было  4 года назад.

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