1. КОМАНДА "Keenetic lite lll" 

 
Хисматуллин Радмир Богданов Азат Антонов Илья Саиткулов Данил
«Keenetic Lite III» - это команда энтузиастов, лидеров изменений из МАОУ «БЛИ №3» г. Стерлитамак Республики Башкортостан (9класс)
Наша команда профилируется в следующих направлениях: Электронная инженерия: Умный город, Machine Learning & Data Science и IoT. Активно работаем над своими soft & hard skills, имеем огромный опыт проектных работ в команде.
Наши проекты:
• Сетевая инфраструктура Умного города на основе MQTT и Node Red,
• Многофункциональное интернет-устройство,
• Конвейер-сортировщик на основе TensorFlow.
Являемся финалистами два года подряд Олимпиады Кружкового движения НТИ по профилям: Умный город, Научно-инженерная коммуникация и Интернет вещей. Участники заключительного этапа Всероссийской робототехнической олимпиады 2019 (WRO, сезон «Умные города»). Каждый член команды является призером различных этапов ВОШ и других предметных олимпиад по информатике, физике, математике и астрономии.
Мы верим, что современные технологии и наша команда помогут человечеству менять наш мир к лучшему и прекрасному. Мы из будущего 2035! 

 

 

Описание устройства:

Устройство предназначено для поддержания климата в ограниченной среде, включающая себя систему мониторинга и формирования микроклимата в ограниченной области пространства  , являющегося прототипом системы жизнеобеспечения удаленной, автономной, обитаемой станции — космического корабля, лунной базовой станции или подводного аппарата.

Описание работы:

Задается начальный уровень воды в боксе - половина от макс.объема воды

также константа уровня CO2

Основной цикл содержит 3 подпрограммы:

-снятие показаний данных с датчиков и их контроль с периодом 1 сек.

-поддержка уровня воды в боксе

-поддержка уровня СО2 в боксе

Акцент  был сделан безопасность работы и отказоустойчивость устройства что очень важно в 

В случае неисправности датчиков/насосов, алгоритм анализирует обратную связь, с изменением определенного параметра, если он не менятся в течении времени, система видит ошибку и прерывает работу алгоритма.

Датчик уровня воды (угловой) AMP-X22 - установлен на предельном уровне воды, если дальномер откажет то вода не поднимется выше предела по запасной логике.

Основной алгоритм же просто поддерживает работу по простой логике больше/меньше  и вкл/выкл вентилятор/насос

Принципиальная схема:

Алгоритм работы:

 

 

 

 

Задача 2

Написать и отладить на удаленном учебном стенде программу автоматической работы устройства контроля микроклимата (см Базовую схему и таблицу межблочных электрических соединений), которое выполняет следующие действия

1. Закачивает в "жилой бокс" слабогазированную воду до максимальной отметки, фиксируемой датчиком уровня воды.

2. Измеряет уровень СО2 (измеряется в ppm) в момент достижения максимальной отметки и через 10 сек. Принимает среднее значение этих двух измерения за ОПТИМАЛЬНЫЙ уровень СО2.

3. С помощью вентилятора, выкачивающего воздух, и погружных насосов, удерживает уровень СО2 в "жилом боксе" в течение 5 минут на ОПТИМАЛЬНОМ уровне +/- 20 ppm.

В случае если во время удаленного тестирования или финального испытания уровень воды в "жилом боксе" поднялся до красной отметки, расположенной выше датчика уровня воды, устройство выключается в организаторами в ручном, аварийном порядке.
 
