Wii Motion Plus

原文出處 http://randomhacksofboredom.blogspot.com/2009/06/wii-motion-plus-arduino-love.html
任天堂革命性的產品,
自己實作了一次,
這也算是窮人的陀螺儀吧..
//========= Arduino Code =========
#include <Wire.h>

byte data[6];    //six data bytes
int yaw, pitch, roll;  //three axes
int yaw0, pitch0, roll0;  //calibration zeroes
int startTag=0xDEAD;

void wmpOn(){
  Wire.beginTransmission(0x53);    //WM+ starts out deactivated at address 0x53
  Wire.send(0xfe);     //send 0x04 to address 0xFE to activate WM+
  Wire.send(0x04);
  Wire.endTransmission();    //WM+ jumps to address 0x52 and is now active
}

void wmpSendZero(){
  Wire.beginTransmission(0x52);    //now at address 0x52
  Wire.send(0x00);     //send zero to signal we want info
  Wire.endTransmission();
}

void calibrateZeroes(){
  for (int i=0;i<10;i++){
    wmpSendZero();
    Wire.requestFrom(0x52,6);
    for (int i=0;i<6;i++){
data[i]=Wire.receive();
    }
    yaw0+=(((data[3]>>2)<<8)+data[0])/10;  //average 10 readings for each zero
    pitch0+=(((data[4]>>2)<<8)+data[1])/10;
    roll0+=(((data[5]>>2)<<8)+data[2])/10;
  }
  /*Serial.print("Yaw0:");
  Serial.print(yaw0);
  Serial.print("  Pitch0:");
  Serial.print(pitch0);
  Serial.print("  Roll0:");
  Serial.println(roll0);*/
}

void receiveData(){
  wmpSendZero(); //send zero before each request (same as nunchuck)
  Wire.requestFrom(0x52,6);  //request the six bytes from the WM+
  for (int i=0;i<6;i++){
    data[i]=Wire.receive();
  }
  yaw=(((data[3]>>2)<<8)+data[0]);  //see http://wiibrew.org/wiki/Wiimote/Extension_Controllers#Wii_Motion_Plus
  pitch=(((data[4]>>2)<<8)+data[1]);    //for info on what each byte represents
  roll=(((data[5]>>2)<<8)+data[2]);
}

void setup(){
  Serial.begin(115200);
  //Serial.println("WM+ tester");
  Wire.begin();
  wmpOn(); //turn WM+ on
  calibrateZeroes();  //calibrate zeroes
  delay(1000);
}

void loop(){
  receiveData(); //receive data and calculate yaw pitch and roll
  Serial.write((unsigned byte*)&startTag, 2);  //see diagram on randomhacksofboredom.blogger.com
  Serial.write((unsigned byte*)&pitch0, 2);    //for info on which axis is which
  Serial.write((unsigned byte*)&yaw0, 2);
  Serial.write((unsigned byte*)&roll0, 2);
  Serial.write((unsigned byte*)&pitch, 2);
  Serial.write((unsigned byte*)&yaw, 2);
  Serial.write((unsigned byte*)&roll, 2);
  delay(10);
}
//================= End


//========= Processing Code =========
// 劃出波形

import processing.serial.*;

// Globals
int g_winW             = 820;   // Window Width
int g_winH             = 600;   // Window Height
boolean g_dumpToFile   = false;  // Dumps data to c:\\output.txt in a comma seperated format (easy to import into Excel)
boolean g_enableFilter = false;  // Enables simple filter to help smooth out data.

cDataArray pitch0    = new cDataArray(200);
cDataArray yaw0    = new cDataArray(200);
cDataArray roll0    = new cDataArray(200);
cDataArray pitch      = new cDataArray(200);
cDataArray yaw     = new cDataArray(200);
cDataArray roll     = new cDataArray(200);
cGraph g_graph         = new cGraph(10, 190, 800, 400);
Serial g_serial;
PFont  g_font;

