Closed sadr0b0t closed 7 years ago
Предыдущий тикет в тему Разобраться с размерами целочисленных типов на разных архитектурах для step_delay https://github.com/1i7/stepper_h/issues/13
По производительности, на ChipKIT по сравнению с предыдущими замерами https://github.com/1i7/stepper_h/issues/17 ничего не поменялось:
Если здесь ничего заметно не ухудшилось, на остальные места тем более пох.
Здесь есть патч Serial.print() of a 64-bit DOUBLE http://forum.arduino.cc/index.php?topic=143584.0 но в главную ветку, похоже, не отправлен (тред 13го года)
тикет висит с 13го года https://github.com/arduino/Arduino/issues/1236
еще оттуда бонусом оффтопом - быстрый sprintf (itoa_ для всех целых, в том числе 64хбитных) https://github.com/JensGrabner/snc98_Slash-Number-Calculator/tree/master/Software/Arduino/libraries/itoa_ljust
Есть 64 бит рабочая область https://github.com/1i7/stepper_h/commit/9d516f955be47e5a8a3b07f144fac7dfb4721dc7
Тип данных curren_pos, min_pos и max_pos - long long (int64_t), 64-битное знаковое целое.
Для 64-битного значения current_pos размеры рабочей области с базовой единицей нанометры:
2^63=9223372036854776000 нанометров /1000/1000/1000 = 9223372037 метров /1000 = 9223372км (9 миллионов км).
в обе стороны от -9млн км до 9млн км, всего 18млн км (1/3 пути до Марса)
64-битные типы данных не поддерживаются аппаратно на 32-битных (тем более, на 16-битных) контроллерах, но они реализованы на уровне компилятора и библиотеки libc (как минимум, для платформ ChipKIT и Arduino). Они могу работать чуть медленнее, чем "родные" (на 32-битных контроллерах) 32-битные переменные long, но потеря производительности по факту оказывается не существенной даже в критических частях кода (сравнение с точностью до микросекунд не показало разницы).
При этом использование 64-битных значений фактически позволяет не задумываться о максимальных границах рабочей области.
Для 32хбитного значения current_pos размеры рабочей области были бы:
Если брать базовую единицу измерения за нанометры (1/1000 микрометра), то диапазон значений для рабочей области будет от нуля в одну сторону: 2^31=2147483648-1 нанометров/1000/1000/1000=2.15метра в обе строны: [-2.15м, 2.15м], т.е. всего 4.3 метра.
Для базовой единицы микрометр (микрон) рабочая область от -2.15км до 2.15км, всего 4.3км.
Для 32-битного случая вариант рабочей области 4.3 метра (2.15, если считать от 0) с нанометрами для многих случаев в принципе приемлем, но почти не оставляет запаса для экспериментов.
Вариант размера рабочей области с базовой идиницей микрометры более, чем достаточен, но размер шага для настольных станков (хотя они на уровне механики могут не поддерживать такую точность) математически часто предполагает доли микрон (6.15мкм, 7.5мкм и т.п.), поэтому в качестве целевой единицы измерения рекомендуется ориентироваться на целочисленные нанометры.
По размерам и выходу за границы теперь можно вообще не париться. Еще для полной красоты, нужно посчитать варианты для переменных step_count в вызовах prepare_steps и внутренних счетчиках stepper_timer (стоит ли их для единообразия тоже привести в long long или и так пойдет с запасом).
По проблеме с Serial.println(long long, DEC): закинул патченую версию Print.h/Print.cpp в репозиторий до лучших времен (появятся в апстриме - удалю) https://github.com/1i7/stepper_h/tree/master/3pty/arduino
For Serial.println(int64_t, DEC) copy patched Print.cpp and Print.h to:
for Arduino platform ~/.arduino15/packages/arduino/hardware/avr/1.6.19/cores/arduino/ for ChipKIT platform ~/.arduino15/packages/chipKIT/hardware/pic32/1.4.3/cores/pic32/
This is required to compile example sketch:
Serial.print(sm_x.current_pos, DEC);
(sm_x.current_pos has int64_t/"long long" data type)
Or remove/replace this line in example sketch, patched Print is not required to compile stepper_h library core.
patched version of Print by Rob Tillaart https://github.com/RobTillaart
Code to print int64_t and uint64_t for UNO (and maybe DUE) http://forum.arduino.cc/index.php/topic,143584.0.html https://github.com/arduino/Arduino/issues/1236
По поводу step_count. Посчитаем.
Базовые эксперименты и вычисления задержек между шагами и по частоте таймера были здесь
Добавить вызов max_cycle_time https://github.com/1i7/stepper_h/issues/17
Там выяснили, что на фиолетовом драйвере с делителем шага 32 мотор будет стабильно работать при минимальной задержке между шагами step_delay=30 микросекунд (ок, самый минимальный вариант - 20мкс, но он уже не очень стабильный). На PIC32MX (ChipKIT Uno32) с библиотекой stepper_h с такой задержкой можно крутить одновременно 2 мотора.
для количества шагов step_count знаковое целое (long) можно на один цикл задать максимальное количество шагов:
2^31=2147483648
30мкс*2147483648шагов = 64424509440мкс/1000=64424509секунд/60=1073741824мин/60= 17895697часов/24=745654дней/365=2042лет
прошляпил миллисекунды
30мкс2147483648шагов = 64424509440мкс/1000000=64425секунд/60=1074мин/60= 18часов
https://duckduckgo.com/?q=2%5E3130%2F1000%2F1000%2F60%2F60&t=canonical&atb=v76-1&ia=calculator
пожалуй, хватит на цикл без int64_t
для step_delay=20 микросекунд (прям совсем максимальная скорость на китайском бросовом железе) 2^3120/1000/1000/60/60=12 часов https://duckduckgo.com/?q=2%5E3120%2F1000%2F1000%2F60%2F60&t=canonical&atb=v76-1&ia=calculator чуть поменьше, но, наверное, тоже достаточно
Если заменить long (32 бит) на int (16 бит на Ардуине): 2^15*20/1000= 655.36 миллисекунд.
вообще ни о чем, long без вариантов
Сюда же - минимальная задержка между шагами step_delay и расстояние за шаг distance_per_step.
/**
* Минимальная задержка между импульсами step, микросекунды
* (для движения с максимальной скоростью).
*
* для 32-битного знакового целого:
* макс задержка=2^31=2147483648 микросекунд=2147483 миллисекунд=2147 секунды=35 минут
* для 32-битного беззнакового целого:
* макс задержка=2^32=4294967296 микросекунд=4294967 миллисекунд=4294 секунды=71 минута=~1 час
*
* итого 32 бит: оба варианта - более, чем достаточно
*
* для 16-битного знакового целого:
* макс задержка=2^15=32768 микросекунд=33 миллисекунды - с натягом норм, но на грани (1/30 макс скрости)
* для 16-битного беззнакового целого:
* макс задержка=2^16=65536 микросекунд=65 миллисекунд - не сильно лучше
*
* итого 16 бит: задержки не подходят.
*
* В PIC32/ChipKIT int и long - 32 бит.
* В AVR/Arduino long - 32 бит, int - 16 бит.
*
* итого: нам нужны 32 бит, для всех платформ (PIC32/ChipKIT, AVR/Arduino) это long.
*/
unsigned long step_delay;
/**
* Расстояние, проходимое координатой за один шаг мотора,
* базовая единица измерения мотора.
*
* На основе значения distance_per_step счетчик шагов вычисляет
* текущее положение рабочей координаты current_pos.
*
* Единица измерения выбирается в зависимости от задачи и свойств
* передаточного механизма (рекомендуется считать за нанометры).
*
* для 32-битного беззнакового целого:
* макс расстояние/шаг = 2^32 = 4294967296 нанометров = 4294967 микрометров = 4294 миллиметров = 4 метра
*
* итого 32 бит: вполне достаточно
*
* для 16-битного беззнакового целого:
* макс расстояние/шаг = 2^16 = 65536 нанометров = 65 микрометра
*
* итого 16 бит: в ряде ситуаций приемлемо, но уже не достаточно:
* например, для шкива 3д-принтера на моторе без делителя 1 шаг может
* быть уже 200 микрометров, т.е. не вмещаться в 16 бит.
*
* В PIC32/ChipKIT int и long - 32 бит.
* В AVR/Arduino long - 32 бит, int - 16 бит.
*
* итого: нам нужны 32 бит, для всех платформ (PIC32/ChipKIT, AVR/Arduino) это long.
*/
unsigned long distance_per_step;
Короче, логично ввести такое правило:
Во-первых, для большинства рассмотренных ситуаций 16-битных значений действительно мало. Во-вторых, использование long даёт единообразие на всех платформах.
Сейчас поля stepper current_pos, min_pos и max_pos имеют тип данных long - это знаковое 32битное целое (и на Arduino с AVR и на ChipKIT с PIC32).
Если за базовую единицу измерения брать нанометры (для для целого значение current_pos подругому не получится - например, для шкива GT2 один шаг, поделенный на 32, будет 6.25микрометра=6250нанометров), максимальный полный размер рабочей области будет 4.3метра (если начальная позиция 0, то 2.15м). Для настольного станка хватает, но как-то без запаса.
Внезапно оказалось, что даже на ардуине (на чипките тем более) есть 64хбитный целочислинный тип данных "long long" (если не ошибаюсь, поддерживается софтово на уровне libc и компилятора).
Можно просто заменить тип данных у current_pos, min_pos и max_pos с long на long long и получить размер рабочей области от нуля в один конец: 2^63=9223372036854776000нанометров /1000/1000/1000=9223372037метров=9223372км (9млн км) полная рабочая область от -9млн до 9млн км = 18млн км (треть пути до Марса).
sprintf работает с long long через формат %lld
Serial.println(xxx, DEC) с long long из коробки не работает.
Здесь есть патч Serial.print() of a 64-bit DOUBLE http://forum.arduino.cc/index.php?topic=143584.0
но в главную ветку, похоже, не отправлен (тред 13го года)
итого
Плюсы:
Минусы: