Запуск кода внутри void loop() и внутри отдельной функции с бесконечным циклом

Я пишу программу для запуска шагового двигателя на высоких оборотах с использованием AccelStepper на NodeMCU esp8266. Супер новичок в AccelStepper, но читаю, экспериментирую и учусь по ходу дела

Когда код для переключения шагового двигателя в одну сторону, а затем в другую находится внутри voidloop(), он работает как положено, но есть куча других входных данных, которые мне нужно проверить для настройки запускают систему, и когда все они находятся внутри voidloop(), они заметно замедляют цикл, поскольку выполняют различные цифровые и аналоговые чтения.

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

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

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

Вот весь тестовый код, который я использую. Когда я раскомментирую блок кода внутри voidloop() и закомментирую вызов функции go_to, все работает отлично. Когда тот же самый блок кода запускается внутри go_to, это дает странные результаты

    #include <AccelStepper.h>
    
    const int DIR = D6;
    const int STEP = D7; 
    
    AccelStepper stepper(1,STEP,DIR); 
    
    int EndPoint = 50000
    
    
    void setup()
    {  
      stepper.setMaxSpeed(8000); 
      stepper.setAcceleration(10000);   
      stepper.setMinPulseWidth(10);     
      stepper.setCurrentPosition(0);     
      delay(2000);  // необходимо предотвратить частичный запуск при загрузке
    }
    
    
    void loop()
    {
      /*  if this code runs it works perfectly
      stepper.run(); 
      if (stepper.currentPosition()==EndPoint)
        {
        NewEndPoint=0;
        stepper.moveTo(NewEndPoint);
        }
      else if (stepper.currentPosition()==0)
        {
        NewEndPoint=EndPoint;
        stepper.moveTo(NewEndPoint);
        }
        */
    
      go_to();
      
    }
    
    
    void go_to()
    {
      for(;;) // тоже попробовали while(true), те же результаты
      {
      stepper.run();
      if (stepper.currentPosition()==EndPoint)
        {
        NewEndPoint=0;
        stepper.moveTo(NewEndPoint);
        }
      else if (stepper.currentPosition()==0)
        {
        NewEndPoint=EndPoint;
        stepper.moveTo(NewEndPoint);
        }
      }
    }

Причина, по которой я пытаюсь заставить это работать, заключается в том, что для полной программы есть несколько цифровых и аналоговых считываний, которые необходимо выполнить для скорости, расстояния, количества циклов и т. д., и все это должно быть в void Loop() или вызывается оттуда, и если они находятся в том же цикле, что и stepper.run(), это сильно замедляет скорость вращения, поэтому я пытаюсь поместите stepper.run() в собственный цикл, где он не просматривает ненужные входные данные, но я столкнулся с этой проблемой и не понимаю, почему он так реагирует.

, 👍-1

Обсуждение

оба кода делают одно и то же... второй код никогда не возвращается в цикл(), @jsotola

Они должны были сделать то же самое. Это тот же самый код, но когда он находится внутри отдельной функции, степпер проходит только часть пути к конечной точке, а затем резко останавливается, немного задерживается, а затем начинает обратное направление, проходит часть пути и резко останавливается, а затем повторяется. Я никогда не удосужился добавить выход из функции, поскольку он работает не так, как я ожидал., @Bart

на каждой итерации loop() может выполняться некоторая служебная работа... цикл внутри go_to() предотвращает его выполнение, @jsotola

Если код шагового двигателя необходимо быстро обслужить, вам придется сосредоточиться на другом коде, который вы удалили из цикла() для этой демонстрации и который замедлил его. Вы должны исключить любой блокирующий код, такой как задержка() или комплексное число с плавающей запятой, а также другие трудоемкие вычисления. Альтернативой может быть переход на платформу ESP32, где вы сможете использовать RTOS для более или менее параллельного выполнения быстрого и медленного кода., @6v6gt

посмотрите на пример random в библиотеке AccelStepper... используйте distanceToGo вместо currentPosition для более простого кода, @jsotola

Ваша проблема заключается в части вашего кода, которую вы удалили. Пожалуйста, опубликуйте полный, тестируемый (и проверенный!) пример., @Edgar Bonet

Я добавил полный код, который тестирую, не хватает только настройки. Это реальный код, который я тестирую, который работает внутри цикла void, но перемещает степперы только частично, если выполняется внутри отдельной функции., @Bart

