EEZYbotARM mk1を動かしてみる

# はじめに
ここでは，Arduino UNOを使って「EEZYbotARM mk1」を動かしてみます．
ただし，今回はラジコンサーボの角度を変化させることはなく，ニュートラル角度で固定したままです．

目次へ戻るには [ここ](https://qiita.com/hsgucci/items/5e3772c6e93bbfee74f7) をクリック

※本ページは実験のテキストです．

# 概要

前回は「 Adafruit PWM Servo Driver Library 」がインストールされていることを確認しました．
今回はこのライブラリを使って，ラジコンサーボが搭載されたロボット「EEZYbotARM mk1」を動かしてみます．

# 配線の接続

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/256470/b9731f09-eacf-5bf2-13c0-62759299780f.png)

ACアダプタをPCA9685シールド基板に挿してください．
既にI2Cの動作テストのプログラムを書き込んであるので，暴走する危険はありません．

 **<font color=red>※注意
ACアダプタを挿すのは，Arduino UNO本体ではありません．PCA9685シールド基板の方です．
</font>**

コネクタが同じなので，挿すことはできるのですが，
Arduino UNO側に電力を供給しても，ラジコンサーボに電力が供給されないのでモータが動きません...



# スケッチを書き込む

では、Adafruit PWM Servo Libraryを使って，EEZYbotARMを動かしてみましょう。

メニューバーから[ファイル]-[新規ファイル]をクリックし、新しいプログラムを書く準備をしてください。

以下のプログラムを打ち込み、コンパイル/実行してみましょう。
ファイル名は `9685_servo_test.ino` としました。

```cpp:9685_servo_test.ino
// ライブラリの読み込み
#include <Wire.h>                     // I2C通信
#include <Adafruit_PWMServoDriver.h>  // PCA9685でサーボを動かすライブラリ

// サーボのパルス幅(μs)
#define SERVO_MIN   800   // 最小パルス幅
#define SERVO_CENT 1500   // ニュートラル(センター)
#define SERVO_MAX  2200   // 最大パルス幅

// ロボットアームのピン番号
#define SERVO0_YAW    0
#define SERVO1_LINK1  1
#define SERVO2_LINK2  2
#define SERVO3_HAND   3

// サーボ制御クラスの作成
Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver(0x40);  // PCA9685のI2Cアドレスは0x40番地

// 初期化関数
void setup() {

  // PWM Servoドライバを初期化する
  Servo.begin();

  // PWM周波数を50Hzに設定する
  Servo.setPWMFreq(50);
  delay(1000);

  // それぞれのサーボにパルス幅(マイクロ秒)を与える
  Servo.writeMicroseconds(SERVO0_YAW,   1500);
  Servo.writeMicroseconds(SERVO1_LINK1, 1500);
  Servo.writeMicroseconds(SERVO2_LINK2, 1500);
  Servo.writeMicroseconds(SERVO3_HAND,  1500);
  
  delay(100); // 待ち時間

}

// ループ関数
void loop() {
  // 今回はなにもしない
}

```


# 動作テスト

Arduinoに書き込みが終わると，ロボットアームに力が入って動きます．
今回は全てのサーボをニュートラル位置(1500マイクロ秒)にするだけなので，連続して動くことはありません．

もし，ロボットアームが変な姿勢になっていたら，サーボがズレているかもしれないので，担当の先生に申し出てください．

# プログラム解説

それではプログラムを解説していきます．

## 準備
まずはプログラムの冒頭部分で，
I2C通信をするための`Wire.h`と，Adafruitのライブラリ`Adafruit_PWMServoDriver.h`をインクルードしています．
前回インストールしたライブラリは，`#include`することで使えるようになるのです．

```cpp:#include,#define,クラスの宣言
// ライブラリの読み込み
#include <Wire.h>                     // I2C通信
#include <Adafruit_PWMServoDriver.h>  // PCA9685でサーボを動かすライブラリ

// サーボのパルス幅(μs)
#define SERVO_MIN   800   // 最小パルス幅
#define SERVO_CENT 1500   // ニュートラル(センター)
#define SERVO_MAX  2200   // 最大パルス幅

// ロボットアームのピン番号
#define SERVO0_YAW    0
#define SERVO1_LINK1  1
#define SERVO2_LINK2  2
#define SERVO3_HAND   3

// サーボ制御クラスの作成
Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver(0x40);  // PCA9685のI2Cアドレスは0x40番地
```

