Arduino Due, арифметика и другие вопросы

Доброго дня,уважаемые.
Пытаюсь отследить быстро вращающийся энкодер струйного принтера. С помощью библиотеки encoder.h считываю значения, затем эти значение через коэффициент привожу к нужному. Но здесь вроде бы и просто, но есть математические операции и преобразование типов переменных. Вот два способа, два варианта. Говорят. что оба плохие…

photo_2023-08-20_11-13-24

подскажите пожалуйста, касательно DUE структуры, что делать лучше аппаратно делить целые числа, или может аппаратно делить на float ? Энкодер быстрый, нужно делать возможно быстрее.

Спасибо.

Если быстрее, то лучше не делить, а умножать.
Т.е. заранее вычислить величину 1/stepper_Factor и ею пользоваться.
Если нужно еще быстрее, то следует разбираться уже с двоичной системой.
Напишите, чему у Вас равен stepper_Factor и каков диапазон изменения new_Encoder. Выбор оптимального варианта зависит от ответа на эти вопросы. Ну и заодно, на какую точность претендуете.

Для справки:

   Uno:  Time Measurements, byte size:	1320,	int size:	660,	float size:	330
   Due:  Time Measurements, byte size:	32768,	int size:	16384,	float size:	8192
            Uno  mcs         cyc         rep    Due  mcs       cyc         rep
Fill bytes:      0.48 mcs    7.71 cycles  1320    0.21 mcs   17.29 cycles  32768
Fill bytes(L):   0.48 mcs    7.76 cycles  1320    0.10 mcs    8.54 cycles  32768
Fill ints:       0.62 mcs    9.89 cycles   660    0.10 mcs    8.29 cycles  16384
Fill longs:      0.90 mcs   14.35 cycles   330    0.10 mcs    8.62 cycles   8192
Fill floats:     0.90 mcs   14.35 cycles   330    0.10 mcs    8.63 cycles   8192
Fill doubles:                                     0.15 mcs   12.22 cycles   4096

millis(b):       1.81 mcs   28.90 cycles  1320    0.34 mcs   28.20 cycles  32768
millis(i):       1.94 mcs   31.03 cycles   660    0.32 mcs   27.11 cycles  16384
millis(L):       2.22 mcs   35.49 cycles   330    0.36 mcs   30.23 cycles   8192
micros(L):       4.00 mcs   64.00 cycles   330    1.46 mcs  122.71 cycles   8192
int MUL:         0.77 mcs   12.32 cycles   660    0.13 mcs   10.75 cycles  16384
int DIV:        15.35 mcs  245.62 cycles   660    0.24 mcs   20.44 cycles  16384
int ADD:         0.77 mcs   12.32 cycles   660    0.24 mcs   20.24 cycles  16384
int SUB:         0.77 mcs   12.32 cycles   660    0.22 mcs   18.22 cycles  16384
long MUL:        1.38 mcs   22.11 cycles   330    0.10 mcs    8.14 cycles   8192
long DIV:       42.48 mcs  679.76 cycles   330    0.33 mcs   27.71 cycles   8192
ong ADD:         1.47 mcs   23.47 cycles   330    0.28 mcs   23.80 cycles   8192
long SUB:        1.43 mcs   22.88 cycles   330    0.17 mcs   13.88 cycles   8192
int => float:    4.47 mcs   71.56 cycles   330    0.87 mcs   73.02 cycles   8192
float MUL:      13.89 mcs  222.25 cycles   330    3.00 mcs  251.81 cycles   8192
float DIV:      34.93 mcs  558.93 cycles   330   12.25 mcs 1028.62 cycles   8192
float AD:       12.67 mcs  202.67 cycles   330    3.33 mcs  279.80 cycles   8192
float SUB:      12.62 mcs  201.89 cycles   330    3.45 mcs  289.40 cycles   8192
sin(float):    123.55 mcs 1976.82 cycles   330   52.99 mcs 4451.54 cycles   8192
int => double:                                    1.08 mcs   90.99 cycles   4096
double MUL:                                       2.54 mcs  213.06 cycles   4096
double DIV:                                      11.84 mcs  994.65 cycles   4096
double ADD:                                       2.86 mcs  240.27 cycles   4096
double SUB:                                       3.19 mcs  268.00 cycles   4096
sin(double):                                     52.59 mcs 4417.79 cycles   4096
digitalWrite:    5.80 mcs   92.85 cycles  1320    1.77 mcs  148.30 cycles  32768
digitalWrite:    7.38 mcs  118.06 cycles  1320    2.25 mcs  189.34 cycles  32768
digitalWrite:    5.81 mcs   92.90 cycles  1320    2.36 mcs  198.36 cycles  32768
pinOut:          0.90 mcs   14.40 cycles  1320
pinOutHihh+Low:  0.56 mcs    8.92 cycles  1320
digitalRead:     4.57 mcs   73.12 cycles  1320    1.16 mcs   97.24 cycles  32768
digitalRead:     5.99 mcs   95.90 cycles  1320    1.21 mcs  101.24 cycles  32768
analogRead:    112.20 mcs 1795.20 cycles   660    4.48 mcs  376.57 cycles  16384
pinMode:         5.27 mcs   84.27 cycles   660    3.14 mcs  263.54 cycles  16384
shiftOut:      182.21 mcs 2915.39 cycles   660   53.06 mcs 4457.16 cycles  16384
delayMs(1):      1.24 mcs   19.88 cycles  1320    1.04 mcs   87.22 cycles  32768
delayMs(10):    10.35 mcs  165.53 cycles  1320   10.06 mcs  845.11 cycles  32768
delayMs(100):  100.89 mcs 1614.21 cycles  1320  100.16 mcs 8413.77 cycles  32768

