iOS * BLEシリアルで簡単にプロトタイピングできた話


iOSで外部デバイスを接続する場合、下記の2択から考えることが多いと思います。

 * WiFiで繋ぐ
 * Bluetooth Low Energy（以下BLE）で繋ぐ

WiFiで繋ぐ場合、接続中にiOSデバイスがインターネットに繋げないため、BLEを選択する場合が多くなると思います。しかしながら、BLEを使いこなすには結構な勉強が必要で、パッと思いついたアイデアをチャチャッとプロトタイプしたいときに大変です。

そこで,浅草ギ研さんが出している[BLE-Serial](http://www.robotsfx.com/robot/BLESerial.html)というモジュールを使ったらBLE詳しくなくても簡単にプロトタイプできた！という話を書きたいと思います。GATTプロファイルの作り込みなどもプロトタイプ内でしたい場合は、konashiをご検討ください。

# 目標
iOSからマイクロマウスを操作できるようにします。また、マイクロマウス側からセンサーデータ（今回はロータリーエンコーダから回転数）を取得して、iOS側でそれを表示させます。

こんなのを作ります。iOSデバイスから、マイクロマウスを操縦します。
![スクリーンショット 2015-04-08 23.31.39.png](https://qiita-image-store.s3.amazonaws.com/0/48091/975b1217-6d94-b0c7-5d47-bafe83117bbd.png)


# 必要なもの
 * [BLE-Serialモジュール](http://www.robotsfx.com/robot/BLESerial.html)
 * [マイクロマウス（ビュートミニARM エンコーダ・ブザー搭載）](http://www.vstone.co.jp/products/beauto_mini_arm/)
 * 半田付セット

# 環境構築
 * iOS側はXcode6.1.1を使用
 * マイクロマウス側は[こちらのサイト](http://www.vstone.co.jp/products/beauto_mini_arm/)からLPCxpressoを使用
 * iOS側言語：swift
 * マイクロマウス側言語：c

# マイクロマウス側の開発
## 回路
BLE-Serialとマイクロマウスをシリアルで接続する必要があります。
下記４つを結線します。色がわかりにくくてごめんなさい。半田付けもひどいです。

 * 5V（オレンジ）
 * GND（緑）
 * RX（青）
 * TX（白）

マイクロマウス側
![IMG_0059.JPG](https://qiita-image-store.s3.amazonaws.com/0/48091/71ceeca8-0206-6298-4b58-cd71edb3d39b.jpeg)


BLE-Serial側
![IMG_0061.jpg](https://qiita-image-store.s3.amazonaws.com/0/48091/8a4e4b73-7568-7a40-ab1f-71f67d6d180e.jpeg)



## コード
[こちらのサイトのサンプルコードの](http://www.vstone.co.jp/products/beauto_mini_arm/)「IXポート（SCI)シリアル通信サンプル」サンプルのmain.cを下記のように書き換えました。
受信処理は、すごく雑なコードですが、'a'を受け取ったら前進、'z'を受け取ったら後退、以下....。
送信処理では、TIMER32_1_IRQHandlerで１秒に一回のタイマー割り込みを用意し、
その中で、sprintf(str,"r:%d,l:%d",right_b - right , left_b - left);
とし、その１秒間のエンコーダの回転数を送っています。

マジックナンバーばかりで意味不明な部分が多いですが、right,leftの変数に大きな数字を入れるほど、モーターが前向きに回転速度をあげ、マイナスの数字を入れると後ろ向きに回転速度を上げるようになっています。

```c:main.c


int main (void)
{
	//制御周期の設定[単位：Hz　範囲：30.0~]
	const unsigned short MainCycle = 60;
	Init(MainCycle);		//CPUの初期設定

	InitTimer1();

	InitEncoder();
	ClearEncoder();

	//シリアル通信初期化
	InitSci3(CBR_9600,non,1);

	int rotateFlag = 0;
	long right , left;
	right = left = 0;

	long r , l;
	r = l = 0;
	unsigned char data;

	//ループ
	while(1){
		Sync();
		GetEncoder(&right,&left);
		if(SciByteRx(&data) > 0){
			{
				if(data == 'a')//前進
				{
					ClearEncoder();
					r = 6000;
					l = 6000;
					rotateFlag = 0;
				}
				else if(data == 'z')//後退
				{
					ClearEncoder();
					r = -6000;
					l = -6000;
					rotateFlag = 0;
				}
				else if(data == 'r')//回転
				{
					ClearEncoder();
					r = -8000;
					l = 8000;
					rotateFlag = 1;
				}
				else//停止
				{
					r = 0;
					l = 0;
					ClearEncoder();
					rotateFlag = 0;
				}
			}
		}
		if(rotateFlag)
			Mtr_Run_lv(r,-l,0,0,0,0);// 回転中は制御しない
		else
			Mtr_Run_lv(r+Proportinal(right  ,-left),-(l+Proportinal(-left  , right)),0,0,0,0);
	}
}

long Proportinal(long value , long target)
{
	long ret = ( target - value ) * 10;
	return ret;
}

void InitTimer1()
{
	NVIC_EnableIRQ(TIMER_32_1_IRQn);

	LPC_SYSCON->SYSAHBCLKCTRL |=0x400;
	LPC_TMR32B1->TCR =(1 << 1);	 // TCR Reset
	LPC_TMR32B1->PR = 7200 -1;
	LPC_TMR32B1->MR0 =10000-1;
	LPC_TMR32B1->CTCR=0;
	LPC_TMR32B1->MCR |=(1 << 1)|(1 << 0);
	//LPC_TMR32B1->IR = 0xff;
	LPC_TMR32B1->TCR =(1 << 0);	 // TCR start
}

void TIMER32_1_IRQHandler(void)
{
	static long right = 0 , left = 0;
	long right_b = 0 , left_b = 0;
	GetEncoder(&right_b,&left_b);
	char str[256];
	sprintf(str,"r:%d,l:%d",right_b - right , left_b - left);
	SciStrTx(str,strlen(str));
	right = right_b;
	left = left_b;
    n++;
    LED(n % 4);
    LPC_TMR32B1->IR = 0xff;
}

```



## iOS側の開発

[コードをgithubにあげました。](https://github.com/TakahiroYamamoto/BLE-Serial)
是非是非使ってください。


使い方は簡単です。viewDidLoadなどで、connectする。
readは、callback型になっているので、事前にクロージャーを設定しておくと、
データが送られてくるたびにこのクロージャーが呼ばれます。
データの本体は、stringの中に文字列として入ってきます。

```swift:TopViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        var communicator : BLESerialCommunicator = BLESerialCommunicator.sharedInstance
        communicator.connect()
        
        
        // string には、r:xxxx,l;xxxx の形で入ってくる
        communicator.readBlock = {string in
            self.dispatch_async_main
                {
                    println("\(string)")
            }
        }
    }

```

あとは、適時送信したいときに、writeするだけです。
今回は、ボタンを押したらマイクロマウスを前進、後退させたいのでボタンのAction内で'a'や'z'を送信しています。

```swift:TopViewController.swift
    @IBAction func prev(sender:AnyObject)
    {
        var communicator : BLESerialCommunicator = BLESerialCommunicator.sharedInstance
        communicator.write("a")
    }
    
    @IBAction func back(sender:AnyObject)
    {
        var communicator : BLESerialCommunicator = BLESerialCommunicator.sharedInstance
        communicator.write("z")
    }
```

# 出来上がったもの

[動画](https://youtu.be/ONnHqti4aOE)