В уроке рассказываю о моей библиотеке StepMotor, предназначенной для управления униполярными и биполярными шаговыми двигателями.
Предыдущий урок Список уроков Следующий урок
Предыдущий урок был посвящен подключению униполярных шаговых двигателей к плате Ардуино и стандартной библиотеке Stepper.
На мой взгляд, библиотека Stepper может быть использована только для демонстрации и проверки работы двигателей. В практических приложениях применение этой библиотеки крайне ограничено из-за ряда недостатков:
- при управлении двигателем функции Stepper подвешивают программу, забирают все вычислительные ресурсы микроконтроллера;
- в один момент времени может работать только один двигатель;
- не поддерживаются все основные режимы коммутации обмоток;
- ограничены функциональные возможности.
Я написал свою библиотеку StepMotor, которая работает в параллельном процессе, может управлять одновременно несколькими шаговыми двигателями, поддерживает все возможные режимы. По сути это аналог моей библиотеки для системы управления шаговыми двигателями фасовочного оборудования.
StepMotor - библиотека управления шаговыми двигателями в системе Ардуино.
От стандартной библиотеки Stepper мою библиотеку отличает:
- работает в параллельном процессе, не блокирует выполнение программы;
- может управлять одновременно несколькими двигателями;
- поддерживает шаговый, полу шаговый и между шаговый режимы;
- при остановке двигателя поддерживает режимы: полное выключение фаз и с током удержания для фиксации положения ротора;
- использует минимум ресурсов производительности микроконтроллера;
- занимает мало программной и оперативной памяти.
Загрузить библиотеку StepMotor.h можно по этой ссылке:
Как установить написано в нескольких предыдущих уроках, например, в уроке 9.
Описание класса StepMotor.
Я привожу только public методы.
class StepMotor {
public:
StepMotor(byte pinA, byte pinB, byte pinC, byte pinD); // конструктор
void control(); // управление, метод должен вызываться регулярно с максимальной частотой коммутации фаз
void step(int steps); // инициирует поворот двигателя на заданное число шагов
void setMode(byte stepMode, boolean fixStop); // задает режимы коммутации фаз и остановки
void setDivider(int divider); // установка делителя частоты для коммутации фаз
int readSteps(); // чтение оставшихся шагов
}
Описание методов класса StepMotor.
void control()
Метод должен вызываться регулярно в параллельном процессе. Частота вызова метода определяет частоту коммутации фаз двигателя. Делитель частоты, устанавливаемый функцией setDivider, делит именно частоту вызова control().
// обработчик прерывания
void timerInterrupt() {
myMotor.control(); // управление двигателем
}
void step(int steps)
Инициирует поворот двигателя на заданное число шагов. При работе двигателя в полу шаговом режиме имеется в виду не физические шаги двигателя, а полушаги. Аргумент с положительным значением вызывает вращение против часовой стрелки, отрицательный аргумент приводит к вращению двигателя по часовой стрелке.
Запустив вращение двигателя функцией step(), например
myMotor.step(400); // сделать 400 шагов против часовой стрелки
программа может заниматься другими задачами. Двигатель остановится сам. При необходимости в любой момент можно остановить двигатель командой
myMotor.step(0); // остановить двигатель
Можно задать новое число шагов, не дожидаясь остановки двигателя. Например, для непрерывного вращения следует периодически посылать команду с большим числом шагов
myMotor.step(32000); // постоянное вращение
О том, что двигатель остановился, программа может узнать с помощью функции readSteps().
void setMode(byte stepMode, boolean fixStop)
Метод задает режим коммутации фаз двигателя и состояние остановленного двигателя.
stepMode – режим управления двигателем.
Значение stepMode | Режим |
0 | Шаговый |
1 | Полу шаговый |
2 | Между шаговый |
О режимах коммутации обмоток шаговых двигателей можно посмотреть по этой ссылке.
fixStop – определяет режим остановленного двигателя.
Значение fixStop | Состояние двигателя в остановленном состоянии |
false | С обмоток снимается напряжение, двигатель разблокирован |
true | Через обмотки продолжает течь ток удержания, ротор находится в фиксированном положении |
myMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor.setMode(1, true); // полу шаговый режим, с фиксацией ротора при остановке
void setDivider(int divider)
Метод задает коэффициент деления частоты вызова функции control(), а значит, определяет скорость вращения двигателя. Для расчетов можно использовать следующую формулу:
Rpm = 60 000 / ( divider * Tcontrol * Nдвигателя )
- Rpm – скорость вращения в оборотах в минуту;
- Tcontrol – период вызова метода control() в мс;
- Nдвигателя – число шагов двигателя на полный оборот.
Для полу шагового режима формула несколько меняется.
Rpm = 30 000 / ( divider * Tcontrol * Nдвигателя ).
Например,
myMotor.setDivider(21); // делитель частоты 21 (при прерывании 1 мс период коммутации фаз 21 мс)
означает, что фазы будут коммутироваться через каждые 21 мс. Это соответствует скорости вращения:
Rpm = 60 000 / ( 21 * 1 * 48 ) = 59,5 об./мин или примерно один оборот в сек.
int readSteps()
Метод позволяет узнать количество шагов, оставшихся до остановки двигателя. Если он возвращает 0, то это означает, что двигатель остановился.
if (myMotor.readSteps() == 0) {
// двигатель остановился
}
Примеры использования библиотеки StepMotor.
Библиотеку необходимо загрузить и установить (можно посмотреть в уроке 9).
Для проверки примеров я использовал драйвер и двигатель PM35S-048 из предыдущего урока. У двигателя 48 шагов на оборот.
В следующем уроке подключу через этот же драйвер более мощный двигатель.
Вот пример скетча программы, которая постоянно вращает двигатель.
// программа управления шаговым двигателем с помощью библиотеки StepMotor
// двигатель вращается постоянно против часовой стрелке со скоростью 60 об. в мин
#include <MsTimer2.h>
#include <StepMotor.h>
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
void setup() {
MsTimer2::set(1, timerInterrupt); // задаем период прерывания по таймеру 1 мс
MsTimer2::start(); // разрешаем прерывание по таймеру
myMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(21); // делитель частоты 21 (при прерывании 1 мс период коммутации фаз 21 мс)
}
void loop() {
myMotor.step(1000);
}
//-------------------------------------- обработчик прерывания 1 мс
void timerInterrupt() {
myMotor.control(); // управвление двигателем
}
В цикле loop() надо периодически вызывать метод step() не позволяя, двигателю остановиться. Если число шагов в аргументе функции step() задавать большим, например, 30000, то вызывать метод достаточно раз в несколько секунд. Все остальное время можно использовать для других задач.
Вот скетч аналога программы из предыдущего урока. Двигатель делает 5 оборотов против часовой стрелки, затем пауза 1 сек. Еще 5 оборотов по часовой стрелки, пауза 1 сек и так в бесконечном цикле.
// программа управления шаговым двигателем с помощью библиотеки StepMotor
// двигатель вращается против часовой срелки 5 оборотов, пауза 1 сек,
// 5 оборотов по часовой стрелке, пауза 1 сек, и так в бесконечном цикле
#include <MsTimer2.h>
#include <StepMotor.h>
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
unsigned int timeCounter; // счетчик времени
byte md; // режим: 0 - вращение против ч.с., 1 - пауза, 2 - вращение против ч.с., 3 - пауза
void setup() {
MsTimer2::set(1, timerInterrupt); // задаем период прерывания по таймеру 1 мс
MsTimer2::start(); // разрешаем прерывание по таймеру
myMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(21); // делитель частоты 21 (при прерывании 1 мс период коммутации фаз 21 мс)
md= 0; // начальный режим
myMotor.step(240); // начальный запуск
}
void loop() {
// управление вращением двигателя
if (md == 0) {
// пять оборотов против часовой стрелки
if (myMotor.readSteps() == 0) { md=1; timeCounter=0; }
}
else if (md == 1) {
// пауза 1 сек
if (timeCounter >= 1000) { md=2; myMotor.step(-240); }
}
else if (md == 2) {
// пять оборотов по часовой стрелке
if (myMotor.readSteps() == 0) { md=3; timeCounter=0; }
}
else {
// пауза 1 сек
if (timeCounter >= 1000) { md=0; myMotor.step(240); }
}
}
//-------------------------------------- обработчик прерывания 1 мс
void timerInterrupt() {
myMotor.control(); // управление двигателем
timeCounter++; // счетчик времени
}
Программный блок управления двигателем размещен в цикле loop(), но он не подвешивает программу и занимает минимум времени. Все остальное время можно использовать для других задач. В принципе этот блок можно разместить в обработчике прерывания.
Библиотека StepMotor отсчитывает время переключения фаз от периода вызова функции control(). Функция control() обычно вызывается прерыванием от таймера. Период прерывания определяет скорость вращения двигателя по формуле, описанной выше:
Rpm = 60 000 / ( divider * Tcontrol * Nдвигателя ).
Видно, что зависимость скорости вращения от периода вызова метода control() нелинейная, с гиперболической зависимостью. Например, для двигателя из предыдущего урока (48 шагов на оборот) и периода вызова метода control() 1 мс получим следующие значения скоростей.
divider | Скорость вращения, об. / мин |
1 | 1250 |
2 | 625 |
3 | 417 |
4 | 312 |
5 | 250 |
6 | 208 |
7 | 179 |
8 | 156 |
. . . | . . . |
При малых значениях делителя divider скорость вращения задается со значительным шагом. При увеличении коэффициента divider шаг уменьшается. Т.е. если необходима плавная регулировка скорости, следует уменьшить период вызова control() и увеличить значение делителя. А библиотека MsTimer2 позволяет формировать прерывание с минимальным периодом 1 мс. Для прерываний с меньшим периодом существует другая библиотека управления таймером.
Библиотека TimerOne.
Библиотека использует таймер 1 контроллера Ардуино и позволяет формировать прерывания с периодом от 1 мкс до 8,4 сек. Дискретность установки времени - 1 мкс.
Кроме того она управляет режимами ШИМ на выводах микроконтроллера, но сейчас мы будем использовать TimerOne только для формирования временных интервалов.
Работать с библиотекой достаточно просто. Загрузить ее можно по этой ссылке TimerOne-r11.zip. Как установить, написано в уроке 9.
Методы TimerOne.
void initialize(long microseconds)
Метод инициализирует таймер. Должен быть вызван прежде использования любого другого метода.
Аргумент microseconds задает период таймера в мкс. По умолчанию задана 1 сек.
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
void setPeriod(long microseconds)
Метод устанавливает период таймера в диапазоне 1 мкс … 8,4 сек.
Timer1. setPeriod (250); // период 250 мкс
void start()
Метод запускает таймер с нового периода. Следует использовать, если таймер был остановлен.
void stop()
Метод останавливает таймер.
void restart()
Перезапускает таймер с нового периода.
void attachInterrupt(void (*isr)(), long microseconds)
Метод вызывает функцию с заданным периодом прерывания.
Timer1.attachInterrupt(timerInterrupt, 250); // задаем обработчик прерываний функции timerInterrupt
void detachInterrupt()
Метод запрещает прерывание.
Timer1. detachInterrupt(); // запретить прерывание от таймера 1
unsigned long read()
Метод позволяет считать текущее время таймера.
void pwm(char pin, int duty, long microseconds)
Генерирует сигнал ШИМ на выводе, заданном аргументом pin. На Ардуино могут использоваться выводы 9 и 10. Скважность задается аргументом duty в диапазоне 0 … 1023.
void setPwmDuty(char pin, int duty)
Задает значение ШИМ на выводе.
void disablePwm(char pin)
Выключает режим ШИМ для вывода.
С использованием библиотеки TimerOne программа постоянного вращения двигателя выглядит так.
// программа управления шаговым двигателем с помощью библиотеки StepMotor
// двигатель вращается постоянно против часовой стрелке со скоростью 60 об. в мин
#include <TimerOne.h>
#include <StepMotor.h>
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
void setup() {
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // задаем обработчик прерываний
myMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(83); // делитель частоты 83
}
void loop() {
myMotor.step(1000);
}
//-------------------------------------- обработчик прерывания 1 мс
void timerInterrupt() {
myMotor.control(); // управление двигателем
}
Время периода прерывания по таймеру нельзя задавать слишком маленьким, иначе программа будет заниматься только обработкой прерываний. Для Arduino UNO R3 в простых приложениях я бы ограничил его значением 100 мкс. При более сложных задачах лучше период таймера увеличить.
Если одновременно требуются прерывания с более низкой частотой, например, для регенерации светодиодных индикаторов, то его можно реализовать программными таймерами в обработчике прерывания. Надо стремиться, чтобы в системе было только одно прерывание от таймера с самой высокой частотой, а остальные формировались программными таймерами.
В нескольких последующих уроках будем использовать библиотеку StepMotor для управления как униполярными, так и биполярными шаговыми двигателями. В следующем уроке напишем программу для драйвера шагового двигателя на Ардуино и научимся управлять им от компьютера.
У Вас на сайте отличные статьи, материал исчерпывающий и доходчиво преподнесен!
Спасибо, приятно слышать.
Здравствуйте. Мне очень нужна помощь, у меня осталось всего три дня, помогите мне поставить паузу в алгоритм, который я скину. У меня не получается сделать паузу в шаговом двигателе при повороте.
#include // Подключаем библиотеку управления шаговым двигателем. По умолчанию настроена на двигатель 28BYJ-48-5V
CustomStepper stepper(8, 9, 10, 11); // Указываем пины, к которым подключен драйвер шагового двигателя
int example = 1; // Переменная для демонстрации работы, отвечающая за смену режимов
void setup()
{
stepper.setRPM(12); // Устанавливаем кол-во оборотов в минуту
stepper.setSPR(4075.7728395); // Устанавливаем кол-во шагов на полный оборот. Максимальное значение 4075.7728395
}
void loop()
{
if (stepper.isDone() and example == 1) // Когда предыдущая команда выполнена (см. ниже), метод stepper.isDone() возвращает true
{
stepper.setDirection(CW); // Устанавливает направление вращения. Может принимать 3 значения: CW — по часовой, CCW — против часовой, STOP
stepper.rotate(1); // Устанавливает вращение на заданное кол-во оборотов
example = 2;
}
if (stepper.isDone() and example == 2)
{
stepper.setDirection(CCW);
stepper.rotateDegrees(90); // Поворачивает вал на заданное кол-во градусов. Можно указывать десятичную точность (например 90.5), но не принимаются отрицательные значения
example = 3;
}
if (stepper.isDone() and example == 3)
{
stepper.setDirection(CW);
stepper.rotate(); // Будет вращать пока не получит команду о смене направления или пока не получит директиву STOP
}
stepper.run(); // Этот метод обязателен в блоке loop. Он инициирует работу двигателя, когда это необходимо
}
Там три действия. Вот мне необходимо, чтобы после поворота двигателя на 90 градусов он остановился на какое то время и потом продолжил крутиться на постоянной основе. Как прописать паузу? команда Delay не работает или я ее неправильно прописываю
Здравствуйте!
А как вы используете delay()? Попробуйте использовать эту функцию только после остановки двигателя в начале блоков if (в скобках {}) до вызова функций stepper.
Ха, я как раз после танцев с бубном с библиотекой CustomStepper нашел данный ресурс. Она не работает с прерываниями, в этом ее основная ущербность. Пришел к этому выводу самостоятельно после двух потерянных вечеров. Команда delay у вас не работает, потому что код до нее не доходит, система ждет остановки мотора, метод stepper.isDone() почему то возвращает значение false при добавлении любого исполняемого кода в скетч.
Здравствуйте, а этой библиотекой можно управлять например 4-мя шаговыми двигателями через отдельные драйвера посредством сигналов step и dir?
Здравствуйте. Этой библиотекой можно управлять несколькими двигателями, но с простыми драйверами-ключами. Для STEP/DIR драйверов есть другая библиотека уроки 34, 35. Ей также можно управлять несколькими двигателями.
Добрый день, уважаемый автор, Эдуард!
Добрый день, уважаемый коллеги!
Во-первых, хочу поздравить всех с праздником и пожелать успехов в творчестве, хорошего самочувствия, оптимизма и всего самого наилучшего! Пусть сбываются все Ваши мечты и планы. А теперь по теме данного урока №29. Спасибо автору Эдуарду за его старание, за его компетенцию и достаточно высокий уровень профессионализма. Но, к моему сожалению, не всё так сладко, Эдуард! Так, например, во-первых, Ваша основная программа, которой Вы посвятили урок №31 не проходит компиляцию. При выполнении компиляции Arduino IDE выдает целую серию ошибок. Отсюда вывод: программа сырая, не проверенная и не прошла отладку автором перед её демонстрацией. Это ни есть хорошо, уважаемый Эдуард! Во-вторых, после прохода по приведенной в уроке ссылке и скачивании основной Вашей программы русские буквы в комментариях — не читаются. Видимо, шрифт выбран какой-то специфический, который вместо руских букв прописывает какие-то иероглифы. В результате текст комментариев — не читаемый и автоматически превращается в муссор. Спасибо за понимание! Буду благодарен автору урока Эдуарду, если он услышит мои пожелания и внесет необходимые корректировки в текст программы и урока. Спасибо всем! С уважением, Валерий.
Валерий! Спасибо за добрые слова.
Что касается остального. Программы тщательно проверены, и не мной одним. Если выдает ошибки при компиляции, значит у вас в системе что-то не так. Может быть не установлена библиотека, может очень старая версия Arduino IDE, может файлы находятся в каталоге названным русскими буквами…
Иероглифы вместо русских вам показывает браузер. Можете установить другую кодировку и все будет русскими буквами. Но Вы же не в браузере собираитесь программировать. Загрузите файл в Arduino IDE и все будет нормально. Скетчи программ созданы в Arduino IDE и сохраняют исходную кодировку кириллических символов.
Ошибка компиляции. Нет библиотеки MsTimer2.h, где её взять?
Если не ошибаюсь, в уроке 10.
О, спасибо за такой быстрый ответ. Вот не могу понять, у меня гибридный двигатель 57HS7630A4 (nema 23), драйвер на микросхеме TB6600 и плата arduino Uno R3. Я использую интерфейсы контроллера DIR, Step и GND. Не подскажите, как мне программировать функцию StepMotor myMotor? Там же 4 переменных…
Не понял вопрос. STEP, DIR это сигналы? Какие 4 переменные? Что у вас за задача?
STEP, DIR — это входы на драйвере, которые соединяются с цифровыми выводами на arduino. У Вас функция StepMotor(byte pinA, byte pinB, byte pinC, byte pinD) задействует 4 пина на ардуино.
Анатолий. Посмотрите уроки 34 и 35. Урок 29 и библиотека StepMotor для простых драйверов-ключей. Для STEP/DIR драйверов есть другая библиотека.
Извиняюсь, это из стандартной библиотеки. Нашел. Я новичок и не знаю, что стандартно, а что нет. Не плохо было бы упомянуть об этом.
STEP — Вход драйвера для шаговых импульсов (рабочим является передний фронт, длительность > 10мкс)
DIR — Вход драйвера для управления направлением вращения вала шагового двигателя
Задача пока запустить гибридный шаговый двигатель.
Здравствуйте Эдуард.
для знакомства с библиотекой пробую использовать мотор 28BYJ-48-5V
команда MT.step(10) — работает. но почему то эти 10 шагов двигатель делает со скоростью примерно 3-4 шага в секунду… хотя судя по его характеристикам он должен делать 2048 шагов (оборот) — за 4 секунды.
не знаете, в чем причина такого его поведения?
Здравствуйте! Скорость вращения двигателя зависит от: времени периода прерывания, значения делителя, числа шагов двигателя на оборот, режима переключения фаз. Проверяйте все составляющие.
Извините, а здесь нет ошибки?
if ( _mode == 0 ) {
switch (_stepPhase) {
case 0:
digitalWrite(_pinA, HIGH);
digitalWrite(_pinB, LOW);
digitalWrite(_pinC, LOW);
digitalWrite(_pinD, LOW);
break;
case 1:
digitalWrite(_pinA, LOW);
digitalWrite(_pinB, HIGH);
digitalWrite(_pinC, LOW);
digitalWrite(_pinD, LOW);
break;
case 2:
digitalWrite(_pinA, LOW);
digitalWrite(_pinB, LOW);
digitalWrite(_pinC, HIGH);
digitalWrite(_pinD, LOW);
break;
case 3:
digitalWrite(_pinA, LOW);
digitalWrite(_pinB, LOW);
digitalWrite(_pinC, LOW);
digitalWrite(_pinD, HIGH);
break;
}
}
Просто биполярник у меня не заводится с таким кодом.
Завелся с таким:
if ( _mode == 0 ) {
switch (_stepPhase) {
case 0:
digitalWrite(_pinA, HIGH);
digitalWrite(_pinB, LOW);
digitalWrite(_pinC, HIGH);
digitalWrite(_pinD, LOW);
break;
case 1:
digitalWrite(_pinA, LOW);
digitalWrite(_pinB, HIGH);
digitalWrite(_pinC, HIGH);
digitalWrite(_pinD, LOW);
break;
case 2:
digitalWrite(_pinA, LOW);
digitalWrite(_pinB, HIGH);
digitalWrite(_pinC, LOW);
digitalWrite(_pinD, HIGH);
break;
case 3:
digitalWrite(_pinA, HIGH);
digitalWrite(_pinB, LOW);
digitalWrite(_pinC, LOW);
digitalWrite(_pinD, HIGH);
break;
}
}
в соответствии с: http://robocup.idi.ntnu.no/wiki/images/c/c6/PL15S020.pdf
Я проверил. Все скетчи из уроков работают. Может у вас схема драйвера другая? Или обмотки двигателя подключены по другому?
да вроде обычная схема подключения шагового биполярного двигателя от CD-Rom через L293D.
Я не знаю этого драйвера. Значит у него другая логика, чем у L298. На L298 все работает. Посмотрите урок 33. В нем я подключаю биполярный двигатель.
http://myrobot.ru/wiki/index.php?n=Projects.MyDRIVER
Брал схему подключения с этого сайта.
Посмотрите внимательно схему подключения в уроке 33. Входы драйвера IN1, IN2, IN3, IN4 подключены соответственно к выводам управления фазами A, C, B, D.
Здравствуйте! Проверьте меня. Все пересмотрел…
Вот схема как подключено:
https://cloud.mail.ru/public/5Z2t/hM9MeTETm
Результат:
https://cloud.mail.ru/public/KH2Y/E8rjBNaZL
КОД:
#include
…
StepMotor myMotor(8, 9, 12, 13); // создаем объект типа
….
void setup(){
…
MsTimer2::set(1, timerInterrupt); // задаем период прерывания по таймеру 1 мс
MsTimer2::start(); // разрешаем прерывание по таймеру
myMotor.setMode(0, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(50);
….
}
void loop(){
…
if (myMotor.readSteps() == 0)
{
myMotor.setDivider(52-abs(xPosition));
myMotor.step(-0.5*xPosition);
}
…
}
void timerInterrupt() {
myMotor.control(); // управление двигателем
timeCounter++; // счетчик времени
}
Здравствуйте!
Попробуйте сначала просто вращать двигатель. Потом движение до заданной точки без изменения скорости.
результат
https://cloud.mail.ru/public/LTqd/fzyLFMwHx
Эдуард, приветствую! Как правильно вставить в код строки, если нужна остановка двигателя по фотодатчику?
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
const int pinPhoto = 9; // Назначаем вывод 9 фотодатчику ID103
const int ENA = 8; // Input ENA,ENB драйвера L298N подключены к выводу 8 Ардуино
unsigned int timeCounter; // счетчик времени
byte md; // режим: 0 — вращение против ч.с., 1 — пауза, 2 — вращение по ч.с., 3 — пауза
void setup() {
pinMode(pinPhoto, INPUT); // Объявляем назначение PIN-ам
MsTimer2::set(1, timerInterrupt); // задаем период прерывания по таймеру 1 мс
MsTimer2::start(); // разрешаем прерывание по таймеру
myMotor.setMode(2, false); // между шаговый режим, без фиксации при остановке
myMotor.setDivider(21); // делитель частоты 21 (при прерывании 1 мс период коммутации фаз 21 мс)
md= 0; // начальный режим
myMotor.step(576); // начальный запуск
Здравствуйте!
Вы не написали какой активный уровень у датчика. Если 1, то
void loop() {
if( digitalRead(pinPhoto) == HIGH) myMotor.step(0);
else myMotor.step(100);
}
Двигатель вращается, если состояние вывода pinPhoto имеет низкий уровень и останавливается, если вывод находится в высоком уровне.
Добрый день, Эдуард! Да, я немного не правильно сформулировал вопрос. Задача простая: открывать и закрывать жалюзи по уровню освещенности ФД. Не суть важно, что на ФД, 0 или 1. Допустим, при «0» мотор крутится по часовой стрелке на 576 оборотов, при «1» — против.
Здравствуйте!
Надо выделить 2 события переход состояния датчика из 0 в 1 и из 1 в 0. И на эти события вызывать myMotor.step(576) и myMotor.step(-576). Если хотите, откройте тему на форуме сайта, я помогу с программой. В комментариях тяжело общаться на объемные темы.
Строку
const int ENA = 8; // Input ENA,ENB драйвера L298N подключены к выводу 8 Ардуино
можно закомментировать, она в этом случае не нужна
В каком разделе создать тему?
Мне кажется лучше в разделе шаговые двигатели.
Ок!
MsTimer2.h не работает с nodemcu?
Существует проблема с подключением шагового двигателя
VID60 является усовершенствованной версией на основе VID69 двигателя часов. Имеется оптико-механическая система обнаружения физического расположения стрелок часов. Алгоритм для синхронизации времени аналоговый дисплей в режиме реального времени.
Нулевая функция обнаружения (построен в OSRAM LPT80A ИК-приемника)
Широкий диапазон рабочих напряжений: 5 ~ 10В.
Низкое потребление тока: 18mA, 5V, 2X90mW
Пиковый ток 18 мА при 5 В
С непосредственным приводом от μ-контроллера.
Большой статическое усилие.
Пригодны для применения в автомобильной промышленности.
Рабочий диапазон температур -40 ° С ~ 105oC
Вариант с установкой на плату:
VID60-02 (усиленная шахта, вал высотой 12,1мм)
из описания есть понимание, что опто-датчик на стрелку не завязан. Так ли это. И есть ли схема подключения шагового двигателя с оптодатчиком? Спасибо
спасибо за крутые статьи!!
Спасибо за отзыв.
Добрый день! у меня движок FL57STH76-2804A драйвер l298n
Не получается запустить чтоб просто вращался.
Какой должен быть параметр setDivider. пробовал разные не крутит. только дребезжит или свистит.
Здравствуйте!
Программа из урока должна работать. Там myMotor.setDivider(21).
Скорее всего, вы фазы попутали, или какая-то из фаз не работает.
С ардуиновской библиотекой он работает. Но по одному движку. Двигатели новые и драйвера тоже. Фазы перепроверил. Но реакция та же
Обратите внимание, что в моей библиотеке фазы по-другому подключаются.
А где это можно увидеть
Сравните в уроке 28
Stepper motor(48, 10, 12, 11, 13); // объект motor, 48 шагов на оборот
и уроке 29
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
Спасибо завтра буду пробовать
Все заработала. Но есть одна проблемка.
У меня работаю два двигателя. один вращается без остановки и с ним все хорошо. А второй делает N шагов потом меняет направления и Опять N шагов. И так 10 раз. и где- то на 5 раз он начинает делать остановки секунду -две и дальше идет. С чем это связанно.?
Вот код while (start) {
if (10> I) {
if (md == 0) {
if (myMotor1.readSteps() == 0) { md=1; myMotor1.step((N*200/5)); I= I + 1;}
}
else if (md == 1) {
if (myMotor1.readSteps() == 0) { md=0; myMotor1.step(-(N*200/5)); I= I + 1;}
}
}
else {
if (myMotor1.readSteps() == 0) {
start = false;
myMotor1.step(0);
myMotor2.step(0);
}
}
I становится больше 10 и все прекращается. Выведите I в последовательный порт и посмотрите, что делается.
Вы меня видимо не правильно поняли. он должен 10 раз проработать туда сюда. но на 2-3 ходке. двигатель останавливается на 2 секунды и дальше идет и опять остановка она не связана с переменой I что-то другое
вот код
#include
#include
StepMotor myMotor(10, 11, 12, 13); // создаем объект типа StepMotor, задаем выводы для фаз
void setup() {
Timer1.initialize(25); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 25); // задаем обработчик прерываний
myMotor.setMode(1, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(21); // делитель частоты 83
myMotor.step(200);
}
void loop() {
}
//————————————— обработчик прерывания 1 мс
void timerInterrupt() {
myMotor.control(); // управление двигателем
}
А в место таймера можно будет использовать датчик приближении
Здравствуйте!
Не понял вопроса.
Эдуард, подскажите а сервопривод типа SG90 — это один из вариантов шагового двигателя или это отделений девайс? И можно ли им управлять при помощи тех же библиотек что и для шагового двигателя? Нет ли у вас урока про сервоприводы?
Здравствуйте!
Это не шаговый двигатель. Это коллекторный двигатель с датчиком угла и схемой управления. Устройству задается угол положения ротора, а он его отрабатывает.
Спасибо за библиотеку.
Поигрался — работает отлично.
Возможность одновременной работы с несколькими моторами плюсик.
К сожалению, не получается плавной регулировки скорости с помощью потенциометра — рывки, дёрганья.
Делитель частоты меняю от 5 до 100.
Что то подсказать можете или проблема не решаема.
Здравствуйте!
Способ один — уменьшение периода прерывания. Почитайте в уроке о скорости вращения. Там эта проблема затронута.
День добрый , подскажите , а как мне сделать так что бы количество шагов менять например не в программе а в отладочном режиме с экрана ?
Здравствуйте!
В уроке 31 есть такая программа.
Добрый день. Подскажите я правильно понимаю, для регулировки скорости потенциометром, myMotor.setDivider(21); выносим из setup в loop и подставляем значения с потенциометра.
Здравствуйте, Эдуард.
Мне надо управлять, как минимум, пятью nema32 и силовым реле, значит контроллер KFB-3.0 мне не подойдет или два понадобится? И если да, то как их синхронизировать?
Здравствуйте,Эдуард. Подскажите что эти строки делают и зачем они нужны? void timerInterrupt() {
myMotor.control(); // управвление двигателем
Здравствуйте!
В этом месте происходит управление двигателем. С периодом, заданным временем таймера, вызывается функция control. В ней отсчитывается нужное время и переключаются фазы двигателя. Это происходит параллельной задачей. Другие функции задают режимы, запускают шаги двигателя…
Эдуард, добрый день! Ругается на
Timer1.attachInterrupt(timerInterrupt, 250); // задаем обработчик прерываний
Что не так?
Это полное описание ошибки.
C:\Step_davy\Step_davy.ino: In function ‘void setup()’:
Step_davy:21:26: error: ‘timerInterrupt’ was not declared in this scope
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
^
exit status 1
‘timerInterrupt’ was not declared in this scope
Здравствуйте!
Вы скетч из урока взяли, без изменений?
Здравствуйте!
Я написал скетч по вашему принципу, и мне он выдает ошибку. В этом предложении.
Timer1.attachInterrupt(timerInterrupt, 250);
Этот код, который сделал я на 4 мотора.
#include
#include
//StepDirDriver myMotor1 (10, 11, 12);
StepDirDriver myMotor2 (A0, A1, 38);
StepDirDriver myMotor3 (A6, A7, A2);
StepDirDriver myMotor4 (26, 28, 24);
StepDirDriver myMotor5 (36, 34, 30);
unsigned int timeCounter;
byte md;
void setup() {
Timer1.initialize(250);
Timer1.attachInterrupt(timerInterrupt, 250);
myMotor1.setMode(0, false);
myMotor1.setDivider(5);
myMotor2.setMode(0, false);
myMotor2.setDivider(5);
myMotor3.setMode(0, false);
myMotor3.setDivider(5);
myMotor4.setMode(0, false);
myMotor4.setDivider(5);
md= 0;
myMotor1.step(0);
myMotor2.step(0);
myMotor3.step(0);
myMotor4.step(0);
}
void loop() {
if (md == 0) {
if (myMotor1.readSteps() == 0)
{ md=1; timeCounter=0; }
}
else if (md == 1) {
if (timeCounter >= 1000) {
md=2;
myMotor1.step(800);
myMotor2.step(800);
myMotor3.step(800);
myMotor4.step(800); }
}
else if (md == 2) {
if (myMotor1.readSteps() == 0) {
md=3; timeCounter=0; }
}
else if {
if (timeCounter >= 1000) {
md=3;
myMotor1.step(-800);
myMotor2.step(-800);
myMotor3.step(-800);
myMotor4.step(-800); }
else if (md == 3) {
if (myMotor1.readSteps() == 0) {
md=4; timeCounter=0; }
}
else if {
if (timeCounter >= 1000) {
md=4;
myMotor1.step(-800);
myMotor2.step(800);
myMotor3.step(800);
myMotor4.step(-800); }
}
else if (md == 4) {
if (myMotor1.readSteps() == 0) {
md=4; timeCounter=0; }
}
else if {
if (timeCounter >= 1000) {
md=4;
myMotor1.step(800);
myMotor2.step(-800);
myMotor3.step(-800);
myMotor4.step(800); }
}
}
void timerInterrupt() {
myMotor1.control();
myMotor2.control();
myMotor3.control();
myMotor4.control();
timeCounter++; //
}
Здравствуйте!
У вас непонятная конструкция
else if {
if (timeCounter >= 1000) {.
а можно зделат так чтобы по нажатии кнопки двигател делал один шаг нажатием ешо раз ешо один шаг а нажтием другой кнопки работал реверс по 1 шагам
void loop() {
if (digitalRead(KN1) == 0) // нажатие кнопки 1
{
motor.step(1); // вперед
}
else
{
motor.step(0); // стоп
}
if (digitalRead(KN2) == 0) // нажатие кнопки 2
{
motor.step(-1); // реверс
}
else
{
motor.step(0); // стоп
}
Приветствую. А можно ли наоборот сделать — скетч будет следить за состоянием шагового двигателя и в случае поворота/шага вперёд и назад будет считать и увеличивать показания на дисплее/индикаторе?
Заранее спасибо и всем Бобра!
Здравствуйте!
Шаговый двигатель вместо датчика положения использовать? Для этого есть инкрементальные энкодеры.
Здравствуйте! Как всегда, толково и по делу! Только мне не дает покоя один вопрос. Когда-то в 86-ом году наше КБ очень плотно работало с шаговыми двигателями. Использовали типовые платы минского КБТМ. Плату нужно было настроить под конкретный привод. Очень много внимания уделялось Разгону — Торможению. Без правильной настройки этого параметра двигатель или визжал на месте и не мог двинуться, или терял шаги, или работал на очень малой скорости. Настройку производили, в основном, по звуку. Правильно настроенный привод издавал тихий приятный звук без визжания. Почему то в Ваших статьях этот вопрос опускается.
Еще вспомнил. Пробовали для оптимизации разгона ставить своеобразный оптический датчик угла поворота. Разгон получался довольно вялым, но двигатель работал мягко и выходил на большие скорости. Но этот датчик искажал моментно массовые характеристики привода, и когда датчик снимали после проведения настройки, то привод начинал явно грустить. Т.е. эта идей не проканала… Оставить датчик на серийной установке не было возможности.
https://kolotushkin.com/article.php?id=44
Долго ковырял инет по вопросу разгона-торможения, много чего наковырял, но особо впечатлила статейка: «Плавный пуск и остановка биполярного шагового двигателя. Спец драйвер на Digispark Attiny85».
https://kolotushkin.com/article.php?id=44
Идея, как по мне крайне интересная… Digispark Attiny85 вешается на I2C и полностью управляет шаговиком учетом с разгона-торможения. Ресурсы основного проца при этом остаются свободными!!!