Search This Blog

Thursday, May 5, 2011

Degrees of Freedom of the Human Arm

လူတွေရဲ့ လက်မှာ လှုပ်ရှားနိုင်တဲ့ ပုံစံ (degrees of freedom) ဘယ်နှစ်မျိုး ရှိလဲလို့ စဉ်းစား ဘူးပါသလား။ Saeed Benjamin Niku ရေးတဲ့ စာအုပ် တစ်အုပ် ဖြစ်တဲ့ Introduction to Robotics -Analysis, Control, Applications ထဲမှာ ဖတ်မိတဲ့ ဟာ တစ်ချို့ကို ပြန်ပြီး ထုတ်နုတ် တင်ပြ ချင်ပါတယ်။ လူ့ လက်မှာ ပခုံး၊ တံတောင်ဆစ် နဲ့ လက်ကောက်ဝတ် တွေက ကိုယ်၊ လက်မောင်း၊ လက်ဖျံ၊ လက်ဖဝါး တွေကို ဆက်ထား ပေးတဲ့ အဆက် နေရာတွေပါ။ ပခုံး က သုံးမျိုး လှုပ်နိုင်ပါတယ်။ coronal plane အတိုင်း အပေါ်အောက် လှုပ်လို့ရ သလို၊ transverse plane အတိုင်း ရှေ့နောက် လွှဲလို့ လဲရနိုင်ပြီး၊ လက်မောင်း ဝင်ရိုးမှာ လှည့်လို့ လည်း ရပါတယ်။ လူတွေရဲ့ ခန္ဓာဗေဒ ပြင်ညီ အခေါ်အဝေါ် ကို အောက်က Wikipedia က ပုံမှာ တွေ့နိုင်ပါတယ်။
တံတောင်ဆစ် ကတော့ အကွေး၊ အဆန့် တစ်မျိုးပဲ လှုပ်လို့ရတာပါ။ လက်ကောက်ဝတ် ကလဲ သုံးမျိုး လှုပ်နိုင်ပါတယ်။ အပေါ်အောက် လှုပ်တာ၊ ဘေးတိုက် လှုပ်တာ နဲ့ လက်ဖျံ တလျှောက် လှည့်တာ တွေ ဖြစ်ပါတယ်။ ဒါ့ကြောင့် လက်ချောင်းတွေကို ထည့်မစဉ်းစားဘူးဆိုရင် လူတွေရဲ့ လက်မှာ လှုပ်ရှားနိုင်တဲ့ ပုံစံ (degrees of freedom) ခုနှစ်မျိုး ရှိတယ်လို့ ပြောနိုင်ပါတယ်။

Tuesday, May 3, 2011

Byte Stuffing

ပစ္စည်း တစ်ခု ကနေ တစ်ခု data bytes တွေကို ပို့ဖို့ နဲ့၊ လက်ခံဖို့ အတွက် program တွေကို မကြာခဏ ရေးရပါတယ်။ ဒါနဲ့ပဲ ရိုးရှင်းတဲ့ byte stuffing မူကွဲ တစ်ခု ကို ရွေးပြီး data bytes တွေကို frame ဆောက် ပြီး ပို့ဖို့ နဲ့၊ လက်ခံဖို့ အတွက် လုပ်ရပါတယ်။ ပထမဆုံး အနေနဲ့ Frame ရဲ့ အစ နဲ့ အဆုံးကို သတ်မှတ်ဖို့ အတွက် control characters တွေ အနေနဲ့ 0x02 နဲ့ 0x03 ကို start of text (STX) ရယ်၊ end of text (ETX) ရယ် လို့ ထားလိုက် ပါမယ်။ လက်ခံရရှိတဲ့ ဒေတာ မှာ အမှား ပါမပါ စစ်ဖို့ အတွက် data bytes တွေရဲ့ exclusive-or တန်ဖိုးကို ETX နောက်မှာ အဆုံးသတ် checksum အနေနဲ့ ထည့်လိုက်ပါမယ်။ ပိုကောင်းတဲ့ error detection အတွက်တော့

CRC Calculation in VB and C

