Это авторский материал IoT лаборатории ЮУрГУ, представленный в дополнение к существующему практикуму.
# Регулятор освещения/lamp/value` мы можем менять уровень свечения лампы,
изменяя тем самым освещеность того места, над которым лампа располагается (конечно же, речь в данном случае не о виртуальной
лампе, а о настоящей).
Нынешняя цель – сделать так, чтобы умная лампочка не только светилась с заданной яркостью, но и создавала требуемый уровень
освещенности в месте, где она установлена. Вообще, это классическая задача ТАУ (теории автоматического управления).
Кстати, ранее (в 60-х...70-х годах прошлого века) использовался термин ТАР – теория автоматического регулирования.
Для решения подобного рода задачи необходим **регулятор** (Р), который на основе информации от **датчика** (Д),
измеряющего интересующий нас параметр *y* **объекта управления** (ОУ), сформирует такое **управляющее воздействие** *u*,
которое обратит величину **ошибки** *e* в ноль. Ошибка – это разность между **уставкой** (или **желаемым значением**)
сигнала *y*\* и либо его реальным текущим значением *y*, получаемым непосредственно с объекта управления,
либо оценки сигнала *ŷ*, получаемой средствами измерения, то есть при помощи датчика (как показано на рисунке).
![sys_ctrl](/assets/images/iot-academy/sys_ctrl.png)
Существуют разные законы управления, по которым работают регуляторы. Самый простой – *пропорциональный* закон управления
(в ТАУ его ещё называю П-законом, а регулятор – П-регулятором). Суть очень проста: величина ошибки умножается на некоторую
константу – это и есть управляющее воздействие.
Тем не менее, П-регулятор для нашего случая плохо подходит, так как наш объект (лампа) срабатывает очень быстро (и быстрее скорости
света пока еще ничего не открыли), и пока регулятор расчитает нужное значение, лампа уже включится на полную мощность.
Лучшим выбором будет использование И-регулятора (*интегрального*).
Что И-регулятор, что П-регулятор – это все частные случаю более общего, ПИД-регулятора.
Есть достаточно много информации на эту тему. Например, [тут](https://odinelectric.ru/kipia/chto-takoe-pid-regulyator-dlya-chajnikov)
или [тут](https://www.reallab.ru/bookasutp/5-pid-regulyatori/5-2-klassicheskii-pid-regulyator/).
Ранее мы уже [эксперементировали](/iot/sensors) с датчиком освещенности, и, соответственно, знаем как получить текущее значение
освещенности в [люксах](https://ru.wikipedia.org/wiki/Люкс). Определив для себя некоторый желаемый уровень освещенности,
например, *y*\*=500 лк, давайте порассуждаем, что будет происходить. Если у нас темно, и значение с датчика освещенности меньше
желаемого значения, то яркость лампочки нужно увеличить. Если же, наоборот, значение с датчика освещенности больше уставки,
то яркость нужно убавлять. И вот если желаемое и действительное значение равны друг другу, то нужно перестать "крутить ручку яркости"
лампы – то есть нужно зафиксировать сигнал управления на прежнем уровне. Этого как раз и можно добиться введением И-регулятора.
Тут ещё нужно вспомнить, что лампа у нас управляется заданием уровня яркости, выраженным в процентах, и, соответственно,
не может быть меньше нуля и больше 100 %. Таким образом, реализация регулятора при помощи некоторого псевдо-кода
(близкого по синтаксису к языкам 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%
...
```
Коэффициент пропорциональности `K` в программе задается один раз. Его можно подобрать на основе серии экспериментов или рассчитать
средствами классической ТАУ. Уставка `luminocity_sp` в целом может меняться (но в данном фрагменте программы это не рассматривается),
ведь наши предпочтения относительно уровня освещенности могут меняться.
Тут сделаем ещё одно пояснение. Интегрирование – это фактически суммирование. Соответственно, переменная `light` в этом фрагменте
программы и реализует тот самый, необходимый нам, И-закон регулирования.
Совместим две ранее написанных программы: [опрос датчика освещенности](/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 В источника напряжения:
![led_strip](/assets/images/iot-academy/led_strip.png)
Ленту нужно подключить синим (-) проводом к клемме **26**, а белым (+) – к клемме **V+**.
"Плюс" и "минус" внешнего источника питания к этому модулю подключаются к клеммам **V+** и **V-** (соответственно).
![umdk-6fet_led](/assets/images/iot-academy/umdk-6fet_led.png)
Использование цветовой маркировки очень часто помагает при монтаже электрических схем и поиске неисправностей.
Распространенная практика: "плюсовые" провода имеют более светлую окраску, нежели "минусовые".
Очень часто "плюс" – это белый или красный провод, "минус" – синий или черный.
Чтобы задействовать транзисторный ключ платы UMDK-6FET на выводе 26 нужно соответствующий переключатель 26 на этой плате
установить в положение 'on'.
![apocalypse](/assets/images/iot-academy/apocalypse.gif)
Что-то идет явно не так...
Всё не работает уже который день... месяц...
# Атака SkyNet
Искусственный интеллект SkyNet захватил планету, и сегодня атаке SkyNet подверглись все наши устройства интернета
вещей – вы больше не можете полноценно ими управлять, все они вышли из-под контроля! Но остались повстанцы, Сопротивление – люди,
недовольные таким порядком вещей, которые всеми силами стараются преодалеть SkyNet и возродить мирную жизнь.
Так что отставим в сторону регулятор освещенности. Наша задача – вывести из-под удара все серверы, обслуживающие интернет вещей!
Из старых архивов известно, что за трафик IoT отвечают серверы `aws`, `oracle`, `azure`, `thingworx`, `cisco`, `watson`,
`thethingsnetwork`, `ibmcloud` и `yandex`.
Наши хакеры, проникнув в SkyNet, определили, что если в топик `iot_practice//servers/`
(где `` – ваш идентификатор в IT Академии Samsung, а `` – идентификатор конкретного сервера,
например, `iot_practice/5404/servers/yandex`) отправить 6 первых символов md5-хэша, образованного от строки,
в которой идентификатор сервера отделен он идентификатора пользователя символом двоеточия (без каких-либо пробелов),
например, `yandex:5404`, то указанный сервер окажется в безопасности.
Но сделать это надо для всех серверов практически мгновенно, так как SkyNet проверяет контроль над серверами каждые 5 секунд,
и если вы не справитесь с задачей за это время, то SkyNet вновь возьмет под контроль уже, казалось бы, обезвреженные серверы.
## Задача
1. Создайте новую программу на Python, аналогичную предыдущей, за исключением того, что вместо организации бесконечного цикла ожидания
сообщения `client.loop_forever()`, программа будет просто отправлять сообщения командами вроде `client.publish(topic, payload)`.
в топик `iot_practice//servers/yandex`. И, да, такой программе совершенно не обязательно подписываться на
какие-либо сообщения.
2. Запустите вашу виртуальную умную лампочку (не забудьте настроить ее идентификатор!), и понаблюдайте за ее поведением.
Попробуйте передать ей какие-либо команды аналогично предыдущему практикуму (включение, выключение, смена яркости и т.д.).
3. Модифицируйте программу так, чтобы она отправляла в топики `iot_practice//servers/` коды деактивации SkyNet.
Для справки:
md5("yandex:5404") = 8900E1E22B2EE9ACD93D10131EB4741B
Соответственно, в топик `iot_practice/5404/servers/yandex` нужно отправить сообщение `8900E1`
Для вычисления хэша md5 можно воспользоваться каким-либо online-калькулятором или рассчитать прямо в программе на Python.
![skynet_calc](/assets/images/iot-academy/skynet_calc.png)