Posted at

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

More than 1 year has passed since last update.

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

前回までに、LEGO MINDSTORMS EV3のセンサー値を確認するまでを紹介しました。

今回は、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 の各種モーターが動く事を確認してみましょう。

今回作成したサンプルプログラムは、ここからダウンロードできます。

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

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

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