изменить скетч с управления 8 шаговыми двигателями на 8 соленоидов

Я хочу посмотреть, смогу ли я изменить прикрепленный скетч, который управляет 8 шаговыми двигателями, на простое переключение 8 реле для ткацкого станка, который у нас есть, к сожалению, внесение этого изменения намного выше моей зарплаты, лол. Я использую arduino mega и 8-канальную релейную плату, которая, в свою очередь, отключает соленоиды, которые уже подключены к ткацкому станку, спасибо за любую помощь

Это скетч, который я пытаюсь изменить


// Интерфейс ткацкого станка для интерфейса Ashford Dobby (с использованием 8 шаговых двигателей):
// Линии Arduino 0 & 1 к интерфейсу USB
// строка 13 — педаль
// 14-43 — управление двигателем

// Общие определения:
#define MAX_CHARS 80
#define DEBUG 0
#define MOTORS 8
#define IDENTITY "Generic Dobby Interface (Jones Stepper Motor Dobby)\n"

// Данные, управляющие позициями моторов, состояниями и т. д.:
const long MOTOR_DELAY=900;                                                      // Временная задержка между шагами двигателя (уменьшайте, пока валы не будут двигаться надежно)
const long  SHAFT_UP=8*170, SHAFT_DOWN=0 ;                                       // Количество шагов двигателя, необходимое для подъема валов
unsigned long shaft_state=0x00000000, shaft_cue=0xffffffff;                      // отслеживание текущего & следующие желаемые состояния управления валом
long MotorActual[MOTORS], MotorWant[MOTORS];                                     // Текущее значение & желаемое положение для каждого из двигателей

// Определение того, какие выходные контакты подключаются к какому двигателю
char MotorPin[MOTORS][4]=                                                        // Моторы 1,3,5,7 справа, 2,4,6,8 слева: левая сторона меняет направление
              { {14,15,16,17}, {18,21,20,19}, {22,23,24,25}, {26,29,28,27},      // Двигатели 1-4
                {30,31,32,33}, {34,37,36,35}, {38,39,40,41}, {42,45,44,43}};     // Двигатели 5-8

unsigned long NextMotorUpdate=0;                                                 // Таймер для следующего шага двигателя
const int ADVANCE  =13;                                                          // входной контакт для ножного переключателя (имеет подтяжку, только контакт переключателя)

// Последовательный (USB) интерфейс
// Последовательный интерфейс является "Общим" Добби интерфейс:
// Хост отправляет, какие валы должны быть активированы для текущего выстрела
// Валы поднимутся при активации ножного переключателя
// Валы возвращаются, когда ножной переключатель отпущен, и кнопка "Вперед" команда возвращена хосту
// Также отвечает на "?" с "ИДЕНТИЧНОСТЬ" указано выше, показывает хозяина, который здесь

int serial_chars=0;                                                              // Количество символов в буфере последовательного ввода
char serial_string[MAX_CHARS]="";                                                // Буфер последовательного ввода
char Message[MAX_CHARS]="";                                                      // Выходной буфер сообщений
long serial_time=0;                                                              // Используется для закрытия последовательной строки по тайм-ауту (таймер)
const int serial_timeout=100;                                                    // Дайджест последовательной строки после истечения времени ожидания
char serial_idle=1;                                                              // Отслеживает активность на последовательной шине
char HostPresent = 1;                                                            // устанавливаем, когда какой-то хост идентифицирован
int Button_state=1;                                                              // отслеживает изменения состояния переключателя этажей


