Durum Makineleri (State Machines)

 


Durum makinesi, önceki durumlardan gelen değerlere veya sistem girdilerine bağlı olarak durumlara dinamik akış sağlayan bir programlama mimarisidir. Bu mimari, aşağıdakilerin bir kombinasyonu olarak tanımlanabilecek uygulamalar için uygundur:

  • Durumlar (states)
  • Belirli bir duruma ne zaman geçileceğini belirleyen karar verme mantığı

Bir durum, programın genel görevini yerine getirirken program içindeki durum olarak tanımlanabilir. Durum örnekleri başlatma, bekleme, bir hesaplama çalıştırma, durumu kontrol etme vb. olabilir.

Mantıksal ifadeler yeni bir duruma ne zaman geçileceğini ve hangi duruma geçileceğini belirlemeye yardımcı olur. Olaylar bir durumdan diğerine geçişi tetiklemek için kullanılabilir. Bunlar programatik olaylar olabileceği gibi bir butona basmak gibi kullanıcı tanımlı olaylar da olabilir.

Durum Makinesindeki her durum benzersiz bir şey yapar ve diğer durumları çağırır. Böylece işlemler belli bir sırayla yapılabilir. Örneğin, resimde gördüğünüz state şemasına göre kapı sadece kapalı durumdayken kilitlenebilir. Kapı kilitli durumdayken açılamaz. Kapıyı açmak için, önce kilidi açmak gerekir.


State makinesi örnekleri

  • Bir otomatik vezne makinesi (ATM). Bu uygulamadaki state'ler, kullanıcı girdisini bekleme, istenen miktarı hesap bakiyesiyle karşılaştırma, parayı dağıtma, makbuzu yazdırma ve benzeri işlemleri içerebilir.
  • Durum makinesi, yaygın olarak oyun programlamasında kullanılır. Örneğin, kullanıcının atladığı her seviye bir durumdur.
  • Süreç testi, Durum Makinelerinin bir başka yaygın uygulamasıdır. Bu örnekte, sürecin her bir bölümü bir durum ile temsil edilmektedir. Her bir durumun testinin sonucuna bağlı olarak farklı bir durum çağrılabilir. Bir fabrikada ürünler için kullanılan sızdırmazlık vb. testleri yapan bir makine süreç testine örnek gösterilebilir. 
  • Vapur iskelesinde bulunan turnikeler. Ödeme işlemi yapıldıktan sonra kapı bir kez açılır. Ödeme işlemi kapıyı kapalı durumdan açık durumuna getirmektedir.
  • İnsan davranışları da örnek gösterilebilir. Araç kullanırken yola bir yaya adım attığında, frene basmak. Saçımız uzayınca berbere gitmek gibi.

Palet etiketleme aplikatörü yazılım örneği

