Search

2013年12月24日 星期二

STM32 Toolchain Build For Mac OS X

  1.先裝xcode以及homebrew接著在terminal執行

brew install mpfr gmp libmpc texinfo libusb-compat libftdi wget automake libtool

2.編譯Toolchian

summon-arm-toolchain

3.編譯stlink tool

3-1.改.bashrc後source .bashrc

4.將STM32F4DISCOVERY與PC連接

5.執行st-util



6.執行arm-none-eabi-gdb並且連接

tar ext localhost:4242

7.下載examples

stm32f4-examples
or
STM32F4-workarea

8.隨便選一個project make

9.load elf

load YourPath/spi.elf


10.run


2013年12月21日 星期六

[memo] 仙人掌與多肉植物種植百科重點整理(未完)

  主要記錄最近讀多肉植物仙人掌種植活用百科這本書的重點,和一些網路上以及學校多肉社團吸收到的重點,目前接觸多肉約一個禮拜有誤請幫忙指正XD。

前言:

  多肉植物主要產於非洲、中亞、美洲,基本種類約三千種以上若含園藝雜交的就破萬以上。

  多肉植物葉子偏白或有白細毛以及刺葉可以減少吸熱以及紫外線,也可以禦寒或者凝聚水氣在順流到根部。

  仙人掌科原產於美洲大陸,種類約一千多種若含園藝雜交就超過五千種。

  仙人掌科的針刺是退化葉,除了減少水分蒸散也能保護自身,其它如:龍舌蘭屬的葉緣鋸齒、石頭玉(番杏科)則是用保護色。

  仙人掌有肉質莖,接著肉質莖突出一稜一稜的就是,稜上就有仙人掌的刺座,刺座等同於一般植物的,因此會長出刺、側芽子球、花苞,刺座下半部長刺上半部長花苞或是側芽子球。

  仙人掌的莖可分五大類,葉片形、長柱形、指形、團扇形、球形。
  葉片形:雨林生長,扁平狀,莖軟弱會長出氣根依附在其他東西上。
  長柱形:大型的仙人掌,可達數公尺之上,十幾公分大小還算是幼株離開花還要幾十年...。
  指形:約手指粗的柔軟細長莖,會隨著上長長度慢慢變成往地面成長,適合種植成吊盆。
  團扇形:莖為扁平或圓筒狀,刺座分佈在扁平莖上,除幾枝主刺還有細小的芒刺。
  球形:莖呈現球狀,稜呈縱向排列或者螺旋排列。

  仙人掌花為完全花(同時具備雄蕊與雌蕊),但大多還是要由異株授粉才會成功,開花前為了保護花苗會先在刺座長出綿毛,果實大多為漿果可以食用。

種植:

  多肉大約在十度到四十度左右都可種植,有些生長在岩縫或灌木叢比較不用太多日照,而理論上溫室栽培最好。

  澆水:


   每次澆水都要澆透(整盆土皆有水滲透到,且水從盆底流出),並且避免澆水澆到植物表面產生水漬甚至因此增加染病基層。

   夏季生長種:夏天一週一次,冬天兩週一次,澆水時機在清晨或者太陽快下山時,夏天澆水要等植物表面的水分乾了再關閉溫室這樣植物才不會因為水分升溫造成灼傷,冬季則要避免在夜晚澆水尤其寒流來這樣做更容易凍傷植物,如期間遇到颱風來襲則可延長一週半左右的時間再澆水。

冬季生長種:冬季時一到兩週給一次水即可,但夏季因為不是生長季不能給太多水而腐爛且又不能給太少水枯死,所以最好將植物放到陰涼通風的地方且避免雷陣雨還有颱風,澆水時可用噴霧或其他方法讓土壤表面保濕即可。

  介質:



  換盆:


   換盆


  繁殖:


   有性:



   無性:





害蟲與病害:




其他:





參考:

多肉植物仙人掌種植活用百科
台中教育大學仙人掌與多肉植物研究社
BATMAN的秘密花園

2013年12月19日 星期四

多肉植物是我看過最知性的植物了

又好久沒看這裡.......因為最近迷上多肉植物..................................而且還發現學校居然有這種社團...........所以現在都在研究園藝....對了我開始吃素...


2013年11月2日 星期六

換了吃飯的工具

  用了快四年的Thinkpad NB幫我完成了不少大大小小的案子,前陣子它開始出現怪毛病後就想來換NB,後來因為公司都用Apple的產品所以也有想換看看Mac的想法,然後趁這次MacBook Pro 13" Retina 2013改款就花五萬台票請人從香港帶一台回來用看看,目前用起來感覺不錯只是不太習慣而已,話說好久沒上來Blog看看了...。


2013年9月29日 星期日

ATmega328P-AU With UNO Bootloader

    最近想到拿ATmega328P-AU寫入Arduino UNO Bootloader來快速做個樣品給人看,結果今天Layout好了零件焊上完全無法用Arduino ISP的方式寫入Bootloader,一直朝更改Boards.txt與avrdude.conf的方向去走,結果弄了幾個小時想到把當作ISP的Digital 10直接接到ATmega328P-AU的Reset,不是走原本預留給Upload程式用的Auto Reset線路上有個104P電容,就可以寫入Bootloader了,不知道為什麼Digital 10多走一個104P電容就沒辦法,總之ATmega328P-AU寫入Arduino UNO Bootloader跟ATmega328P-PU一樣,接下來可以改作STM32F1的cost down版本。



=============2014/01/06===============


    如果發現Upload程式失敗可能是Upload的過程中被原先的程式佔用(?),可以Reset或者改接3.3v供電再試幾次就可以了。




=============2016/07/19===============
若在燒錄bootloader時發生錯誤可以在ArduinoISP board上的RESET與GND並聯一個10uF的電容。

2013年9月26日 星期四

三個月的近況...

  話說Blog荒廢三個月以上幾乎快忘記這邊的存在了,現在除了忙案子和開發公司的產品之外還有研究所要準備,以及大大小小的比賽和畢業專題...還是記錄一下這三個月在幹嘛好了

  大約在去年十二月左右強者我班上同學就想拉我去他開的公司(Doit 杜瓦行銷有限公司),不過一開始我因為案子很多還有我對當時想產品實在沒有興趣,所以我只有說等到有我有興趣的東西再去幫忙,五月左右聽到一個不錯的想法後就答應七月中處理完日檢還有帶女友回高雄老家玩後,就去桃園中壢公司住到開學全力開發產品雛形跟腦力激盪新產品,這兩個月都在弄指紋機、RFID和各種影像處理程式和奇怪的程式與公司內的Hackday XD。


  這兩個月其實很好玩,我覺得中壢生活比想像中的好,在我心中大約高雄 > 中壢 > 台中這樣吧,基本上能吃的都吃過了該去看的也都有,而且不知道為什麼總覺得中壢生態很好半夜都能聽到公司外的蟲叫,總之現在我們只是四人的新創公司,正在全力研發我們的新產品,因為人少的原因常常得一人Cover很多技術或公司內部等等的東西。


  開學到現在也要兩週了,都在忙比賽的文件和研究所甄試資料,這學期光比賽就被叫去參加四個以上,還有研究所推甄文件也要在十月五號前生出來才保險,畢業專題就等老師要看什麼就給什麼就好XD總之這學期真的很忙,還有女友、案子等等的事情...,雙手抓住太多東西真的怕什麼都會弄不好...XDZ

