Zákmity na rotačním encoderu

Raspberry, Arduino, Mini-PC a další

Moderátor: Moderátoři

Zpráva
Autor
Uživatelský avatar
chromnikl
Příspěvky: 37
Registrován: 21 dub 2021, 02:00

Zákmity na rotačním encoderu

#1 Příspěvek 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

Uživatelský avatar
Cowley
Příspěvky: 3087
Registrován: 04 úno 2005, 01:00

#2 Příspěvek 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
}

Uživatelský avatar
samec
Příspěvky: 3692
Registrován: 19 pro 2017, 01:00

#3 Příspěvek od samec »

blik je void, nemá mať return tik.
tik má byť volatile.

Uživatelský avatar
Mahoney
Příspěvky: 347
Registrován: 26 říj 2019, 02:00

#4 Příspěvek 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.

Uživatelský avatar
chromnikl
Příspěvky: 37
Registrován: 21 dub 2021, 02:00

#5 Příspěvek 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č.

Uživatelský avatar
chromnikl
Příspěvky: 37
Registrován: 21 dub 2021, 02:00

#6 Příspěvek 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;
  } 
}
 

Uživatelský avatar
Mahoney
Příspěvky: 347
Registrován: 26 říj 2019, 02:00

#7 Příspěvek 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

Kód: Vybrat vše

tik++
, 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).
Naposledy upravil(a) Mahoney dne 16 kvě 2023, 09:52, celkem upraveno 1 x.

Uživatelský avatar
Celeron
Příspěvky: 16140
Registrován: 02 dub 2011, 02:00
Bydliště: Nový Bydžov

#8 Příspěvek 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ý.
Jirka

Proč mi nemůže všechno chodit hned ?!!

Uživatelský avatar
bdn
Příspěvky: 436
Registrován: 16 led 2020, 01:00

#9 Příspěvek 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?

Uživatelský avatar
Mahoney
Příspěvky: 347
Registrován: 26 říj 2019, 02:00

#10 Příspěvek 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.
Přílohy
cut.jpg

Uživatelský avatar
chromnikl
Příspěvky: 37
Registrován: 21 dub 2021, 02:00

#11 Příspěvek 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 .

Uživatelský avatar
Mahoney
Příspěvky: 347
Registrován: 26 říj 2019, 02:00

#12 Příspěvek 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
Naposledy upravil(a) Mahoney dne 16 kvě 2023, 21:51, celkem upraveno 2 x.

nixdorf
Příspěvky: 540
Registrován: 06 kvě 2017, 02:00

#13 Příspěvek 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 :D Dik, opravené. Ano, micros pretečie každých ~71min
Naposledy upravil(a) nixdorf dne 17 kvě 2023, 09:12, celkem upraveno 1 x.

Uživatelský avatar
bdn
Příspěvky: 436
Registrován: 16 led 2020, 01:00

#14 Příspěvek 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

Uživatelský avatar
Mahoney
Příspěvky: 347
Registrován: 26 říj 2019, 02:00

#15 Příspěvek od Mahoney »

Slušně vychovanej člověk čekačky vůbec nepoužívá, a přerušovací rutiny píše v assembleru :D

(samozřejmě si dělám srandu, díky za tip :) )

Odpovědět

Zpět na „Miniaturní počítače (Arduino, Raspberry a další)“