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

オシロスコープを手に入れた

ついにオシロスコープを買っちゃいました。 と言っても、DSO QUADと言うポータブルタイプの

記事を読む

no image

Softmodem Terminal 公開しました。

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

記事を読む

Androidから米粒AVRへデータを送る

米粒AVRでSoftModem的なこと その2

前回は「米粒AVRからAndroidへデータを送る」ことを試しました。 今回はその逆の「And

記事を読む

no image

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

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

記事を読む

S2 SoundIR analyzer

赤外線リモコン受信機(イヤホンジャック接続)のアプリ

 前回の赤外線リモコン受信機(イヤホンジャック接続)の回路 を使う為のAndroidア

記事を読む

Arduino + STTS751

パソコンで温度計

ありきたりのPC温度計ですが、なんとなく作りたくなったので作ってみる。 コントローラーは手軽な

記事を読む

raspi-config

Raspbianの最初の設定

  Raspbianのインストール後にraspi-configを使って行う最初の設定

記事を読む

no image

米粒AVR(ATtiny10)

通称「米粒AVR」で知られるTiny10を使ってみたくて、秋月の通販で買ってみました。 超小型

記事を読む

no image

Android+Arduinoでリモコン3 その2(AndroidAccessory接続)

何度か、Android+リモコンのネタを書いたことがあるのですが、今回はAndroid Access

記事を読む

no image

赤外線リモコン受信機(イヤホンジャック接続)を作ってみた

最近、このブログ何も書いて無かったので、作成中の物の紹介・・・  これは、Andro

記事を読む

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 ↑