Нашей задачей является создание программы автоматической работы устройства контроля микроклимата.
Цель - удерживать ОПТИМАЛЬНЫЙ уровень СО2 (+/- 20 ppm), контролировать и регулировать ДОПУСТИМЫЙ уровень воды (не выше максимальной отметки).
Для этой цели наше устройство сделано на базе платы Arduino UNO с подключенными к ней вентилятором, 2 погружными помпами и датчиками. Управление вентилятором осуществляется через Реле (Troyka-модуль), помпами с помощью Motor Shield (2 канала, 2 А).
Контроль микроклимата осуществляется на основании показаний датчиков:
1) Датчик углекислого газа MQ-135 (Troyka-модуль)
2) Ультразвуковой дальномер HC-SR04
3) Датчик уровня воды (угловой)
Программа состоит из подпрограмм:
  • Инициализация и калибровка - Init
  • Управление насосами - Pomps_control
  • Управление вентилятором - Fan_control
  • Поддержание CO2 - CO2Control
  • Управление водой / CO2 – WaterControl
  • Передача данных на IoT Alterzoom – DataServer
При запуске программы в Init выполняются следующие задачи:
1. Заполнение "жилого бокса" слабогазированной водой до максимальной отметки.
2. Прогревание датчика СО2
3. Определение ОПТИМАЛЬНОГО уровня СО2
Далее подпрограммы CO2Control и WaterControl удерживают ОПТИМАЛЬНЫЙ уровень СО2 в течение 5 минут обеспечивают ДОПУСТИМЫЙ уровень воды в "жилом боксе".
Подпрограмма DataServer осуществляет передачу даннных. На интерактивные графики выводятся
1. уровень воды, [см] (высота относительно дна бокса в см)
2. уровень газа СО2, [ppm] 

Базовая схема устройства контроля микроклимата

Таблица межблочных электрических соединений

 Элемент  Контакт  Контакт  Элемент

Датчик углекислого газа MQ-135 (Troyka-модуль)

Артикул AMP-B094

S

5V

Arduino UNO R3

V

A0

G

GND

E

09

Ультразвуковой дальномер HC-SR04

Артикул AMP-X142-U2

GND

GND

Echo

11

Trig

10

VCC

08

Датчик уровня воды (угловой)

Артикул AMP-X221

*

GND

*

12

Motor Shield (2 канала, 2 А)

Артикул AMP-B001

H2

07

E2

06

E1

05

H1

04

M1 +

Красный провод

Погружная помпа с трубкой

Артикул AMP-X157 №1

M1 -

Черный провод

M2 +

Красный провод

Погружная помпа с трубкой

Артикул AMP-X157 №2

M2 -

Черный провод

+

-V

Встраиваемый блок питания (12 В, 2100 мА)

Артикул AMP-X285

-

+V

Реле (Troyka-модуль)

Артикул AMP-B010

S

A5

Arduino UNO R3

V

3,3V

G

-V

Встраиваемый блок питания (12 В, 2100 мА)

Артикул AMP-X285

NO

COM

Черный провод

Вентилятор Evercool EC2510H12B (12В, 25х25х10мм)

Встраиваемый блок питания (12 В, 2100 мА)

Артикул AMP-X285

+V

Красный провод

Примечания:
1. У датчика углекислого газа MQ-135 (Troyka-модуль) Артикул AMP-B094 перемычка «H=V» установлена
2. У Motor Shield (2 канала, 2 А) Артикул AMP-B001 перемычка «PWR JOINT» установлена
3. Погружная помпа с трубкой Артикул AMP-X157 №1 – установлена в "жилом боксе". 
4. Погружная помпа с трубкой Артикул AMP-X157 №2 – установлена в боксе с газированной водой

 

 

 

Код программы:

 

#include <Arduino.h>
#include <TroykaMQ.h>
#include <Ultrasonic.h>
#include <ARpcDevice.h>


#pragma region config

#define DEBUG 1
#define CO2_TIME 5000
#define CO2_HEAT_TIME 60000
#define CO2_DELTA 20
#define CO2_OK_DELAY 1000
#define HEAT_MQ 0
#define SERVER_INTERVAL 2000

#pragma region actuating_device
#define H2 7
#define E2 6
#define E1 5
#define H1 4
#define FAN_PIN A5
#pragma endregion

#pragma region senors
#define DIST_TRIG 10
#define DIST_ECHO 11
#define WATER_PIN 12
#define MQ135_PIN A0
#pragma endregion

