Pull to refresh

Comments 87

angle += increment[AB+ABprev*4];

сильно ли изменит картину замена операции умножения сдвигом?

не изменит вообще, gcc сам ставит сдвиг вместо умножения в ассемблере
Зато int можно было бы на signed char заменить в таблице трансляции. Возможно, чуть улучшило бы ситуацию.
Если позволите, два соображения по поводу точности софтверного варианта:
1. Может влиять вывод в сериал при собственно формировании вывода (они обожают блокировать прерывания) и при собственно передаче (во время прерывания после очередного байта).
2. Дребезг может быть слишком быстрым и к моменту считывания текущего значения в прерывании Вы теряете, к примеру +1 и делаете лишнюю -1.
Посоветовал бы попробовать вариант с отключением прерывания по тому пину, что только что сработал и оставлять второй, и так их постоянно менять — тогда дребезг просто не заметен и таблица инкрементов становится проще — лет 10 назад я так делал с обычными, не настолько быстрыми, энкодерами — получалось неплохо.
Если отключать прерывание по сработавшему пину, то тогда плохо будет отрабатываться смена направления, разв нет?
Это так, но приводит только к +-1 при смене направления и не накапливается, что есть очень хорошо.
Интересное замечание, спасибо большое!
2. Дребезг может быть слишком быстрым

4. Дребезга может не быть вообще, т.к. в правильном энкодере он подавлен аппаратно.
> 4. Говорят, stm32 и дёшев, и имеет хардверный счётчик. Но цена вхождения (в смысле времени) в вопрос больно кусается.

А в чем сложность? Туда же вроде тот же код ардуины можно залить, не?
Я могу только в режиме «Мойша напел», так как сам вопросом не владею. Возможно, уже допилили оболочку ардуины для поддержки stm32, но относительно недавно я ещё читал статью, где до мигания светодиодом дошли в конце второй, причём не самой короткой, статьи:
статья 1
статья 2
Не, там про нативную разработку, это совсем другая история (тем более на асме).

Я сам то с обычной ардуины на ESP перепрыгнул. Там именно код от ардуины «как есть» можно брать, через ту же arduino IDE (хотя я взял VisualStudio). И забыть про нехватку памяти и производительности.

Вроде и для STM так можно, только настроить один раз по инструкции.

Правда как хардверный счётчик цеплять — это отдельно надо думать, но вообще производительности STM может и на софтверном хватить с большим запасом.
> 4. Говорят, stm32 и дёшев, и имеет хардверный счётчик. Но цена вхождения (в смысле времени) в вопрос больно кусается.
А если stm32+Micropython?
А не проще ставить прерывание по фронту только на одну ногу, а в прерывании читать состояние второй, её состояние и будет направление движения? кода меньше, скорость больше.

Если я правильно понял предложение, то в два раза падает точность. Вместо четырёх отсчётов на прорезь получится два.

если только по фронту то в 4, но надо ли оно при 2000ppr? Нужна ли точность в 3 минуты при 1000+RPM? Зато учитывая что при текущей схеме оно обрабатывает до 1000rpm, то при моей будет условно до 4000

Мда… STM32 Blue Pill стоит 1.8$. Ардино 3$. Помоему ардуино просто лишняя трата денег. В stm32 частота выше, а код пишеться за 5 минут не спешего ковыряние STM32CubeMX, одного make, openocd -l stm32f103c8t6.cfg --init

Предлагаю эксперимент. Я за свои деньги покупаю blue pill, затем ставлю секундомер, если за 10 минут я не могу воспроизвести подсчёт энкодера с выводом в последовательный порт, то вы мне возмещаете потраченные деньги.

Купите blue pill за 1.8$. Я настолько уверен, что готов сделать перевод денег, хоть сейчас. Но подождите я щас вам статью забацаю :).

(1.8$ с бесплатной доставкой)

Хорошо, спасибо за совет, заказал пару плат. Ехать будут недели три, так что ждать статьи перед заказом ни к чему :)

