Bimeji Client for Arduino

前回紹介したWimeji Client for Arduinoの最後で予告していた、Wimeji clientのBluetooth版が完成したのでご報告。

Bimeji client for Arduino

概要

  • これはArduinoを使ったAndroid向けの自作ハードウェアキーボードです
  • 自身で、Arduinoの配線をする必要があります。
  • Bluetoothなのでバッテリー駆動させれば、どんな場所でも利用可能です
  • PS/2接続タイプのキーボードなら、自分好みのキーボードが利用可能です

これらの機能を実現する為に、アンドロイドアプリ adamrocker氏作のSimeji と esmasui氏作のBimejiSPP版を利用しています。

必要な部品

今回使った主な部品は以下の通り。
部品だけで、13,000円以上(目安)もかかってしまって随分高いBTキーボードです><

品名

個数 価格
Arduino Duemilanove 1 3,200 円
BT-MOD100R(Bluetoothモジュール) 1 7,500 円
80FG970(BT-MOD100R用アダプタ) 1 1,300 円
PS/2(mini-DIN6) コネクター 1 120円
PS/2 キーボード 1 1,000円程

 PS/2コネクターは、僕は不要マザーボードからもぎ取りましたが、千石電商では6P ミニDINソケット(基板用) 120円で売られているようです。
 

配線(回路図)

Bimeji Client 回路図

BTモジュールは、こちら(Android+Bluetooth+Arduino)で紹介したBT-MOD100Rを利用しています。
他のモジュールを使う場合も、TXを6PINにRXを5PINに接続して、ソースのスピード設定部分を変更すれば利用できると思います。

ps2keyboardキーアサイン(mini-din6)
(間違えやすいのでご注意を)

Bimeji Client 写真1 Bimeji Client 写真2
完成写真です。今回はユニバーサル基板を割って、自作シールド化してみました。
PS2コネクタは、前回利用した物で、不要マザーボードから無理矢理剥がし取った物。1段高くなっていて不細工です。

ソース

Arduinoのソースです。WimejiとBimeji両対応のソースとなっています。
このままでも動作しますが、Bimejiで利用する場合は冒頭の #include <Ethernet.h> を削除すると、コンパイル後のコードが多少小さくなります。
逆にWimejiで利用する場合は冒頭の #include <NewSoftSerial.h> を削除すれば、こちらも多少コードが小さくなります。

#include <NewSoftSerial.h>
#include <Ethernet.h>
#include <ps2.h>

//#define DEBUG

#define USB_BAUD 9600UL    // USB Serial Baudrate
#define BT_BAUD 9600UL     // Bluetooth Connection Baudrate

#define PS2_CLK_PIN     3
#define PS2_DAT_PIN     4
#define BT_TX_PIN       5
#define BT_RX_PIN       6

PS2 kbd(PS2_CLK_PIN, PS2_DAT_PIN);

#ifdef Ethernet_h
// 各自の環境に合わせて編集してください。
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    byte ip[] = { 192, 168, 1, 25 };
    byte server[] = { 192, 168, 1, 12 };
    Client client(server, 10000);
#endif

#ifdef NewSoftSerial_h
    NewSoftSerial BTSerial(BT_RX_PIN,BT_TX_PIN);
#endif