Можете ли вы попробовать это на микро, Uno или Mega на базе AVR? Я ожидаю, что вы увидите, что двигатель работает так, как ожидалось, независимо от того, выполняется ли он в loop() или в go_to().<br>На ESP8266 между вызовами loop() происходит гораздо больше, чем обычно на АВР. Кажется вероятным, что одна или несколько из этих фоновых задач в ESP между вызовами loop() необходимы для правильного выполнения вашего моторного кода. Но когда вы запускаете двигатель в go_to() на ESP, loop() никогда не возвращается, и эти фоновые задачи не выполняются., @JRobert

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

Или еще более простой тест, возможно, даже исправление: все еще используя ESP: просто добавьте вызов yield() внутри цикла for(;;){} вверху или внизу его. yield() разработан специально для того, чтобы позволить длительным процессам, таким как ваш, дать фону возможность выполнять необходимые обязанности в момент, выбранный программистом., @JRobert

Таким образом, первоначальная проблема, заключающаяся в том, что степперы действуют иначе внутри функции, отличной от функции цикла(), очевидно, связана с «дополнительным кодом, который необходимо запускать между итерациями функции цикла», «На ESP8266 между вызывает цикл(), чем на AVR», на что было указано. Добавление выходного() в отдельную функцию решило проблему с степпером... Я скажу, что эта проблема решена. К сожалению, это также привело к другой проблеме в моем процессе, так что вернемся к чертежной доске. Большое спасибо за понимание и предложения, я собираюсь пойти и попробовать что-нибудь, @Bart


3 ответа


1

цикл уже работает бесконечно, отсюда и его название. Вам не нужно добавлять еще один цикл в функцию go_to. Удалите это, и оно будет функционально идентично.

,

1

В ESP8266 имеется дополнительный код, который необходимо запускать между итерациями функции цикла. Если вы собираетесь перехватить его где-нибудь в каком-нибудь цикле while, вам также необходимо обязательно вызвать там delay(0); или yield;, чтобы он мог заниматься другими своими делами. Если цикл цикла не запускается вовремя, плата сбрасывается из сторожевого таймера IIRC. Я думаю, это именно тот симптом, который вы наблюдаете.

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

,

Я хотел бы иметь его в основном цикле, но я не понял, как предотвратить замедление этого run() при цифровом и аналоговом чтении, которое должно происходить там. Достаточно плохо, что мне все равно придется выполнить одно цифровое чтение аварийного выключателя с помощью этого run(). Возможно, использование прерывания (attachInterrupt()?) будет лучшим вариантом, чем digitalRead()., @Bart

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

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

Добавление метода yield() в конец функции go_to() устранило странное поведение шаговых двигателей, и теперь они действуют так же, как при запуске кода внутри цикла(). НО он не рассматривает функцию как нечто, что необходимо выполнить перед возвратом в основной цикл... Думаю, мне нужно еще кое-что прочитать по этой команде. Но это отвечает на вопрос, почему тестовый код не работал., @Bart

Вам не следует кодировать его так, чтобы он был завершен перед возвратом в основной цикл. Это плохой дизайн блокировки. Запишите его как конечный автомат, чтобы цикл продолжал работать во время движения шаговых двигателей., @Delta_G


0

Самый простой способ исправить все это — сохранить код шагового двигателя внутри функции цикла, но сохранить переменную, которая «запоминает» когда шаговый двигатель работает. Используйте эту переменную, чтобы знать, когда не следует выполнять трудоемкие задачи. Пусть loop() возвращает после каждой итерации независимо от того, работает степпер или нет. Никакого вызова yield() не потребуется. Просто убедитесь, что знаете, когда работает шаговый двигатель, и не выполняйте длительную работу, если это так.

Возможно, что-то вроде этой (непроверенной!) структуры кода:

void loop()
{
   static bool isStepping = false;
     :
   if( !isStepping ){
      /* call time-consuming tasks here; */

      if( time to start the stepper now ){
         /* set up any stepping conditions you need to here; */
         isStepping = true;
   }
 
   if( isStepping ){
      /* run one iteration of the stepper code; */
      if( stepping is complete ){
         isStepping = false;
      }
   }
}  // пусть ваш цикл() возвращается после каждой итерации шагового двигателя
,

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