Arduino を無線化(Blutooth)して戦車を作る(ユニバーサル基板編)

AE-DRV8830 と HC-05を連携させてモーターを制御する(ブレッドボード編) | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6964

の続きで、これをユニバーサル基板で作ります。本来ならば、プリント基板を作ってとか、回路図を作ってってことになるのでしょうが、初手なので手作りで半田付け、ってのと最終的には Arduino 用のチップも載せてしまって小型化したかったってのがあります。まあ、やってみた感じでは、ユニバーサル基板で作るのは手作業が大変です…が、感光基盤だと子供がいる家ではできないし、ちょっと考えないと。

材料

  • DRV8830 x2 @170円
  • HC-05 x1 @1,000 円ぐらい
  • オス・メスピン @100円ぐらい?
  • ユニバーサル基板 x1 @270円(昔買った)
  • 抵抗 10kΩ x2
  • コンデンサ 10nF x2

な感じです。まあ、完成品を Amazon.co.jp: Arduino MEGA UNO Duemilanove 最高品質 用の L293D モーター シールド ボード: DIY・工具 あたりで買うのが手っ取り早いのですが(これは、ひどく安いけど、1,000円から2,000円ぐらいです。秋月電子で DRV8830 のキット 650円 を2つ買うってのもありです。本来ならばターミナルブロックを使って給電したり、モーターを回したりすればいいのですが、手元になかったのでピンヘッダで代用。どうせ、Arduino からジャンパーピンを差してテストするので、このほうがやりやすいです。

DRV8830 を使うといいのは、I2C で通信ができるので、通信回線が SCL/SDA の 2本だけで済むことです。L293D を使ったモータードライバだと、モーター2個でGPIO 経由で 4本の線が必要になります。2個くらいだったらそれでもいいけど、4個とか8個とかにふえても SCL/SDA の 2本だけになるから便利ですよね…となっていますが、本当に 4個いけるかどうかは分かりません。モーター駆動のと、信号線の電源が同じになっているので、ノイズが多くてモーターの挙動が信号線に乗ってしまうのは結構問題なんですよね。モーターによってはノイズが乗って、暴走状態になります。もともと、プリンタの駆動系とかを動かすものなので、ミニ四駆とか車輪とかを動かすには向いていないようです。でも、まあ、タミヤのギアボックス付属のモーター FA-130 レベルならば大丈夫でした。

配線

回路図はよくわからないので、ブレッドボードで作ったものを

20150310_02

そのままユニバーサル基板に配置して、

image

配線します(苦笑)

image

配線の美意識のかけらもないものですが、まあ、腐ったコードでも動くコードを乗せておくこともあるし、ひとまず動けば ok 的なものなので、これでいいです。ひとまず動きますから。

これを、Arduino とつなげます。

image

更に、ギアーボックスとつなげます。

image

ブレッドボードじゃなくてわざわざ基板を使っているのにジャンパーピンが錯綜しているのは、Arduino のシールドになっていないからです。これだと、あまりにも壊れやすいので、もうちょっと頑丈につくらないと駄目なので、昨晩 Arduino 用のシールド基板を注文しました。他にも色々と。

どうやって通信するのか?

HC-05 は Bluetooth 2.0 なので、今流行りの BLE ではありません。なので、iPhone から操作することはできないのですが、単純な SPP 通信(シリアル通信)を使って手軽にパソコンとやり取りができます(最終的には、PS3 Dualshock3 のような既存のコントローラーと通信したいところなのですが、これは Raspberry Pi のほうが非常に簡単なのです。たしか、USB ポートがあってロボットを操作する SBDBT とか)。

Arduino + USBホストシールドの実験。 – robo8080のブログ
http://blog.goo.ne.jp/roboz80/e/9d2fc6e1266932f7ace682b43393217b

でもって、手元の HC-05 は Bluetooth シリアル変換モジュールなので、そのまま Serial を使うことができます。

Arduino のスケッチ

#include <Wire.h>

const int DRV8830a = 0xC8 >> 1 ; // 0x64;
const int DRV8830b = 0xC6 >> 1 ; // 0x63;
const int FAULTn = 13 ;
const int LED  = 12 ;

int writeRegister( byte drv, byte vset, byte data ) {
  int vdata = vset << 2 | data ;
  Wire.beginTransmission( drv );
  Wire.write( 0x00 );
  Wire.write( (vset<<2) + data );
  return Wire.endTransmission();
}

void clearError() {
  Wire.beginTransmission( DRV8830a );
  Wire.write(0x01);
  Wire.write(0x80);
}

void checkError() {
  if ( digitalRead(FAULTn) == HIGH ) {
    return ;
  }
  Wire.beginTransmission( DRV8830a );
  Wire.write(0x01);
  Wire.endTransmission();
  
  Wire.requestFrom( DRV8830a, 1 );
  byte error = Wire.read();
  Serial.println( error, BIN);
  if ( error & 0b00000011 ) {
    Serial.println("over current" );
  } else if ( error & 0b00000101 ) {
    Serial.println("under voltage" );
  } else if ( error & 0b00001001 ) {
    Serial.println("over heat" );
  } else if ( error & 0b00010001 ) {
    Serial.println("limit current" );
  }
  clearError();
}

int mode = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode( FAULTn, INPUT );
  pinMode( LED,  OUTPUT );
  Wire.begin();
  Serial.begin(9600);
  Serial.println( "Motor Standby" );
  Serial.println( DRV8830a, HEX);
  Serial.println( DRV8830b, HEX);
  writeRegister( DRV8830a, 0x00, 0x00 );
  writeRegister( DRV8830b, 0x00, 0x00 );
  delay( 2000 );
}