void setup()
{
  size(g_winW, g_winH, P2D);

  println(Serial.list());
  g_serial = new Serial(this, "COM3", 115200, 'N', 8, 1.0);  //enter COM port of
  g_font = loadFont("AVGmdBU-30.vlw");                       //of arduino here
  textFont(g_font, 20);

  // This draws the graph key info
  strokeWeight(1.5);
  stroke(255, 0, 0);     line(20, 440, 35, 440);
  stroke(0, 255, 0);     line(20, 460, 35, 460);
  stroke(0, 0, 255);     line(20, 480, 35, 480);
  stroke(255, 0, 0);     line(20, 500, 35, 500);
  stroke(0, 255, 0);     line(20, 520, 35, 520);
  stroke(0, 0, 255);     line(20, 540, 35, 540);
  fill(0, 0, 0);
  text("pitch0", 40, 450);
  text("yaw0", 40, 470);
  text("roll0", 40, 490);
  text("pitch", 40, 510);
  text("yaw", 40, 530);
  text("roll", 40, 550);
  //text("current raw", 180, 430);
  //text("current deg/s", 320, 430);

  if (g_dumpToFile)
  {
    // This clears deletes the old file each time the app restarts
    byte[] tmpChars = {'\r', '\n'};
    saveBytes("c:\\output.txt", tmpChars);
  }
}

void draw()
{
  // We need to read in all the avilable data so graphing doesn't lag behind
  while (g_serial.available() >= 2*6+2)
  {
    processSerialData();
  }

  strokeWeight(1);
  fill(255, 255, 255);
  g_graph.drawGraphBox();

  strokeWeight(1.5);
  stroke(255, 0, 0);
  g_graph.drawLine(pitch0, 0, 16384);
  stroke(0, 255, 0);
  g_graph.drawLine(yaw0, 0, 16384);
  stroke(0, 0, 255);
  g_graph.drawLine(roll0, 0, 16384);
  stroke(255, 0, 0);
  g_graph.drawLine(pitch, 0, 16384);
  stroke(0, 255, 0);
  g_graph.drawLine(yaw, 0, 16384);
  stroke(0, 0, 255);
  g_graph.drawLine(roll, 0, 16384);
}

// This reads in one set of the data from the serial port
void processSerialData()
{
  int inByte = 0;
  int curMatchPos = 0;
  int[] intBuf = new int[2];

  intBuf[0] = 0xAD;
  intBuf[1] = 0xDE;

  while (g_serial.available() < 2); // Loop until we have enough bytes
  inByte = g_serial.read();

  // This while look looks for two bytes sent by the client 0xDEAD
  // This allows us to resync the server and client if they ever
  // loose sync.  In my testing I haven't seen them loose sync so
  // this could be removed if you need to, but it is a good way to
  // prevent catastrophic failure.
  while(curMatchPos < 2)
  {
    if (inByte == intBuf[curMatchPos])
    {
      ++curMatchPos;
     
      if (curMatchPos == 2)
        break;
   
      while (g_serial.available() < 2); // Loop until we have enough bytes
      inByte = g_serial.read();
    }
    else
    {
      if (curMatchPos == 0)
      {
        while (g_serial.available() < 2); // Loop until we have enough bytes
        inByte = g_serial.read();
      }
      else
      {
        curMatchPos = 0;
      }
    }
  }

  while (g_serial.available() < 2*6);  // Loop until we have a full set of data

  // This reads in one set of data
  {
    byte[] inBuf = new byte[2];
    int pitch0_cur, yaw0_cur, roll0_cur, pitch_cur, yaw_cur, roll_cur;

    g_serial.readBytes(inBuf);
    // Had to do some type conversion since Java doesn't support unsigned bytes
    pitch0_cur = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    yaw0_cur = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    roll0_cur = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    pitch_cur   = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    yaw_cur  = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
    g_serial.readBytes(inBuf);
    roll_cur  = ((int)(inBuf[1]&0xFF) << 8) + ((int)(inBuf[0]&0xFF) << 0);
   
    pitch0.addVal(pitch0_cur);
    yaw0.addVal(yaw0_cur);
    roll0.addVal(roll0_cur);
    pitch.addVal(pitch_cur);
    yaw.addVal(yaw_cur);
    roll.addVal(roll_cur);

    if (g_dumpToFile)  // Dump data to a file if needed
    {
      String tempStr;
      tempStr = pitch0_cur + "," + yaw0_cur + "," + roll0_cur + "," + pitch_cur + "," + yaw_cur + "," + roll_cur + "\r\n";
      FileWriter file;

      try 
      { 
        file = new FileWriter("c:\\output.txt", true); //bool tells to append
        file.write(tempStr, 0, tempStr.length()); //(string, start char, end char)
        file.close();
      } 
      catch(Exception e) 
      { 
        println("Error: Can't open file!");
      }
    }

    /*
    print(pitch0_cur);  print(" ");   print(yaw0_cur);   print(" ");    print(roll0_cur);     print(" ");
    print(pitch_cur);    print(" ");   print(yaw_cur);    print(" ");    println(roll_cur);
    */
  }
}

