Search This Blog

Thursday, March 6, 2014

Reading Rotary Encoder Using Microcontroller

Rotary encoder တွေကို ထောင့်ဘယ်လောက်လှည့်သွားသလဲ (angular position) နဲ့ ဘယ်လောက်ဘီးလည်ပြီး ရွေ့သွားလဲ (motion sensing) ဆိုတာတွေကို တိုင်းတာဖို့ သုံးလေ့ရှိပါတယ်။ Optical rotary encoder တွေမှာ အပေါက်လေးတွေ ပုံဖော်ပြီး ဖောက်ထားတဲ့ အချပ်ကလေး ပါလေ့ရှိပြီး၊ အလင်းထုတ်ပေးတဲ့ LED နဲ့ အလင်းကို အာရုံခံနိုင်တဲ့ photo detector ကြားမှာ အဲဒီ အဝိုင်းလေး လည်တဲ့အခါ၊ အလင်းကျသွား၊ အလင်းကွယ်သွားတဲ့ ပေါ်မူတည်ပြီး ဗို့အား အနိမ့်အမြင့် digital waveform တွေထွက်လာပါတယ်။


VEX Robotics Design System ကထုတ်လုပ်တဲ့ optical encoder တခု

Encoder တွေမှာ glitch တွေ မဖြစ်အောင် ပုံမှန် binary code အစား Gray code ကို သုံးလေ့ပါတယ်။ Gray code မှာ ကပ်ရပ်နံပါတ် တစ်ခုနဲ့ တစ်ခု အကြား ပြောင်းလဲတဲ့ bit အရေအတွက်က တစ်ခု ထက် မပိုတဲ့အတွက် glitch တွေ ဖြစ်မယ့် ပြဿနာကနေ ကာကွယ်ပေးပါတယ်။ Gray code 0 ကနေ 3 အထိကို အောက်က ဇယားမှာ ပြထားပါတယ်။

Gray code
Number 2-bit Gray Code
0 00
1 01
2 11
3 10


Encoder အများစုမှာ A နဲ့ B လို့ ခေါ်တဲ့ output နှစ်ခု ပါလေ့ရှိပြီး၊ သူ့ကို clockwise လှည့်လိုက်ရင် အောက်က waveform မှာ ပြထားတဲ့ အတိုင်း phase အစီအစဉ်အလိုက် 0, 1, 2, 3 ဆိုပြီး၊ 3 ပြီးတဲ့ အခါ 0 ကနေ ပြန်စထွက်လာပါမယ်။ counter-clockwise လှည့်ရင်တော့ 3, 2, 1, 0, .... ဆိုပြီး အစီအစဉ် ပြောင်းပြန်ထွက်လာပါမယ်။



Encoder ကို microcontroller ကနေ ဖတ်ဖို့ အတွက် နမူနာ ပရိုဂရမ် တွေ အင်တာနက်ပေါ်မှာ ရှိပေမယ့် တွေ့တဲ့ဟာတွေ က ရှည်ပြီး၊ ထိရောက်မှု မရှိဘူးထင်လို့ မကြိုက်ပါဘူး။ Low end microcontroller လေးတွေ အတွက်ပါ အဆင်ပြေမယ့်၊ တိုတောင်းရှင်းလင်း လွယ်ကူ ပြီး တွက်ချက်မှု အနည်းဆုံးနဲ့ အမြန်ဆုံး ဖြစ်မယ်ထင်တဲ့ ကုဒ်ကို ရေးကြည့်ထားပါတယ်။ Encoder ရဲ့ resolution (pulses per revolution) ကို လေးဆ ပိုရစေနိုင်တဲ့ နည်းကို သုံးပါမယ်။

State machine တွေကို design လုပ်တဲ့ နည်းကို သုံးပြီး encoder ကထွက်လာမယ့် 0, 1, 2, 3 စတဲ့ state တွေကို s0, s1, s2, s3 လို့ အသီးသီး နာမည်ပေးလိုက်ပါမယ်။ ဥပမာ အရင် state က s0 ဖြစ်ခဲ့ပြီး နောက်ထွက်လာတဲ့ state က s1 ဆိုရင် pulse အရေအတွက်ကို တစ်တိုး (count up) လိုက်ပါမယ်။ အရင် state က s3 ဖြစ်ခဲ့ပြီး နောက်ထွက်လာတဲ့ state က s2 ဆိုရင်တော့ pulse အရေအတွက်ကို တစ်လျော့ပြီး (count down) လိုက်မှာပါ။ ဖြစ်နိုင်တဲ့ လက်ရှိ state နဲ့ နောက် state တွေအတွက် လုပ်ဆောင်ချက် တွေကို အောက်မှာ ဇယားနဲ့ ပြထားပါတယ်။

Counting encoder states
Next state Present state Count
s0 s0 No change
s0 s1 Down
s0 s3 Up
s0 s2 Don't care
s1 s0 Up
s1 s1 No change
s1 s3 Don't care
s1 s2 Down
s3 s0 Down
s3 s1 Don't care
s3 s3 No change
s3 s2 Up
s2 s0 Don't care
s2 s1 Up
s2 s3 Down
s2 s2 No change