မှာဖော်ပြထားသလို CRC ကို သုံးလို့ ရပါတယ်။
ဥပမာ data byte နှစ်လုံး
0x30 0x31
ကို ပို့ဖို့ ဆိုရင်၊ ပို့ရမယ့် frame က
0x02 0x30 0x31 0x03 0x01
ဖြစ်ပါတယ်။ အစက 0x02 က STX အနေနဲ့ ထည့်ထားပြီး၊ data bytes တွေကို ပို့ပါမယ်။ ဘိတ်ရှေ့ က 0x03 က ETX အနေနဲ့ ထည့်ထားတာပါ။ data byte တွေရဲ့ exclusive-or (0x02^0x03) ဖြစ်တဲ့ 0x01 ကို checksum အနေနဲ့ နောက်ဆုံးက နေ ထည့်ထားတာပါ။ အကယ်၍ ပို့ရမယ့် ဒေတာမှာ control characters တွေ အနေနဲ့ သုံးထားတဲ့ 0x02 တို့၊ 0x03 တို့ ပါလာရင် ဘယ်လို လုပ်မလဲ လို့ မေးစရာရှိ ပါတယ်။ အဲဒီ အတွက် နောက်ထပ် control character 0x10 ကို Data Link Escape (DLE) အနေနဲ့ သတ်မှတ်ဖို့ လိုပါတယ်။ နောက်ထပ် ဥပမာ အနေနဲ့ data byte ငါးလုံး ဖြစ်တဲ့
0x30 0x02 0x65 0x10 0x03
အတွက် frame တစ်ခု ဆောက်ကြည့် ပါမယ်။ ဒေတာထဲမှာ STX တို့၊ ETX တို့၊ DLE တို့ ကိုတွေ့တိုင်း control character မဟုတ်ကြောင်း သိအောင် ရှေ့မှာ DLE တစ်လုံးကို အပို ထည့်ပေး မှာပါ။ ဒါဆို ပို့ရမယ့် frame က
0x02 0x30 0x10 0x02 0x65 0x10 0x10 0x10 0x03 0x03 0x44
ဖြစ်ပါတယ်။ C တို့၊ LabVIEW တို့ နဲ့ ပရိုဂရမ် တချို့ ရေးကြည့်ထားပါတယ်။ Example programs တွေကို အောက်က link မှာ တွေ့နိုင်ပါတယ်။

Byte Stuffing on GitHub


အောက်ကဟာက ပို့ဖို့ အတွက် frame ဆောက်တဲ့ C++ code ဖြစ်ပါတယ်။
// Byte stuffing- sending and receiving frames
// Author: Yan Naing Aye

#ifndef  FRAME_H
#define FRAME_H

#include 
#define STX 0x02
#define ETX 0x03
#define DLE 0x10

#define TX_BUF_SIZE 128
#define RX_BUF_SIZE 128
enum RX_STATE { IGNORE,RECEIVING,ESCAPE,RXCRC1,RXCRC2 };
//-----------------------------------------------------------------------------
class Frame {    
    RX_STATE rState;
protected:
    int TxN;//number of transmitting bytes
    int RxN;//number of receiving bytes
    char tb[TX_BUF_SIZE];//transmit buffer
    char rb[RX_BUF_SIZE];//receiving data
public:
    Frame();
    int setTxFrame(char* d,int n);
    unsigned int CRC16CCITT_Calculate(char* s,unsigned char len,unsigned int crc);
    int getTxN();
    int getRxN();
    int receiveRxFrame(char c);//get receiving frame from received char
    char* getTxBuf();
    char* getRxBuf();
};
//-----------------------------------------------------------------------------
Frame::Frame():TxN(0),RxN(0),rState(IGNORE){}
//-----------------------------------------------------------------------------
char* Frame::getTxBuf(){
    return tb;
}
//-----------------------------------------------------------------------------
char* Frame::getRxBuf(){
    return rb;
}
//-----------------------------------------------------------------------------
//Prepare transmitting frame
int Frame::setTxFrame(char* d,int n)
{
    unsigned int txcrc=0xFFFF;//initialize crc
    char c;
    int i=0,j=0;
    tb[i++]=STX;//start of frame
    for(j=0;j < n;j++) {
        c=d[j];
        if((c==STX)||(c==ETX)||(c==DLE)) tb[i++]=(DLE);
        tb[i++]=c;
    }
    tb[i++]=(ETX);//end of frame

    txcrc=CRC16CCITT_Calculate(d,n,txcrc);//calculate crc
    tb[i++]=txcrc & 0xFF;
    tb[i++]=(txcrc >> 8) & 0xFF;
    TxN=i;
    return TxN;
}
//-----------------------------------------------------------------------------
//Inputs
//s : pointer to input char string
//len: string len (maximum 255)
//crc: initial CRC value

