Запрашиваю помощь в проекте с ЧПУ с использованием Arduino

Я сделал настройку с помощью Arduino Uno, Nema 17, ходового винта T8, ИК-датчика и двигателя постоянного тока. Я пытаюсь создать код, который:

  1. Сбрасывает исходное положение обрабатывающей головки на ходовом винте
  2. Имеет кнопку действия, которая срабатывает только тогда, когда положение головки на ходовом винте опускается на заданную глубину
  3. Принимает входные данные от пользователя для запуска двигателя постоянного тока (для вращения инструмента на головке станка)
  4. Требуется второй вход, чтобы остановить вращение и вернуться в положение сброса.

Я сталкиваюсь с одной серьезной проблемой и двумя второстепенными проблемами:

Основная Проблема: Чтобы устранить ошибку, которая позже была устранена, я добавил строку: action_permit=0 Теперь по какой-то причине (я вытащил много волос, пытаясь понять это), когда я удаляю эту строку action_permit, вращение двигателя постоянного тока прекращается. Я должен включить эту линию, чтобы вращать мой двигатель постоянного тока.

Незначительная Проблема: Чтобы получить ввод от пользователя для управления запуском и остановкой двигателя постоянного тока, я включил код, который принимает " y " как " да "(начало вращения двигателя постоянного тока) и " n " как " нет " (остановка вращения и возврат в исходное положение).

Незначительная Проблема: Я не уверен, как управлять ШИМ, я скопировал код с видео, но не знаю, как достичь максимальной и минимальной частоты вращения; также я понимаю, что разница между значением ШИМ и частотой вращения не линейна. Любая обратная связь о том, как точно контролировать частоту вращения двигателя, была бы отличной

int IR_signal=2;
int DC_ENB=11;
int DC_IN3=4;
int DC_IN4=5;
int STE_dir=6;
int STE_step=7;
int STE_ena=10;
int button_reset=8;
int button_action=9;
//define arduino pin
int action_permit;//0-action part is not allowed to run. 1-action part is allowed to run
int IRon;
int COUNT;//the amount of steps that the machine head should go
int HEIGHT;//total height that the machine head should go
int i;
int reset_on;
int action_on;
String Switch_DC;

//parameter
void setup() {
  // put your setup code here, to run once:
  pinMode(IR_signal,INPUT);
  pinMode(button_reset,INPUT);
  pinMode(button_action,INPUT);
  //input part
  pinMode(DC_ENB,OUTPUT);
  pinMode(DC_IN3,OUTPUT);
  pinMode(DC_IN4,OUTPUT);
  pinMode(STE_dir,OUTPUT);
  pinMode(STE_step,OUTPUT);
  pinMode(STE_ena,OUTPUT);
  //output part
  action_permit=0;// ban the action part at the beginning
  COUNT=0;
  HEIGHT=0;

  //original value of parameters
  //digitalWrite(DC_ENB,HIGH);
  analogWrite(DC_ENB,200);
  digitalWrite(STE_ena,LOW);
  digitalWrite(DC_IN3,HIGH);
  digitalWrite(DC_IN4,HIGH);
  //original pin output
  Serial.begin(9600);
  // start the monitor
}