// This class helps mangage the arrays of data I need to keep around for graphing.
class cDataArray
{
  float[] m_data;
  int m_maxSize;
  int m_startIndex = 0;
  int m_endIndex = 0;
  int m_curSize;

  cDataArray(int maxSize)
  {
    m_maxSize = maxSize;
    m_data = new float[maxSize];
  }

  void addVal(float val)
  {
   
    if (g_enableFilter && (m_curSize != 0))
    {
      int indx;
     
      if (m_endIndex == 0)
        indx = m_maxSize-1;
      else
        indx = m_endIndex - 1;
     
      m_data[m_endIndex] = getVal(indx)*.5 + val*.5;
    }
    else
    {
      m_data[m_endIndex] = val;
    }
   
    m_endIndex = (m_endIndex+1)%m_maxSize;
    if (m_curSize == m_maxSize)
    {
      m_startIndex = (m_startIndex+1)%m_maxSize;
    }
    else
    {
      m_curSize++;
    }
  }

  float getVal(int index)
  {
    return m_data[(m_startIndex+index)%m_maxSize];
  }

  int getCurSize()
  {
    return m_curSize;
  }

  int getMaxSize()
  {
    return m_maxSize;
  }
}

// This class takes the data and helps graph it
class cGraph
{
  float m_gWidth, m_gHeight;
  float m_gLeft, m_gBottom, m_gRight, m_gTop;

  cGraph(float x, float y, float w, float h)
  {
    m_gWidth     = w;
    m_gHeight    = h;
    m_gLeft      = x;
    m_gBottom    = g_winH - y;
    m_gRight     = x + w;
    m_gTop       = g_winH - y - h;
  }

  void drawGraphBox()
  {
    stroke(0, 0, 0);
    rectMode(CORNERS);
    rect(m_gLeft, m_gBottom, m_gRight, m_gTop);
  }

  void drawLine(cDataArray data, float minRange, float maxRange)
  {
    float graphMultX = m_gWidth/data.getMaxSize();
    float graphMultY = m_gHeight/(maxRange-minRange);
   
    for(int i=0; i<data.getCurSize()-1; ++i)
    {
      float x0 = i*graphMultX+m_gLeft;
      float y0 = m_gBottom-((data.getVal(i)-minRange)*graphMultY);
      float x1 = (i+1)*graphMultX+m_gLeft;
      float y1 = m_gBottom-((data.getVal(i+1)-minRange)*graphMultY);
      line(x0, y0, x1, y1);
    }
  }
}
//================= End

Roboard RB-100 computer control with Hitec Robonova - First walk (Prototype I)

