Bresenham Algoritma (takıldığım noktalar var yardımcı olurmusunuz ?)

Başlatan computerboy, 12 Şubat 2013, 13:25:28

iyildirim

Herhalde titreme son eklediğin kod ile ortadan kalkmamıştır. Bu kod ile doğru çalışması da mümkün görünmüyor ve öylesine hazırlanmış gibi.

Bahsettiğimiz şeyde anahtar nokta uzun yol kateden eksende (buna master eksen diyelim) putMotor her çağrıldığında hareket olması.
Bresenham ile tam olarak bir kareli defter sayfasında imiş gibi hareket ediyoruz. Bu ekranda-bellekte grafik çizerken işimizi kolaylaştırıyor. Ekran çözünürlüğüne göre bilgiyi digitize ediyoruz. Cnc de de aynı şekilde.
Cnc ile Kareli defter sayfasını üzerinde ilerlediğini düşün. İki çizgi arası mesafe de senin step boyun.  putMotor her çağrıldığında eksenlerin pozisyonu ancak çizgilerin kesişme noktaları olabilir.
Master eksende daima ilerleme olacak diğerinde bazen. Bu yüzden sadece master eksene tek bir timer kurmak yeterli.

Verdiğin kodda aynı timer 3 kere kullanılmış. Diğer eksende hareket olduğunda Master eksen hızın anlık olarak düşecek.

PutMotor için bu koda bir bak.
void putMotor(SL x, SL y, SL z )
{
    while(TMR1 < delayTime); /* veya aşağıdaki açıklamaya göre while(TMR1 < delayTime>>1);*/
    /* minPeriod ve delayTime 'ın hareket başındaki startup değeri dışarıda set edilmiş olmalı. */
    TMR1 = 0;
 /* minPeriod , hız parametresine göre en başta hesapladığın master eksenin hızı..periodu 1 / STEP_sn den hesaplanacak */
    if (delayTime > minPeriod)             
        delayTime -= hızlama_miktarı        
 
 
/* sürücün yükselen kenarda step alıyorsa    if(x-oldX |= 0) STP_X = 1; gibi olmalı.. düşen kenar için aşağıdaki gibi.. 
 burada ne zaman step puls göndereceğimizi hallediyoruz. Ama step darbesi bir süre sonra pasif konumuna gelmeli. 
 Burada ya belli bir süre yada tam %50 duty istersek delayTime kadar beklenecek. delayTime üzerinden gidilecekse, süreyi hesaplarken 
 iki kere delayTime beklendiğini gözönüne almak gerekir. Birde daha detayda buradaki kodun işlenme süresi var.
 Diğer seçenek ise işlemci uygunsa OC modülü kullanıp one shot puls üretmek olabilir. İşlemcin uygun değilse de uygun olanını kullanmanı öneririm.. 
 OC için kullanılan timer aynı zamanda delayTime için kullandığın timer olacak. Bu şekilde burada beklemek yerine bresenham'a daha fazla zaman ayırabilir ve daha yüksek hızlara çıkabilirsin. 
*/
if(x-oldX |= 0) STP_X = 0;
if(y-oldY |= 0) STP_Y = 0; 
if(z-oldZ |= 0) STP_Z = 0; 

while(TMR1 < delayTime); /* veya yukarıdaki açıklamaya göre while(TMR1 < delayTime>>1);*/
 
STP_X =1;// veya STP_X = 0 
STP_Y =1;
STP_Z =1;  
                        
stepcount=stepcount+1;

    oldY = y;
    oldX = x;
    oldZ = z;

}

computerboy

Hocam bu şekilde diyorsunuz sanırım. beynim durdu anlayamıyorum.  delay time derken mesela delaytime 200 olsun minperiod 60 hizmiktari 3. şimdi maxsimum hıza yani 60 ulaşması için 3 er 3er çıkarma işlemimi yapıyoruz burda ?

birde while(TMR1 < delayTime>1); ve while(TMR1 < delayTime); burda büyüktür işareti koymuşsunuz görevi ne acaba programlamada eksikliklerim var kusura bakmayın sizinde başınızı ağrıtıyorum.