Рекомендую еще st-link заказать. Отладка с ним просто рай. И хорошо, что два. Из одного можно сделать BLACK MAGIC PROBE

Докупил и его, спасибо. Жду статью!
А вы уверены, что впервые прикоснувшись к ардуино, вы написали бы это за 10 минут?
Подскажите, где я это утверждал?
Хм. В даташите на atmega328p в разделе 27 описан аппаратный компаратор. Он умеет генерировать прерывания по изменению состояния на выходе. Можно попробовать считать импульсы на нем. Для определения направления не годится — он однопороговый.

Компаратор там вполне годный, я на нем импульсный металлодетектор делал.

С STM32 ситуация такая, что там программно особо ничего не сделаешь с дребезгом, если подсчёт через таймер делать. Я смог 100% побороть только аппаратно, через фильтр + триггер Шмитта.
Я ардуинщик так что сильно не пинайте за вопросы.
на некоторых atmel только 2 прерывания, как быть если надо несколько энкодеров?
даже если есть несколько прерываний не будут ли они конфликтовать при одновременной работе?
на некоторых atmel только 2 прерывания


Я не очень понял, можете пояснить?
Например UNO int0, int1 получается можно подключить только один энкодер?
image
The External Interrupts are triggered by the INT0 and INT1
pins or any of the PCINT23...0 pins.

тоесть прерываний таки 2, только они могут быть назначены на другие ножки.
получается можно подключить только один энкодер?
Там ещё есть прерывания по изменению уровня на пине, т.е. не два, а
EXT_INT0, EXT_INT1, PCINT0, PCINT1, PCINT2 т.е. 5. И потенциально можно использовать как внешнее прерывание ANA_COMP(от встроенного компаратора).

А кто вам чушь про дребезг на плавно меняющихся фронтах рассказал?
Расскажите ему про гистерезис логических уровней.
'дребезг' в данном случае может возникнуть только если энкодер физически вибрирует.

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

ps:
Вы много видели механических энкодеров с разрешением бОльшим нескольких десятков импульсов? А это уже немного другие временнЫе параметры и дребезг там вполне можно давить софтово.
У меня под руками лежит оптический энкодер без подавления дребезга, просто фотодиод через компаратор.
компаратор без гистерезиса?
Видимо да, т.к. дребезг присутствует.

Так ведь можно выход на один из входов кинуть и получить гистерезис с нужными характеристиками. Или там диапазоны напряжений разные?

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

Ну, тут разница между приличным и неприличным энкодером в один резистор выходит...

Просто большинство «разработчиков», особенно тех, кто использует ардуино, слабо знакомы со схемотехникой, и не догадываются, что можно не делать костыли в коде.
К чему эта высокомерность? Если можете привести код без «костылей», был бы очень благодарен.
Это не высокомерность: просто смысл давить дребезг программно, да ещё в очень ограниченных ресурсах, есть, в основном, тогда, когда у вас готовое устройство в котором забыли сделать это аппаратно.

Ну и подавляющее большинство тех, кто балуется с ардуино, пришли из программирования в лучшем случае, или вообще со стороны, а не из схемотехники, или тем более, проектирования встраиваемых систем, и не имеют профильного образования. Т.е. это не высокомерие, это констатация факта — многие просто не знают о том, как это делается. И уровень поделок на ардуино весьма низок, как и порог вхождения, кстати.
UFO just landed and posted this here

У высокоточных оптических энкодеров нет перобразования синусоиды в меандр. Вместо этого есть специальные коробочки (умножители), которые анализируют две входны синусоиды A и B и по ним восстанавливают угол с повышенной точностью. Например, 1000 отсчётов на прорезь.
Это я так, для информации, захотелось поделиться.

Дурацкий вопрос: а корректно ли вообще использовать слова «синусоида» и «меандр» применительно к энкодерам? Ведь они же не с постоянной скоростью вращаются…

