Автоматическая подсветка лестницы

Тема в разделе "Глядите, что я сделал", создана пользователем ИгорьК, 19 сен 2013.

  1. ИгорьК

    ИгорьК Гуру

    По мотивам статьи на Хабре озадачился и сделал подсветку лестницы.
    Поскольку идея чрезвычайно простая (и полезная) и состоит, по сути, в мигании диодом - не стал реализовывать ее так, как сделал Владимир Лукьянов - упростил все по максимуму, заменив управление на Мегу2560 (там 15 ШИМ и этого (мне) достаточно, а драйверы ступенек на ULN. Можно "дотянуть" Мегу до 16 ног, если включить параллельно две ступеньки - первую и последнюю. Они все равно вместе подсвечиваются ночью, а одновременное их включение/выключение даже в некоторой степени прикольно.
    Ультразвуковые датчики - SEN136B5B. Датчик освещенности - этот.
    Код для Меги2560 представляю ниже. Постарался закомментировать его изо всех сил.
    В коде оставил закомментированные строчки работы с последовательным портом для контроля ситуации и понимания что там вещают датчики. При настройке - раскомментируйте.

    Готов ответить на вопросы, если появятся. Более подробно описал ход работ вот здесь.

    Кстати, в Меге2560 - 15 ног PWM, а на этом сайте указано 14. Если у тебя 15 ступенек - ошибка серьезная :)
     

    Вложения:

    • lesenka.zip
      Размер файла:
      2,7 КБ
      Просмотров:
      1.506
    Последнее редактирование: 14 мар 2016
    aurimaspr, Mestniy и Nabla нравится это.
  2. ИгорьК

    ИгорьК Гуру

    UPD: Вот здесь еще пара картинок: http://forum.amperka.ru/threads/Автоматическая-подсветка-лестницы.1930/page-13#post-43415

    На вопросы нескольких коллег в личку.
    Если у вас датчик hc-sr04, то вот, полагаю, как надо изменить скетч:
    (к сожалению сам проверить не могу за неимением оного)
    Код (C):

    //В дефайнах добавить:

    #define trigPin00 31     // сюда присоединяем тригерную ногу первого датчика
    #define trigPin01 33     // сюда присоединяем тригерную ногу второго датчика

    //в void setup() добавить:

    pinMode(trigPin00,OUTPUT);
    pinMode(trigPin01,OUTPUT);
    pinMode(pingPin00,INPUT);
    pinMode(pingPin01,INPUT);

    //в void loop() поменять:

    getDistance(pingPin00); на getDistance(trigPin00, pingPin00);

    getDistance(pingPin01);  на getDistance(trigPin01, pingPin01);


    //Функцию unsigned int getDistance(int pingPin) заменить на:

    unsigned int getDistance(byte trig, byte ping) {
        unsigned int duration = 0;
        digitalWrite(trig, LOW);
        delayMicroseconds(2);
        digitalWrite(trig, HIGH);
        delayMicroseconds(10);
        digitalWrite(trig, LOW);
        duration = pulseIn(ping,HIGH);
        Distance = duration/29/2;
        return Distance;
    }
     
     
    Последнее редактирование: 22 июн 2015
  3. vist

    vist Нуб

     
  4. ИгорьК

    ИгорьК Гуру

    Этот датчик должен подсоединяться и работать с двумя контактами. В данном случае на 30 и 32 вход ардуино вешаются контакты для получения данных, а на 31 и 33 соответственно контакты тригера.
    Логика там следующая - на триггерный контакт посылается стартовый импульс, а с другого контакта считываются данные.
    Вот ссылка. Поиграйте датчиком, я из нее информацию и взял.
     
  5. ИгорьК

    ИгорьК Гуру

    Вот это полный код программы для датчиков hc-sr04:
    Код (C):
    // Для ArduinoMega 2560
    #define sensorPin A0                    // Нога для фоторезистора;
    #define ledNight 24                    // Нога для LED - показывает включение ночного режима;
    unsigned int sensorValue = 0;          // Переменная для снятия показаний сенсора освещенности;
    unsigned int sensorRef = 1010;          // Референсное значение сенсора освещенности, выше которого считается ночь;
    boolean night = 0;                      // Если 1 - то ночь;
    //PWM ноги ArduinoMega 2560 от 2 до 13 и от 44 до 46;

    int OutPins[15] = {2,3,4,5,6,7,8,9,10,11,12,13,44,45,46}; // Массив PWM ног;

    // Подсветка;
    int i;                                  // Счетчик для зажигания и тушения диодов, определения день/ночь;
    #define timer 20                        //Таймер для задержек при включении/выключении последовательности ступенек;
    #define SwitchOffDelay 15000            // Задержка выключения посветки;
    #define SwitchOnBright 150              // Яркость включенных ступенек, максимально - 255;
    #define NightBright  20                // Яркость подсвеченных ступенек в ночном режиме (первая, последняя);
    int timeForBlink = 10;              // Число циклов мерцания включенной подсветки, баловство;

    //SEN00 - нижний ультрасоник;
    #define pingPin00 30                    // Echo Выход первого датчика  hc-sr04;
    #define trigPin00 31                    // сюда присоединяем Trig ногу первого датчика  hc-sr04

    //SEN01 - верхний ультрасоник;
    #define pingPin01 32                    // Echo Выход второго датчика  hc-sr04;
    #define trigPin01 33                    // сюда присоединяем Trig ногу второго датчика  hc-sr04

    #define LedUltra 25                    // Нога светодиода - в ночном режиме показывает что любой ультрасоник схватил дистанцию, в дневном режиме просто светится;

    unsigned int Distance=0;                // Дистанция с ультрасоника;

    //===================================================================================================================
    // Setup
    void setup()
    {
        //Serial.begin(9600);
        pinMode(ledNight, OUTPUT);          // Ночной диод  ;
        pinMode(LedUltra,OUTPUT);        // Диод, индикатор "день" а ночью - чтобы видно было как действует ультрасоник;
        digitalWrite(LedUltra,LOW);

        for(i=0; i<15; i++)                // Режим работы PWM ног - выход;
        {
            pinMode(OutPins[i], OUTPUT);
        }

        pinMode(trigPin00,OUTPUT);
        pinMode(trigPin01,OUTPUT);
        pinMode(pingPin00,INPUT);
        pinMode(pingPin01,INPUT);



    }

    //===================================================================================================================
    // Loop
    void loop()
    {
        NightIn();                                // Получаем данные День/Ночь;
        //Serial.print(night);
        //Serial.print(" - boolean night");
        //Serial.println();

        if(night == 1)                            // Если ночь;
        {
            //getDistance(pingPin00);            // Опрашиваем нижний ультрасоник;
            getDistance(trigPin00, pingPin00);


            //Serial.print(Distance);
            //Serial.print(" - First Distance");
            //Serial.println();
            //delay(1000);
            if(Distance < 140)                  // Проверка дистанции для нижнего ультрасоника в сантиметрах (140 см.). Сделано для верхнего и нижнего раздельно.

            {
                SwitchOn();                      // Включаем подсветку снизу вверх;
       
                delay(SwitchOffDelay);                    // Ждем;
                blink (timeForBlink);                // Померцаем;
                SwitchOff();                      // Выключаем подсветку;
            }

            //getDistance(pingPin01);              // Опрашиваем верхний ультрасоник;
            getDistance(trigPin01, pingPin01);


            //Serial.print(Distance);
            //Serial.print(" - Second Distance");
            //Serial.println();
            //delay(1000);

            if(Distance < 55)                    // Проверка дистанции для нижнего ультрасоника в сантиметрах (55 см.).
            {
                SwitchOnDown();                  // Включаем подсветку сверху вниз;
                delay(SwitchOffDelay);            // Ждем;
                SwitchOffDown();                  // Выключаем подсветку;
            }
        }
    }
    //====================================================================================================================

    void SwitchOn()                                // Включаем снизу вверх;
    {
        digitalWrite(LedUltra, HIGH);
        for (i=0; i<15; i++)
        {
            analogWrite(OutPins[i], 254);                  // Зажигаем полностью первый сетодиод;
            delay(timer);                                  // Пауза перед следующим;
            if(i!=14)                                      // Проверяем, чтобы не включить несуществующий диод;
            {
                analogWrite(OutPins[i + 1], 254);      // Зажигаем полностью следующий светодиод;
                delay(timer);
            }
            if(i!=13)                                      // Проверяем, чтобы не включить несуществующий диод;
            {
                analogWrite(OutPins[i + 2], 254);      // Зажигаем полностью еще светодиод;
                delay(timer);
            }
            analogWrite(OutPins[i], SwitchOnBright);    // Слегка гасим подсветку;
            delay(timer);
        }
    }


    void SwitchOff()                                  // Выключаем снизу вверх;
    {
        for (i=0; i<15; i++)
        {
            analogWrite(OutPins[i], 254);
            delay(timer);

            if(i!=14)
            {
                analogWrite(OutPins[i + 1], 254);
                delay(timer);
            }

            analogWrite(OutPins[i], 0);
            delay(timer);
        }
        digitalWrite(LedUltra, LOW);
    }

    //=====================================================================================================================

    void SwitchOnDown()                              // Включаем сверху вниз;
    {
        digitalWrite(LedUltra, HIGH);

        for (i=14; i > -1; i--)
        {
            analogWrite(OutPins[i], 254);
            delay(timer);

            if(i!=0)
            {
                analogWrite(OutPins[i - 1], 254);
                delay(timer);
            }

            analogWrite(OutPins[i], SwitchOnBright);
            delay(timer*2);
        }
    }


    void SwitchOffDown()                                // Выключаем сверху вниз;
    {
        for (i=14; i > -1; i--)
        {
            analogWrite(OutPins[i], 254);
            delay(timer);

            if(i!=0)
            {
                analogWrite(OutPins[i - 1], 254);
                delay(timer);
            }

            analogWrite(OutPins[i], 0);
            delay(timer*2);
        }
        digitalWrite(LedUltra, LOW);
    }
    //=====================================================================================================================

    unsigned int getDistance(byte trig, byte ping) {
        unsigned int duration = 0;
        digitalWrite(trig, LOW);
        delayMicroseconds(2);
        digitalWrite(trig, HIGH);
        delayMicroseconds(10);
        digitalWrite(trig, LOW);
        duration = pulseIn(ping,HIGH);
        Distance = duration/29/2;
        return Distance;
    }


    //===========================================================================================
    boolean NightIn()                                        // Чтение день или ночь;
    {
        sensorValue = 0;
        unsigned int a = 0, b = 0;

        for(i = 0; i < 50; i++)
        {
            sensorValue = analogRead(sensorPin);            // Чтение показаний датчика;
            if (sensorValue > sensorRef) a++;              // Увеличиваем а, если темнее референсного значения;
            if (sensorValue > (sensorRef - 25)) b++;        // Увеличиваем b, если темнее чем референсное значение минус допуск на гистерезис;
        }

        if ((night == 0) && (a > 49))                      // Если сейчас режим день и 50 раз значение датчика оказалось выше референсного,
        {                                                  // то переключаемся в ночной режим, включаем дежурную подсветку ступенек.
            digitalWrite(ledNight, HIGH);
            digitalWrite(LedUltra, LOW);
            analogWrite(2,NightBright );
            analogWrite(46,NightBright );
            night = 1;
        }

        if ((night == 1) && (b == 0))                      // Если сейчас режим ночь, и 50 раз значение датчика оказалось ниже референсного за
        {                                                  // вычетом запаса на гистерезис - включаем режим "день", гасим подсветку ступенек.
            digitalWrite(ledNight, LOW);
            digitalWrite(LedUltra, HIGH);
            analogWrite(2,0);
            analogWrite(46,0);
            night = 0;
        }

        else {}

        return night;
    }
    /*********************************************************************************************************************************************

    Мерцание во время задержки

    /*********************************************************************************************************************************************/


    void blink (int timeForBlink)
    {
    unsigned char brightness = 0;

    for (int a = 0; a < timeForBlink; a++)                                          // Цикл определяет длительность мерцания;
    {
    for(i = 1; i < 15; i++)                                                    // Мерцаем диодами;
    {
    brightness = random((SwitchOnBright-25), SwitchOnBright);
    analogWrite(OutPins[i], brightness);
    delay(2);                                                                  // Маленькая задержка;
    }
    }

    //for(i = 1; i < 15; i++)                                                          // Восстанавливаем свечение лестницы. Можно восстанавливать, можно не восстанавливать;
    //{
    //  analogWrite(OutPins[i], SwitchOnBright);
    //}

    return;
    }

     
    И работать это должно так:

     
    Последнее редактирование: 12 ноя 2013
    dwk26111974 нравится это.
  6. Megakoteyka

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

    Скомпилировал Ваш код, получил целую пачку ошибок.

    sketch_nov08a:44: error: invalid conversion from 'int*' to 'uint8_t'
    Код (Text):
    for(i=0; i<15; i++) // Режим работы PWM ног - выход;
      pinMode(OutPins, OUTPUT);
    Компилятор ругается на несовпадение типов. Функция pinMode ожидает получить номер ножки в виде целого числа, а Вы ей указатель подсунули. Тип переменной OutPins - указатель на int.
    Должно быть
    Код (Text):
    OutPins[i]
    - это значит "прибавить к указателю на начало массива i раз размер указателя этого типа и вернуть значение, лежащее по полученному адресу. Подробней смотрите в справочнике по языку C/C++.
    sketch_nov08a:63: error: 'pingPin00' was not declared in this scope
    Компилятор жалуется на то, что pingPin00 нигде не объявлен. С pingPin01 такая же история.

    А дальше вообще непонятно, что хотел сказать автор. Вот, например:
    Код (Text):
    unsigned int getDistance(int pingPin) // Чтение ультрасоника;
    {
    unsigned int getDistance(byte trig, byte ping) {
    digitalWrite(trig, LOW);
    delayMicroseconds(2);
    digitalWrite(trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(trig, LOW);
    long duration = pulseIn(ping,HIGH);
    Distacne = duration/29/2;
    }
    return Distance;
    }
    Одна функция объявляется внутри другой функции; переменая Distacne, которую Вы пытаетесь вернуть, нигде не объявлена.

    Начните изучать язык. Начните форматировать код.

    Располагайте все константы в начале исходника, после секции подключения хидеров (строчек #include <...>). Дайте константам такие имена, чтобы сразу было видно, что это константы. Обычно используют заглавные буквы, например #define SOME_PIN 1.

    После констант располагайте глобальные переменные. Чтобы в коде было легко отличить глобальную переменную от локальной, можно начинать имя глобальной переменной с символа "_", но это дело вкуса.

    Затем функции.

    Делайте отступы в коде. Вот так:
    Код (Text):
    int Function(int x)
    {
        if(x < 10)
        {
            return 1;
        }
        else
        {
            int y = 0;
            for(int i = 0; i < 5; i++)
                y = y + x * 10;
        }
    }
    Тогда код будет читаться гораздо легче и будет сразу видна его структура.

    Внимательно читайте сообщения компилятора и пытайтесь понять, что они значат. Так Вы быстрей перестанете совершать простые ошибки.
    Смотрите, как пишут код более опытные Ваши коллеги и перенимайте их стиль.
    При размещении кода в сообщении на форуме используйте тэг CODE (кнопка с символами "<>" на панели кнопок в заголовке сообщения, 19-я по счету слева).
     
  7. ИгорьК

    ИгорьК Гуру

    Уважаемый Megakoteyka! Вы абсолютно правы, но вряд ли vist рассчитывает на что-то большее, чем сделать подсветку лестницы. Поэтому проще дать ему готовый код, чем искать ошибки в том, что он попытался сделать сам.
    Думаю, с этим придется смириться - это следствие самого существования Ардуино.
    Единственно, я бы тоже попросил уважаемого vist отредактировать свои сообщения и поместить его код в соответствующее оформление. Для этого нужно нажать 19 кнопочку слева, ту, что между кнопочки с кадрами и кнопочки с кавычками, откроется окошко и переместить код в него.
     
    glory24 и Festour нравится это.
  8. vist

    vist Нуб

    Добрый вечер!
    Не хочет скетч видеть датчики hc-sr04! Хотя отдельно с демо версией для датчиков все прекрасно.
     
  9. ИгорьК

    ИгорьК Гуру

    Ок, прежде чем двигаться дальше, очень прошу помочь мне вот чем: исправьте, пожалуйста, свои сообщения где Вы привели огромные куски кода. Или оформите их правильно, или просто удалите за ненадобностью. Очень уж тему загромождает.
    Ну а я подумаю куда дальше ...
     
  10. ИгорьК

    ИгорьК Гуру

    1. Проверьте, так ли присоединены датчики:
    [​IMG]
    2. Почему Вы решили, что скетч не видит датчики, в чем это выражается? Как работает вся Ваша схема в целом? Переходит из ночного режима в дневной и обратно? Что происходит, когда схема входит в ночной режим? Как это работает в сравнении с тем видео, что я выложил выше?
     
  11. ИгорьК

    ИгорьК Гуру

    Известный недостаток программ подсветки лестницы заключается в том, что они не учитывают случаев, когда на лестницу входит другой человек или по ней идет старенькая бабушка, которая не успевает подняться за время подсветки. Теоретически можно устанавливать ультразвуковые или ИК датчики вдоль лестницы и проверять их, но эстетически это вряд ли получится хорошо.
    Для тех у кого лестница деревянная предлагаю проверить такой вариант - в ее средину поставить пьезо-датчик и проверять вибрации на нем перед выключением подсветки.
    Все что нужно - добавить пару дефайнов и подпрограмму, которую проверять перед выключением.
    Код (C):
    #define vibroCalm 20                    // Значение, выше которого уровень вибрации указывает на движение на лестнице
    #define vibroPin A1                        // Нога для вибродатчика включается в A1 http://goo.gl/V9Tr9i;


    // В тело программы добавить
    checkVibration();            // Проверим, нет ли кого на лестнице;

    // И сама функция проверки

    void checkVibration (void) {                            // Влезаем в подпрограмму и сидим 3 секунды в ней пока лестница не перестанет вибрировать
        int vibroIn, vibroMax;
        do {
            vibroIn = 0;
            vibroMax = 0;
           
          for (int i = 0; i < 300; i++) {
                vibroIn = analogRead(vibroPin);
                if  (vibroIn > vibroMax) {
                    vibroMax = vibroIn;
                }
            delay(10);
            }
        } while (vibroMax > vibroCalm);
    }
     
    Теперь остается вопрос какое значение указать в "#define vibroCalm"?
    Для его определения накидал вот такой скетч:
    Код (C):
    #define vibroPin A1                        // На ногу А2 вешаем датчик вибрации;
    #define error 2                        // Погрешность (постоянные вибрации) датчика когда на лестнице никого нет
    int vibroIn = 0, vibro =0, vibroMax = 0;// Переменные для работы с вибрацией;
    int vibroMin = 0;
    int i = 0;                                // Счетчик;
    void setup() {
        Serial.begin(9600);                    // Инициализация порта;
    }

    void loop() {
        vibroIn = analogRead(vibroPin);        // Читаем датчик вибрации;
        delay(10);
     
        if (vibroMax<vibroIn) {                // Сведения о самом большом показании датчика;
            vibroMax = vibroIn;
        }
     
        if ((abs(vibroIn - vibro)) > error) {// Чтобы не было много лишних цифр;
            vibro = vibroIn;
            Serial.print(vibro);            // Печатаем в порт только неодинаковые;
            Serial.print(" ");
            i++;
            if (20 == i) {
                Serial.println("");
                Serial.print("Max = ");        // Переход на новую строку после двадцати значений;
                Serial.println(vibroMax);    // И печать максимального показания;
             
                i = 0;
            }
        }
    }
     
    Как его использовать? Прикрепить датчик, загрузить и запустить скетч, открыть монитор порта... и тихо-тихо прокрасться по лестнице.
    Монитор покажет результаты этого перемещения... :)
     
    Последнее редактирование: 12 ноя 2013
  12. vist

    vist Нуб

    1.Датчики я проверял именно по этой схемке только, еще добавлял светодиод на разницу расстояния, плюс еще и на встроенном мониторе проверял расстояние меняя оператор if (distance_sm<30).
    2.Ночной режим я создаю искусственно для данной boolean night = 0; изменяя на1, загорается LED 25
     
  13. ИгорьК

    ИгорьК Гуру

    "Ночной режим я создаю искусственно для данной boolean night = 0; изменяя на1, загорается LED 25"
    Ну а что происходит дальше? Если у Вас датчики не задействуются, то по умолчанию расстояние установлено в ноль, и должно начинаться включение-выключение диодов. Это так?

    "меняя оператор if (distance_sm<30)." - в моем скетче нет такой переменной. О чем речь?
     
  14. vist

    vist Нуб

    "меняя оператор if (distance_sm<30)." - в моем скетче нет такой переменной. О чем речь?-Это когда на панельке датчики проверял, вставлял другой скетч, только для проверки, чтобы не разбирать схему.
     
  15. Tomasina

    Tomasina Сушитель лампочек Модератор

    А как можно уменьшить число проводов? Для 16 каналов это уже 32 провода 1,5 кв.мм. каждый - приличный жгут получается.
    Можно все "плюсы" объединить - будет 18 проводов, но все равно много и неудобно в монтаже получается.
    Напрашивается создание 3-4 проводной шины SPI/I2C/1wire, тогда получится типа такого, но в моноцветном исполнении, по 1 чипу на канал (ступеньку) + драйвер 500 мА с поддержкой Шим:
    [​IMG]
    Плюсы: компактность и удобство при монтаже - всего 4 провода на всю лестницу, каналы легко переопределять программно (разные спецэффекты).

    Минусы: небольшое удорожание (не факт, ибо провода надо в 8 раз меньше), выше порог вхождения при программировании.

    Проблема: в схемотехнике моих познаний недостаточно, т.е. на каких компонетах это можно реализовать? Какой из интерфейсов на таком расстоянии (8-12 метров) более помехоустойчив? Какой драйвер выбрать?
     
  16. ИгорьК

    ИгорьК Гуру

    Обойтись можно пятью проводами (Общий, +5в, +12в, SDA, SCL ) плюс еще 2 (4, в зависимости от датчика) на датчики, итого 7 (или 9).
    Это будет второй вариант. Как раз планирую сделать подсветку на I2C. Решение для этого простейшее, хотя удорожение, безусловно, будет.
    На каждую ступеньку отдельно связочку ATtiny45+UNL2303. Это по 80-90 рублей плюс на ступеньку.
    Ну и коль скоро такая возможность появляется - ленту надо ставить не монохромную, а цветную.
    Это тоже проект не удешевит. Но зато возможности появляются невероятные, и ограничиваются только вкусом исполнителя.
    Один только стремный момент... После того как раз это все смонтируешь, настроишь и запустишь, надо хотя бы полгода подождать :) (Хотя, ничего сложного в этом монтаже не было, тянешь и тянешь себе провода...)
    Сейчас делаю модули на I2C как раз для подготовки ко второй редакции.
    Эти конкретно для отработки программы и для фана, а для лестницы будут несколько другие.
    00331.jpg
     
    Последнее редактирование: 27 ноя 2013
  17. Tomasina

    Tomasina Сушитель лампочек Модератор

    +5В к концу шины может превратиться в +3В, если провода тонкие. +10В некритично - на лестнице высокая яркость не нужна, да и светики дольше прослужат.
    Я к тому, что выкинуть линию +5В, а на каждый канал поставить стабилизатор типа КРЕН или 7805, Стоит копейки, зато напруга не плавает, .т.е более стабильная работа.
     
  18. fr0ster

    fr0ster Гик

    Большая часть проблем снимается, если освещать лестницу дискретно управляемыми осветителями, причем каждый осветитель управляется по сигналам датчиков расположенных ниже и выше на пару ступеней.
    Так, что бы подошел к лестнице, подсветка зажглась, прошел мимо осветителя, подсветка погасла.
     
  19. Tomasina

    Tomasina Сушитель лампочек Модератор

    Ну городить 15 датчиков - это еще больше сложностей ;)
     
  20. fr0ster

    fr0ster Гик

    Это если лестница длинной метров 30, то да 15 датчиков.
    А так и 4мя обойтись можно