SL			delayTime=200; 		// delayTime ise o anki hızına göre period.
SL 			minPeriod=60; 		// minPeriod en yüksek hıza göre master eksenin hızı. 
SL			hizMiktari=3; 		// hızlanma miktarı

void putMotor(SL x, SL y, SL z)
{

	if(x-oldX==1 || x-oldX==-1) STP_X = 0; // sürücü düşen kenardan step alıyor.
	if(y-oldY==1 || y-oldY==-1) STP_Y = 0;  
	if(z-oldZ==1 || z-oldZ==-1) STP_Z = 0; 

	while(TMR1 < delayTime>1);TMR1 = 0; // burda delaytime 1000 olsun diyelim tmr1 değeri 1000' e ulaşıncaya kadar döngü kuracak ve 1000'e ulaşınca alt satırlardaki kodları işlemeye alacak değilmi ?
    if (delayTime > minPeriod)             
        delayTime -= hizMiktari;
 
 	STP_X =1;							
	STP_Y =1;								
	STP_Z =1;           				
	               
	while(TMR1 < 20);TMR1 = 0; 			   // Fazla aktif etmedim 20 usb kesmesi yaptım.

	oldY = y;
	oldX = x;
	oldZ = z;

}

JKramer

Büyüktür işareti değil, sağa kaydırma (>>1, ikiye bölme).

computerboy

hocam iki adet olunca kaydırma işlemii olmuyormuydu yanlışmı biliyorum. orda sadece bir tane var.

JKramer


computerboy


iyildirim

Alıntı yapılan: computerboy - 18 Şubat 2013, 13:52:42
birde while(TMR1 < delayTime>1); ve while(TMR1 < delayTime); burda büyüktür işareti koymuşsunuz görevi ne acaba
>>  olacak.. Yanlış yazmışım. Düzelttim sonra. Periodu 2 ye bölmek için. while(TMR1 < delayTime>>1); olmalı.  Tam %50 duty li kare dalga için.

Alıntı yapılan: computerboy - 18 Şubat 2013, 13:52:42
Hocam bu şekilde diyorsunuz sanırım. beynim durdu anlayamıyorum.  delay time derken mesela delaytime 200 olsun minperiod 60 hız miktarı 3. şimdi maxsimum hıza yani 60 ulaşması için 3 er 3er çıkarma işlemimi yapıyoruz burda ?
Evet..

Diyelim ki G1 X500 Y300 F100 gibi bir komut işleyeceksin. F100 mm/sn cinsinden olsun. Max hızın saniyede 100mm ve 5mm hatveli vidali mil kullanıyorsun. Step motorun 200adım/tur ve sürücünde 8mikrostep destekliyor.
100 mm/sn hız, 5mm hatveye göre  100/5 = 20 tur/sn demek.

Üretmen gereken palslerin max frekansı = 20tur * 200(adım/tur) *8(mikrostep) = 32000Hz bulunur.
Diyelimki işlemcin 16MIPS ve Timer 16 bitlik ve Timer prescaler değeri olarakda 1 kullanıyorsun. 

Bu durumda 16e6/1 (prescaler) = 16e6 max üretebileceğin frekans değeri.  Minimum Frekans yani puls sayısı ise 16e6/65535 = 244 hz olur.
Buda 244 /8(mikrostep)/200 (adım/tur) * 60 =  9 RPM eder.

Bu aralıklar diyelim ki işimizi görüyor. Görmüyorsa prescaler değerleri ile oynayıp uydurman gerekecek.
max Hız için timer değeri 500 çıkıyor. min hız için timer değeri 65535.. 65535/500 = 131 gibi bir şey çıkacak. Yani dairesel enterpolasyonda eksen hızları arasındaki max oran bu  olacak. Yeterlimi sen karar ver. 
Yani öncelikle çalışma aralığını limitlerini vs. işlemcinin yetenekleri çerçevesinde tasarlamalısın.

