似顔絵を描くロボットを製作する。
どのようなロボットに関しては良い案が思いつかなかったので、LEGO社のサイトにある「Building Instructions for Robot Educator」にあるMedium Motor Driving Baseを少し変えただけのものです。変えた点としてはほとんどペンの持ち手の部分だけで、ある程度ペンの太さに合わせられるような構造にしました。太めの線で描けるペンで描こうと思いましたが、ペンの摩擦などによる抵抗にそこまで強くはしていなかった(ペンがほぼ垂直なためペンの紙と接触している点が後ろにずれやすい)のでそのようなペンとしては書く時の抵抗が少なめである筆ペンを使いました。
今回の課題はロボット自体はあまり凝ったことをしていないため、プログラミングを少しだけ工夫しました。ですが、今までこれくらいの大きさのプログラムは書いたことはなかったので、結果的には最後まで期待通りの挙動が得られず、改善点も多いプログラムとなってしまいました。以下が今回使ったプログラムです。
#!/usr/bin/env python3 from ev3dev2.motor import MoveTank,Motor,OUTPUT_A,OUTPUT_B,OUTPUT_C from time import sleep tank = MoveTank(OUTPUT_B,OUTPUT_C) pen_M = Motor(OUTPUT_A) class Pen: def __init__(self): self.pen_M = Motor(OUTPUT_A) #ペンを下す def down(self,speed=2,degree=0): self.pen_M.on_to_position(speed,degree) sleep(0.5) #ペンを上げる def up(self,speed=2,degree=15): self.pen_M.on_to_position(speed,degree) sleep(0.5) class Car: pi = 3.141592653589793 r_t = 2.8 v = 3.0 #定数読み込み with open("constant", "r") as f: cons_list = f.readlines() k = float(cons_list[0].strip("k:").strip()) pen_d = float(cons_list[1].strip("pen_d:").strip()) def __init__(self): self.tank = MoveTank(OUTPUT_B,OUTPUT_C) #まっすぐ進む def go_s(self,d): self.tank.on_for_degrees(Car.v,Car.v, 180/(Car.pi*Car.r_t)*d) sleep(0.5) #方向転換 def cod(self,theta,rl): self.go_s(Car.pen_d) sleep(0.5) if (rl=="l"): self.tank.on_for_degrees((-1)*Car.v,Car.v,theta*Car.k) #d_ else: self.tank.on_for_degrees(Car.v,(-1)*Car.v,theta*Car.k) #d_ self.go_s((-1)*Car.pen_d) sleep(0.5) pen = Pen() car = Car() #ペンの位置の調整 while True: i=input("q=up,a=down,p=ok:") if i=="p": break elif i=="q": pen_M.on_for_degrees(1,1) elif i=="a": pen_M.on_for_degrees(1,-1) print("position:",pen_M.position) pen_M.reset() pen_M.on_to_position(5,15) #命令の読み込みとリストへの変換 command_list = [] while True: file_name = input("file_name:") try: with open(file_name, "r") as f: command_list_raw = f.readlines() for command in command_list_raw: command_list.append(command.strip().split(",")) print(command_list_raw) #debug print(command_list) #debug break except: pass v = 10 #実行 for i,command in enumerate(command_list): if len(command) == 1: if command[0] == "pu": pen.up() elif command[0] == "pd": pen.down() else: try: car.go_s(float(command[0])) except: print("pass1:",i) #debug elif len(command) == 2: try: pen.up() car.cod(float(command[0]),command[1]) pen.down() except: print("pass3:",i) #debug else: print("else") #debug print(i,command) #debug
constant(テキストファイル)
k:2.13 pen_d:9.27
test(テキストファイル)
pd 5 90,r 5
rinnkaku(テキストファイル)
pd 9 45,r 5 45,r 4 45,r 5 45,r 9 60,r 4.5 30,r 4 30,r 4.5 60,r
kami(テキストファイル)
pd 1.5 110,r 1.6 40,l 2 40,r 3.7 40,l 5 60,l
mayu(テキストファイル)
pd pu 0.5 pd 90,l pu 1 pd 3 pu 1.9 pd 3 pu 1 pd 90,r
me(テキストファイル)
pd pd pu 1.5 pd pd 90,r pu 2.7 pd pd pd 1.8 pu 2.9 pd pd 1.6 pu 1.6 pd pd
kuti(テキストファイル)
pd pd pu 4.5 pd pd 90,l pu 3.5 pd pd 5
レポートの製作がギリギリになってしまい細かいところは書く時間が無くなってしまいましたが、大まかな動きとしてはmain.pyが電圧やペンの位置などその時の状況で変わる定数(自分で調整する)をconstantから読み込みrinnkakuやkamiなどの、あるルールに従って書かれたテキストファイルにある命令に従って動くというものです。定数の調整にはtestを使い定規と分度器(90°を測るだけ)を使い、ある程度は正確に調整できますが、確実なものではなく、最後まで確実な調整法はわかりませんでした。顔のパーツごとに命令を分けた理由は、このプログラムを動かすと強制終了が(少なくとも私には)できなかったためです。ごちゃごちゃとしたプログラムになってしまいましたが、このプログラムの長所としては条件さえ整えればそれなりに正確に描くことができること、描かせるための命令を作ることや変更が簡単であることなどであると思います。
下にある画像の絵が今回作ったロボットで描いた絵です。最初はもう少しだけより似顔絵らしいものを書くつもりでしたが、定数の良い調整法が作れなかったことや描いたときの床が完全な平らでなかったことなどにより動きの精度が少し荒く時間がギリギリになったため簡略化しました。また、今回はプログラムを作る段階に時間を使いすぎ、描かせるためのテキストファイルの数値を調整するための時間がすくなかったため、一つのパーツ(テキストファイル一つ分)を描き終わるごとに数値を測って定数などを調整してしまったので、完全に1回で描き切った場合はよりずれたと思いますが、もう少しちゃんと調整できれば、一回で描いてもおおよそこのぐらいの精度で描けるのではないかと思います。