void loop() {
  // put your main code here, to run repeatedly:
  reset_on=digitalRead(button_reset);
  action_on=digitalRead(button_action);
  //read the signal from the button
  if(reset_on==0)//reset button is pressed
  {
    delay(10);
    // preventing manual error
    if(reset_on==0)
    {
      RES();
    }
  }
  if(action_on==0)//action button is pressed
  {
    delay(10);
    // preventing manual error
    if(action_on==0)
    {
      ACT();
    }
  }
}
void RES()//reset part
{
  while(action_permit==0)//when 0, this "while" loop will keep running
  {
    IRon=digitalRead(IR_signal);// read the signal from IR sensor
    if(IRon==1)// machine head is not in original position
    {
      delay(1);
      //ensure the signal is not happened by a BUG
      IRon=digitalRead(IR_signal);
      if(IRon==1)
      {
        digitalWrite(STE_dir,LOW);
        digitalWrite(STE_step,HIGH);
        delay(1);
        digitalWrite(STE_step,LOW);
        delay(1);
        //if machine head is not in original position, it will go up for one step
      }
    }//if HIGH, go up
    else if(IRon==0)
    {
      action_permit=1;
      COUNT=0;

    }//once machine head reaches the original position, controller will get out this loop and allow action part to run
  }
}
void ACT()//action part
{
  if(action_permit==1)
  {

   for(i=0;i<3523;i+=1)
   {
     digitalWrite(STE_dir,HIGH);
     digitalWrite(STE_step,HIGH);
     delay(1);
     digitalWrite(STE_step,LOW);
     delay(1);
   }
   delay(100);
   for(i=0;i<100;i+=1)
   {
     digitalWrite(STE_step,HIGH);
     delay(10);
     digitalWrite(STE_step,LOW);
     delay(10);
   }
   action_permit=0;

   Serial.println("Please press y to start tool rotation");
   while((Serial.available()==0))
   {
    //waiting for input  
   }
   Switch_DC=Serial.readString();
   if (Switch_DC == "y")
   action_permit=0;
   {
    analogWrite(DC_ENB,200);
    digitalWrite(DC_IN3,HIGH);
    digitalWrite(DC_IN4,LOW);
    delay(2000);
   }

   Serial.println("Please press n to stop tool rotation");
   while((Serial.available()==0))
   {
    //waiting for input 
   }
   Switch_DC=Serial.readString();
   if(Switch_DC == "n")
   action_permit=0;
   {
    analogWrite(DC_ENB,200);
    digitalWrite(DC_IN3,LOW);
    digitalWrite(DC_IN4,LOW);
   }
   digitalWrite(STE_dir,LOW);
   for(i=0;i<4523;i+=1)
   {
     digitalWrite(STE_step,HIGH);
     delay(1);
     digitalWrite(STE_step,LOW);
     delay(1);
   }
   action_permit=0;
  }
}

, 👍-1

Обсуждение

для точного контроля оборотов двигателя необходимо использовать датчик, генерирующий импульс или несколько импульсов за один оборот двигателя, @jsotola


1 ответ


0

