Шаговые моторы проблема со скоростью

Тема в разделе "Arduino & Shields", создана пользователем sanik, 7 янв 2020.

Метки:
  1. sanik

    sanik Гик

    Не получается остановить один мотор if (pins[num].State == 1 && pins[num].fOn == 0) break; Веде к полному выходу из цикла останавливаются все моторы.
     
    Daniil нравится это.
  2. Daniil

    Daniil Гуру

    break.
    Извиняюсь, перепутал с continue.
    Так, если мы в начале цикла проверяем if (pins[num].State == 1 && pins[num].fOn == 0) (по-русски это звучит "выключить ли мотор И не подано ли на него напряжение"), то если условие выполняется и далее идёт continue, то весь остальной код в цикле пропускается и цикл переходит к следующему шагу где num=num+1, т.е. переходим к следующему мотору. Таким образом, не работая с мотором, напряжение на пине остаётся неизменным, т.е. мотор должен стоять.
    Да, для для остановки первого мотора нужно выполнить pins[0].fOn = 0; НО. Я бы не назвал это "команда остановки", т.к. по моему разумению команда должна выполняться сразу, а это смена флага. Мотор остановится только после того как будет проверка этого флага, а это произойдёт не дольше, чем 2 цила loop.
    Я ночью видел простыню кода, вы ввели структура для таймера, который следит за скоростью. Она идентична моей структуре таймера, поэтому можно было не изобретать ещё одну структуру, а использовать уже имеющуюся.
    Код (C++):
    struct point_t{//структура точки состоит из
      uint8_t x;//координаты Х
      uint8_t y;//координаты Y
    }
    struct rect_t{
      point_t points[4]; //в структуре прямоугольника 4 точки
    }
    struct tria_t{
      point_t points[3]; //в структуре треугольника 3 точки
    }
    struct person_t{
      point_t GPS; // в структуре Персона есть координаты человека
      string name; // у человека может быть имя и другой огромный набор полей структуры
    }
    и т.д. структуру point_t можно использовать везде где удобно.
    Хотя, честно говоря, я не знаю как повлияет на объём кода наличие двух одинаковых структур, но что-то мне подсказывает, что без острой нужды лучше не плодить сущности.
     
  3. sanik

    sanik Гик

    Да вы правы я ночью так и переделал убрал вторую структуру таймера :)
     
  4. Daniil

    Daniil Гуру

    Нюанс, который я вижу, в том, что если обращаться к pins[num].State из другого участка кода, то эта переменная хранит будущее значение состояния мотора, т.к. по коду получается так
    время прошло
    запуск таймера
    изменить состояние пина на то, которое было выбрано на предыдущем такте управления мотора
    выбрать следующее состояние мотора
    ...
    Т.е. если нужно текущее состояние мотора, то нужно вычислять !(pins[num].State).
    Если же переписать код так:
    Код (C++):
    if (millis() - pins[num].PWM.last_time > pins[num].PWM.period_ms){
          pins[num].PWM.last_time = millis();
          pins[num].State=!(pins[num].State); //инвертирование переменной состояния пина
          digitalWrite(pins[num].Name, pins[num].State);
        }
    То всё на оборот. Теперь pins[num].State хранит текущее значение состояния мотора.

    Во всех 2-х случаях, если обратиться к pins[num].State в промежутке времени после digitalWrite и до pins[num].State=!(pins[num].State) (или на оборот), то pins[num].State будет возвращаться неправильное значение для 2-х листингов. Это можно сделать в прерывании. Если вы ими не пользуетесь, то проблем нет, но помнить нужно.
     
  5. Daniil

    Daniil Гуру

    Я ещё у себя ошибку нашёл!
    Оператор инверсии это тильда - "~", а не восклицательный знак. И это побитовое отрицание т.е. из 0b00000001 будет 0b11111110, а из 0b00000000 будет 0b11111111.
    В языке СИ ложь это 0, а все остальные числа считаются истиной. Поэтому как бы не хотелось по-проще, но со state надо работать не так:
    Код (C++):
    pins[num].State=!(pins[num].State); //инвертирование переменной состояния пина
    а так:
    Код (C++):
     if (pins[num].State==1) {pins[num].State=0;}
      else {pins[num].State=1;}//инвертирование переменной состояния пина
    или в самом начале инициализировать pins[num].State=0b11111111;, но в таком случае под 1 флаг отдаётся 8 бит, а в случае с if только 1 бит (см. битовые поля, я может парюсь не о том)
     
  6. sanik

    sanik Гик

    Я тоже это заметил что переменную лучше инвертировать а уже потом передать состояние на пин.Вот все получилось остановить мотор
    Код (C++):
    for (uint8_t num = 0; num < kol_Pins; num++) {
        if (pins[0].State == 1 && pins[0].fOn == 0) {//
          if (num == 0) continue;
        }
    Еще раз благодарю вас за помощь. Хоть немного познал конструкции Хотя как понял есть еще нюансы но пока не сунешься ничего не поймешь)) Когда читаешь все вроде просто начинаешь юзать встречаешься со всякими неожиданностями)
     
    Daniil нравится это.
  7. Daniil

    Daniil Гуру

    Если бы были битовые поля, то вот как можно было бы сделать.
    Код (C++):
    //Объявляем тип структуры таймера
    struct timer_t {
      uint16_t period_ms;
      uint32_t last_time;
    };
    struct state_t{
      unsigned pulse : 1;
    //7 бит отсались неиспользованными, но их можно занять потом чем-нибудь
    }
    //Объявляем тип структуры пина
    struct pin_t {
      uint8_t Name;
      state_t State;
      timer_t PWM;
    };

    #define pin1 D13
    #define pin2 A2
    const uint8_t kol_Pins=2; // количество пинов с моторами
    pin_t pins[kol_Pins];

    //Иницализация переменных
    void init_mas(){
      pins[0].Name=pin1;        pins[1].Num=pin2;
      pins[0].State.pulse=LOW;
      pins[0].PWM.period_ms=13;
      pins[0].PWM.last_time=0;
      pins[1].PWM.period_ms=1123;
      pins[1].PWM.last_time=0;
    }

    void setup() {
      init_mas();
      for (uint8_t num=0; num < kol_Pins; num++){
        pinMode(pins[num].Name, OUTPUT);
      }
    }

    void loop() {
      for (uint8_t num=0; num < kol_Pins; num++){
        if (millis() - pins[num].PWM.last_time > pins[num].PWM.period_ms){
          pins[num].PWM.last_time = millis();
          pins[num].State.pulse=~(pins[num].State.pulse); //инвертирование переменной состояния пина
          digitalWrite(pins[num].Name, pins[num].State.pulse);
        }
      }
    }
    т.к. теперь работаем с битами, то можно просто инвертировать 0b1 в 0b0 и работать как с обычным флагом. Если нужно больше состояний (к примеру ехать "налево", "прямо", "направо" и "назад"), т.е. 4 состояния, то выделяем 2 бита и в свитч-case случаи будут 0b00, 0b01, 0b10 и 0b11.
     
    Последнее редактирование: 11 янв 2020
  8. Daniil

    Daniil Гуру

    Почему так, а не так:
    Код (C++):
    for (uint8_t num = 0; num < kol_Pins; num++) {
        if (pins[num].State == 1 && pins[num].fOn == 0) {
          continue;
        }
      }
     
  9. Daniil

    Daniil Гуру

    У вас есть цикл loop, за 1 цикл loop вы пробегаете по всем моторам в цикле for. Не нужно в цикле for выделять какой-то специальный блок под мотор №0, а потом всё равно ждать когда num станет нулём, т.е. ждать когда цикл for завершиться и цикл loop начнётся заново...т.е. этот код будет работать, но каждый раз (для разных num) проверять условие для мотора №0 это трата времени. (Может я не осознаю необходимость?)
     
  10. Daniil

    Daniil Гуру

    Я сам себя запутал "!" оператор логического отрицания, он из истины превращает ложь и на оборот.
    В си неноль это истина, а ноль = ложь.
    Если int i = 2, то это истина. !i = 0 = ложь, а !!i = ? = истина. То есть по сути всё было правильно...
    !!i = 1, для любых i != 0
     
  11. sanik

    sanik Гик

    Работает только так
    Код (C++):
    for (uint8_t num = 0; num < kol_Pins; num++) {  if (pins[0].State == 1 && pins[0].fOn == 0) {// if (num == 0) continue; }
    если так
    Код (C++):
    f (pins[num].State == 1 && pins[num].fOn == 0) {
          continue;
        }
    То эффект тот же что и с break
     
  12. Daniil

    Daniil Гуру

    а чему равны остальные pins[num].fOn? они инициализированы как не ноль?
     
  13. sanik

    sanik Гик

    Оператор continue
    Оператор continue (англ. “продолжить”) досрочно завершает текущую итерацию цикла и переходит к следующей. Например давайте заполним массив, как делали выше, но пропустим один элемент:

    • // создадим массив на 100 ячеек
    • byte myArray[100];
    • for(int i = 0; i < 100; i++){
    • // если i равно 10, пропускаем
    • if(i == 10)continue;
    • // заполним все ячейки значением 25
    • myArray = 25;
      [*]}

    Таким образом элемент под номером 10 не получит значения 25, итерация завершится до операции присваивания.
     
  14. DetSimen

    DetSimen Guest

    Последняя строка: myArray = 25. относится не к программированию, а к разрушительной боевой магии. Да еще в цикле.
     
    parovoZZ и Daniil нравится это.
  15. sanik

    sanik Гик

    Код (C++):
    void init_mas() {
      pins[0].Name = pin1;
      pins[0].State = LOW; // преременная состояния пина под номером 0 Dolly из массива
      pins[0].PWM.period_ms = Velocity_Dolly;//  задержка мотора под номером 0 из массива
      pins[0].PWM.last_time = 0; //  переменная  хранения последнего обновления пина dir Dolly
      pins[0].VLS.periodV_ms = 1; //период наращивания скорости
      pins[0].VLS.prew_time = 0;
      pins[0].ST.step_time = Speed_Dolly; //установленная скорость;
      pins[0].count = 0;
      pins[0].fOn = 1;
      pins[0].fVel = true;
      pins[1].Name = pin2;
      pins[1].State = LOW; // преременная состояния пина под номером 1 Pan из массива
      pins[1].PWM.period_ms = Velocity_Pan; //  начальная скорость Pan
      pins[1].PWM.last_time = 0; // переменная  хранения последнего обновления пина dir Pan
      pins[1].VLS.periodV_ms = 1;
      pins[1].VLS.prew_time = 0;
      pins[1].ST.step_time = Speed_Pan;  //установленная скороость  Pan
      pins[1].count = 0;
      pins[1].fOn = 1;
      pins[2].Name = pin3;
      pins[2].State = LOW; // преременная состояния пина под номером 2 Tilt из массива
      pins[2].PWM.period_ms = Velocity_Tilt; // начальная скорость Pan
      pins[2].PWM.last_time = 0; // переменная  хранения последнего обновления пина dir Tilt
      pins[2].VLS.periodV_ms = 1;
      pins[2].VLS.prew_time = 0;
      pins[2].ST.step_time = Speed_Tilt; //установленная скороость Tilt
      pins[2].count = 0;
      pins[2].fOn = 1;
    }
     
  16. sanik

    sanik Гик

    В изначальной инициализации ошибка компилятора.
    sketch_jan11a:24: error: 'struct pin_t' has no member named 'Num'

    pins[0].Name=pin1; pins[1].Num=pin2;
     
  17. sanik

    sanik Гик

    Я так же посмотрел другой пример)
    Код (C++):
    Пример
    for (x = 0; x < 255; x ++)
    {
        if (x > 40 && x < 120){      // если истина то прыгаем сразу на следующую итерацию цикла
            continue;
        }
        digitalWrite(PWMpin, x);
        delay(50);
    }
     
     
  18. Daniil

    Daniil Гуру

    да это я обозначил пин как Num, а потом цикл сделал с счетчиком num, чтобы не было путаницы переименовал обозначения пина name. Но упустил в некоторых местах.
    А как вы сбрасываете fOn в ноль? Может там ошибка закралась? Я не вижу алгоритмических ошибок в своем коде. Если
    то, мне кажется, это может быть в случае когда все fOn == 0
     
  19. Daniil

    Daniil Гуру

    в примере ошибка, должно быть myArray = 25
    дополнение
    хахаха. Форум проглатывает квадратные скобки с i внутри.
    Скорее всего это из-за html, где i - italic/курсив. Если пихать через теги code
    Код (C++):
    // создадим массив на 100 ячеек
    byte myArray[100];
    for(int i = 0; i < 100; i++){
    // если i равно 10, пропускаем
    if(i == 10)continue;
    // заполним все ячейки значением 25
    myArray[i] = 25;
    }
    Кстати, во всех сообщениях, где есть i в квадратных скобках можно заметить курсив)
     
    Последнее редактирование: 12 янв 2020
  20. sanik

    sanik Гик

    Для пробы сделал самое простое Остальные моторы вообще не трогал :)
    Код (C++):
    if ( pins[0].count == 97982) {
        pins[0].fOn = 0;
      }