HULUGAMES
← All news

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.

ESP32-S3 saját AI projekt illusztráció

1. Alkatrészlista

AlkatrészMennyiségMiért kell?
ESP32-S3 fejlesztőpanel1 dbA helyi AI futtatása
BH1750 I²C fényérzékelő modul1 dbLuxban méri a fényt
Breadboard1 dbKényelmes prototípushoz
Dupont jumper vezeték4 dbBekötés
USB adatkábel1 dbProgramozás és soros adatgyűjtés
PC Python 3-mal és Arduino IDE-vel1Betaní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.

ESP32-S3 BH1750 bekötési rajz

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.csv cí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 új model.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.

Hasznos források