.NET対応組み込みデバイス「Netduino」入門(11)
Bluetoothで遠隔操作しよう
BluetoothでPCと連携し、電源もバッテリー給電とすることで、移動体などへの搭載も可能なコードレス仕様のDCモーター制御を実現してみよう。
前回はDCモーターの制御を取り上げたが、制御といってもあらかじめプログラミングしたとおりに回転数を制御するだけだった。今回は、Netduinoデバイス上にBluetoothデバイスを搭載して、PC(※Bluetoothデバイス搭載)側のUWP(Universal Windows Platform)アプリからBluetooth経由でのDCモーター制御にチャレンジする。
Bluetooth接続について
NetduinoでBluetooth通信を行う方法はいくつかあるが、今回はランニングエレクトロニクスのSBDBTを使ってBluetooth通信をシリアル通信に変換して接続する方法を使う。
SBDBTの特徴は、USBコネクターにBluetoothドングルを挿すことで、シリアル接続によりPCとBluetooth通信が行える点である。また、SBDBT自体が小型のマイコンで、出荷時にはBTstack(=公式Bluetoothスタックの一実装)を使用したBluetooth用のファームウェアが書き込まれているが、ファームウェアを書き換えることで、さまざまな用途に転用できる点も面白い。例えば今回のサンプルでは、初期出荷のBluetooth用ファームウェア(正確にはBluetooth SSPサーバー用ファームウェア)を使用したが、Bluetooth Low Energy(以下、BLE)用のファームウェアに書き換えてBLE対応のドングルを使うことで、より消費電力の少ないBLE接続を行うことも可能だ。
SBDBTのスペック
項目 | SBDBT | SBDBT 5V |
---|---|---|
CPU | PIC24FJ64GB004T-I/PT | PIC24FJ64GB004T-I/PT |
動作周波数 | 32MHz | 32MHz |
入力電圧 | 2.55~3.6V | 2.6~5.5V |
消費電流 | 30mA | 30mA |
USB電圧 | 3.3V | 5.0V |
SBDBTのピンについて
SBDBTの各ピンの意味をデータシートからピックアップした結果が次のようだ。
ピン | 用途 | 接続先 |
---|---|---|
1 | - | - |
2 | VDD | 3.3V |
3 | GND | GND |
4 | - | - |
5 | - | - |
6 | RTS | CTSと直結 |
7 | TX | デジタル0番ピン(RX受信) |
8 | RX | デジタル1番ピン(TX送信) |
9 | CTS | RTSと直結 |
10 | - | - |
SBDBTは3.3V駆動であり、接続するBluetoothドングルも3.3V駆動が前提だ。PC用のBluetoothドングルのスペックは5Vだが、SBDBTのユーザーマニュアルには3.3V駆動で動作確認済みのBluetoothドングルが掲載されている。今回はその中から、PLANEX BT-Micro4を使ってみた。
SBDBTを使った回路例
前回のMP4207の回路が組んであるブレッドボードにSBDBTのピンに合わせて配線を行うと次のようになる。
今回もモーター部分についてはプラレール車両に搭載されているFA130モーターに対してブレッドボートを経由してMP4207の出力ピンを接続する。
SBDBT制御用ソースコード
プロジェクトの作成方法は、これまでと同様なので割愛する(第3回などを参考にされたい。本稿の例では、プロジェクト名はVB.NET用は「SBDBTMotorVB」、C#用は「SBDBTMotorCS」とした)。もし、Visual Studio 2015をお使いの場合は番外コラム01も参照にしてほしい。
MP4207を使うので、PWM出力用クラスライブラリはSecretLabs.NETMF.Hardware.PWMライブラリを使用する。そのため、参照設定で「SecretLabs.NETMF.Hardware.PWM」ライブラリの参照を削除し、「SecretLabs.NETMF.Hardware.PWM」ライブラリの参照を追加する必要がある。
このサンプルのコードは次のとおりだ。
Imports System.IO.Ports
Imports Microsoft.SPOT.Hardware
Imports SecretLabs.NETMF.Hardware
Imports SecretLabs.NETMF.Hardware.Netduino
Module Module1
Private MotorPower As UInteger = 0
Sub Main()
Dim power = New PWM(Pins.GPIO_PIN_D9)
Dim serial = New SerialPort("COM1", 9800, Parity.None, 8, StopBits.One)
Dim motorIn8 = New OutputPort(Pins.GPIO_PIN_D8, False)
AddHandler Serial.DataReceived, AddressOf serial_DataReceived
motorIn8.Write(True)
Do While (True)
Try
Dim value = MotorPower
If (Not Serial.IsOpen) Then
Serial.Open()
End If
Power.SetPulse(20000, value)
Thread.Sleep(1000)
Catch ex As Exception
Dim mes = ex.Message
End Try
Loop
End Sub
Private Sub serial_DataReceived(sender As Object, e As SerialDataReceivedEventArgs)
Try
Dim serial = CType(sender, SerialPort)
Dim data(10) As Byte
Dim cmd = serial.Read(data, 0, data.Length)
MotorPower = CType(CType(data(0), UInteger) * 100, UInteger)
If (MotorPower > 20000) Then
MotorPower = 20000
End If
Catch ex As Exception
Dim mes = ex.Message
End Try
End Sub
End Module
Namespace Global.System
<AttributeUsageAttribute(AttributeTargets.Method)>
Public NotInheritable Class STAThreadAttribute
Inherits Attribute
End Class
End Namespace
|
using System.IO.Ports;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;
using System.Threading;
using System;
namespace SBDBTMotorCS
{
public class Program
{
private static uint MotorPower = 0;
public static void Main()
{
var serial = new SerialPort("COM1", 9800, Parity.None, 8, StopBits.One);
var power = new PWM(Pins.GPIO_PIN_D9);
var motorIn8 = new OutputPort(Pins.GPIO_PIN_D8, false);
serial.DataReceived += Serial_DataReceived;
motorIn8.Write(true);
while (true)
{
try
{
var value = MotorPower;
if (!serial.IsOpen)
{
serial.Open();
}
power.SetPulse(20000, value);
Thread.Sleep(1000);
}
catch (Exception ex)
{
var mes = ex.Message;
}
}
}
private static void Serial_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
var serial = (SerialPort)sender;
var data = new byte[10];
var cmd = serial.Read(data, 0, data.Length);
MotorPower = (uint)((uint)data[0] * 100);
if (MotorPower > 20000)
{
MotorPower = 20000;
}
}
catch (Exception ex)
{
var mes = ex.Message;
}
}
}
}
|
今回のサンプルではデジタル0番
ピンとデジタル1番
ピンを使っているので、シリアルポートはCOM1になる。
PC側コード
PC側のアプリはUWPアプリとして作成する。Windows 10やWindows 10 MobileなどUniversal Windows Platformが稼働するデバイスでBluetooth通信ができるものならば大きさは問わず動くはずだ。作成方法やコードの全体像は割愛するが、Bluetoothでデータを送信する部分は次のようになる。
Public Async Function Connect() As Task
Dim name = Common.Settings.DeviceName
If (name IsNot Nothing) Then
' 保存されたBluetoothデバイス名と一致するデバイス情報を取得しデータを送信する
Dim serviceInfos = Await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort))
For Each serviceInfo In serviceInfos
If (serviceInfo.Name = name) Then
Await Connect(serviceInfo)
Exit For
End If
Next
End If
End Function
Public Async Function Connect(serviceInfo As DeviceInformation) As Task
Try
' 指定されたデバイス情報で接続を行う
If (DeviceService Is Nothing) Then
DeviceService = Await RfcommDeviceService.FromIdAsync(serviceInfo.Id)
BtSocket = New StreamSocket()
Await BtSocket.ConnectAsync(
Me.DeviceService.ConnectionHostName,
Me.DeviceService.ConnectionServiceName,
SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication)
Writer = New DataWriter(BtSocket.OutputStream)
Me.Message = "Connected " + DeviceService.ConnectionHostName.DisplayName
End If
' 接続されたBluetoothデバイスにデータを送信する
SetPower(Me.Power)
Catch ex As Exception
Me.Message = ex.Message
DeviceService = Nothing
End Try
End Function
Private Async Sub SetPower(power As Integer?)
Try
If (DeviceService IsNot Nothing) Then
' 0~200の値を送信する
Dim moterPower = If(power <= 200, power, 200)
Dim byteArray() As Byte = {CType(moterPower, Byte)}
Writer.WriteBytes(byteArray)
Dim sendResult = Await Writer.StoreAsync()
End If
Catch ex As Exception
Me.Message = ex.Message
DeviceService = Nothing
End Try
End Sub
|
public async Task Connect()
{
var name = Common.Settings.DeviceName;
if (name != null)
{
// 保存されたBluetoothデバイス名と一致するデバイス情報を取得しデータを送信する
var serviceInfos = await DeviceInformation.FindAllAsync(RfcommDeviceService.GetDeviceSelector(RfcommServiceId.SerialPort));
foreach (var serviceInfo in serviceInfos)
{
if (serviceInfo.Name == name)
{
await Connect(serviceInfo);
break;
}
}
}
}
private async Task Connect(DeviceInformation serviceInfo)
{
try
{
// 指定されたデバイス情報で接続を行う
if (DeviceService == null)
{
DeviceService = await RfcommDeviceService.FromIdAsync(serviceInfo.Id);
BtSocket = new StreamSocket();
await BtSocket.ConnectAsync(
this.DeviceService.ConnectionHostName,
this.DeviceService.ConnectionServiceName,
SocketProtectionLevel.BluetoothEncryptionAllowNullAuthentication);
Writer = new DataWriter(BtSocket.OutputStream);
this.Message = "Connected " + DeviceService.ConnectionHostName.DisplayName;
}
// 接続されたBluetoothデバイスにデータを送信する
SetPower(this.Power);
}
catch (Exception ex)
{
this.Message = ex.Message;
DeviceService = null;
}
}
private async void SetPower(int? power)
{
try
{
if (DeviceService != null)
{
// 0~200の値を送信する
var moterPower = (power <= 200 ? power : 200);
byte[] byteArray = new byte[] { (byte)moterPower };
Writer.WriteBytes(byteArray);
var sendResult = await Writer.StoreAsync();
}
}
catch (Exception ex)
{
this.Message = ex.Message;
DeviceService = null;
}
}
|
アプリ実行の前準備
本サンプルを実行するには、まず、Netduino側サンプルを実行しておく。このとき、通信が正しく行われるかが判断しやすいように、USBでNetduinoに接続し、Netduino側コードのSerial_DataReceivedプロシージャの先頭にブレークポイントを設定した上でNetduino側サンプルをデバッグ実行しておくとよいだろう。
Netduino側が動いたら、Windows 10の[スタート]メニューの[設定]から[デバイス]-[Bluetooth]の設定で、NetduinoのBluetoothデバイスとペアリングする。SBDBTを使っている場合、デバイス名は必ず「SBDBT-」から始まっているので識別しやすい(図3)。また、パスコードは「0000」となる。
アプリ実行
ペアリングが終わったらWindows側サンプルを実行する。
画面上のBluetoothデバイス名にはペアリングしたデバイス名を指定する(図4)。ボタンをクリックすれば、Bluetooth通信が行われ、ボタンに応じてNetduino側のモーター回転数が変化する。
なお、最初に通信が行われるときにアクセス許可の画面が表示されるので「はい」をクリックする。
【動画】Bluetooth制御でのモーター制御
まとめ
今回はPCからNetduino側にデータを送信していたが、Netduino側からPCにデータ送信するのも同様に簡単で、Read
メソッドの代わりにWrite
メソッドを実行すればよい。
このようにSBDBTのおかげでNetduino側ではBluetooth通信ということを全く意識せずにPCと接続することができた。
次回は、littleBitsとNetduinoを組み合わせて、ブレッドボード以上に簡単な回路作成にチャレンジしてみたい。本連載で使用する予定にしているのは、littleBits_Base Kitに加えて、追加購入が必要な2個のPROTOモジュールだ(※あくまで予定であり、実際の記事では異なるパーツが必要になる場合がある点をご了承いただきたい)。
なお、今回、littleBitsの代理店であるゼッタリンクスさんのご厚意により、2015年12月31日までの期間限定で何回でも利用可能なBuild Insider読者専用の割引クーポンを提供していただけた。ゼッタリンクス・オンラインショップの[お支払方法の設定]画面でクーポンコード「Build_Insider」を入力すれば、オンラインショップ内の全製品が8%割引となるので、ぜひご利用いただきたい。
※以下では、本稿の前後を合わせて5回分(第10回~第14回)のみ表示しています。
連載の全タイトルを参照するには、[この記事の連載 INDEX]を参照してください。
10. Windows 10+Visual Studio 2015でNetduinoアプリを動かすには?
本シリーズのNetduinoサンプルをWindows 10+Visual Studio 2015で動かす方法と注意点を番外編のコラムとしてまとめた。
12. 【現在、表示中】≫ Bluetoothで遠隔操作しよう
BluetoothでPCと連携し、電源もバッテリー給電とすることで、移動体などへの搭載も可能なコードレス仕様のDCモーター制御を実現してみよう。
13. littleBitsではんだ付けなしの電子工作を実現
磁石で電子回路をつないで電子工作が行えるlittleBits。Netduinoと組み合わせると、どのような電子工作が実現できるのか? その可能性を探る。
14. MESHとNetduinoでiOSデバイスとの連携を実現
SONYのスマートDIYキット「MESH」とは? さまざまな連携が実現可能なMESHを使って、NetduinoとiPadを連携をさせてみよう。