#pragma region sensors_object
Ultrasonic water_dist(DIST_TRIG, DIST_ECHO);
MQ135 mq135(MQ135_PIN);
#pragma endregion

#pragma region server
const char *deviceName="lite 3";//имя устройства
const ARpcUuid deviceId("{49b95e88-1168-4254-bb2f-9cb90915718c}");//идентификатор устройства


const char *sensorsDef="<sensors>"
"<sensor name=\"deep\" type=\"f32_sv\"/>"
"<sensor name=\"co2\" type=\"f32_sv\"/>"
"</sensors>";

class WriteCallback
    :public ARpcIWriteCallback
{
public:
    virtual void writeData(const char *data,unsigned long sz)
    {
        Serial.write(data,sz);
    }
    virtual void writeStr(const char *str)
    {
        Serial.print(str);
    }
    virtual void writeStr(const __FlashStringHelper *str)
    {
        Serial.print(str);
    }
}wcb;

ARpcDevice dev(300,&wcb,&deviceId,deviceName);

#pragma endregion

#pragma region Setpoints
int water_mode = 0;       
int optimal_co2 = -1;
long pomp_delta = -1;
int co2_mode = -1;
int end_deep = -1;
int start_deep = -1;

int co2_init = 0;


#pragma endregion
#pragma endregion





void Pomps_control(bool in, bool out){  //Управление насосами

  if (DEBUG) {
    Serial.println();
    Serial.print("  [Log]Pomp state: ");
    Serial.print(in);
    Serial.print(out);}

  digitalWrite(H1, 1);
  analogWrite(E1, in * 255);

  digitalWrite(H2, 1);
  analogWrite(E2, out * 255);
}

void Fan_control(bool mode){ //Управление вентилятором

  if (DEBUG) {
    Serial.println();
    Serial.print("  [log] Fan state: ");
    Serial.print(mode);}

  digitalWrite(FAN_PIN, mode);
}

void DataServer()  // Передача данных на IoT Alterzoom по Serial
{                    
    while(Serial.available())  //проверяем, нет ли данных в Serial
        dev.putByte(Serial.read());  //если данные есть, передаем в объект библиотеки
    
   if(millis() % SERVER_INTERVAL == 0){

     dev.disp().writeMeasurement("co2", String(mq135.readCO2()).c_str());
     dev.disp().writeMeasurement("deep", String(start_deep - water_dist.distanceRead()).c_str());
  }
}


int _prevState = -1;
int _currState = -1;
long _lastChangeTime = 0;
long timer = -1;
void WaterControl()  // Упраление водой / CO2
{
    if(water_mode == 1){

    int state = !digitalRead(WATER_PIN);
    long t = millis();
    if (state != _prevState) _lastChangeTime = t;
    if (t - _lastChangeTime > 50) {
    if (state != _currState) { _currState = state;

        if(state){

          if (DEBUG) {
            Serial.println();
            Serial.print("  [water] is max");
          }

          Pomps_control(0, 0);

        }
    }
    
    }
   _prevState = state; 
  }

  
}


int prev_co = -1;
void CO2Control()  // Поддержание CO2
{

    if(co2_init){
  
    int val_co = mq135.readCO2(); //считывание

    if(prev_co != val_co && abs(val_co - prev_co) > 5){ //проверяем изменилиь ли показания


    if (DEBUG) {
      Serial.println();
      Serial.print("  [MQ135] CO2 LEVEL: ");
      Serial.print(val_co);
      }

    if(val_co > optimal_co2 && (abs(val_co - optimal_co2) > CO2_DELTA)){ // > газа стало больше
      if(co2_mode != 1){
      co2_mode = 1;
      if (DEBUG) {
      Serial.println();
      Serial.print("  [CO2] CO2 LEVEL >");
      }
      
      Fan_control(1); // Вкл вытяжного вентилятора

      }
    }
    else if(val_co < optimal_co2 && (abs(val_co - optimal_co2) > CO2_DELTA)){ // < газа стало меньше
      if(co2_mode != 2){
      co2_mode = 2;
      if (DEBUG) {
      Serial.println();
      Serial.print("  [CO2] CO2 LEVEL <");
      }

      Pomps_control(1, 1);
      water_mode = 1; // Вкл подачи воды / обогащение СО2

      }
    }
    else{ 
     if(co2_mode != 3){ //Уровень оптимальный
      co2_mode = 3;
      if (DEBUG) {
        Serial.println();
        Serial.print("--CO2 LEVEL OK--");
      }

      delay(CO2_OK_DELAY); //Задержка для приблилежения к оптимальному знчению
       
      water_mode = 0;
      
      Pomps_control(0,0);
      Fan_control(0);

      }
          
    }
    prev_co = val_co; 
 
    }
  }
  
}