State တွေနေရာ မှာ သတ်မှတ်ထားတဲ့ code တွေနဲ့ ပြန်အစားထိုးရင် အောက်က truth table ကို ရပါမယ်။

Truth table
Decimal number Next state - Present state Up Down
0 00 00 0 0
1 00 01 0 1
2 00 10 1 0
3 00 11 0 0
4 01 00 1 0
5 01 01 0 0
6 01 10 0 0
7 01 11 0 1
8 10 00 0 1
9 10 01 0 0
10 10 10 0 0
11 10 11 1 0
12 11 00 0 0
13 11 01 1 0
14 11 10 0 1
15 11 11 0 0


ဇယားကနေပြီး next state နဲ့ present state တွေကို တဆက်ထဲ တွဲစပ်ပြီး binary code အနေနဲ့ စဉ်းစားရင် v တန်ဖိုး နံပါတ် ၂၊ ၄၊ ၁၁ နဲ့ ၁၃ မှာ count up လုပ်ပြီး၊ နံပါတ် ၁၊ ၇၊ ၈၊ ၁၄ မှာ count down လုပ်ဖို့ လိုတာကို တွေ့ရပါမယ်။ အဲဒီ truth table ကို array တစ်ခု နဲ့ အောက်ကအတိုင်း ကိုယ်စားပြု လို့ ရပါတယ်။
 int En_TruthTable[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

နမူနာ အနေနဲ့ Arduino UNO single board microcontroller နဲ့ optical shaft encoder (VEX Robotics Design System) တို့ကို သုံးပါတယ်။

ကျွန်တော်တို့ရဲ့ circuit မှာ pin 9 ကို encoder ရဲ့ channel A နဲ့ဆက်ပြီး pin 10 ကို channel B နဲ့ဆက်လိုက်ပါတယ်။ အဲဒီ channel A နဲ့ channel B ကဖတ်လို့ရတဲ့ binary bit တွေကနေ next state (NS) ရအောင် အောက်ပါအတိုင်း ပြောင်းလို့ရပါတယ်။
  NS = (digitalRead(pinA)<<1) | digitalRead(pinB);

Encoder လည်တဲ့အခါ ထွက်လာတဲ့ digital waveform တွေကို microcontroller က နေ စဉ်ဆက်မပြတ် စစ်နေရမှာ ဖြစ်ပြီး next state (NS) က present state (PS) နဲ့ မတူတော့ပဲ ပြောင်းသွားတာနဲ့ သူရဲ့လက်ရှိ နေရာကို သက်ဆိုင်တဲ့ တန်ဖိုးပြောင်းပေးဖို့ လိုပါတယ်။ Encoder ရဲ့ လက်ရှိနေရာကို ရှာဖို့ state ပြောင်းလဲတဲ့ အရေအတွက်ကို မှတ် ထားတဲ့ variable ကို c လို့ ခေါ်မယ်ဆိုရင်၊ သူ့ရဲ့ တန်ဖိုးက Encoder ကတစ်ပတ်တိတိ ပတ်ပြီး ပြီဆိုရင် အစဦးဆုံး count သုညကို ပြန်ရောက် သွားပါမယ်။ Encoder ရဲ့ pulses per revolution က PPR ဆိုရင် တစ်ပတ်စာ အတွက် state အရေအတွက် (state changes per revolution - SPR) က PPR ရဲ့ လေးဆ ( c = 4 . PPR ) ဖြစ်ပါတယ်။ c ကို အောက် ကအတိုင်း တွက်နိုင်ပါတယ်။
c=(c+En_TruthTable[(NS<<2)|PS]+SPR)%SPR;
c ရဲ့ သက်ဆိုင်ရာ ထောင့် (a) ကို ဒီဂရီ ( 0 ≤ a < 360 ) နဲ့အောက်ကအတိုင်း ရပါတယ်။
a =  c * 360.0  / SPR
ထောင့် b ( -180 ≤ a < 180 )ကို အပေါင်း၊အနုတ် ဒီဂရီ အနေနဲ့ ရချင်ရင်တော့ ထောင့် a ကနေ အောက်ပါအတိုင်း ပြောင်းနိုင်ပါတယ်။
b =  a - floor(a/180)*360.
Arduino ကိုသုံးထားတဲ့ နမူနာ ကုဒ်ကို Rotary Encoder to get absolute value (on GitHub) မှာရနိုင်ပါတယ်။ Arduino software (IDE) ကတော်တော်လွယ်ကူတာကို တွေ့ရပါတယ်။ ကျွန်တော့်တုန်းကတော့ board နဲ့ COM port ကို "Tools" menu ကနေရွေးပြီးတဲ့ အခါ ဘာမှ ပြဿနာမရှိပဲ အလုပ်လုပ်တာကို တွေ့ရပါတယ်။

No comments:

Post a Comment