Где может быть ошибка кода?

Тема в разделе "Arduino & Shields", создана пользователем sanik, 8 окт 2013.

  1. Megakoteyka

    Megakoteyka Оракул Модератор

    Нужно просто идти по алгоритму по порядку и мысленно выполнять действия.
    Первые 7 режимов же получилось описать - почему дальше не получается?
    Вот, например, режим 8. Сперва сделали паузе, затем проверили, нажата ли кнопка "стоп".
    А нужно проверять, не нажалась ли кнопка "стоп", пока не пройдет определенное время. Если кнопку не нажали - идем в следующий режим. Если нажалась - идем в режим 2.
    Алгоритм должен быть похож на ветку режима 7, только нижняя проверка должна проверять, не прошло ли нужное количество времени (таймаут нажатия кнопки). Если время истекло - проваливаемся дальше, если не истекло - идем наверх к проверке нажатия на кнопку "стоп".
     
  2. sanik

    sanik Гик

    Да алгоритм я давно переделал
     

    Вложения:

    • controler2.zip
      Размер файла:
      5,1 КБ
      Просмотров:
      260
  3. Megakoteyka

    Megakoteyka Оракул Модератор

    Извиняюсь, замотался малость :(
    Режим 9: счетчик только один раз уменьшается на 1 и все, потом переходим к режиму 10. разве так и задумано?
    Таймер exposure - как Вы его программировать будете? По алгоритму совершенно непонятно, как таймер будет работать. Любое действие можно сделать при помощи блоков "действие" и "вопрос", лучше их и использовать, проще будет код писать потом.
    Первые 8 веток удалось запрограммировать?
     
  4. sanik

    sanik Гик

    Да режим 9 так и задуман.
    Если б я знал как? Уже отстал от этой идеи самостоятельно сделать, не по моим зубам это все... Пусть все умрет мертвым грузом.Я походу дела уже смирился с этим. Или буду наедятся что когда нибудь найду, того кто сможет справиться с этим...
     
  5. Megakoteyka

    Megakoteyka Оракул Модератор

    Вместо использования непонятного блока "таймер" можно сначала записать в переменную текущее время, прибавить к нему длительность желаемой задержки, а в нужный момент проверять, не сравнялось ли текущее время с тем, которое записано в переменной. если сравнялось или стало больше - интервал прошел, идем дальше. Если текущее время меньше того, что записано в переменной, продолжаем крутиться.
    Не стоит опускать руки, осталось совсем немного и настанет понимание :)
     
  6. Megakoteyka

    Megakoteyka Оракул Модератор

    Код (Text):
    #include <Bounce.h>

    // время подавления дребезга кнопок, мс
    #define DEBOUNCE_INTERVAL 20

    // номера пинов для кнопок
    #define PIN_BTN_SELECT ...
    #define PIN_BTN_PLUS  ...
    #define PIN_BTN_MINUS  ...

    // максимальные значения
    #define MAX_POS_VALUE      ...// для положения каретки
    #define MAX_PAUSE_VALUE    ...// для времени паузы
    #define MAX_EXPOSURE_VALUE ...// для времени экспозиции

    // шаги алгоритма
    typedef enum STEPS {
      STEP1_HELLO,
      STEP2_GET_POTS,
      STEP3_GET_POSITION,
      STEP4_GET_PAUSE,
      STEP5_GET_EXPOSURE,
      STEP6_GET_COUNT;
    };

    // текущий шаг алгоритма
    STEPS currentStep = STEP1_HELLO;

    // создаем "давилки дребезга" для кнопок
    Bounce bouncerBtnSelect(PIN_BTN_SELECT, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnPlus(PIN_BTN_PLUS, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnMinus(PIN_BTN_MINUS, DEBOUNCE_INTERVAL);

    void setup()
    {
      Serial.begin(9600);
    }

    int pot1Value  = 0; // значение потенциометра 1
    int pot2Value  = 0; // значение потенциометра 1
    int posValue  = 0; // значение положения каретки
    int pauseValue = 0; // значение времени паузы
    int exposValue = 0; // значение времени экспозиции
    int countValue = 0; // значение количества кадров

    void loop()
    {
      bouncerBtnSelect.update();
      bouncerBtnPlus.update();
      bouncerBtnMinus.update();

      switch(currentStep)
      {
        case STEP1_HELLO:
          Serial.println("Привет! Переходим к шагу 2");
          currentStep = STEP2_GET_POTS;
          break;
       
        case STEP2_GET_POTS:
          // проверяем, нажата ли кнопка
          if(bouncerBtnSelect.read() == HIGH)
          {
            pot1Value = analogRead(...);
            pot2Value = analogRead(...);
            Serial.println("Прочитаны значения потенциометров! Переходим к шагу 3");
            currentStep = STEP3_GET_POSITION;
          }
          break;
       
        case STEP3_GET_POSITION:
          // кнопка нажата и значение меньше максимально допустимого?
          if(bouncerBtnPlus.read() == HIGH && posValue < MAX_POS_VALUE)
            posValue++;
          // кнопка нажата и значение больше минимально допустимого (нуля)?
          if(bouncerBtnMinus.read() == HIGH && posValue > 0)
            posValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("Установлено положение каретки! Переходим к шагу 4");
            currentStep = STEP4_GET_PAUSE;
          }
          break;
       
        case STEP4_GET_PAUSE:
          if(bouncerBtnPlus.read() == HIGH && pauseValue < MAX_PAUSE_VALUE)
            pauseValue++;
          if(bouncerBtnMinus.read() == HIGH && pauseValue > 0)
            pauseValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 5");
            currentStep = STEP5_GET_EXPOSURE;
          }
          break;
       
        case STEP5_GET_EXPOSURE:
          if(bouncerBtnPlus.read() == HIGH && exposValue < MAX_EXPOSURE_VALUE)
            exposValue++;
          if(bouncerBtnMinus.read() == HIGH && exposValue > 0)
            exposValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 6");
            currentStep = STEP6_GET_COUNT;
          }
          break;
       
        case STEP6_GET_COUNT:
       
          break;
      }
    }
    Сравните со своей ДРАКОН-схемой. Похоже?
    Расставьте отладочный вывод (Serial.print...), напишите подробные комментарии и переходите к следующим веткам.
    Используйте такой прием: дописав маленький кусочек кода, проверьте правильность его работы, затем переходите к следующему. Если возникнет ошибка - всегда будете знать, что она сидит в последнем написанном куске, так как до него все работало правильно.
     
    Unixon нравится это.
  7. Unixon

    Unixon Оракул Модератор

    Ну вы же знаете, как оно должно быть. Если уж совсем зашли в тупик, ОК, опишите любыми словами как вы себе представляете работу с этой установкой. Вот просто скопируйте все мысли из головы как есть. Оставьте алгоритм в покое раз он не получается. С работой пунктов меню в общем то все понятно, это штука простая. Что вы пытались реализовать в synchronize() - немного понятно из кода, во что в итоге превратился processAnalog() - непонятно, какая в механике установки взаимосвязь между частями и нафига онцевикам нужны какие то координаты (520 530 540), когда они (концевые микропереключатели) и так просто тупо срабатывают. Вы их наличие моделировали в коде при их физическом отсутствии в конструкции установки?

    sanik, вы только не сдавайтесь, все получится, осталось всего чуть-чуть.
     
    Megakoteyka нравится это.
  8. sanik

    sanik Гик

    Концевик был реализован по типу четырех кнопок на аналоговом входе (теперь уже две кнопки), Установка такая: Вручную просто тупо гоняю каретку с помощью потенциометра влево в право, достиг концевика остановка каретки это и есть processAnalog(), это для сьемки простого видео, а для сьемки таймлапса переключаемся в меню устанавливаем значение обратной связи перемещения двигателя (он должен продвигаться минимум 0,5mm ) далее устанавливаем значение паузы , потом значение экспозиции, и значение количества кадров и перемещений каретки. Стартуем, на экране вывод оставшего количества кадров выдерживается таймер пауза, далее выдерживается таймер экспозиции за это время отрабатывают две релюшки по окончанию времени релюшки обесточиваются, снова выдерживается таймер пауза и в это же время начинает двигаться каретка ( первая пауза без движения каретки) продвинулась остановилась, снова таймер экспозиции и релюшки, и опять пауза и движение каретки до тех пор пока не закончится установленное количество кадров или не нажата кнопка стоп...
     
  9. sanik

    sanik Гик

    Вот в чем проблема мне никак было не описать режим2, так то теперь понятно примерно что в коде писать но привязка значений потенциометра к остальным режимам не нужна, в этом режиме просто двигаем каретку туда сюда а при нажатии setup это значение должно быть pot1Value =0 в этот момент потенциометр отключается он больше не нужен дальше мотором управляет int posValue = 0; а потенциометр pot2Value по моему лишний так как я говорил что ось Х я решил убрать. Или я опять чего то не понимаю... В алгоритме наверное должно быть так.
     

    Вложения:

    • controler2.zip
      Размер файла:
      5,2 КБ
      Просмотров:
      276
    Последнее редактирование: 21 окт 2013
  10. Unixon

    Unixon Оракул Модератор

    Так я и не понял. Концевик - это у вас реальная деталь в установке (выключатель, кнопка) или просто условие в программе, симуляция реального концевика?
     
  11. sanik

    sanik Гик

    Два выключателя на одном аналоговом пине немного неправильно нарисовал:) Один концевик analogRead 534-543 Второй analogRead 450-459
     

    Вложения:

  12. Unixon

    Unixon Оракул Модератор

    Где они физически расположены? На торцах рельса, по которому каретка ездит ?
     
  13. Megakoteyka

    Megakoteyka Оракул Модератор

    Нужно это дело запрограммировать в виде отдельного скетча, отладить, а затем просто вставить в нужную ветку switch.
     
  14. sanik

    sanik Гик

    Да.
     
  15. sanik

    sanik Гик

    Так, с этим понятно это у меня есть готовое и рабочее только поменять название переменой,а как сделать что бы каретка парковалась сама при нажатии кнопки setup то есть отключаем зависимость от потенциометров и едим в право до концевика?
    Код (Text):
    {
      x = analogRead(PIN_POS_X); // считываем сзначение потециомера и записываем в переменую х
      if(x <= 511) // если х меньше или равно 511 то,
      {
        a = (511 - x) * 2;  //
      }
      else
      {
        a = (x - 511) * 2;
      }
      rewX = analogRead(PIN_POS_X); // читаем показания потециомера и записываем в rewX
      if (rewX > 500)  // если показания меньше 520 то,
      {
        PinLOWx = HIGH; // запускаем мотор в одном направлении
        PinHIGHx = LOW;
      }
      if (rewX < 530 )  // если показания больше 520 то,
      {
        PinLOWx = LOW; // реверсим мотор
        PinHIGHx = HIGH;
      }
      else if(rewX >= 500 && rewX < 530) //иначе если показания между 510 и 520 то,
      {
        PinLOWx = LOW; // останавливаем мотор
        PinHIGHx = LOW;
      }
      digitalWrite(PIN_IN3, PinLOWx);
      digitalWrite(PIN_IN4, PinHIGHx);
      analogWrite(PIN_ENB, a/4);
    }
     
  16. Megakoteyka

    Megakoteyka Оракул Модератор

    Код (Text):
    x = analogRead(PIN_POS_X);
    rewX = analogRead(PIN_POS_X);
    зачем одно и то же хранить в двух разных переменных?

    Код (Text):
     if (rewX > 500)  // если показания меньше 520 то,
      {
        PinLOWx = HIGH; // запускаем мотор в одном направлении
        PinHIGHx = LOW;
      }
      if (rewX < 530 )  // если показания больше 520 то,
      {
        PinLOWx = LOW; // реверсим мотор
        PinHIGHx = HIGH;
      }
      else if(rewX >= 500 && rewX < 530) //иначе если показания между 510 и 520 то,
      {
        PinLOWx = LOW; // останавливаем мотор
        PinHIGHx = LOW;
      }
    Вот тут совсем непонятно. Значения в условиях не сходятся с комментариями, как работать должно?
    Ветка else никогда не выполнится: мы в нее попадем только в том случае, если rewX >= 530, но тогда не выполнится условие if(rewX >= 500 && rewX < 530).


    Код (Text):

    // принцип работы:
    // DIR_1 ... 510 ... STOP ... 520 ... DIR_2

    // если rewX в пределах [510; 520] - остановить мотор
    if(rewX >= 510 && rewX <= 520)
      StopMotor();
    // если rewX в пределах (0; 510) - крутить в направлении 1
    if(rewX < 510)
      RunMotor(DIR_1);
    // если rewX в пределах (520; 0) - крутить в направлении 2
    if(rewX > 520)
      RunMotor(DIR_2);
    Так похоже на задуманное?
     
    Последнее редактирование: 21 окт 2013
  17. sanik

    sanik Гик

    Да похоже. Вот откуда мне знать что можно управлять намного проще!
     
  18. Megakoteyka

    Megakoteyka Оракул Модератор

    Я тоже на все грабли наступил в свое время, все приходит с опытом, не надо переживать.
    Меньше нервов, больше размышлений!
    Если задача никак не решается - есть смысл ее на время отложить и вернуться позже, имея бодрый вид и свежий взгляд. И не забывайте метод Цезаря - "разделяй и властвуй". Почти любую задачу можно разбить на множество мелких кусочков, каждый из которых осилить гораздо легче, а потом из кусочков сложить целое.
     
  19. sanik

    sanik Гик

    Так вроде немного продвинулся, а как быть со скоростью?
    Код (Text):
    #include <Bounce.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27,16,2);

    // время подавления дребезга кнопок, мс
    #define DEBOUNCE_INTERVAL 20

    // номера пинов для кнопок
    #define btn_SELECT 3
    #define btn_PLUS  7
    #define btn_MINUS  6
    #define btn_START  4
    #define btn_STOP 2
    // номера пинов мотора
    #define pin_A 10
    #define pin_B 11
    #define pin_ENABLE 12
    // пин потенциометра
    #define pin_dist A1
    // пин фотоинтераптора
    #define pin_pos
    // максимальные значения
    #define MAX_POS_VALUE      ...// для положения каретки
    #define MAX_PAUSE_VALUE    ...// для времени паузы
    #define MAX_EXPOSURE_VALUE ...// для времени экспозиции

    // шаги алгоритма
    typedef enum STEPS {
      STEP1_HELLO,
      STEP2_GET_POTS,
      STEP3_GET_POSITION,
      STEP4_GET_PAUSE,
      STEP5_GET_EXPOSURE,
      STEP6_GET_COUNT;
    };

    // текущий шаг алгоритма
    STEPS currentStep = STEP1_HELLO;

    // создаем "давилки дребезга" для кнопок
    Bounce bouncerBtnSelect(btn_SELECT, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnPlus(btn_PLUS, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnMinus(btn_MINUS, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnStart(btn_START, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnStop(btn_STOP, DEBOUNCE_INTERVAL);
    void setup()
    {
      Serial.begin(9600);
      lcd.init();lcd.backlight();lcd.clear(); // инициализация дисплея, включаем подсветку, очищаем экран
    }

    int potValue  = 0; // значение потенциометра 1
    int pot2Value  = 0; // значение потенциометра 1
    int posValue  = 0; // значение положения каретки
    int pauseValue = 0; // значение времени паузы
    int exposValue = 0; // значение времени экспозиции
    int countValue = 0; // значение количества кадров

    void hello()
    {
      lcd.setCursor(5, 0);lcd.print("Hello");delay(200);// установка курсора, печать надписи, задержка на 200 мс.
      lcd.setCursor(0, 1);lcd.print(" Slider Timelaps");delay(2000);
      lcd.clear();// очистка дисплея.
    }
    void RunMotor1()
    {
    digitalWrite (pin_A, LOW);
    digitalWrite(pin_B, HIGH);
    }
    void RunMotor2()
    {
      digitalWrite (pin_A, HIGH);
      digitalWrite(pin_B, LOW);
    }
    void StopMotor()
    {
      digitalWrite(pin_ENABLE, LOW);
    }
    void ENABLE()


    void loop()
    {
      bouncerBtnSelect.update();
      bouncerBtnPlus.update();
      bouncerBtnMinus.update();
      bouncerBtnStart.update();
      bouncerBtnStop.update();
      switch(currentStep)
      {
        case STEP1_HELLO:
          hello();
          currentStep = STEP2_GET_POTS;
          break;
     
        case STEP2_GET_POTS:
          // проверяем, нажата ли кнопка
          if(bouncerBtnSelect.read() == HIGH)
          {
            potValue = analogRead(pin_dist A1);
            if(potValue >= 510 && potValue <= 520)// если rewX в пределах [510; 520] - остановить мотор
            StopMotor();
            if(potValue < 510)// если rewX в пределах (0; 510) - крутить в направлении 1
            RunMotor1();
            if(potValue > 520)// если rewX в пределах (520; 0) - крутить в направлении 2
            RunMotor2();
            Serial.println("Прочитаны значения потенциометров! Переходим к шагу 3");
            currentStep = STEP3_GET_POSITION;
          }
          break;
     
        case STEP3_GET_POSITION:
          // кнопка нажата и значение меньше максимально допустимого?
          if(bouncerBtnPlus.read() == HIGH && posValue < MAX_POS_VALUE)
            posValue++;
          // кнопка нажата и значение больше минимально допустимого (нуля)?
          if(bouncerBtnMinus.read() == HIGH && posValue > 0)
            posValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("Установлено положение каретки! Переходим к шагу 4");
            currentStep = STEP4_GET_PAUSE;
          }
          break;
     
        case STEP4_GET_PAUSE:
          if(bouncerBtnPlus.read() == HIGH && pauseValue < MAX_PAUSE_VALUE)
            pauseValue++;
          if(bouncerBtnMinus.read() == HIGH && pauseValue > 0)
            pauseValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 5");
            currentStep = STEP5_GET_EXPOSURE;
          }
          break;
     
        case STEP5_GET_EXPOSURE:
          if(bouncerBtnPlus.read() == HIGH && exposValue < MAX_EXPOSURE_VALUE)
            exposValue++;
          if(bouncerBtnMinus.read() == HIGH && exposValue > 0)
            exposValue--;
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 6");
            currentStep = STEP6_GET_COUNT;
          }
          break;
     
        case STEP6_GET_COUNT:
     
          break;
      }
    }
     
  20. Megakoteyka

    Megakoteyka Оракул Модератор

    Тогда немного иначе: мы должны постоянно попадать в ветку STEP2_GET_POTS, а перестаем в нее попадать только тогда, когда нажмется кнопка.
    Код (Text):

        case STEP2_GET_POTS:
            potValue = analogRead(pin_dist A1);
            if(potValue >= 510 && potValue <= 520)// если rewX в пределах [510; 520] - остановить мотор
                StopMotor();
            if(potValue < 510)// если rewX в пределах (0; 510) - крутить в направлении 1
                RunMotor1();
            if(potValue > 520)// если rewX в пределах (520; 0) - крутить в направлении 2
                RunMotor2();
            Serial.println("Каретка установлена! Переходим к шагу 3");

            // проверяем, нажата ли кнопка
            if(bouncerBtnSelect.read() == HIGH)
                currentStep = STEP3_GET_POSITION;
        break;
    Для управления скоростью постараюсь вечером примерный код накатать, когда с работы вернусь.
    Общая идея такая: от положения потенциометра должна зависеть длительность работы мотора и длительность паузы в работе мотора. Эти длительности придется подбирать экспериментально.
    Будем запоминать время включения мотора и прибавлять к нему длительность работы, а затем следить, когда текущее время сравняется с тем, которое запомнили, и в этот момент выключать мотор. То же самое с паузой в работе мотора.
    В итоге, регулируя потенциометрами эти длительности, заставим мотор вращаться с необходимой нам средней скоростью.