次に，サーボのパルス幅の下限値・ニュートラル値・上限値を`#define`で宣言しています．
また，サーボのピン番号も`#define`で宣言しています．

`#define `はプログラム中で「置換」される機能です．変数の宣言ではありません．
変数は値が変化しますが，固定値で変えることのない数値を使う場合に`#define`というマクロ機能を使って書くことがあります．

　参考：[defineで文字列を値に置換](https://www.sejuku.net/blog/25927#define-2)

例えば，`#define SERVO0_YAW 0`と書いてあるので，"SERVO0_YAW"という文字列があったら"0"に置き換えろ，と指示していることになります．

初期化関数の中で`Servo.writeMicroseconds(SERVO0_YAW,   1500);`と書いているので．
コンパイルする前にその部分が置換され，`Servo.writeMicroseconds(0,   1500);`という状態に変化します．

`#define`の次に書く文字列は，小文字を混ぜることもできるのですが，
「この文字列は変数じゃなくて#defineマクロだよ」と言うことを明確にするために，
ワザと全て大文字で書くプログラマが多いです．

最後に`Adafruit_PWMServoDriver`クラスの実体(インスタンス)として`Servo`を作っています．
その際にインスタンスの中身の初期化作業を行うため，
`Servo = Adafruit_PWMServoDriver(0x40);`
としてPCA9685のI2Cアドレスである0x40を引数として渡しているのがわかります．
こう書くことで，クラスが0x40番地との通信を勝手にやってくれます．
I2C通信の何たるかを理解する必要が無いので，便利です．

## 初期化関数

次は初期化関数です．

まずはインスタンス`Servo`を使って，ラジコンサーボを動かすための初期設定をしています．

`Servo.begin()`は必ず最初に呼ぶ必要があります．

[ラジコンサーボの信号](https://qiita.com/hsgucci/items/1ae0dbeb0438db8a23fa#%E3%83%A9%E3%82%B8%E3%82%B3%E3%83%B3%E3%82%B5%E3%83%BC%E3%83%9C%E3%81%AE%E4%BF%A1%E5%8F%B7)　で解説しましたが，
サーボ信号は20ミリ秒おき，すなわち50Hzなので，
`Servo.setPWMFreq(50)`でパルス周期を50Hzに設定しています．

```cpp:setup関数
// 初期化関数
void setup() {

  // PWM Servoドライバを初期化する
  Servo.begin();

  // PWM周波数を50Hzに設定する
  Servo.setPWMFreq(50);
  delay(1000);

  // それぞれのサーボにパルス幅(マイクロ秒)を与える
  Servo.writeMicroseconds(SERVO0_YAW,   1500);
  Servo.writeMicroseconds(SERVO1_LINK1, 1500);
  Servo.writeMicroseconds(SERVO2_LINK2, 1500);
  Servo.writeMicroseconds(SERVO3_HAND,  1500);
  
  delay(100); // 待ち時間

}
```

初期設定が終わった後で`Servo.writeMicroseconds`関数を使って，
EEZYbotARM mk1の４つのサーボにパルス幅を与えています．

今回は全てのサーボを1500マイクロ秒にしました．ニュートラルの値に固定しています．
他の角度になることはありません．


## ループ関数

次はループ関数です．

```cpp:loop関数
// ループ関数
void loop() {
  // 今回はなにもしない
}
```

なんと今回はループ関数の中身は **空** です(^^;
繰り返して実行する作業がない場合は，今回のように空にしてしまう使い方もあるのです．


# まとめ

今回は「 Adafruit PWM Servo Driver Library 」を使って「EEZYbotARM mk1」を動かしてみました．

ですが，１つの決まった姿勢になるだけでは全然面白くないですね．
各関節を自由に動かしてみたいところです．

# おわりに

これでEEZYbotARMの動作テストは完了です．

次回はシリアル通信で動かしてみます．

[目次](https://qiita.com/hsgucci/items/5e3772c6e93bbfee74f7#%E5%AE%9F%E9%A8%93%E6%89%8B%E9%A0%86) へ戻って次の作業を行ってください。