Wiiヌンチャク + Arduino + RCB-1 で8軸ロボットを動かしてみた。

ArduinoはI2CでWiiヌンチャクの状態を取得し、RCB-1の低速シリアルのデータを返す。
加速度センサで移動、ジョイスティックで技が出せる。
http://youtube.com/watch?v=yeGf9P09vBo

左右に寝かすと横移動。
前に寝かすと前進、後ろに寝かすと後進。
ジョイスティックの左右でチョップを出す。


現状のArduinoのスケッチはこちら。
RCB-1の低速シリアルは負論理なので、SoftwareSerialのソースを修正して負論理で使えるようにして動作させた。
識者の良きアドバイスをお待ちしています。

/**
 * Wiiヌンチャク利用の8軸用コントローラ
 * 
 * Wiiヌンチャクの状態から、RCB-1 の低速シリアルをSoftwareSerial2
 * で制御する。
 *
 * SoftwareSerial2 は Arduino付属の SoftwareSerial の出力を正負逆転
 * させたもの。(hardware\libraries\SoftwareSerialフォルダを 
 * SoftwareSerial2フォルダとしてコピーし、SoftwareSerial.cpp を
 * SoftwareSerial2.cpp、SoftwareSerial.h を SoftwareSerial2.h に
 * にリネームし、それぞれのファイル内のSoftwareSerial・HIGH・LOWを
 * SoftwareSerial2・LOW・HIGHに置換しただけ。.oファイルがあれば削除
 * してから Sketch をコンパイルする。)
 *
 * (参考)
 * Wii ヌンチャクと通信してみた(2)CommentsAdd Star
 * http://d.hatena.ne.jp/clayfish/20090405/1238924970
 * Wiimote/Extension Controllers/Nunchuk
 * http://www.wiili.org/index.php/Wiimote/Extension_Controllers/Nunchuk
 */
#include <SoftwareSerial2.h> 
#include <Wire.h>

#define rxPin 2
#define txPin 3
#define ledPin 13

// 新たなシリアルポートを設定
SoftwareSerial2 mySerial =  SoftwareSerial2(rxPin, txPin);

uint8_t outbuf[6];		// array to store arduino output
int cnt = 0;

byte pinState = 0;  // LEDの状態

void setup() {
  pinMode(rxPin, INPUT);
  pinMode(txPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  mySerial.begin(2400);	// 2400bpsでポートを開く
  Serial.begin(9600);	// 9600bpsでポートを開く
  Wire.begin ();    // join i2c bus with address 0x52
  nunchuck_init (); // send the initilization handshake
}

void
nunchuck_init ()
{
  Wire.beginTransmission (0x52);	// transmit to device 0x52
  Wire.send (0x40);		// sends memory address
  Wire.send (0x00);		// sends sent a zero.  
  Wire.endTransmission ();	// stop transmitting
}

void
send_zero ()
{
  Wire.beginTransmission (0x52);	// transmit to device 0x52
  Wire.send (0x00);		// sends one byte
  Wire.endTransmission ();	// stop transmitting
}

void
loop ()
{
  Wire.requestFrom (0x52, 6);	// request data from nunchuck
  while (Wire.available ()) {
    outbuf[cnt] = nunchuk_decode_byte (Wire.receive ());	// receive byte as an integer
    cnt++;
  }
  // If we recieved the 6 bytes, then go print them
  if (cnt >= 5) {
    print ();
  }
  cnt = 0;
  send_zero (); // send the request for next bytes
  delay (50);
}


void
print ()
{
  int threshold = 16;
  int joy_x_axis   = outbuf[0];
  int joy_y_axis   = outbuf[1];
  int accel_x_axis = outbuf[2]; 
  int accel_y_axis = outbuf[3];
  int accel_z_axis = outbuf[4];
  int z_button = 0;
  int c_button = 0;
  
  if ((outbuf[5] >> 0) & 1) z_button = 1;
  if ((outbuf[5] >> 1) & 1) c_button = 1;
  if ((outbuf[5] >> 2) & 1) accel_x_axis += 2;
  if ((outbuf[5] >> 3) & 1) accel_x_axis += 1;
  if ((outbuf[5] >> 4) & 1) accel_y_axis += 2;
  if ((outbuf[5] >> 5) & 1) accel_y_axis += 1;
  if ((outbuf[5] >> 6) & 1) accel_z_axis += 2;
  if ((outbuf[5] >> 7) & 1) accel_z_axis += 1;
  
  // RCB-1 send data
  int b1 = 0xf0;
  int b2 = 0x00;
  
  // 1byte 
  if (c_button == 0) b1 |= 0b00000001;
  if (z_button == 0) b1 |= 0b00000010;
  
  // 2byte 
  if (accel_y_axis > 128 + threshold) b2 |= 0b00000001;
  if (accel_y_axis < 128 - threshold) b2 |= 0b00000010;
  if (accel_x_axis > 128 + threshold) b2 |= 0b00000100;
  if (accel_x_axis < 128 - threshold) b2 |= 0b00001000;
  if (joy_y_axis > 128 + threshold)   b2 |= 0b00010000;
  if (joy_y_axis < 128 - threshold)   b2 |= 0b00100000;
  if (joy_x_axis > 128 + threshold)   b2 |= 0b01000000;
  if (joy_x_axis < 128 - threshold)   b2 |= 0b10000000;

  delay (17);
  mySerial.print(b1, BYTE);        // 文字を送信
  mySerial.print(b2, BYTE);        // 文字を送信
  
  toggle(ledPin); // 動作が見えるよう、受信するたびにLEDを反転

  Serial.print (joy_x_axis, DEC);
  Serial.print (",");
  Serial.print (joy_y_axis, DEC);
  Serial.print (",");
  Serial.print (accel_x_axis, DEC);
  Serial.print (",");
  Serial.print (accel_y_axis, DEC);
  Serial.print (",");
  Serial.print (accel_z_axis, DEC);
  Serial.print (",");
  Serial.print (z_button, DEC);
  Serial.print (",");
  Serial.print (c_button, DEC);
  Serial.print (",");
  Serial.print (b1, DEC);
  Serial.print (",");
  Serial.print (b2, DEC);
  Serial.print("\r\n");
}

char
nunchuk_decode_byte (char x)
{
  x = (x ^ 0x17) + 0x17;
  return x;
}

void toggle(int pinNum) {
  digitalWrite(pinNum, pinState);
  pinState = !pinState;  // pinStateが0なら1、1なら0に反転
}