Arduino - RFID NXP MFRC522

  MFRC522是飛利浦的13.56Mhz的RFID Solution,悠遊卡或者高雄一卡通用的,本來想說要自己Layout洗板,不過因為沒熱風槍不知道怎麼黏MFRC522,總之只要按照Document由SPI傳操作暫存器跟指令就可以用了,Mifare One卡的Block 0前面4byte就是UID,第5byte是校驗和由UID的4byte依序XOR沒錯誤就會得到和第5byte相同的值,另外就是一開始很那悶為什麼得到的UID和iBon不同,原來要轉換成8H10D的格式,將Block 0前面4byte十六進位值反向然後直接視為一個4byte的十進位值就是8H10D了,例如得到:0x12 0x34 0x56 0x78 -> 8H10D:0x78563412 = 2018915346,如果不滿十位數就在開頭補零,最後在網路上看到很多Library不過都很亂所以我重寫整理一下和加入一個8H10D格式的example。


                 Arduino                     MFRC522
            Digital 10            ---->     SDA
            Digital 11(MOSI)  ----> MOSI(DI)
            Digital 12(MISO)  ----> MISO(DO)
            Digital 13(SCK) ----> SCLK(CK)
            Digital 5              ---->      RST
                VCC 3.3V  ---->      VCC
                    GND    ---->      GND

MFRC522.h

#ifndef __MFRC522__
#define __MFRC522__


#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

#include <SPI.h>

//data array maxium length
const unsigned int MAX_LEN = 16;

//MFRC522 command bits
const unsigned char PCD_IDLE = 0x00; //NO action; cancel current commands
const unsigned char PCD_AUTHENT = 0x0E; //verify password key
const unsigned char PCD_RECEIVE = 0x08; //receive data
const unsigned char PCD_TRANSMIT = 0x04; //send data
const unsigned char PCD_TRANSCEIVE = 0x0C; //send and receive data
const unsigned char PCD_RESETPHASE = 0x0F; //reset
const unsigned char PCD_CALCCRC = 0x03; //CRC check and caculation

//Mifare_One card command bits
const unsigned char PICC_REQIDL = 0x26; //Search the cards that not into sleep mode in the antenna area
const unsigned char PICC_REQALL = 0x52; //Search all the cards in the antenna area
const unsigned char PICC_ANTICOLL = 0x93; //prevent conflict
const unsigned char PICC_SElECTTAG = 0x93; //select card
const unsigned char PICC_AUTHENT1A = 0x60; //verify A password key
const unsigned char PICC_AUTHENT1B = 0x61; //verify B password key
const unsigned char PICC_READ = 0x30; //read
const unsigned char PICC_WRITE = 0xA0; //write
const unsigned char PICC_DECREMENT = 0xC0; //deduct value
const unsigned char PICC_INCREMENT = 0xC1; //charge up value
const unsigned char PICC_RESTORE = 0xC2; //Restore data into buffer
const unsigned char PICC_TRANSFER = 0xB0; //Save data into buffer
const unsigned char PICC_HALT = 0x50; //sleep mode


//THe mistake code that return when communicate with MFRC522
const unsigned char MI_OK = 0;
const unsigned char MI_NOTAGERR = 1;
const unsigned char MI_ERR = 2;


//------------------MFRC522 register ---------------
//Page 0:Command and Status
const unsigned char Reserved00 = 0x00;
const unsigned char CommandReg = 0x01;
const unsigned char CommIEnReg = 0x02;
const unsigned char DivlEnReg = 0x03;
const unsigned char CommIrqReg = 0x04;
const unsigned char DivIrqReg = 0x05;
const unsigned char ErrorReg = 0x06;
const unsigned char Status1Reg = 0x07;
const unsigned char Status2Reg = 0x08;
const unsigned char FIFODataReg = 0x09;
const unsigned char FIFOLevelReg = 0x0A;
const unsigned char WaterLevelReg = 0x0B;
const unsigned char ControlReg = 0x0C;
const unsigned char BitFramingReg = 0x0D;
const unsigned char CollReg = 0x0E;
const unsigned char Reserved01 = 0x0F;
//Page 1:Command
const unsigned char Reserved10 = 0x10;
const unsigned char ModeReg = 0x11;
const unsigned char TxModeReg = 0x12;
const unsigned char RxModeReg = 0x13;
const unsigned char TxControlReg = 0x14;
const unsigned char TxAutoReg = 0x15;
const unsigned char TxSelReg = 0x16;
const unsigned char RxSelReg = 0x17;
const unsigned char RxThresholdReg = 0x18;
const unsigned char DemodReg = 0x19;
const unsigned char Reserved11 = 0x1A;
const unsigned char Reserved12 = 0x1B;
const unsigned char MifareReg = 0x1C;
const unsigned char Reserved13 = 0x1D;
const unsigned char Reserved14 = 0x1E;
const unsigned char SerialSpeedReg = 0x1F;
//Page 2:CFG
const unsigned char Reserved20 = 0x20;
const unsigned char CRCResultRegM = 0x21;
const unsigned char CRCResultRegL = 0x22;
const unsigned char Reserved21 = 0x23;
const unsigned char ModWidthReg = 0x24;
const unsigned char Reserved22 = 0x25;
const unsigned char RFCfgReg = 0x26;
const unsigned char GsNReg = 0x27;
const unsigned char CWGsPReg = 0x28;
const unsigned char ModGsPReg = 0x29;
const unsigned char TModeReg = 0x2A;
const unsigned char TPrescalerReg = 0x2B;
const unsigned char TReloadRegH = 0x2C;
const unsigned char TReloadRegL = 0x2D;
const unsigned char TCounterValueRegH = 0x2E;
const unsigned char TCounterValueRegL = 0x2F;
//Page 3:TestRegister
const unsigned char Reserved30 = 0x30;
const unsigned char TestSel1Reg = 0x31;
const unsigned char TestSel2Reg = 0x32;
const unsigned char TestPinEnReg = 0x33;
const unsigned char TestPinValueReg = 0x34;
const unsigned char TestBusReg = 0x35;
const unsigned char AutoTestReg = 0x36;
const unsigned char VersionReg = 0x37;
const unsigned char AnalogTestReg = 0x38;
const unsigned char TestDAC1Reg = 0x39;
const unsigned char TestDAC2Reg = 0x3A;
const unsigned char TestADCReg = 0x3B;
const unsigned char Reserved31 = 0x3C;
const unsigned char Reserved32 = 0x3D;
const unsigned char Reserved33 = 0x3E;
const unsigned char Reserved34 = 0x3F;
//-----------------------------------------------

class MFRC522
{
public:
MFRC522();

void Write(const unsigned char,const unsigned char);
unsigned char Read(const unsigned char);
void SetBitMask(const unsigned char,const unsigned char);
void ClearBitMask(const unsigned char,const unsigned char);
void AntennaOn();
void AntennaOff();
void Reset();
void Init();

unsigned char MFRC522ToCard(const unsigned char,
const unsigned char*,
const unsigned char,
unsigned char*,
unsigned int*);
unsigned char WriteBlock(unsigned char,unsigned char*);
unsigned char Request(unsigned char,unsigned char*);
unsigned char Anticoll(unsigned char*);
void CalulateCRC(unsigned char*,unsigned char,unsigned char*);
unsigned char SelectTag(unsigned char*);
void Halt();
private:
const static int chip_select_pin = 10;
const static int NRSTPD = 5;
};

#endif

MFRC522.cpp

#include <MFRC522.h>

#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif

MFRC522::MFRC522()
{
pinMode(chip_select_pin,OUTPUT);
digitalWrite(chip_select_pin,LOW);

    pinMode(NRSTPD,OUTPUT);
digitalWrite(NRSTPD,HIGH);
}

void MFRC522::Write(const unsigned char address,const unsigned char value)
{
digitalWrite(chip_select_pin,LOW);
SPI.transfer((address << 1) & 0x7E);
    SPI.transfer(value);
digitalWrite(chip_select_pin,HIGH);
}

unsigned char MFRC522::Read(const unsigned char address)
{
unsigned char value;

digitalWrite(chip_select_pin,LOW);
    SPI.transfer(((address << 1) & 0x7E) | 0x80);
    value = SPI.transfer(0x00);
digitalWrite(chip_select_pin,HIGH);

return value;
}

void MFRC522::SetBitMask(const unsigned char reg,const unsigned char mask)
{
    unsigned char temp;
    temp = Read(reg);
    Write(reg,temp | mask);
}

void MFRC522::ClearBitMask(const unsigned char reg,const unsigned char mask)
{
    unsigned char temp;
    temp = Read(reg);
    Write(reg,temp & (~mask)); // clear bit mask
}

void MFRC522::AntennaOn()
{
    unsigned char temp;

    temp = Read(TxControlReg);
    if(!(temp & 0x03)){
SetBitMask(TxControlReg,0x03);
}
}

void MFRC522::AntennaOff()
{
ClearBitMask(TxControlReg,0x03);
}

void MFRC522::Reset()
{
Write(CommandReg,PCD_RESETPHASE);
}

void MFRC522::Init()
{
Reset();

    Write(TModeReg,0x8D);
    Write(TPrescalerReg,0x3E);
    Write(TReloadRegL,30);
    Write(TReloadRegH,0);
   
    Write(TxAutoReg,0x40);
    Write(ModeReg,0x3D);

AntennaOn();
}

unsigned char MFRC522::MFRC522ToCard(const unsigned char command,const unsigned char *send_data,const unsigned char send_len,unsigned char *back_data,unsigned int *back_len)
{
    unsigned char status = MI_ERR;
    unsigned char irqEn = 0x00;
    unsigned char waitIRq = 0x00;
    unsigned char lastBits;
    unsigned char n;
    unsigned int i;

    switch(command)
    {
        case PCD_AUTHENT: //verify card password
        {
            irqEn = 0x12;
            waitIRq = 0x10;
            break;
        }
        case PCD_TRANSCEIVE: //send data in the FIFO
        {
            irqEn = 0x77;
            waitIRq = 0x30;
            break;
        }
        default:
            break;
    }
 
    Write(CommIEnReg,irqEn | 0x80); //Allow interruption
    ClearBitMask(CommIrqReg,0x80); //Clear all the interrupt bits
    SetBitMask(FIFOLevelReg,0x80); //FlushBuffer=1, FIFO initilizate
   
    Write(CommandReg,PCD_IDLE); //NO action;cancel current command ???

    //write data into FIFO
    for (i = 0; i < send_len;++i){
        Write(FIFODataReg,send_data[i]);
    }

    //procceed it
    Write(CommandReg,command);
    if (command == PCD_TRANSCEIVE){
SetBitMask(BitFramingReg,0x80); //StartSend=1,transmission of data starts
    }
   
    //waite receive data is finished
    i = 2000; //i should adjust according the clock, the maxium the waiting time should be 25 ms???
    do {
        //CommIrqReg[7..0]
        //Set1 TxIRq RxIRq IdleIRq HiAlerIRq LoAlertIRq ErrIRq TimerIRq
        n = Read(CommIrqReg);
        --i;
    }

    while ((i != 0) && !(n & 0x01) && !(n & waitIRq));

    ClearBitMask(BitFramingReg,0x80); //StartSend=0
   
    if (i != 0){
if(!(Read(ErrorReg) & 0x1B)){ //BufferOvfl Collerr CRCErr ProtecolErr
            status = MI_OK;
            if(n & irqEn & 0x01){
                status = MI_NOTAGERR; //??
            }
           
            if(command == PCD_TRANSCEIVE){
                n = Read(FIFOLevelReg);
                lastBits = Read(ControlReg) & 0x07;
                if (lastBits){
                    *back_len = (n - 1) * 8 + lastBits;
                }
                else{
                    *back_len = n*8;
                }
               
                if(n == 0){
                    n = 1;
                }
                if (n > MAX_LEN){
                    n = MAX_LEN;
                }
               
                //read the data from FIFO
                for (i=0; i < n;++i){
                    back_data[i] = Read(FIFODataReg);
                }
            }
        }
        else{
            status = MI_ERR;
        }
       
    }
   
    //SetBitMask(ControlReg,0x80); //timer stops
    //Write(CommandReg, PCD_IDLE);

    return status;
}

unsigned char MFRC522::WriteBlock(unsigned char block_address,unsigned char  *write_data)
{
    unsigned char status;
    unsigned int recvBits;
    unsigned char i;
    unsigned char buff[18];
   
    buff[0] = PICC_WRITE;
    buff[1] = block_address;
    CalulateCRC(buff,2,&buff[2]);
    status = MFRC522ToCard(PCD_TRANSCEIVE,buff,4,buff,&recvBits);

    if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)){
        status = MI_ERR;
    }
       
    if (status == MI_OK){
for (i=0;i < 16;++i){ //Write 16 bytes data into FIFO
            buff[i] = *(write_data+i);
        }
        CalulateCRC(buff,16,&buff[16]);
        status = MFRC522ToCard(PCD_TRANSCEIVE,buff,18,buff,&recvBits);
       
        if ((status != MI_OK) || (recvBits != 4) || ((buff[0] & 0x0F) != 0x0A)){
            status = MI_ERR;
        }
    }
   
    return status;
}

unsigned char MFRC522::Request(unsigned char mode,unsigned char *tag_type)
{
    unsigned char status;
    unsigned int backBits; //the data bits that received

    Write(BitFramingReg,0x07); //TxLastBists = BitFramingReg[2..0] ???
   
    tag_type[0] = mode;
    status = MFRC522ToCard(PCD_TRANSCEIVE,tag_type,1,tag_type,&backBits);

    if ((status != MI_OK) || (backBits != 0x10)){
        status = MI_ERR;
    }
 
    return status;
}

unsigned char MFRC522::Anticoll(unsigned char *uid)
{
    unsigned char status;
    unsigned char i;
    unsigned char serNumCheck=0;
    unsigned int unLen;
   
    //ClearBitMask(Status2Reg, 0x08); //strSensclear
    //ClearBitMask(CollReg,0x80); //ValuesAfterColl
    Write(BitFramingReg,0x00); //TxLastBists = BitFramingReg[2..0]

    uid[0] = PICC_ANTICOLL;
    uid[1] = 0x20;
    status = MFRC522ToCard(PCD_TRANSCEIVE,uid,2,uid,&unLen);

    if (status == MI_OK){
        //Verify card UID
        for (i=0;i < 4;++i){
            serNumCheck ^= uid[i];
        }
        if (serNumCheck != uid[i]){
            status = MI_ERR;
        }
    }

    //SetBitMask(CollReg, 0x80); //ValuesAfterColl=1

    return status;
}

