RS232-USART seçmeli komut

Başlatan lordsandman, 10 Temmuz 2011, 19:03:03

lordsandman

merhaba arkadaşlar başlık biraz saçma oldu kusuruma bakmayın,
RS232'den göndereceğim komutlarla PIC16F628 kontrollü 3 tane step motoru sürmek istiyorum. PC yazılımını VB6 ile hazırladım. motorlar M1,M2,M3 olarak etiketlendi. komutları M210050 formatında gönderiyorum.
M2: 2.motor / 1:saat yönü / 0050: 5 derece dön anlamında(0.1 derece hassasiyetle)  PC'den sadece dönecek motora ilişkin komut gidecek. ve PIC motor dönüşünü tamamladığında PC'ye M2' döndü şeklinde bir onay gönderecek.

hi-tech c ile "M210050" şeklinde PIC'e gelen komutu nasıl bir bütün olarak algılatıp ayrıştırabilirim. yani komutun byte byte tamamını usarttan aldıktan sonra motor=2;yön=1;donu=50 şeklinde ayrıştırmam gerekiyor. her motor için girdisi yön ve açı değerleri olan fonksiyonlar yazdım. fakat strcmp ile gelen komutu ayıklayamadım. kısa bir kod örneği verirseniz çok sevinirim

veya bu işi yapmanın daha sade ve makul bir yolu varmı?

Tagli

Ben genelde bu tür işleri ham veri göndererek yapıyorum. Yani karakter göndermek yerine kendim bir paket formatı oluşturuyor ve onu gönderiyorum.

Örneğin senin uygulamanda bu işi 3 byte ile yapabilirsin. İlk byte hangi motorun hangi yönde döneceğini gösterir. Örneğin en büyük biti yön olarak alırsan, kalan 7 bit ile 128 motor ifade edebilirsin. Dönme miktarını da ardından yollayacağın 2 byte ile (0 - 65535 arası tamsayı) ile belirleyebilirsin.
Gökçe Tağlıoğlu

Klein

#2
sscanf(buffer,"%01u%01u%04u",&M1,&M2,&M3);
// buffer : seri portttan aldığın bilgiyi tuttuğun dizi
// M1: motor sırası değişkeni
// M2: Yön değişkeni
// M3: Hız değişkeni


gönderirken aralara ayraç karakterler koyarsan daha sağlam olur.
örn: 1,2,0050 gibi.
eğer böyle yaparsan  scanf formatın şöyleolur.
sscanf(buffer,"%01u,%01u,%04u",&M1,&M2,&M3);


yamak

Ben olsam şöyle yapardım.
Her bir komut için ona özgü bir başlangıç byte ı gönderirdim. bu şekilde ayrıştırırdım 3 farklı veriyi.
örneğin birinci motor için x 2. motor için y 3. motor için z gönderilirsin. saat yönü için a saat yönünün tersi için b. açı içinde normal açı değeri tabi sonra bu değeri atoi fonksiyonu ile int e çevrimeniz gerek. motor bilgisi için  "!" yön bilgisi için "+" açı bilgisi için de "&"  ilk olarak gönderilirsin. bu şekilde gelen verirlerin ne olduğu anlamış olursunuz.

lordsandman

hızlı ve güzelcevaplarınız için teşekkür ederim
sayın Tagli ve yamak; söylediğiniz yöntemler muhakkak daha sade fakat PC yazılımında devrenin geri kalanı için(DAC ve EEPROMlar gelecek) standart etiketler yapmıştım. PC yazılımı biraz karmaşık olduğu için mnemonic takılmak kolay geldi :)

sayın Klein, sscanf komutunu bilmiyordum aradığım şey buydu. proteusta LEDlerle denedim işimi görüyor. dönüp biraz C'ye baksam iyi olacak sanırım, az bildiğimi de unutmuşum. devrenin geri kalanı için etiketleri case ile ayrıştırıp DAC'lara komut gönderebilirim sanırım

teşekkürler arkadaşlar, bir başka konuda kafa şişirmek üzere

iyildirim

Yapmak istediğinize benzer bir şey için alttaki kodu kullanıyorum.. Kod C30 için..

