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

Android+Arduinoでリモコン4(Microbridge接続)

前回AndroidAccessory接続で作った赤外線学習リモコンを、今回はMicrobridge接

記事を読む

秋月電子 キャラクタLCD

秋月の小型キャラクタLCD

今回秋月電子で売られている小型のキャラクター液晶2種を買ったので、ちょっと比較してみる。 買っ

記事を読む

米粒AVRで温度計

米粒AVRで温度計(STTS751使用)

前回までに紹介したI2CライブラリとLCDライブラリを使って作る、温度計のサンプルです。 温度

記事を読む

no image

AndroidにPS2キーボードを繋いでみた

@yishiiさんの素のAndroid端末を外部のキーにより操作する実験と言う記事を参考に、Ardu

記事を読む

Arduinoで温湿度データロガー

Arduinoで温湿度計 #2

今回は、前回作った温湿度計にRTCモジュールとSDカードアダプタを取り付けて温湿度データロガーを

記事を読む

thermometer overlay

パソコンで温度計 #4

前回までに作ったPC温度計のログデータを、計測と同時に撮影した映像にオーバーレイ表示(スーパーイ

記事を読む

no image

AVRISPmk2

米粒AVR(ATtiny10)のプログラム書き込み用にAVRISPmk2を購入しました。 先人

記事を読む

no image

Android + Bluetooth + Arduino

 以前書いた『気になる物』で紹介したBluetoothモジュールですが、本当に気になって実

記事を読む

no image

S2 Resistor Color Code 公開しました。

このアプリは、抵抗のカラーコードから抵抗値を素早く見る為のAndroidアプリです。 4本帯と、5

記事を読む

no image

Android+Arduinoでリモコン3のおまけ

Androidとは関係ないのですが、前回の記事  Android+Arduinoでリモコ

記事を読む

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 ↑