Arduino + encoder — обработка высоких оборотов

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Небольшой очерк как решить простую практическую задачу по обработке показаний с инкрементарного энкодера (E6B2 -CWZ1X) на arduino. Данная задача возникла в связи с необходимостью точного измерения пройденного расстояния в помещении. Энкодер соединен с колесом достаточно большого диаметра через редуктор. Размеры колеса, редуктора для целей задачи пока не имеют значение. Первично — считывать показания энкодера на достаточно больших оборотах.


Шаг первый. Uno.


За основу был взят «золотой стандарт»: arduino uno и код, скорость работы которого, не подвергалась скептическому анализу:
код для arduino
/*
 Максимально быстрый универсальный код для обработки энкодера
 Работает на перывании (используется одно)
 Тут код построен на bitRead(PIND..) - только для Arduino NANO!
*/
#define ENC_A 2       // пин энкодера
#define ENC_B 4       // пин энкодера
#define ENC_TYPE 1    // тип энкодера, 0 или 1
volatile int encCounter;
volatile boolean state0, lastState, turnFlag;
void setup() {
  Serial.begin(9600);
  attachInterrupt(0, int0, CHANGE);
}
void int0() {
  state0 = bitRead(PIND, ENC_A);
  if (state0 != lastState) {
#if (ENC_TYPE == 1)
    turnFlag = !turnFlag;
    if (turnFlag)
      encCounter += (bitRead(PIND, ENC_B) != lastState) ? -1 : 1;
#else
    encCounter += (bitRead(PIND, ENC_B) != lastState) ? -1 : 1;
#endif
    lastState = state0;
  }
}
void loop() {
  Serial.println(encCounter);
  delay(100);
}


*ссылка на оригинал кода и статью.

Код работал без нареканий, однако после крепления энкодера на вал (через редуктор), выяснилось следующее. При движении, энкодер шлет слишком большой поток показаний (ticks) и вывод быстро ими забивается и виснет. Это связано, как выяснилось, не только с самой моделью энкодера, который выдавал 1000 ticks на оборот, но и с микроконтроллером arduino.
Были предприняты попытки выводить не все шаги энкодера, а каждый 10 или каждый 100 шаг, заменить arduino uno на nano, увеличить скорость serial portа до максимума, использовать иные варианты кода для arduino. Однако проблему это не решило, и arduino все так же умирал на высоких оборотах энкодера.
Встал вопрос: брать энкодер с меньшим количеством шагов (минимальный 100 против текущих 1000) у того же производителя либо заменить arduino на что-то еще. Пошли по второму пути, поглядывая на первый.

Шаг второй. Чем заменить Uno.


Выбор пал на достаточно доступную в продаже Nodemcu v.3 на esp8266, у которой и достаточное количество пинов и частота (тактовая частота: 80 – 160 МГц против 16 МГц arduino). Однако найти внятный, быстрый код под плату не удалось, а колхозить не было времени и желания. Кроме того, плата оказалась с дефектом и не работала через micro-usb.
Очень интересной показалась Wemos ESP32, на которой еще и уютно расположился micro-display, но на шаге вытянутой руки ее не было, и тут на глаза попалась raspberry pico. Но, с pico тоже оказалось не все так гладко в части скорости работы с прерываниями — "
*фото из видео.
Поэтому решили временно в ее сторону не смотреть.

Самый мелкий arduin.


В итоге, как всегда, остановились на том, что было «под рукой» — на Seeeduino-XIAO, который по размерам чем-то напоминает digispark, но выгодно отличается по характеристикам (до 48 МГц против 16 МГц).

Подробно о том как с ним работать можно почитать на странице разработчика.
Так как данный микроконтроллер можно условно отнести к семейству arduino, предыдущий код на нем заработал с небольшими косметическими правками.
Код для xiao
#define ENC_A 0       // пин энкодера
#define ENC_B 1       // пин энкодера
volatile int encCounter;
volatile boolean flag, resetFlag;
volatile byte curState, prevState;
void setup() {
  Serial1.begin(115200);
  while (!Serial);
  attachInterrupt(0, int0, CHANGE);
  attachInterrupt(1, int0, CHANGE);
}
void int0() {
  encTick();
}

// алгоритм со сбросом от Ярослава Куруса
void encTick() {
  curState = digitalRead(ENC_A) | digitalRead(ENC_B) << 1;  // digitalRead хорошо бы заменить чем-нибудь более быстрым
  if (resetFlag && curState == 0b11) {
    if (prevState == 0b10) encCounter++;
    if (prevState == 0b01) encCounter--;
    resetFlag = 0;
    flag = true;
  }
  if (curState == 0b00) resetFlag = 1;
  prevState = curState;
}
void loop() {  
  if (flag) {
    Serial1.println(encCounter);
    flag = 0;
  }
}


Вместо serial — serial1, пины 0,1. Не все digital пины можно использовать, как оказалось: 4-й, 5й и 7й одновременно. Сам seral port «висит» на 6,7 пинах. Однако, этого достаточно, так как для общения с энкодером нужно 2 пина.
Еще один момент который необходимо иметь ввиду, это то, что xiao использует 3,3 V логику и подключать напрямую к нему энкодер небезопасно. Поэтому использовался логический согласователь уровней 5V-3,3V.
Общая схема сопряжения выглядит так:

При работе с xiao также есть небольшие особенности. Контроллер имеет type-C вход и на это сразу «покупаешься», когда видишь. Однако, этот вход только для питания и прошивки. Как serial port его использовать нельзя, а жаль.
Также для перезагрузки xiao нет никакой внешней кнопки (в виду размеров самого контроллера видимо) и чтобы его перезагрузить необходимо замкнуть два контакта на лицевой стороне либо на оборотной стороне (об этом написано на странице разработчика). В остальном работа с ним такая же как и с другими представителями семейства arduino.

Итог.


В результате замены arduino uno на собрата меньшего размера с лучшими характеристиками проблема была решена. Задержек при выводе в serial и подвисаний не выявлено:
Источник: https://habr.com/ru/post/649845/


Интересные статьи

Интересные статьи

TiSpark – это подключаемый модуль Apache Spark, который работает с платформой  TiDB  и отвечает на запросы сложной интерактивной аналитической обработки (OLAP). Этот плагин Spark широко и...
Ранее в одном из наших КП добавление задач обрабатывалось бизнес-процессами, сейчас задач стало столько, что бизнес-процессы стали неуместны, и понадобился инструмент для массовой заливки задач на КП.
Каждый лишний элемент на сайте — это кнопка «Не купить», каждая непонятность или трудность, с которой сталкивается клиент — это крестик, закрывающий в браузере вкладку с вашим интернет-магазином.
Для уважаемых читателей GeekTimes очередная (четвёртая) долгожданная статья о том, что будет, если снова замешать ардуинку, ESP8266, WI-FI, приправить смартфоном на Android и посыпать сверх JAVA ...
Сегодня мы поговорим о перспективах становления Битрикс-разработчика и об этапах этого пути. Статья не претендует на абсолютную истину, но даёт жизненные ориентиры.