この記事では、ロボットを使ってインターフェースという機能を主に見ていきます。
#目次
0.インターフェースとは
1.コードの構造
1-0.インターフェース内で処理を実装するサンプルコード
1-1.クラスをつくってインターフェースを実装するサンプルコード
2.インターフェースTimerListnenerと実装クラスTimerのサンプルコード
3.leJOSにおけるモーターのクラスとインターフェースの関係
#0.インターフェースとは
インターフェースはメソッドの仕様のみを定義するクラスのようなものです。
インターフェースの中にはメソッドが並べられていますが、その処理は書いてありません。
なのでメソッドを見たときそれが何をするものなのかはわかりますが、実際にどういった処理をするものなのかはわかりません。
メソッドの処理の内容は、インターフェースを実装するクラスの中を見ればわかります。
Point : インターフェース
メソッドの仕様(戻り値とメソッド名、引数)のみを定義する
実際には処理をしない
Point : インターフェースを実装するクラス
メソッドの処理の内容を定義する
処理を実際に行う
[参考記事]インターフェースを実装!Javaでimplementsを使う方法
※ここに書いてあるように、インターフェースでメソッドの処理を実装することもあります。
#1.コードの構造
##1-0.インターフェース内で処理を実装するサンプルコード
まずは、以下のコードをみてみましょう。
モーター回転開始時と終了時に文字を表示するプログラムです。
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.RegulatedMotor;
import lejos.robotics.RegulatedMotorListener;
import lejos.utility.Delay;
public class MotorEvent{
//インスタンスの生成
//RegulatedMotor:インターフェース
//EV3LargeRegulatedMotor:インターフェースを実装するクラス
private static RegulatedMotor l_a = new EV3LargeRegulatedMotor(MotorPort.A);
public static void main(String[] args) {
//インスタンスの生成
//インターフェースRegulatedMotorListenerの中のメソッドをカスタマイズして処理を定義する
final RegulatedMotorListener listener = new RegulatedMotorListener() {
//インターフェースRegulatedMotorListenerがもつ以下の2つのメソッドをカスタマイズする
//モーターが回転を開始した時に呼び出されるメソッドをカスタマイズする
@Override
public void rotationStarted(
final RegulatedMotor motor,
final int tachoCount,
final boolean stalled,
final long timeStamp) {
//カスタマイズする内容
System.out.println("Started");
Delay.msDelay(500);
}
//モーターが回転を停止した時に呼び出されるメソッドをカスタマイズする
@Override
public void rotationStopped(
final RegulatedMotor motor,
final int tachoCount,
final boolean stalled,
final long timeStamp) {
//カスタマイズする内容
System.out.println("Stopped");
Delay.msDelay(500);
}
};
//addListenerメソッドはRegulatedMotorListenerのインスタンスを引数にとる
//モータに何かしらの動きがあれば、listenerに伝えられる
//そしてlistenerの中のメソッドが呼び出される
l_a.addListener(listener);
l_a.forward();
Delay.msDelay(2000);
l_a.stop();
Delay.msDelay(500);
}
}
###サンプルコードの概要
1.モーターの回転開始時と終了時に文字を表示するためにaddlistenerメソッドを使いたい。
※void addListener(RegulatedMotorListener listener)
ローテーションが開始または停止したときに通知されるリスナーオブジェクトを追加します
2.addlistenerメソッドはクラスEV3LargeRegulatedMotorで実装されているので、そこから参照型変数l_aをつくってl_a.addlistenerという形で使用する。
3.また、addlistenerメソッドは、引数にインターフェースRegulatedMotorListenerのインスタンスをとるので、まずそのインターフェースからインスタンスをつくる必要がある。
4.しかし、インターフェースはメソッドの処理を定義していないので、インスタンスをつくったとしても実際に処理を行うことができない。
そこで、インターフェースの中にあるメソッドをカスタマイズして処理を定義し、処理を行うことができるようにする。
###サンプルコードの整理
◯インターフェース : RegulatedMotor
実装クラス:EV3LargeRegulatedMotor
◯インターフェース : RegulatedMotorListener
実装クラス:なし(インターフェース内で実装)
◯メソッド : rotationStarted()
RegulatedMotorListenerの中で仕様のみが定義されている
モーターの回転開始時に呼び出されるメソッド
◯メソッド : rotationStopped()
RegulatedMotorListenerの中で仕様のみが定義されている
モーターの回転終了時に呼び出されるメソッド
◯メソッド : addlistener()
void addListener(RegulatedMotorListener listener)
インターフェースから生成されたオブジェクトを引数にとる。インターフェースRegulatedMotorで仕様が定義され、EV3LargeRegulatedMotorクラスで実装されている。
##1-0.クラスをつくってインターフェースを実装するサンプルコード
◯インターフェースRegulatedMotorListenerを実装するために自分でRotateStateEventというクラスをつくります。
そのなかでRegulatedMotorListenerのなかにあるメソッドをカスタマイズして、処理を定義します。
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.RegulatedMotor;
import lejos.robotics.RegulatedMotorListener;
public class MotorEvent02 {
private static RegulatedMotor l_a = new EV3LargeRegulatedMotor(MotorPort.A);
public static void main(String[] args) {
//クラスRotateStateEventのインスタンスを引数にする
l_a.addListener(new RotateStateEvent());
l_a.forward();
Delay.msDelay(2000);
l_a.stop();
Delay.msDelay(500);
}
}
//インターフェースRegulatedMotorListenerを実装するクラスをつくる
class RotateStateEvent implements RegulatedMotorListener{
@Override
public void rotationStarted(
final RegulatedMotor motor,
final int tachoCount,
final boolean stalled,
final long timeStamp) {
//処理を定義する
System.out.println("Started");
Delay.msDelay(500);
}
@Override
public void rotationStopped(
final RegulatedMotor motor,
final int tachoCount,
final boolean stalled,
final long timeStamp) {
//処理を定義する
System.out.println("Stopped");
Delay.msDelay(500);
}
}
Point : implements
クラス implements インターフェース{}
という形で、インターフェースを実装するクラスとして定義することができます。
#2.インターフェースTimerListnenerと実装クラスTimerのサンプルコード
◯Timerクラスを扱うためにSecondCounterクラスを自分でつくります。
Timerクラスは、TimerListenerインターフェース(を実装しているクラス)のインスタンスを引数にとります。
そして、指定した周期ごとに、TimerListenerインターフェース(を実装しているクラス)の中にあるtimedOutメソッド(=処理)を呼び出します。
今回は1秒おきにカウントを数え、それを表示し、5秒おきに音を鳴らすプログラムにしてあります。
import lejos.utility.Timer;
import lejos.hardware.Sound;
import lejos.utility.TimerListener;
public class SecondCounter {
private int second;
// 1000ミリ秒ごとに割り込みを発生させる
private Timer timer = new Timer(1000, new CountTimer());
public void reset() {
second = 0;
}
public int getSecond() {
return second;
}
public void start() {
timer.start();
}
public void stop() {
timer.stop();
}
//インターフェースTimerListenerを実装するCountTimerクラスをつくる
class CountTimer implements TimerListener {
// 1000ミリ秒ごとにtimedOut()メソッドが、Timerから呼ばれる
//インターフェースの中にあるメソッドの処理内容をカスタマイズして定義する
@Override
public void timedOut() {
//1ずつ加算する
second++;
System.out.print(second);
//5秒おきに音を鳴らす
if(second % 5 == 0 ) {
Sound.beep();
}
}
}
}
import lejos.hardware.Button;
import lejos.hardware.motor.EV3LargeRegulatedMotor;
import lejos.hardware.port.MotorPort;
import lejos.robotics.RegulatedMotor;
import lejos.utility.Delay;
public class SecondCounterSample {
private static RegulatedMotor l_a = new EV3LargeRegulatedMotor(MotorPort.A);
public static void main(String[] args) {
////上で定義したクラスSecondCounterのインスタンスの生成
SecondCounter counter = new SecondCounter();
//カウントを開始する
counter.start();
//20回処理を繰り返す
for (int i = 0; i < 20; i++) {
if(i == 10) {
//タイマーをリセット
System.out.print("reset ");
counter.reset();
}else if(i > 15) {
//徐行運転
System.out.print("slowdown ");
l_a.setSpeed(100);
}else {
//加速する
//カウント*100にスピードを設定する
l_a.setSpeed(counter.getSecond() * 100);
}
l_a.forward();
Delay.msDelay(1000);
}
l_a.stop();
counter.stop();
System.out.println("push any button");
Button.waitForAnyPress();
}
}
Point : public Timer(int theDelay,TimerListener el)
周期とTimerListenerクラス(を実装するクラス)のインスタンスを引数にとる。
Point : void timedOut()
Called every time the Timer fires.
Timerが発火する時に毎回呼ばれる
#3.leJOSにおけるモーターのクラスとインターフェースの関係
モーターに関するクラスとインターフェースの関係性についてみていきます。
・クラスBaseRegulatedMotor
・クラスEV3LargeRegulatedMotor
・インターフェースRegulatedMotor
・インターフェースBaseMotor
モーターの一番大きな集合として、クラスBaseRegulatedMotorがあり、それをEV3LargeRegulatedMotorは継承しています。
インターフェースRegulatedMotorは、これら2つのクラスに実装されています。
また、インターフェースBaseMotorを継承しています。
###クラスBaseRegulatedMotor
◯以下のインターフェースを実装している
BaseMotor,RegulatedMotor...
◯サブクラス
EV3LargeRegulatedMotor, EV3MediumRegulatedMotor...
//BaseRegulatedMotorクラスの一部を抜粋
public abstract class BaseRegulatedMotor extends Device implements RegulatedMotor{
public void forward()
{
reg.newMove(speed, acceleration, +NO_LIMIT, true, false);
}
public void rotate(int angle, boolean immediateReturn)
{
rotateTo(Math.round(reg.getPosition()) + angle, immediateReturn);
}
public void addListener(RegulatedMotorListener listener)
{
reg.addListener(this, listener);
}
public RegulatedMotorListener removeListener()
{
return reg.removeListener();
}
...
}
Point : 継承
extendsを使ってクラスの継承を行うことができます。
[参考記事]extendsキーワード
Point : implements
クラス implements インターフェース{}
という形で、インターフェースを実装するクラスとして定義することができます。
###クラスEV3LargeRegulatedMotor
◯以下のインターフェースを実装している
インターフェース:BaseMotor, Encoder, RegulatedMotor, Tachometer
//BaseRegulatedMotorクラスを継承するEV3LargeRegulatedMotorクラス
public class EV3LargeRegulatedMotor extends BaseRegulatedMotor
{
public EV3LargeRegulatedMotor(Port port)
{
super(port, null, EV3SensorConstants.TYPE_NEWTACHO, MOVE_P, MOVE_I, MOVE_D,
HOLD_P, HOLD_I, HOLD_D, OFFSET, MAX_SPEED);
}
...
}
###インターフェースRegulatedMotor
◯以下のクラスで実装されている
BaseRegulatedMotor, EV3LargeRegulatedMotor, EV3MediumRegulatedMotor...
◯インターフェースBaseMotorを継承している
//インターフェースRegulatedMotorの一部を抜粋
public interface RegulatedMotor extends BaseMotor, Tachometer, Closeable {
public void addListener(RegulatedMotorListener listener);
public RegulatedMotorListener removeListener();
void rotate(int angle, boolean immediateReturn);
public void stop(boolean immediateReturn);
...
###インターフェースBaseMotor
◯インターフェースRegulatedMotorから継承されているインターフェース
public interface BaseMotor {
void forward();
void backward();
void stop();
}
#最後に
読んでいただきありがとうございました。
間違いなど改善すべき点などございましたら教えていただけると幸いです。