Подвисает Motor Drive Shield L293D - нужна помощь

Тема в разделе "Arduino & Shields", создана пользователем Misha1, 14 фев 2017.

  1. Misha1

    Misha1 Нуб

    Здравствуйте, есть проект:

    Управление макетом железной дороги:
    - 4 поезда, каждый на своем кольце. Поезда управляются 1им мотор-шилдом для коллекторных двигателей, вставленным в Arduino (Motor Drive Shield L293D for Arduino http://www.dessy.ru/catalog-pdc380990.html). сигналы на увеличение/уменьшение скорости приходят от 4ех энкодеров
    - освещение домиков(12 В) и фонарей (3В и 5В) на макете и несколько аттракционов (16В ПЕРЕМЕННОЕ напряжение)

    Для управления светом использую реле-шилд (Реле электромеханическое ДО 250V 10 А. 8- канал 5V для Arduino - http://iarduino.ru/shop/rele/rele-elektromehanicheskoe-do-250v-10-a-8--kanal-5v.html)

    Проблемма:
    - при коммутации 16В переменного напряжения (щелкания соответствующего реле по нажатию кнопки) иногда происходит виртуальное нажатие соседних кнопок и включение соответсвующих реле, при том, что кнопки реально не нажимались. При отсоединенных 16В ошибку получить невозможно

    2 дня пытался решать проблему аппаратным путем, вводя фильтры, ферриты и притягивая кнопки через что-только можно ко всему до чего достал.

    проблема была поборота только введением delay(300) при проверке нажатия кнопки вместо millis() (алгоритм был такой: delay блокирует работу программы на время переходных процессов в реле, и что бы не появлялось на входах в это время - сигнал будет игнорироваться),

    но теперь проявилась другая (она и раньше была, просто реже): при размыкании реле 16В иногда замирают все поезда, при этом кнопки отвечающие за свет продолжают всё включать и выключать и стоит лишь коснуться любого энкодера (не важно какого и в какую сторону) все поезда начинают двигаться с предыдущими скоростями.

    Очень похоже, что происходит какая-то пауза в драйвере моторов. Управление происходит библиотекой AFmotor.h (http://voltom.ru/project/89-podklyuchenie-drajvera-dvigatelej-motor-shield-l293d-k-plate-arduino)

    Скорее всего моторы постоянно получают команды с текущими скоростями вращения и возмущение, вызванное размыканием реле, прерывает поток команд.

    Прошу по возможности помочь советом куда копать.
    Знаком с Arduino всего 2 недели, поэтому не судите строго, если нужно код могу выложить, но он большой и, не думаю, что кто-то будет его читать.

    Конроллер: Arduino Mega R3 (Not Original)
    Мотор-шилд: Motor Drive Shield L293D for Arduino (http://www.dessy.ru/catalog-pdc380990.html)
    Библиотека управления: AFmotor.h
    Реле-шилд: ДО 250V 10 А. 8- канал 5V для Arduino (http://iarduino.ru/shop/rele/rele-elektromehanicheskoe-do-250v-10-a-8--kanal-5v.html)
    Энкодеры управляются библиотекой: Encoder.h
     
  2. serg_admin

    serg_admin Гик

    Схему бы и сам скетч. А то вроде понятно но как-то смутно.
    Как 16 вольт коммутируется? и почему переменное?
    Что за энкодеры чем управляются?
     
  3. Misha1

    Misha1 Нуб

    1) 16 В переменное потому что моторы каруселей на макете работают именно от него.
    2) 16 В коммутируется реле как выключателем, только один потребитель, для него отдельный источник напряжения. Эта цепь вообще нигде к остальной не подсоединена.
    3) Энкодеры без кнопки за 200 руб, купленные на рынке, очень похожи на http://crcm.ru/index.php?route=product/product&product_id=16803 управляются библиотекой Encoder.h

    схему нарисовать не могу - не знаю как и где, но там всё суперэлементарно

    4) код следующим сообщением
     
  4. Misha1

    Misha1 Нуб

    #include <Encoder.h> // Подключаем библиотеку для работы с энкодером
    #include <AFMotor.h> // Подключаем библиотеку для работы с Motor Shield L293D


    // ------ МОТОРЫ ------

    // стартовые настройки ПЕРВОГО мотора
    int MaxSpeed1 = 250; // максимальная скорость
    int MinSpeed1 = 10; // скорость при которой двигатель выключается
    int CurentSpeed1 = (MinSpeed1 + 1); // начальная скорость при включении питания
    int EncoderStep1 = 5; // шаг изменения скорости


    // Придумываем имя моторам и объявляем клеммники к которым они подсоединены
    AF_DCMotor my_motor1(1);

    // ------ РЕЛЕ ------

    int Relay1 = 32; // пин, к которому подключено реле №1



    // ------ КНОПКИ ------

    int button1Pin = 48; // номер входа, подключенный к кнопке
    int button1Pressed = 0; // переменная, фиксирующая запустила кнопка процесс или отпустила
    bool button1_state = false; // переменная, фиксирующая состояние кнопкки
    uint32_t ms_button1 = 0;

    // ------ ЭНКОДЕРЫ ------

    Encoder myEnc1(28, 29); // avoid using pins with LEDs attached


    long oldPosition1 = -999; // начальное положение энкодера 1

    // общие стартовые положения и настройки

    void setup()
    {
    Serial.begin(9600);
    Serial.println("Basic Test:");
    pinMode(Relay1, OUTPUT); // инициализируем пин, подключенный к реле, как выход


    pinMode(button1Pin, INPUT); // инициализируем пин, подключенный к кнопке, как вход


    digitalWrite(button1Pin, HIGH); // инициализируем начальное состояние реле - выключено



    digitalWrite(Relay1, HIGH); // инициализируем начальное состояние реле - выключено


    }

    // ------ НАЧАЛО ГЛАВНОГО ЦИКЛА ------

    void loop() {


    // ------ работа с кнопкой 1 ------

    if( digitalRead(button1Pin) == LOW && !button1_state ){
    delay(300);
    button1_state = true;

    // проверяем ЗАПУСКАЕТ кнопка цепь или ОТПУСКАЕТ
    if (button1Pressed == 0) {
    Serial.println("Button 1 pressed once");
    button1Pressed = 1;
    digitalWrite(Relay1, LOW);

    }
    else
    {
    Serial.println("Button 1 pressed twice");
    button1Pressed = 0;
    digitalWrite(Relay1, HIGH);

    }

    }
    // Фиксируем отпускание кнопки
    if( digitalRead(button1Pin) == HIGH && button1_state ){
    delay(300);
    button1_state = false;
    Serial.println("Released button 1");
    }

    // ------конец работы с кнопкой 1 ------

    */
    // --------------------------------- работа с первым энкодером -------------------------
    long newPosition1 = myEnc1.read(); // читаем энкодер 1
    if (newPosition1 != oldPosition1) { // если зафиксирован поворот

    if (newPosition1 > oldPosition1) { // если поворот вправо

    if (CurentSpeed1 > MinSpeed1 && CurentSpeed1 < MaxSpeed1) { // проверка условия достижения максимума
    oldPosition1 = newPosition1;
    CurentSpeed1 = CurentSpeed1 + EncoderStep1;
    Serial.println("Encoder1:");
    Serial.println(CurentSpeed1);
    my_motor1.setSpeed(CurentSpeed1); // задаем скорость вращения двигателя
    my_motor1.run(FORWARD); // вращаем
    }

    if (CurentSpeed1 >= MaxSpeed1){ // если вышли за верхний предел
    oldPosition1 = newPosition1;
    my_motor1.setSpeed(MaxSpeed1); // задаем скорость вращения двигателя
    my_motor1.run(FORWARD); // вращаем вперед
    Serial.println("Encoder1: Already max speed");
    CurentSpeed1 = (MaxSpeed1 - 1);
    Serial.println("Encoder1:");
    Serial.println(CurentSpeed1);
    }
    }

    if (newPosition1 < oldPosition1) { // если поворот влево

    if (CurentSpeed1 > MinSpeed1 && CurentSpeed1 < MaxSpeed1) { // проверка условия достижения максимума
    oldPosition1 = newPosition1;
    CurentSpeed1 = CurentSpeed1 - EncoderStep1;
    Serial.println("Encoder1:");
    Serial.println(CurentSpeed1);
    my_motor1.setSpeed(CurentSpeed1); // задаем скорость вращения двигателя
    my_motor1.run(FORWARD); // вращаем
    }

    if (CurentSpeed1 <= MinSpeed1){ // если вышли за нижний предел
    my_motor1.run(RELEASE); // останавливаем мотор
    Serial.println("Encoder1: Already stoped");
    CurentSpeed1 = MinSpeed1 + 1;
    Serial.println("Encoder1:");
    Serial.println(CurentSpeed1);
    }

    }

    }

    // --------------------------------- работа с первым энкодером -------------------------

    }
     
  5. serg_admin

    serg_admin Гик

    1. В коде не вижу ни каких других кнопок, но если у тебя не "мокрый контакт", то должна быть защита от "дребезга" : delay(как у тебя), возможно конденсатор.
    2. Думаю в момент размыкания проходит сбой питания процессора. Проверь вывод, в RS232 должно даваться стартовое сообщение "Basic Test:". При сдвиге энкодера поезда начинают двигаться с прежней скоростью потому, что память не сбрасывается. Теоретически процессор может работать до 3.3 вольта, но при частоте 16 MHz будет перезагружаться.
    3. Схему можно нарисовать карандашом и выложить фотографию
     
    Последнее редактирование: 15 фев 2017
  6. Misha1

    Misha1 Нуб

    1) по кнопкам - их там 4, просто форум не позволяет залить весь код - я удалил все кратные куски кода (из 4ех одинаковых кнопок оставил одну, из 4ех моторов - один, из 4ех энкодеров - один)
    кнопки подключены через встроенные подтягивающие резисторы (20 кОм) и параллельно поставлены внешние по 1 кОм

    2) вывод проверил - процессор не перегружается, сообщения соответствующие старту программы "Basic Test" не выводятся, просто появляются следующие значения энкодера. Питание arduino взял вообще из другой розетки.

    p.s. обратил внимание, что на один щелчок энкодера появляется 4 значения (т.е. при 1 щелчке скорость меняется на 4 позиции, а не на 1 как задумано)

    3) схема вот
    [​IMG]
     
  7. serg_admin

    serg_admin Гик

    В описании библиотеки encoder написано что есть режим 4x - видимо это он.
    Еще рекомендуют для точной производительной работы сделать так

    // This optional setting causes Encoder to use more optimized code,
    // It must be defined before Encoder.h is included.
    #define ENCODER_OPTIMIZE_INTERRUPTS
    #include <Encoder.h>
     
    Последнее редактирование: 15 фев 2017
  8. serg_admin

    serg_admin Гик

    И еще одно интересное замечание

    With Arduino Uno, Duemilanove or Mega, Serial.print() can cause trouble. Arduino 1.0 provides transmit buffering, which works much better than Arduino 0023 and earlier. With either, a high speed baud rate should be used, and minimizing the amount of data transmitted helps.

    Иными словами сделайте скорость обмена больше чем 9600.
    Например 19200, 38400, 57600, 115200.
     
  9. serg_admin

    serg_admin Гик

    На счет кода. Вроде есть кнопка загрузить файл. Через нее не получится?
    Подозреваю, что я там ни чего неправильного не найду, но все таки...
     
  10. Misha1

    Misha1 Нуб

    а можно ссылку на описание библиотеки Encoder.h
     
  11. Misha1

    Misha1 Нуб

    код по ссылке "присоединить код" не позволяет загрузить больше 10 000 символов, полный код в приложении
     

    Вложения:

  12. serg_admin

    serg_admin Гик

    Код (C++):
    http://playground.arduino.cc/Main/RotaryEncoders
     
  13. serg_admin

    serg_admin Гик

    Пришла мысль. Моторы могут остановиться если завис ШИМ. Почему завис не понятно (недра чужих библиотек), но судя по Вашему описанию он презапускается командой
    Код (C++):
     my_motor3.setSpeed(CurentSpeed3);
    или подобными

    Если эту команду поместить куда-нибудь в loop где она будет выполнятся без условно. Возможно это решит проблему. И на работу программы большого влияние не окажет.
     
  14. Misha1

    Misha1 Нуб

    спасибо за предположение, я тоже так думаю. Сейчас всё разобрал до 0, буду собирать по этапам и проводить полные тесты после каждого присоединения. Тоже считаю, что ШИМ зависает, но ловит он программный косяк или аппаратный понять пока не могу
     
  15. Misha1

    Misha1 Нуб

    экспериментировал сегодня только с одним реле, одной кнопкой и одним энкодером - результаты удивительные:

    - если отключить коммутируемые 16В от реле, сколько кнопкой не клацай - сбой не происходит (поезд ездит без остановок)
    - если оставить кнопку во включенном положении и включать/выключать реле с подключенными 16В просто вставляя/вынимая провод в соответствующем пине ардуино - сбоя тоже добиться не получается

    Но если все соединить (кнопка - ардуино - реле - нагрузка 16 В) иногда происходит зависание ШИМ (поезд замирает, а при касаниии энкодера начинает движение с прежней скоростью).

    Буду копать дальше, о результатах должу)
     
  16. Misha1

    Misha1 Нуб

    итоги:
    всё разобрал, оставил только:
    - Ардуину,
    - шилд с реле (никакой нагрузки не подключено, используется 1 реле как индакатор нажатия кнопки)
    - 1 кнопку - работает по 3 (третьему) прерыванию на 20 пине - подтянута к земле через внешние 10 кОм

    Во время эксперимента Ардуина питается от ноутбука, в эксперименте просто рядом с кнопкой соединяю провода НИКАК не связанного источника питания переменного напряжения 16В 500мА, который питает рядом лежащий мотор и, вуаля, реле щелкает (не всегда, но достаточно стабильно)! Тоже самое происходит если рядом включить дрель или любой другой потребитель переменного напряжения.

    Вот код, там ошибок, вроде, быть не может:

    Код (C++):
    volatile int state2 = HIGH;

    void button2()  // задаем функцию, которая будет происходить по факту наступления события в прерывании
    {
      static unsigned long millis_prev2;
      if(millis()-300 > millis_prev2) state2 = !state2;   // меняем значение на противоположное
      millis_prev2 = millis();      
    }

    void setup()
    {
      attachInterrupt(3, button2, RISING);    // привязываем 3-е прерывание к функции button2().
      digitalWrite(20, LOW);

      pinMode(35, OUTPUT);    // инициализируем пин, подключенный к реле, как выход
      digitalWrite(35, HIGH);       // инициализируем начальное состояние реле - выключено
     

    }

    // ------ НАЧАЛО ГЛАВНОГО ЦИКЛА ------

    void loop() {

      digitalWrite(35, state2);          // выводим state

    }
     
  17. Misha1

    Misha1 Нуб

    Проблема решена!
    В коде выше ошибочно обрабатывается дребезг контактов.
    Обработал через библиотеку Bounce - проблема исчезла.

    Стартовая проблема тоже решена - был конфликт библиотеки энкодеров Encoder.h c портом Serial.
    Переписал обработчик энкодеров - работает отлично (пример вот здесь: http://cxem.net/arduino/arduino8.php)

    Вот, кстати, обсуждалась похожая проблема:
    http://forum.amperka.ru/threads/Энкодер-на-arduino.10550/