Arduino+LIS3DH(3軸加速度センサ)+Unityのテスト

## やった結果

https://vine.co/v/eAwZQAggJi7

## ArduinoとLIS3DHの接続

| Arduino | LIS3DH |
|:--------|:-------|
| 3.3V    | pin1   |
| GND     | pin2   |
| pin13   | pin3   |
| pin11   | pin4   |
| pin12   | pin5   |
| pin10   | pin6   |

## Arduinoで使ったコード

```cpp:LIS3DH.ino
#include <SPI.h>

const byte R_BIT  = 0x80; // 0b10000000
const byte R_MASK = 0xBF; // 0b10111111  
const byte W_MASK = 0x3F; // 0b00111111
const byte CS = 10; // pin10
const int CTRL_REG1 = 0x20;
const int OUT_X_L = 0x28;
const int OUT_X_H = 0x29;
const int OUT_Y_L = 0x2A;
const int OUT_Y_H = 0x2B;
const int OUT_Z_L = 0x2C;
const int OUT_Z_H = 0x2D;
int x_axis = 1;
int y_axis = 2;
int z_axis = 3;

unsigned int readRegister(byte reg) {
  unsigned int result;
  reg |= R_BIT;
  reg &= R_MASK;
  digitalWrite(CS, LOW);
  SPI.transfer(reg);
  result = SPI.transfer(0x00);
  digitalWrite(CS, HIGH);
  return result;
}

void writeRegister(byte reg, byte data) {
  reg &= W_MASK;
  digitalWrite(CS, LOW);
  SPI.transfer(reg);
  SPI.transfer(data);
  digitalWrite(CS, HIGH);
}

void setup() {
  unsigned int res = 0;
  
  pinMode(CS, OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);
  SPI.setClockDivider(SPI_CLOCK_DIV2);
  
  writeRegister(CTRL_REG1, 0x27);
  res = readRegister(0x0F);
  
  Serial.begin(115200);
  delay(1);
}

int getValue(int axis) {
  int Val = 0;
  int h, l;
  if (axis == x_axis) {
    l = readRegister(OUT_X_L);
    h = readRegister(OUT_X_H);
  } else if (axis == y_axis) {
    l = readRegister(OUT_Y_L);
    h = readRegister(OUT_Y_H);
  } else if (axis == z_axis) {
    l = readRegister(OUT_Z_L);
    h = readRegister(OUT_Z_H);
  }
  Val = h << 8 | l;
  return Val;
}

void loop() {
  int x, y, z;
  
  writeRegister(CTRL_REG1, 0x27);

  x = getValue(x_axis);
  y = getValue(y_axis);
  z = getValue(z_axis);
  
  const int angleX = atan2(x, z) / PI * 180;
  const int angleY = atan2(y, z) / PI * 180; 

  Serial.print(angleX);
  Serial.print("\t");
  Serial.println(angleY);
  Serial.flush();

  delay(100);
}
```

## Unityで使うC#コード

```csharp:LIS3DH.cs
using System;
using System.IO.Ports;
using System.Threading;
using UnityEngine;
using System.Collections.Generic;

public class LIS3DH : MonoBehaviour {
	public const string SERIAL_PORT = "COM8";
	public const int SERIAL_BAUD_RATE = 115200;
	private const int SERIAL_TIMEOUT = 100;
	
	private Thread _readThread;
	private static SerialPort _serialPort;
	private static bool _continue;
	
	private static Quaternion _handQuaternion = new Quaternion();

	private List<Vector3> angleCache = new List<Vector3>();
	public int angleCacheNum = 10;
	public Vector3 angle {
		private set {
			angleCache.Add(value);
			if (angleCache.Count > angleCacheNum) {
				angleCache.RemoveAt(0);
			}
		}
		get {
			if (angleCache.Count > 0) {
				var sum = Vector3.zero;
				angleCache.ForEach(angle => { sum += angle; });
				return sum / angleCache.Count;
			} else {
				return Vector3.zero;
			}
		}
	}

	void Start() {
		_readThread = new Thread(Read);
		_serialPort = new SerialPort(SERIAL_PORT, SERIAL_BAUD_RATE);
		_serialPort.ReadTimeout = SERIAL_TIMEOUT;
		_serialPort.Open();
		_continue = true;
		_readThread.Start();
	}
	
	void Update() {
		//Debug.Log (angle);
		transform.rotation = Quaternion.Euler(angle);
	}
	
	void OnApplicationQuit() {
		_continue = false;
		_readThread.Join();
		_serialPort.Close();
	}
	
	private void Read() {
		string[] values;
		while (_continue) {
			if (_serialPort.IsOpen) {
				try {
					values = _serialPort.ReadLine().Split('\t');
					var angleX = float.Parse(values[0]) * -1;
					var angleY = float.Parse(values[1]) * -1;
					angle = new Vector3(angleX, 0, angleY);
					//_handQuaternion.eulerAngles.Set(angleX, 0, angleY);
					//Debug.Log (angleX + "," + angleY);
				} catch (TimeoutException) {
				}
			}
			Thread.Sleep(1);
		}
	}
}
```

## 参考
http://makers-with-myson.blog.so-net.ne.jp/2014-03-08
http://tips.hecomi.com/entry/2014/07/28/023525