Saját AI betanítása ESP32-S3-ra – teljes útmutató nullától
Ebben a projektben saját méréseken betanított modellt futtatunk ESP32-S3-on, internet és felhős AI nélkül. A feladat: egy BH1750 fényérzékelőből megállapítani, hogy a környezet sötét (0) vagy világos (1). Egy kis döntési fa (decision stump) tökéletes első modell: könnyű tanítani, tesztelni és néhány C++ sorra lefordítani.
1. Alkatrészlista
| Alkatrész | Mennyiség | Miért kell? |
| ESP32-S3 fejlesztőpanel | 1 db | A helyi AI futtatása |
| BH1750 I²C fényérzékelő modul | 1 db | Luxban méri a fényt |
| Breadboard | 1 db | Kényelmes prototípushoz |
| Dupont jumper vezeték | 4 db | Bekötés |
| USB adatkábel | 1 db | Programozás és soros adatgyűjtés |
| PC Python 3-mal és Arduino IDE-vel | 1 | Betanítás és feltöltés |
*Az ESP32-S3 kiváltható más ESP32-vel, de a választott GPIO-kat és fejlesztőkörnyezetet ellenőrizd. E projekthez nincs szükség PSRAM-ra.*
2. Bekötés
A BH1750 tipikus négy csatlakozója: VCC → 3V3, GND → GND, SDA → GPIO8, SCL → GPIO9. A GPIO-számok az itt választott ESP32-S3 beállításhoz tartoznak; a saját paneleden nézd meg a lábkiosztást. 5 V-ot ne köss közvetlenül a 3,3 V-os I²C jelekre.
3. Arduino IDE beállítása
Telepítsd az Arduino IDE-t, a Board Managerben az esp32 by Espressif Systems csomagot, majd válaszd a saját ESP32-S3 panelodat és COM-portodat. A Library Managerben telepítsd a BH1750 by Christopher Laws könyvtárat.
Elsőként töltsd fel az alábbi adatgyűjtő programot. A soros monitor sebessége 115200 baud legyen. Indításkor csak a CSV fejléc és a mérési sorok jelenjenek meg.
#include <Wire.h>
#include <BH1750.h>
BH1750 sensor;
void setup() {
Serial.begin(115200);
Wire.begin(8, 9); // ESP32-S3: SDA, SCL
if (!sensor.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("# BH1750 hiba: ellenorizd a bekotest");
while (true) delay(1000);
}
Serial.println("lux");
}
void loop() {
if (sensor.measurementReady()) {
float lux = sensor.readLightLevel();
if (lux >= 0) Serial.println(lux, 2);
}
delay(200);
}
Ha szenzorhiba jelentkezik, ellenőrizd az I²C bekötést, a tápot és szükség esetén az I²C címet (BH1750 tipikusan 0x23, ADDR beállítástól függően 0x5C).
4. Gyűjts saját tanítóadatot a számítógépen
Zárd be az Arduino Serial Monitort, majd telepítsd a csomagokat:
python -m venv .venv
# Windows: .venv\Scripts\activate
# Linux/macOS: source .venv/bin/activate
pip install pyserial pandas scikit-learn joblib
Mentés collect.py néven:
import csv, sys, serial
port = sys.argv[1] # Windows: COM5; Linux: /dev/ttyACM0
label = int(sys.argv[2]) # 0 = dark, 1 = bright
assert label in (0, 1)
with serial.Serial(port, 115200, timeout=3) as device, open(
"measurements.csv", "a", newline="", encoding="utf-8"
) as file:
writer = csv.writer(file)
if file.tell() == 0:
writer.writerow(["lux", "label"])
count = 0
while count < 100:
line = device.readline().decode(errors="ignore").strip()
try:
lux = float(line)
except ValueError:
continue
if not 0 <= lux <= 65000:
continue
writer.writerow([lux, label])
count += 1
print("Mentve:", count, "minta; osztály:", label)
Tedd a szenzort sötét helyre, majd futtasd:
python collect.py COM5 0
Ezután tedd világos helyre, és futtasd:
python collect.py COM5 1
A COM5 helyére a saját portodat írd. A program mindig 100-100 mintát vesz; próbálj változatos fényhelyzeteket létrehozni. Ha az adatok csak ugyanabban a két beállításban készülnek, a tesztpontosság félrevezetően magas lehet. Célszerű több különböző megvilágítási körülményben, több körben adatot gyűjteni.
5. Betanítás és tesztelés PC-n
Hozd létre a train.py fájlt:
import pandas as pd
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
import joblib
df = pd.read_csv("measurements.csv")
X = df[["lux"]]
y = df["label"].astype(int)
assert len(df) >= 20 and set(y.unique()) == {0, 1}
X_train, X_test, y_train, y_test = train_test_split(
X, y, test_size=0.25, stratify=y, random_state=42
)
model = DecisionTreeClassifier(max_depth=1, random_state=42)
model.fit(X_train, y_train)
print(classification_report(y_test, model.predict(X_test),
zero_division=0))
joblib.dump(model, "model.joblib")
tree = model.tree_
left = tree.children_left[0]
right = tree.children_right[0]
if left < 0 or right < 0:
raise RuntimeError("A modell nem tanult elválasztást.")
labels = model.classes_
def predicted_class(node):
return int(labels[tree.value[node][0].argmax()])
threshold = float(tree.threshold[0])
with open("model.h", "w", encoding="utf-8") as f:
f.write(
"#pragma once\n"
f"const float THRESHOLD_LUX = {threshold:.6f}f;\n"
f"const int CLASS_LEFT = {predicted_class(left)};\n"
f"const int CLASS_RIGHT = {predicted_class(right)};\n"
"int predict(float lux) {\n"
" return lux <= THRESHOLD_LUX ? CLASS_LEFT : CLASS_RIGHT;\n"
"}\n"
)
print("Elkészült: model.joblib és model.h")
Futtasd:
python train.py
A döntési fa megtanult egy lux-határt. Nem mi írjuk be kézzel a küszöböt: a tanítóadatokból származik. A teszteléshez később gyűjtött, teljesen új környezeti mintákat is használj.
6. Telepítés az ESP32-re
Másold a generált model.h fájlt ugyanabba a mappába, mint az új Arduino sketch (.ino). Cseréld a korábbi adatgyűjtő programot erre:
#include <Wire.h>
#include <BH1750.h>
#include "model.h"
BH1750 sensor;
void setup() {
Serial.begin(115200);
Wire.begin(8, 9);
if (!sensor.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("Szenzorhiba");
while (true) delay(1000);
}
}
void loop() {
if (sensor.measurementReady()) {
float lux = sensor.readLightLevel();
if (lux >= 0) {
int result = predict(lux);
Serial.print("Lux: ");
Serial.print(lux);
Serial.print(" | AI: ");
Serial.println(result == 1 ? "VILAGOS" : "SOTET");
}
}
delay(200);
}
Töltsd fel, nyisd meg a Serial Monitort 115200 baudon, és változtasd a megvilágítást. Az inferencia most a mikrokontrolleren történik: nem kell hozzá hálózat, Python vagy szerver.
7. Mi van, ha nem működik?
- Nem látod a portot? Ellenőrizd az USB-adatkábelt és az ESP32-S3 USB-beállítását.
- I²C hiba? Ellenőrizd SDA/SCL bekötést, a 3,3 V tápot és a szenzor címét.
- Minden „világos”? Nézd meg a
measurements.csvcímkéit, illetve hogy a sötét mérések tényleg eltérnek-e. - Pontatlan a modell? Gyűjts adatot különböző körülményekből, és próbáld ki korábban nem használt helyen.
- Újra kell tanítani? Gyűjts új CSV sorokat, futtasd a
train.py-t, és töltsd fel az újmodel.h-t.
8. Miben más egy neurális hálózat?
A mostani modell AI/ML, de nem deep learning. Következő lépésként több szenzoradatból, idősorokból vagy hangmintákból egy kicsi kvantált neurális hálózatot is taníthatsz TensorFlow Lite Micro vagy ESP-DL segítségével. Az már memóriatervezést és külön modellkonverziót igényel.
Testvércikk: Ugyanez az AI Raspberry Pi-on: adatgyűjtés, tanítás, futtatás.