Pythonロボティクスコース レッスン 24
テーマ.6-3 車型ロボット用コントローラの制作
車型ロボットを操作するオリジナルコントローラーを制作しよう
チャプター1
このレッスンで学ぶこと
このレッスンでは、クラスの継承を重ねる方法と同時に複数のクラスを継承する方法を新たに学びます。また、レッスンの後半では、テーマ.6-1で製作した車型ロボットのクラスと新たに製作するコントローラーのクラスの2つを継承させることで、コントローラーで操作できる車型ロボットを製作します。
チャプター2
新しいPython文法の学習
前回のレッスンでは、クラスの継承と、継承元がもつメソッドをオーバーライド(上書き)する方法を学びました。このクラスの継承は1つ限りということはなく、継承を重ねたり、複数のクラスを同時に継承することもできます。では、それぞれの継承について詳しく見ていきましょう。
2. 1 クラスの継承を重ねる
Pythonでは、別のクラスを継承して作成されたクラスをさらに継承することができます。例えば次のコードでは、クラスBはクラスAを継承しており、さらにクラスCはクラスBを継承しています。これによって、クラスCはクラスAとクラスBの2つからプロパティとメソッドを継承します。
class A: . . class B(A): . . class C(B): . .
では、RPGの世界に例えて具体的なコードを書いてみましょう。RPGというジャンルでは、キャラクターの職業がレベルアップしていくことで、新たに強い技を覚える仕様のゲームが多数あります。そこで、「ソルジャー」⇒「ナイト」⇒「ロイヤルナイト」と職業がレベルアップしていくことで、前の職業の技も継承しつつ新たな技も習得するという設定で以下のコードを考えてみます。
【 サンプルコード 2-1-1 】
class Soldier: # ソルジャー
def get_job(self): # 職業名を表示する
print("I'm a soldier.")
def get_action(self): #使用可能な技名の一覧を表示する
print("Normal attack.")
class Knight(Soldier): # ナイト
def get_job(self):
print("I'm a knight.")
def get_action(self):
super().get_action()
print("Strong attack.")
class RoyalKnight(Knight): # ロイヤルナイト
def get_job(self):
print("I'm a royal knight.")
def get_action(self):
super().get_action()
print("Ultimate attack.")
character = RoyalKnight()
character.get_job()
character.get_action()
このコードでは、Soldier
からKnight
へ継承し、さらにKnight
からRoyalKnight
への継承を行っています。継承の過程でget_job()
とget_action()
の2つのメソッドをオーバーライドしています。このプログラムをMuのエディタエリアに複製して実行してみましょう。
(実行結果)
I'm a royal knight. Normal attack. Strong attack. Ultimate attack.
get_job()
メソッドを実行すると、RoyalKnight
で定義した処理だけが行われています。一方で、get_action()
メソッドでは、Soldier
とKnight
、RoyalKnight
の3つのクラスで定義した処理がすべて実行されています。
この2つの違いはsuper()
関数でスーパークラスを呼び出し、そのメソッドを実行しているかどうかという点にあります。このように、super()
関数でスーパークラスを呼び出す連鎖をつくることで、継承を重ねた全てのクラスのメソッドを引き継ぐことができます。
2. 2 複数のクラスを継承する
【 サンプルコード 2-1-1 】のように、「ソルジャー」⇒「ナイト」⇒「ロイヤルナイト」と順序立てができる場合は、継承を重ねる方法が適していますが、「ソーサラー(魔法使い)」と「モンク(僧侶)」という順序立てが出来ない2つの職業を習得して「賢者」へとレベルアップできるという仕様では、この方法はあまり向いているとは言えません。
Pythonにはクラスの継承を重ねる以外にも、複数のクラスを同時に継承する方法が用意されています。以下の例では、クラスAとクラスBを同時に継承したクラスCを作成しています。
class A: . . class B: . . class C(A, B): # 「,」で区切ることで複数のクラスを継承できる . .
では、この方法を使用して「ソーサラー(Sorcerer
)」と「モンク(Monk
)」の2つのクラスを継承した「賢者(Sage
)」のクラスを定義してみましょう。
【 サンプルコード 2-2-1 】
class Monk:
def heal(self): # 回復魔法
print("Heal!")
class Sorcerer:
def fire_ball(self): # 火炎魔法
print("Fire ball!")
class Sage(Monk, Sorcerer): # ソーサラーとモンクの両方を継承
def ice_storm(self): # 氷結魔法
print("Ice storm!")
character = Sage()
character.heal() # Monkから継承
character.fire_ball() # Sorcererから継承
character.ice_storm() # Sageで新たに定義
複数のクラスを継承すると、それぞれのプロパティとメソッドを引き継ぐことができます。では、このコードをエディアエリアに複製して実行してみましょう。
(実行結果)
Heal! Fire ball! Ice storm!
見事に、Sage
クラスのインスタンスからSorcerer
クラスとMonk
クラスから継承したメソッドを呼び出すことができました。
■ 複数のクラスを継承する場合の注意点
複数のクラスを継承すると、それぞれのクラスのプロパティとメソッドを引き継ぐことができるというメリットがありましたが、継承したクラスの中に同じ名前のメソッドが含まれている場合はどうなるでしょうか?
次のコードでは、どちらも__init__()
メソッドをもつ「Super_1
クラス」と「Super_2
クラス」を継承した「Sub
クラス」を定義し、そのインスタンスを作成しています。
【 サンプルコード 2-2-2 】
class Super_1:
def __init__(self):
print("I'm Super 1.")
class Super_2:
def __init__(self):
print("I'm Super 2.")
class Sub(Super_1, Super_2):
def __init__(self):
super().__init__()
sub = Sub()
Sub
クラスの__init__()
メソッド内でsuper()
関数を実行し、スーパークラスを呼び出しています。しかし、このコードを実行するとSuper_1
クラスの__init__()
メソッドしか実行されません。
(実行結果)
I'm Super 1.
このような結果となるのは、MicroPythonがsuper()
関数で1つのクラスしか呼び出せない仕様になっているためです。そのため、この場合はクラスを重ねて継承する方法が有効です。
【 サンプルコード 2-2-3 】
class Super_1:
def __init__(self):
print("I'm Super 1.")
class Super_2(Super_1):
def __init__(self):
super().__init__()
print("I'm Super 2.")
class Sub(Super_2):
def __init__(self):
super().__init__()
sub = Sub()
このコードを実行すると、Super_1
クラスとSuper_2
クラスのどちの__init__()
メソッドも呼び出せていることが確認できます。
(実行結果)
I'm Super 1. I'm Super 2.
チャプター3
コントローラーの組み立て
ここからは、コントローラーで操作できる車型ロボットを製作していきます。早速、レッスン22(テーマ.6-1)で制作した車型ロボットを準備し、新たに赤外線フォトリフレクタとカラーセンサーを使用したコントローラーを組み立てましょう。
3. 1 組み立てに必要なパーツ
【 パーツ一覧 】
- レッスン22で製作した車型ロボット×1
- 赤外線フォトリフレクタ×1
- カラーセンサー×1
- センサー接続コード(3芯30cm)×1
- センサー接続コード(4芯30cm)×1
- ブロック基本四角(白)×4
- ブロック基本四角(グレー)×2
- ブロック基本四角(赤)×1
- ブロック基本四角(緑)×1
- ブロック基本四角(青)×1
- ブロック基本四角(黄)×1
- ブロックハーフA(グレー)×2
- ブロックハーフC(白)×6
- ステー×1
- 回転軸×2
【 アーテックブロックの形状 】
3. 2 組立説明書
車型ロボットを分解している場合は、以下のリンク先から組立説明書を確認して、再度組み立てを行ってください。
チャプター4
車型ロボットを操作するプログラムの作成
レッスン22で作成した車型ロボットの制御クラス「VehicleRobot
」と、組み立てたコントローラーを制御する新たなクラス「Controller
」の2つを継承し、コントローラー付きの車型ロボットのクラス「ControlRobot
」を作成します。
このように、何かを製作するときに、部品や機能ごとにクラスを分けて定義しておくと、他のものを製作するときに、クラスを再利用して素早く作業を進めることができます。
では、はじめにコントローラーのクラスを定義し、そのあとでコントローラー付き車型ロボットのクラスを定義しましょう。
4. 1 コントローラーのクラスの定義
組み立てたコントローラーの操作は左側と右側に分かれています。
それぞれ回転軸を取り付けたブロックを回し、センサーの正面に色の付いたブロックを置くことで、次の信号(文字列)を出力します。
【 左側で出力する信号 】
赤外線フォトリフレクタ の正面に置くブロックの色 | 出力する信号(文字列) |
---|---|
白色 | "on" |
なし | "off" |
【 右側で出力する信号 】
カラーセンサー の正面に置くブロックの色 | 出力する信号(文字列) |
---|---|
青色 | "b" |
赤色 | "r" |
緑色 | "g" |
なし | "none" |
※ "b"
、"r"
、"g"
はそれぞれの色を表す英単語の頭文字です。
※ 右側の黄色のブロックは次のチャプターの課題で使用します。
そして、この信号を出力を制御するために、次のプロパティとメソッドを持つ「Controller
クラス」を定義します。
【 Controller
クラスのプロパティ 】
プロパティ名 | 役割 |
---|---|
irp | IRPhotoReflector クラスのインスタンスを格納する。 |
cs | ColorSensor クラスのインスタンスを格納する。 |
threshold_irp | 赤外線フォトリフレクタで白色のブロックが正面にあるかどうかを判別するためのしきい値 |
【 Controller
クラスのメソッド 】
メソッド名 | 役割 | 引数 | 戻り値 |
---|---|---|---|
set_controller() | __init__() メソッドに代わるコンストラクタ。 | pin_irp :赤外線フォトリフレクタの接続端子名 pin_cs :カラーセンサーの接続端子名 | なし |
get_signals() | 左右の信号を取得するメソッド。 | なし | (signal_l , signal_r) 左側の信号と右側の信号を格納したタプル |
通常はコンストラクタとして、__init__()
メソッドを定義しますが、このController
クラスは他のクラス(ここではVehicleRobot
クラス)と組み合わせて継承されることを前提としているため、そのままでは__init__()
メソッドが衝突してしまいます。
そこで、その代わりとなるset_controller()
メソッドを定義して、継承されたControlRobot
クラスの__init__()
メソッドの中で呼び出します。
では、順番にこれら2つのメソッドを定義していきましょう。
■ set_controller()
メソッドの定義
まずは、Controller
クラスを宣言し、その中でset_controller()
メソッドを宣言します。set_controller()
メソッドでは、IRPhotoReflector
クラス(赤外線フォトリフレクタ)とColorSensor
クラス(カラーセンサー)のインスタンスを作成するため、そのために必要な引数として、接続先の端子名が渡されるpin_irp
とpin_cs
を用意します。これらの引数の前に「*(アスタリスク)」を入れて、キーワード引数として渡すように強制しておきましょう。
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
次に、引数として受け取った端子名を渡し、IRPhotoReflector
クラスとColorSensor
クラスのインスタンスを作成します。作成したインスタンスはそれぞれirp
プロパティとcs
プロパティに格納しましょう。
追加【4行目~8行目】
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
from pyatcrobo2.parts import IRPhotoReflector
from pyatcrobo2.parts import ColorSensor
self.irp = IRPhotoReflector(pin_irp)
self.cs = ColorSensor(pin_cs)
最後に、赤外線フォトリフレクタで白色のブロックが正面にあるかどうかを判別するためのしきい値を設定します。新しいプログラムを作成し、以下のコードを実行して、赤外線フォトリフレクタの正面に白色のブロックを置いたときと、置いていないときの値を先に調べておきましょう。調べた結果からその平均をしきい値として設定します。
※ 太陽光には赤外線が含まれているため、赤外線フォトリフレクタの正面に日差しが当たらないように注意して、値を調べるようにしましょう。
【 赤外線フォトリフレタの値を調べるためのコード 】
from pyatcrobo2.parts import IRPhotoReflector
import time
irp = IRPhotoReflector("P0")
while True:
print(irp.get_value())
time.sleep_ms(500)
求めたしきい値をthreshold_irp
プロパティに格納します。カラーセンサーのしきい値は今回用意しません。しきい値を使用しない代わりにColorSensor
クラスに用意されているget_colorcode()
メソッドを使用して、「赤」や「緑」などの色として直接取得します。
追加【9行目】
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
from pyatcrobo2.parts import IRPhotoReflector
from pyatcrobo2.parts import ColorSensor
self.irp = IRPhotoReflector(pin_irp)
self.cs = ColorSensor(pin_cs)
self.threshold_irp = 500 # 自分で求めたしきい値を設定してください。
なお、前のレッスンで取り組んだライントレース機能の作成では、環境に合わせてしきい値が設定できるように、プログラムの中で取得した赤外線フォトリフレクタの値からしきい値を求めるメソッドを用意していました。もちろん今回も同様のメソッドを用意することはできますが、コードの量が増えてしまうため、省略しています。
■ get_signals()
メソッドの定義
次に、コントローラーの左側と右側の両方からの信号を取得するget_signals()
メソッドを定義します。左側はさきほど設定したthreshold_irp
プロパティのしきい値と取得した赤外線フォトリフレクタの値を比較して出力する信号を決定します。
追加【11行目~16行目】
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
from pyatcrobo2.parts import IRPhotoReflector
from pyatcrobo2.parts import ColorSensor
self.irp = IRPhotoReflector(pin_irp)
self.cs = ColorSensor(pin_cs)
self.threshold_irp = 500
def get_signals(self)
val_irp = self.irp.get_value()
if val_irp > self.threshold_irp:
signal_l = "on" # 白色のブロックが正面に置かれている
else:
signal_l = "off" # 正面に何もない
右側はColorSensor
クラスのget_colorcode()
メソッドを使って出力する信号を決めます。このメソッドを実行すると、色に応じてColorSensor
クラスで定義されている次のプロパティの値が返されます。
【 ColorSensor
クラスのget_colorcode()
メソッドで返される値 】
色 | プロパティ名 | 値 |
---|---|---|
赤 | ColorSensor.COLOR_RED | 1 |
緑 | ColorSensor.COLOR_GREEN | 2 |
青 | ColorSensor.COLOR_BLUE | 3 |
白 | ColorSensor.COLOR_WHITE | 4 |
黄 | ColorSensor.COLOR_YELLOW | 5 |
オレンジ | ColorSensor.COLOR_ORANGE | 6 |
紫 | ColorSensor.COLOR_PURPLE | 7 |
該当なし | ColorSensor.COLOR_UNDEF | 0 |
これらは定数としての扱いになるため、取得した値から何色であるかを条件文で判定するときは、次のようにインスタンスまたはクラスからプロパティを呼び出して比較します。
from pyatcrobo2.parts import ColorSensor cs = ColorSensor("I2C") color = cs.get_colorcode() if color == cs.COLOR_RED: # 「color == 1」のように数値を書いて比較はしない。 print("red") else: print("not red")
そのため、以下のようなコードを書いて、出力する信号を決めましょう。
追加【18行目~26行目】
def get_signals(self):
val_irp = self.irp.get_value()
if val_irp > self.threshold_irp:
signal_l = "on"
else:
signal_l = "off"
color = self.cs.get_colorcode()
if color == self.cs.COLOR_RED:
signal_r = "r"
elif color == self.cs.COLOR_GREEN:
signal_r = "g"
elif color == self.cs.COLOR_BLUE:
signal_r = "b"
else:
signal_r = "none"
最後に、決定した2つの信号signal_l
とsignal_r
をタプルとして返します。これで、Controller
クラスの定義ができました。
追加【28行目】
def get_signals(self):
val_irp = self.irp.get_value()
if val_irp > self.threshold_irp:
signal_l = "on"
else:
signal_l = "off"
color = self.cs.get_colorcode()
if color == self.cs.COLOR_RED:
signal_r = "r"
elif color == self.cs.COLOR_GREEN:
signal_r = "g"
elif color == self.cs.COLOR_BLUE:
signal_r = "b"
else:
signal_r = "none"
return (signal_l, signal_r)
■ 前のレッスンでget_colorcode()
メソッドを使用しなかった理由
前のレッスンでも課題の中で、カラーセンサーを使い、コースに描かれた円の色の識別を行いました。今回と同様にget_colorcode()
メソッドを使用することもできましたが、このメソッドはあらかじめStuduino:bit側で設定されているしきい値から色を判別するものであるため、ブロックのように均一なものであればある程度正確に判別できますが、印刷物のようなインクの種類や印刷する紙の質によってばらつきがあるものでは、誤った判別をしてしまうことがあります。そのため、印刷されたものに合わせてしきい値を設定して、色を判別するということを行いました。
4. 2 コントローラー付き車型ロボットのクラスの定義
新たに定義したController
クラスとレッスン22で用意したVechicleRobot
クラスを継承してコントローラー付きの車型ロボットのクラスを定義します。このクラスでは、コントローラーから出力される信号に対して、それぞれ次のように動作を制御します。
【 左側の出力信号に対する動作 】
コントローラー の出力信号 | 動作 |
---|---|
"on" | 右側の出力信号で決められた動作を行う |
"off" | ブレーキをかけて停止 |
【 右側の出力信号に対する動作 】
コントローラー の出力信号 | 動作 |
---|---|
"b" | (左側の出力信号が"on" のとき)前進 |
"r" | (左側の出力信号が"on" のとき)右回転 |
"g" | (左側の出力信号が"on" のとき)左回転 |
"none" | ブレーキなしで停止 |
【 オーバーライドするメソッド 】
__itni__()
メソッド
継承するVehicleRobot
クラスの__init__()
メソッドをオーバーライドし、継承するもうひとつのController
クラスのset_controller()
メソッドを実行します。また、操作する車型ロボットの走行時の速さ(左右のタイヤの回転の速さ)を変更したい場合もこのメソッド内で処理します。
【 新たに追加するメソッド 】
start()
メソッド
インスタンスからこのメソッドを呼び出すことで、コントローラーで操作できるようにします。内部では、継承したController
クラスのget_signals()
メソッドを繰り返し実行して信号を取得し、それによって車型ロボットの走行を制御します。
では、順番に2つのメソッドを定義していきましょう。
■ __init_()
メソッドのオーバーライド
前の続きからコードを書いていきます。まずは先頭で、Studuino:bit内に保存しているvehicle(.py)
からVehicleRobot
クラスをインポートしましょう。
追加【1行目】
from vehicle import VehicleRobot
class Controller():
def set_controller(self, *, pin_irp, pin_cs):
次に、Controller
クラスを定義したコードの下に、新しくContorolRobot
クラスのコードを書いていきます。ControlRobot
クラスは、VehicleRobot
、Controller
の順番にクラスを継承します。
このクラスのコンストラクタである__init__()
メソッドでは、VehicleRobot
クラスの__init__()
メソッドとController
クラスのset_controller()
メソッドの2つに必要な引数を受け取る必要があります。そのため、次のようにコードを書くことになります。
追加【36行目~38行目】
class ControlRobot(VehicleRobot, Controller):
def __init__(self, *, pin_l, pin_r, pin_irp, pin_cs):
super().__init__(pin_l=pin_l, pin_r=pin_r) # VehicleRobotクラスより継承
self.set_controller(pin_irp=pin_irp, pin_cs=pin_cs) # Controllerクラスより継承
そして、タイヤの回転の速さを変更したい場合はこの中で、VehicleRobot
クラスのset_speed_to_left()
メソッドとset_speed_to_right()
メソッドを呼び出します。
追加【39行目~40行目】
class ControlRobot(VehicleRobot, Controller):
def __init__(self, *, pin_l, pin_r, pin_irp, pin_cs):
super().__init__(pin_l=pin_l, pin_r=pin_r)
self.set_controller(pin_irp=pin_irp, pin_cs=pin_cs)
self.set_speed_to_left(5) # 1~10の10段階で好きな速さを設定
self.set_speed_to_right(5) # 1~10の10段階で好きな速さを設定
■ start()
メソッドの定義
続けて、コントローラーの出力信号によって動作を制御するstart()
メソッドを定義していきます。このメソッドでは次の流れで処理を行います。
まずは、get_signals()
メソッドで出力信号を取得し、その左側の信号(インデックスが「0」のデータ)が"off"
の場合は、brake()
メソッドを呼び出すコードを書きましょう。
追加【40行目~45行目】
def start(self):
while True:
signals = self.get_signals()
if signals[0] == "off":
self.brake() # ブレーキをかけて停止
次に、左側の信号が"on"
だった場合に、さらに右側の信号(インデックスが「1」のデータ)によって4つに分岐して動作を制御するコードを書きます。
追加【46行目~54行目】
def start(self):
while True:
signals = self.get_signals()
if signals[0] == "off":
self.brake()
else:
if signals[1] == "b":
self.move_forward() # 前進
elif signals[1] == "r":
self.rotate_right() # 右回転
elif signals[1] == "g":
self.rotate_left() # 左回転
else:
self.stop() # ブレ―キをかけずに止まる
これで、ControlRobot
クラスが定義できました。
4. 3 プログラムの動作を確認する
定義したクラスが正しく動作することを確認するため、プログラムの末尾でインスタンスを作成し、start()
メソッドを呼び出すコードを追加します。
robo = ControlRobot(pin_l="M1", pin_r="M2", pin_irp="P0", pin_cs="I2C")
robo.start()
完成したプログラムの全体像は次のようになります。誤りがないかもう一度確認しておきましょう。
【 サンプルコード 4-3-1 】
from vehicle import VehicleRobot
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
from pyatcrobo2.parts import IRPhotoReflector
from pyatcrobo2.parts import ColorSensor
self.irp = IRPhotoReflector(pin_irp)
self.cs = ColorSensor(pin_cs)
self.threshold_irp = 500
def get_signals(self):
val_irp = self.irp.get_value()
if val_irp > self.threshold_irp:
signal_l = "on"
else:
signal_l = "off"
color = self.cs.get_colorcode()
if color == self.cs.COLOR_RED:
signal_r = "r"
elif color == self.cs.COLOR_GREEN:
signal_r = "g"
elif color == self.cs.COLOR_BLUE:
signal_r = "b"
else:
signal_r = "none"
return (signal_l, signal_r)
class ControlRobot(VehicleRobot, Controller):
def __init__(self, *, pin_l, pin_r, pin_irp, pin_cs):
super().__init__(pin_l=pin_l, pin_r=pin_r)
self.set_controller(pin_irp=pin_irp, pin_cs=pin_cs)
self.set_speed_to_left(5)
self.set_speed_to_right(5)
def start(self):
while True:
signals = self.get_signals()
if signals[0] == "off":
self.brake()
else:
if signals[1] == "b":
self.move_forward()
elif signals[1] == "r":
self.rotate_right()
elif signals[1] == "g":
self.rotate_left()
else:
self.stop()
robo = ControlRobot(pin_l="M1", pin_r="M2", pin_irp="P0", pin_cs="I2C")
robo.start()
USBケーブルを接続したまま動作を確認する場合は、メニューの「実行」をクリックしてプログラムを実行します。
USBケーブルを外して動作を確認したい場合は、このプログラムをmain(.py)
と名前を付けてPC上に保存し、メニューのファイルからStuduino:bitへ写しましょう。Studuino:bitのリセットボタンを押すと、このプログラムが実行され、動作が確認できます。
※ Studuino:bit上からvehicle.pyのファイルを削除してしまった場合は、以下のリンクの上で右クリックをしてファイルをPCにダウンロードし、もう一度Studuino:bitへ保存しましょう。
チャプター5
課題:コントローラーの信号を1つ追加しよう
この課題では、コントローラーの右側にある黄色のブロックについて、新たな出力信号を追加し、車型ロボットが後進する操作を行えるように【 サンプルコード 4-3-1 】を改造してみましょう。
【 追加する出力信号(右側) 】
色 | 出力信号(文字列) |
---|---|
青 | "b" |
赤 | "r" |
緑 | "g" |
黄 | "y" |
なし | "none" |
【 追加する車型ロボットの動作 】
出力信号 | 動作 |
---|---|
"b" | 前進(左側の出力信号が"on" のとき) |
"r" | 右回転(左側の出力信号が"on" のとき) |
"g" | 左回転(左側の出力信号が"on" のとき) |
"y" | 後進(左側の出力信号が"on" のとき) |
"none" | ブレーキなしで停止 |
5. 1 プログラムの作成例
この課題は【 サンプルコード 4-3-1 】の内容が理解できていれば、簡単に信号とそれに対する動作を追加することができます。
- 信号の追加
【 サンプルコード 4-3-1 】の19行目~27行目が、コントローラーの右側の出力信号を決める処理になっています。そのため、ここにもうひとつ条件文を追加して、色が黄色のときの出力信号を設定します。 - 動作の追加
コントローラーの右側の出力信号に対する車型ロボットの動作の制御は【 サンプルコード 4-3-1 】の46行目~53行目で行っています。そのため、こちらももうひとつ条件文を追加して、「”y”」の信号を取得したときに、後進する「move_backward()
メソッド」を呼び出すようにします。
以上の2点の変更を行ったコードが以下になります。
【 サンプルコード 5-1-1 】
追加【26行目、27行目、54行目、55行目】
from vehicle import VehicleRobot
class Controller:
def set_controller(self, *, pin_irp, pin_cs):
from pyatcrobo2.parts import IRPhotoReflector
from pyatcrobo2.parts import ColorSensor
self.irp = IRPhotoReflector(pin_irp)
self.cs = ColorSensor(pin_cs)
self.threshold_irp = 500
def get_signals(self):
val_irp = self.irp.get_value()
if val_irp > self.threshold_irp:
signal_l = "on"
else:
signal_l = "off"
color = self.cs.get_colorcode()
if color == self.cs.COLOR_RED:
signal_r = "r"
elif color == self.cs.COLOR_GREEN:
signal_r = "g"
elif color == self.cs.COLOR_BLUE:
signal_r = "b"
elif color == self.cs.COLOR_YELLOW:
signal_r = "y"
else:
signal_r = "none"
return (signal_l, signal_r)
class ControlRobot(VehicleRobot, Controller):
def __init__(self, *, pin_l, pin_r, pin_irp, pin_cs):
super().__init__(pin_l=pin_l, pin_r=pin_r)
self.set_controller(pin_irp=pin_irp, pin_cs=pin_cs)
self.set_speed_to_left(5)
self.set_speed_to_right(5)
def start(self):
while True:
signals = self.get_signals()
if signals[0] == "off":
self.brake()
else:
if signals[1] == "b":
self.move_forward()
elif signals[1] == "r":
self.rotate_right()
elif signals[1] == "g":
self.rotate_left()
elif signals[1] == "y":
self.move_backward()
else:
self.stop()
robo = ControlRobot(pin_l="M1", pin_r="M2", pin_irp="P0", pin_cs="I2C")
robo.start()
チャプター6
おわりに
6. 1 このレッスンのまとめ
このレッスンでは新たに「クラスを重ねて継承する方法」と「複数のクラスを継承する方法」について学習しました。このように複雑にクラスの継承が行えることは、コードの再利用性を高められるというメリットがある一方で、仕様をしっかりと理解していないと、思わぬところでつまづいてしまうこともあります。今回学んだ基礎をしっかりと理解して、徐々にクラスを使いこなせるようになっていきましょう。
6. 2 次のレッスンについて
次のレッスンでは、算術演算子や比較演算子などに対応する特殊なメソッドのオーバーライドと、クラスメソッドとインスタンスメソッドという2つのメソッドのちがいについて学習します。レッスンの後半では、これまでの学習のまとめとして、ボタン操作で動きをプログラミングできる車型ロボットを製作します。