UART dan gelen data cmdBuffer adında unsigned char bir arraya,  buffere alınıyor. 
Komut formatıda 3 ayrı motor - eksen için X-Y-Z şeklinde, parametre olarak da kaç step dönecekleri bildiriliyor. Yani X100Y200Z-300 gibi.. Pc den gönderilen satırlar ascii(13) ile bitiyor.. Yön bilgisi için de + veya - kullanılıyor.  cmdX 'e atanan değer pozitif ise örneğin saat yönünde negatif ise de saat yönünün tersine dönüyor..


doCommand_getParams() kısmını kullanmayıp atol gibi standart C fonksiyonlarıda kullanabilirsiniz. Ben hafıza problemlerinden dolayı kendim yazmıştım.
Genel değişken tanımları,  deklarasyonlar yok ancak fikir vereceğini düşünüyorum.

Birde öneri..
ne kadar dönüleceği bilgisini step sayısı olarak gönderin. Açı hesapları ve floating işlemlerle uğraşmak zorunda kalmazsınız.
Eğer 0.1 derece hassasiyette istiyorsanız sürücünün mikrostep desteği de olmalı.

void processCommandLine()
{

    unsigned char commandTemp = 0;
    signed long commandParamTemp = 0;
    
    char calibLoad = 0;
    
    cmdBufferPtr = 0;
    
    
    while (1)

    {
            switch(cmdBuffer[cmdBufferPtr])
            {
                
            case 0x0d:
                while(cmdDone == 0);
                command = commandTemp;
                commandParam = commandParamTemp;
                doCommand();
                
                break;
                    
            case 'X':
                cmdX = doCommand_getParams(cmdBufferPtr);
                break;
            case 'Y':
                cmdY = doCommand_getParams(cmdBufferPtr);
                break;
            case 'Z':
                cmdZ = doCommand_getParams(cmdBufferPtr);
                break;
            case 'F':
                cmdSpeed = doCommand_getParams(cmdBufferPtr) * 2;
                break;
            default:
                break;
            }
        } 

        if (cmdBuffer[cmdBufferPtr] == 0x0d)
        {
            break;
            
        }

        cmdBufferPtr++;
    }
    return;
}


signed long doCommand_getParams()
{
    signed char signVal = 1; 
    signed long cmdVal = 0; 
    signed char exitLoop = 0;

    cmdBufferPtr++;

    while (exitLoop == 0)
    {
        switch(cmdBuffer[cmdBufferPtr])
        {
        case '-':     
            signVal = -1;
            cmdBufferPtr++;
            break;
            
        case '+':
            signVal = 1;
            cmdBufferPtr++;
            break;
             
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
            cmdVal = cmdVal * 10 + cmdBuffer[cmdBufferPtr]-48; 
            cmdBufferPtr++;
            break;

        default:
            exitLoop = 1;
            break;
        }
    }

    cmdVal = signVal * cmdVal;

    cmdBufferPtr--;

    return(cmdVal);
}

lordsandman

#6
eğer bir hobi projesi olsaydı her bileşeni farklı bir yöntemle kontrol edip koddan zevk alırdım. aynı şeyi birçok yolla yapmak ne güzel :)
sayın iyildirim, kodunuz çok temiz zaten daha üst kontrollerde sizinkine benzer bir yapı oluşmuştu kafamda örneğini vermiş oldunuz. bir de kodunuzda kalibrasyonu nasıl kontrol ediyorsunuz. kullandığınız sensör vs. varsa nedir?
benim olayda 3 motor diskleri döndürecek, bu disklerde de bazı cihazlar bağlı çarpışma riskleri var ve birbirlerine göre hangi açıda oldukları önemli diğer hesaplar açısından. onun için PC yazılımı tarafında açı bilgisini cihazların aralarındaki açı olarak tutuyorum hep. zaten bu cihazların 0.1 derece dönmesi için motorun 800 step falan atması gerekiyor telli bir sistemle motor şaftına bağlı diskler. konudan saptık ama kalibrasyon işi beni düşündürdüğü için hazır üstadları hepbirden bulmuşken sorayım:)

iyildirim