int prevState = -1;
int currState = -1;
long lastChangeTime = 0;
long end_time = -1;
long start_time = -1;

int first_co = -1;
int second_co = -1;


void Init()  //Инициализация и калибровка
{
  
  if (DEBUG) {
      Serial.println();
      Serial.print("Task #1 start: ");
      Serial.print(millis());
      Serial.println();
     }

  dev.disp().setSensors(sensorsDef); // сервак
  dev.resetStream();
  
  if(water_dist.distanceRead() == 0 ){
    if (DEBUG) {
      Serial.println();
      Serial.print("ERROR: HC-SR04");
    }
  }
  if(analogRead(MQ135_PIN) < 500 ){
    if (DEBUG) {
      Serial.println();
      Serial.print("ERROR: MQ135 < 500");
      Serial.println();
    }
  }

  if(HEAT_MQ){
  if (DEBUG) {
      Serial.println();
      Serial.print(" [MQ-135] HEATING START");
     }
    delay(CO2_HEAT_TIME);
  }

  mq135.calibrate();

  if (DEBUG) {
      Serial.println();
      Serial.print("CO2 ppm: ");
      Serial.print(mq135.readCO2());
      Serial.println();
      Serial.print("Water level: ");
      Serial.print(water_dist.distanceRead());
     }

  start_deep = water_dist.distanceRead();
  start_time = millis();
 
  Pomps_control(1,0);
}



void setup() { 

  Serial.begin(9600);
  
   
  pinMode(E1, OUTPUT);
  pinMode(E2, OUTPUT);
  pinMode(H1, OUTPUT);
  pinMode(H2, OUTPUT);
  pinMode(FAN_PIN, OUTPUT);
  pinMode(WATER_PIN, INPUT_PULLUP);
 
  Init(); //Инициализация / калибровка

}

void loop(){
 
if(!co2_init){

    int state = !digitalRead(WATER_PIN);
    long t = millis();
    if (state != prevState) lastChangeTime = t;
    if (t - lastChangeTime > 50) {
    if (state != currState) { currState = state;

      if(state){
      Pomps_control(0,0);
      end_time = millis();  
      pomp_delta = end_time - start_time;
      first_co = mq135.readCO2();
      end_deep = water_dist.distanceRead();

      if (DEBUG) {
        Serial.println();
        Serial.print("Pomp time delta: ");
        Serial.print(pomp_delta);
        Serial.println();
        Serial.print("First CO2: ");
        Serial.print(first_co);
        }

      delay(CO2_TIME);

      second_co = mq135.readCO2();

      optimal_co2 = (first_co + second_co) / 2;

      if (DEBUG) {
        Serial.println();
        Serial.print("Second CO2: ");
        Serial.print(second_co);
        Serial.println();
        Serial.print("--Optimal CO2: --");
        Serial.print(optimal_co2);
        }

        Pomps_control(0, 1);
        delay(pomp_delta / 2);
        Pomps_control(0, 0);

        co2_init = 1;

      }

       }
    }
    prevState = state; 


}

CO2Control();
WaterControl();
if(!DEBUG) DataServer();

 

 

Интерактивные графики показаний датчиков устройства: