IT Академия Samsung – Регулятор освещения <div class="copyright"> Это авторский материал IoT лаборатории ЮУрГУ, представленный в дополнение к существующему практикуму. </div> # Регулятор освещения<a name="reg"></a> Мы уже работали с [виртуальной умной лампочкой](/iot/fake-lamp). Она запускается в браузере, и ее можно включать, выключать, посылая команды через MQTT. Можно управлять яркостью ее свечения, а также превратить в RGB-лампу. ![fake_lamp_firefox_on](/assets/images/iot-academy/fake_lamp/fake_lamp_firefox_on.png) Задавая уровень яркости в процентах в топике `iot_practice/<UserID>/lamp/value` мы можем менять уровень свечения лампы, изменяя тем самым освещеность того места, над которым лампа располагается (конечно же, речь в данном случае не о виртуальной лампе, а о настоящей). Нынешняя цель – сделать так, чтобы умная лампочка не только светилась с заданной яркостью, но и создавала требуемый уровень освещенности в месте, где она установлена. Вообще, это классическая задача ТАУ (теории автоматического управления). Кстати, ранее (в 60-х...70-х годах прошлого века) использовался термин ТАР – теория автоматического регулирования. Для решения подобного рода задачи необходим **регулятор**&nbsp;(Р), который на основе информации от **датчика**&nbsp;(Д), измеряющего интересующий нас параметр&nbsp;*y* **объекта управления**&nbsp;(ОУ), сформирует такое **управляющее воздействие**&nbsp;*u*, которое обратит величину **ошибки**&nbsp;*e* в ноль. Ошибка – это разность между **уставкой** (или **желаемым значением**) сигнала&nbsp;*y*\* и либо его реальным текущим значением&nbsp;*y*, получаемым непосредственно с объекта управления, либо оценки сигнала&nbsp;*y&#770;*, получаемой средствами измерения, то есть при помощи датчика (как показано на рисунке). ![sys_ctrl](/assets/images/iot-academy/sys_ctrl.png) Существуют разные законы управления, по которым работают регуляторы. Самый простой – *пропорциональный* закон управления (в ТАУ его ещё называю П-законом, а регулятор – П-регулятором). Суть очень проста: величина ошибки умножается на некоторую константу – это и есть управляющее воздействие. Тем не менее, П-регулятор для нашего случая плохо подходит, так как наш объект (лампа) срабатывает очень быстро (и быстрее скорости света пока еще ничего не открыли), и пока регулятор расчитает нужное значение, лампа уже включится на полную мощность. Лучшим выбором будет использование И-регулятора (*интегрального*). <div class="info"> Что И-регулятор, что П-регулятор – это все частные случаю более общего, ПИД-регулятора.<br /> Есть достаточно много информации на эту тему. Например, [тут](https://odinelectric.ru/kipia/chto-takoe-pid-regulyator-dlya-chajnikov) или [тут](https://www.reallab.ru/bookasutp/5-pid-regulyatori/5-2-klassicheskii-pid-regulyator/). </div> Ранее мы уже [эксперементировали](/iot/sensors) с датчиком освещенности, и, соответственно, знаем как получить текущее значение освещенности в [люксах](https://ru.wikipedia.org/wiki/Люкс). Определив для себя некоторый желаемый уровень освещенности, например, *y*\*=500&nbsp;лк, давайте порассуждаем, что будет происходить. Если у нас темно, и значение с датчика освещенности меньше желаемого значения, то яркость лампочки нужно увеличить. Если же, наоборот, значение с датчика освещенности больше уставки, то яркость нужно убавлять. И вот если желаемое и действительное значение равны друг другу, то нужно перестать "крутить ручку яркости" лампы – то есть нужно зафиксировать сигнал управления на прежнем уровне. Этого как раз и можно добиться введением И-регулятора. Тут ещё нужно вспомнить, что лампа у нас управляется заданием уровня яркости, выраженным в процентах, и, соответственно, не может быть меньше нуля и больше 100&nbsp;%. Таким образом, реализация регулятора при помощи некоторого псевдо-кода (близкого по синтаксису к языкам C/C++) могла бы выглядеть так: ```c ... int luminocity_sp = 500; // Желаемый уровень освещенности (SP - Set Point) float K = 3.3e-5; // Коэффициент пропорциональности int light = 0; // Управляющее воздействие. Исходное значение - лампа выключена ... // Опрашиваем датчик с некоторой периодичностью и формируем сигнал управления int luminocity = opt.readSensor(); // Текущая освещенность (с датчика) light += (int)(K * (luminocity_sp - luminocity)); // Вычисляем и прибавляем интегральную часть light = (light < 0)? 0 : (light > 100)? 100 : light; // Ограничиваем значение допустимым диапазоном 0-100% ... ``` Коэффициент пропорциональности&nbsp;`K` в программе задается один раз. Его можно подобрать на основе серии экспериментов или рассчитать средствами классической ТАУ. Уставка `luminocity_sp` в целом может меняться (но в данном фрагменте программы это не рассматривается), ведь наши предпочтения относительно уровня освещенности могут меняться. Тут сделаем ещё одно пояснение. Интегрирование – это фактически суммирование. Соответственно, переменная `light` в этом фрагменте программы и реализует тот самый, необходимый нам, И-закон регулирования. <a name="pid"></a> Совместим две ранее написанных программы: [опрос датчика освещенности](/iot/sensors#luminosity) и [ШИМ управление выходом](/iot/gpio#pwm) с приведенной выше реализацией закона управления: ```cpp #include "mbed.h" #include "OPT3001.h" const int PWM_PERIOD_US = 2000; // Период ШИМ const int MAXLUM = 3000; // Максимальная освещенность const int luminocity_sp = 500; // Желаемый уровень освещенности const float K = 0.1; // Коэффициент пропорциональности int main() { PwmOut led(LED1); PwmOut lamp(UNWD_GPIO_26); OPT3001 sensor_opt(I2C_SDA, I2C_SCL); float brightness = 0.0f; // Управляющее воздействие. Исходное значение - лампа выключена // Задаем период ШИМ led.period_us(PWM_PERIOD_US); lamp.period_us(PWM_PERIOD_US); while(1) { // Получаем с датчика текущую освещенность int luminocity = sensor_opt.readSensor(); // Вычисляем и прибавляем интегральную часть brightness += (K * (luminocity_sp - luminocity) / MAXLUM); // Ограничиваем значение допустимым диапазоном 0-100% brightness = (brightness < 0.0f)? 0.0f : (brightness > 1.0f)? 1.0f : brightness; led = brightness; lamp = brightness; printf("Luminocity = %d lux, PWM = %.2f\r\n", luminocity, brightness); ThisThread::sleep_for(500ms); } } ``` В данной программе помимо управления яркостью встроенного на плату светодиода осуществляется ещё и ШИМ-управление выходом `UNWD_GPIO_26`. Добавив к нашему микроконтроллеру модуль транзисторных ключей UMDK-6FET ![umdk-6fet](/assets/images/iot-academy/umdk-6fet.png) можно организовать управление более мощной нагрузкой, в качестве которой может выступить светодиодная лента с питанием от 12&nbsp;В источника напряжения: ![led_strip](/assets/images/iot-academy/led_strip.png) Ленту нужно подключить синим&nbsp;(-) проводом к клемме **26**, а белым&nbsp;(+) – к клемме **V+**. "Плюс" и "минус" внешнего источника питания к этому модулю подключаются к клеммам **V+** и **V-** (соответственно). ![umdk-6fet_led](/assets/images/iot-academy/umdk-6fet_led.png) <div class="info"> Использование цветовой маркировки очень часто помагает при монтаже электрических схем и поиске неисправностей. Распространенная практика: "плюсовые" провода имеют более светлую окраску, нежели "минусовые". Очень часто "плюс" – это белый или красный провод, "минус" – синий или черный. </div> Чтобы задействовать транзисторный ключ платы UMDK-6FET на выводе 26 нужно соответствующий переключатель 26 на этой плате установить в положение 'on'. ![apocalypse](/assets/images/iot-academy/apocalypse.gif) Что-то идет явно не так... Всё не работает уже который день... месяц... <div style="min-height:5em;"></div> # Атака SkyNet<a name="atack"></a> Искусственный интеллект SkyNet захватил планету, и сегодня атаке SkyNet подверглись все наши устройства интернета вещей – вы больше не можете полноценно ими управлять, все они вышли из-под контроля! Но остались повстанцы, Сопротивление – люди, недовольные таким порядком вещей, которые всеми силами стараются преодалеть SkyNet и возродить мирную жизнь. Так что отставим в сторону регулятор освещенности. Наша задача – вывести из-под удара все серверы, обслуживающие интернет вещей! Из старых архивов известно, что за трафик IoT отвечают серверы `aws`, `oracle`, `azure`, `thingworx`, `cisco`, `watson`, `thethingsnetwork`, `ibmcloud` и `yandex`. Наши хакеры, проникнув в SkyNet, определили, что если в топик `iot_practice/<UserID>/servers/<IoTServer>` (где `<UserID>` – ваш идентификатор в IT Академии Samsung, а `<IoTServer>` – идентификатор конкретного сервера, например, `iot_practice/5404/servers/yandex`) отправить 6 первых символов md5-хэша, образованного от строки, в которой идентификатор сервера отделен он идентификатора пользователя символом двоеточия (без каких-либо пробелов), например, `yandex:5404`, то указанный сервер окажется в безопасности. Но сделать это надо для всех серверов практически мгновенно, так как SkyNet проверяет контроль над серверами каждые 5&nbsp;секунд, и если вы не справитесь с задачей за это время, то SkyNet вновь возьмет под контроль уже, казалось бы, обезвреженные серверы. ## Задача<a name="task"></a> 1. Создайте новую программу на Python, аналогичную предыдущей, за исключением того, что вместо организации бесконечного цикла ожидания сообщения `client.loop_forever()`, программа будет просто отправлять сообщения командами вроде `client.publish(topic, payload)`. в топик `iot_practice/<UserID>/servers/yandex`. И, да, такой программе совершенно не обязательно подписываться на какие-либо сообщения. 2. Запустите вашу виртуальную умную лампочку (не забудьте настроить ее идентификатор!), и понаблюдайте за ее поведением. Попробуйте передать ей какие-либо команды аналогично предыдущему практикуму (включение, выключение, смена яркости и т.д.). 3. Модифицируйте программу так, чтобы она отправляла в топики `iot_practice/<UserID>/servers/<IoTServer>` коды деактивации SkyNet. <div class="info"> Для справки:<br /> md5("yandex:5404") = 8900E1E22B2EE9ACD93D10131EB4741B<br /> Соответственно, в топик `iot_practice/5404/servers/yandex` нужно отправить сообщение `8900E1` </div> Для вычисления хэша md5 можно воспользоваться каким-либо online-калькулятором или рассчитать прямо в программе на Python. ![skynet_calc](/assets/images/iot-academy/skynet_calc.png)