void MFRC522::CalulateCRC(unsigned char *input,unsigned char len,unsigned char *output)
{
    unsigned char i,n;

    ClearBitMask(DivIrqReg,0x04); //CRCIrq = 0
    SetBitMask(FIFOLevelReg,0x80); //Clear FIFO pointer
    //Write(CommandReg, PCD_IDLE);

    //Write data into FIFO
    for (i=0;i < len;i++){
        Write(FIFODataReg,*(input + i));
    }
    Write(CommandReg,PCD_CALCCRC);

    //waite CRC caculation to finish
    i = 0xFF;
    do {
        n = Read(DivIrqReg);
        --i;
    }
    while ((i != 0) && !(n & 0x04)); //CRCIrq = 1

    //read CRC caculation result
    output[0] = Read(CRCResultRegL);
    output[1] = Read(CRCResultRegM);
}

unsigned char MFRC522::SelectTag(unsigned char *uid)
{
unsigned char i;
unsigned char status;
unsigned char size;
unsigned int recvBits;
unsigned char buffer[9];

//ClearBitMask(Status2Reg, 0x08);                        //MFCrypto1On=0

buffer[0] = PICC_SElECTTAG;
buffer[1] = 0x70;

for (i=0; i<5; i++){
    buffer[i + 2] = *(uid + i);
}

  CalulateCRC(buffer,7,&buffer[7]);

  status = MFRC522ToCard(PCD_TRANSCEIVE,buffer,9,buffer,&recvBits);
  if ((status == MI_OK) && (recvBits == 0x18)){
    size = buffer[0];
  }
  else{
    size = 0;
  }

  return size;
}

void MFRC522::Halt()
{
    unsigned char status;
    unsigned int unLen;
    unsigned char buff[4];

    buff[0] = PICC_HALT;
    buff[1] = 0;
    CalulateCRC(buff,2,&buff[2]);

    status = MFRC522ToCard(PCD_TRANSCEIVE,buff,4,buff,&unLen);
}


8H10D.ino

#include <MFRC522.h>
#include <SPI.h>

/* 16^0 ~ 16^7 */
unsigned long table[8] = {1,16,256,4096,65536,1048576,16777216,268435456};

MFRC522 mfrc522;

unsigned char uid[5];

void setup()
{
  Serial.begin(9600);
  SPI.begin();
  mfrc522.Init();
}

void loop()
{
  unsigned char status;
  unsigned char str[MAX_LEN];

  status = mfrc522.Request(PICC_REQIDL,str);
  if (status != MI_OK){
    return;
  }

  status = mfrc522.Anticoll(str);
  if (status == MI_OK){
    memcpy(uid,str,5);
    mfrc522.SelectTag(uid); //防止同張卡片持續感應與讀取
 
    Serial.print("Original UID : ");
    unsigned long sum = 0; //將UID每位byte加總(4byte uid & 1byte check)
    for(int i = 3;i >= 0;--i){
      unsigned long temp_h = (uid[i] >> 4) & 0x0000000F;
      Serial.print(temp_h,HEX);
      sum += (temp_h * table[(i*2)+1]); //加上UID每byte的高4bit
      unsigned long temp_l = (uid[i] & 0x0000000F);
      Serial.print(temp_l,HEX);
      sum += (temp_l * table[i*2]); //加上UID每byte的低4bit
    }
    Serial.println("");
 
    Serial.print("8H10D UID : ");
    String _8H10D = String(sum);
    if(_8H10D.length() < 10){
      for(int i = 0;i < (10 - _8H10D.length());++i){
        Serial.print("0"); //8H10D格式未滿十碼開頭補零
      }
    }
    for(int i = 0;i < _8H10D.length();++i){
      Serial.print(_8H10D.charAt(i));
    }
  }
  Serial.println("");

  mfrc522.Halt();
  delay(100);
}

參考

MFRC522 Datasheet

2013年6月11日 星期二

好久沒接線了..

  最近其實都不知道在做什麼,只好來寫寫近況文,話說四月之後都在忙其他事情沒時間玩玩具,不過因為學校期末作業剛好作物聯網相關又去LAB借器材玩一下,但其實我本來就不太喜歡幹體力活,原本是要寫一個網路連線遊戲或者網路工具軟體等等跟網路相關的程式草草交差...(話說我也不太喜歡寫程式),但是老師說還是要有一個Device才能讓他高潮,所以只好用BeagleBone做個東西交差,但不知道為什麼借到的BeagleBone有點問題而其他的都被人借走只好改借WiFiBee(MRF24WB0MA & ATmega328),這個東西的設計我不是很喜歡,他的pin硬是要用比2.54英吋小的而且參考電壓用3.3v感覺不太方便,總之最後還是想了一個應該要跟綠能、智慧、雲端、嵌入式等等很潮的名詞相關的題目好交差作業,不然出席率幾乎零的我應該是會被大刀砍死,因此最後就做大家作到爛掉的智慧住宅,所以今天只好出席一下用三節課的時間和隊友接接線路寫個WebUI跟一個撈Sensor資料的程式把資料Push到DB讓WebUI可以觀察變化,意思意思一下看起來就可以交差了,另外暑假會北上去同學工作室做自己的產品,不過我要負責影像處理的部份看來又要開始讀Paper了,話說最近其實工作、約會各佔45%,剩下10%就是日常,但想到一個多月沒讀教材七月日檢好像真的有點危險XD






2013年6月9日 星期日

Arduino - PIR Sensor(ZEPIR0AAS01SBCG )

  學校作業做物聯網相關,所以就借一大堆Sensor來玩,人體紅外線跟一般三隻腳的不同,借到的ZEPIR0AAS01SBCG有很多隻腳,可以選擇兩個Mode,一個是跟三隻腳的用法一樣,另一個是Serial的方式,可以看下面參考的Datasheet。

VCC         --->         3.3V
GND         --->         GND
MD/RST   --->         GPIO
LG            --->         3.3V


const int PIR_PIN = 5;

void setup()
{
  Serial.begin(9600);
  pinMode(PIR_PIN,INPUT);
}

void loop()
{
  boolean pir = digitalRead(PIR_PIN);

  Serial.println(pir);

  delay(10);
}

參考:

2013年5月18日 星期六

