mbedを用いたUSBエアマウスの作成

# はじめに

この記事では、mbedを使ってUSBエアマウスの簡単なプロトタイプを作成する方法を説明します。

# mbedとは

mbedとは、mbed対応ボード（ARM Cortex-Mベース）のための開発フレームワークのことです。オンラインIDE、OS、mbed対応ボードなどを含めたエコシステム全体のことをmbedと呼びます。mbedを使うことで、プロトタイプ開発を迅速に進めることができます。詳細については、[公式ページ](https://www.mbed.com/en/)などを参照してください。

# 作成したUSBエアマウスの使い方

以下に、作成したUSBエアマウスの使い方を説明します。

## マウスカーソルの水平移動

ボードを横方向に傾けると水平方向にマウスカーソルが移動します。また、傾きを検出している間は、LEDが青色に点灯します。

![mouse_move_horizontal.gif](https://qiita-image-store.s3.amazonaws.com/0/46434/e60d3237-4d72-95fa-909c-93f433226173.gif)

## マウスカーソルの垂直移動

ボードを縦方向に傾けると垂直方向にマウスカーソルが移動します。傾きを検出している間は、LEDが青色に点灯します。

![mouse_move_vertical.gif](https://qiita-image-store.s3.amazonaws.com/0/46434/efa404ab-df48-dcb4-24d0-0ca69d8cabbd.gif)

## マウスの右クリック

タッチセンサの右半分をタッチすることで、マウスの右クリックができます。同時にLEDが緑色に点灯します。

![mouse_right_click.gif](https://qiita-image-store.s3.amazonaws.com/0/46434/0bf105b0-1097-dfa0-833f-3dbb0c5fcc4c.gif)

## マウスの左クリック

タッチセンサの左半分をタッチすることで、マウスの左クリックができます。同時にLEDが赤色に点灯します。

![mouse_left_click.gif](https://qiita-image-store.s3.amazonaws.com/0/46434/b1b0a61c-585b-0730-03f9-28902096e7f5.gif)

# USBエアマウスの作成方法

USBエアマウスは、以下の流れで作成しました。

1. FRDM-KL25Zのファームウェアの更新
2. 必要なライブラリのインポート
3. コーディング
4. コンパイル

## FRDM-KL25Z

今回は、mbed対応ボードとして、[FRDM-KL25Z](https://www.switch-science.com/catalog/1287/)を採用しました。FRDM-KL25Zは、以下のような機能を備えています。

* ARM Cortex-M0+
* ３軸加速度センサ
* 静電容量タッチセンサ

mbed FRDM KL25Z 諸元
https://os.mbed.com/users/okini3939/notebook/mbed_frdm_kl25z_jp/

# ファームウェアの更新

FRDM-KL25Z上でmbedを使うために、ファームウェアを更新する必要があります。更新方法については、以下のWebページなど参照してください。

mbed FRDM KL25Z ゲッティングスターテッド
https://os.mbed.com/users/Norisuke/notebook/mbed-frdm-kl25z-Getting-started-jp/

# コーディング

続いて、mbedのオンラインIDE上でC/C++を使って実装を行っていきます。

## mbedのオンラインIDEの使い方

mbedのオンラインIDEの使い方については、以下のWebページなどを参照してください。

mbed入門
https://os.mbed.com/users/RyoheiHagimoto/notebook/mbed_introduction/

## ライブラリのインポート

今回は以下の３つのライブラリを使いました。

1. [USBMouse](https://os.mbed.com/handbook/USBMouse)
2. [タッチセンサ（Touch Sensor）](https://os.mbed.com/handbook/mbed-FRDM-KL25Z-Examples)
3. [加速度センサ（Accelerometer）](https://os.mbed.com/handbook/mbed-FRDM-KL25Z-Examples)

それぞれのWebページで「Import program」のボタンをクリックします。

![import_program.png](https://qiita-image-store.s3.amazonaws.com/0/46434/259522e5-668b-6537-47ce-946b5e665cd3.png)

インポートする際は、Libraryとしてインポートしてください。

![import_library.png](https://qiita-image-store.s3.amazonaws.com/0/46434/7a027b8b-95bf-9213-b184-3fd03fc0a4de.png)

ライブラリとしてインポートした場合、ライブラリ内のmain.cppは不要ですので削除してください。

## コード

今回実装したコードは以下のとおりです。main.cppに以下のコードを記述してください。

```cpp:main.cpp
#include "mbed.h"
#include "MMA8451Q.h"
#include "TSISensor.h"
#include "USBMouse.h"

class LED {
public:
    LED() : _rled(LED_RED), 
            _gled(LED_GREEN), 
            _bled(LED_BLUE) {}
            
    void turnOn(PinName pin) {
        turnOffAll();
        if (pin == LED_RED) {
            _rled = 0;
            _timeout_rled.attach(this, &LED::turnOffAll, 0.01);
        } else if (pin == LED_GREEN) {
            _gled = 0;
            _timeout_gled.attach(this, &LED::turnOffAll, 0.01);
        } else {
            _bled = 0;
            _timeout_bled.attach(this, &LED::turnOffAll, 0.01);
        }
    }
    
private:
    DigitalOut _rled;
    DigitalOut _gled;
    DigitalOut _bled;
    
    Timeout _timeout_rled;
    Timeout _timeout_gled;
    Timeout _timeout_bled;
    
    void turnOffAll(void) {
        _rled = 1;
        _gled = 1;
        _bled = 1;
    }
};

class TouchSensor {
public:
    TouchSensor() {}
    
    bool isLeftClick(void) {
        float tsi_val = _tsi.readPercentage();
        return tsi_val > 0.0 && tsi_val < 0.5;
    }
    
    bool isRightClick(void) {
        float tsi_val = _tsi.readPercentage();
        return tsi_val >= 0.5 && tsi_val < 1.0;
    }
        
private:
    TSISensor _tsi;
};

class Accelerometer {
public:
    Accelerometer() : _acc(PTE25, PTE24, MMA8451_I2C_ADDRESS) {}
                      
    int getMouseCursorXDist(void) {
        return (int)(10.0 * _acc.getAccY());
    }
    
    int getMouseCursorYDist(void) {
        return (int)(10.0 * _acc.getAccX());
    }
    
    bool isMouseCursorMoved(void) {
        return getMouseCursorXDist() != 0 || getMouseCursorYDist() != 0;
    }            
    
private:
    static const int MMA8451_I2C_ADDRESS = 0x1d << 1;
    MMA8451Q _acc;
};

class Mouse {
public:              
    Mouse() {}

    void handle(void) {
        while (true) {
            handleClick();
            handleMove();
            wait(0.01);
        }
    }

private:
    LED _led;
    USBMouse _mouse;
    TouchSensor _ts;
    Accelerometer _acc;
    
    void handleClick(void) {        
        if (_ts.isLeftClick()) {
            _mouse.click(MOUSE_LEFT);
            _led.turnOn(LED_RED);
        } else if (_ts.isRightClick()) {
            _mouse.click(MOUSE_RIGHT);
            _led.turnOn(LED_GREEN);
        }
    }
    
    void handleMove(void) {
        if (_acc.isMouseCursorMoved()) {
            _mouse.move(_acc.getMouseCursorXDist(), _acc.getMouseCursorYDist());
            _led.turnOn(LED_BLUE);
        }
    }
};

int main(void) {
    Mouse mouse;
    mouse.handle();    
}
```

# コンパイル

以下の画像のとおり、FRDM-KL25Zにある２つのUSBのうち、「OpenSDA」の方にUSBケーブルを接続すると、「MBED」という名前のUSBメモリとして認識されます。

![openSDA.png](https://qiita-image-store.s3.amazonaws.com/0/46434/751c6920-48a8-9674-7c07-ce8b12ea3cf9.png)

続いて、オンラインIDE上で「コンパイル」ボタンをクリックすると、.binファイルが作成されるので、それを先ほどの「MBED」にコピーしてください。自動的に.binファイルがインストールされます。

# USBエアマウスとして使用する

USBエアマウスとして使用する場合は、以下の画像のとおり、２つのUSBのうち、「KL25Z USB」の方にUSBケーブルを接続します。

![KL25Z_USB.png](https://qiita-image-store.s3.amazonaws.com/0/46434/931afcf8-ccbe-5147-6590-85136e4b207a.png)

補足）
Windows、Macの双方でUSBエアマウスとして使用することができます。

# 参考文献

ほとんどコピペで作るコピペ専用USBデバイス
http://www.dm9records.com/index.php/tips/elec/mbedadvent2014/