LEGO Mindstorms EV3 を Android端末からコントロールする（その5）

LEGO MINDSTORMS EV3 を Android端末でコントロールするために必要な開発環境の構築方法を備忘録も兼ねて記録します。

前回までに、[LEGO MINDSTORMS EV3のセンサー値を確認する](http://qiita.com/karubeita/items/32bc0ed7c38fb9bf6c7b)までを紹介しました。
 今回は、LEGO Mindstorms EV3 のモーターを動かします。


プロジェクトを実行して、接続した　LEGO Mindstorms EV3 の各種モーターを動かしてみましょう。

#1. 部品の配置

まず、モーターパワーを設定するためのシークバーと、モーターの回転方向を決めるボタンを、activity_main.xml に記述します。
※ここでは、前回センサーの値を表示したり、センサーの値を取得するためのボタン類も一緒に表示しています。

    <TableLayout
        android:id="@+id/tb.motors"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" >

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
		        android:layout_width="wrap_content"
		        android:layout_height="wrap_content"
		        android:text="Motor"
		        android:textAppearance="?android:attr/textAppearanceLarge" />
        </TableRow>
        
        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="A" />

            <SeekBar
                android:id="@+id/sb.motor1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.forward1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/forward" />

            <Button
                android:id="@+id/bt.backward1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/backward" />

            <Button
                android:id="@+id/bt.stop1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/stop" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="B" />

            <SeekBar
                android:id="@+id/sb.motor2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.forward2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/forward" />

            <Button
                android:id="@+id/bt.backward2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/backward" />

            <Button
                android:id="@+id/bt.stop2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/stop" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="C" />

            <SeekBar
                android:id="@+id/sb.motor3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.forward3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/forward" />

            <Button
                android:id="@+id/bt.backward3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/backward" />

            <Button
                android:id="@+id/bt.stop3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/stop" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="D" />

            <SeekBar
                android:id="@+id/sb.motor4"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.forward4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/forward" />

            <Button
                android:id="@+id/bt.backward4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/backward" />

            <Button
                android:id="@+id/bt.stop4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/stop" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >
            
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Sensors"
                android:textAppearance="?android:attr/textAppearanceLarge" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="1: " />

            <TextView
                android:id="@+id/tv.sensorName1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <TextView
                android:id="@+id/tv.sensor1"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.percent1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/percent" />

            <Button
                android:id="@+id/bt.si1"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/si_unit" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="2: " />

            <TextView
                android:id="@+id/tv.sensorName2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <TextView
                android:id="@+id/tv.sensor2"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <Button
                android:id="@+id/bt.percent2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/percent" />

            <Button
                android:id="@+id/bt.si2"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/si_unit" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="3: " />

            <TextView
                android:id="@+id/tv.sensorName3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <TextView
                android:id="@+id/tv.sensor3"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />

            <Button
                android:id="@+id/bt.percent3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/percent" />

            <Button
                android:id="@+id/bt.si3"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/si_unit" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="4: " />

            <TextView
                android:id="@+id/tv.sensorName4"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <TextView
                android:id="@+id/tv.sensor4"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1" />
            
            <Button
                android:id="@+id/bt.percent4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/percent" />

            <Button
                android:id="@+id/bt.si4"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/si_unit" />
        </TableRow>

        <TableRow
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" >

            <Button
                android:id="@+id/bt.connect"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/connect" />
            
        </TableRow>
    </TableLayout>
       
#2. 部品の実装

次に、MainActivityに次の様な記述を追加します。

     import ev3command.ev3.Motor;


モーターのパワーを設定するシークバーや、ボタンを実装します。

    private SeekBar[] mMotorSeekBars = new SeekBar[4];
    private Button[] mForwardButtons = new Button[4];
    private Button[] mBackwardButtons = new Button[4];
    private Button[] mStopButtons = new Button[4];
    private Motor[] mMotors = new Motor[4];


setUpEV3 メソッドに、モーターの設定を追記します。

    private void setUpEV3() {
        mMotors[0] = Motor.A;
        mMotors[1] = Motor.B;
        mMotors[2] = Motor.C;
        mMotors[3] = Motor.D;
        
        // If you know specified sensors are connected, you can use
        // TouchSensor, SoundSensor etc. instead of UnidentifiedSensor.
        mSensors[0] = new UnidentifiedSensor(SensorPort.S1);
        mSensors[1] = new UnidentifiedSensor(SensorPort.S2);
        mSensors[2] = new UnidentifiedSensor(SensorPort.S3);
        mSensors[3] = new UnidentifiedSensor(SensorPort.S4);
    }

findViews メソッドにも、モーターの設定を追記します。

    private void findViews() {
        for (int i = 0; i < 4; i++) {
            mMotorSeekBars[i] = (SeekBar) findViewById(getResources().getIdentifier("sb.motor" + (i + 1), "id", getPackageName()));
            mForwardButtons[i] = (Button) findViewById(getResources().getIdentifier("bt.forward" + (i + 1), "id", getPackageName()));
            mBackwardButtons[i] = (Button) findViewById(getResources().getIdentifier("bt.backward" + (i + 1), "id", getPackageName()));
            mStopButtons[i] = (Button) findViewById(getResources().getIdentifier("bt.stop" + (i + 1), "id", getPackageName()));
            
            mSensorNameTexts[i] = (TextView) findViewById(getResources().getIdentifier("tv.sensorName" + (i + 1), "id", getPackageName()));
            mSensorValueTexts[i] = (TextView) findViewById(getResources().getIdentifier("tv.sensor" + (i + 1), "id", getPackageName()));
            mGetPercentValueButtons[i] = (Button) findViewById(getResources().getIdentifier("bt.percent" + (i + 1), "id", getPackageName()));
            mGetSiUnitValueButtons[i] = (Button) findViewById(getResources().getIdentifier("bt.si" + (i + 1), "id", getPackageName()));
        }
        mConnectButton = (Button) findViewById(R.id.bt_connect);
    }

setUpButtons に、モーター用ボタンが押されたときの処理を追記します。

            mForwardButtons[i].setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mMotors[getIndex(v, mForwardButtons)].forward(); // forward
                }
            });
            mBackwardButtons[i].setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mMotors[getIndex(v, mBackwardButtons)].backward(); // backward
                }
            });
            mStopButtons[i].setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    mMotors[getIndex(v, mStopButtons)].stop(); // stop
                }
            });


