Donkey Carのプロポ対応その２（ソフトウェア編）

### はじめに

HID対応しているArduinoは実行時にUSBを使い、デバッグ時にもUSB経由でArduino IDEのシリアルコンソールに表示させるため、デバッグを意識したスケッチにしておくと便利です。Arduinoの開発方法を知っている前提で書いてあります。

### 想定機能

プロポにより色々とキー割り当てが考えられるため、以下の機能に想定して説明をします。

|                         | 操作     | ピン |
| ----------------------- | -------- | ---- |
| 左スティックX軸(横方向) | Steering | D09  |
| 右スティックY軸(縦方向) | Throttle | D10  |
| ボタンL1                | 任意     | D11  |
| ボタンR1                | 任意     | D15  |

### ライブラリの取り込み

- PinChangeInterrupt ... ライブラリマネージャから取り込みます。
- Joystick ... 以下のサイトから取り込みます。

　　　https://github.com/MHeironimus/ArduinoJoystickLibrary

### 受信データのPWM値を調べる

スケッチの最初の２行のライブラリを取り込んだのち、測定したいチャンネル毎のプロポの値を調べる。以下のスケッチのDEBUGを１にして実行します。左スティックのX軸を左、右に倒して、最小値・最大値をシリアルモニターに表示させます。最小値は1000㎲近辺、最大値は2000㎲近辺になると思います。

スケッチは可読性をよくするために1チャンネルだけの処理をしていますが、同様に別なチャンネルもプロポの設定値を確認します。

```c
#include <PinChangeInterrupt.h>
#include <Joystick.h>

#define DEBUG 1

#define NUM_BUTTON      3
#define BUTTON_MODE     0
#define R1              1
#define L1              2  

#define NUM_CHANNEL     4
#define BUTTON_PRESSED  1
#define BUTTON_RELEASED 0

#define STEERING_LEFT_PWM  1000
#define STEERING_RIGHT_PWM 2000

#define MIN_VALUE16          -32767
#define MAX_VALUE16           32767
#define ERROR_RANGE           16

const byte channel_pin[] = {9, 10, 11, 15};
volatile unsigned long rising_start[] = {0, 0, 0, 0};
volatile long channel_length[] = {0, 0, 0, 0};
volatile long base_value[] = {0, 0, 0, 0};

Joystick_ Joystick = Joystick_(
  0x03,                    // reportid
  JOYSTICK_TYPE_JOYSTICK,  // type
  NUM_BUTTON,              // button count
  0,                       // hat switch count
  true, false, false,      // left x,y,z axis enable
  false, true, false,      // right x,y,z axis enable
  false,                   // rudder enable
  false,                   // throttle enable
  false,                   // accelerator enable
  false,                   // brake enable
  false                    // steering enable
);


void setup() {
  int counter;

  if(DEBUG) {
    Serial.begin(115200);
    while (!Serial) {}
  }

  pinMode(channel_pin[0], INPUT);  // steering
  pinMode(channel_pin[1], INPUT);  // throttle
  pinMode(channel_pin[2], INPUT);  
  pinMode(channel_pin[3], INPUT);  
  
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(channel_pin[0]), onRising0, CHANGE);
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(channel_pin[1]), onRising1, CHANGE);
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(channel_pin[2]), onRising2, CHANGE);
  attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(channel_pin[3]), onRising3, CHANGE);

  // Initialize Joystick
  if(!DEBUG) {
    Joystick.begin();
    Joystick.setXAxisRange(MIN_VALUE16, MAX_VALUE16);
    Joystick.setRyAxisRange(MIN_VALUE16, MAX_VALUE16);
  }

  // Wait Initial value of all channel
  while(1) {
    counter = 0;
    for(int i=0; i<NUM_CHANNEL; i++) {
      if(channel_length[i] == 0) { counter++; }
    }
    if(counter == 0) { break; }
  }
  // set base value 
  for(int i=0; i<NUM_CHANNEL; i++) {
    base_value[i] = channel_length[i];
  }
}

void processPin(byte pin) {
  uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(channel_pin[pin]));

  if(trigger == RISING) {
    rising_start[pin] = micros();
  } else if(trigger == FALLING) {
    channel_length[pin] = micros() - rising_start[pin];
  }
}

void onRising0(void) {
  processPin(0);
}

void onRising1(void) {
  processPin(1);
}

void onRising2(void) {
  processPin(2);
}

void onRising3(void) {
  processPin(3);
}

void loop() {
  int steering_range, throttle_range;
  int steering_value, throttle_value;

  if(DEBUG) {
    Serial.println(channel_length[0]); 
  } else  {
    steering_value = map(channel_length[0], STEERING_LEFT_PWM, STEERING_RIGHT_PWM, MIN_VALUE16, MAX_VALUE16);
    Joystick.setXAxis(steering_value); 
  }
}
```

### HIDとしてArduinoを動作させる

DEBUGを０にして、前のステップで採取したデータをSTEERING_LEFT_PWM, STEERING_RIGHT_PWMにセットして実行すると、ジョイスティック関連のプログラムが動くようにしています。

ArduinoのD09からのPWM値を、map関数により符号付き16ビット整数にして、Raspberry Pi側に送ります。

### ボタンの扱い

ボタン番号 2を押して、50ms経って離したことを示しています。

```c
      Joystick.pressButton(L1);
      delay(50);
      Joystick.releaseButton(L1);
```

詳しくは、以下のサイトのJoystick APIを参照してプログラミングしてください。

https://github.com/MHeironimus/ArduinoJoystickLibrary

### 続き

次は、Raspberry PiでのDonkey Carプログラムの書き換え及び設定を書きます。