void loop() {
  // put your main code here, to run repeatedly:
  
  int len = Serial.available();
  if ( len < 2 ) return ;
  int type = Serial.read();   // M or L
  int num  = Serial.read();   // MF/MB/M0, L0/L1

  if ( type == 'M' || type == 'N') {
    int mode = 0;
    switch ( num ) {
      case '0': mode = 0; break;
      case 'F': mode = 1; break;
      case 'B': mode = 2; break;
      default: mode = 0; break;
    }
    switch ( mode ) {
      case 0: 
        Serial.println("motor standby" );
        writeRegister( type == 'M'? DRV8830a: DRV8830b,  0x00, 0x00 );
        break;
      case 1:
        Serial.println("motor forward" );
         writeRegister( type == 'M'? DRV8830a: DRV8830b,  0x15, 0x02 );
        checkError();
        // delay( 2000 );
        break;
      case 2:
        Serial.println("motor back" );
         writeRegister( type == 'M'? DRV8830a: DRV8830b,  0x15, 0x01 );
        checkError();
        // delay( 2000 );
        break;
    }
  }
  if ( type == 'L' ) {
    Serial.println("LED on/off" );
    int mode = 0;
    switch ( num ) {
      case '0': mode = 0; break;
      case '1': mode = 1; break;
      default: break;
    }
    if ( mode == 0 ) {
        digitalWrite(LED, LOW );
    } else {
        digitalWrite(LED, HIGH );
    }
  }
}

ブレッドボード用に作ったものなので、エラーチェックの FAULTn と LED のコードが入っていますが、”MF” とか “MB” とかいう自作のコマンドを使ってモーターをコントロールします。

Windows ストアアプリから操作する

Android からやるのが見栄えがいいのですが、まずは Windows ストアアプリからやります。

Arduino で Bluetooth シリアル変換モジュール(HC-05)を使う | Moonmile Solutions Blog
http://www.moonmile.net/blog/archives/6819

と同じように Package.appxmanifest を設定したあとに、接続とコマンド送信部分を書きます。

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 async void clickMF(object sender, RoutedEventArgs e)
{
    writer.WriteString("MF");
    await writer.StoreAsync();
}
private async void clickMB(object sender, RoutedEventArgs e)
{
    writer.WriteString("MB");
    await writer.StoreAsync();
}
private async void clickM0(object sender, RoutedEventArgs e)
{
    writer.WriteString("M0");
    await writer.StoreAsync();
}

private async void clickNF(object sender, RoutedEventArgs e)
{
    writer.WriteString("NF");
    await writer.StoreAsync();
}
private async void clickNB(object sender, RoutedEventArgs e)
{
    writer.WriteString("NB");
    await writer.StoreAsync();
}
private async void clickN0(object sender, RoutedEventArgs e)
{
    writer.WriteString("N0");
    await writer.StoreAsync();
}

画面はボタンを並べただけ。

image

これだと、Arduino 側からフィードバックがないので、様子がわからないのですが、それなりに動きます。あと、DRV8830 はモーターに流れる電圧を変えることができるので前進後進だけではなく、スピードを変えることができます。このあたりを入れて Arduino のスケッチとストアアプリのコードを変えると結構いけるかなと。ああ、あとバーンと鳴るとか、LED を光らせるとかギミック用のコマンドもいれないと。

で、これは Windows ストアアプリで作ったけど、デスクトップアプリ(WinフォームとかWPFとか)でも作れます。次は、Windows のコンソールアプリで RFCOMM を利用する | Moonmile Solutions Blog を使って WPF アプリに書き直してみます。

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

Arduino を無線化(Blutooth)して戦車を作る(ユニバーサル基板編) への2件のフィードバック

  1. tonye Lekara のコメント:

    you did well even if i cant understand ur language,the picture are enough,, please can you tell me how to configure bluetooth

コメントは停止中です。