00 Edge Impulse nedir?
Edge Impulse, gömülü sistemler için makine öğrenmesi geliştirme sürecini uçtan uca otomatize eden bulut tabanlı bir platformdur. Veri toplamadan model deployment'a kadar her adım web arayüzü veya CLI üzerinden yönetilir.
Platform bileşenleri
┌─────────────────────────────────────────────────────┐
│ Edge Impulse Studio (edgeimpulse.com) │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────────────┐ │
│ │ Veri │→ │ DSP │→ │ Model Eğitimi │ │
│ │ Toplama │ │ Blokları│ │ (bulut GPU) │ │
│ └──────────┘ └──────────┘ └────────┬─────────┘ │
│ ↓ │
│ ┌─────────────────────────┐ │
│ │ Deployment │ │
│ │ Arduino lib / C++ SDK │ │
│ │ Linux runner / TFLite │ │
│ └─────────────────────────┘ │
└─────────────────────────────────────────────────────┘
↓ CLI (edge-impulse-cli)
Hedef cihaz (MCU / Linux / Android)
Edge Impulse hızlı prototipleme ve standart sensör tipleri (accelerometer, ses) için idealdir. Özel model mimarisi, büyük veri setleri veya özel quantization gerektiren durumlar için manuel TFLite/ONNX pipeline tercih edilmelidir.
01 Veri toplama — CLI, serial acquisition, synthetic
Kaliteli model eğitiminin temeli kaliteli veri toplamaktır. Edge Impulse, web dashboard, CLI ve doğrudan seri port üzerinden veri toplama imkânı sunar.
CLI kurulumu
# Node.js gerekli (v14+)
npm install -g edge-impulse-cli
# Giriş
edge-impulse-login
# Edge Impulse kullanıcı adı ve şifre gir
# Proje listesi
edge-impulse-daemon --list
# Cihazı projeye bağla (USB serial)
edge-impulse-daemon
# → Cihaz listesi görünür, seç ve onayla
Seri port ile veri toplama (Python)
"""
Edge Impulse CSV formatında veri toplama.
MPU-6050 accelerometer → RPi → Edge Impulse uploader
"""
import serial, json, time, requests, base64
import numpy as np
EI_API_KEY = "ei_XXXX..." # Edge Impulse project API key
EI_API_URL = "https://ingestion.edgeimpulse.com/api/training/data"
SAMPLE_RATE = 100 # Hz
SAMPLE_LEN = 2000 # ms (2 saniye pencere)
LABEL = "normal" # "normal", "anomaly", "vibration_high"
ser = serial.Serial("/dev/ttyACM0", 115200, timeout=1)
def collect_sample():
"""100Hz'de 2 saniye accelerometer verisi topla"""
samples = []
n_samples = int(SAMPLE_RATE * SAMPLE_LEN / 1000)
for _ in range(n_samples):
line = ser.readline().decode().strip()
try:
ax, ay, az = map(float, line.split(","))
samples.append([ax, ay, az])
except ValueError:
pass
return samples
def upload_to_edge_impulse(samples, label):
"""Edge Impulse Ingestion API'ye yükle"""
# Edge Impulse CBOR/JSON formatı
payload = {
"protected": {
"ver": "v1",
"alg": "none",
"iat": int(time.time())
},
"signature": "0000",
"payload": {
"device_name": "rpi4-sensor",
"device_type": "RASPBERRY_PI_4",
"interval_ms": 1000.0 / SAMPLE_RATE,
"sensors": [
{"name": "accX", "units": "m/s2"},
{"name": "accY", "units": "m/s2"},
{"name": "accZ", "units": "m/s2"}
],
"values": samples
}
}
headers = {
"x-api-key": EI_API_KEY,
"x-label": label,
"Content-Type": "application/json"
}
resp = requests.post(EI_API_URL,
json=payload, headers=headers, timeout=30)
print(f"Upload: {resp.status_code} — {resp.text[:100]}")
# Ana döngü
print(f"Veri toplama başlıyor: etiket={LABEL}")
for i in range(50): # 50 örnek
samples = collect_sample()
upload_to_edge_impulse(samples, LABEL)
print(f"Örnek {i+1}/50 yüklendi ({len(samples)} veri noktası)")
Sentetik veri üretimi
import numpy as np
import requests, time, json
def generate_vibration_sample(
freq_hz=50, amplitude=2.0, noise=0.1,
sample_rate=100, duration_ms=2000):
"""Sinüsoidal titreşim + Gaussian gürültü"""
n = int(sample_rate * duration_ms / 1000)
t = np.linspace(0, duration_ms/1000, n)
ax = amplitude * np.sin(2*np.pi*freq_hz*t) + np.random.normal(0, noise, n)
ay = (amplitude*0.3) * np.cos(2*np.pi*freq_hz*t) + np.random.normal(0, noise, n)
az = np.random.normal(9.8, noise, n) # yerçekimi + gürültü
return [[float(ax[i]), float(ay[i]), float(az[i])] for i in range(n)]
# 100 normal ve 100 anomalous örnek üret
for label, kwargs in [
("normal", {"freq_hz": 50, "amplitude": 0.5}),
("anomaly", {"freq_hz": 150, "amplitude": 5.0, "noise": 0.5})
]:
for i in range(100):
samples = generate_vibration_sample(**kwargs)
upload_to_edge_impulse(samples, label)
time.sleep(0.1)
02 DSP blokları — MFCC, Spectral Analysis, custom
DSP (Dijital Sinyal İşleme) blokları, ham sensör verisini model için anlamlı özellik vektörlerine dönüştürür. Edge Impulse, çeşitli hazır DSP blokları ve özel Python bloğu desteği sunar.
DSP blok türleri
process(raw_data, axes, sampling_freq, draw_graphs) fonksiyonunu implement eder. GitHub üzerinden import edilebilir.Custom DSP block — Python
"""
Edge Impulse Custom DSP Block
Accelerometer için istatistiksel özellik çıkarımı
"""
import numpy as np
from scipy import stats
from scipy.signal import welch
def process(raw_data, axes, sampling_freq, draw_graphs):
"""
raw_data: list of [ax, ay, az] per timestep
axes: ['accX', 'accY', 'accZ']
sampling_freq: Hz
draw_graphs: görselleştirme modu (False = üretim)
"""
data = np.array(raw_data) # (N, 3)
features = []
graphs = []
for i, axis_name in enumerate(axes):
x = data[:, i]
# Zaman alanı özellikleri
features += [
float(np.mean(x)),
float(np.std(x)),
float(np.min(x)),
float(np.max(x)),
float(stats.skew(x)),
float(stats.kurtosis(x)),
float(np.sqrt(np.mean(x**2))), # RMS
float(np.percentile(x, 95) - np.percentile(x, 5)) # IQR-like
]
# Frekans alanı: Welch PSD
freqs, psd = welch(x, fs=sampling_freq, nperseg=min(256, len(x)))
# Frekans bantlarında güç
features += [
float(np.sum(psd[(freqs >= 0) & (freqs < 10)])),
float(np.sum(psd[(freqs >= 10) & (freqs < 50)])),
float(np.sum(psd[(freqs >= 50) & (freqs < 100)])),
float(np.sum(psd[(freqs >= 100) & (freqs < 200)])),
float(freqs[np.argmax(psd)]), # dominant frekans
]
if draw_graphs:
graphs.append({
"name": f"{axis_name} PSD",
"x": freqs.tolist(),
"y": psd.tolist(),
"type": "line"
})
return {"features": features, "graphs": graphs}
# Özellik isimlerini döndür (Studio'da görünür)
def feature_names(axes):
names = []
stats_names = ["mean","std","min","max","skew","kurt","rms","iqr"]
freq_names = ["psd_0-10","psd_10-50","psd_50-100","psd_100-200","dom_freq"]
for axis in axes:
names += [f"{axis}_{s}" for s in stats_names]
names += [f"{axis}_{f}" for f in freq_names]
return names
03 Model eğitimi — Transfer Learning, NN designer
Edge Impulse, model eğitimi için iki temel yol sunar: Neural Network Designer (görsel sürükleme-bırakma) ve Transfer Learning (önceden eğitilmiş modeller üzerine fine-tuning).
Eğitim blok türleri
Eğitim parametreleri (Spectral Analysis → NN)
| Parametre | Vibrasyon Anomali için | Açıklama |
|---|---|---|
| Öğrenme hızı | 0.0005 | Adam optimizer LR |
| Epoch sayısı | 100 | Erken durma ile |
| Validation split | %20 | Dengesiz sınıflar için stratified |
| Batch size | 32 | Küçük veri setinde 16 daha iyi |
| Dropout | 0.25 | Overfitting'i önler |
| Quantization | INT8 | MCU deployment için zorunlu |
Dengesiz sınıf durumunda (normal:anomaly = 10:1) "Autobalance dataset" seçeneğini etkinleştir. Zaman serisi augmentation: random crop, additive noise, time warp — Edge Impulse Studio'da yerleşik olarak mevcuttur.
04 Model deployment — Arduino, C++ SDK, TFLite
Edge Impulse, eğitilen modeli birden fazla deployment formatında dışa aktarır. Her format farklı hedef ortam için optimize edilmiştir.
Deployment formatları
libedge-impulse-sdk.a statik kütüphane ve başlıklar.Edge Impulse CLI ile deployment
# C++ kütüphanesi indir (proje ID gerekli)
edge-impulse-export-project --engine tflite-eon
# Ya da Studio'dan: Deployment → C++ Library → Download
# → vibration_anomaly-cpp-v1.zip
# Kütüphaneyi aç
unzip vibration_anomaly-cpp-v1.zip -d ei_model/
ls ei_model/
# edge-impulse-sdk/ model-parameters/ tflite-model/
# CMakeLists.txt README.md
05 C++ SDK entegrasyonu — run_classifier, result
Edge Impulse C++ SDK'nın temel çıkarım API'si run_classifier() fonksiyonu etrafında şekillenir. Giriş tamponu, DSP, model çıkarımı ve sonuç ayrıştırma tek bir çağrıda yönetilir.
Proje CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
project(vibration_anomaly_detector CXX C ASM)
set(CMAKE_CXX_STANDARD 11)
# Edge Impulse SDK dahil et
add_subdirectory(ei_model)
add_executable(detector
src/main.cpp
src/sensor_reader.cpp
)
target_link_libraries(detector
ei_model # Edge Impulse SDK statik kütüphane
pthread m # POSIX thread ve math
)
# ARM64 optimizasyon
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
target_compile_options(detector PRIVATE -O3 -march=armv8-a+simd)
endif()
Tam çıkarım implementasyonu
#include <iostream>
#include <vector>
#include "edge-impulse-sdk/classifier/ei_run_classifier.h"
#include "model-parameters/model_metadata.h"
// MPU-6050 okuma fonksiyonu (platform'a özgü)
extern std::vector<float> read_accelerometer_window(
int samples, float sample_rate_hz);
int main() {
std::cout << "Edge Impulse Vibrasyon Anomali Dedektörü" << std::endl;
std::cout << "Model: " << EI_CLASSIFIER_PROJECT_NAME << std::endl;
std::cout << "Giriş: " << EI_CLASSIFIER_RAW_SAMPLE_COUNT
<< " örnekler x "
<< EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME << " eksen" << std::endl;
while (true) {
// 1. Ham veriyi topla
// EI_CLASSIFIER_RAW_SAMPLE_COUNT = N_samples
// EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME = 3 (ax, ay, az)
auto raw = read_accelerometer_window(
EI_CLASSIFIER_RAW_SAMPLE_COUNT,
EI_CLASSIFIER_FREQUENCY
);
// 2. EI signal_t yapısını doldur
signal_t signal;
signal.total_length = EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE;
signal.get_data = [&raw](size_t offset, size_t len, float *out) -> int {
for (size_t i = 0; i < len; i++) {
if (offset + i < raw.size())
out[i] = raw[offset + i];
else
out[i] = 0.0f;
}
return 0;
};
// 3. Sınıflandır
ei_impulse_result_t result;
EI_IMPULSE_ERROR err = run_classifier(&signal, &result, false);
if (err != EI_IMPULSE_OK) {
std::cerr << "Classifier hatası: " << err << std::endl;
continue;
}
// 4. Sonuçları yazdır
std::cout << "DSP süresi : " << result.timing.dsp << " ms" << std::endl;
std::cout << "Çıkarım : " << result.timing.classification << " ms" << std::endl;
for (int i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
printf(" %-15s: %.4f\n",
ei_classifier_inferencing_categories[i],
result.classification[i].value);
}
// 5. Anomali skoru (varsa)
#if EI_CLASSIFIER_HAS_ANOMALY == 1
printf(" Anomali skoru: %.4f\n", result.anomaly);
if (result.anomaly > 0.7f) {
std::cout << "!!! ANOMALI TESPİT EDİLDİ !!!" << std::endl;
// GPIO alarm, UART mesaj vs.
}
#endif
// 6. En yüksek skoru bul
int best_idx = 0;
float best_score = 0.0f;
for (int i = 0; i < EI_CLASSIFIER_LABEL_COUNT; i++) {
if (result.classification[i].value > best_score) {
best_score = result.classification[i].value;
best_idx = i;
}
}
printf("Sonuç: %s (%.2f%%)\n",
ei_classifier_inferencing_categories[best_idx],
best_score * 100);
}
return 0;
}
Önemli makrolar
| Makro | Açıklama | Örnek Değer |
|---|---|---|
| EI_CLASSIFIER_RAW_SAMPLE_COUNT | Toplam giriş verisi uzunluğu | 200 (100Hz × 2s) |
| EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME | Her timestep'te eksen sayısı | 3 (ax,ay,az) |
| EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE | DSP girişi toplam eleman sayısı | 600 (200×3) |
| EI_CLASSIFIER_FREQUENCY | Örnekleme frekansı (Hz) | 100.0 |
| EI_CLASSIFIER_LABEL_COUNT | Sınıf sayısı | 2 (normal/anomaly) |
| EI_CLASSIFIER_HAS_ANOMALY | Anomali dedektörü var mı? | 0 veya 1 |
06 Yocto/Buildroot entegrasyonu — bitbake recipe
Üretim sistemlerinde Edge Impulse C++ SDK'nın Yocto layer'ına veya Buildroot paket sistemine entegre edilmesi gerekir. Statik kütüphane ve başlık dosyaları özel bir recipe ile paketlenir.
Yocto bitbake recipe
SUMMARY = "Vibration anomaly detector using Edge Impulse"
DESCRIPTION = "Edge Impulse C++ SDK ile titreşim anomali dedektörü"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://LICENSE;md5=..."
SRC_URI = "git://github.com/your-org/vibration-detector.git;branch=main;protocol=https"
SRCREV = "${AUTOREV}"
S = "${WORKDIR}/git"
# Bağımlılıklar
DEPENDS += "i2c-tools libgpiod"
inherit cmake
# Edge Impulse SDK subdirectory
EXTRA_OECMAKE += " \
-DCMAKE_BUILD_TYPE=Release \
-DEI_SDK_PATH=${S}/ei_model \
"
# Kurulum
do_install() {
install -d ${D}${bindir}
install -m 0755 ${B}/detector ${D}${bindir}/vibration-detector
install -d ${D}${sysconfdir}/vibration-detector
install -m 0644 ${S}/config/detector.conf \
${D}${sysconfdir}/vibration-detector/
}
# systemd servisi
SYSTEMD_SERVICE:${PN} = "vibration-detector.service"
SYSTEMD_AUTO_ENABLE = "enable"
do_install:append() {
install -d ${D}${systemd_system_unitdir}
install -m 0644 ${S}/systemd/vibration-detector.service \
${D}${systemd_system_unitdir}/
}
FILES:${PN} += " \
${bindir}/vibration-detector \
${sysconfdir}/vibration-detector/ \
${systemd_system_unitdir}/vibration-detector.service \
"
Buildroot package
config BR2_PACKAGE_VIBRATION_DETECTOR
bool "vibration-detector"
depends on BR2_INSTALL_LIBSTDCPP
depends on BR2_TOOLCHAIN_HAS_THREADS
help
Edge Impulse tabanlı titreşim anomali dedektörü.
MPU-6050 accelerometer ile çalışır.
VIBRATION_DETECTOR_VERSION = 1.0.0
VIBRATION_DETECTOR_SITE = https://github.com/your-org/vibration-detector
VIBRATION_DETECTOR_SITE_METHOD = git
VIBRATION_DETECTOR_LICENSE = Apache-2.0
VIBRATION_DETECTOR_DEPENDENCIES = i2c-tools libgpiod
VIBRATION_DETECTOR_CONF_OPTS = \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTS=OFF
define VIBRATION_DETECTOR_INSTALL_INIT_SYSV
$(INSTALL) -m 755 -D $(VIBRATION_DETECTOR_PKGDIR)/S99vibration \
$(TARGET_DIR)/etc/init.d/S99vibration
endef
$(eval $(cmake-package))
07 Pratik — Vibrasyon anomali tespiti
Raspberry Pi 4 + MPU-6050 accelerometer ile endüstriyel ekipman vibrasyon anomali tespiti. Edge Impulse Spectral Analysis DSP + anomali dedektör modeli, UART alarm çıkışı.
Donanım bağlantısı
MPU-6050 (I2C, 0x68)
┌─────────────────────────────────┐
│ VCC → RPi4 Pin 1 (3.3V) │
│ GND → RPi4 Pin 6 (GND) │
│ SCL → RPi4 Pin 5 (GPIO3) │
│ SDA → RPi4 Pin 3 (GPIO2) │
│ INT → RPi4 Pin 11 (GPIO17) │
└─────────────────────────────────┘
RPi4
├── GPIO17 (INT) — interrupt-driven sampling
├── GPIO18 — alarm LED
└── /dev/ttyS0 — UART alarm çıkışı (RS-485 converter ile)
MPU-6050 I2C okuma
#include <linux/i2c-dev.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <cstdint>
#include <vector>
#include <chrono>
#include <thread>
#define MPU6050_ADDR 0x68
#define MPU6050_PWR1 0x6B
#define MPU6050_ACCX_H 0x3B
class MPU6050Reader {
int fd;
float scale = 16384.0f; // ±2g: 16384 LSB/g
public:
MPU6050Reader(const char* dev = "/dev/i2c-1") {
fd = open(dev, O_RDWR);
ioctl(fd, I2C_SLAVE, MPU6050_ADDR);
// Uyku modundan çıkar
uint8_t pwr_cmd[2] = {MPU6050_PWR1, 0x00};
write(fd, pwr_cmd, 2);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
bool read_accel(float& ax, float& ay, float& az) {
uint8_t reg = MPU6050_ACCX_H;
write(fd, ®, 1);
uint8_t buf[6];
if (read(fd, buf, 6) != 6) return false;
int16_t raw_x = (buf[0] << 8) | buf[1];
int16_t raw_y = (buf[2] << 8) | buf[3];
int16_t raw_z = (buf[4] << 8) | buf[5];
ax = raw_x / scale; // g cinsinden
ay = raw_y / scale;
az = raw_z / scale;
return true;
}
~MPU6050Reader() { close(fd); }
};
// Edge Impulse için pencere toplama
std::vector<float> read_accelerometer_window(
int n_samples, float sample_rate_hz) {
MPU6050Reader sensor;
std::vector<float> window;
window.reserve(n_samples * 3);
auto interval = std::chrono::microseconds(
(int)(1e6 / sample_rate_hz));
auto next = std::chrono::steady_clock::now();
for (int i = 0; i < n_samples; i++) {
float ax, ay, az;
sensor.read_accel(ax, ay, az);
window.push_back(ax);
window.push_back(ay);
window.push_back(az);
next += interval;
std::this_thread::sleep_until(next);
}
return window;
}
Alarm sistemi ve UART
#include <termios.h>
#include <fcntl.h>
#include <gpiod.h>
#include <cstdio>
#include <cstring>
#include <time.h>
class AlarmSystem {
int uart_fd;
struct gpiod_chip *chip;
struct gpiod_line *alarm_line;
int alarm_count = 0;
public:
AlarmSystem() {
// UART aç (RS-485)
uart_fd = open("/dev/ttyS0", O_WRONLY | O_NOCTTY);
struct termios tty = {};
cfsetospeed(&tty, B115200);
tty.c_cflag = CS8 | CLOCAL | CWRITE;
tcsetattr(uart_fd, TCSANOW, &tty);
// GPIO alarm çıkışı
chip = gpiod_chip_open_by_name("gpiochip0");
alarm_line = gpiod_chip_get_line(chip, 18);
gpiod_line_request_output(alarm_line, "vibration-alarm", 0);
}
void trigger(float anomaly_score, const char* category) {
alarm_count++;
// Timestamp al
time_t now = time(NULL);
char timestamp[32];
strftime(timestamp, sizeof(timestamp),
"%Y-%m-%dT%H:%M:%S", localtime(&now));
// UART mesajı gönder
char msg[128];
snprintf(msg, sizeof(msg),
"ALARM,%s,%.3f,%s,#%d\r\n",
timestamp, anomaly_score, category, alarm_count);
write(uart_fd, msg, strlen(msg));
// GPIO yükselt (500ms)
gpiod_line_set_value(alarm_line, 1);
}
void clear() {
gpiod_line_set_value(alarm_line, 0);
}
~AlarmSystem() {
gpiod_line_release(alarm_line);
gpiod_chip_close(chip);
close(uart_fd);
}
};
Sistem performansı
| Metrik | Değer | Not |
|---|---|---|
| Veri toplama (100Hz, 2s) | 20 ms | I2C 400kHz |
| DSP (Spectral Analysis) | 12 ms | CPU, 4 thread |
| Model çıkarımı (NN) | 4 ms | TFLite INT8 |
| Anomali skoru hesaplama | 1 ms | K-Means distance |
| Toplam çıkarım döngüsü | 37 ms | ~27 döngü/sn |
| Tespit hassasiyeti | 96.8% | Test setinde |
| Yanlış pozitif oranı | 2.3% | Kalibrasyon sonrası |
Anomali skoru eşiği (varsayılan 0.3) üretim ortamında kalibre edilmelidir. Normal operasyon sırasında 1000 pencere toplayarak skor dağılımını analiz et ve %99 percentile'ı eşik olarak ayarla. Bu, false positive oranını minimize ederken gerçek anomalileri yakalamayı garantiler.