Stránka 1 z 2
Zákmity na rotačním encoderu
Napsal: 15 kvě 2023, 21:36
od chromnikl
Zdravím, řeším takový problém,
mám zařízení viz foto:
Jedná se o laserový efekt stavěný z toho, co bylo doma.
Pomocí encoderu chci sledovat polohu paprsku.
Zatím chci pouze čítat pulzy a po každém otočení - to jest 16 náběžných hran, je chci vynulovat.
Bohužel program nefunguje. i pokud je proměnná tik > 16 tak stále jede dále.
Představa je cca 2000 RPM - aby byl paprsek stabilní a neblikal. To je cca 530 impulzů za sekundu.
mezní frekvence je cca 10 kHz, takže tady by problém být neměl.
Nejsem si jistý kvalitou vstupního signálu, ale i kdyby to byly zákmity, tak by je to mělu nulovat správně.
Zde je blok kódu, který nefunguje.
Kód: Vybrat vše
int interruptPin = 2;
int tik = 0;
void setup()
{
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blik, FALLING);
Serial.begin(9600);
}
void blik()
{
tik ++;
Serial.println(tik);
return tik;
}
void loop()
{
if (tik > 16) {
tik = 0;
Serial.println(tik);}
}
Nějaký nápad
Napsal: 15 kvě 2023, 22:24
od Cowley
Ladíš program na správné (stejné) desce, jako je nastavena v IDE?
A co znamená: "Jede dále" ? Proč by neměl?
Vždyť nevoláš "DetachInterrupt"
Ještě zruš Serial.print uvnitř void blik().
Zaveď si proměnnou byte tisk=0;
Uvnitř void blik()
{ tik++; //pripocti
tisk=1; //nastav tisk
}
Do loop pak přidej
If (tisk ==1) //došlo ke změně
{Serial.println(tik); //vypiš kolik je tik
tisk=0; //jen jednou
}
If(tik >16) // víc jak 16?
{
tik = 0; //vynuluj
}
Napsal: 16 kvě 2023, 01:12
od samec
blik je void, nemá mať return tik.
tik má byť volatile.
Napsal: 16 kvě 2023, 05:32
od Mahoney
2chromnikl: Taky by chtělo vědět co je to za enkodér (foto nějak chybí), to máš nějaký optický s tvarovačem výstupních impulsů, nebo mechanický (když jsi vlákno nazval tak, jak jsi ho nazval…)?
A ještě drobný detail, když máš v interruptu komunikaci po serialu rychlostí 9600bd, tak ho určitě nevypíšeš 530x za vteřinu (s tím, co se pak ještě děje v pc), to z toho inrerruptu časově skoro nevylezeš … zvýšil bych té lince rychlost.
Napsal: 16 kvě 2023, 08:55
od chromnikl
Zdravím, nějak se mi nepovedlo vložit obrázky, zde jsou:
https://ctrlv.cz/JLc1 tady je foto encoderu.
Je to nějaký čínský modul, takže o tvarování nemůže být řeč.
Napsal: 16 kvě 2023, 09:15
od chromnikl
Tady je upravený kód.
Ve finále se to nebude odesílat po ser. lince, to je jen pro lazení.
Kód: Vybrat vše
const byte interruptPin = 2;
volatile int tik = 0;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blik, CHANGE);
Serial.begin(9600);
}
void blik(){
Serial.println(tik);
tik ++;
}
void loop() {
if (tik == 16){
Serial.println(tik);
tik = 0;
}
}
Napsal: 16 kvě 2023, 09:27
od Mahoney
Tohle ale není enkodér, to co jsi vytvořil je ekvivalent inkrementu. Dej odkaz na ten čínský modul, nějakou elektroniku tam vidím, nemůžeme říci jistě že tvarování impulsu tam není ošetřené. Jak jsi vlastně vydedukoval, že tě trápí zrovna zákmity? Osciloskopem?
To že máš sériovou linku jen pro ladění na věci nic nemění, jde o to že je potřeba si uvědomovat souvislosti a dělat věci pořádně (používat to správným způsobem). Přerušovací rutiny mají obecně být co nejkratší, a tvá tráví ~50 % celkového procesorového času na jednom jediném řádku (a přitom stačí jen zvýšit rychlost linky). A nebo jinak, v interruptu přeci vůbec nepotřebuješ dělat nějaký výpis, nech tam jenom
, jestli se to napočítá přeci vidíš v hlavní smyčce (a nebo si dej na nějaký pin ledku a ovládej ji místo té linky, pokud to chceš vidět).
Napsal: 16 kvě 2023, 09:52
od Celeron
Já bych do toho zatím přerušení netahal nožná ani nebude potřeba. Udělej si jednoduchej prográmek kterej čte signál z toho optickýho incrementu. A jen bych to co vstoupí do Arduina hned poslal na jinej port a kouknul na to osciloskopem jak na vstupním portu, tak na výstupním jestli tam jsou nějaký zákmity či ne. A zároveň tak můžeš vyzkoušet, kolik otáček to zvládne snímat.
U mechanickýho n-codéru s dvouma kontaktama se s tvarováním moc nemažou, dávají se pouze dvě keramiky 10N proti zemi. Když s ním něco ladím, i bez těch kondíků to krokuje správně. Ale používám knihovnu rotary.h. Moc jsem nezkoumal, jestli a jak tam mají zákmity ošetřený.
Napsal: 16 kvě 2023, 20:17
od bdn
@chromnikl
funkce Serial.print je "pomalá" ve srovnání s rychlostí 530 impulzů /s. Tvůj program ti nebude vypisovat správně proměnnou tik. A už vůbec nevolej Serial.print uvnitř přerušení !
Nevím co má program dělat, co má být výsledná hodnota?
Napsal: 16 kvě 2023, 20:30
od Mahoney
Zatím jenom zkouší napočítat těch 16 otvorů, co má na tom 3D printed kole, ale jelikož mu tam stejně chybí alespoň kontrolní otvor na celou otáčku + čidlo, nebo něco na těch rotujících zrcátkách, tak to stejně nebude mít jak zkontrolovat (teoreticky by mohl mít hallovu sondu na té desce motoru zespodu, ale nevím). To by ale nevadilo, mě by spíš zajímalo jak vydedukoval, že má na optickém čidle zákmity.
Napsal: 16 kvě 2023, 21:08
od chromnikl
Zdravím, závoru používám tuto:
https://www.gme.cz/v/1508304/modul-opti ... ry-s-lm393
Co se týče zákmitů, pokud ručně pootočím o jeden "krok", na seriovou linku mi to vypíše třeba 30 pulzů.
Program mám tady.
Kód: Vybrat vše
const byte interruptPin = 2;
const byte Led = 13;
volatile int tik = 0;
void setup() {
pinMode(interruptPin, INPUT_PULLUP);
pinMode(Led, OUTPUT);
attachInterrupt(digitalPinToInterrupt(interruptPin), blik, RISING);
Serial.begin(9600);
}
void blik(){
tik ++;
}
void loop() {
Serial.println(tik) ;
if (tik > 16){
tik = 0;
digitalWrite(Led,HIGH);
} else{digitalWrite(Led,LOW);}
}
Teď to pracuje tak jak chci - počítá to, ale pulzy nesedí, při jednom posunutí o jednu dírku, naskočí třeba 20 pulzů.
Co se týče hlídání pozice, vždy jednou za otáčku projde laser přes fotodiodu, z toho určuju začátek jednoho otočení.
Jak signál vytvarovat, aby nedocházelo k zákmitům? Změna řešení toho kola? Menší dírky?
Díky .
Napsal: 16 kvě 2023, 21:40
od Mahoney
Neříkej tomu zákmity, zákmity mohou mít jen mechanické kontakty (myslel jsem, že ti to dojde). Jsou to nejspíš odrazy, máš to kolo lesklé a otvory nejsou rovnoměrné, projeď je jehlovým pilníkem abys je zarovnal, a plochy těch kol polep něčím matným (nebo nastříkej matnou černou barvou ze spreje, ale aby ti chytla na plast, musíš předtím ještě použít primer na plasty). Další věc je, že když máš snímání optozávorou, tak i když je infračervená, musíš ji zastínit od okolního osvětlení, může reagovat na něco zvnějšku. Další věc je stínění vedení se signálem od závory, máš dole pod tím motor a ten má cívky a magnety (motor z CD/DVD ROM je oběžka, takže rotují magnety), obyčejný drát taky může něco pochytat, je to v podstatě anténa a ten Atmel vedle má na vstupech poměrně velký vstupní odpor, je to CMOS obvod, takže ti to klidně může sejmout taky.
Jinak podobné kolo lze koupit hotové přímo k té závoře:
https://www.ebay.de/itm//292360097717
Napsal: 16 kvě 2023, 21:42
od nixdorf
Ak dochádza k falošným odpalom, možno by to šlo spraviť i softwarovo, ale nebude to rýchle... Vyskúšaj nasledovné - toto čaká min. 1ms od odpalu. Ak to bude až príliš hluché a pomalé, zmeň tú tisícku na niečo menšie; ak to stačiť nebude, tak ju zvýš.
Kód počíta s tým, že je pin 2 prizemňovaný, skús ten inkrement zapojiť tak. Ak to nie je možné, nahraď INPUT_PULLUP na INPUT, FALLING na RISING a "== LOW" na "== HIGH".
Kód: Vybrat vše
const byte interruptPin = 2;
const byte Led = 13;
byte tick_count = 0;
volatile unsigned long us_tick = 0;
void setup()
{
pinMode(Led, OUTPUT);
digitalWrite(Led, LOW);
pinMode(interruptPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(interruptPin), blik, FALLING);
Serial.begin(9600);
}
void blik()
{
us_tick = micros();
}
void loop()
{
if (us_tick && (micros() - us_tick > 1000))
{
us_tick = 0;
if (digitalRead(interruptPin) == LOW)
{
tick_count++;
if (tick_count == 16)
{
digitalWrite(Led, HIGH);
}
else if (tick_count > 16)
{
tick_count = 1;
digitalWrite(Led, LOW);
}
Serial.println(tick_count);
}
}
}
//edit: bdn má pravdu, předsedo

Dik, opravené. Ano, micros pretečie každých ~71min
Napsal: 17 kvě 2023, 07:46
od bdn
@nixdorf
zajímavé minimalistické řešení, ale pozor na micros() je zde jedno nebezpečí:
1/ Pokud přijde přerušení blink() v době, kdy bude hodnota micros() blízko přetečnení např. N=(0xFFFFFFFF - 800);
2/ potom výraz (micros() > us_tick + 1000) bude okamžitě pravdivý, tj. ( N> (0xFFFFFFFF-800) + 1000), tj. (N>200);
Řešení: závorka "sčítání", by se měla nahradit "odečítáním"
// původně
(micros() > us_tick + 1000)
// nově
(micros()- us_tick > +1000)
Zdroj:
http://www.gammon.com.au/forum/?id=12127
Napsal: 17 kvě 2023, 09:47
od Mahoney
Slušně vychovanej člověk čekačky vůbec nepoužívá, a přerušovací rutiny píše v assembleru
(samozřejmě si dělám srandu, díky za tip

)