Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Рабочие проекты Ардуино
АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 20 мар 2020, 18:31

Всем доброго дня! Возникла следующая задача. Нужно 2 стрелочных индикатора громкости, большого размера. Примерно 300мм в диаметре. Использовать стрелочный подвес от готовых индикатров не выйдет - стрелка будет большая, ее не раскачать рамкой даже большого вольтметра. Решено подвижную систему сделать на миниатюрных ШД X27 168 от приборной панели автомобиля, у них приличный момент, которого за глаза хватит для данной системы и высокая скорость работы.
Номер модели: X27 168
Угол Шага (градусы): 0.33 degrees
Поворот оси со встроенными ограничителями - 315 градусов, но у стрелки на валу рабочий ход будет 90 градусов.
Драйвера - а4988 с регулировкой выходного тока на минимуме, дабы не подпалить мотор.
Теперь нужно преобразовать сигнал аудио в аналоговый выход 0-5 в, и подружить его с ардуино нано.
Сигнал аудио усилен предусилителем на ne5532, затем фильтруется платой китайского стрелочного Vu метра на BA6138. На выходе платы стоит диод, резистор и конденсатор, как раз получается на выходе 0-5 вольт при подключении мобилы к предусилителю.
Чертеж1-Model.jpg

Алгоритм работы.
Рабочий ход стрелки - 90 градусов. При подаче питания, обе стрелки крутятся на 273 шага против часовой, упираются в механические ограничители. это положение далее будет 0 громкости входа. Далее стрелки работают, отклоняясь по часовой с увеличением громкости, против - с уменьшением.
Прошу помощи со скетчем.


Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 20 мар 2020, 19:48

Здравствуйте!
Для начала попробуйте второй проект этого урока http://mypractic.ru/urok-32-sledyashhij-elektroprivod-s-shagovym-dvigatelem.html

Видео: https://youtu.be/pg3lP__Uxh8

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

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 21 мар 2020, 11:36

Загружен скетч следующий

Код: Выделить всё

// программа следящего электропривода без обратной связи
 
#include <TimerOne.h>
#include <StepMotor.h>

#define MEASURE_PERIOD 80  // время периода измерения (* 250 мкс)
#define numStepsMotor 400  // число шагов двигателя на оборот

int timeCount;  // счетчик времени
long  sumU; // переменные для суммирования кодов АЦП
long  averageU; // сумма кодов АЦП (среднее значение * 80)
int currentStep;  // текущее положение двигателя
int setStep;  // заданное положение двигателя

StepMotor myMotor(9, 10, 11, 12);  // создаем объект типа StepMotor, задаем выводы для фаз

void setup() {
  Timer1.initialize(250);  // инициализация таймера 1, период 250 мкс
  Timer1.attachInterrupt(timerInterrupt, 250);  // обработчик прерываний
  myMotor.setMode(0, false);  // шаговый режим, без фиксации при остановке
  myMotor.setDivider(15);     // делитель частоты 15
}

void loop() {
  // проверка остановки двигателя
  if( myMotor.readSteps() == 0) {
    // двигатель остановился

    // вычисление заданного положения
    setStep = averageU * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

    // определение сколько шагов надо сделать
    int stepsToDo;  // сколько шагов надо сделать

    stepsToDo = currentStep - setStep; // ошибка рассогласования

    if( abs(stepsToDo) >= (numStepsMotor / 2) ) {

      if((stepsToDo) > 0) stepsToDo -= numStepsMotor;
      else                stepsToDo += numStepsMotor;     
    }
 
    myMotor.step(stepsToDo);  // запуск двигателя
    currentStep = setStep;  // перегрузка текущего положения   
  }
}

//-------------------------------------- обработчик прерывания 250 мкс
void  timerInterrupt() {
  myMotor.control(); // управвление двигателем

  sumU += analogRead(A0);  // суммирование кодов АЦП
  timeCount++;  // +1 счетчик выборок усреднения

  // проверка числа выборок усреднения
  if ( timeCount >= MEASURE_PERIOD ) {
    timeCount= 0;
    averageU= sumU; // перегрузка среднего значения
    sumU= 0;
    }
}


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

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 21 мар 2020, 12:50

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

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 21 мар 2020, 14:55

Здравствуйте!
А какая задержка? Откуда она берется? Я смотрю на собственном фильме и не вижу задержки.
Дрожание стрелки, скорее всего, происходит из-за дискретности шагового двигателя. Попробуйте первую программу из урока 32, в которой система управляется от компьютера. Там увидите чистое перемещение, оцените равномерность движения, подберете микрошаг.

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 22 мар 2020, 18:29

