Macademia'nın robotik ve mühendislik programı · ücretsiz seviye tespiti ve kişisel öğrenme yolu

9. ünite / 10 · yaklaşık 4 saat

Flask ile web kontrol paneli

Pi'de küçük bir HTTP sunucusu: yönlendirmeler, JSON, girdi doğrulama, belirteç ve güvenlik bekçisi.

Bu ünitenin sonunda

  • Flask ile GET ve POST uç noktaları yazmak ve JSON döndürmek
  • Girdiyi doğrulayıp doğru HTTP durum kodlarını (200, 400, 401, 404, 405) vermek
  • Bağlantı kesilince robotu durduran bir bekçi (watchdog) kurmak
  • Tarayıcıdan basılı tutulan düğmeyle güvenli sürüş sağlamak

Ders notları

Flask, birkaç satırla HTTP sunucusu yazdıran bir Python kütüphanesidir. Pi'de çalışır, aynı ağdaki telefon ya da dizüstü http://raspberrypi.local:5000 adresinden paneli açar.

Uç noktalar

  • GET /: panelin HTML sayfası.
  • GET /api/status: robotun durumu (komut, hız, pil) JSON olarak.
  • POST /api/drive: {"cmd": "forward", "speed": 0.5}.

Sunucu gelen her şeye şüpheyle bakar: bilinmeyen komut ya da 0–1 dışındaki hız 400, belirteç yoksa 401, yanlış yöntem 405 döner. Doğrulama robotun ilk güvenlik katmanıdır.

Bekçi

Wi-Fi koparsa son komut "ileri" olarak kalır ve robot duvara gider. Çözüm: tarayıcı basılı tutulan düğme için komutu her 200 ms'de bir yeniden yollar, sunucudaki bekçi iş parçacığı 1 s komut gelmezse robotu durdurur. Bu desen sanayide deadman switch olarak bilinir.

Güvenlik

Panel yalnız yerel ağda çalışmalı. Belirteç koda değil ortam değişkenine yazılır. Kamera görüntüsü eklenecekse MJPEG akışı ayrı bir uç noktadır ve kare hızı sınırlandırılır.

Simülasyon

Flask kontrol paneli ve bekçi (watchdog)

Tarayıcıdaki panelden Pi'deki küçük HTTP sunucusuna istek gönder. Yanıt kodlarını (200, 400, 401, 405), belirteç denetimini ve bağlantı kesilince robotu durduran bekçiyi dene.

http://raspberrypi.local:5000/
L0,00
R0,00

Robot: stop · hız 0,00

Kendin dene

Panelde ileri düğmesine basılı tut ve bırak: bekçi açıkken ve kapalıyken ne oluyor? "Bağlantıyı kes" ile Wi-Fi kopmasını dene. Belirteci aç ve belirteçsiz istek gönder. Hızı 1,5 yapıp hangi kodu aldığını, "jump" komutuyla ne döndüğünü not et.

Kod

Flask sunucusu: /api/drive ve bekçi
from flask import Flask, jsonify, request, abort
import threading, time, os

app = Flask(__name__)
TOKEN = os.environ["ROBOT_TOKEN"]          # belirteç koda değil ortama
state = {"cmd": "stop", "speed": 0.0, "t": 0.0}
lock = threading.Lock()

@app.post("/api/drive")
def drive():
    if request.headers.get("X-Token") != TOKEN:
        abort(401)
    body = request.get_json(silent=True) or {}
    cmd, speed = body.get("cmd"), body.get("speed", 0.5)
    if cmd not in {"forward", "back", "left", "right", "stop"} or not 0 <= speed <= 1:
        return jsonify(error="bad command"), 400
    with lock:
        state.update(cmd=cmd, speed=0 if cmd == "stop" else speed, t=time.monotonic())
    return jsonify(ok=True, **state)

def watchdog():
    while True:                             # 1 s komut gelmezse dur
        with lock:
            if state["cmd"] != "stop" and time.monotonic() - state["t"] > 1.0:
                state.update(cmd="stop", speed=0.0)
        time.sleep(0.1)

threading.Thread(target=watchdog, daemon=True).start()
app.run(host="0.0.0.0", port=5000)          # yalnız yerel ağda; internete açma
Tarayıcı tarafı: basılı tutunca komutu tekrarla
// Bekçi 1 s'de durdurur; bu yüzden basılıyken her 200 ms'de yeniden gönder
let timer = null
const send = (cmd) => fetch('/api/drive', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-Token': localStorage.token },
  body: JSON.stringify({ cmd, speed: Number(speedInput.value) }),
})
function hold(cmd) { send(cmd); timer = setInterval(() => send(cmd), 200) }
function release() { clearInterval(timer); send('stop') }   // bırakınca hemen dur
document.querySelectorAll('[data-cmd]').forEach((b) => {
  b.addEventListener('pointerdown', () => hold(b.dataset.cmd))
  b.addEventListener('pointerup', release)
  b.addEventListener('pointerleave', release)
})

Sık yapılan hatalar

  • Flask geliştirme sunucusunu internete açmak: yalnız yerel ağ; dışarıdan erişim gerekiyorsa VPN kullan.
  • Komutu tek seferlik göndermek (bas, bırak): bağlantı koparsa durma komutu hiç gitmez.
  • Girdiyi doğrulamadan motora vermek: speed = 5 motoru zorlar.
  • Belirteci kaynak koda yazıp depoya göndermek.

Yazılım mühendisliği bağlantısı

HTTP arayüzü bir sözleşmedir: uç noktaları, gövdeleri ve durum kodlarını belgeleyip test et.

  • Flask'ın test istemcisiyle (app.test_client()) her durum kodunu sınayan testler yaz.
  • Yönlendirme mantığını donanımdan ayır: benzetimdeki handle() gibi saf bir fonksiyon.

Kendini sına

  1. POST /api/drive {"cmd": "jump"} için uygun durum kodu?

  2. GET /api/drive (yalnız POST tanımlı) ne döner?

  3. Bekçi neden gerekli?

  4. Belirteç (token) nerede saklanmalı?

Bu üniteden sonra bitirme projesinde

Gerçek parçalar (Hyvex, 3B modelli)

Esc
  • PanelAna sayfaSayfa
  • ModüllerTüm modüllerSayfa
  • ParçalarParça ansiklopedisiSayfa
  • Mühendislik yoluBüyükler için robotik: 128 parça, 7 seviyeSayfa
  • Robotik dersi (ESOF 323)Üniversite robotik dersi, 14 haftaSayfa
  • Drone dersiBüyükler için: parça, simülasyon, yazılım; 10 üniteSayfa
  • Blok atölyesiSerbest blok programlamaAraç
  • Devre laboratuvarıSanal Arduino ve devreAraç
  • Robot arenasıSanal robot sürüşüAraç
  • OyunlarBloklarla 8 öğretici oyunAraç
  • Mikro Kart atölyesiSanal LED kartı bloklarla programlaAraç
  • Robot atölyesiMikro Kart'ı robota tak, bloklarla görev yapAraç