Как сделать компас с шаговым двигателем с 360° на 0°?

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

Мой вопрос... может ли кто-нибудь помочь мне в создании кода, который заставляет линейное пересечение от 360° до 0° работать в обоих направлениях?

Симулятор передает значение с плавающей запятой, которое представляет собой градус из 360°, например 172,13. У моего степпера 4076 шагов на полный оборот. Вы увидите математику в коде ниже. Я использую библиотеку AccelStepper.

void ProgOut(byte id, float val) {
switch (1) {
case 1:  

if (val)
        { stepper1.moveTo(val * 11.3222222);         } 
         
        stepper1.run(); 

break; }}

Я пробовал что-то вроде этого:

void ProgOut(byte id, float val) {
switch (1) { 
case 1:  
if ( stepper1.distanceToGo () >= 4064){
          stepper1.moveTo(4076);
          stepper1.setCurrentPosition(0);
}
    else if (val)
        { 
                
                stepper1.moveTo(val * 11.3222222);         
        } 
         
        stepper1.run(); 

break; }}

, 👍2

Обсуждение

ты пробовал зайти на 361?, @jsotola

почему вы используете данные симулятора во время отладки? .... выяснить, как перейти от 359 к 0, не совершая полный круг..... как только это сработает, снова используйте данные симулятора, @jsotola


2 ответа


1

Два варианта (для начала):

  1. Используйте класс move(), а не класс moveTo(). Это позволит вам делать относительные движения, а не абсолютные.
  2. Используйте setCurrentPosition() (который устанавливает текущую позицию в ноль), а затем moveTo() с пунктом назначения newPos - prevPos .

Чтобы работать в обоих случаях, вам необходимо отслеживать текущее положение иглы.

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

// дельта - требуемая угловая регулировка.
delta = (currHeading + 180 - prevHeading) % 360 - 180;
setCurrentPosition();        // Обнуление двигателя.
moveTo(delta);               // Перемещение абсолютного значения из нового нуля.
prevHeading = currHeading;   // Следить.
  • Код предполагает, что вам никогда не придется корректировать курс более чем на 180°. за один шаг.
  • Добавление 180° перед вычислением по модулю и повторным вычитанием после него - это уловка, позволяющая получить отрицательные результаты из арифметики по модулю.
,

1

Также работаю над компасом для авиасимулятора. Надеюсь, следующий код поможет ответить на вопрос. Это рабочий код, который я тестировал с помощью последовательного монитора... Примечание. Для использования Flight Sim я обнаружил, что для получения достаточной скорости и плавного движения двигателя датчика X27-168 вам нужно использовать шаговый драйвер с микрошагом, а не управлять X27-168 напрямую от контактов ввода-вывода Nano. Вам нужно будет настроить максимальную скорость & ускорение, а также отредактировать прошивку для микрошага с помощью шагового драйвера. Примечание. При использовании микросхемы драйвера шагового двигателя вам необходимо использовать правильный тип для 6-ступенчатой обмотки, которая используется, например, в шаговом устройстве X27-168. AX1201728SG. Драйверы шаговых двигателей типа Polulu (A4988) используют 8-ступенчатую подачу питания на катушку, которая не будет правильно двигать двигатель манометра - хотя он будет перемещать двигатель манометра, он создает много шума и не идеален.