原來我也是正常人(●′ω`●)

  先說四月中之後都在忙學校考試還有工作,本來預計月底事情都結束後要開始來研究MonoSLAM與Inverse Kinematics,不過到了五月後整個人五月病發作...,可以一整個禮拜天天都上論壇或者玩玩SNS跟PTT什麼正事都沒做到,但最重要的原因是因為一直在想某個女生...,想到已經嚴重影響到我的工作效率了,例如常常在coding時她就會突然在腦中冒出來...。

  但其實我很久以前就一直有在注意她,只是實在不知道為什麼四月中之後可以想她想到這樣誇張...,在這之前就有向她的好朋友們而且是我覺得可以信任的人問過她的事了,所以我有比較積極一點的接觸她找她聊天之類的,我以前很少跟她講話的原因是因為我會有點害羞XDZ...,不過向來我是有問題一定要解決的人,既然這事已經會影響到我的工作效率,所以上週我把她約出來看展之後就直接告訴她我的想法,雖然身邊朋友都說我主動接近她的時間根本還不到一個月似乎有點太操之過急,但我認為拖拖拉拉的有違我的原則,而且對於這種有想法的女生用暗示的實在是有點污辱她,可是同時我也想到現在都是我一個人自以為的想法,因此我當天還是選擇希望可以慢慢來且也不用馬上給我答覆的說法,兩天後的晚上她就把我抓出來並且直接給我願意慢慢來的答案了,不過她緊張時搖頭晃腦的模樣真的好可愛 :$

  她是一個很有想法跟主見的女生,要就要不要就拒絕不會為了迎合別人而答應自己不喜歡的事,還有她也不像我見過的一些女生花太多時間在外表上,例如我看過有人的女友光擦一個防曬乳都可以拖個30分鐘還不包含化妝之類的...,但她還是會維持該有的儀容這樣更顯得優雅,最重要的是我覺得她跟我一樣專注在自己的研究或者興趣,光這點我就知道錯過她就太可惜了,因為這樣的人我雖然認識很多但是分散後事實上一堆人裡面還不見得有一個,更何況是這麼特別的她。

  這週開始我們的交往後,我們先互相溝通好一些事情,例如我有問過她的好友請她吃飯她是否會在意之類的,因為對她這種有原則的女生來說不太喜歡平白受人好處是可以理解的,但我還是跟她談了如果特殊日子或者我結案請她吃個好料之類的就不要太過介意了,而她也跟我約定不可以互相生對方的氣,有不滿就要直接說出來!(我就是喜歡這點)等等的一些約定,也許是我跟他都是同類人而且都是理工科系相關,所以我們才能這麼理性的談這些問題,我對她的熱情每天都在增加,雖然她說怕我以後對她沒有像現在這麼熱情的話她心情一定會很不好 :$,總之說出心底話也有好結果後我的戰鬥力最近開始要恢復到以前的水平了 :P。

  話說我把這邊遺忘了一個多月了............XDZ

2013年4月13日 星期六

STM32F10xC DIY

  今天趁有空稍微確認了幾點,首先是電源電路用3.3v並聯三個0.1u陶瓷電容與一個1u無極性電解電容,接著reset電路可以參考這裡,然後8 or 12MHz Crystal配上22p陶瓷電容(PD0 OSC_IN、PD1 OSC_OUT),32.768KHz Crtstal配10p陶瓷電容(PC14-OSC32_IN、PC15-OSC32_OUT),VBAT與所有VDD都接3.3v然後所有VSS都接地,最後將USB to Serial的RX&TX接到STM32F10xC(我在STM32F100C8T6B測試)的PA9&PA10。

Reset Circuit



  接著toolchain因為自己DIY沒有STLINK所以必須用UART的方式去將binary upload到flash,在windows下可以用Keil ARM編譯code接著就可以用MCUISP將binary upload,而linux可以找ARM-Toolchain編譯code然後用stm32flash將binary upload,要注意的是upload前要先將BOOT 0接上3.3v然後最好再按下reset(因為像是MCUISP上一次燒錄完程式會自動reset但stm32flash不會),接著再將BOOT 0 接地並且按下reset按鈕就可以運作了。



  話說先畫成轉接板接到breadboard再搭電路對我來說比較保險,而且我不太會焊電子零件這樣小小一個我也要弄30分鐘(看以前學電子的學長不用一下就好了)...下次有空應該可以Layout出完整的版子了:Q

2013年4月7日 星期日

No.100 キタ━━━━━━(゚∀゚)━━━━━━!

  這篇是第一百篇!當初寫這blog最主要目的還是記錄電子DIY相關而且中文資料少的,不過後來看wxWidgets在台灣用的人不多(我只知道有某公司作的Game Tools用它寫UI)我這幾年寫的案子UI也都用它(三年前都用MFC到是Qt沒用來作案子過),不過其實API沒啥好寫的直接看DOCUMENT即可但是各種Library跟wxWidgets如何整合有的資料也很少所以我也寫,至於我主要研究的領域以後可能再開另一個blog紀錄,未來這裡文章方向大概也是這樣都寫比較輕鬆好玩打發時間的。

  話說最近買了STM32F407來玩,功能非常強大而且很便宜(戰略產品),雖然這兩三年免費幫人改寫過各種MCU Proto當額外Service,但是STM32比較特別的一點大概就是很少看到商業入門就是直接用Library,跟其它常見MCU一開始入門都是ASM也直接控制暫存器等等反而讓我很不習慣XD,而且看很多電子電機R&D大多也都自己搭MCU開發板,不過STM32的LQFP封裝對我來說實在太小腳距不太好弄而且板子也洗不好,弄一個48 pin的STM32F10xC轉板良率才20% XDD(下圖上方那塊),等在麵包板搭完測試後再Layout一個完整版,未來有時間大概都玩STM32(我覺得功能蠻棒的),還有研究寫RTOS等等...


基本運作作電路

看起來基本電路是正確(?)的可以Upload Program


突然發現STM32F10xC轉版沒焊好有的腳輸出不到...



2013年4月1日 星期一

wxKinect - Hand Detect

  前幾天看到一個日本人寫的這篇檢測手的方法,流程:Frame轉成HSV(因為要檢測顏色) =>  濾波(去除雜訊) => 將膚色作為閾值做二值化 => 接著就是標準的找輪廓(Find Contours)、找尋凸包(Convex Hull)、找尋凸缺陷(Convexity Defects),就可以找到手的幾個辨識關鍵,實作這個方法後感覺還可以但是就沒有發揮到Kinect的功能,不過昨天在GitHub看到這篇,有個我覺得很高明的地方也利用到Kinect的特點,就是直接把手的深度範圍當作閾值獨立出手的部分算是蠻準的,其餘的處理就都是一樣了,玩Kinect一個禮拜感覺上可以發揮的點很多。





wxKinect.h


#ifndef __WX_KINECT__
#define  __WX_KINECT__

#if _MSC_VER < 1600
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
#else
#include <stdint.h>
#endif

#include <wx/wx.h>

#include <cv.h>
#include <highgui.h>

#include <NiTE.h>

const int SCREEN_WIDTH = 640;
const int SCREEN_HIGHT = 480;
/*
const int ROI_MAX_SIZE_X = 540;
const int ROI_MAX_SIZE_Y = 380;
*/
const float DEPTH_SACLE = 255.0f / 4096.0f;
const int HAND_ROI_SIZE = 100;

const int LIKELY_THE_HAND_AREA = 2000;
const float HAND_IS_GRASPING = 0.8f;

const int DEPTH_RANGE = 7;

class App:public wxApp
{
public:
bool OnInit();
};

class Frame:public wxFrame
{
public:
Frame(const wxString&);
~Frame();

void InitKinect();
void CreateUI();
void Display();

void OnExit(wxCommandEvent&);
private:
friend class Thread;
Thread *thread;

nite::HandTracker hand_tracker;
nite::HandTrackerFrameRef hand_tracker_frame;

wxPanel *depth_screen;
wxPanel *hand_screen;

DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(Frame,wxFrame)
EVT_MENU(wxID_EXIT,Frame::OnExit)
END_EVENT_TABLE()

class Thread:public wxThread
{
public:
Thread(Frame*);

void* Entry();
private:
Frame *frame;
};

#endif



wxKinect.cpp


#include "wxKinect.h"

DECLARE_APP(App)
IMPLEMENT_APP(App)

bool App::OnInit()
{
Frame *frame = new Frame(wxT("wxKinect - Hand Detect"));

frame->Show(true);

return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(700,800),wxMINIMIZE_BOX | wxCLOSE_BOX | wxCAPTION | wxSYSTEM_MENU)
{
InitKinect();
CreateUI();

thread = new Thread(this);
thread->Create();
thread->Run();
}

void Frame::CreateUI()
{
wxMenu *file = new wxMenu;
file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("exit"));

wxMenuBar *bar = new wxMenuBar;
bar->Append(file,wxT("file"));
SetMenuBar(bar);

wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
this->SetSizer(top);

wxBoxSizer *screen_box = new wxBoxSizer(wxVERTICAL);
top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

depth_screen = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(SCREEN_WIDTH,SCREEN_HIGHT));
screen_box->Add(depth_screen,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

hand_screen = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(HAND_ROI_SIZE * 2,HAND_ROI_SIZE * 2));
screen_box->Add(hand_screen,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

CreateStatusBar(2);
SetStatusText(wxDateTime::Now().Format());
}

void Frame::InitKinect()
{
nite::NiTE::initialize();

hand_tracker.create();
hand_tracker.startGestureDetection(nite::GESTURE_CLICK);
hand_tracker.startGestureDetection(nite::GESTURE_WAVE);
hand_tracker.startGestureDetection(nite::GESTURE_HAND_RAISE);
}

Frame::~Frame()
{
thread->Delete();

//hand_tracker.destroy();
nite::NiTE::shutdown();
}

void Frame::Display()
{
hand_tracker.readFrame(&hand_tracker_frame);

cv::Mat depth_mat(hand_tracker_frame.getDepthFrame().getHeight(),hand_tracker_frame.getDepthFrame().getWidth(),CV_16UC1,(void*)hand_tracker_frame.getDepthFrame().getData());
depth_mat.convertTo(depth_mat,CV_8UC1,DEPTH_SACLE);

const nite::Array<nite::GestureData> &gestures = hand_tracker_frame.getGestures();
CvPoint2D32f position;

for(int i = 0;i < gestures.getSize();++i){

if(gestures[i].isComplete()){

const nite::Point3f &pos = gestures[i].getCurrentPosition();
nite::HandId hand_id;
hand_tracker.startHandTracking(pos,&hand_id);
}
}

const nite::Array<nite::HandData> &hands = hand_tracker_frame.getHands();

for(int i = 0;i < hands.getSize();++i){

const nite::HandData hand = hands[i];

if(hand.isTracking()){ //如果跟蹤到手的運動

const nite::Point3f &pos = hand.getPosition();
hand_tracker.convertHandCoordinatesToDepth(pos.x,pos.y,pos.z,&position.x,&position.y);
float hand_depth = pos.z * DEPTH_SACLE;

/*
* 將ROI設定在手的大小左右,
* 而且ROI範圍不可以超出擷取的影像否則會丟出Exception。
*/
cv::Rect hand_roi;
hand_roi.width = HAND_ROI_SIZE * 2;
hand_roi.height = HAND_ROI_SIZE * 2;
hand_roi.x = position.x - HAND_ROI_SIZE;
hand_roi.y = position.y - HAND_ROI_SIZE;
int ROI_MAX_SIZE_X = SCREEN_WIDTH - (HAND_ROI_SIZE * 2);
int ROI_MAX_SIZE_Y = SCREEN_HIGHT - (HAND_ROI_SIZE * 2);
if(hand_roi.x < 0){hand_roi.x = 0;}
if(hand_roi.x > ROI_MAX_SIZE_X){hand_roi.x = ROI_MAX_SIZE_X;}
if(hand_roi.y < 0){hand_roi.y = 0;}
if(hand_roi.y > ROI_MAX_SIZE_Y){hand_roi.y = ROI_MAX_SIZE_Y;}

cv::Mat hand_roi_mat(cv::Mat(depth_mat,hand_roi).clone());
hand_roi_mat = (hand_roi_mat > (hand_depth - DEPTH_RANGE)) & (hand_roi_mat < (hand_depth + DEPTH_RANGE)); //這裡是關鍵,二值化的閾值取決於手的深度範圍。

cv::medianBlur(hand_roi_mat,hand_roi_mat,5); //做中值濾波使邊緣明顯
cv::Mat hand_roi_debug;
hand_roi_debug = hand_roi_mat.clone();
cvtColor(hand_roi_debug,hand_roi_debug,CV_GRAY2RGB);

std::vector<std::vector<cv::Point> > contours;
cv::findContours(hand_roi_mat,contours,CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE); //找尋所有可能的多邊形邊緣

if(contours.size()){ //如果有找到

for (int i = 0;i < contours.size();i++){ //則迭代每個多邊形邊緣

std::vector<cv::Point> contour = contours[i];
cv::Mat contour_mat = cv::Mat(contour);
double contour_area = cv::contourArea(contour_mat); //計算該多邊形面積

if(contour_area > LIKELY_THE_HAND_AREA){ //如果大於這個值則可能是手的面積

cv::Scalar center = mean(contour_mat);
cv::Point center_point = cv::Point(center.val[0],center.val[1]);

std::vector<cv::Point> approx_curve;
cv::approxPolyDP(contour_mat,approx_curve,10,true); //逼近該多邊形的邊緣

std::vector<std::vector<cv::Point> > contour_vector;
contour_vector.push_back(approx_curve);
cv::drawContours(hand_roi_debug,contour_vector,0,CV_RGB(255,0,0),3); //畫出該多邊形的邊緣

/*
* 找尋凸包(Convex Hull)並畫出點。
*/
std::vector<int> hull;
cv::convexHull(cv::Mat(approx_curve),hull,false,false);
for(int j = 0;j < hull.size();j++){
int index = hull[j];
cv::circle(hand_roi_debug,approx_curve[index],3,CV_RGB(0,255,0),2);
}

/*
* 找尋凸缺陷(Convexity Defects)並畫出點。
*/
std::vector<CvConvexityDefect> convex_defects;
CvSeq* contour_points;
CvSeq* defects;
CvMemStorage* storage;
CvMemStorage* str_defects;
CvMemStorage* contour_str;
CvConvexityDefect *defect_array = 0;
str_defects = cvCreateMemStorage();
defects = cvCreateSeq(CV_SEQ_KIND_GENERIC|CV_32SC2, sizeof(CvSeq),sizeof(CvPoint),str_defects);
contour_str = cvCreateMemStorage();
contour_points = cvCreateSeq(CV_SEQ_KIND_GENERIC | CV_32SC2,sizeof(CvSeq),sizeof(CvPoint),contour_str);
for(int j = 0; j < (int)approx_curve.size(); j++) {
CvPoint cp = {approx_curve[j].x,approx_curve[j].y};
cvSeqPush(contour_points, &cp);
}
int count = (int)hull.size();
int *convert_hull = (int*)malloc(count * sizeof(int));
for(int j = 0;j < count;j++){
convert_hull[j] = hull.at(j);
}
CvMat hull_mat = cvMat(1,count,CV_32SC1,convert_hull);
storage = cvCreateMemStorage(0);
defects = cvConvexityDefects(contour_points, &hull_mat,storage);
defect_array = (CvConvexityDefect*)malloc(sizeof(CvConvexityDefect)*defects->total);
cvCvtSeqToArray(defects,defect_array,CV_WHOLE_SEQ);
for(int j = 0;j < defects->total;j++){
CvConvexityDefect def;
def.start       = defect_array[j].start;
def.end         = defect_array[j].end;
def.depth_point = defect_array[j].depth_point;
def.depth       = defect_array[j].depth;
convex_defects.push_back(def);
}
for(int j = 0;j < convex_defects.size();j++){
cv::circle(hand_roi_debug,cv::Point(convex_defects[j].depth_point->x,convex_defects[j].depth_point->y),3,CV_RGB(0,0,255),2);
}
cvReleaseMemStorage(&contour_str);
cvReleaseMemStorage(&str_defects);
cvReleaseMemStorage(&storage);
free(defect_array);

/*
* 這裡也算關鍵,直接把逼近的面積除以凸包的面積得到的值來決定手是張開還是合閉。
*/
std::vector<cv::Point> hull_points;
for(int j = 0;j < hull.size();j++){
int curve_index = hull[j];
cv::Point p = approx_curve[curve_index];
hull_points.push_back(p);
}
double hull_area  = cv::contourArea(cv::Mat(hull_points));
double curve_area = cv::contourArea(cv::Mat(approx_curve));
double hand_ratio = curve_area / hull_area;
if(hand_ratio > HAND_IS_GRASPING){
cv::circle(hand_roi_debug,center_point,5,CV_RGB(255,0,255),5); //張手就在手中心畫出淺綠的點
}
else{
cv::circle(hand_roi_debug,center_point,5,CV_RGB(100,220,80),5); //閉手就在手中心畫出粉紅的點
}

IplImage hand_image(hand_roi_debug);
wxClientDC hand_dc(hand_screen);
cvConvertImage(&hand_image,&hand_image,CV_CVTIMG_SWAP_RB);
unsigned char *data;
cvGetRawData(&hand_image,&data);
wxImage *image = new wxImage(hand_image.width,hand_image.height,data,true);
wxBitmap *bitmap = new wxBitmap(*image);
int x,y,width,height;
hand_dc.GetClippingBox(&x,&y,&width,&height);
hand_dc.DrawBitmap(*bitmap,x,y);
delete image;
delete bitmap;
}
}
}
//imwrite("hand.jpg",hand_roi_image);
}
}

IplImage depth_image(depth_mat);
IplImage *convert_image = cvCreateImage(cvGetSize(&depth_image),IPL_DEPTH_8U,3);
cvCvtColor(&depth_image,convert_image,CV_GRAY2BGR);

wxClientDC depth_dc(depth_screen);
cvConvertImage(convert_image,convert_image,CV_CVTIMG_SWAP_RB);
unsigned char *data;
cvGetRawData(convert_image,&data);
wxImage *image = new wxImage(convert_image->width,convert_image->height,data,true);
wxBitmap *bitmap = new wxBitmap(*image);
int x,y,width,height;
depth_dc.GetClippingBox(&x,&y,&width,&height);
depth_dc.DrawBitmap(*bitmap,x,y);

delete image;
delete bitmap;
cvReleaseImage(&convert_image);
}

void Frame::OnExit(wxCommandEvent &event)
{
Close();
}

Thread::Thread(Frame *parent):wxThread(wxTHREAD_DETACHED)
{
frame = parent;
}

void* Thread::Entry()
{
while(!TestDestroy()){
frame->Display();
}

return NULL;
}









參考:

2013年3月25日 星期一

wxKinect

  話說老師的Lab東西很多昨天借了Kinect來玩一下,寫一個Demo試試SDK可以很簡單讀取骨架也可以選擇顯示Color & Depth & Canny...等等的影像處理,感覺OpenNI很好用,OpenNI 2在Windows下已經不使用這個Driver了而改用MS Kinect SDK的Driver,整體來說影像格式轉換比較浪費時間 OpenNI & NiTE => OpenCV => wxWidgets 不過應付FPS只有30的Kinect已經足夠,使用OpenNI或其他Middleware如果在VS2008含以下必須判斷一下然後做一些Define,收到的深度影像是CV_16UC1且數值是0 ~ 4096(10000),要轉換成CV_8UC1要把數值從0 ~ 4096(10000)映射到0 ~ 255畫出來顏色才不會太黑,如果要轉換到wxImage直接灰階轉彩色就好(CV_GRAY2BGR),然後如果要Release Binarry就要把OpenNI含Middleware的SDK安裝目錄下的Redist目錄內的動態連結檔案與Redist底下還有一個資料夾放一起就可以了。




wxKinect.h


#ifndef __WX_KINECT__
#define __WX_KINECT__

#if _MSC_VER < 1600
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int8 uint8_t;
#else
#include <stdint.h>
#endif


#include <wx/wx.h>

#include <highgui.h>
#include <cv.h>

#include <OpenNI.h>
#include <NiTE.h>

const int SCREEN_WIDTH = 640;
const int SCREEN_HIGHT = 480;

const int COLOR_MODE = 1;
const int DEPTH_MODE = 2;
const int CANNY_MODE = 3;

enum{
ID_COLOR_FRAME = 100,
ID_DEPTH_FRAME,
ID_CANNY_FRAME
};

class App:public wxApp
{
public:
bool OnInit();
};

class Frame:public wxFrame
{
public:
Frame(const wxString&);
~Frame();

void CreateUI();
void InitKinect();

void Display();

void OnExit(wxCommandEvent&);
void OnColor(wxCommandEvent&);
void OnDepth(wxCommandEvent&);
void OnCanny(wxCommandEvent&);
private:
friend class Thread;
Thread *thread;

openni::Device device;
nite::UserTracker user_tracker;
openni::VideoMode color_mode;
openni::VideoStream color_stream;
openni::VideoMode depth_mode;
openni::VideoStream depth_stream;
openni::VideoFrameRef color_frame;
openni::VideoFrameRef depth_frame;
nite::UserTrackerFrameRef user_tracker_frame;
int max_depth;

int select_mode;

wxPanel *screen;

DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(Frame,wxFrame)
EVT_MENU(wxID_EXIT,Frame::OnExit)
EVT_MENU(ID_COLOR_FRAME,Frame::OnColor)
EVT_MENU(ID_DEPTH_FRAME,Frame::OnDepth)
EVT_MENU(ID_CANNY_FRAME,Frame::OnCanny)
END_EVENT_TABLE()

class Thread:public wxThread
{
public:
Thread(Frame*);

void* Entry();
private:
Frame *frame;
};

#endif


wxKinect.cpp


#include "wxKinect.h"

DECLARE_APP(App)
IMPLEMENT_APP(App)

bool App::OnInit()
{
Frame *frame = new Frame(wxT("wxKinect"));

frame->Show(true);

return true;
}

Frame::Frame(const wxString &title):wxFrame(NULL,wxID_ANY,title,wxDefaultPosition,wxSize(800,600),wxMINIMIZE_BOX | wxCLOSE_BOX | wxCAPTION | wxSYSTEM_MENU)
{
InitKinect();
CreateUI();

select_mode = COLOR_MODE;

thread = new Thread(this);
thread->Create();
thread->Run();
}

Frame::~Frame()
{
thread->Delete();

color_stream.destroy();
depth_stream.destroy();
device.close();
openni::OpenNI::shutdown();
nite::NiTE::shutdown();
}

void Frame::CreateUI()
{
wxMenu *file = new wxMenu;
file->Append(wxID_EXIT,wxT("E&xit\tAlt-q"),wxT("exit"));

wxMenu *select = new wxMenu;
select->AppendRadioItem(ID_COLOR_FRAME,wxT("c&olor\tCtrl-c"),wxT("color"));
select->AppendRadioItem(ID_DEPTH_FRAME,wxT("d&epth\tCtrl-d"),wxT("depth"));
select->AppendRadioItem(ID_CANNY_FRAME,wxT("c&anny\tCtrl-x"),wxT("canny"));

wxMenuBar *bar = new wxMenuBar;
bar->Append(file,wxT("file"));
bar->Append(select,wxT("select"));
SetMenuBar(bar);

wxBoxSizer *top = new wxBoxSizer(wxVERTICAL);
this->SetSizer(top);

wxBoxSizer *screen_box = new wxBoxSizer(wxHORIZONTAL);
top->Add(screen_box,0,wxALIGN_CENTER_HORIZONTAL | wxALL,5);

screen = new wxPanel(this,wxID_ANY,wxDefaultPosition,wxSize(SCREEN_WIDTH,SCREEN_HIGHT));
screen_box->Add(screen,0,wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL,5);

CreateStatusBar(2);
SetStatusText(wxDateTime::Now().Format());
}

void Frame::InitKinect()
{
openni::OpenNI::initialize();
nite::NiTE::initialize();

device.open(openni::ANY_DEVICE);
device.setImageRegistrationMode(openni::IMAGE_REGISTRATION_DEPTH_TO_COLOR);

user_tracker.create();
user_tracker.setSkeletonSmoothingFactor(0.1f);

color_mode.setFps(30);
color_mode.setResolution(SCREEN_WIDTH,SCREEN_HIGHT);
color_mode.setPixelFormat(openni::PIXEL_FORMAT_RGB888);

color_stream.setVideoMode(color_mode);
color_stream.create(device,openni::SENSOR_COLOR);
color_stream.start();

depth_mode.setFps(30);
depth_mode.setResolution(SCREEN_WIDTH,SCREEN_HIGHT);
depth_mode.setPixelFormat(openni::PIXEL_FORMAT_DEPTH_100_UM);

depth_stream.setVideoMode(depth_mode);
depth_stream.create(device,openni::SENSOR_DEPTH);
depth_stream.start();
max_depth = depth_stream.getMaxPixelValue();
}

void Frame::Display()
{
color_stream.readFrame(&color_frame);
depth_stream.readFrame(&depth_frame);
user_tracker.readFrame(&user_tracker_frame);

cv::Mat RGBMat(color_frame.getHeight(),color_frame.getWidth(),CV_8UC3,(void*)color_frame.getData());
IplImage color_image(RGBMat);
cvCvtColor(&color_image,&color_image,CV_RGB2BGR);

cv::Mat DepthMat(depth_frame.getHeight(),depth_frame.getWidth(),CV_16UC1,(void*)depth_frame.getData());
DepthMat.convertTo(DepthMat,CV_8UC1,255.0f / max_depth);
IplImage depth_image(DepthMat);

IplImage *select_image = cvCreateImage(cvGetSize(&color_image),IPL_DEPTH_8U,3);

if(select_mode == COLOR_MODE){
cvCopyImage(&color_image,select_image);
}
else if(select_mode == DEPTH_MODE){
cvCvtColor(&depth_image,select_image,CV_GRAY2BGR);
}
else if(select_mode == CANNY_MODE){
cvCanny(&depth_image,&depth_image,50,200);
cvCvtColor(&depth_image,select_image,CV_GRAY2BGR);
}

const nite::Array<nite::UserData> &users = user_tracker_frame.getUsers();
for(int i = 0;i < users.getSize();++i){
const nite::UserData &user = users[i];

if(user.isNew()){
user_tracker.startSkeletonTracking(user.getId());
}
else if(user.isLost()){
}

if(user.isVisible()){
const nite::Skeleton &skeleton = user.getSkeleton();
nite::SkeletonJoint joints[15];

if(skeleton.getState() == nite::SKELETON_TRACKED){
joints[0] = skeleton.getJoint(nite::JOINT_HEAD);
joints[1] = skeleton.getJoint(nite::JOINT_NECK);
joints[2] = skeleton.getJoint(nite::JOINT_LEFT_SHOULDER);
joints[3] = skeleton.getJoint(nite::JOINT_RIGHT_SHOULDER);
joints[4] = skeleton.getJoint(nite::JOINT_LEFT_ELBOW);
joints[5] = skeleton.getJoint(nite::JOINT_RIGHT_ELBOW);
joints[6] = skeleton.getJoint(nite::JOINT_LEFT_HAND);
joints[7] = skeleton.getJoint(nite::JOINT_RIGHT_HAND);
joints[8] = skeleton.getJoint(nite::JOINT_TORSO);
joints[9] = skeleton.getJoint(nite::JOINT_LEFT_HIP);
joints[10] = skeleton.getJoint(nite::JOINT_RIGHT_HIP);
joints[11] = skeleton.getJoint(nite::JOINT_LEFT_KNEE);
joints[12] = skeleton.getJoint(nite::JOINT_RIGHT_KNEE);
joints[13] = skeleton.getJoint(nite::JOINT_LEFT_FOOT);
joints[14] = skeleton.getJoint(nite::JOINT_RIGHT_FOOT);
}

CvPoint2D32f point[15];
for(int i = 0;i < 15;++i){
const nite::Point3f &pos = joints[i].getPosition();
user_tracker.convertJointCoordinatesToDepth(pos.x,pos.y,pos.z,&(point[i].x),&(point[i].y));
}

cvLine(select_image,cvPoint(point[0].x,point[0].y),cvPoint(point[1].x,point[1].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[1].x,point[1].y),cvPoint(point[2].x,point[2].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[1].x,point[1].y),cvPoint(point[3].x,point[3].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[2].x,point[2].y),cvPoint(point[4].x,point[4].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[3].x,point[3].y),cvPoint(point[5].x,point[5].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[4].x,point[4].y),cvPoint(point[6].x,point[6].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[5].x,point[5].y),cvPoint(point[7].x,point[7].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[1].x,point[1].y),cvPoint(point[8].x,point[8].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[8].x,point[8].y),cvPoint(point[9].x,point[9].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[8].x,point[8].y),cvPoint(point[10].x,point[10].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[9].x,point[9].y),cvPoint(point[11].x,point[11].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[10].x,point[10].y),cvPoint(point[12].x,point[12].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[11].x,point[11].y),cvPoint(point[13].x,point[13].y),CV_RGB(255,0,0),3);
cvLine(select_image,cvPoint(point[12].x,point[12].y),cvPoint(point[14].x,point[14].y),CV_RGB(255,0,0),3);

for(int i = 0;i < 15;++i){
if(joints[i].getPositionConfidence() > 0.5f){
cvCircle(select_image,cvPoint(point[i].x,point[i].y),3,CV_RGB(0,255,0),2);
}
else{
cvCircle(select_image,cvPoint(point[i].x,point[i].y),3,CV_RGB(0,0,255),2);
}
}
}
}

wxClientDC dc(screen);
cvConvertImage(select_image,select_image,CV_CVTIMG_SWAP_RB);
unsigned char *data;
cvGetRawData(select_image,&data);
wxImage *image = new wxImage(select_image->width,select_image->height,data,true);
wxBitmap *bitmap = new wxBitmap(*image);
int x,y,width,height;
dc.GetClippingBox(&x,&y,&width,&height);
dc.DrawBitmap(*bitmap,x,y);
delete image;
delete bitmap;

cvReleaseImage(&select_image);
}

void Frame::OnColor(wxCommandEvent &event)
{
select_mode = COLOR_MODE;
}

void Frame::OnDepth(wxCommandEvent &event)
{
select_mode = DEPTH_MODE;
}

void Frame::OnCanny(wxCommandEvent &event)
{
select_mode = CANNY_MODE;
}

void Frame::OnExit(wxCommandEvent &event)
{
Close();
}

Thread::Thread(Frame *parent):wxThread(wxTHREAD_DETACHED)
{
frame = parent;
}

void* Thread::Entry()
{
while(!TestDestroy()){
frame->Display();
}

return NULL;
}