Про меандр можно пообсуждать и подокапываться до формальных определний, а про синусоиду — можно. То есть y1=sin(t) это гармонический сигнал, синусоида времени, периодическая функция и всё такое. А y2=sin(phi(t)) — это синусоидальная функция с аргументом phi. Про y2 можно говорить "синусоида угла", но не стоит говорить "гармоническая функция".
Вообще, это всё вопрос терминологий и догворённостей. Например, сумму двух гармонических функций уже нельзя называть периодическим сигналом, но все называют. Главное, чтобы люди друг друга понимали. :)

Главное, чтобы люди друг друга понимали. :)


Ну я как бы согласен, но меня тут уже не раз закидывали тухлыми яйцами за нестрогое следование терминологии. Этажинтернет ;)
У некоторых энкодеров (например ЛИР) умножитель уже встроен в схему и на выходе имеется квадратурный ТТЛ сигнал. «Коробочки» не нашел где купить, только в СКБ ИС если, поскольку они представители в РФ фирмы -производителя.
вообще я не увидел антидребезг. а без него нельзя. все три счетчика посчитают дребезг правильно. а количество пройденных оборотов неправильно. самое правильное это конечно на stm 32 квадратурный аппаратный счетчик.
можно посмотреть реализацию в проекте по «автономному контроллеру на stm32»
Подскажите, а чем квадратурный аппаратный счётчик STM32 лучше квадратурного аппаратного счётчика ARM8 или квадратурного аппаратного счётчика hctl2032, описанных в статье?
А почему не код Грея? Тогда энкодер можно абсолютным сделать.
Не надо менять сценарий по ходу пьесы! У меня была задача именно инкрементальный энкодер считать. А абсолютные того же разрешения стоят совсем других денег. Инкрементальный энкодер 2000ppr даёт разрешение 1/8000 оборота, стоит 30 долларов. Сколько стоит 13 битный энкодер с кодом Грея?
Лучше посмотрите в сторону AS5048A и им подобных.
Я по ходу работы столкнулся с такой же задачей.
Есть оптический энкодер ЛИР-158Б, и к нему родной преобразователь ЛИР-917 с выходом на USB. Производитель уверяет что преобразователь тянет частоту запросов до 50Гц, а мне для задачи (оценка ускорений при разрушении маятником образца) требуется суб-миллисекундная точность. Потому тоже пробую приспособить Arduino Uno для чтения энкодера. Поначалу повторил вашу мысль о таблице преобразований, но затем упростил её до следующей логики (упрощенно):
volatile bool StateA, StateB; //глобальные, инициализируются при запуске чтением ножек.
volatile long Coord; //глобальная, при запуске 0
// Прерывание по каналу A датчика угла поворота
void interruptChannelA() {
  // меняем состояние канала (чтобы не делать digitalRead())
  StateA = !StateA; 
  // корректируем координату
  if (StateA != StateB) Coord++;
  else Coord--;
}

// Прерывание по каналу B датчика угла поворота
void interruptChannelB() {
  // меняем состояние канала (чтобы не делать digitalRead())
  StateB = !StateB;
  // корректируем координату
  if (StateA == StateB) Coord++;
  else Coord--;
}


