Самопальные энкодеры и STM32F4Discovery

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

Зато выглядят довольно симпатично.

IMG_20160406_223553

God, save the Queen.

Сначала я тестировал их, подключив к Arduino. Всё замечательно работало, кроме подсчёта скорости от интервала между кликами. Поэтому в какой-то момент я решил перебросить управление шасси на более навороченный STM32F4Discovery. Тут и частота на порядок больше, и периферия жирнее, и плавающую точку в уме считает.

Практически ничего не предвещало беды…

Спойлер: На самом деле, всё-таки предвещало.

Итак, на монтажной плате спаян минимальный брейкаут: пины от Discovery подведены к драйверу моторов и к разъёму энкодеров. Пару раз всплывали неожиданности, связанные с навороченностью камня, но здесь это легко решалось переброской проводков (благо, не делал сразу печатную плату).

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

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

Да-да, когда-нибудь я буду делать скриншоты рабочего процесса. А сейчас не хочу делать постановочные кадры, дабы не вводить в заблуждение. Будет реквест — переделаю плату обратно и сделаю снимки.

Сначала я грешным делом решил, что дело в наводках от линий управления драйвером, ибо самые жёсткие выбросы получались при включённых движках. Так как на выходах энкодеров стоят триггеры Шмитта (для нас — относительно мощные полумостовые драйверы), я попробовал напаять рядом с пинами контроллера резисторы на землю, чтобы получилась эдакая токовая петля. Обычно электромагнитные помехи петлям нипочём, но сегодня явно не мой день, и проблема не решилась. Тем не менее, петли я пока оставил.

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

Переписал код, проверил подключения. Эффект абсолютно такой же. Когда я решил в прерывании дёргать отладочный светодиод, я увидел, что прерывание иногда вызывается где-то между фронтами. Чертовщина какая-то…

Ладно, пёс с ней, со скоростью. Надо попробовать проверить фазы, мало ли что. Задача — сделать сигнал с двух фаз сдвинутым один относительно другого на 90 градусов методом подкладывания шайб под держатель одного из датчиков.

На первом канале сдвига не было впринципе, и там шайбы пришлось убрать. На втором , подшаманив немного, я получил довольно аккуратную пару сигналов. Начинаю проверять получаемые данные…

Прикол. Один из энкодеров выдаёт фокус: в одну сторону тики считаются нормально, в другую — ровно в два раза меньше. Нет, это уже перебор. Перепроверяю настройку прерываний — всё чисто. Решил ввести отдельные счётчики на увеличение и уменьшение и — да! — в сторону увеличения на каждые два прибавления приходит одно вычитание. Ровно.

Практически отчаявшись, я сидел с осциллографом на коленях, подключенным к разным каналам энкодера, и лениво покручивал колесо.

IMG_20160406_005259

 

Ба-а-а. А это что за иголка на верхнем канале в момент переключения второго?

Вытаскиваю картинку с ножки отладочного светодиода — и точно, «лишнее» прерывание на первом канале получается как раз в момент переключения второго с высокого на низкий уровень.

IMG_20160404_204706

Было уже два часа ночи, в соседней комнате ночевали гости, и я решил просто напаять RC-фильтры на каналы, способные по времени не пропустить эту иголку.

Утром я снова достал осцилл и посмотрел на результат. После этих шаманств иголки дейстаительно пропали, более того — пропали странные «перелёты» уровней на фронтах с энкодеров. Однако, теперь фронты стали пологими, и контроллер начал считать лишние прерывания.

И тут я вспомнил об одном интересном поле в настройке захвата таймера — фильтре. Открыл reference manual и убедился, что это как раз то, что я искал: блок захвата считает изменение уровня случившимся, если за заданное количество тиков таймера уровень не меняется. Выставил фильтр в 8 (задержка 8 мкс, это как раз время зарядки RC-цепочки) — и графики с энкодеров сразу стали достаточно гладкими.

snapshot102

Иногда бывают всплески, но это уже не тот масштаб проблемы. Более того, фильтром Калмана вся эта ботва приводится в довольно удобоваримый и аккуратный вид.

Софтину пока рекомендовать не буду. Найдена на просторах Интернета, выглядит сыроватой и отхавывает весь процессор активным ожиданием. Если что-то с ней решится — будет хорошо.
UPD: Даже без фильтра частота работы таймера ниже, чем у ядра, и этого хватает для нормальной обработки пологих фронтов.

Дебрифинг

Проводя после всего этого разбор полётов, я начал понимать, почему проблема не дала о себе знать на Arduino. Дело в том, что в ней используется 5-вольтовая логика, а на STM32 — 3.3-вольтовая, хоть и толерантная к 5 вольтам, а триггеры Шмитта на выходах энкодеров выдавали как раз 5 вольт. Соответственно, пороги срабатывания стали ниже, из-за чего иголки не ловились на AVR, но начали влиять на ARM-камень. Ну и увеличение частоты в 10 раз могло дать о себе знать.

На будущее — надо раскурить природу появления этих иголок и «перелётов» уровня, ну и понять метод эффективной борьбы с ними. И вот о спойлере выше: что-то мне подсказывает, что это как-то связано…

А сейчас самое время подключать гироскоп. Но это будет уже совсем другая история.

Оставить комментарий