У вас есть некоторые очевидные проблемы в вашем коде, хотя я не знаю, будет ли логика правильной (делать то, что вы хотите), если вы их исправите. Но в любом случае это хорошее начало.

  • Вы проверяете, чтобы action_on и reset_on были НИЗКИМИ, поэтому я думаю, что кнопка опустит штифт до НИЗКОГО уровня, если вы нажмете ее. Вы не активировали внутренние подтягивающие резисторы, так что, я думаю, они у вас уже есть снаружи (если нет: они вам определенно нужны). Таким образом, action_on==0 на самом деле имеет место, когда действие разрешено, а не запрещено. Вы, кажется, думаете, что все наоборот.
  • Затем вы делаете это (и то же самое с reset_on):

    if(action_on==0)//action button is pressed
      {
      delay(10);
      // предотвращение ошибок вручную
      if(action_on==0)
    

    Вы проверяете, равно ли action_on нулю. Если да, вы немного подождете и проверите то же самое еще раз. Значение action_on не может измениться во время задержки, поэтому это всегда будет верно и, следовательно, излишне. Если вы хотели прочитать кнопку еще раз, чтобы проверить, действительно ли кнопка была нажата (для отмены), вам нужно снова прочитать состояние кнопки с помощью digitalRead() и сохранить его в action_on, как вы делали раньше. Это не делается автоматически для вас.

  • для(i=0;i<3523;i+=1) Использование глобальной переменной для подсчета в цикле for не является хорошей идеей. Вместо этого вы всегда должны использовать локальную переменную для этого: for(int i=0;i<3523;i+=1)
  • Switch_DC=Serial.ReadString(); Использование ReadString() не является хорошим кодированием, потому что эта функция просто считывает все данные, которые поступают до истечения времени ожидания (по умолчанию 1 с). Это ненадежный способ считывания данных с последовательного. Вместо этого вы должны считывать каждый символ по отдельности из последовательного интерфейса, помещать его в буфер и останавливать и обрабатывать вывод только в том случае, если был отправлен разделительный символ. Часто для этого используется символ новой строки \n. Таким образом, одно сообщение/команда, которые должны быть обработаны в целом, должны заканчиваться символом новой строки. Это предотвратит, что ввод с последовательного канала обрабатывается неправильно, только потому, что время было другим. Если у вас есть только команды, состоящие только из 1 символа, вы можете вместо этого использовать один Serial.read(), который считывает ровно один символ из последовательного интерфейса (или возвращает -1, если нет символа для чтения).
  • Затем вы написали следующее:

    if (Switch_DC == "y")
    action_permit=0;
    {
    

    Я предполагаю, что здесь вы вставили action_permit=0. Этого не может быть, хочу, чтобы ты имел в виду. Как вы написали, строка action_permit=0 будет выполнена только в том случае, если Switch_DC равно "y", поскольку этот оператор находится внутри оператора if. Параметр ; в конце инструкции также закрывает инструкцию if. Таким образом, код внутри следующих скобок всегда будет выполняться, и скобки будут переполнены. Я не знаю, куда вы намеревались вставить action_permit=0, но поскольку он никогда не используется в остальной части функции, достаточно просто использовать его в конце функции, как вы уже сделали. Удалите все остальные эти строки из этой функции.


Если вы хотите контролировать частоту вращения двигателя, а не просто какое-то относительное значение ШИМ, вам сначала нужно измерить частоту вращения. ШИМ просто управляет электрической энергией, поступающей в двигатель относительным образом (относительно полностью включенного питания). Чтобы задать значение оборотов двигателя, вам необходимо измерить текущую частоту вращения (например, с помощью светового барьера или поворотного энкодера) и использовать ее в качестве входного сигнала для ПИД-регулятора (пропорциональный интегральный дифференциал). Затем выход ПИД-контроллера должен быть подан в функцию analogWrite (). ПИД-контроллер будет повышать или понижать значение ШИМ до тех пор, пока не будет достигнуто заданное значение оборотов в минуту. Существует библиотека PID для Arduino, которая поможет вам с вычислениями.

,

Большое спасибо вам за вашу помощь! Я буду реализовывать ваши предложения одно за другим и смотреть, как улучшается код. Ваша помощь позволила мне начать думать как программист, и я не могу отблагодарить вас за это. Как реагировать на action_permit. Да, это нормально закрытая кнопка, также когда я удаляю action_permit из любого места кода (я пытался удалить его один за другим во всех местах), строки кода рядом с этим оператором начинают плохо себя вести. Что касается вашего комментария о чтении ввода от пользователя, можете ли вы предложить лучшую альтернативу тому, как читать "y" и "n"? Еще раз спасибо!, @Shreeniket Joshi

привет, Крисл, что касается функции ШИМ. Да, у меня есть тахометр. Я не уверен, хочу ли я использовать PID, можете ли вы предложить, как я могу откалибровать его вручную?, @Shreeniket Joshi

О Serial: Как я уже писал в ответе, если у вас есть только команды, состоящие из 1 байта/символа, вы можете просто использовать Serial.read (), который считывает ровно 1 символ. О ШИМ: Это типичная ситуация для цикла управления. Использование PID здесь лучше всего. Он дает вам желаемый результат быстрее и без колебаний. Если вы калибруете только значения ШИМ (сопоставляя значения ШИМ с оборотами при тестировании), это не учитывает нагрузку на двигатель и не будет точным. В конечном счете это ваше решение, то, что вам нужно. PID со связанной библиотекой не составляет труда., @chrisl