честно говоря я не вполне понял, откда была задержка, после пересобирания, все получилось отлично.
Настройка работы мотора получена опытным путем, менял переменные в скетче. Выяснилась особенность, что рабочая амплитуда стрелки при работе смещается по часовой. Но так как на краях амплитуды будут установлены ограничители механические, все хорошо, и не требуется обнуление в начале работы, хотя если получится его прописать, было бы здорово для красоты.
Конденсатор подобран так же опытным путем, емкость 100мкф. Диод 4007, резистор 10кОм.
Подскажитне пожалуйста, как прикрутить второй мотор к скетчу.

Код: Выделить всё

// программа следящего электропривода без обратной связи

#include <TimerOne.h>
#include <StepMotor.h>

#define MEASURE_PERIOD 80 // время периода измерения (* 250 мкс)
#define numStepsMotor 1600 // число шагов двигателя на оборот

int timeCount; // счетчик времени
long sumU; // переменные для суммирования кодов АЦП
long averageU; // сумма кодов АЦП (среднее значение * 80)
int currentStep; // текущее положение двигателя
int setStep; // заданное положение двигателя

StepMotor myMotor(9, 10, 11, 12); // создаем объект типа StepMotor, задаем выводы для фаз

void setup() {
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
myMotor.setMode(1, false); // шаговый режим, без фиксации при остановке
myMotor.setDivider(6); // делитель частоты 6
}

void loop() {
// проверка остановки двигателя
if( myMotor.readSteps() == 0) {
// двигатель остановился

// вычисление заданного положения
setStep = averageU * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

// определение сколько шагов надо сделать
int stepsToDo; // сколько шагов надо сделать

stepsToDo = currentStep - setStep; // ошибка рассогласования

if( abs(stepsToDo) >= (numStepsMotor / 2) ) {

if((stepsToDo) > 0) stepsToDo -= numStepsMotor;
else stepsToDo += numStepsMotor;
}

myMotor.step(stepsToDo); // запуск двигателя
currentStep = setStep; // перегрузка текущего положения
}
}

//-------------------------------------- обработчик прерывания 250 мкс
void timerInterrupt() {
myMotor.control(); // управвление двигателем

sumU += analogRead(A0); // суммирование кодов АЦП
timeCount++; // +1 счетчик выборок усреднения

// проверка числа выборок усреднения
if ( timeCount >= MEASURE_PERIOD ) {
timeCount= 0;
averageU= sumU; // перегрузка среднего значения
sumU= 0;
}
}

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 22 мар 2020, 19:02

Здравствуйте!
Смещение происходит потому что не задана фиксация ротора двигателя при остановке.
myMotor.setMode(1, false); // шаговый режим, без фиксации при остановке
Попробуйте второй параметр указать true.

Может в начале работы просто сделать количество шагов, которое гарантировано упрет стрелку в крайнее левое положение.

Давайте с одним двигателем закончим, потом второй добавим.

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 00:12

С фиксацией вала значительно лучше. Рабочая амплитуда перемещения стреклки перестала уходить по часовой, практически ровно возвращается в точку ноля при паузе в воспроизведении, погрешность есть, но незначительная, ее, думаю, можно списать на большую инерцию стрелки при высокой частоте колебаний. Плюс, в самом моторчике редуктор с 3 шестернями. Рабочая зона у стрелки будет примерно 90 градусов. Количество шагов на оборот стоит 1600. Следовательно в начале работы стрелку нужно откатить на 1600\4 = 400 шагов. Думаю, лучше пусть будет 500, дабы был запас, так как точный угол работы стрелки не рассчитан еще. Остается откат стрелки и второй моторчик! Окончательную схему и распиновку я выложу.

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 23 мар 2020, 11:59

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

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 13:38

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

Код: Выделить всё

// программа следящего электропривода без обратной связи

#include <TimerOne.h>
#include <StepMotor.h>

#define MEASURE_PERIOD 8  // время периода измерения (* 100 мкс)
#define numStepsMotor 1600 // число шагов двигателя на оборот

int timeCount; // счетчик времени
long sumU1; // переменные для суммирования кодов АЦП
long averageU1; // сумма кодов АЦП (среднее значение * 8)
long sumU2; // переменные для суммирования кодов АЦП
long averageU2; // сумма кодов АЦП (среднее значение * 8)
int currentStep1; // текущее положение двигателя 1
int setStep1; // заданное положение двигателя 1
int currentStep2; // текущее положение двигателя 2
int setStep2; // заданное положение двигателя 2


