Fórum témák
» Több friss téma |
Figyelj, a szervókat azt végülis PWM úton kell vezérleni nem? Egy PIC meg elég silányul van ellátve PWM kimenetekkel. Úgy oldod meg, hogy minden szervóhoz készítesz egy 555IC-vel működő önálló PWM modult, és akkor a PIC-ed programozza fel a modulokban a kitöltési tényezőket? Vagy mi a mód amit követni fogsz? Esetleg multiplexelni fogod a szervókhoz a PWM-et?
Összesen 18 szervó van a lábakban.
Mind a 18 szervó vezérlését egy áramkörön szeretném megoldani. Egy szervó vezérlőjele 750 és 2300us között mozog (ezzel felkészültem a nagy kitérésű szervókra is). Így gyorsan kiszámolható, hogy maximum 8 servót tudnék vezérelni 1 PWM modulátor multiplexálásával, 2 PWM-mel 16-ot. Fontos arra is gondolni, hogy kell holtidő is, amikor a PIC fogadhatja az adatot SPI buszon. Ekkor nem futhat servo vezérlés, különben a servo rossz pozícióra áll. Tehát minimum 3PWM vezérlővel megáldott PIC kell. Ilyet a 18-as szériában találunk is szép számmal, de sajnos TQFP tokozással. Egyenlőre szívesebben maradnék a DIP változatnál. Marad az,h ASM-ből pontos időzítésekkel kapcsolgatom a lábakat. A szervo vezérlőt 20Mhz kristály fogja hajtani, így egy us alatt 5 ASM műveletet tudok végrehajtani. Úgy számoltam,h kb 1us pontossággal tudom majd vezérelni a kimenő jelet.
Azt mondtam segíteni szeretnék, tehát akkor most szólok, hogy nem értek egyet azzal, hogy programból adsz ki PWM vezérlő jeleket. A szoftveresen előállított PWM nagyon pontalan és rendkívül sok program memória igénye van.
Gyorsan javaslom is Neked a PIC16F887-et, ami DIP-ben is kapható és 3 PWM kimenettel rendelezik. Ez az a PIC típus ami a PicKit2 demoboardján megtalálható (persze ott nem DIP). Mit szólnál ahhoz, ha kettő, vagy több PIC-ed lenne és ők szépen bármilyen protokoll alapján megbeszélnék és megosztanák a funkciós teendőket? Ha azt veszed, hogy van két PIC-ed, már van is 6 PWM-ed és akkor már csak lábanként kell multiplexelned, ami már nagy könnyítés. Nem beszélve arról, hogy hardveresen időzített PWM-ről van szó. Üdv: SegítőGooga
Igaz,h az eccp-vel 4 kimenetet lehet hajtani, de ha jól emlékszem a működésére akkor nekem inkább 3 különálló CCP kellene. De most vettem észre,h a 16-os sorozatban is van 4 ilyen DIP tokban.
Azt hiszem jövő héten rendelek pár új PIC-et Amúgy a szoftveres ötlet innen származik: http://www.mikroe.com/forum/viewtopic.php?t=7081 Köszönöm a segítséget!
lábanként 1 szervó elhanyagolható, hogyha a lábai közé rugot teszünk, legalábbis ahogy én gondolkoztam úgy lehetséges.
Igen elhanyagolható lábanként 1 szervó. Ezt hívják 2DOF lábnak.
Sok ilyenről van terv a neten. De nekem a 3DOF megvalósítás jobban tetszik. Sokkal élethűbb. Az anyagi rész pedig biztosítva van hozzá, így nem okoz problémát a +6 szervó
Szia! Tegnap nagyon felbozdultam és én is úgy határoztam, hogy lebonyolítok Veled párhuzamosan, na jó, kicsit lemaradva egy robot projektet, ami rc-servo-kkal működik.
Éjjel mélyebben belerugdostam magam a hardweres PWM-jel előállításába és rájöttem egy furcsa dologra. Ugyebár a szervók nagyjából (némi tűréssel) 20ms-ként várják a vezérlő jeleket. Az egyik végálláshoz ~1ms, a másik végálláshoz pedig ~2ms hosszúságú 'magas' jel szükséges. A középálláshoz értelemszerűen ~1.5ms hosszú jelre van szükség. (Ez most a standard analóg szerókra vonatkozik, hiszen vannak digitális szervók is.) Lehet, hogy azért, mert este volt, de amikor próbáltam kiszámolni a PR2 értékét (periódus idő), akkor a 4Mhz-re nem jött ki sehogy, hiszen a 16-os előosztóval is 10bites lett volna a PR2, amit én úgy néztem, hogy 8 bites. Rámentem a másik belső oszcillátorra, amit a PIC-em tud, ez 37kHz. Így kiszámoltam, hogy (mivel a szervóhoz 50Hz-es PWM frekvencia kell) a PR2 185 lesz. Ez ugyebár a teljes periódusidő. Amire nekünk ~1-2ms hosszú jelekt kell kiadnunk, amik kb. 5 és 10% kitöltési tényezőt jelentenek, minden esetben. Ez így számolásra 9,2 és 18,4 értéket jelent számolva. Be is programoztam a PIC-be, rákötöttem a szervót és működik, na azért ez nem semmi tőlem A következő lépés az volt, hogy megkerestem a minimum, és maximum kitérítéshez az értékeket. Az egyik 3 a másik pedig 27 lett. Na most ez a legjobb barátok közt is, csak 25 lépcső, ami a kb 180°-os elfordulást nézve igen silány felbontás, gyakorlatilag 7,2°-onként lehet léptetni. Ideális esetben: Ha a PR2 maximális felbontása csak 8bites lehet, ami 1024-et jelent decimális számként. Ha veszem a kitérítéshez szükséges 5%-tól 10%-ig terjedő kitöltési tényezőt, akkor az decimális értékben 51 és 102 között van, tehát a felbontás 51 lépcsős. Ez a 180 fokos elfordulás esetén is csak közel 3°, ami még mindig silány egy robotnál. Most jobban belevetem magam a leírásokba és máris nem lesz ekkora a probléma, ha a PR2 10bites is lehet. Lehet csa kelkerülte a figyelmemet. A lényeg, a lényegben, hogy ezt lehet szoftveres PWM-ezéssel kiküszöbölni. Remélem másoknak is hasznára vállik, hamár ennyit gépeltem.
Szia,
én is sokat olvasgattam és mindenhol softPWM-et használnak. megszakításokkal eléggé pontos időzítést lehet elérni. Nekem ez a megoldás nagyon tetszik: delay_us(500) ASM movlw 0 decfsz _servo+0, 1,0 iorlw 1 decfsz _servo+1, 1,0 iorlw 2 decfsz _servo+2, 1,0 iorlw 4 decfsz _servo+3, 1,0 iorlw 8 decfsz _servo+4, 1,0 iorlw 32 andwf LATA, 1,0 Az elején várunk 500us-t, mivel addig legalább minden servonak magasan kell lennie (gyakorlatilag ez lehet,h inkább 1000 kell, hogy legyen, de persze ezt szervója válogatja). wevébe pedig szépen összeszedi, hogy az adott porton lévő szervók közül melyik kapjon jelet, majd egybe kiküldi az A portra. és így könnyű számolni is, mert a decfsz ha átugorja a köv sort, akkor dob egy nop-ot. Ezt az ASM-et pedig a 16bites timer hívja meg 17.5ms-enként a teljes kód (igaz basic, de azért rá lehet jönni ) itt van: http://www.mikroe.com/forum/viewtopic.php?t=7081
Csak egy gyors kérdés:
FOSC/4 utasításidő P16 és P18 esetében is van, dsPIC esetében és P24 esetében pedig nincs. ez így helyes?
Igen. Bár szebben is meg lehetett volna fogalmazni a kérdést.
Még annyit, hogy az adatlapokban szépen le van írva és rajzolva az utasításvégrehajtás menete.
kiszámoltam, hogy softPWM-mel
20Mhz órajellel (0,2us/asm) amíg végigállít 18 servót, az 10us-t vesz igénybe. 255 lépéssel számolva, 2550us-ig fut. Nos ha multiplexeljük a dolgot, tehát pl 8-8-2 lépésekben állítjuk a servókat akkor a kód kb így néz ki: PORTA = 255 delay_us(1000) 8 servo állítása PORTB = 255 delay_us(1000) 8 servo állítása PORTC = 255 delay_us(1000) 2 servo állítása + annyi nop, hogy kitegyen 8 szervónyi időt 8 servót 4us beállítani. 255 pozícióval számolva 1020 us (pont fedi az 1000-2000us közötti időt ) Nah ezt meg kell ismételni háromszor. Akkor kb 4ms-ig fut az interrupt és beállított maximum 24 szervót !!4us!! pontossággal! Mi a véleményed róla? még nem csináltam meg, csak agyalok
Így visszaolvasva valóban magyarabbul is fel lehett volna tenni kérdést
Köszönöm a gyors választ!
Hát, ha tőlem kérdezted, akkor átgondolom. Én is a helyes megoldást keresem. Valahogy attól tartok, hogy amint egy másik szervóval kezdesz foglalkozni, máris elveszted a kontrollt az első szervó felett.
Most így hírtelen az jut eszembe, hogy addig kénytelen vagy egyetlen szervóval "foglalkozni", amíg a magas jelet küldöd ki neki, aztán marad még Periódusidő minusz Kitöltési időnyi időd, egy másik szervóra koncentrálni. Ezt ugye a periódusidő ~90% és ~95%-a között van. Vagyis szerintem egy időzítésen bellül, maximum 10 szervóval tudsz foglalkozni - ha mindegyik a maximális kitérítésben van éppen - hogy ne veszítsenek jelet. Végülis ez is egyfajta multiplexelés lesz. Nem tudom, érthető miről beszélek?
Egyébként akárhogy is gondolkodom rajta. A legszebb megoldás az lenne, hogy minden szervót egy saját PIC és a rajta futó PWM vezérelne. Ezeket pedig egy központi PIC utasítgatná, gyakorlatilag az aktuális kitöltési tényezőt küldené el.
Van olyan dsPIC(ha már szóba került) aminek van egy halom OCx kimenete. Ezeket két Timerhez lehet hozzárendelni(egyszerre csak egyikhez), és saját kitöltés regiszterük van.
A másik megoldás pedig a megszakításos vezérlés, ahol minden PWM-hez egy kitötlés regisztert rendelünk, és a felbontás ütemében egy számlálót léptetünk. Minden megszakításkor végigellenőrizzük a kitöltési tényezőt tartalmazó regisztereket, hogy egyezik e valamelyik a számláló értékével. Ha igen, akkor a hozzá tartozó kimenetet nullába vezéreljük. Ha lejárt az egy periódusnyi számlálás, akkor minden kimenetet magasba vezérlünk, és kezdjük előről a számlálást, és hasonlítgatást. Két számlálás között el kell tudni végezni a kimenetek vezérlését és az összehasonlítgatásokat és még a program egyébb műveleteinek is kell időt hagyni! Ez meghatározhat egy maximális felbontást, ami a kitöltés lépésenkénti változtathatóságát adja meg. Minél több kimenetet akarunk vezérelni, minél nagyobb frekin, annál nagyobb lépésekben lehet a kitöltést változtatni. Rátok bízom annak kiszámolását, hogy ilyen módon milyen frekivel és milyen kitöltési lépésekben hány kimenetet lehet vezérelni. Érdemes a lekezelés és az egyéb program szálak közötti idő arányt max 50%-ra választani. Ez egy kiindulási alap, ami akkor változhat, ha a "kinti" programszál működését nem befolyásolja. Az órajel a lehető legnagyobb kell legyen(20MHz...). Ezzel a megoldással lehet a leghatékonyabban és a legegyszerűbben ezt megoldani, legalább is szerintem.
Első körben én is arra gondoltam, hogy valami soros buszra felfűzöm a vezérlőket és mindegyik önálló PWM-mel dolgozna. De ahhoz nagyon sok PIC kell.
Viszont nekem egyre jobban tetszik a softPWM megoldás. Egyszerre lehet 8 szervó jelét állítani. 4us alatt végigfut a 8 szervón és a portra csak a ciklus végén nyomja ki az adatot. 4us pont jó arra,h az 1000 és 2000us közötti időtartamot 250 részre felosszuk. Mivel a szervóknak 50hz-cel kell tolni az impulzust ezért egy ilyen 8-as csoport vezérlése után még maradt 19ms szabad időnk. Tehát ha 3 8-as csoporttal foglalkozunk, még mindig marad ~16ms szabad idő, amikor pl soros porton fogadhatjuk az új szervó pozíciókat. Csatoltam egy képet az elvről. A három sor a három "8-as" csoportot jelöli. A sötétpiros rész az első 1000us fix delay a világospiros pedig az az idő amikor a kapott kitöltés alapján valamikor meg kell szakítani a szervó impulzust. Az első sötétpiros pixelnél adnám a logikai 1-et portra az utolsó világos pirosnál pedig már biztos, hogy egyiken sem lenne logikai 1. A citromsárga szakaszokban egyik csoportot sem vezérlem, tehát ott fel lehet dolgozni a bejövő soros adatot. A teljes folyamat 20ms ideig tart. és az pont 50hz Remélem érthető a gondolatmenetem.
Most olvasom és értem meg, hogy ez itt több model szervó vezérlése lenne, ami 50Hz "PWM" lenne. Ez nem nagy ügy a korábban leírtak alapján...
Ez már tetszik!
Watt: Hidd el nekem nagy ügy
Az előző írásom egy teljes PWM-re vonatkozott volna, de ha ilyen előre ismert kitöltési idejű impulzus előállítása a cél, akkor van jobb megoldás.
A megszakítás 50Hz-es lenne, és minden alkalommal elrabolna a fő időből kb. 2ms-et, ami idő alatt csak a kitöltés kiszámolásával foglalkozna a rutin. Ez még egyszerűbb is. A fennmaradó idő elég lenne a többi feladatra. A felbontást itt is a lekezeléshez szükséges idő határozná meg.
Örülök,hogy mindenki kezdi érteni
Én úgy gondolkodtam, hogy mindenképpen muszály felosztani 3 részre a 18 szervó vezérlését, ugyanis csak így lehet 4us pontossággal vezérelni őket. Watt: Fentebb linkeltem az én gondolatmenetemet kirobbantó kódot. Ahogy írtad, a szervók vezérlése egy 50hz-es interruptból történne. Annyi a különbség, hogy az én elgondolásomban 3*2ms az elrabolt idő. Tehát: - Megszakítás kezd - PORTA = 255 - delay_us(1000) - Vezérlés (1020us) - PORTB = 255 - delay_us(1000) - Vezérlés (1020us) - PORTC = 255 - delay_us(1000) - Vezérlés (1020us) -Megszakítás vége Ez kicsivel több mint 6,5ms Marad 13,5ms a többi műveletre. ui: az előző hsz-ben csak 4ms-et írtam a vezérlésre, de ott elfelejtettem 3* beleszámolni a fix 1ms időtartamot.
Azért kell 3 részre osztani, mert a 18 szervó vezérlése kb 10us lenne. Amit ha egy 255 elemes ciklusba nézünk, akkor 2550us lenne amíg a végigfut.
Így 10us pontossággal lehetne vezérelni 18 szervót 3*8-as felosztásban viszont 8 szervó vezérlése 4us, ez 255ször 1020. És ez elé be kell szúrni az 1000us fix időt. Így pedig 4us pontossággal lehetne vezérelni 18 szervót.
Ne vedd fixnek, hogy a két végállás éppen 1000us-nál és 2000us-nál áll be. Este ez már a hardveres PWM-nél kiderült számomra. Még majdnem 5%-ot rá lehetett számolni mindkét irányban és ott volt a maximum kitérés.
Meg fogok szenvedni ezzel az ASM szoftveres késleltetéssel. Már vagy két órája képletet találok fel magamnak a ciklusokhoz.
Szia!
Én is most kezdtem el egy szervó vezérlő modult fejleszteni a robotomhoz. Vagy 16f628A ra fog épülni vagy 16F690 re attól függ ,hogy SPI vagy RS232-vel kommunikálni a fő mcuval. 8 szervót tud vezérelni (jelenleg még csak 1db ot de elég könnyen át lehet írni 8 ra), pontossága 255db pozíció (a 0 és az 1 et közel ugyanannak veszi). A prociból kb 5% ot használ mivel megszakításban fut így lehetőség van ugyanazon a procin más feladatot is futtatni mellette. Forráskódot küldhetek bár (még) érthetetlenül kusza . Jelenleg azon filózok hogy spi vagy rs232-vel kapcsolódjon addig meg nem írom meg(teljesen). Magához a hexapodhoz: elég nagy feladatnak tűnik. És az is. Ha fixen akarod vezérelni (szóval nem számolgatja hogy hova kell neki tenni a lábát hanem csak egy táblából vagy valahonnan olvasgatja) akkor elég esetlenül fog mozogni. A másik megoldás mikor számolgatja hogy hova kell rakni a lábát az nagyon bonyolult viszont nagyon szép eredményt lehet vele elérni (nem fog csúszkálni, rángatózni stb..). Erre itt egy példa: Videó 1, Videó 2, a vele foglalkozó oldal.
Szia,
Ismerem azt a robotot amit linkeltél. Ugyan olyan szervók hajtják mint amiket én rendeltem. Állítólag nagyon rosszak, de ezen a roboton is tökéletesen működik. Na meg majd később lesz mit fejleszteni rajta Sajnos most nem tudok youtube-ot nézni, de azt hiszem ezen a linken van amit meg fogok építeni: Youtube Erről a robotról többet a Lynxmotion.com oldalon olvahatsz, valamint ebben a fórumban: Lynxmotion.net Xan's Phoenix code Ha eléggé szemfülesek vagytok, akkor megtalálhatjátok a robot forráskódját, benne az inverz kinematikai számításokat is (ez az ami kiszámolja, hogy az adott izületeket milyen szögbe kell vezérelni a kívánt pozícióhoz) Igaz basic nyelven, de könnyen átültethető akármi másra. Ja és benne van a PS2 vezérlés is. ui: Zenta volt olyan nagylelkű és segítőkész, hogy átküldte a Phoenix autocad tervrajzait Idézet: „Örülök,hogy mindenki kezdi érteni” Szeretem mikor szerény valaki! Egyébként az egész 2ms(+ néhány programlépésnyi idő) alatt megoldható, és ez alatt nem csak 3 szervó kezelhető le, hanem sokkal több. De úgy csinálod ahogy akarod... MÉg annyit, hogy megszakításban várakozó rutinokat beiktatni kóklerség.
nem véletlenül volt ott ám ott az a batárnagy smile
itt sem 3 szervót kezelek, hanem 3*8-at. 8 szervó vezérlését 20 utasításba tudtam belenyomni. Ebbe van 1 bra meg egy nop (hogy kerek 10us legyen ) is. 20 utasítás 20Mhz órajellel 0.2*20 vagyis 4us alatt fut le. Ha egy ciklusba kezelem a 18 szervót, akkor 10us amíg egyszer lefut a ciklus tartalma. És ez a futás határozza meg a minimális lépésközt. Ezért háromfelé bontottam a 18 szervót és a 3 csoportot egymás után vezérlem. Sajnos muszály várakozó rutint beleraknom a kódba, mivel megszakítással tudom a legegyszerűbben elérni, hogy a kódom másodpercenként 50* fusson. Persze meg lehet oldani, 2ms-be is, de akkor nem 255 lépésem lesz hanem csak 100, ami azt jelenti, hogy ~1,2 fokonként tudom állítani a szervót. Így pedig 0,47 fokonként.
Nem kell semmi várakozó rutni a megszakításba. (16f-eknél) TMR2 és a TMR0 vagy 1 kell. Az én megoldásom a következő:
Elősször magasra állítja a servo0 lábat, tmr2 őt beállítja , hogy xxx uS (attól függ mi a 0 pozíció) múlva megszakítson majd beállítja a 1-255 ig terjedő pozícióba és ezzel megadott uS időt vár(ez a pozíció). Ezután low ra állítja a servo0 lábat és high re a servo1 et majd folytatja egészen a servo8 ig. A másik timer nek a feladata , hogy újraindítsa a jel generálást 20mS időtartamonként (ez még nincs benne a programomba mivel még csak 1 szervót vezérlek). Így a szervókat egyessével "frissíti" és nem is eszik meg sok cpu időt, sehol nincs sw-es várakozás. Ennek a megoldásnak egy hátránya van: sok (kb 800) megszakítást igényel másodpercenként de 5mips-on ez az érték elfogadható. 18F pic használata esetén még ha akarunk több megszakítást engedélyezni akkor érdemes a szervó vezérlő rutin megszakítását magas prioritásúnak választani (nem vagyok benne annyira a 18F ek lelkivilágában..) mert ha egy másik megszakítás "eltolja" akár pár uS-al a a szervó megszakítást akkor a szervók elkezdenek remegni (tapasztalat... volt egy másik pwm megszakításom egy másik servo "driver" mellett és "összeakadtak" mikor közel egyszerre érkezett a két megszakítás) 16F eknél az lehet a lehetséges megoldás ,hogy a servo megszakításnak sw-esen elsőbséget adunk. [szóval újra engedélyezzük a megszakításokat egyéb megszakítás érkezése esetén (mert ugye a megszakításba való belépéssel letiltódnak) és végrehajtjuk az alacsonyabb megszakítást és itt ugye közben lefuthat a szervóé is ha épp jön ] Idézet: „nem véletlenül volt ott ám ott az a batárnagy smile” Bocsánat, nem úgy jött le, ne haragudj! Idézet: „itt sem 3 szervót kezelek, hanem 3*8-at.” Ez sem értettem akkor! Mégegyszer átgondolom...
hmm... Ez jó! jó ötlet! csak tényleg elég macerás ennyi megszakítást kezelni. ezen az ötleten még gondolkodok.
8 szervót a következőképpen vezérlek:
movlw 0 decfsz _servo+0, 1,0 iorlw 1 decfsz _servo+1, 1,0 iorlw 2 decfsz _servo+2, 1,0 iorlw 4 decfsz _servo+3, 1,0 iorlw 8 decfsz _servo+4, 1,0 iorlw 16 decfsz _servo+5, 1,0 iorlw 32 decfsz _servo+6, 1,0 iorlw 64 decfsz _servo+7, 1,0 iorlw 128 andwf PORTA, 1,0 incfsz _pos, 1,0 bra $-19 a _servo egy 18 elemű tömb amiben 0-255 közötti érték található. ez a kódrészlet 4us alatt fut le. az utolsó két sor miatt (ha _pos értéke 0) 255* ismétlődik. Tehát összesen 1020us-ig fut és egyszerre 8 szervót vezérel. Ha ezt 3* egymás után rakom akkor 3*8 szervót tud vezérelni. |
Bejelentkezés
Hirdetés |