後輩たちのためのEV3rt講座②(モーターを動かす)

今回はロボットでは基本中の基本、モーター関連のことを教えていきます。
ただ、僕も使っていないAPIがあるので、それについては紹介できません。

でも安心してください。基本動作はできるようになります!!

以下はモーター関連のAPIです。これも参考にしながら見てください。
[EV3RT C API Reference サーボモータ](http://www.toppers.jp/ev3pf/EV3RT_C_API_Reference/group__ev3motor.html)
#①使うモーターをコンフィグする#
前回もお伝えしましたが、モーターを使うには**宣言**をして置かなければなりません。
ここではモーターAとDにLモーターを繋ぐことにします。

```c:app.c
#include "ev3api.h" //絶対必要
#include "app.h"//絶対必要
#include <stdio.h>
#include <stdbool.h>

#if defined(BUILD_MODULE)
#include "module_cfg.h"
#else
#include "kernel_cfg.h"
#endif

#define DEBUG

#ifdef DEBUG
#define _debug(x) (x)
#else
#define _debug(x)
#endif

void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);
```

これでモーターが使えるようになります。
ポートとの接続は
![スクリーンショット 2018-08-22 10.39.57.png](https://qiita-image-store.s3.amazonaws.com/0/183170/d8dec1db-aa1f-a957-c17b-8e2b34d59a22.png)
もしくは
![スクリーンショット 2018-09-10 12.46.25.png](https://qiita-image-store.s3.amazonaws.com/0/183170/205f3bd2-ad7b-ebbd-48ee-c80e3e47c7ab.png)
つまり

| ポート | 列挙型① | 列挙型② |
|:-:|:-:|:-:|
| A | EV3_PORT_A | 0 |
| B | EV3_PORT_B | 1 |
| C | EV3_PORT_C | 2 |
| D | EV3_PORT_D | 3 |
という風にプログラムします。

センサーの対応表はこちら
![スクリーンショット 2018-08-22 10.40.01.png](https://qiita-image-store.s3.amazonaws.com/0/183170/fb1e47dc-feb3-0008-4fd7-89d043f5ee03.png)

#②モーターを動かしてみる#
さて、いよいよ動かしていきます。
といっても、EV3には様々な命令方法がありますので、教育用ソフトウェアと比較して見ていきたいと思います。

##モーターON##
教育用ソフトウェアだと↓のコマンド
![スクリーンショット 2018-08-22 10.48.55.png](https://qiita-image-store.s3.amazonaws.com/0/183170/cdac84cd-fcad-e7e6-c632-b89e83cc87d9.png)
EV3rtだと…

```c:app.c
void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);

    ev3_motor_set_power(EV3_PORT_A,50);
    ev3_motor_set_power(EV3_PORT_D,50);
}
```
ただし、この命令はストップ命令を掛けない限り永遠に動き続けます。
ということで次は、
##モーターOFF##
教育用ソフトウェアだと↓のコマンド
![スクリーンショット 2018-08-22 10.54.57.png](https://qiita-image-store.s3.amazonaws.com/0/183170/efbd342a-508a-cc95-10e5-7d458fc0146f.png)
EV3rtだと…

```c:app.c
void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);

    ev3_motor_stop(EV3_PORT_A, true);//Aで即時停止
    ev3_motor_stop(EV3_PORT_D, true);//Dで即時停止

    ev3_motor_stop(EV3_PORT_A, false);//Aで惰性減速
    ev3_motor_stop(EV3_PORT_D, false);//Dで惰性減速
}
```
こんな感じです。

さて、基本的にはこれだけで作業できますが、他にもいくつかあるので紹介しておきましょう。

#③回転角を取得する#
```c:app.c
void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);

    int MotorAcount=ev3_motor_get_count(EV3_PORT_A);
    int MotorDcount=ev3_motor_get_count(EV3_PORT_D);
}
```
この例では変数MotorAcountとMotorDcountにAとDの回転角を代入します。
これを使うと何ができるか？
教育用ソフトウェアでいう↓のようなことができるようになります。
![スクリーンショット 2018-08-22 11.16.37.png](https://qiita-image-store.s3.amazonaws.com/0/183170/9ce2d6b8-610d-5f66-f61b-fe3c838a7220.png)
角度を指定して動く事ができるのです。下に例を提示しておきます。

```c:app.c
void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);

    ev3_motor_reset_counts(L_motorA);//回転角のリセット
    while (360>ev3_motor_get_counts(EV3_PORT_A)) {
        ev3_motor_set_power(EV3_PORT_A,50);
        ev3_motor_set_power(EV3_PORT_D,50);
    }
    ev3_motor_stop(EV3_PORT_A, true);//Aで即時停止
    ev3_motor_stop(EV3_PORT_D, true);//Dで即時停止
}
```
こんな風にすることで簡単に指定角文動かすことができます!!
さらに!!「C言語コンパイルが可能なんただったら、関数化してしまえばいいじゃないか」ということで、私は下の関数をめちゃくちゃ使ってプログラミングしました。よかったら参考にしてみてください。
#④関数化してプログラムを効率化#

```c:app.c
void main_task(intptr_t unused)
{
    /* コンフィグゾーン　*/
    ev3_motor_config (EV3_PORT_A, LARGE_MOTOR);
    ev3_motor_config (EV3_PORT_D, LARGE_MOTOR);

    func_motor(50,50,360);
    func_motor_stop();
}

void func_motor(double a,double d,double dis);//aとdはパワーレベル・disは角度の指定

void func_motor(double a,double d,double dis)
{
    ev3_motor_reset_counts(EV3_PORT_A);
    if (a>0) {//パワーが正か負かで場合分け
        while (dis>ev3_motor_get_counts(EV3_PORT_A)) {
            ev3_motor_set_power(EV3_PORT_A,a);
            ev3_motor_set_power(EV3_PORT_D,d);
        }
    }
    else if(a<0){
        while (dis>-(ev3_motor_get_counts(EV3_PORT_A))) {
            ev3_motor_set_power(EV3_PORT_A,a);
            ev3_motor_set_power(EV3_PORT_D,d);
        }
    }
}

void func_motor_A(double a,double dis);

void func_motor_A(double a,double dis)
{
    ev3_motor_reset_counts(EV3_PORT_A);
    if (a>0) {
        while (dis>ev3_motor_get_counts(EV3_PORT_A)) {
            ev3_motor_set_power(EV3_PORT_A,a);
        }
    }
    else if(a<0)
    {
        while (dis>-(ev3_motor_get_counts(EV3_PORT_A))) {
            ev3_motor_set_power(EV3_PORT_A,a);
        }
    }
}

void func_motor_B(double a,double dis);

void func_motor_B(double a,double dis)
{
    ev3_motor_reset_counts(EV3_PORT_B);
    if (a>0) {
        while (dis>ev3_motor_get_counts(EV3_PORT_B)) {
            ev3_motor_set_power(EV3_PORT_B,a);
        }
    }
    else if(a<0)
    {
        while (dis>-(ev3_motor_get_counts(EV3_PORT_B))) {
            ev3_motor_set_power(EV3_PORT_B,a);
        }
    }
}

void func_motor_C(double a,double dis);

void func_motor_C(double a,double dis)
{
    ev3_motor_reset_counts(EV3_PORT_C);
    if (a>0) {
        while (dis>ev3_motor_get_counts(EV3_PORT_C)) {
            ev3_motor_set_power(EV3_PORT_C,a);
        }
    }
    else if(a<0)
    {
        while (dis>-(ev3_motor_get_counts(EV3_PORT_C))) {
            ev3_motor_set_power(EV3_PORT_C,a);
        }
    }
}

void func_motor_D(double a,double dis);

void func_motor_D(double a,double dis)
{
    ev3_motor_reset_counts(EV3_PORT_D);
    if (a>0) {
        while (dis>ev3_motor_get_counts(EV3_PORT_D)) {
            ev3_motor_set_power(EV3_PORT_D,a);
        }
    }
    else if(a<0)
    {
        while (dis>-(ev3_motor_get_counts(EV3_PORT_D))) {
            ev3_motor_set_power(EV3_PORT_D,a);
        }
    }
}

void func_motor_stop();

void func_motor_stop()
{
    ev3_motor_stop(EV3_PORT_A, true);
    ev3_motor_stop(EV3_PORT_B, true);
    ev3_motor_stop(EV3_PORT_C, true);
    ev3_motor_stop(EV3_PORT_D, true);
}

void func_motor_sleep();

void func_motor_sleep()
{
    ev3_motor_stop(EV3_PORT_A, false);
    ev3_motor_stop(EV3_PORT_B, false);
    ev3_motor_stop(EV3_PORT_C, false);
    ev3_motor_stop(EV3_PORT_D, false);
}
```

#まとめ#
今回はモーター関連のAPIを紹介しました。
また、今回以下の4つは紹介していません。

- `ev3_motor_get_type (motor_port_t port)` 
- `ev3_motor_get_power (motor_port_t port)`
- `ev3_motor_rotate (motor_port_t port, int degrees, uint32_t speed_abs, bool_t blocking)`
- `ev3_motor_steer (motor_port_t left_motor, motor_port_t right_motor, int power, int turn_ratio)`

紹介しなかった理由としては大きく2つあります。
1つは使う機会がかなり限られているということ(特に上2つ)
もう1つは私自身使い方がイマイチわからないということ(特に下2つ)

ということで、これら4つを使いたい方は自分で使い方を調べてください。今回紹介した他のAPIとノリは同じなので、リファレンスを見ればだいたいわかります。また機会があれば紹介したいと思います。

次回:[第3回](https://qiita.com/koushiro/items/97d08cf3d863d6f81f2e)
前回:[第1回](https://qiita.com/koushiro/items/a3fb52f0f1c17f2b1670)