//Output
//Returns calculated CRC
unsigned int Frame::CRC16CCITT_Calculate(char* s,unsigned char len,unsigned int crc)
{
    //CRC Order: 16
    //CCITT(recommendation) : F(x)= x16 + x12 + x5 + 1
    //CRC Poly: 0x1021
    //Operational initial value:  0xFFFF
    //Final xor value: 0
    unsigned char i,j;
    for(i=0;i < len;i++,s++) {
        crc^=((unsigned int)(*s) & 0xFF) << 8;
        for(j=0;j<8;j++) {
            if(crc & 0x8000) crc=(crc << 1)^0x1021;
            else crc <<=1;
        }
    }
    return (crc & 0xFFFF);//truncate last 16 bit
}
//-----------------------------------------------------------------------------
//get number of transmitting bytes
int Frame::getTxN()
{
    return TxN;
}
//-----------------------------------------------------------------------------
//get number of transmitting bytes
int Frame::getRxN()
{
    return RxN;
}
//-----------------------------------------------------------------------------
//process receiving char
int Frame::receiveRxFrame(char c)
{
    static char b;
    unsigned int crc;
    unsigned int rxcrc=0xFFFF;//initialize CRC
    switch(rState){
        case IGNORE:
            if(c==STX) { rState=RECEIVING;RxN=0;}
            break;
        case RECEIVING:
            if(c==STX) { rState=RECEIVING;RxN=0;}
            else if(c==ETX){rState=RXCRC1;}
            else if(c==DLE){ rState=ESCAPE; }
            else { rb[RxN++]=c; }
            break;
        case ESCAPE:
            rb[RxN++]=c; rState=RECEIVING;
            break;
        case RXCRC1:
            b=c; rState=RXCRC2;
            break;
        case RXCRC2:
            rState=IGNORE;
            crc=( (int)c << 8 | ((int)b & 0xFF) ) & 0xFFFF;//get received crc
            rxcrc=CRC16CCITT_Calculate(rb,RxN,rxcrc);//calculate crc
            //printf("crc: %x  rxcrc:%x \n",crc,rxcrc);
            if(rxcrc==crc){return RxN;}//if crc is correct            
            else {RxN=0;}//discard the frame

            break;
    }
    return 0;
}

//-----------------------------------------------------------------------------

//#############################################################################

class Frame2:public Frame {
    char Dt[20];//transmitting data
public:
    Frame2();
    void printTxFrame();
    void printRxFrame();
    void printRxData();
    void setTxData(float x,float y,float z,float b,float t);
};
//-----------------------------------------------------------------------------
Frame2::Frame2():Frame(),Dt(""){}
//-----------------------------------------------------------------------------
//Print out frame content
void Frame2::printTxFrame()
{
    printf("Tx frame buffer: ");
    for(int j=0;j < TxN;j++) printf("%02X ",(unsigned char)tb[j]);
    printf("\n");
}
//-----------------------------------------------------------------------------
//Print out frame content
void Frame2::printRxFrame()
{
    printf("Rx data buffer: ");
    for(int j=0;j < RxN;j++) printf("%02X ",(unsigned char)rb[j]);
    printf("\n");
}
//-----------------------------------------------------------------------------
//Set transmitting data
void Frame2::setTxData(float x,float y,float z,float b,float t)
{
    *(float*)(Dt)=x;
    *(float*)(Dt+4)=y;
    *(float*)(Dt+8)=z;
    *(float*)(Dt+12)=b;
    *(float*)(Dt+16)=t;
    Frame::setTxFrame(Dt,20);
}
//-----------------------------------------------------------------------------
//Print out received data
void Frame2::printRxData()
{
    float x,y,z,b,t;
    x=*(float*)(Dt);
    y=*(float*)(Dt+4);
    z=*(float*)(Dt+8);
    b=*(float*)(Dt+12);
    t=*(float*)(Dt+16);
    printf("Rx data: %f %f %f %f %f \n",x,y,z,b,t);
}
//-----------------------------------------------------------------------------

#endif // FRAME_H