Практическая работа | Урок 24 | Прикладная робототехника
Мобильная станция экологического мониторинга — автономный робот, который:
| 🌡️ Температура | 💧 Влажность | ☀️ Освещенность | 🌬️ Качество воздуха |
|---|---|---|---|
| DHT22 | DHT22 | BH1750 | MQ-135 |
| -40…+80°C | 0-100% RH | 0-65535 lx | 10-10000 ppm |
| ±0.5°C | ±2-5% | ±20% | CO₂, NH₃, NOₓ |
| Digital | Digital | I²C | Analog |
🔬 Сенсоры → 🧠 Микроконтроллер → 📱 Дисплей
↓
📡 Беспроводная связь → 💻 Компьютер → 📊 Анализ → 🗂️ База данных
| Блок | Функция | Технология | Параметры |
|---|---|---|---|
| Сенсорный | Измерение параметров | Аналоговые/цифровые датчики | 1-4 датчика |
| Обработки | Сбор и обработка данных | Arduino Uno/Mega/ESP32 | 16 МГц, 32 КБ |
| Отображения | Локальная визуализация | LCD I2C 16×2/20×4 | Подсветка, контраст |
| Связи | Передача данных | Bluetooth HC-05/ESP32 WiFi | 9600-115200 bps |
| Питания | Автономность | Li-ion/Li-Po батарея | 7.4-12V, 2000+ мАч |
DHT22 (Температура/Влажность):
├─ VCC → 5V
├─ GND → GND
└─ DATA → Pin 2
BH1750 (Освещенность):
├─ VCC → 3.3V
├─ GND → GND
├─ SCL → A5
└─ SDA → A4
MQ-135 (Качество воздуха):
├─ VCC → 5V
├─ GND → GND
└─ AOUT → A0
LCD I2C (Дисплей):
├─ VCC → 5V
├─ GND → GND
├─ SCL → A5
└─ SDA → A4
HC-05 (Bluetooth):
├─ VCC → 5V
├─ GND → GND
├─ TX → Pin 8
└─ RX → Pin 9
Без калибровки:
После калибровки:
где:
Эталон: 22.0°C → Датчик: 21.5°C
Эталон: 5.0°C → Датчик: 4.8°C
Эталон: 40.0°C → Датчик: 39.2°C
K = (40.0 - 5.0) / (39.2 - 4.8) = 35.0 / 34.4 = 1.017
B = 5.0 - 1.017 × 4.8 = 0.118
Формула: T_cal = T_sensor × 1.017 + 0.118
// Основные блоки программы
void setup() {
// Инициализация датчиков и модулей
}
void loop() {
// Основной цикл работы
readSensors(); // Чтение датчиков
processData(); // Обработка данных
displayData(); // Отображение на LCD
sendData(); // Передача по Bluetooth
delay(interval); // Пауза между измерениями
}
// Скользящее среднее для сглаживания
float movingAverage(float newValue, float oldAverage, int n) {
return (oldAverage * (n-1) + newValue) / n;
}
// Медианный фильтр для удаления выбросов
float medianFilter(float values[], int size) {
// Сортировка массива
for (int i = 0; i < size-1; i++) {
for (int j = i+1; j < size; j++) {
if (values[i] > values[j]) {
float temp = values[i];
values[i] = values[j];
values[j] = temp;
}
}
}
return values[size/2]; // Возврат медианы
}
void displayData() {
lcd.clear();
// Первая строка: Температура и влажность
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(temperature, 1); // 1 знак после запятой
lcd.print("C H:");
lcd.print(humidity, 0); // Без дробной части
lcd.print("%");
// Вторая строка: Освещенность и качество воздуха
lcd.setCursor(0, 1);
lcd.print("L:");
if (lightLevel < 1000) {
lcd.print((int)lightLevel);
} else {
lcd.print(lightLevel/1000.0, 1);
lcd.print("k");
}
lcd.print(" A:");
lcd.print(airQuality);
}
void sendData() {
String jsonData = "{";
jsonData += "\"timestamp\":" + String(millis()) + ",";
jsonData += "\"temperature\":" + String(temperature, 2) + ",";
jsonData += "\"humidity\":" + String(humidity, 1) + ",";
jsonData += "\"light\":" + String(lightLevel, 0) + ",";
jsonData += "\"airQuality\":" + String(airQuality);
jsonData += "}";
bluetooth.println(jsonData);
Serial.println(jsonData); // Дублирование в консоль для отладки
}
void sendDataCSV() {
String csvData = String(millis()) + "," +
String(temperature, 2) + "," +
String(humidity, 1) + "," +
String(lightLevel, 0) + "," +
String(airQuality);
bluetooth.println(csvData);
}
import serial
import matplotlib.pyplot as plt
import json
from collections import deque
import time
class EcoMonitor:
def __init__(self, port='COM5', baudrate=9600):
self.serial_connection = serial.Serial(port, baudrate)
self.data_buffer = {
'time': deque(maxlen=100),
'temperature': deque(maxlen=100),
'humidity': deque(maxlen=100),
'light': deque(maxlen=100),
'air_quality': deque(maxlen=100)
}
def read_data(self):
"""Чтение данных с Arduino"""
if self.serial_connection.in_waiting:
raw_data = self.serial_connection.readline().decode().strip()
try:
# Парсинг JSON или CSV данных
data = json.loads(raw_data)
return data
except:
# Fallback для CSV формата
values = raw_data.split(',')
if len(values) == 5:
return {
'timestamp': int(values[0]),
'temperature': float(values[1]),
'humidity': float(values[2]),
'light': float(values[3]),
'airQuality': int(values[4])
}
return None
def setup_plots(self):
"""Настройка графических окон"""
self.fig, self.axes = plt.subplots(2, 2, figsize=(12, 8))
self.fig.suptitle('Мониторинг окружающей среды')
# Настройка каждого графика
self.axes[0,0].set_title('Температура (°C)')
self.axes[0,0].set_ylim(0, 50)
self.axes[0,0].grid(True)
self.axes[0,1].set_title('Влажность (%)')
self.axes[0,1].set_ylim(0, 100)
self.axes[0,1].grid(True)
self.axes[1,0].set_title('Освещенность (lx)')
self.axes[1,0].set_yscale('log') # Логарифмический масштаб
self.axes[1,0].grid(True)
self.axes[1,1].set_title('Качество воздуха')
self.axes[1,1].set_ylim(0, 1023)
self.axes[1,1].grid(True)
plt.tight_layout()
plt.ion() # Интерактивный режим
THRESHOLDS = {
'temperature': {'min': 18, 'max': 26}, # Комфортная температура
'humidity': {'min': 40, 'max': 60}, # Оптимальная влажность
'light': {'min': 200, 'max': 1000}, # Достаточное освещение
'air_quality': {'min': 0, 'max': 300} # Приемлемое качество воздуха
}
def check_alerts(self, data):
"""Проверка превышения пороговых значений"""
alerts = []
for param, value in data.items():
if param in THRESHOLDS:
threshold = THRESHOLDS[param]
if value < threshold['min']:
alerts.append(f"⚠️ {param}: {value} ниже нормы ({threshold['min']})")
elif value > threshold['max']:
alerts.append(f"🚨 {param}: {value} выше нормы ({threshold['max']})")
return alerts
| Роль | Ответственность | Основные задачи |
|---|---|---|
| 🔧 Конструктор | Механическая часть | Сборка платформы, крепление компонентов |
| ⚡ Электронщик | Электроника | Подключение датчиков, проводка |
| 💻 Программист | Код и алгоритмы | Программирование Arduino, отладка |
| 🧪 Тестировщик | Качество | Калибровка, тестирование, валидация |
Механика:
Размещение компонентов:
□ DHT22 подключен к Pin 2 (проверить питание 5V)
□ BH1750 подключен к I2C (SDA/SCL, питание 3.3V)
□ MQ-135 подключен к A0 (питание 5V, прогрев 24ч)
□ LCD I2C подключен к I2C (адрес 0x27, питание 5V)
□ HC-05 подключен к Pin 8/9 (питание 5V)
□ Все GND соединены с общей землей
□ Питание подается от стабилизированного источника
□ Проводка аккуратная, соединения надежные
Температура:
Влажность:
Освещенность:
| Датчик | Показание | Эталон | Коэффициент |
|---|---|---|---|
| DHT22 (T) | ___ °C | ___ °C | K = ___ |
| DHT22 (H) | ___ % | ___ % | K = ___ |
| BH1750 | ___ lx | ___ lx | K = ___ |
#include <DHT.h>
#include <Wire.h>
#include <BH1750.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
// Конфигурация пинов
#define DHT_PIN 2
#define DHT_TYPE DHT22
#define MQ135_PIN A0
#define BT_RX 8
#define BT_TX 9
// Инициализация объектов
DHT dht(DHT_PIN, DHT_TYPE);
BH1750 lightMeter;
LiquidCrystal_I2C lcd(0x27, 16, 2);
SoftwareSerial bluetooth(BT_RX, BT_TX);
// Переменные данных
struct SensorData {
float temperature;
float humidity;
float light;
int airQuality;
unsigned long timestamp;
};
SensorData currentData;
void setup() {
// TODO: Инициализация всех компонентов
}
void loop() {
// TODO: Основной цикл работы
}
void readSensors() {
// Чтение температуры и влажности
currentData.temperature = dht.readTemperature();
currentData.humidity = dht.readHumidity();
// Проверка на ошибки DHT22
if (isnan(currentData.temperature) || isnan(currentData.humidity)) {
Serial.println("Ошибка чтения DHT22!");
return;
}
// Чтение освещенности
currentData.light = lightMeter.readLightLevel();
// Чтение качества воздуха
currentData.airQuality = analogRead(MQ135_PIN);
// Временная метка
currentData.timestamp = millis();
// Применение калибровочных коэффициентов
applyCalibration();
}
void applyCalibration() {
// TODO: Применить коэффициенты калибровки
currentData.temperature *= TEMP_CALIBRATION;
currentData.humidity *= HUMIDITY_CALIBRATION;
currentData.light *= LIGHT_CALIBRATION;
}
void displayData() {
lcd.clear();
// Строка 1: T:25.3C H:45%
lcd.setCursor(0, 0);
lcd.print("T:");
lcd.print(currentData.temperature, 1);
lcd.print("C H:");
lcd.print((int)currentData.humidity);
lcd.print("%");
// Строка 2: L:1250 A:245
lcd.setCursor(0, 1);
lcd.print("L:");
if (currentData.light < 1000) {
lcd.print((int)currentData.light);
} else {
lcd.print(currentData.light/1000, 1);
lcd.print("k");
}
lcd.print(" A:");
lcd.print(currentData.airQuality);
}
void sendData() {
// JSON формат для структурированной передачи
String jsonString = "{";
jsonString += "\"time\":" + String(currentData.timestamp) + ",";
jsonString += "\"temp\":" + String(currentData.temperature, 2) + ",";
jsonString += "\"hum\":" + String(currentData.humidity, 1) + ",";
jsonString += "\"light\":" + String(currentData.light, 0) + ",";
jsonString += "\"air\":" + String(currentData.airQuality);
jsonString += "}";
// Отправка через Bluetooth
bluetooth.println(jsonString);
// Дублирование в Serial для отладки
Serial.println(jsonString);
}
Базовая функциональность:
Точность измерений:
Тест 1: Температурный отклик
Тест 2: Влажностный отклик
Тест 3: Световой отклик
Тест 4: Качество воздуха
# Быстрый тест приема данных
import serial
import json
ser = serial.Serial('COM5', 9600) # Замените на ваш порт
for i in range(10): # Прочитать 10 измерений
if ser.in_waiting:
data = ser.readline().decode().strip()
try:
parsed = json.loads(data)
print(f"T: {parsed['temp']}°C, "
f"H: {parsed['hum']}%, "
f"L: {parsed['light']}lx, "
f"A: {parsed['air']}")
except:
print(f"Raw data: {data}")
🔬 “Наша станция умеет…” (60 сек)
📊 “Точность наших измерений…” (45 сек)
🚀 “Уникальные особенности…” (30 сек)
| Критерий | Оценка | Описание |
|---|---|---|
| Функциональность | 0-5 | Все ли работает как задумано? |
| Точность измерений | 0-5 | Насколько данные соответствуют реальности? |
| Стабильность | 0-3 | Есть ли сбои, ошибки, зависания? |
| Автономность | 0-3 | Время работы от батареи |
| Презентация | 0-4 | Качество объяснения и демонстрации |
Максимум: 20 баллов
Ближайшие улучшения:
Долгосрочные цели:
Технический отчет о мобильной станции
Описание системы (1 страница)
Калибровка и тестирование (1 страница)
Программная реализация (0.5 страницы)
Результаты измерений (0.5 страницы)
“Эко-станция будущего”
“Сегодня вы создали не просто робота — вы создали цифрового помощника в защите окружающей среды. Каждый ваш датчик — это окно в мир природы, каждое измерение — шаг к пониманию планеты”