////////////////////////////////////////////////// ///////////////////////
// Отправляем управление валом на оборудование
////////////////////////////////////////////////// ///////////////////////
    void set_motor(char m,char state)                                            // Функция самого низкого уровня для обработки шагов в двигателях
    {
// sprintf(Message,"M %d @ state %d\n",m,state);
// Serial.write(Сообщение);
     switch(state)
     {
      case 0:                                                                    // Установить двигатель в неактивное состояние
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 1:                                                                    // Установить мотор в состояние 1
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 2:                                                                    // Установить состояние двигателя 2
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 3:                                                                    // Установить состояние двигателя 3
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 4:                                                                    // Установить состояние двигателя 4
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 1);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 5:                                                                    // Установить состояние двигателя 5
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 0);
      break;

      case 6:                                                                    // Установить состояние двигателя 6
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 1);    digitalWrite(MotorPin[m][3], 1);
      break;

      case 7:                                                                    // Установить состояние двигателя 7
      digitalWrite(MotorPin[m][0], 0);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 1);
      break;

      case 8:                                                                    // Установить состояние двигателя 8
      digitalWrite(MotorPin[m][0], 1);    digitalWrite(MotorPin[m][1], 0);
      digitalWrite(MotorPin[m][2], 0);    digitalWrite(MotorPin[m][3], 1);
      break;
     }
    }
 
   char set_motors()                                                            // Установить все двигатели в новое состояние двигателя - вызывается для каждого шага двигателя на любом двигателе
    {                                                                            // возврат указывает, активен ли еще какой-либо двигатель
     int m=0;
     long setting, entry_setting;
     char active=0;

     while(m<MOTORS)
     {
                                                                                 // Проверяем необходимое направление движения
      entry_setting=setting=MotorActual[m];
      if(setting==MotorWant[m])       setting=setting;
      else if(setting<MotorWant[m])   setting++;
      else                            setting--;
                                                                                 // Отправляем элементы управления настройками обновления
      if((entry_setting!=MotorWant[m]))
      {
       active=1;
       MotorActual[m]=setting;                                                   // обновить актуальное для текущего перемещения
       setting=(setting&7)+1;                                                    // состояние set_motor 0 неактивно, 1-8 активны
       set_motor(m,setting);                                                     // Установить новое состояние мотора
      }
      m++;                                                                       // Следующий мотор
     }
     if(active==0)
     {                                                                           // Если сделано, отключите питание двигателей, которые вернулись в пассивное состояние.
      m=0;
      while(m<MOTORS)
      {
       if(MotorActual[m]==SHAFT_DOWN)set_motor(m,0);                             // установка мотора в неактивное состояние
       m++;
      }
     }
     return active;
    }

    char run_motors()                                                            // Функция более высокого уровня для установки моторов в нужное положение
    {                                                                            // возврат указывает, активны двигатели или простаивают
     char active=1;
     if(micros()>=NextMotorUpdate)
     {                                                                           // время для обновления позиций двигателей
      active=set_motors();                                                       // Обновить все моторы
      NextMotorUpdate=micros()+MOTOR_DELAY;                                      // устанавливаем часы для следующего обновления
     }
     return active;
    }

    void set_shafts(unsigned long shafts)                                        // Вызывается для установки желаемых положений двигателя в зависимости от того, какие валы были запрошены
    {                                                                            // Это предполагает, что все валы перемещаются на одинаковую величину, на самом деле им не нужно
     unsigned long bit_mask=1;
     int i=0;
     while(i<MOTORS)
     {
      if(shafts&bit_mask)MotorWant[i]=SHAFT_UP;
      else               MotorWant[i]=SHAFT_DOWN;
// sprintf(Message,"M %d @ хочу %d\n",i,MotorWant[i]>>8);
// Serial.write(Сообщение);
      i++;
      bit_mask=bit_mask<<1;
     }
    }
////////////////////////////////////////////////// ///////////////////////
// Preset-вызывается при инициализации
////////////////////////////////////////////////// ///////////////////////
    void preset()                                                                // Может поднять все валы, чтобы показать, что он работает и т. д.
    {                                                                            // Эта версия ничего не делает, по умолчанию все валы поднимаются при нажатии ножного переключателя до того, как будет запрошено что-либо еще
    }

//////////////////////////////////////////////////
// ФУНКЦИИ ПОСЛЕДОВАТЕЛЬНОГО ИНТЕРФЕЙСА (USB)
//////////////////////////////////////////////////
                                                                                 // Команды ввода USB:
                                                                                 // 1,2,3,n Установить валы 1,2,3,n
                                                                                 // ? Запрос идентификатора, ответ с идентификатором
    unsigned long get_shafts(char* command)                                      // Ввод представляет собой серию чисел, разделенных запятыми, для поднятия валов
    {                                                                            // возвращает слово, указывающее, какие валы были идентифицированы в строке
     int chars=strlen(command);                                                  // Количество символов во входной строке
     int i=0;
     unsigned long shafts=0, bits;                                               // Устанавливает биты для указанных валов
     char shaft=0, digit=0, character;

     while(i<=chars)                                                             // цикл по всем символам в команде
     {
      character=command[i];

      if((character==',')||(i==chars))
      {                                                                          // есть разделитель полей или конец строки, а не вал
       if((shaft>0)&&(shaft<=32))
       {                                                                         // 'shafts' отмечает, что этот вал необходим
        bits=1<<shaft-1;
        shafts|=bits;
        shaft=0;
       }
      }
      else if(('0'<=character)&&(character<='9'))
      {                                                                          // есть цифра
       character&=0x0f;                                                          // уменьшить до десятичного числа
       shaft=shaft*10+character;
      }
      else if((character==' ')||(character=='\n'));                              // игнорировать пробелы/возвраты
      else
      {
       Serial.println("Invalid Character detected in command:");                 // отладочное отображение извлеченной команды
       Serial.println(command);                                                  // отладочное отображение извлеченной команды
       i=chars;                                                                  // выходим, дерьмо
      }
      i++;
     }
     return shafts;
    }

    void digest_serial(char* command)                                            // Основная функция последовательного ответа
    {
     int chars=strlen(command);                                                  // Количество символов в команде

     if(chars>0)
     {                                                                           // Если что-то делать, переварить ввод
      HostPresent=1;                                                             // обратите внимание, что там что-то говорит со мной
      if(('0'<=command[0])&&(command[0]<='9'))                                   // идем число, должны быть валы
       shaft_cue=get_shafts(command);                                            // преобразовать строку ASCII в двоичное слово
      else  if((command[0]=='c')||(command[0]=='t'))                             // тестовая команда для переключения клапанов
       preset();                                                                 // циклически переключаться между клапанами (для этого ткацкого станка ничего не определено, можно реализовать самопроверку вала и т. д.)
      else if(command[0]=='?')
      {                                                                          // У вас есть вопрос "Кто вы?" своего рода команда, скажите хозяину, кто мы
       char message[256]=IDENTITY;                                               // Команда создания первичной идентификации
       message[strlen(message)-1]=0;                                             // удалить возврат в строке
       sprintf(message,"%s  [Solenoid state = 0x%3x]\n",message,shaft_state);    // обратите внимание, что мы будем делать при нажатии кнопки
       Serial.write(message);                                                    // Отправляем идентификатор с текущим состоянием коммутатора на хост (для устранения неполадок)
      }
     }
    }

    void serial_input()
    {                                                                            // Последовательная обработка высокого уровня
     char inChar;
     char command[MAX_CHARS]="";

     while((Serial.available()>0))
     {                                                                           // Получить последовательную команду от хоста (посимвольно)
      inChar=char(Serial.read());
      serial_string[serial_chars]=inChar;
      serial_chars++;
      serial_string[serial_chars]=0;
      serial_time=millis();
     }
     if((serial_chars>0)&&(serial_idle)&&((serial_string[serial_chars-1]=='\n')||(millis()>(serial_time+serial_timeout))))
     {                                                                           // Если есть команда, переварить ее
      serial_idle=0;
      strcpy(command,serial_string);
      serial_chars=0;
      serial_string[0]=0;
// Serial.println(команда); // отладочное отображение извлеченной команды
      digest_serial(command);
                                                                                 // выполнено с последней командой, очищаем входные буферы
      serial_idle=1;                                                             // готов к дальнейшему последовательному вводу
     }
    }

////////////////////////////////////////////////// //////////// /
// Монитор ножного переключателя - установить валы/указать хосту двигаться вперед
////////////////////////////////////////////////// //////////// /
    void monitor_button()
    {                                                                            // проверка нажатия кнопки для продвижения вперед, отправляется только тогда, когда кнопка нажата (не удерживается)
     char state=digitalRead(ADVANCE);                                            // чтение состояния ножного переключателя (0=активно, 1=неактивно)

     if(state==0)
     {                                                                           // кнопка нажата,
      set_shafts(shaft_cue);                                                     // Установите требуемые состояния двигателя из списка желаемых валов для этого кадра
      run_motors();                                                              // Запустим моторы, чтобы это произошло
     }
     else
     {                                                                           // кнопка не нажата,
      set_shafts(0);                                                             // Устанавливаем требуемые состояния двигателя обратно в состояние сброса
      run_motors();                                                              // Сделай это
      if(Button_state!=state)
       Serial.write("ADVANCE\n");                                                // Отправить "Доступно" когда ножной переключатель отпущен
     }
     if(state!=Button_state)                                                     // Проверяем, изменилось ли состояние кнопки
      delay(500);                                                                // Подождать полсекунды после изменения переключателя устранения дребезга
     Button_state=state;                                                         // Отслеживание текущего состояния кнопки для поиска изменений
    }


//////////////////////////////////////////////////
// ФУНКЦИИ ВЕРХНЕГО УРОВНЯ - НАСТРОЙКА & ПЕТЛЯ //
//////////////////////////////////////////////////
    void setup()
    {
     char m;                                                                     // Индикатор двигателя

                                                                                 // USB-интерфейс для хост-компьютера
     Serial.begin(9600);                                                         // запускаем последовательный порт на скорости 9600 бит/с:
     Serial.print(IDENTITY);                                                     // вывести сообщение на серийный монитор

                                                                                 // Управление двигателем
                                                                                 // устанавливаем управление мотором для всех моторов
     m=0;
     while(m<MOTORS)
     {
      digitalWrite(MotorPin[m][0], LOW);                                         // установить низкий уровень
      digitalWrite(MotorPin[m][1], LOW);                                         // установить низкий уровень
      digitalWrite(MotorPin[m][2], LOW);                                         // установить низкий уровень
      digitalWrite(MotorPin[m][3], LOW);                                         // установить низкий уровень
      pinMode(MotorPin[m][0], OUTPUT);                                           // Установить как выходной бит
      pinMode(MotorPin[m][2], OUTPUT);                                           // Порядок смешивания, чтобы двигатель не двигался
      pinMode(MotorPin[m][1], OUTPUT);                                           // Установить как выходной бит
      pinMode(MotorPin[m][3], OUTPUT);                                           // Установить как выходной бит
      MotorWant[m]=MotorActual[m]=0;                                             //
      m++;
     }

      pinMode(ADVANCE, INPUT_PULLUP);                                            // Установить как входной контакт для управления педальным переключателем
      preset();                                                                  // "самопроверка" - обратите внимание, что он жив
      unsigned long T0=millis();                                                 // Обратите внимание на время запуска
     }



    void loop()
    {
     serial_input();                                                             // проверяем последовательный интерфейс, обрабатываем, если он приходит
     monitor_button();                                                           // проверка нажатия кнопки
    }

, 👍2

Обсуждение

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

комментарии не являются частью кода... они не должны вплетаться в код... почистил для вас листинг программы, @jsotola

Привет, Jsotola, спасибо за ваш ответ, все, что соленоид будет делать, это активировать, когда двигатель работает нормально, то есть вместо того, чтобы двигатель включался и делал x число оборотов, соленоид просто включается, это запускается программным обеспечением, которое работает в Windows для создания и запуска заданного шаблона, затем при срабатывании педального переключателя соленоид отключится, и программное обеспечение ПК перейдет к следующему шагу шаблона и задействует правильные соленоиды. извините за все комментарии, так как они уже были в скетче, который я нашел., @Vaughan Ratahi

много комментариев - это очень хорошо, но они не должны загромождать код... вот и все, что я хочу сказать, @jsotola

Я всегда думал, что лучшее место для комментариев — начало функций. Хорошие комментарии указывают на то, что мысль была направлена на то, чтобы разделить задачу на хорошо организованные функции. Однако даже такие гиганты, как NXP и STMicro, не делают этого регулярно в своем коде. Кроме того, комментарии типа «Установить состояние двигателя 1» бесполезны. Опытные программисты тут же прокомментируют: «Это очевидно… но что такое «Состояние 1»… вот настоящий вопрос/комментарий, который нужно сделать»., @st2000


2 ответа


1
  • Предполагаемая цель – автоматизация ткацкого станка с использованием соленоидов вместо шаговых двигателей.

  • В
  • В этом видео утверждается, что необходимо тянуть 3 кг. Может быть трудно найти подходящий / экономичный соленоид с таким тяговым усилием, ходом и усилием. рассчитан на непрерывную работу (удерживать свое положение в течение длительного периода времени без вреда для себя из-за проблем, связанных с нагревом).

  • Если найти такой соленоид не проблема, в приведенном выше коде есть только две функции, которые управляют шаговыми двигателями. "установить_двигатель" и "настройка". Измените их, чтобы активировать/деактивировать соленоиды.

  • Кроме того, это может быть сложнее, удалите код, который циклически переводит шаговые двигатели в положение / из положения. Вам это не нужно с соленоидами.

,

0

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

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

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

,