停擺了幾年.. 終於完成了第一步了..
使用 Hitec Robonova 機構
和 Hitec HSR-8498HB Servo
換上 Robaord Rb-100 控制板..

首先須要先準備一些東東..
A. 線材 (杜邦線 )















光華商場買來只有一頭有做好杜邦頭, 另外一邊有吃錫,
所以需要DIY接頭..















因為是 Prototype 所以接頭都用活動的.
需要準備 1 pin, 2pin ..



























好像在做家庭手工...
因為要準備 16 Servo x 3 ( 正極 / 負極 / 信號 )
總共  48 條線 ...
因為要外接電源, 所以另外做一個轉版,
工具需要剝線鉗 + 端子鉗.



















48條線做好出入杜邦頭後..逐一用電表測試導通與否..
















寫了一個小介面程式控制,
先暫時調了2個動作... 站立 + 走一步..

因為才剛剛開始...
所以都還沒有加入任何感測元件..等
動起來搖搖晃晃的, 接下來將陸續實作這部分了~

影片:

video

RGB Led 1W

接線圖


















關鍵一:
Arduino Mini
腳位接到數位IO腳 3, 5, 6, 9, 10, 11 才能做輸出.. !!!
關鍵二:
此 RGB LED circuit 標示錯誤 - 負極..實際上要接 +正極,
R/G/B 接 Digital Pin, 共4線.. 不須接地線.

影片:

video


程式碼:
int R_ledPin = 9;

int G_ledPin = 10;

int B_ledPin = 11;

int ledPin = 13;



// val 255 = off

int R_val=254;

int G_val=254; 

int B_val=254;



void setup()

{ 

pinMode(ledPin, OUTPUT);



pinMode( R_ledPin, OUTPUT); 

pinMode( G_ledPin, OUTPUT); 

pinMode( B_ledPin, OUTPUT); 



Serial.begin ( 9600 );



analogWrite ( R_ledPin, R_val );

analogWrite ( G_ledPin, G_val );

analogWrite ( B_ledPin, B_val ); 



delay ( 1000 );

}

int dir=0;

int color = 0;

int offset = 5;

void loop() 

{

digitalWrite(ledPin, HIGH); 



switch ( color )

{

case 0: analogWrite ( R_ledPin, R_val ); break;

case 1: analogWrite ( G_ledPin, R_val ); break;

case 2: analogWrite ( B_ledPin, R_val ); break;

}



if ( dir == 0 )

{

if ( R_val - offset > 0 )

{

R_val -= offset;

}

else 

{

R_val = 0;

dir = 1; 

}

}



if ( dir == 1 )

{

if ( R_val + offset < 255 )

{ 

R_val += offset;

}

else 

{

R_val = 254;

dir = 0;



if ( color + 1 < 3 ) color ++;

else color = 0;

} 

}

//delay ( 300 );



clearLCD (); // 清除 LCD 畫面



// 輸出數值到 LCD

Serial.print ( "R= ");

Serial.print ( R_val, DEC );

Serial.print ( "\n");
}

// ===== clear the LCD =====

void clearLCD()
{
Serial.print(12, BYTE);

}

計數器

試試這家的計數器...
http://www.pax.com

智慧手機 Android 平台

Adnroid 開發環境軟體安裝步驟

1.安裝 Android SDK and AVD Manager
檔案 android-sdk_r06-windows.zip


2.安裝 Java SDK
下載網址  http://www.oracle.com/technetwork/java/javase/downloads/index.html
檔案 jdk-6u21-windows-i586.exe


3.安裝 Eclipse
下載網址 http://www.eclipse.org/downloads/
檔案 eclipse-java-helios-win32.zip
A. 執行 Eclipse -> Help -> install new software ->
     Work with  "http://dl-ssl.google.com/android/eclipse/site.xml" Add
B. 執行 Eclipse -> Windows->Preferences-> SDK Location: (選擇步驟一的路徑)