StepMotor myMotor1(9, 10, 11, 12); // создаем объект типа StepMotor, задаем выводы для фаз мотора 1
StepMotor myMotor2(4, 5, 6, 7); // создаем объект типа StepMotor, задаем выводы для фаз мотора 2

void setup() {
Timer1.initialize(100); // инициализация таймера 1, период 100 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
myMotor1.setMode(1, true); // шаговый режим, без фиксации при остановке
myMotor1.setDivider(6); // делитель частоты 8
myMotor2.setMode(1, true); // шаговый режим, без фиксации при остановке
myMotor2.setDivider(6); // делитель частоты 8

myMotor1.step(500); //вращение мотора 1 на 500 шагов до ограничителя
myMotor2.step(500); //вращение мотора 2 на 500 шагов до ограничителя
}

void loop() {
  //  ------------------------------------мотор 1--------------------------------------
// проверка остановки двигателя
if( myMotor1.readSteps() == 0) {
// двигатель остановился

// вычисление заданного положения
setStep1 = averageU1 * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

// определение сколько шагов надо сделать
int stepsToDo1; // сколько шагов надо сделать

stepsToDo1 = currentStep1 - setStep1; // ошибка рассогласования

if( abs(stepsToDo1) >= (numStepsMotor / 2) ) {

if((stepsToDo1) > 0) stepsToDo1 -= numStepsMotor;
else stepsToDo1 += numStepsMotor;
}

myMotor1.step(stepsToDo1); // запуск двигателя
currentStep1 = setStep1; // перегрузка текущего положения
}
// -------------------------------------мотор 2 ----------------------------------------
// проверка остановки двигателя
if( myMotor2.readSteps() == 0) {
// двигатель остановился

// вычисление заданного положения
setStep2 = averageU2 * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

// определение сколько шагов надо сделать
int stepsToDo2; // сколько шагов надо сделать

stepsToDo2 = currentStep2 - setStep2; // ошибка рассогласования

if( abs(stepsToDo2) >= (numStepsMotor / 2) ) {

if((stepsToDo2) > 0) stepsToDo2 -= numStepsMotor;
else stepsToDo2 += numStepsMotor;
}

myMotor2.step(stepsToDo2); // запуск двигателя
currentStep2 = setStep2; // перегрузка текущего положения
}
}

//-------------------------------------- обработчик прерывания 100 мкс
void timerInterrupt() {
myMotor1.control(); // управвление двигателем
myMotor2.control(); // управвление двигателем

sumU1 += analogRead(A0); // суммирование кодов АЦП
sumU2 += analogRead(A1); // суммирование кодов АЦП
timeCount++; // +1 счетчик выборок усреднения

// проверка числа выборок усреднения
if ( timeCount >= MEASURE_PERIOD ) {
timeCount= 0;
averageU1= sumU1; // перегрузка среднего значения
sumU1= 0;
averageU2= sumU2; // перегрузка среднего значения
sumU2= 0;
}
}

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 23 мар 2020, 14:19

Время обработчика прерывания у вас осталось 250 мкс. Возможно, хотели установить 100 мкс.

Код: Выделить всё

Timer1.initialize(100); // инициализация таймера 1, период 100 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний

Но, период 100 мкс использовать нельзя. У вас в прерывании 2 вызова analogRead, каждый из которых выполняется дольше 100 мкс. Возможно, и в таком варианте (250 мкс) у вас обработчик прерывания выполняется не каждый раз.
Если все же требуется такой малый период обработки прерывания по таймеру, то надо хотя бы чередовать вызовы analogRead для разных каналов. Еще лучше использовать АЦП в фоновом режиме (урок 65).
Как вариант - увеличить быстродействие АЦП за счет снижения точности измерения.

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 15:23

Исправил!
Последняя исправленная версия скетча. Схемку чуть позже выложу, для желающих повторить. Залью видео работы.


Код: Выделить всё

// программа стрелочного индикатора громкости на 2 шаговых микродвигателях

#include <TimerOne.h>
#include <StepMotor.h>

#define MEASURE_PERIOD 8  // время периода измерения (* 100 мкс)
#define numStepsMotor 1200 // число шагов двигателя на оборот

int timeCount; // счетчик времени
long sumU1; // переменные для суммирования кодов АЦП
long averageU1; // сумма кодов АЦП (среднее значение * 8)
long sumU2; // переменные для суммирования кодов АЦП
long averageU2; // сумма кодов АЦП (среднее значение * 8)
int currentStep1; // текущее положение двигателя 1
int setStep1; // заданное положение двигателя 1
int currentStep2; // текущее положение двигателя 2
int setStep2; // заданное положение двигателя 2


