本来ならば 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[i] = Serial.read();
}
// コマンドを判別
if ( ch[0] == 'm' ) {
if ( ch[1] == '1' ) {
if ( ch[2] == 'o' && ch[3] == '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[i]);
}
}
}
[/code]
<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 版を入れて確かめてみるってのもありですね。