Установка энкодера и счетчик количества оборотов

Тема в разделе "Моторы, сервоприводы, робототехника", создана пользователем Aleksey702, 14 май 2015.

  1. Aleksey702

    Aleksey702 Нуб

    Добрый вечер, форумчане!
    Спрашиваю у вас по поводу данного энкодера
    http://amperka.ru/product/miniq-wheel-encoder
    С его помощью хочу считать количество оборотов и смотреть на "это дело" во временной шкале.
    Это модель 1.2. Как я понял, провода в комплекте заменяют припой, без которого нельзя было обойтись в модели 1.1?
    Сам с ардуино знаком всего лишь 3-й день, поэтому обращаюсь за помощью к вам.
    1. Каким образом подключить энкодер к ардуино (у меня версия UNO)? Сам понял, что из комплектующих проводов через "папа-папа" подключить соответственно на землю и на 5 вольт по 2 раза, а вот выходы А и B не понимаю куда.
    2. Имеется ли примерный код для подсчета количества сигналов?
    3. В описании сказано, что сигнал поступает через каждые 7.5 градусов, но прорезей на том колесе всего 12. За счет чего получается такая точность? Или в описании ошибка.

    Заранее благодарю всех, кто откликнется и поможет дельным советом.
     
  2. ANV

    ANV Гуру

    Я энкодер вешаю на прерывания, но только через триггер Шмидта.
    Завтра могу код показать, но тим ничего сверхъестественного нету - по таблице сравнивается текущее и предыдущее состояние
     
  3. Aleksey702

    Aleksey702 Нуб

    Было бы замечательно, спасибо.
     
  4. ANV

    ANV Гуру

    Код (Text):

    #define ENCODER_A 21 // пин А энкодера
    #define ENCODER_B 20 // пин В энкодера
    #define ENCODER_A_int 2 // номер прерывания пина А
    #define ENCODER_B_int 3 // номер прерывания пина В

    volatile unsigned char EncoderPrev = 0;
    volatile int          Encoder    = 0;
    volatile int          EncoderTemp = 0;

    int decode_direction[16] =
                                    {  0,  1, -1,  0,  // 0  1  2  3
                                      -1,  0,  0,  1,  // 4  5  6  7
                                      1,  0,  0, -1,  // 8  9 10 11
                                      0, -1,  1,  0}; //12 13 14 15

    void calcEncoder()
    {
      static unsigned char EncoderCur;

      EncoderCur = ((digitalRead(ENCODER_A)==HIGH)?2:0) + ((digitalRead(ENCODER_B)==HIGH)?1:0);
      Encoder -= decode_direction[EncoderCur + EncoderPrev*4];
      EncoderPrev = EncoderCur;
    }

    void setup() {

      pinMode(ENCODER_A, INPUT);
      pinMode(ENCODER_B, INPUT);
      attachInterrupt(ENCODER_A_int, calcEncoder, CHANGE);
      attachInterrupt(ENCODER_B_int, calcEncoder, CHANGE);
    }

    void loop() {
      Serial.println(Encoder);
    }
     
    Tomasina и Aleksey702 нравится это.
  5. ANV

    ANV Гуру

    Этот код для самодельной Меги. Для остальных плат соответствие прерываний и пинов тут
     
  6. Aleksey702

    Aleksey702 Нуб

    Схему подключения можете показать? Боюсь спалить что-нибудь.
    Нужны ли резисторы для подключения данного энкодера? Или напрямую через 5В пустить и на землю выход?
     
  7. geher

    geher Гуру

    На каждом таком энкодере две группы по три контакта. Каждая группа соответствует одному из двух датчиков на энкодере. Два датчика, смещенных на полфазы, позволяют определять направление движения и/или делать более точными измерения угла поворота.
    В каждой группе +5, земля и данные. Данные надо подключать к цифровым пинам.
    Один из вариантов подключения (с точностью определения поворота в соответствии с количеством прорезей в колесе) такой: один датчик к пину с прерыванием, второй - к любому. Первый будет считать импульсы, по данным второго можно будет определить, куда крутится колесо.
    С питанием и землей, надеюсь, понятно что делать.
    Никаких дополнительных резисторов не нужно.
    Данный конкретный энкодер можно подключать напрямую к пинам ардуины.
    Когда я покупал такие в Амперке, на них были распаяны разъемы под шлейфы, которые можно подключать к Тройка-щиту.

    Вот плоды моих экспериментов с двумя энкодерами, по одному на мотор (простые счетчики импульсов, при вращении в одну сторону значение увеличивается, в другую - уменьшается).
    На данный момент работы по проекту приостановлены на неопределенный срок.
    Эксперименты показали, что разница в показаниях энкодеров растет непостоянно, и приходится этот рост в основном на старт и остановку. Движение с постоянной скоростью идет по почти идеальной прямой.
    Внешнее управление и обратная связь через БТ HC-06, подключенный к Serial1 на Leonardo.
    Код (Text):

    // пин направления первого мотора
    #define PIN_MDIR_1 4
    // пин направления второго мотора
    #define PIN_MDIR_2 7
    // пин скорости первого мотора
    #define PIN_MPWR_1 5
    // пин скорости второго мотора
    #define PIN_MPWR_2 6

    // датчик первого энкодера с прерыванием
    #define PIN_MENC_IRQ_1 2
    // датчик второго энкодера с прерыванием
    #define PIN_MENC_IRQ_2 3
    // дополнительный датчик первого энкодера
    #define PIN_MENC_ADD_1 10
    // дополнительный датчик второго энкодера
    #define PIN_MENC_ADD_2 11

    // минимальная допустимая скорость, передаваемая на мотор.
    #define STOPZONE_SPEED 12
    // минимальное допустимое значение разницы скоростей моторов, передаваемое на моторы.
    #define STOPZONE_DIR 12
    // скорость (значение для ШИМ), на которой моторы начинают вращаться (установлено экспериментально для конкретной пары моторов)
    #define MINPOWER 100

    signed int speedM=0;
    signed int diff=0;
    volatile long int Encoder1=0;
    volatile long int Encoder2=0;


    void setup()
    {
      pinMode(PIN_MDIR_1, OUTPUT);
      pinMode(PIN_MDIR_2, OUTPUT);
      pinMode(PIN_MPWR_1, OUTPUT);
      pinMode(PIN_MPWR_2, OUTPUT);
      pinMode(PIN_MENC_IRQ_1, INPUT);
      pinMode(PIN_MENC_IRQ_2, INPUT);
      pinMode(PIN_MENC_ADD_1, INPUT);
      pinMode(PIN_MENC_ADD_2, INPUT);
      Serial1.begin(57600);
      //
      attachInterrupt(0, Encoder1Interrupt, RISING);
      attachInterrupt(1, Encoder2Interrupt, RISING);
    }

    void loop()
    {
      WriteSerialMessage();

      ReadSerialMessage();

      byte dirL = LOW;
      byte dirR = HIGH;
      byte pwrL = 0;
      byte pwrR = 0;
      signed int speedL = 0;
      signed int speedR = 0;
      speedM=(speedM>-STOPZONE_SPEED)&&(speedM<STOPZONE_SPEED)?0:speedM;
      diff=(diff>-STOPZONE_DIR)&&(diff<STOPZONE_DIR)?0:diff;
      int halfdiff=diff/2;
      if (halfdiff>0) {
        speedL = (speedM-halfdiff>=-512)?speedM-halfdiff:-512;
        speedR = (speedM+halfdiff<=511)?speedM+halfdiff:511;
      }
      else {
        speedL = (speedM-halfdiff<=511)?speedM-halfdiff:511;
        speedR = (speedM+halfdiff>=-512)?speedM+halfdiff:-512;
      }
      dirL = (speedL >= 0);
      dirR = !(speedR >= 0);
      pwrL = (speedL==0)?0:map(abs(speedL),1,512,MINPOWER,255);
      pwrR = (speedR==0)?0:map(abs(speedR),1,512,MINPOWER,255);
      digitalWrite(PIN_MDIR_1, dirL);
      digitalWrite(PIN_MDIR_2, dirR);
      analogWrite(PIN_MPWR_1, pwrL);
      analogWrite(PIN_MPWR_2, pwrR);
    }

    void ReadSerialMessage()
    {
      char c;
      if (Serial1.available()) {
        c=Serial1.read();
        if (c=='C') {
          speedM = Serial1.parseInt();
          diff = Serial1.parseInt();
        }
    }

    long int lastEncoder1=0;
    long int lastEncoder2=0;

    void WriteSerialMessage()
    {
      if ((Encoder1!=lastEncoder1)||(Encoder2!=lastEncoder2)) {
        Serial1.print("E");
        Serial1.print(Encoder1);
        Serial1.print(",");
        Serial1.print(Encoder2);
        Serial1.print(".");
        Serial1.println("Z");
        lastEncoder1=Encoder1;
        lastEncoder2=Encoder2;
      }
    }

    void Encoder1Interrupt()
    {
      if (digitalRead(PIN_MENC_ADD_1) == LOW) {
        Encoder1--;
      } else {
        Encoder1++;
      }
    }
    void Encoder2Interrupt()
    {
      if (digitalRead(PIN_MENC_ADD_2) == LOW) {
        Encoder2++;
      } else {
        Encoder2--;
      }
    }
     
     
    Последнее редактирование: 15 май 2015
    Aleksey702 нравится это.
  8. ANV

    ANV Гуру

    Не знаю как эти энкодеры, а те что были у меня устраивали ад и содомию если колесо останавливается в нехорошем месте. Поэтому во второй раз я сигналы завел сразу через 74HC14
     
  9. Aleksey702

    Aleksey702 Нуб

    Добрый вечер, уважаемые форумчане!
    Очень долго, благодаря вашим советам, осваивал энкодеры.
    Вот возник вопрос.
    http://static12.insales.ru/images/products/1/2005/11626453/E-MQEN.2.jpg
    При таком взаимном расположении энкодера и колеса, можем ли мы отбросить резиновую часть?
    По моей логике, при прохождении "резины", сигнал не возвращается и мы получаем логический ноль, таким образом сама шина тут служит для перемещения какой-нибудь тележки, а к энкодеру не имеет никакого отношения.
    Заранее спасибо за ответы.
     
  10. andriano

    andriano Нерд

    Не понял вопроса, но энкодер - это не шина, а та плата, которая привинчена к моторчику. Оптические датчики срабатывают либо на белый пластик, либо на черную резину, выдавая логические 0 и 1.
    Если снять шину, сигнал, как и основном варианте, не будет возвращаться. Но система станет не защищенной от внешней засветки. Хотя бы от мигающих на платах устройств (контроллера, драйвера двигателя и пр.) светодиодов, а также ПДУ и прочей бытовой техники, не говоря уже о работе на солнце.
     
    Aleksey702 нравится это.
  11. Aleksey702

    Aleksey702 Нуб

    Подскажите, а от белого пластика возвращается логический 0 или 1?
     
  12. andriano

    andriano Нерд

    Понятия не имею.
    Собственно, на логику работы это никак не сказывается.

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