Kod üç eksen bir cnc için hem indexer hemde step sürücü olarak çalışan bir işlemci için yazılmış kodun bir parçası..
Uzun bir süre pozisyonlama kısmı sensör vs. olmadan (ki sensörden kastım enkoder gibi cihazlar) çalıştı. Şimdi yeni bir işlemciye geçip, kendi yaptığım resolverimsi bir bir şey de kullanacağım. Resolver yeterince iyi olmaz ise ya enkoder kullanmak gerekecek yada açık çevrime devam..

Açık çevrim de de oldukça uzun bir süre çalıştı  ve tek sıkıntısı step kaçırma ihtimalinden dolayı yüksek hızlarda motorları sürememek oldu.

Eğer bazı varsayımlar yaparsak, makaralar ve disklerin çaplarının tam olarak bilindiği, bunları bağlayan telde kayma olmadığı gibi..
Disklerin 0.1 derece dönmesi için motorların 800 step ilerlemesi, dolayısıyla motorların 200step tur olduğunu varsayarsak çok büyük bir redüktör oranının çıktığı gibi..
Disklerin dönmesi için gerekecek güç de sanırım fazla değildir. Dolayısıyla tork vs den dolayı motorların step kaçırmayacağı varsayılabilir.

Diğer yandan bu disklerin ne hızla dönmesi, ne kadar hızlı tepki vermesi gerektiği gibi şeyler de bilinmeli.  Eğer diskler 1 derece/sn hızla dönsün derseniz bu hıza söylediğiniz oranlarla güvenli bir şekilde steplerle çıkamayabilirsiniz. Bu durumda belki step yerine DC veya BLDC servo gibi şeylerde düşünülebilir.
Steplere takılacak bir enkoder ile sistemi servoya çevirmek de mümkün.

Ancak projeniz ne kadar oturdu, neler araştırma safhasında, nelerin kararı verildi gibi şeyleri bilmediğimden tüm bu söylenenlerin havada kalacağı da bir gerçek.

Kalibrasyon ise ayrı bir konu.. Bu konuda birşeyler söylemek için daha çok şeyin bilinmesi gerekli. Test ortamınız nedir. Bu sistemi test amaçlı kullanabilirmisiniz yoksa hiç hata yapmamak mı gerekir gibi şeyler aklıma geliyor.

Motorlar çalışırken yeni komut gelebilir,  pozisyon bilgisini güncelleyebilirmi,  yoksa komutlar yalnızca motorlar duruyorken mi gelecek. Motorların her birinin farklı hızlarda çalışması gibi birşey olacakmı, yada motorların hızları  sabitmi, yada motorların hızları arasında sabit veya değişken bir oran varmı gibi sorular da sorulabilir.

Bu cihazın ne olduğunu da merak ettim.. Çok özel bir şey değilse biraz açabilirmisiniz.


lordsandman

#8
en büyük sorun disklerin veya disk üzeri cihazların açısal konumlarını algılayıp servo yapmak. bu olmazsa son çarem disklere çember dişli takmak ama bunu da yapmak istemiyorum

bir de step sürücü olarak TIP122 transistörleri kullandım. önerebileceğiniz bir devre var mı? motorlar 5V, 1A, 8-uçlu unipolar

iyildirim

Resimden gördüğüm kadarı ile diskler belli bir açıya kadar dönmek zorundalar. Mekanik engellerden dolayı tam bir tur atmıyorlar görebildiğim kadarı ile.

Bana göre en büyük handikap da motorlarla diskleri tel ile bağlamak. Tel, bildiğimiz tel ise metal-metale çalışırken kayma olmayacağına güvenilmez. Bunun yerine kaymayacak birşey koymak gerekli. Silikon bazlı birşeyler bulunabilir belki ancak o konuda malzeme bilgim yok.

Mekanik sınırlamalar nelerdir tam olarak bilinmediğinden enkoder, kapalı çevrim kontrol konularında ancak genel geçer şeyler söylemek mümkün..
Büyük ihtimal yazacaklarımın çoğunu sizde zaten düşünmüşsünüzdür..