Мне пришлось добавить следующее, чтобы получить как левое, так и правое движение через север. Я использовал движение, а не дельту -
if(Движение( < -180){Движение = Движение + 360;

Одиночное движение на 180 градусов по умолчанию выполняется в направлении против часовой стрелки. однако с извлечением данных симулятора полета вы не должны получить ни одного движения на эту сумму.



/*Аналоговый компас.**
В нем используется процессор Arduino Nano, четыре входа/выхода которого напрямую подключены к редукторному шаговому двигателю X27-168 (датчик индикатора).
Пока это работает, должно быть четыре комплекта защитных диодов на каждом из контактов ввода/вывода - диод на +5V & диода на 0 В, чтобы устранить всплески выше 5 В и ниже 0 В на каждом контакте ввода-вывода.
У шагового двигателя с редуктором X27-168 внутренний стопор отключен на шестерне главного выходного вала, чтобы обеспечить полное движение на 360 градусов.
Пластиковая круглая пластина диаметром 55 мм была установлена на приводной вал шагового двигателя с редуктором X27-168 диаметром 1 мм, а к пластине прикреплена печатная этикетка, показывающая направление по компасу.
Пластиковая пластина имеет небольшой неодимовый магнит (диаметр 1 мм и длина 2 мм), который может проходить рядом с датчиком на эффекте Холла (A3144) для обеспечения опорного сигнала самонаведения.
+5В, 0В и сигнальный контакт ввода/вывода подключен непосредственно к датчику Холла. Внутренний резистор ввода-вывода Nano используется для обеспечения подтягивающего напряжения для сигнала датчика Холла. В прошивке используется библиотека AccelStepper.
PC Serial Monitor используется для ввода новых направлений по компасу.
Шаговый двигатель с редуктором X27-168 в прошивке обозначается как «stepper1».
*/
    #include "AccelStepper.h" 
        AccelStepper Stepper1(AccelStepper::FULL4WIRE, 3, 4, 5, 6);   // Определяем контакты ввода-вывода шагового двигателя (используя контакты ввода-вывода, подключенные непосредственно к шаговому двигателю с редуктором X27-168)
       //AccelStepper Stepper1(AccelStepper::DRIVER, 2, 5); // Определяет контакты ввода/вывода при использовании драйвера шагового двигателя, например, AX1201728SG Quad driver chip - Dir pin - Stepper pin
       #define Home_Sensor      2   // Контакт 2 — подключен к датчику исходного положения — эффект Холла A3144- (0 В при обнаружении)
       int Offset = -67;   // ****** Отрегулируйте этот параметр, чтобы обеспечить направление на север в исходном положении (0) ******
       int MaxSpeed = 80;   // ****** Настройте этот параметр для максимальной скорости шагового двигателя, чтобы не пропускать шаги ******
       int Acceleration = 25   // ****** Настройте этот параметр для Acceleration of Stepper, чтобы не пропускать шаги ******
       int    Move_finished =   1;   // Используется для проверки завершения перемещения d
       long   Initial_Homing = -1;   // Используется для Home Stepper при запуске
       String InputString =    "";   // Строка для хранения входящих данных от последовательного монитора
       bool   StringComplete = false;   // Полна ли строка
       int    LastHeading = 0;   // Регистрация для последнего заголовка
       int    NewHeading  = 0;   // Регистрация для нового заголовка
       int    Movement;   // Регистрируем разницу между последним и новым заголовком
       void setup() {
       Serial.begin(9600);   // Запуск последовательного монитора на скорости 9600 бод
       pinMode(Home_Sensor, INPUT_PULLUP);   // Использование внутренней подтяжки для датчика Холла
       delay(5);   // Ожидание пробуждения драйвера шагового двигателя (если он используется)
       Stepper1.setMaxSpeed(MaxSpeed);   // Начальная максимальная скорость шагового двигателя (медленнее, чтобы повысить точность)
       Stepper1.setAcceleration(Acceleration );   // Начальное ускорение шагового двигателя
       Serial.println("........ Homing Stepper ........");

       while (digitalRead(Home_Sensor)) {   // Заставляем Stepper1 двигаться по часовой стрелке, пока датчик не активируется
       Stepper1.moveTo(Initial_Homing);   // Устанавливаем позицию для перехода
       Initial_Homing--;   // Уменьшить на 1 для следующего хода, если необходимо
       Stepper1.run();   // Начать движение stepper1
       delay(5);
       }
       Stepper1.setCurrentPosition(0);   // Установить текущую позицию как нулевую на данный момент
       Initial_Homing=1;
       while (!digitalRead(Home_Sensor)) {   // Заставляем Stepper1 двигаться против часовой стрелки, пока датчик не отключится
       Stepper1.moveTo(Initial_Homing);  
       Stepper1.run();
       Initial_Homing++;
       }
       //**** Теперь должно быть установлено исходное положение в положение магнита, которое может не быть северным, как указано на этикетке. Ниже позволяет настроить правильное положение метки ****
       Stepper1.setCurrentPosition(0);
       Stepper1.setMaxSpeed(MaxSpeed);   // Начальная коррекция возврата в исходное положение, максимальная скорость Stepper1
       Stepper1.setAcceleration(Acceleration );   // Начальное ускорение коррекции возврата в исходное положение Stepper1

       Stepper1.moveTo(Offset);   // Чтобы исправить север в качестве исходной позиции
       while(Stepper1.distanceToGo() != 0){Stepper1.run();}   // Шаг к скорректированному исходному положению
       Stepper1.setCurrentPosition(0);   // Задаем исходную позицию, которая будет использоваться для всех дальнейших перемещений..
       Serial.println("........ Homing Completed ........");
       Serial.println(" *** Enter Compass Heading 0 - 259 Degrees ***");
       // --------- Конец начальной настройки возврата ------------
       }
       void loop() {
       while (Serial.available() > 0) {   // Чтение последовательного ввода:
       int InChar = Serial.read();
       if (isDigit(InChar)) {InputString += (char)InChar;}   // Преобразование входящего байта в char и добавление его в строку
       if (InChar == '\n') {   // Если вы получаете новую строку,
       NewHeading = (InputString.toInt());   // Преобразование входной строки заголовка в заголовок типа int
       NewHeading = (NewHeading/2)*2;   // Устраняет смещения на 1 градус. Уменьшает ошибки движения при небольших движениях
       Serial.print(NewHeading); 

       if(NewHeading > 359 ||NewHeading < 0) {   // Отображает сообщение об ошибке, если ввод вне допустимого диапазона
       NewHeading = LastHeading;   // Без изменений из-за введенных неверных данных
       Serial.println("Input Error. Enter value between 0 - 259 Degrees ");
       }
       else { Serial.print("Heading "); Serial.print(NewHeading); Serial.println("...  Enter New Heading");

       }
       InputString = "";   // Очистить строку для нового ввода:
       Movement = ((NewHeading + 180 - LastHeading) % 360) - 180;   // Позволяет двигаться с северо-востока на северо-запад
       if(Movement < -180){Movement = Movement + 360;}   // Позволяет двигаться с северо-запада на северо-восток
       Stepper1.setCurrentPosition(0);   // Обнуление двигателя.
       Stepper1.setMaxSpeed(MaxSpeed);   // Установить максимальную скорость Stepper1
       Stepper1.setAcceleration(Acceleration );   // Установить ускорение Stepper1

       Stepper1.move(Movement*2);   // Установить новый ход в позицию Stepper1
       LastHeading = NewHeading;   // Новый заголовок теперь становится последним заголовком
       }
       }
       while(Stepper1.distanceToGo() != 0){Stepper1.run();   // Продолжаем обновлять AccelStepper для текущего движения
       int XInChar = Serial.read();XInChar = Serial.read();}   // Продолжить очистку последовательного буфера — разрешить ввод нового заголовка только после завершения движения.
       }
,