StepMotor myMotor1(9, 10, 11, 12); // создаем объект типа StepMotor, задаем выводы для фаз мотора 1
StepMotor myMotor2(4, 5, 6, 7); // создаем объект типа StepMotor, задаем выводы для фаз мотора 2

void setup() {
Timer1.initialize(250); // инициализация таймера 1, период 250 мкс
Timer1.attachInterrupt(timerInterrupt, 250); // обработчик прерываний
myMotor1.setMode(1, true); // шаговый режим, без фиксации при остановке
myMotor1.setDivider(8); // делитель частоты 8
myMotor2.setMode(1, true); // шаговый режим, без фиксации при остановке
myMotor2.setDivider(8); // делитель частоты 8

myMotor1.step(500); //вращение мотора 1 на 500 шагов до ограничителя
myMotor2.step(500); //вращение мотора 2 на 500 шагов до ограничителя
}

void loop() {
  //  ------------------------------------мотор 1--------------------------------------
// проверка остановки двигателя
if( myMotor1.readSteps() == 0) {
// двигатель остановился

// вычисление заданного положения
setStep1 = averageU1 * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

// определение сколько шагов надо сделать
int stepsToDo1; // сколько шагов надо сделать

stepsToDo1 = currentStep1 - setStep1; // ошибка рассогласования

if( abs(stepsToDo1) >= (numStepsMotor / 2) ) {

if((stepsToDo1) > 0) stepsToDo1 -= numStepsMotor;
else stepsToDo1 += numStepsMotor;
}

myMotor1.step(stepsToDo1); // запуск двигателя
currentStep1 = setStep1; // перегрузка текущего положения
}
// -------------------------------------мотор 2 ----------------------------------------
// проверка остановки двигателя
if( myMotor2.readSteps() == 0) {
// двигатель остановился

// вычисление заданного положения
setStep2 = averageU2 * (numStepsMotor - 1) / 1023 / MEASURE_PERIOD;

// определение сколько шагов надо сделать
int stepsToDo2; // сколько шагов надо сделать

stepsToDo2 = currentStep2 - setStep2; // ошибка рассогласования

if( abs(stepsToDo2) >= (numStepsMotor / 2) ) {

if((stepsToDo2) > 0) stepsToDo2 -= numStepsMotor;
else stepsToDo2 += numStepsMotor;
}

myMotor2.step(stepsToDo2); // запуск двигателя
currentStep2 = setStep2; // перегрузка текущего положения
}
}

//-------------------------------------- обработчик прерывания 100 мкс
void timerInterrupt() {
myMotor1.control(); // управление двигателем 1
myMotor2.control(); // управление двигателем 2

sumU1 += analogRead(A0); // суммирование кодов АЦП
sumU2 += analogRead(A1); // суммирование кодов АЦП
timeCount++; // +1 счетчик выборок усреднения

// проверка числа выборок усреднения
if ( timeCount >= MEASURE_PERIOD ) {
timeCount= 0;
averageU1= sumU1; // перегрузка среднего значения
sumU1= 0;
averageU2= sumU2; // перегрузка среднего значения
sumU2= 0;
}
}

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 16:28

https://www.youtube.com/watch?v=Idpw3bbUbj4
Видео работы. Снимал на утюг, извините за качество.

Эдуард
Администратор
Сообщения: 484
Зарегистрирован: 30 окт 2016, 20:53

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение Эдуард » 23 мар 2020, 17:02

Мне понравилось. Можно я ссылку на видео в урок по следящей системе поставлю?

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 17:08

Ссылка на моторчики
https://aliexpress.ru/item/2034683840.h ... y=bkkZKvWB

Ссылка на плату Vu метра
https://aliexpress.ru/item/400009446501 ... b201603_52

Преамп
https://aliexpress.ru/item/400072409658 ... web201603_

Конденсаторы 100мкф 16в, резисторы - 10кОм, диод 4007.

Всем успехов и процветания! Эдуард, большое вам спасибо за помощь!
Вложения
логшическая схема волюметра-Модель.jpg

АнтонНикиточкин
Сообщения: 32
Зарегистрирован: 13 апр 2018, 01:07

Re: Стрелочный индикатор громкости на 2 шаговых двигателях и Ардуино

Сообщение АнтонНикиточкин » 23 мар 2020, 17:22

Эдуард писал(а):Мне понравилось. Можно я ссылку на видео в урок по следящей системе поставлю?

Конечно!


Вернуться в «Проекты Ардуино»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 1 гость