シークバーの処理を実装します。

    private void setUpSeekBars() {
        for (int i = 0; i < 4; i++) {
            mMotorSeekBars[i].setMax(100);
            mMotorSeekBars[i].setProgress(50); // Set the initial value
            mMotorSeekBars[i].setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
                @Override
                public void onStopTrackingTouch(SeekBar seekBar) {
                    int power = seekBar.getProgress();
                    int index = getIndex(seekBar, mMotorSeekBars);
                    
                    // This method only sets the power on Android.
                    mMotors[index].setSpeed(power);
                }
                
                @Override
                public void onStartTrackingTouch(SeekBar seekBar) {
                }
                
                @Override
                public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                }
            });
        }
    }

各種ボタンは、最初は利用不可にしておくために、setUiEnabled メソッドに追記します。

    private void setUiEnabled(boolean enabled) {
        for (int i = 0; i < 4; i++) {
            mMotorSeekBars[i].setEnabled(enabled);
            mForwardButtons[i].setEnabled(enabled);
            mBackwardButtons[i].setEnabled(enabled);
            mStopButtons[i].setEnabled(enabled);
            mGetPercentValueButtons[i].setEnabled(enabled);
            mGetSiUnitValueButtons[i].setEnabled(enabled);
        }
    }


次に、onCreate メソッドで、setUpSeekBars メソッドを呼び出します。

    setUpSeekBars();

プロジェクトを実行して、接続した　LEGO Mindstorms EV3 の各種モーターが動く事を確認してみましょう。

今回作成したサンプルプログラムは、[ここ](https://afrel.co.jp/tech_info/Sample.zip)からダウンロードできます。

これで、LEGO Mindstorms　EV3をAndroid端末からコントロールする内容は終了です。

これらを応用して、お楽しみいただければ幸いです。

最後に、EV3Commandを作成していただいたり、様々なご指導をいただいた、岩成さんに感謝いたします。