Собственно скорости вращения небольшие, порядка 5-10 радиан/сек (60-100 rpm).
Проблема в памяти — 2КБ всё-таки маловато для регистрации даже одного маха маятника (я регистрирую число микросекунд, прошедших с предыдущего тика энкодера). Но если верить вашим результатам, хотя бы с быстродействием все будет в порядке.
Я не понял, что именно вы хотите хранить в памяти? Динамику поведения маятника? Почему бы её не выдавать наружу вместо хранения внутри ардуины? Пусть хранят те, у кого память есть.
Да, динамику поведения.
Проблема в том, что по моим подсчетам получается следующее:
6 радиан/сек дают порядка 9500 тиков энкодера в секунду. Я собираюсь передавать интервалы между тиками в микросекундах, т.е. у меня будет 1 пакет на тик.
Максимальная заявленная скорость виртуального серийного порта для Uno — 115200 бод, что даёт порядка 11КБ/с. Т.е. я успеваю передавать данные быстрее, чем они генерируются, только если каждый тик будет кодироваться 8-10 битами — а такой разрядности мне может не хватить.
Сейчас я планирую использовать ОЗУ ардуины как кольцевой буффер, с таким расчетом чтобы он не успел переполниться за характерный интервал измерения. Но все равно, как-то ненадежно.
И всё это при допущении, что Ардуино реально вытянет эти 11КБ/с. Если завязаться на протокол USB напрямую, наверняка можно выжать куда больше, но это уже сложнее чем написать Serial.begin(115200). =)
Не используйте последовательный порт, используйте SPI, он гораздо, гораздо быстрее. Я когда делал контур тока, выдавал с ардуины данные в SPI, читал их логическим анализатором, сохранял логи и парсил потом логи.
Интересная идея. Но если нужно ставить промежуточную ступень, то тогда проще уж сразу задействовать что-то с большим объемом памяти. Я Uno-то выбрал потому что дешево (для proof of concept, что я вообще смогу читать этот энкодер саомстоятельно) и потому что 5В выходы есть. Соотв. порог вхождения примерно на уровне плинтуса — как раз для меня. =)
Соглашусь, это может быть оверкилл, но сейчас, на этапе прототипирования, простота может оказаться важнее.
А что, надо в реальном времени передавать? Сохраняйте в массив, а по окончании измерений передавайте.
См. мой комментарий выше про объем памяти. В 2КБ на Uno не влезает.
Сейчас использую Arduino Mega2560, вот там уже можно жить — со скрипом, но памяти хватает на одно измерение.

Правда, всплыла другая проблема — такое чувство, что меандр там (в ЛИР-158Б) не совсем равномерный. Наблюдаются периодические отклонения от среднего интервалов между фронтами — где-то +-5% от среднего, причем наблюдаются при любой скорости вращения.

P.S.: извините за столь поздний ответ — забыл про тему.
Я для работы с энкодером использую Ардуино Дуе. Там аппаратный режим для подключения энкодера, памяти хватает на все про все. На ebay цена порядка 900 руб. Кроме того там есть «Native USB» разъем.
По поводу ЛИР-158. Это довольно точный датчик. В зависимости от исполнения
5 класс ±15" 6 класс ±30" 7 класс ±75" 8 класс ±150"
причем это накопленная погрешность, а не между штрихами.
Хотя может быть между фронтами 5% отклонение возможно.Там число физических штрихов на лимбе 5400 максимум, а для повышения разрешения применяется интерполяция.
В моей модели 2500 штрихов. Собственно, вопрос был не в точности измерения угла (она приемлемая), а в источнике погрешности фронтов. То бишь, это неустранимая особенность датчика, которую надо просто обойти, или это я дурак и неправильно запрограммировал Ардуино. =)
А как Вы вообще определили, что что фронты гуляют на 5%?
Соединил энкодер с маятником и измерял интервалы между соседними
прерываниями (фронтами по обоим каналам энкодера) — последовательность dT(X) где X — положение вала энкодера.
Уже тогда стал заметен определённый паттерн — например, на одном энкодере задержки формировали повторяющийся периодический паттерн (значения условные): 110мкс, 105мкс, 105мкс, 95мкс. На другом энкодере той же модели паттерн отличался, но он тоже был повторяющийся и тоже имел период 4 измерения (4 фронта = 1 деление на лимбе).
Этот паттерн наблюдался на всех участках траектории, т.е. при разных скоростях вращения, в том числе и при низких (возле крайних положений маятника). Значит, дело не в производительности МК.
Далее, я нашел относительное отклонение значения каждого измерения от среднего по пяти точкам — это порядка 0,18 градуса дуги, средняя скорость не должна существенно измениться на таком интервале. Величины этого отклонения были в пределах ±5%.
Что самое интересное, характер распределения величины отклонения по положениям вала энкодера сохранялся — то есть, если в каком-то положении вала разброс был меньше, он был меньше и при последующих измерениях. Конкретные значения чуть «гуляли», но картина распределения сохранялась и была уникальной для каждого экземпляра энкодера в моем распоряжении.
Исходя из этого, я сделал вывод, что «гуляющие» интервалы между соседними тиками энкодера вызваны погрешностями изготовления лимба, а не особенностями программы/МК.
P.S.: интервалы в микросекундах измерялись 16битным таймером с предделителем 8, без использования прерываний — просто брал значение счетчика и сдвигал на бит вправо. Однако идентичная картина наблюдалась и при использовании стандартной micros(), с поправкой на её разрешение 4мкс.
Добавлю ещё, что я рассматривал гипотезы о колебаниях питающего напряжения, вибрациях маятника и плавающей тактовой частоте Ардуино. Но насколько я понимаю, ни в одном из этих случаев не появлялся бы такой устойчивый паттерн задержек, сохраняющийся при разных скоростях.
image

