Arduino で Bluetooth シリアル変換モジュール(HC-05)を使う

本来ならば Bluetooth LE を使うところなのでしょうが、価格が高い(苦笑)なので安い方から手を入れていきます。

<b>連載</b>Bluetooth LE (5) Android 4.3 で Bluetooth LE 機器を使う (フェンリル | デベロッパーズブログ)
http://blog.fenrir-inc.com/jp/2013/10/bluetooth-le-android.html
Bluetoothでデバイスと通信するには | garicchi.com
http://garicchi.com/?p=17111

なところで、BLE を使っているのでいずれ追いつこうということで。手始めには、先に作ったモーターの駆動系を Bluetooth で制御していきます。同時に Raspberry Pi の Bluetooth シールドも買ったのですが、まあ、これは要らなかったかも。同じ HC-05 の変換モジュールだけで ok みたいです。

Bluetoothシリアル変換モジュール(マスタ/スレーブ) – Androciti Wiki
http://wiki.androciti.com/index.php?Bluetooth%A5%B7%A5%EA%A5%A2%A5%EB%CA%D1%B4%B9%A5%E2%A5%B8%A5%E5%A1%BC%A5%EB(%A5%DE%A5%B9%A5%BF%2F%A5%B9%A5%EC%A1%BC%A5%D6)

価格的には 1,500円ぐらいですね。スレーブ専用の HC-06 だと 1,000 円ちょっとなので複数使うときに良さそうです。
実は、BLE とそれ以前の Bluetooth の違いを知らなくて、去年 Xamarin のカンファレンスで SensorTag を見せてもらったときに「うーん、Bluetooth なのか」と思ってただけなんですよ。実は、グロサミで解説してもらった(英語だったけど)Rolling Spider も BLE を使っていて、それの SDK を使って Bluetooth 対応のコントローラーで動かした、ってのミソだったんですね…と今更思い直しました。SensorTag は試しに買ってみたので、到着したら試してみる予定です。あと、BLE 対応のシールドも。

シリアルポートでつなげる

とはいえ、Bluetooth に様々なプロファイルがあって、それを使えば様々なことができる、ってことは以前に Bluetooth を調べたときに分かってはいたのですが、その時には具体的な端末がなくて、オーディオ関連とかファイル転送をしてもなぁ、ってな感じでした。あまりハードウェアに詳しくなかったので、何かを制御するには WiFi ぐらいだろうと思っていたわけで、RealSense 絡みも WiFi で作っています。
が、とある人から、がりっちさんの RFCOMM 通信の記事を知って、ちょっと通信部分の制御を変えてみようかと思ったわけです。WiFi+RPi の組み合わせや、Bluetooth+RPi+PSコントローラーのみかと思っていたら、RFCOMM プロトコルでつなげれば、結構手軽に iPhone/Android から繋げられそうです。実は Windows からは Windows Windows ストアアプリから接続しないといけない(デスクトップアプリでもできるはずなんですけどね?)ので、あれこれとややこしいのですが、さっくりと繋がります。
COM ポートとして使えるので、そのまま適当なコマンドを作ってやり取りすれば自前のモーター制御/サーボ制御ぐらいはできそうです。

Bluetooth シリアル変換モジュール(HC-05)をArduinoにつなげる

HC-05 Arudino
RX — TX
TX — RX
GND — GND
VCC — 3.3V

につなげます。RX/TX が送受信でワンセットになっているのと電源用の VCC/GND を差すだけで十分です。これは Raspberry Pi の場合も同じなので、結構さっくりと認識するはずです。

ちなみに、Windows 8 から Bluetooth 機器につなげるときはペアリングが必須なんですが(Windows 10の場合は BLE に対応するので、ペアリングは必要ないらしい?)、Bluetooth 機器だけを認識させる場合は、電源の VCC/GND の間に 3.3V – 6V ぐらい流せば ok です。電波を弱くして Bluetooth 機器の近くに入ったよ、ってのは、これでで十分かもしれませんね(実際、BLE の使い方でそういうのはあると思う)。

Android 側のスケッチを作る

シリアルポートは1バイト単位で読み込むのですが、コマンドっぽく送受信したかったので8バイト単位で受信しています。このあたりはマインドストーム EV3 を制御するときも同じみたいですね。こっちもいずれやってみたいところです。

int ledPin=13;
int mPin  = 8; // モーター

void setup(){
  pinMode(ledPin,OUTPUT);
  pinMode(mPin,OUTPUT);
  Serial.begin(9600);
}
 