Şimdi 20 Tur/sn için 32000 puls üretecektik. 16e6/ 32000 = 500 timer değerimiz.  Bu hesabı mcu da yapabilir veya PC de hesaplayıp mcu ya direkt timer değerini yollayabilirsin.
Hızlanmada olacak ve bir başlangıç hızımız olacak. Diyelimki 0.5 Tur/sn  yani 0.5*200*8 = 800 Hz başlangıç hızımız, puls frekansımız.  Bu durumda başlangıç timer period değeri 16e6/800= 20000 olacak..
20000 olan Timer periodunu 500 değerine kadar birer, üçer ,beşer eksiltirsek belli bir hızlanma sağlayacağız. Ama, eğer hızlanmanın tam lineer olmasını istiyorsan üçer beşer arttırmak işini görmez..  Hızlanma için ayrı bir timer kullanabilirsin.
Öte yandan birde hızlandığımız gibi yavaşlamakta lazım. Ve her zaman eksen yolları max hıza çıkabilmeni sağlayacak kadar uzun olmaz. Bu durumda daha tanımlı hıza ulaşamadan yavaşlamaya başlaman ve ne zaman yavaşlamaya başlayacağını da bilmen gerekir. 

Kod içerisinde anlatmaya çalıştığım şey ise putMotor içinde boş yere beklemek yerine hesap kitaba nasıl daha fazla vakit ayırırsın konusu.
Puls ları üretirken bir kare dalga üretiyorsun.  Sürücünün aktif high çalıştığını varsayalım.  Puls pinini high yaptıktan sonra tekrar low yapmak zorundasın.
Bu durumda ya putmotor içinde pin high olduktan sonra belli bir  süre bekleyip pini tekrar low yapacaksın ve bekleme ile vakit kaybetmiş olacağız. Yada OC modülü ile tek seferlik puls üretip putMotor içinde bekleme yapmak gerekmeyecek ve hesap kitaba daha fazla vakit ayırabileceksin.

if(x-oldX==1 || x-oldX==-1)
master eksende her zaman hareket var ve teker teker ilerliyor. Yani ya sıfır yada değil.. Yani
if(x-oldX |=0) şeklinde yazabilirsin..

mcu nedir?..

computerboy

Teşekkürler hocam.

PIC18F4550 kullanıyorum 16 mips çalışıyormuş. timer2 16 bit, müsait olduğum zaman sizin örneklediğiniz şekilde deneme yapacağım

Step Motor 200 Adım
Step Sürücü 8 Mikrostep
Vidalı Mil Hatvesi 5

yukardaki özelliklere göre düz 10 cm çizgi için X4000 şeklinde step sayısı çıkması lazım. mach3 gibi gcode üreten programlarda böyle üretiyor herhalde.

Mesela ;

X4000 Y0 Z0 F100 // burdaki f100 feedrate hızımı oluyor hocam mach3deki gibi ?

4000(step sayısı)/200(Motor Adımı) = 20(tur)*5(vidalı mil hatvesi) = 100 mm/sn

saniyede 100 mm ilerleyecek mikrostep için pulse adedi = 4000(step sayısı)*8(mikrostep sürücü) = 32.000 pulse

timer değeri için 16.000.000/32.000 = 500 bu minperiod olacak.
hızlanmayı yavaş yavaş artırmak içinse 100(step sayısı)*8(mikrostep) = 800 pulse

16.000.000(mips)/800(pulse adedi) =20.000 buda delaytime olacak

hizlanma için uygun rakamıda ben belirleyeceğim.

bunun içinde


delayTime=20000;       // düşük hızdan yüksek hıza çıkmak için çıkartma işlemi uygulanacak.
minPeriod=500;       // minPeriod en yüksek hıza göre master eksenin hızı.
hizMiktari=15;       // hızlanma miktarı - delaytimeden çıkacak.

örneği doğru anlamışmıyım hocam. timeride düzgün kurarsam benden keyiflisi olmaz :)


iyildirim

Doğrudur.
İşlemcinin timerlarından 1 ve 3 16 bit ve kullanıma uygun görünüyor.
Sadece Timer1'i kullanırsan ya putMotor içinde puls darbesini sonlandırmak için bekleyeceksin yada timer1 ile birlikte timer3'ü de delayTime/2 'ye kurup ISR de bütün puls pinlerini, puls polaritesine göre high yada low yapacaksın.
Kolay gelsin..