> интервалы между соседними прерываниями (фронтами по обоим каналам энкодера)

Фронты — это именно фронты, или фронт и спад?
Если фронт и спад, то длительности полуволн наверное могут быть неодинаковы. В этом случае можно попробовать брать прерывания только по [восходящему] фронту или только по спаду.
Да, я имел ввиду оба перехода между уровнями, независимо от направления.
Ну вот можно попробовать прерывание только по фронту одного из сигналов. Разрешение конечно будет меньше.
Это будет эквивалент усреднения по нескольким точкам. Памяти мне хватает, так что лучше я сделаю это программно, на ПК.
ЛИР-917
Максимальная входная частота сигналов преобразователя 5 МГц
Его я поначалу и использовал — но 5МГц это именно что входная частота, т.е. сигнал с энкодера. А я говорю о частоте опроса преобразователя с компа.
Увы, ЛИР-917 не умеет работать в пакетном режиме (сделать N измерений за промежуток времени и отдать их разом). А вручную задержки порядка 1 мс в юзерспейсе обычной ОС с вытесняющей многозадачностью сделать трудно. Вот и пришлось городить огород с ардуино в роли преобразователя — провести пакет измерений, сохранить в ОЗУ, потом неторопливо отдать на комп по виртуальному COM-порту.
Да он еще и дорогой. Ардуино во всех отношениях лучше. Можно обрабатывать сигнал так, как тебе нужно.
Я конечно все понимаю, но ATMega и STM32 — изначально сильно отличные микроконтроллеры.
Но почему бы не взять Xmega — где вообще аппаратный блок для работы с энкодером.
Причем та же Atmel студия, только библиотеки ASF для удобства.
Я активно работаю над сложным проектом с STM32, но в своих проектах часто использую Atmel Xmega.
Кроме того — у Atmel полно недорогих ARM процессоров, весьма доступных. От 100 руб. за штуку, и там тоже хватает интересной периферии. Те же M0+ — это 32 бита и 48 МГц. И даже в soic корпусе.
Вот только стм стартует от примерно 50р в розницу.
Да, неплохо. У Atmel будет в два раза дороже.
Метод на прерываниях вообще непредсказуемый — никогда не угадаешь, найдется ли среди всех этих прерываний время для выполнения основного кода.

А «Ардуино головного мозга» — это когда делают отдельную плату на STM32, которая считает энкодер и передает в Ардуину показания энкодера по UART.

В arduino due имеется аппаратный энкодер. Надо не забыть только подтягивающие резисторы ( 1 ком например)на 3.3в заводить, потому что встроенные 20 к не обеспечивают быстродействия из-за завала фронтов.
Sign up to leave a comment.

Articles