Disklere dişli takmak çözüm. Sanırım bu dişlinin özel yapılması gereğinden veya dişli bir mekanizmanın uygulama zorluğundan dolayı istenmiyor. Dişli yerine trigger benzeri bir şey ve kayış kasnak da iş görebilir.
Yine de disklerin çok hassas olması istendiğinden kapalı çevrimde kontrol gerekir. Eğer dişli takmak çözümü uygulanırsa aynı dişli ile bir enkoder, resolver vs de sürmek mümkün olabilir.
Veya, eğer disklerin max dönme açıları kısıtlıysa, kendi çevrelerinde serbestçe dönemiyorlarsa,  uygun dişli oranı ile çok turlu kaliteli bir pot da kullanılabilir. Bu durumda 0.1 dereceden dolayı en az 12bitlik bir ADC kullanılmalı. Potun iyi tarafı sisteme ilk enerji verildiğinde bile size disklerin açısını söyleyebilmesi olur.

Yine dişli takılmadığı durumda enkoder veya pot ucuna kayma yapmayacak bir malzemeden bir disk takılarak büyük disklerle çalıştırmak da dişli yapmama durumunda çözüm olabilir. Ancak kayma anahtar nokta olduğundan uygun malzeme bulunmalı..

Malzeme bilgisi konusunda forumdaki bu konuda tecrübeli arkadaşların desteği gerekli..

Sürücü konusuna geçmeden önce disklerin 1 derece dönmesi için 800 step gerektiği gibi birşey hatırlıyorum. Resim de disklere tel ile bağlı küçük diskler motorlara direkt bağlı ise disklerin çapları arasında bu kadar fark yok. Dediğiniz doğru ise resimde görünmeyen kısımda motorlardan sonra birde redüktör olmalı..
Buna göre mikrostep gerekip gerekmediğinin kararı verilebilir.

Eğer bir şekilde disklere enkoder takılacaksa, kapalı çevrimde pozisyon kontrolü yapılacaksa motor olarak da ille step kullanılmak zorunluluğu da yok.. İstenen hassasiyeti sağlayacak redüktör oranına sahip  yüksek torklu bir redüktörlü DC motor da kullanılabilir. Step'e göre avantajı torkun yüksek olması olur. Buna disklerin ağırlıkları, sürtünme vs. şeylere göre karar vermeniz daha iyi.

Sürücü kısmına gelirsek, hazır alma seçeneğiniz var. Ebay de vs makul fiyatlı 3-4 eksen  unipolar-bipolar sürücüler var.
Kendim yapmak istiyorum derseniz, mikrostep gerekmiyorsa üzerinde chopper kontrolü de olan SLA7026 gibi bir chip kullanılabilir. Mikrostep gerekiyorsa da SLA serilerinin 16mikrostep'e kadar destekli 706x 707x gibi chipleri vardı. Bunların iyi tarafı chopper-akım kontrollerini yapabilmeleri.. İşlemcide uygun darbeleri üretip gerisine karışmazsınız.

Zaten bir mikro işlemci kullandığınıza göre  PWM ile akım kontrollü çalışacak bir devre de yapılabilir. PWM kullanıldığında bipolar transistör yerine MOS kullanmak daha iyi..
İşlemci dışında gereken 8 uçlu unipolar step motor için sargılar seri veya paralel bağlı durumda 4mos + 4 kanal da mos sürücü olur. Örneğin TC4427, 4428, TC4468, TLP250, TLP5XX gibi mos sürücüler kullanılabilir.  Aynı konfigürasyon da bir DC motor da çalıştırmak mümkün..



lordsandman

sayın iyildirim, değerli fikirleriniz için teşekkür ederim. 800 step konusunu yanlış yazmışım o an. yaklaşık 20 step ile istediğim hassasiyet olan 0.1 dreceyi yakalıyorum. mikrostepe gerek yok yani. sürücüyü L297 ve TIP122 ile kurmuştum, düşük hızlarda olduğum için sorunsuz çalışıyor, torku da yeterli gibi şu an için. kapalı çevrim geribesleme illa ki olacağı için söylediğiniz gibi dc motora da geçebilirim. üniversitemizde mekatronik bölümünden bir arkadaşla sisteme göz attık disklere uygun bir encoder sistemi takabileceğimizi söyledi, önümüzdeki günlerde test ederim. sonuç istediğim gibi olursa burada paylaşırım. şuan stepleri nota frekanslarında sürüp müzik yapmaya çalışıyorum :)