int kcLength,kcExLength;
// http://www.simandl.cz/stranky/elektro/keyboard/keyboard_a.htm
byte ps2_kc[] =
{
  0x16, 0x1e, 0x26, 0x25, 0x2e, 0x36, 0x3d, 0x3e, 0x46, 0x45, 0x4e, 0x55, 0x6A, 0x66,
  0x0D, 0x15, 0x1D, 0x24, 0x2D, 0x2C, 0x35, 0x3C, 0x43, 0x44, 0x4D, 0x54, 0x5B, 0x5D,
  0x58, 0x1C, 0x1B, 0x23, 0x2B, 0x34, 0x33, 0x3B, 0x42, 0x4B, 0x4C, 0x52, 0x5A,
  0x12, 0x1A, 0x22, 0x21, 0x2A, 0x32, 0x31, 0x3A, 0x41, 0x49, 0x4A, 0x51, 0x59,
  0x14, 0x11, 0x29, 0x76,
  0x05, 0x06, 0x04, 0x0C, 0x03, 0x0B, 0x83, 0x0A, 0x01, 0x09, 0x78, 0x07,
  0x77, 0x7B, 0x71, 0x7C, 0x79,
  0x70, 0x69, 0x72, 0x7A, 0x6B, 0x73, 0x74, 0x6C, 0x75, 0x7D,
  0x84, 0x7E,
  0x0E, 0x67, 0x64, 0x13,
};
byte send_kch[] =
{
  '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '^','', 8 ,
   9 , 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '@', '[', ']',
   0 , 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', ':', 10 ,
   0 , 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', '', 0 ,
   0 ,  0 , ' ', 27 ,
   0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
   0 , '-', '.', '*', '+',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   0 ,  0 ,
   0 ,  0 ,  0 ,  0 ,
};
byte send_kch_s[] =
{
  '!', '"', '#', '$', '%', '&',''', '(', ')',  0 , '=', '~', '|', 0 ,
   0 , 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '@', '[', ']',
   0 , 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ';', ':',  0 ,
   0 , 'Z', 'X', 'C', 'V', 'B', 'N', 'M', '<', '>', '?', '_',  0 ,
   0 ,  0 ,  0 ,  0 ,
   0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,
   0 , '-', '.', '*', '+',
  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   0 ,  0 ,
   0 ,  0 ,  0 ,  0 ,
};
word send_kc[] =
{
   0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010, 0x0007, 0x0045, 0x390D, 0x0049, 0x0043,
   0x0000, 0x002D, 0x0033, 0x0021, 0x002E, 0x0030, 0x0035, 0x0031, 0x0025, 0x002B, 0x002C, 0x004D, 0x0047, 0x0048,
   0x0000, 0x001D, 0x002F, 0x0020, 0x0022, 0x0023, 0x0024, 0x0026, 0x0027, 0x0028, 0x004A, 0x3928, 0x0042,
   0x0000, 0x0036, 0x0034, 0x001F, 0x0032, 0x001E, 0x002A, 0x0029, 0x0037, 0x0038, 0x004C, 0x0049, 0x0000,
   0x0000, 0x0000, 0x003E, 0x0004,
   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0045, 0x0038, 0x0011, 0x0051,
   0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F, 0x0010,
   0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
};
word send_kc_s[] =
{
   0x3908, 0x3921, 0x390A, 0x390B, 0x390C, 0x390E, 0x394b, 0x3910, 0x3907, 0x3933, 0x0046, 0x390D, 0x392D, 0x0000,
   0x0000, 0x3B2D, 0x3B33, 0x3B21, 0x3B2E, 0x3B30, 0x3B35, 0x3B31, 0x3B25, 0x3B2B, 0x3B2C, 0x392E, 0x3930, 0x3935,
   0x0000, 0x3B1D, 0x3B2F, 0x3B20, 0x3B22, 0x3B23, 0x3B24, 0x3B26, 0x3B27, 0x3B28, 0x0051, 0x0011, 0x0000,
   0x0000, 0x3B36, 0x3B34, 0x3B1F, 0x3B32, 0x3B1E, 0x3B2A, 0x3B29, 0x3924, 0x3926, 0x394C, 0x3931, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   0x0000, 0x0000,
   0x0000, 0x0000, 0x0000, 0x0000,
};

byte ps2_kc_ex[] =
{
   0x4A,
   0x70, 0x6c, 0x7d, 0x71, 0x69, 0x7a,
   0x75, 0x6b, 0x74, 0x72,
   0x1F, 0x27,
};

byte send_kch_ex[] =
{
   '/',
   155, 36 , 19 , 127, 35 , 34 ,
   82 , 80 , 79 , 81 ,
    0 ,  0 ,
};

word send_kc_ex[] =
{
   0x004C,
   0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
   0x0013, 0x0015, 0x0016, 0x001C,
   0x0000, 0x0000,
};

void kbd_init()
{
    char ack;

    kbd.write(0xff);  // send reset code
    ack = kbd.read();  // byte, kbd does self test
    ack = kbd.read();  // another ack when self test is done
    kcLength=sizeof(ps2_kc);
    kcExLength=sizeof(ps2_kc_ex);
}
void setup()
{
    // Serial setup
#ifdef DEBUG
    Serial.begin(USB_BAUD);
    Serial.flush();
    Serial.println("Bimeji Client");
#endif

    // Bluetooth側 Serial setup
#ifdef NewSoftSerial_h
    BTSerial.begin(BT_BAUD);
    BTSerial.flush();
#endif

#ifdef Ethernet_h
    Ethernet.begin(mac, ip);
    client.connect();
#endif

    kbd_init();

#ifdef DEBUG
    Serial.println("---Table Size---");
    Serial.print("KeyCode=");
    Serial.println(sizeof(ps2_kc), DEC);
    Serial.print("KeyCodeEx=");
    Serial.println(sizeof(ps2_kc_ex), DEC);
    Serial.println("---Start---");
#endif
}

void loop()
{
    unsigned char code;
    boolean release;
    boolean ext;
    boolean shift;
    shift=false;

    for (;;)
    {
        ext=false;
        release=false;
        code = kbd.read();

        if(code==0xE0)
        {
            ext=true;
            code = kbd.read();
        }
        if(code==0xF0)
        {
            release=true;
            code = kbd.read();
        }

        if(ext)
        {
            if(code==0x11 || code==0x14 || code==0x4A || code==0x5A)  ext=false;
        }

        // Shift
        if(code==0x12 || code==0x59)
        {
            shift=(release)?false:true;
            continue;
        }

#ifdef DEBUG
        if(release)  Serial.print("OnKeyUp   ");
        else         Serial.print("OnKeyDown ");

        Serial.print("0x");
        Serial.print(code, HEX);

        if(ext)    Serial.print("(ex)");
        if(shift)    Serial.print("+shift");
#endif

        int i=0;
        if(!ext && !release)
        {
            for(i=0;i<kcLength;i++)
            {
                if(code==ps2_kc[i])  break;
            }
            if(i<kcLength)
            {
                if(!shift)
                {
                    SendKeyCodeET(send_kc[i]);
                    SendKeyCodeBT(send_kch[i]);
                }
                else
                {
                    SendKeyCodeET(send_kc_s[i]);
                    SendKeyCodeBT(send_kch_s[i]);
                }
            }
        }
        else if(ext && !release)
        {
            for(i=0;i<kcExLength;i++)
            {
                if(code==ps2_kc_ex[i])  break;
            }
            if(i<kcExLength)
            {
                if(!shift)
                {
                    SendKeyCodeET(send_kc_ex[i]);
                    SendKeyCodeBT(send_kch_ex[i]);
                }
            }
        }
#ifdef DEBUG
        Serial.println("");
#endif
    }
}
void SendKeyCodeET(word code)
{
#ifdef Ethernet_h
    byte c;
    c=(code>>8)&0xFF;
    if(c)
    {
        client.write((byte)0x00);
        client.write((byte)0x00);
        client.write((byte)0x00);
        client.write(c);
    }
    c=code&0xFF;
    if(c)
    {
        client.write((byte)0x00);
        client.write((byte)0x00);
        client.write((byte)0x00);
        client.write(c);
    }
#endif
}
void SendKeyCodeBT(byte ch)
{
#ifdef NewSoftSerial_h
    if(ch)
    {
        BTSerial.print(ch);
    }
#endif
}

このソースでは、PS2ライブラリNewSoftSerialライブラリを利用しています。
コンパイルするには、これらのライブラリを有効にしておく必要があります。

使い方

Simeji

今まで別プロジェクト扱いだったbimeji/wimejiが、最新版のsimejiからはintentで文字コードを受け付けるBroadcastReceiverが正式採用されたようです。 今まで野良アプリをインストールする必要がありましたが、アンドロイドマーケットにアップされているsimejiで対応されたので便利です。

simejiの設定画面で【外部接続】にチェックを入れておきます。

simeji設定

Bimeji SPP版

今回の自作ハードウェアキーボードとsimejiを繋いでくれるアプリが、bimeji SPP版です。
bluetoothから受け取った文字コードを、intentとしてsimejiに投げてくれるアプリです。

esmasuiさんのページ(BT接続できるSimeji)で公開されています。
apkファイルをダウンロード・インストールします。

起動してconnectで、接続します。

bimeji spp bimeji spp2

 bimejiでconnectが出来れば、入力可能な状態になっています。

最後に

誰が使うでも無いニッチで馬鹿高いデバイスが出来上がりました。
しかし、「アンドロイドでこんなことが出来る」と言う実験が出来たことは、無駄では無かったと思っています。

実際にこのデバイスを使ってキーボード入力するには、もう少し作り込みが必要な感じです。
必要な人がいれば、ここで公開しているソースは自由にして頂いて結構です。

 

関連記事

no image

Softmodem Terminal 公開しました。

需要がどれほど有るのか疑問に思いつつ、以前のエントリ(AndroidでSoftModemを試してみた

記事を読む

SDカード・マイクロSDカード

ArduinoでSDカード

電子工作で大量のデータを保存する方法を調べていると、 Arduinoでも比較的簡単にSDカードを

記事を読む

熱湯の温度計測実験

パソコンで温度計 #3

今回は、I2C接続の温度センサー STTS751をケーブルを使ってArduinoに接続できるよう

記事を読む

no image

Android Open Accessory開発時のWiFiデバッグ

Android Open Accessory開発時のデバッグは、ADBをWiFiで接続しろと、USB

記事を読む

Raspberry Pi 起動SDカード

Raspberry Piの起動SDカードを準備する

先日入手したRaspberry PiでLinuxを起動する為のSDカードを準備します。 Ras

記事を読む

no image

USBホストケーブルとUSBケーブルの違い

USBホストケーブル(OTGケーブル)と普通のUSBケーブルの違いは、USBホストケーブルとして振る

記事を読む

Raspberry Pi

Raspberry Piを買った

先日、Raspberry Pi(ラズベリーパイ)を買いました。 Raspberry Piは噂で

記事を読む

no image

Arduino + USBホストシールド で ADK を試す(その1)

先日Google IOで発表された Android Open Accessory。みなさん知ってます

記事を読む

no image

Android + Bluetoothドングル + PIC24F

@hrdakinori さんと言う方が、PIC24FとBluetoothドングルを使って、Andro

記事を読む

no image

米粒AVRの動作周波数

  米粒AVR(ATtiny10)のデフォルトでは内臓発振器利用の1MHzが指定されてい

記事を読む

Comment (5件)

  1. 高田

    こんにちは。
    製品にしていただければ、非常にありがたいです。
    ゜(-m-)パンパン

    1. Futaba

      コメントありがとうございます
      製品化は難しいですねぇ・・・色々と・・・
      Android 2.x の端末なら、HIDプロファイルのBluetoothキーボードが使えるそうなので、そちらを検討されては如何でしょうか?

  2. 高田

    こんばんは。
    やはり無理ですか(8_8) 。
    Android 2.x の端末で使えるようになるのは確かな情報でしょうか?
    今、私が持っているHT-03Aでは、この先使えるようにならないと言うことですかね(T△T) そんなぁ…
    androidの開発ができればFutabaさんのように試してみるのですが。。。
    羨ましい限りです。

    1. Futaba

      こんばんは
      このBimeji client for arduinoで利用している esmasuiさんのBimeji SPP版は、他にBimeji HID版も公開されています。
      BimejiHID版は、Android 2.x以降対応だそうです。
      僕自身で試してはいませんが、確かな情報です。
      詳しくは氏のブログをご覧下さい。
      http://d.hatena.ne.jp/esmasui/20100112/1263247514

      後、こちらも試した訳ではありませんが、海外製アプリでSPPキーボードに対応したKeyProと言うアプリもあるようです。
      こちらはAndroid 1.5以降対応だったと思います。
      キーボードとアプリで値が張りますが、自作するよりは安いです・・・
      http://jp.androlib.com/android.application.com-mymobilegear-pjqz.aspx

  3. 高田

    ( ^ ^ )/ こんにちは
    情報ありがとうございます。
    申告で忙しくて見ることが出来ませんでした。
    日頃サボっているのでだめですね~!

    教えてもらったサイトを確認してみます。
    ありがとうございましたm(__)m 。

Arduinoで温湿度データロガー
Arduinoで温湿度計 #2

今回は、前回作った温湿度計にRTCモジュールとSDカードアダプタを

Arduinoで温湿度計
Arduinoで温湿度計

秋月電子の温湿度モジュールを使って、温湿度計を作ってみました。 以前

SDカード・マイクロSDカード
ArduinoでSDカード

電子工作で大量のデータを保存する方法を調べていると、 Arduin

秋月電子 リアルタイムクロック(RTC)モジュール
秋月のリアルタイムクロック(RTC)モジュール

今回は秋月電子のI2C接続のリアルタイムクロック(RTC)モジュールを

秋月電子 キャラクタLCD
秋月の小型キャラクタLCD

今回秋月電子で売られている小型のキャラクター液晶2種を買ったので、

PAGE TOP ↑