void loop(){
  int n = Serial.available();
  if ( n >= 8 ) {
    int ch[8];
    int i;
    // 8バイトずつ読み込む
    for ( i=0; i<8; i++) {
      ch&#91;i&#93; = Serial.read();
    }
    // コマンドを判別
    if ( ch&#91;0&#93; == 'm' ) {
      if ( ch&#91;1&#93; == '1' ) {
        if ( ch&#91;2&#93; == 'o' && ch&#91;3&#93; == 'n' ) {
          // pin8 on
          digitalWrite(mPin,HIGH);
        } else {
          // pin8 off
          digitalWrite(mPin,LOW);
        }
      }
    }
    // 通信時に光らせる
    digitalWrite(ledPin,HIGH);
    delay(300);
    digitalWrite(ledPin,LOW);
    // エコーを送信
    for ( i=0; i<8; i++) {
      Serial.write(ch&#91;i&#93;);
    }
  }
}
&#91;/code&#93;
<ul>
<li>m1on  でモータ-をON</li>
<li>m1off でモーターをOFF</li>
</ul>
<p>
な単純な仕組みです。最終的には、モーター制御とアームのサーボ制御も入れたいのと、対物センサーの受信もいれておきたいですね。ここまで来ると、素直に BLE にしたほうがいいような気もするのですが、まあ、HC-05 モジュールが安いので。
</p>
<p>
<h2>Windows ストアアプリから制御する</h2>
</p>
<p>
Windows 8 の制限から、ストアアプリから制御します。たぶん、Windows Phone からも同じ制御ができるはずです。
</p>
[code lang="csharp"]
public sealed partial class MainPage : Page
{
	public MainPage()
	{
		this.InitializeComponent();
	}
	// RFCOMM のサービスID
	Guid serviceGuid = Guid.Parse("00001101-0000-1000-8000-00805f9b34fb");
	RfcommDeviceService rfcommService;
	StreamSocket socket;
	DataWriter writer;
	DataReader reader;

	// 接続する
	private async void btn_findDevice_Click(object sender, RoutedEventArgs e)
	{
		string selector = RfcommDeviceService.GetDeviceSelector(RfcommServiceId.FromUuid(serviceGuid));
		DeviceInformationCollection collection = await DeviceInformation.FindAllAsync(selector);
		if (collection.Count > 0)
		{
			DeviceInformation info = collection.First();
			rfcommService = await RfcommDeviceService.FromIdAsync(info.Id);

			socket = new StreamSocket();
			await socket.ConnectAsync(rfcommService.ConnectionHostName, rfcommService.ConnectionServiceName);
			writer = new DataWriter(socket.OutputStream);
			reader = new DataReader(socket.InputStream);
			textOut.Text = "接続しました";
		}
		else
		{
			MessageDialog dialog = new MessageDialog("デバイスが見つかりませんでした");
			await dialog.ShowAsync();
		}
	}
	// 切断する
	private void btn_close_Click(object sender, RoutedEventArgs e)
	{
		writer.Dispose();
		reader.Dispose();
	}

	// 送信する
	private async void btn_sendMessage_Click(object sender, RoutedEventArgs e)
	{
		// 8文字にして送る
		string text = textIn.Text;
		await SendCommand( text );
	}
	// コマンド送信
	async Task SendCommand(string text)
	{
		textIn.Text = text;
		// 8文字にして送る
		if (text.Length < 8)
		{
			text = text.PadRight(8, '*');
		}
		else
		{
			text = text.Substring(0, 8);
		}
		writer.WriteString(text);
		await writer.StoreAsync();
		// そのまま受信待ち
		var res = reader.LoadAsync(8);
		res.Completed = async delegate
		{
			await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
				string text2 = reader.ReadString(8);
				textOut.Text = text2;
			});
		};
	}

	private async void clickM1on(object sender, RoutedEventArgs e)
	{
		await SendCommand("m1on");
	}

	private async void clickM1off(object sender, RoutedEventArgs e)
	{
		await SendCommand("m1off");
	}
}

基本は、がりっちさんの記事 http://garicchi.com/?p=17111 と変わりません。デバイスを見つけて、最初のデバイスに自動的に接続します。最初の1回だけはストアアプリから接続許可を求めるダイアログが出ます。

あと、RFCOMM を使うために Package.appxmanifest に以下のように追加しておきます。

  <Capabilities>
    <Capability Name="internetClient" />
    <m2:DeviceCapability Name="bluetooth.rfcomm">
      <m2:Device Id="any">
        <m2:Function Type="serviceId:00001101-0000-1000-8000-00805f9b34fb" />
      </m2:Device>
    </m2:DeviceCapability>
  </Capabilities>

うまくできあがると、m1on/m1off のボタンを押すことでモーターが動いたり止まったりします。ここは LED で動かしてて確認してもよいですね。ブレッドボード上でモーターが動いても何も面白くない(娘談)なので、ええ、キャタピラを付けてコントローラーで制御するところまでやりますよ。

ちなみに BLE 機器を見つけるだけならばペアリングが不要(通信には必要?)なので、忘れ物タグとかについているんですね。なるほど。これ Windows 8.1 の場合はまだ見つけるだけでもペアリングが必要で、Windows 10 ではそれに対応するらしいのですが…適当な BLE 対応のスマートフォンを媒介すれば、Windows 8.1 でもできるかなと。まあ、半年後に Windows 10 が出るのでそれ待ちってのもあるし、手元のノートPCにWindows 10 TP 版を入れて確かめてみるってのもありですね。

カテゴリー: 開発, Arduino, WinRT パーマリンク