По идее лучше всего: stepper_Count = new_Encoder*(_1_stepper_Factor)/Factor_2;
где все числа целые (для Due int и long - одно и то же), Factor_2 - подобранное значение равное степени двойки такое, что (_1_stepper_Factor)/Factor_2 == 1/stepper_Factor.

1 лайк

Степпер фактор константа. Если использовать тип float то примерно такое диапазон от 0.35 до 2.45. Т.е не целое число. Это коэффициент, скажем энкодер проехал 1 см, для соответствия и нам нужно проехать 1см, но через stepper_Factor. На данный момент stepper_Factor = 0.89. Это константа, она задается и не меняется вообще.
По энкодеру… Я смотрел через serial значения меняются от 0 (я записываю 0 перед запуском)…затем идет счет. Доходит примерно до 5000 единиц. Примерно, может до 10000 дойдет. И интересно, что есть пропуски, дыры… Например счетчик пишет 1…2…3…4…5…7…12…13…16…25…26. Наверное скорости не хватает. В общем так.

Почему все это спрашиваю, на практике одно и тоже задание происходит с разной повторяемостью. Где ошибка или лаг или сбой тестирую…Грешил на сервопривод, на который идут импульсы сначала… А потом увидел, что в счетчике есть пробелы. Вот и озадачился “правильной” математикой.

Таблица дуевская ? Неплохо…

Ну то есть величина порядка единицы.
Я бы взял Factor_2 = 65536, а _1_stepper_Factor = 65536/stepper_Factor.

А типы какие, извините…новичок

Цитирую свой 2-й пост:

Я так и думал, уточнил. Спасибо ! :slightly_smiling_face:

Тут пытался немного “ускориться” на запись-считывание цифровых входов-выходов. Набрел на библиотеку : Arduino-GPIO

Библиотека Arduino GPIO была разработана для обеспечения высокопроизводительного доступа к цифровым контактам. Большинство функций доступа компилируются в одну инструкцию и выполняются за 1-2 такта. Функции библиотеки более чем в 10 раз быстрее, чем функции цифровых выводов Arduino. В некоторых случаях до 100 раз быстрее.

Дополнительные классы поддержки доступны для цифровых и аналоговых выводов с подавлением отклика, ввода/вывода сдвигового регистра и последовательного программного обеспечения. Они также демонстрируют, как можно использовать класс шаблона GPIO для создания дополнительных библиотек.

Эта библиотека поддерживает платы на базе ATtinyX4, ATtinyX5, ATmega168, ATmega328P, ATmega32U4, ATmega1280, ATmega2560 и SAM3X8E.

GitHub

Все замечательно, по описанию просто супер. Но к сожаление почему-то на некоторых выводах работает , а не некоторых выводах нет. А так задумка хорошая конечно…Может кому интересно

У Due 32-разрядные порты, причем не полные. Кроме того, в Due они не все выведены на гребенку. В общем, геморрой тот еще. Так что могут быть просто ошибки (описки) в библиотеке.
С SAM3 я подробно не разбирался. Разбирался с STM32, там можно установить/сбросить/прочитать один бит несколькими разными способами, - именно для того, чтобы подобрать оптимальный для конкретного случая. Новичков это вгоняет с ступор - зачем можно сделать еще как-то, если работает одним конкретным способом. Так вот именно для оптимизации под конкретные потребности.
Так что, если нужно работать с пинами напрямую, лучше всего почитать дэйташит на GPIO.

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

Энкодер это кодировщик. В мышке компьютерной то же энкодер. Поскольку есть преобразование угла поворота в сигнал,цифровой или аналоговый.

В струйных принтерах два вида энкодеров. Ленточные и круглые. Оба вида расчитаны на работу с оптопарой. Ленточный энкодер отвечает за правильное положение печатной головы по горизонтали, ширине.

Круглый -вращающийся энкодер отвечает за правильное позиционирование материала относительно движения вперед-назад вала принтера.

