VS-RC003HVとArduinoでI2C通信してIXBUS拡張基盤を自作する

# 概要
VS-RC003HVとArduino(Arduino互換ボード)でI2C通信をする方法です。
UARTで通信する例は多いですがI2Cの例はあまり見当たらなかったので書こうと思います。

当時を思い出しながら書いている部分もありますので、一部不正確な部分もあるかと思います。ソースコードや設定をご使用なさる際は自己責任でお願いいたします。

## 前提
VS-RC003HVには拡張端子としてIXBUSポートが搭載されています。[VS-RC003HV 取扱説明書](https://www.vstone.co.jp/products/vs_rc003hv/download/VS-RC003_manual.pdf)には以下の記載があります。

> CN7 IXBUS拡張
> 　外部に IXBUS の拡張機器を接続するための端子です。IXBUS はフィリップス社の提唱するI2CバスとUART、電源(バッテリ電圧、5V、3.3V)、リセット信号等から成り、特にI2Cバスにより豊富な拡張性を確保しています。基板右下、ロータリースイッチ側が 1番ピンです。

このポートにはI2C端子があり、VS-RC003HVの純正拡張基盤「VS-IXxxx」シリーズはVS-RC003HVとI2Cで通信をしています。

## 仕組み
ArduinoをVS-RC003HVのIXBUS拡張基盤として認識させます。
Arduinoは自身を任意アドレスのI2Cスレーブとして設定できるので、IXBUS拡張基盤のI2Cアドレスとして起動してあげることで、VS-RC003HVは純正基盤だと認識して通信してくれます。

単純な方法ですのでI2Cポートがついているマイコンならどれでも可能だと思います。

## できること
+ RobovieMakerのポーズスライダ値を使用した条件分岐
+ Arduinoに接続したセンサ値のVS-RC003HVでの利用（未検証）

などが可能です。

私がプログラムを担当した「METAL GEAR REX 参号機」では、この方法でVS-RC003HVでモーション再生と音声出力、ArduinoでLED発光を同期して行いました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">REX動かしました <a href="https://t.co/jbZTH4KYKQ">pic.twitter.com/jbZTH4KYKQ</a></p>&mdash; ツンの作業場@11/25~28ロボット出展します (@tn340) <a href="https://twitter.com/tn340/status/1447069014719545347?ref_src=twsrc%5Etfw">October 10, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>


# 本編
ここでは「VS-RC003HV用 LED拡張ボード VS-IX004」として認識させる設定で進めます。
[取扱説明書](https://www.vstone.co.jp/robotshop/index.php?main_page=product_info&cPath=30_31&products_id=56)はダウンロードしておくと分かりやすいです。

## VS-RC003HVとArduinoの接続
IXBUSのピンアサイン

| ピン番号 | 端子名 |
| :------: | :----: |
| 1        | TXD0   |
| 2        | RXD0   |
| 3        | RESET  |
| 4        | SDA1   |
| 5        | SCL0   |
| 6        | SDA0   |
| 7        | VBATTD |
| 8        | +5V    |
| 9        | +3.3V  |
| 10       | GND    |

**5番ピン SCL0**と**6番ピン SDA0**をそれぞれArduinoのSCLとSDAに接続します。
10番ピン GNDも接続しておくと良いです。
電源が欲しければ8番や9番ピンから取れます。便利ですね。


## RobovieMaker2の設定

[取扱説明書](https://www.vstone.co.jp/products/robovie_i/Robovie-i_files/vsix004_doc.zip)の *1. LED拡張ボードの基本設定* 、*2. ポーズスライダの設定* に従って設定してください。
1の途中で「I2Cバスアドレス」を設定する部分があると思いますが、ここでは`0xc0`に設定しておいてください。ほとんどの場合はデフォルト値だと思います。

*2-1.ポーズスライダのプロパティ設定* が終わると、33~38番のポーズスライダが追加されるはずです。

## プログラムの書き込み
Arduinoに以下のプログラムを書き込みます。
`Wire.begin();`のカッコ内には任意のI2Cスレーブアドレスを指定できますが、ここでは`Wire.begin(0x60);`にしておいてください。

```
#include <Wire.h>

/* カウンタ変数 */
int count = 0;

/* 一時格納するためのバッファ */
byte dt;

/* 送られてきた数値を格納する配列 */
/* reg_add, PSC_0, PWM_0, PSC_1, PWM_1, LS_0, LS_1, LS_2, LS_3 */
byte reData[9];

void setup(){
    Serial.begin(115200);
    Wire.begin(0x60);
    Wire.onReceive(receiveEvent); //割り込み関数の設定
}

void loop(){
    for(uint8_t i=0; i<9; i++){
        Serial.println(reData[i], BIN);  // 値の確認
    }
}

/* データを受信すると処理される割込み関数 */
void receiveEvent(int howMany){
    while(Wire.available()){
        dt = Wire.read();
        reData[count] = dt;  //reData[count]にRobovieMakerのスライダ値が入る
        count++;
    }
    count = 0;
}
```

### 「I2Cバスアドレス」と「スレーブアドレス」違う理由
RobovieMakerで設定した 「I2Cバスアドレス」 は `0xc0` なのに、Arduinoスケッチでは `Wire.begin(0x60);` と書いています。

これはVS-IX004に使用されているIC「PCA9532PW」の仕様によるためです。
[データシート](https://www.mouser.jp/datasheet/2/302/PCA9532-1127723.pdf)によると、接続時にマスターから送信して欲しいデバイスアドレス8bitのうち、スレーブアドレスは上位7bitなようです。
>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2050833/5367da07-b784-f57f-c3e8-242d58732361.png)

RobovieMaker2で設定した 「I2Cバスアドレス」 `0xc0 = 11000000` の最下位1bitを削除すると `0x60 = 1100000` になり、これがArduinoで設定する本当のI2Cアドレスになります。

最下位1bitはICの動作を切替(1:Read / 0:Write)するために使用されます。マスター側が必要に応じて切り替える必要があるのでデバイスアドレス8bitは最下位ビットのみコロコロ変わり、RobovieMakerで設定する「I2Cバスアドレス」とは正確には違うアドレスになると思うのですが、~~設定ダイアログで7bitのスレーブアドレスのみにしない理由はよくわかりません。~~

## 接続確認

Arduinoの電源を入れ、PCとVS-RC003HVを接続しRobovieMakerの通信開始ボタンを押してください。
「プロジェクトの設定」>「CPUの設定」をクリックし、「拡張機器」タブから、先程追加した「VS-IX004」を選択し、「変更」をクリックしてください。
「拡張機器の追加 / 変更」ダイアログが開いたら、「デバイスの詳細設定」をクリックし、設定ダイアログを確認してください。「現在の接続状態」が`OK`であれば成功です！

ArduinoIDEからシリアルモニタを開き、ArduinoがVS-RC003HVから受け取っている値を確認します。上手くいっていればRobovieMakerのポーズスライダを動かしたとき、次の表のように対応した値が変化するはずです。

| 10010    | Register_Address | reData[0] | ポーズスライダ番号 |
| :------- | ---------------- | --------- | ------------------ |
| 0        | PSC_0            | reData[1] | 35                 |
| 0        | PWM_0            | reData[2] | 33                 |
| 0        | PSC_1            | reData[3] | 36                 |
| 0        | PWM_1            | reData[4] | 34                 |
| 10101010 | LS_0             | reData[5] | 37                 |
| 10101010 | LS_1             | reData[6] | -                  |
| 11111111 | LS_2             | reData[7] | 38                 |
| 11111111 | LS_3             | reData[8] | -                  |

# まとめ
ここでは「VS-IX004」としてArduinoを接続しましたが、肝は **Arduinoが純正拡張基盤と同じアドレスになること** です。
VS-IXxxxシリーズの情報は説明書から回路図まで全て公開されているので、使用されているICのデータシートを見に行けば今回と同じ方法で「デジタル入出力拡張ボード VS-IX007」だろうと「アナログ入力拡張ボード VS-IX008」だろうと自作できてしまいます。

「あるモーション中の決まったタイミングで目を光らせたい」、「あるモーションではガトリングを模したLEDを点滅させたい」などのロボットの動きと発光のタイミング合わせが重要な場合に、RobovieMakerのポーズスライダで制御してモーションに組み込むことができるのは相性がとても良いです。

# 最後に

METAL GEAR REX参号機に携わってから3年経ちましたが、当時頑張っていたことをようやく書き出せてすっきりしました。