Делаем систему «Умный дом» на Arduino

Тема в разделе "Глядите, что я сделал", создана пользователем adatum, 26 мар 2013.

  1. ИгорьК

    ИгорьК Гуру

    Скажите скорее, что надо сделать для помощи? Вы правы, правы, правы!
    Есть только два великих проекта, этот и Ардуино мега сервер! http://forum.amperka.ru/threads/arduino-mega-server.6850/
    Именно эти два проекта заставляют сердце учащенно биться а дыхание может прервааться!
    Чем помочь? Хотите, я по понедельникам буду поднимать эту тему, как постоянно находящийся на этом форуме?
    Чтобы вам каждый раз не приходилось регистрироваться, я же все равно здесь?
     
  2. Виталик

    Виталик Нерд

    Ну почему бы и нет! А мне, достаточно одной регистрации)
     
  3. ИгорьК

    ИгорьК Гуру

    Ок. Буду поднимать эту фейковую тему с ошибкой в первой же картинке вверх.
     
  4. Defender

    Defender Нерд

    Стоит задача разработать некую имитацию умного дома.
    Из чего состоит дом:
    1) фоторезистор: в зависимости от освещённости включается лампа и поворачивается сервопривод на необходимый угол (имитирует работу открытия/закрытия жалюзи).
    2) Датчик вибрации: включает лампу при появлении вибрации (имитирует разбитие окна). Используется датчик SW - 420. С ним возникла отдельная проблема, которую мне помогли решить в этой теме http://forum.amperka.ru/threads/Работа-с-датчиком-вибрации-sw-420.8445/.
    3) Датчик громкости звука: поворачивает сервопривод в зависимости от громкости звука (имитирует закрытие/открытие окна при появлении шума снаружи дома). Имеет аналоговый сигнал на выходе.
    4) Ультразвуковой дальномер: включает/выключает лампу (имитирует подсветку лестницы). Обычный HC-SR 04.
    5) Потенциометр имитирующий температуру пола: включает лампу при достижении уставки
    6) Потенциометр имитирующий температуру снаружи дома: включает лампу при достижении уставки
    7) Потенциометр имитирующий температуру внутри дома: включает лампу при достижении уставки и плюс включает вентилятор
    8) Датчик движения: включает лампу при появлении движения.

    Платформа: Arduino Mega 2560
    Для 7 ламп (220 В) и вентилятора (12 В) используется 8 реле. Для стабильного питания платформы используется стабилизатор на 5 А. Сам стабилизатор подключён к блоку питания на 36 Вт.

    Проблема заключается в следующем. Когда я всё собрал и залил программу, то сразу возникла нестабильная работа проекта, которая заключалась в том, что он включался и выключался примерно через каждые 2 секунды. Вначале подумал, что не хватает мощности. Заменил блок питания на компьютерный (230 Вт). Ничего не изменилось. Проверил напряжение на стабилизаторе. Оно не изменялось при самопроизвольном включении/выключении проекта. Так что и эта версия отпала. "Помехи" - подумал я. Было предпринято следующее: 1) подключены керамические конденсаторы на аналоговые пины и соединены с землёй. 2) подключены резисторы к управляющим сигналам ведущим к реле для того чтобы они не висели в воздухе и соединены с питанием 5В.
    Это почти помогло, возникла следующая ситуация: проект самопроизвольно перестал отключаться/включаться, но он стал это делать при работе одного из датчиков. Например, я кручу один из потенциометров и БАЦ! - всё отключается на пол секунды, потом включается, вновь отключается с тем же интервалом и опять включается, затем стабильная работа восстанавливается, всё вроде бы работает, создаю движение, лампа загорается, меняю освещённость другая лампа загорается и поворачивает сервопривод, создаю вибрацию и БАЦ опять всё отключается и вновь включается и стабильно дальше работает, какое-то время, затем всё повторяется при работе любого из датчиков.
    Было замечено, что когда проект в этот момент отключается, светодиод на 13 пине тоже гаснет, что привело на мысль о том, что микроконтроллер не справляется с таким количеством сигналов поступающих на него. Поэтому в программе (она представлена ниже) были сделаны задержки на измерение некоторыми датчиками. Это привело к сильному сокращению случаев возникновения отключения-включения проекта, но эти случаи по прежнему остались, хоть и носят уже гораздо более редкий характер. Последовательный ввод каждого из датчиков в проект также не выявил ничего подозрительного. В какой-то момент чем больше их становилось, тем больше возникало случаев нестабильной работы.
    Стоит также отметить, что я не совсем доволен работой датчика громкости звука, его показания, как-то не очень хорошо изменяются. Хотелось бы чтобы он работал так: например есть 3 диапазона его аналоговых значений: 1) 570-590 2) 570-500 3) 500-400. Каждому из которых соответствовал бы угол поворота сервопривода. Но пока, что удалось реализовать только такой код, указанный в программе и сервопривод работает, как-то странно.
    Простите, за столь много слов, хотел очень подробно описать возникшую ситуацию. Помогите пожалуйста разобраться с этой многозадачностью. Первый раз делаю, нечто более, чем подключение одного или двух датчиков. Как действовать, когда столько сигналов необходимо обрабатывать МК?


    Код (C++):

    #include <Servo.h>
    Servo servo_jal; // сервопривод жалюзи
    Servo servo_win; // сервопривод окна

    int echoPin = 10;
    int trigPin = 9;

    bool vibration = false; // флаг есть вибрация или нет
    unsigned long now; // время когда появилась вибрация

    long unsigned int lowIn; // время в которое был принятсигнал отсутствия движения
    long unsigned int pause = 3000; // пауза после которой движение считается оконченным
    boolean lockLow = true; // если false, то движение обнаружено, если наоборот, то известно что движения нет
    boolean takeLowTime; // запомнить время начала отсутствия движения


    #define STREET_LIGHT 22 // уличное освещение
    #define POL_PIN 46 // тёплый пол
    #define HOT_PIN 38 // система отопления
    #define SPLIT_PIN 34 // сплит-система
    #define FLOOR_PIN 42 // подсветка ступеней
    #define VENT_PIN 30 // вентилятор
    #define WINDOW 50 // окно
    #define WORK_PIN 26 // освещение рабочей поверхности

    #define LDR_PIN A3 // фоторезистор
    #define TEMP_POLA A2 // потенциометр температура пола
    #define TEMP_OUT A1 // потенциометр температура снаружи дома
    #define TEMP_IN A0 // потенциометр температура внутри дома
    #define VIB_PIN 6 // датчик вибрации
    #define MOOVE_PIN 7 // датчик движения
    #define SOUND_APIN A4 // датчик шума аналоговый сигнал
    #define SOUND_DPIN 8 // датчик шума цифровой сигнал


    /* Временные задержки для измерения датчиков */
    long previousMillis = 0; // время когда производилось последнее измерение фоторезистором
    long interval = 500; // интервал измерения фоторезистора

    long previousMillis1 = 0; // время когда производилось последнее измерение показаний потенциометра температуры пола
    long interval1 = 50; // интервал измерения показаний потенциометра температуры пола

    long previousMillis2 = 0; // время когда производилось последнее измерение показаний потенциометра температуры снаружи
    long interval2 = 50; // интервал измерения показаний потенциометра температуры снаружи

    long previousMillis3 = 0; // время когда производилось последнее измерение показаний потенциометра внутри дома
    long interval3 = 50; // интервал измерения показаний потенциометра внутри дома

    long previousMillis4 = 0; // время когда производилось последнее измерение ультразвуковым дальномером
    long interval4 = 500; // интервал измерения ультразвукового дальномера


    void setup ()
    {
    pinMode(STREET_LIGHT, OUTPUT);
    pinMode(POL_PIN, OUTPUT);
    pinMode(HOT_PIN, OUTPUT);
    pinMode(SPLIT_PIN, OUTPUT);
    pinMode(FLOOR_PIN, OUTPUT);
    pinMode(VENT_PIN, OUTPUT);
    pinMode(WINDOW, OUTPUT);
    pinMode(WORK_PIN, OUTPUT);

    pinMode(LDR_PIN, INPUT);
    pinMode(TEMP_POLA, INPUT);
    pinMode(TEMP_OUT, INPUT);
    pinMode(TEMP_IN, INPUT);
    pinMode(VIB_PIN, INPUT);
    pinMode(MOOVE_PIN, INPUT);
    pinMode(SOUND_APIN, INPUT);
    pinMode(SOUND_DPIN, INPUT);

    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);

    servo_jal.attach(4);
    servo_win.attach(5);

    Serial.begin(9600);
    }


    void loop ()
    {
    unsigned long currentMillis = millis();


    /* Работа фоторезистора */
    if(currentMillis - previousMillis > interval)
    {
    int lightness = analogRead(LDR_PIN); // показания фоторезистора
    int jal = map(lightness, 0, 1023, 0, 180);
    servo_jal.write(jal);

    if(lightness < 950)
    digitalWrite(STREET_LIGHT, HIGH);
    else
    digitalWrite(STREET_LIGHT, LOW);
    previousMillis = currentMillis;
    }


    /* Работа потенциометра "Температура пола" */
    if(currentMillis - previousMillis1 > interval1)
    {
    int pol = analogRead(TEMP_POLA);
    if(pol > 200)
    digitalWrite(POL_PIN, HIGH);
    else
    digitalWrite(POL_PIN, LOW);
    previousMillis1 = currentMillis;
    }


    /* Работа потенциометра "Температура снаружи" */
    if(currentMillis - previousMillis2 > interval2)
    {
    int hot = analogRead(TEMP_OUT);
    if(hot < 700)
    digitalWrite(HOT_PIN, HIGH);
    else
    digitalWrite(HOT_PIN, LOW);
    previousMillis2 = currentMillis;
    }


    /* Работа потенциометра "Температура внутри" */
    if(currentMillis - previousMillis3 > interval3)
    {
    int split = analogRead(TEMP_IN);
    if(split < 300)
    {
    digitalWrite(SPLIT_PIN, HIGH);
    digitalWrite(VENT_PIN, HIGH);
    }
    else
    {
    digitalWrite(SPLIT_PIN, LOW);
    digitalWrite(VENT_PIN, LOW);
    previousMillis3 = currentMillis;
    }
    }


    /* Работа ультразвукового дальномера */
    if(currentMillis - previousMillis4 > interval4)
    {
    int duration, cm;
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);
    cm = duration / 58;
    if(cm > 10)
    digitalWrite(FLOOR_PIN, HIGH);
    else
    digitalWrite(FLOOR_PIN, LOW);
    previousMillis4 = currentMillis;
    }


    /* Работа датчика вибрации */
    if(digitalRead(VIB_PIN) == LOW && vibration == 0)
    {
      vibration = true;
      digitalWrite(WINDOW, LOW);
      now = millis();
    }

    if(digitalRead(VIB_PIN) == HIGH && vibration == 1)
    {
      vibration = false;
    }

    if(millis() - now >= 3000)
    {
      digitalWrite(WINDOW, HIGH);
    }


    /* Работа датчика движения */
    int moove = digitalRead(MOOVE_PIN);
    if (moove == HIGH)
    {
      if(lockLow)
      {
       lockLow = false;
       digitalWrite(WORK_PIN, LOW);
      }
    takeLowTime = true;
    }
    else
    {
      if(takeLowTime)
      {
       lowIn = millis();
       takeLowTime = false;
      }
      if(!lockLow && millis() - lowIn > pause)
      {
       lockLow = true;
       digitalWrite(WORK_PIN, HIGH);
      }
    }


    /* Работа датчика громкости звука */
    int sounda = analogRead(SOUND_APIN);
    if(sounda > 590)
    {
    servo_win.write(90);
    }
    if(sounda < 590)
    {
    servo_win.write(45);
    }
    if(sounda < 500)
    {
    servo_win.write(0);
    }
    Serial.println(sounda);
    }

     
     
    Последнее редактирование: 20 май 2016
  5. ZAZ-965

    ZAZ-965 Гуру

    IMHO, так вернее
    Код (C++):
    /* Работа датчика громкости звука */
    int sounda = analogRead(SOUND_APIN);
    if(sounda < 500)
        { servo_win.write(0);}
        else  if (sounda > 590)
            { servo_win.write(90); }
    else
        { servo_win.write(45); }
    Serial.println(sounda);
    }
     
    Defender нравится это.
  6. Defender

    Defender Нерд

    Да, согласен. Так лучше, спасибо вам большое. Сейчас проверить ваш вариант нет возможности, чуть позже отпишусь по тому как работает сервопривод.
    Но вот по вопросу многозадачности. Правильно ли я всё делаю в программе при обработке такого множества датчиков и устройств? Верна ли её структура? Верна ли моя теория о том, что МК перезагружается в следствии загруженности таким количеством сигналов?
     
  7. ZAZ-965

    ZAZ-965 Гуру

    Я бы начал проверку с питания и надежности соединений.
    Стабилизатор импульсный? На сколько вольт? Блок питания на сколько вольт? И как все это скоммутировано. Можете нарисовать схему?
     
  8. Defender

    Defender Нерд

    Стабилизатор lm1084 напряжение на входе 12 В, на выходе 5 В. Радиатор поставил 5 на 5 см, толщиной 1 см (думаю такой вполне достаточен) + термопаста и 2 конденсатора по 100 мкФ на входе и выходе.
    Блок питания с 12 В на 5 В.
    7 ламп используемых в проекте, а также блок питания запитываются от 220В. От блока питания запитывается вентилятор (12 В), стабилизатор и потенциометры (на них стоят ограничивающие резисторы). От стабилизатора питание попадает на саму Ардуину и датчики. С пинов платформы подаются управляющие сигналы на реле через которые коммутируются все 7 ламп и вентилятор. Ну и соответсвтенно платформа также воспринимает воспринимает сигналы от датчиков и потенциометров.
    Два человека, которым я показывал собранную схему и которые разбираются в составлении электрических схем не по-наслышке утвердительно сказали, что проблема не в сборке схемы, а в программе. Один из этих людей (программирует PIC-контроллеры на Ассемблере) сказал, что проблема 100% в программе, нет оснований ему не доверять. Но так как он не знаком с Ардуино, то подсказать в чём именно проблема он не смог, сказав что скорее всего дело связано с тем, что очень многие вещи в Arduino IDE спрятаны в макрокамандах (функциях) и видимо проблема на его взгляд, состоит в том что при составлении больших программ, где существует много датчиков возможны конфликты между этими функциями, так как неизвестно что там внутри этих функций и как именно происходит их обработка микроконтроллером.
    Соответственно я и подумал, может быть при реализации на Ардуино проектов с большим количеством датчиков и исполнительных механизмов возможно есть какие-то особенные принципы построения программ?
     
  9. ZAZ-965

    ZAZ-965 Гуру

    Я бы подключил так -
    Ардуину через штатный разъем питания к 12В;
    все датчики к внутреннему стабилизатору Ардуины (навскидку, общее их потребление 100мА);
    блок реле через стабилизатор lm1084 к 12В.
    Этим бы снизил влияние бросков по питанию на стабильность работы.

    Переменный резистор к 12В подключен так? И зачем к 12В?
     

    Вложения:

  10. Defender

    Defender Нерд

    Извините может глупый вопрос, но что считают штатным разъёмом питания? Vin или USB?

    Все датчики подключить через Vin, если запитывать Ардуино через USB или через 5 В если под штатным разъёмом вы понимаете Vin?

    Реле у меня так и запитаны. От стабилиазтора, как и на Ардуино идёт на них 5 В.

    Да, он подключён так, но только нет R2. Сам потенциометр имеет сопротивление 5 кОм, ограничивающий резистор, через который подаётся на него напряжение имеет сопротивление 7 кОм.
     
  11. ZAZ-965

    ZAZ-965 Гуру

    Под штатным разъёмом питания я понимал Power Jack (он же Vin на гребенке контактов).
    Датчики подключить к пину 5V (это выход стабилизатора 1117ST50 на плате Ардуино).
    По подключению потенциомера - как на схеме ниже во вложении?
     

    Вложения:

    Последнее редактирование: 20 май 2016
  12. Defender

    Defender Нерд

    Сегодня попробую подключить всё как, вы сказали, спасибо.
    Да, потенциометры подключены по такой схеме, как у вас на рисунке.
    А сама программа значит верна? Таки в схеме проблема?
     
  13. ZAZ-965

    ZAZ-965 Гуру

    Я бы отключил блок реле (для наблюдения на соответствующие выхода подключил светодиоды через токоограничивающий резистор). Все провода от датчиков как можно короче. Земляные провода соединить в одной точке.
    В программе явных ошибок не вижу.
     
  14. az3749

    az3749 Нерд

    1. digitalWrite и servo_win.write вызывают переходные процессы которые могут влиять на последующие показания. Я бы поставил всю исполнительную часть после измерительной или как минимум постaвил везде delay(100) , а потом начал бы их постепенно выбрасывать и уменьшать задержки.
    2. Можно было бы еще помимо керамических конденсаторов отделить помехо-генерящую часть индуктивностями на ферритах - так делают в ноутбуках и в утолщениях на VGA кабелях тоже они внутри.
    3. Процессор достаточно мощный для имитации UART на 115200 - я имею в виду модуль SoftwareSerial.
     
  15. Defender

    Defender Нерд

    Многое уже перепробовал. Ничего не помогло, осталось теперь всё собрать экранированным проводом :)
     
  16. az3749

    az3749 Нерд

    судя по коду датчик звука выдает значение в текущий момент времени. ацп достаточно шустрый для 10 кгц. посчитайте дисперсию (ско) скажем за 1 сек. это ближе к звуковому давлению которое вы хотите мерять.
     
  17. Defender

    Defender Нерд

    Расскажите, пожалуйста, чуть по-подробнее об этом. Я не совсем понял. Мне надо посчитать ско для измерения датчика за 1 сек?
     
  18. az3749

    az3749 Нерд

    analogRead пропускает без искажения примерно частоту 5 кгц - т.е. частота дискретизации 10 кгц примерно. чтобы получить звуковое давление надо усреднить квадрат значения за какое-то время - > 50 мс (20 гц). Если у вас нет аналогового квадратичного детектора - надо организовать софтовый. Сейчас Вы меряете 1 значение из sin со случайной фазой и дергаете очень быстро серво в разные стороны - что не есть хорошо.
     
  19. Defender

    Defender Нерд

    То есть правильно ли я вас понял, что мне необходимо, к примеру, сделать 5 измерений, посчитать ско или среднее значение и уже на основании полученного управлять сервоприводом?
     
  20. az3749

    az3749 Нерд

    10000гц/20гц=500
    ско, среднее значение будет константой.