На обоих видах энкодеров нанесены линиии, которые чередуются с пробелами. При перемещении происходит импульсное считывание количества поступивших сигналов и далее последующая обработка.
У меня обычный Epson, не думаю, что только такой алгоритм только у Epson (энкодерное позиционирование). Общался с сервисниками, у Mimaki тоже самое. Canon тоже…

А это небольшой ликбез:
Энкодерная лента и энкодерный диск в струйных принтерах

Штрих лента не может по определению ничего кодировать. Это датчик и не более. Тем более без контроллера, она не определяет положения головки или бумаги. Автор приведённой статьи тупо подменяет понятия, и сам не понимает о чем говорит.
ТС почитайте, какие функции может выполнять энкодер, и вы поймёте, что используете не правильную библиотеку. В вашем случае вообще не нужна библиотека.

Пока что Вы только болтаете. “Энкодерная лента”, русский же вроде язык.
Я знаю, что есть примеры без библиотек. Мне важно правильное слежение. С библиотекой или без не имеет значения. Я видел dimax на старом форуме приводил пример очень хорошей реализации обработки энкодера с прерываниями и работой напрямую с пинами. Но там уровень, до которого я еще не дорос)

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

Дополнение. Хотя ответ по длительности выполнения команд, вы уже получили. Возможно вопрос уже закрыт.

Вы жалуетесь на плохую повторяемость. Попробуйте вообще обойтись в тестовом варианте без перевода в единицы с плавающей запятой. Ну рассчитайте показания на несколько значений вручную и давайте принтеру задание на перемещение на фиксированное значение, считывайте результат подсчитанный в целых числах вашей программой. Если в целых числах повторяемость будет, то тогда действительно проблемы с операциями с плавающей запятой. А если и с целыми не будет повторяемости, то это проблемы с считыванием с энкодера. Или вы уже так делали? и каков результат?
PS Мне как-то не понятно про повторяемость. Дело в том,что ошибки при переходе к float будут всегда , но они носят стабильный характер. грубо говоря 2314(с энкодера)*0,32(коэффициент) =740,48( ну или что то около) будет всегда именно столько и повторяемость для данных показаний энкодера будет 100%, сколько бы раз вы не повторяли.

Вы уверены что проблемы именно в недостаточной скорости умножения на коэффициент?

Очень был удивлен, что от измнения в скетче, даже в той части, где он НЕ должен в момент движения принтера работать(просто вычисления которые проходят до печати) очень меняется скорость. Мистика какая-то. Одну строчку добавить к примеру и весь алгоритм работает с другой скоростью. По сигналам нужен осциллограф, его нет. Смотрю сигналы в программе серводвигателя.

Повторяемость.
Это принтер переделка. Подключение к энкодеру и на свой контроллер. Принтер двигает энкодер, мы двигаем стол с помощью серводвигателя. Т.е принтер двигая энкодер двигает стол. Так делаются принтеры так называемые DTG (прямой печати )
Поскольку у вала энкодера (на чем установлен диск) своя арифметика мы должны к ней жестко привязаться. Пример 10мм движения вала энкодерного диска == 10мм движения стола. Пересчет идет через коэффициент.
Соответственно формула :
Движение стола == движение энкодерного вала * коэффициэнт;
Все просто. Другие я видел берут float и умножают на него. Но у меня было различие при печати одного и того-же принта и я подумал, что дело в том, что float вносит смещение,так как у float есть пропуски в его ряду. Перевел все к long. появилось деление.
Потом вычитал, что умножение делается быстрее , чем деление. Вот и спросил, что лучше. Либо работать с float (умножение)б либо делить и работать с long.

Повторяемость… Берем один и тот-же рисунок. Запускаем на печать. Скажем текст. Отпечатали все хорошо. Снова этот же файл отправляем на печать с теми-же самыми настройками. Вначале все отлично, а потом начинается сдвиг, двоение. Немного, но оно есть. Я думаю это от того, что энкодер совершает резкие рывки и счетчик энкодера получается разный. Если счетчик разный, то и число импульсов, что мы передаем будет отличаться при первой и второй печати. Вроде бы все логично. НО… я видел у других движения одно в одно. Профессиональные принтеры печатают по одному и тому же месту одинаково. Да и самодельщики тоже смогли делать. Два - три раза и повторямость хорошая. Нет смещения.
Стабильно. Надеюсь поняли меня.

Можно как Вы предложили попробовать вариант с целыми числами, надо тестить.
Сейчас я вернул все к long вычислениям, более менее нормально. Почти шаг в шаг. Пока остановлюсь на этом. И параллельно буду изучать как другие обрабатывают энкодер. Снимают сигналы, и конвертируют в свою величину.

За ответ еще раз благодарю!!!

Чаще всего это происходит из за пропуска шагов шаговым движков при не правильных настройках.

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

Этот вопрос решают установкой “тихих” драйверов, типа TMC2209.