computerboy

hocam yardımlarınız için çok teşekkürler allah razı olsun. usb çalışırken timeri kuramıyorum nasıl yaparım hala araştırma içindeyim çözemedim.

iyildirim

Yukarıda @goo nun yazdığı şekilde olmuyormu. ?

Anladığım kadarıyla bir de usb ISR var. USB kesmesi ile ilgili kodlar direkt kesme altındamı 18f leri pek bilmem ama kodun sığmaması sanki herşeyi direkt kesme altında yazıyosun gibi bir şey düşündürdü.
Ayrıca Timer'ı başka bir şey kullanıyormu gibi şeyleri kontrol edebilirsin.
Timer1 veya timer3'ü kullanabilirsin. Biriyle olmuyorsa diğerini dene.


computerboy

evet goo  hocamin  dedigi gibide denedim ama olmadi usb isr kesmesi ayri calisiyor timer 0 1 2 3 fark etmiyor 10 ms'de bir kesmeye girip usb datasini kontrol etmesi gerekiyor bu yuzden timer period v.s ayarlayinca usb duzeni bozuluyor farkli yontemler ariyorum belki cdc bulk transfer metodunu kullanirim o zaman yazilimda ve kodda buyuk capli degisim gerekecek onuda gozum kesmiyor ayrica timeri aktif etmek icin sadece led yak var timer blogunda daha timer mevzusuna hic gecmedim


computerboy

tekrar merhaba. timer işini hallettim hocam. yalnız  anlayamadığım bir sorunla karşılaştım.

örnek; x=5000 y=6000 yapınca X ekseninde anlamsız bir titreme (pozisyon bozulması-adım atlama) oluyor , x7000  y6000 yapıncada sorun olmuyor anlayamadım belirli bazı buyuk rakamlarda oluyor.

void putMotor(SL x, SL y, SL z)
{
	if(x-oldX==1 || x-oldX==-1) STP_X = 1;  	
	if(y-oldY==1 || y-oldY==-1) STP_Y = 1;  	
	if(z-oldZ==1 || z-oldZ==-1) STP_Z = 1;  

	while(ReadTimer1() < delayTime); WriteTimer1(0);
    if (delayTime > minPeriod)             
        delayTime -= hizMiktari;   

 	STP_X =0;									
	STP_Y =0;								
	STP_Z =0;           					
	
	while(ReadTimer1() < 250);	WriteTimer1(0);

	oldY = y;
	oldX = x;
	oldZ = z;
}


//**********************************************************
void line3d(SL s_d,SL e_d,SL  x1, SL  y1, SL  z1, signed long  x2, signed long  y2, signed long  z2)
   
