Linklist

8 Nisan 2015 Çarşamba

Dairesel bir tampon belleğe kayıt almak (circular buffering)

İnternette çeşitli forumlarda zaman zaman karşılaştığım bir soru...

Konveyor üzerinde sensörle aktuator arasında birden fazla urun girecek kadar mesafe varsa, urunlerin takibini nasıl yapabilirim.

Bu sorunun çözümünü arayanlara destek olması amacıyla kısa bir derleme yapmak istiyorum. Mühendis arkadaşlar için basit olabilecek bu uygulama, işi sahada öğrenmek zorunda kalan elektrikçi arkadaşlar ve teknisyenler için bazen baş ağrıtıcı olabiliyor.

Öncelikle internette konuyla ilgili arama yapmak için ihtiyacınız olan anahtar kelimeler: Data buffering, buffering, queue implementation, FIFO buffer, ...



Biraz işin içine girelim...

Gelen datayı saklayıp, ihtiyaç olduğunda çıkartmak için öncelikle hangi yöneme ihtiyacınız olduğuna karar vermeniz gerekiyor.

Konveyör örneği üzerinden gidersek, konveyör üzerindeki ürün sensörünün önünden geçen ilk ürün aynı zamanda konveyörü ilk terk edecek üründür. Dolayısıyla, "ilk giren ilk çıkar" prensibine sahip bir buffer uygulamalıyız. (FIFO - First In First Out).

Hadi sizi google'da FIFO Buffering yazıp aramaktan kurtarmış olayım, bu cümleye tıklayın yeter.

Bunun için FIFO tabir edilen bir arşivleme sistemi kullanmak gerekiyor.

Bunun için dairesel olarak düşünebileceğimiz bir kayıt alanı (Ön koşul 'array'ler konusu) tasarlayalım.

Kullanılacak kayıt alanı tasarımı

Kayıt alanına parça kayderken neler oluyor?

Kayıt alanından kayıt okurken neler oluyor?

Özetle işlem bu şekilde devam edebilir. Eğer useCell = StoreCell ise, kayıtlı parça olmadığı bilgisinin kullanıcıya verilmesi gerekir. Eğer storeCell bufferSize'a ulaşırsa, yeniden sıfırlanmalı ve çemberin ilk elemanına gitmelidir.

Fikir vermesi açısından kodunu da yazayım. Fakat yazdığım kodu direkt olarak kullanmayın. Zira arıza kontrollerini tamamen çıkarttım ve FIFO'dan pozisyon okuma işlemini nasıl yaptımı görmeniz açısından aynı koda dahil ettim. Konuya yabancı olanların okuması kolay olsun diye değişken tiplerini belirttiğim notasyonu da kullanmadım.

(* If not enabled, return for efficiency! *)
IF NOT(Enable) THEN RETURN; END_IF;
(* Event Handling *)
R_TRIG_Enable(CLK:=Enable);
(* Initialization *)
IF R_TRIG_Enable.Q THEN    
 EncoderPositionParameter := UINT#1006; (* Yaskawa Related: For position, select external encoder *)
UseCell := INT#0;
StoreCell := INT#0;
END_IF; 
(* always read actual position of encoder *)
MC_ReadParameter_1(Axis := Encoder21, Enable := TRUE, ParameterNumber:=EncoderPositionParameter);
EncoderPosition := MC_ReadParameter_1.Value;
(* Operation *)
R_TRIG_PartSensor(CLK := diPartComing);
PartDetected := R_TRIG_PartSensor.Q;
(*part recording to buffer*)
if PartDetected then
(*record position to buffer store cell*)
Buffer[StoreCell] := EncoderPosition;
(*increase store cell, if buffer size reached then store to the first buffer cell (circular buffer)*)
if (StoreCell < (Buffersize - INT#1))  then
StoreCell := StoreCell + INT#1;
else
StoreCell := INT#0;
end_if;
end_if;
(*part reading - to give an idea how to do it, several needs can cause a part read. For instance; if the part passes over the minimum working area...*)
R_TRIG_ReadPart(CLK := ReadPart);
ReadPartPulse := R_TRIG_ReadPart.Q;
if ReadPartPulse then
if NOT (StoreCell = UseCell) then
(*Get part position *)
PartPosition := Buffer[UseCell];
(*increase UseCell, if buffer size reached then store to the first buffer cell (circular buffer)*)
if (UseCell < (Buffersize - INT#1))  then
UseCell := UseCell + INT#1;
else
UseCell := INT#0;
end_if;
else
(*warn user*)
NoPartInBuffer := TRUE;
end_if;
end_if;

(*delete user warning*)
if not ReadPart then
NoPartInBuffer := FALSE;
end_if;
NOT: Buraya kod eklendiğinde güzel gözükmüyormuş. Siz okuyacaksanız kopyalayıp notepad++'a falan atın.


Hiç yorum yok:

Yorum Gönder