Etkili bir Durum Makinesi oluşturmak için tasarımcının olası durumların bir listesini yapması gerekir. Bu liste ile tasarımcı her bir state'in diğeriyle nasıl ilişkili olduğunu planlayabilir. Fabrikalarda kullanılan bu cihazın nasıl birşey olduğunu görmek için kanalımdaki videoyu izleyebilirsiniz. 
Sistem, bir etiket yazıcı ve pnömatik aksamı yöneten bir plc'den oluşmaktadır. Yazıcı bir hata verdiğinde örneğin etiket rulosu bittiğinde, plc bunu farketmektedir. Etikete yazılacak bilgilerle plc'nin bir ilgisi yoktur. Bu bilgiler direk yazıcının ip adresine gönderilmelidir. Plc, sadece yazıcıda gönderilmiş bir iş var mı bunu farkedebilir. Yazıcıya iş (etikete basılacak bilgiler) yollamak için müşteriye özel örneğin .Net tabanlı bir yazılım (C# vb.) geliştirilmelidir. Yazıcıya bilgi yollamak için C# örnek programı önceki yazılarda bulabilirsiniz.
Palet etiketleme işinde, hem etiket aplikatörü hem de bütün sistemi yönetecek .Net yazılımı state makinesi olarak çalışmalıdır.

Etiket aplikatörünü yöneten plc'nin, .Net yazılımı için kullanılabilecek giriş ve çıkışları şöyledir:

Aplikatör plc girişleri 

  • Palet ön etiketini bas ve palete uygula
  • Palet yan etiketini bas ve palete uygula

Aplikatör plc çıkışları

  • Hata durumu (yazıcıda veya sistemde oluşan hata)
  • Meşgül sinyali (aplikatör etiketi yapıştırken bu sinyal 1 olur)
  • Hazır
  • Aplikatör kolu dışarıda veya home pozisyonunda
Plc girişleri, geliştirilecek .Net yazılımı için çıkışlar olacaktır. Yine plc çıkışları, yazılım için girişler olacaktır. Plc ve pc’de çalışan yazılımı haberleştirmek için arada I/O modülü kullanılmalıdır.

Not: Yukarıdaki S7-1200 Plc sinyalleri, OPC UA protokolü ile de okunup yazılabilmektedir. Yazıcıya iş yollama işlemi için OPC desteklenmemektedir. Yazılımda, bu protokol kullanılsa bile örneğin paletin geldiğini anlamak için kullanılan sensörden bilgi almak için I/O modülü gerekecektir.

Sistemin çalışabilmesi operatör müdahelesi de gerekmektedir. Örneğin, etiket veya ribon bittiğinde sistem hata state'ine geçecektir. Operatör hatayı giderdikten sonra, pano üstünde bulunan bir butona basarak süreci devam ettirmektedir. Acil durum butonuna da basabilecektir. Butonlar aplikatörü yöneten plc'ye bağlıdır.

Fabrikaya özel geliştirilecek .Net yazılımı için state'ler

Bu işlemler sırayla yapılmalıdır. Hata durumunda sıra bozulabilecektir. Hata durumundan normale dönüş senaryoları da ayrıca incelenmelidir.
  • Konveyörde taşınan paletin, etiket aplikatörünün yanına gelmesi. Optik bir sensör ile yazılım bunu algılamalıdır.
  • Yazılım, palet geldi bilgisini aldığında paleti taşıyan konveyörü durdurmalıdır. (Yazılım, konveyör plc'si ile de haberleşmelidir)
  • Yazılım, ERP sistemiyle haberleşerek etikete yazılacak bilgileri oluşturmalı, gerekirse ERP'den onay almalıdır.
  • Yazılım, etikete basılacak bilgileri, aplikatör yazıcısına yollamalı.
  • Yazıcıya işin gittiğinden emin olduktan sonra plc'ye etiketi bas ve palete uygula komutu verilmelidir. Yazıcıda iş yokken bu komut verilirse hata durumu oluşacaktır.
  • Yazılım, plc'den gelen meşgül sinyalinin 1 den 0 a düşmesini beklemelidir. Bu sinyal, palet aplikatör kolunun etiketi yapıştırıp geri geldiğini belirtir.
  • Üstteki state'e ulaşılması durumunda ayrı bir önlem olarak aplikatör kolunun yuvaya (home) döndüğünü gösteren sinyal de kontrol edilmelidir. 
  • Aplikatör home pozisyonunda ise ve meşgül sinyali yoksa paletin işi bitmiştir. Palet, serbest bırakılabilir. Yani konveyör dönsün komutu verilebilecektir. Aplikatör kolu dışarıdayken bu komut verilirse palet, aplikatöre çarparak zarar verecektir.

PureBasic ile basit bir state makinesi örneği

Yazının başında bulunan state şemasına göre bir program yazalım. Hemen yazılımı indirip, kendi bilgisayarınızda deneyebilirsiniz. PureBasic programını tanıtan önceki yazılarımı inceleyebilirsiniz. Programın çalışan halini Youtube'da izleyebilirsiniz.

Enumeration 
  #GADGET_btnStart
  #GADGET_btnReset
  #GADGET_btnOpen
  #GADGET_btnClose
  #GADGET_btnLock
  #GADGET_btnUnlock
  #GADGET_txtState 
  #GADGET_lbTrace 
EndEnumeration 

Enumeration
  #STATE_Start
  #STATE_Opened
  #STATE_Closed
  #STATE_Locked
EndEnumeration

#WINDOW_Main = 0
#WINDOW_Main_Flags = #PB_Window_SystemMenu | #PB_Window_ScreenCentered 

State = #STATE_Start 

Macro Trace(MessageText) 
  AddGadgetItem(#GADGET_lbTrace, -1, MessageText) 
  SetGadgetState(#GADGET_lbTrace, CountGadgetItems(#GADGET_lbTrace) -1) 
EndMacro 

Procedure.s StateInfo(number.i)
  st.s = ""
  Select number
    Case 0 : st = "START"
    Case 1 : st = "OPENED"
    Case 2 : st = "CLOSED"
    Case 3 : st = "LOCKED"
  EndSelect
  SetGadgetText(#GADGET_txtState, "Current state : " + st)
  ProcedureReturn st
EndProcedure

OpenWindow(#WINDOW_Main, 0, 0, 400, 360, "State Machine example...", #WINDOW_Main_Flags) 
StickyWindow(#WINDOW_Main, 1)  ; show test app always above the PB_IDE 
ButtonGadget(#GADGET_btnStart,  8, 4, 192, 32, "Start")
ButtonGadget(#GADGET_btnReset,  200, 4, 192, 32, "Reset Machine")
ButtonGadget(#GADGET_btnOpen,  8, 40, 192, 32, "Open") 
ButtonGadget(#GADGET_btnClose,  200, 40, 192, 32, "Close")
ButtonGadget(#GADGET_btnLock,  8, 76, 192, 32, "Lock") 
ButtonGadget(#GADGET_btnUnlock,  200, 76, 192, 32, "Unlock") 
TextGadget(#GADGET_txtState, 8, 115, 384, 20, "Current state : START")
SetGadgetColor(#GADGET_txtState, #PB_Gadget_BackColor, RGB(204,255,204)) 
ListViewGadget(#GADGET_lbTrace, 8, 145, 384, 208, $4000)  ; #LBS_NOSEL == 0x4000 


Repeat
  Select WaitWindowEvent()
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_Gadget 
      Select EventGadget() 
          
        Case #GADGET_btnStart
          Select State 
            Case #STATE_Start
              State = #STATE_Opened
              Trace("State is changed to : " + StateInfo(State))
            Default
              Trace("It is already STARTED")
            EndSelect
          
        Case #GADGET_btnReset
          ClearGadgetItems(#GADGET_lbTrace)
          State = #STATE_Start
          Trace("State is changed to : " + StateInfo(State))
          
        Case #GADGET_btnOpen
          Select State
            Case #STATE_Start 
              Trace("First you have to press the Start button")
            Case #STATE_Opened
              Trace("It is already OPENED")
            Case #STATE_Closed
              State = #STATE_Opened
              Trace("State is changed to : " + StateInfo(State))
            Case  #STATE_Locked
              Trace("You can NOT open! it is LOCKED")
          EndSelect
          
        Case #GADGET_btnClose
          Select State
            Case #STATE_Start 
              Trace("First you have to press the Start button")
            Case #STATE_Opened
              State = #STATE_Closed
              Trace("State is changed to : " + StateInfo(State))
            Case #STATE_Closed
               Trace("It is already CLOSED")
            Case  #STATE_Locked
              Trace("You can NOT close! it is already CLOSED and LOCKED!")
          EndSelect
          
        Case #GADGET_btnLock
          Select State
            Case #STATE_Start 
              Trace("First you have to press the Start button")
            Case #STATE_Opened
              Trace("You can NOT lock! fisrt you have to CLOSE to lock!")
            Case #STATE_Closed
              State = #STATE_Locked
              Trace("State is changed to : " + StateInfo(State))
            Case  #STATE_Locked
              Trace("It is already LOCKED")
          EndSelect
          
        Case #GADGET_btnUnlock
          Select State
            Case #STATE_Start 
              Trace("First you have to press the Start button")
            Case #STATE_Opened
              Trace("You can NOT unlock! state must be LOCKED to unlock!")
            Case #STATE_Closed
              Trace("You can NOT unlock! fist you have to LOCK to unlock!")
            Case  #STATE_Locked
              State = #STATE_Closed
              Trace("State is changed to : " + StateInfo(State))
          EndSelect
          
      EndSelect
  EndSelect
ForEver
End
Youtube'da izle..

Yorumlar

Bu blogdaki popüler yayınlar

VBA - Mscomm (seri port) ile veri loglama

RJ45 2 - Novexx barkod yazıcıya, S7-1200 plc ile etiket yazdırma

Köpüğü alınmış Windows AtlasOS