{	

	SL  x, y, z; 	
    SL  xd, yd, zd;
    SL  ax, ay, az;
    SL  dx, dy, dz;

    dx = x2 - x1;	
    dy = y2 - y1;
    dz = z2 - z1;

    ax = ABS(dx) << 1;	
    ay = ABS(dy) << 1;
    az = ABS(dz) << 1;

    sx = SGN(dx);		
    sy = SGN(dy);
    sz = SGN(dz);

    x = x1;
    y = y1;
    z = z1;
	
	minPeriod = s_d;
	hizMiktari = e_d;
	delayTime=10000;  
	WriteTimer1(0);

	UsbVeriGonder((rom char*)  "2D Kesim İşlemi..");
    if (ax >= MAX(ay, az))            
    {
        yd = ay - (ax >> 1);	
        zd = az - (ax >> 1);
        for (;;)
        {

			if(x-oldX==1) DIR_X = 0;else DIR_X = 1;  
			if(y-oldY==1) DIR_Y = 0;else DIR_Y = 1;  
			if(z-oldZ==1) DIR_Z = 0;else DIR_Z = 1;  

            putMotor(x,y,z);			

            if (x == x2)
            {
                return ;
            }

            if (yd >= 0)
            {
                y += sy;
                yd -= ax;
            }

            if (zd >= 0)
            {
                z += sz;
                zd -= ax;
            }

            x += sx;
            yd += ay;
            zd += az;
        }
    }
    else if (ay >= MAX(ax, az))         
    {
        xd = ax - (ay >> 1);
        zd = az - (ay >> 1);
        for (;;)
        {

			if(x-oldX==1) DIR_X = 0;else DIR_X = 1;  
			if(y-oldY==1) DIR_Y = 0;else DIR_Y = 1;  
			if(z-oldZ==1) DIR_Z = 0;else DIR_Z = 1;  
            putMotor(x,y,z);

            if (y == y2)
            {
                return ;
            }

            if (xd >= 0)
            {
                x += sx;
                xd -= ay;
            }

            if (zd >= 0)
            {
                z += sz;
                zd -= ay;
            }

            y += sy;
            xd += ax;
            zd += az;
        }
    }
    else if (az >= MAX(ax, ay))           
    {
        xd = ax - (az >> 1);
        yd = ay - (az >> 1);
        for (;;)
        {


			if(x-oldX==1) DIR_X = 0;else DIR_X = 1;  
			if(y-oldY==1) DIR_Y = 0;else DIR_Y = 1;  
			if(z-oldZ==1) DIR_Z = 0;else DIR_Z = 1;  

            putMotor(x,y,z);

            if (z == z2)
            {
                return ;
            }

            if (xd >= 0)
            {
                x += sx;
                xd -= az;
            }

            if (yd >= 0)
            {
               y += sy;
                yd -= az;
            }

            z += sz;
            xd += ax;
            yd += ay;
        }
    }
}





computerboy

Hocam, sizinde başınızı ağrıtıyorum lütfen kusuruma bakmayın. mips olayı kafamı karıştırdı.

Vidalı Mil Hatvesi = 5 mm.
Step Motor = 1.8 (360/1.8 = 200 Adım)
Step Motor Sürücü 0.9 (360/0.9 = 400 Pulse)

Mcu Pic18f4550 ;

PLLDIV = 5 // 20 Mhz kristal takılı
CPUDIV = OSC1_PLL2//  [96 MHz PLL Src: /2]) = 96 mhz/2 = 48.000.000 hz.
Timer1 16 bit  ve 1:8 kullanıyorum buda (65535/8 = 8191) Maximum Prescaler 8191 yapıyor.


bu özelliklere göre nasıl bir hesap yapmalıyım ayrıca yukarıdaki hesabı doğrumu yapıyorum.

visual basic 6.0 ile küçük bir hesap programı yazdım vaktiniz müsait ise bir göz atabilirmisiniz ?

http://www.4shared.com/rar/90fb-t_m/Motor_Program.html

birde burada ne demek istediniz biraz daha açarmısınız.

Alıntı yapılan: iyildirim - 20 Şubat 2013, 02:26:23
Doğrudur.
İşlemcinin timerlarından 1 ve 3 16 bit ve kullanıma uygun görünüyor.
Sadece Timer1'i kullanırsan ya putMotor içinde puls darbesini sonlandırmak için bekleyeceksin yada timer1 ile birlikte timer3'ü de delayTime/2 'ye kurup ISR de bütün puls pinlerini, puls polaritesine göre high yada low yapacaksın.
Kolay gelsin..

puls darbesini sonladırmak için aşağıdaki kodda while(ReadTimer1() < 250);   WriteTimer1(0); ile bekleme yaptım bu yetersizmi acaba ?:

void putMotor(SL x, SL y, SL z)
{
    if(x-oldX==1 || x-oldX==-1) STP_X = 1;  	
    if(y-oldY==1 || y-oldY==-1) STP_Y = 1;  	
    if(z-oldZ==1 || z-oldZ==-1) STP_Z = 1;  

    while(ReadTimer1() < delayTime); WriteTimer1(0);
    if (delayTime > minPeriod)             
        delayTime -= hizMiktari;   

 	STP_X =0;									
    STP_Y =0;								
    STP_Z =0;           					
    
    while(ReadTimer1() < 250);	WriteTimer1(0);

    oldY = y;
    oldX = x;
    oldZ = z;
}