Проблема подключения энкодеров

Тема в разделе "Моторы, сервоприводы, робототехника", создана пользователем Marinik, 5 янв 2016.

  1. Marinik

    Marinik Нуб

    Привет всем!
    Нужна помощь с подключением нескольких энкодеров miniQ(http://amperka.ru/product/miniq-wheel-encoder).

    Как их можно подключить через макетную плату, чтобы считывать показания с каждого энкодера(под левое и правое колесо)? И как прописать в программе, чтобы на монитор последовательного порта выводилось показание с правого и левого энкодеры(желательно еще и сделать пометки, чтобы понимать что откуда)?

    Заранее спасибо откликнувшимся!
     
  2. geher

    geher Гуру

    Данный энкодер просто выдает цвет противостоящих датчикам энкодера участков колеса. Не знаю, черный (отсутствие отражения) или белый (отражение) приводит к появлению единицы, но это значения не имеет. Суть в том, что колесо, предназначенное для использования с этим энкодером, имеет чередование черных и белых участков. А датчики сдвинуты относительно друг друга таким образом, что по разнице их показаний можно судить о направлении вращения колеса.
    Датчики подключаются к цифровым пинам и их текущее состояние может быть считано с помощью digitalRead, но лучше воспользоваться механизмом прерываний. Для этого сигнал с одного из датчиков заводится на пин с прерыванием, а другой на какой-нибудь иной пин.
    Прерывание можно "повесить" на любое событие (падение уровня, увеличение уровня, изменение уровня). Последний вариант позволит более точно определять угол поворота (импульсы будут возникать в два раза чаще, т.е. при повороте на вдвое меньший угол).
    В самом простом случае в обработчике прерывания можно просто считать факты вызова прерывания, увеличивая значение глобальной переменной на единицу, которую надо не забыть объявить как volatile.
    Можно также учитывать направление движения. Для этого достаточно в обработчике прерывания получить состояние второго датчика и в зависимости от него увеличивать или уменьшать счетчик на единицу (поскольку направление движения "туда" и "обратно" относительно, придется экспериментально установить, какое именно значение на втором датчике следует использовать для увеличения счетчика, а какое для уменьшения). Если прерывание установлено по смене уровня, также придется дополнительно прочитать состояние и первого датчика и также учитывать его при определении направления вращения.

    Для второго энкодера, установленного на другом колесе, все будет точно так же.

    Как использовать счетчик - отдельный вопрос.

    Простенький пример:
    Код (C):

    #define BTSERIAL Serial
    #define DEBUGMODE 1


    #define nop() __asm volatile ("nop")
    #if 1
    nop();
    #endif

    #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);

      #if DEBUGMODE
      Serial.begin(9600);
      #endif
      //BTSERIAL.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 (BTSERIAL.available()) {
      c=BTSERIAL.read();
      Serial.print(c);
      if (c=='C') {
      speedM = BTSERIAL.parseInt();
      diff = BTSERIAL.parseInt();
      #if DEBUGMODE
      Serial.print("C command: ");
      Serial.print("Speed = ");
      Serial.print(speedM);
      Serial.print("  Diff = ");
      Serial.println(diff);
      #endif
      }
      }
    }

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

    void WriteSerialMessage()
    {
      if ((Encoder1!=lastEncoder1)||(Encoder2!=lastEncoder2)) {
      BTSERIAL.print("E");
      BTSERIAL.print(Encoder1);
      BTSERIAL.print(",");
      BTSERIAL.print(Encoder2);
      BTSERIAL.print(".");
      BTSERIAL.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--;
      }
    }
     
    Данные с энкодеров передаются по последовательному порту (посылка, начинающаяся с "E" и содержащая через запятую текущее значение счетчиков, которые получены при помощи энкодеров):
    Через тот же порт осуществляется и управление командами вида "С<скорость>,<поворот>Z"
    Пример рассчитан на применение амперковского моторшилда и вроде бы леонардоподобной ардуины (точно не помню, для перехода на уну, возможно, что-то придется подправить с прерываниями).
     
  3. Marinik

    Marinik Нуб



    Спасибо за объяснения. У меня уже есть код для определения направления вращения и скорости колеса, меня интересует только как различать энкодеры(левое и правое колесо). Если необходимо - я могу приложить код. Пробовал подключать их в разные порты (2-3 и 4-5) - значения выдает с каждого, но не зная заранее какой куда подключен невозможно определить какой куда вращается. Меня интересует именно как в программе присвоить "имя" каждому датчику, чтобы различать их показания при выводе на экран.
     
  4. geher

    geher Гуру

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

    Контролировать же, какой именно энкодер подключен к каким пинам физически, придется исключительно "вручную", поскольку энкодер не имеет никаких отличительных признаков, которые можно запросить в программе.
     
  5. Marinik

    Marinik Нуб

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

    geher Гуру

    При использовании макетной платы должна четко прослеживаться цепь от энкодера к пину ардуины (маркировкой или цветом проводов). Тогда будет видно, какой энкодер подключен к какому пину.
     
  7. Marinik

    Marinik Нуб

    Вы меня возможно неправильно поняли. Я хочу подключить оба энкодера в одну пару пинов (2-3, например) с помощью макетной платы. Как мне, опрашивая пины 2-3 понять, какие показания идут с левого, а какие с правого энкодера?
     
  8. Onkel

    Onkel Гуру

    так нельзя, не будет работать.
     
  9. Marinik

    Marinik Нуб

    Всем спасибо за ответы. Все попробую, если останутся вопросы - напишу еще