ゴムを使わず小型のタイヤによって固定した。 これによって、ペンがしっかり固定され、多少押し付けても外れなくなった。 また、単純な作りなので、直したり、改良を加えたりしやすかった。
はじめは前にペンを機体の前につけ、A1左のチームと同じような仕組みにしていたが、ペンを持ち上げる過程で用紙に余分な線が入ってしまったので、現在のような中心でペンを上げ下げする形に変更した。
直接モータに上下させていたので、モータ自体がはぜれてしまうのを防ぐ為に取り付けたサポーターが、結果的にペンの台やMindstorm本体の支えにもなり、大いに役立った。
キャタピラを使うと、紙が動いてしまったり、小回りが利かなかったため、タイヤに変更した。 タイヤにすると、回転の際のペンのずれも減り、それを修正するソフトウェア面での負担が減った。
時間をあまりかけなかったので、重心の心配をしておらず、急にバックをしたとき機体が浮くことがあった。各行動ごとに時間を入れることで解決したが、最初から予測するべきだった。また、モータにつないだコードの付け方でモータの挙動が変化したことに悩まされた。
定義した動き
#define turn_left(t) go_straight(10);Wait(30);OnRev(OUT_A);OnFwd(OUT_C);Wait(t);Off(OUT_A+OUT_C);Wait(50);OnRev(OUT_A+OUT_C);Wait(10);Off(OUT_A+OUT_C);Wait(50);//修正をいれ左に曲がる #define turn_right(t) go_straight(10);Wait(30);OnFwd(OUT_A);OnRev(OUT_C);Wait(t);Off(OUT_A+OUT_C);Wait(50);OnRev(OUT_A+OUT_C);Wait(10);Off(OUT_A+OUT_C);Wait(50);//修正をいれ右に曲がる #define go_straight(t) OnFwd(OUT_A+OUT_C);Wait(t);Off(OUT_A+OUT_C);//まっすぐ進む #define A 18//進む距離の目安 #define B 29//30度曲がる時間 #define pen_up OnFwd(OUT_B);Wait(5);Off(OUT_B);//ペンを上げる #define pen_down OnRev(OUT_B);Wait(5);Off(OUT_B);//ペンを下げる
顔を描く動き
task main() { //face//顔を描く go_straight(2*A);//輪郭を描く pen_up; turn_right(B);//30度右に旋回 pen_down; go_straight(3*A);//輪郭を描く pen_up; turn_right(B);//30度右に旋回 pen_down; go_straight(2*A);//輪郭を描く pen_up; turn_left(4*B);//120度左に旋回 pen_down; go_straight(5*A);//輪郭を描く pen_up; turn_left(7/3*B);//70度左に旋回 pen_down; go_straight(7/2*A);//輪郭を描く pen_up; turn_left(7/3*B);//70度左に旋回 pen_down; go_straight(7/2*A);//輪郭を描く pen_up; turn_left(7/3*B);//70度左に旋回 pen_down; go_straight(11/2*A);//輪郭を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; //ear&glass//耳&眼鏡を描く go_straight(A);//耳を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//耳を描く pen_up; turn_right(3/2*B);//45度右に旋回 pen_down; go_straight(2*A);//耳を描く pen_up; turn_right(4*B);//120度右に旋回 go_straight(5/2*A);//左の眼鏡の位置に移動 turn_left(11/3*B);//110度左に旋回 pen_down; go_straight(A); //左の眼鏡を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//左の眼鏡を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//左の眼鏡を描く pen_up; turn_left(3*B);//90度左に旋回 go_straight(A);//右の眼鏡の位置に移動 turn_left(3*B);//90度左に旋回 pen_down; go_straight(A);//右の眼鏡を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//右の眼鏡を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//右の眼鏡を描く pen_up; turn_left(10/3*B);//100度左に旋回 go_straight(2*A);右耳の位置に移動 turn_right(2*B);//60度右に旋回 pen_down; go_straight(3/2*A);//右耳を描く pen_up; turn_right(3/2*B);//45度右に旋回 pen_down; go_straight(A);//右耳を描く pen_up; turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//右耳を描く pen_up; go_straight(2*A);髪の位置に移動 turn_left(3*B);//90度左に旋回 pen_down; //hair//髪を描く go_straight(A);//髪を描く pen_up; turn_right(3*B);//90度右に旋回 go_straight(A);//移動 turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//髪を描く pen_up; turn_left(3*B);//90度左に旋回 go_straight(A);//移動 turn_left(3*B);//90度左に旋回 pen_down; go_straight(A);//髪を描く pen_up; turn_right(3*B);//90度右に旋回 go_straight(A);//移動 turn_right(3*B);//90度右に旋回 pen_down; go_straight(A);//髪を描く pen_up; go_straight(4*A);//鼻の位置に移動 turn_right(3*B);//90度右に旋回 go_straight(A);//鼻の位置に移動 turn_left(3/2*B);//45度左に旋回 pen_down; //nose&mouth//鼻&口を描く go_straight(A);//鼻を描く pen_up; turn_left(3*B);//90度左に旋回 pen_down; go_straight(A);//鼻を描く pen_up; turn_right(3/2*B);//45度右に旋回 go_straight(A);//口の位置に移動 turn_right(3/2*B);//45度右に旋回 pen_down; go_straight(A);//口を描く }
だいたい出来上がってきた(^^)
口ができていないので口をつける(^_^)
とてもいい感じになった!いざ発表!!
(・_・;)エッ......?naze?おそらくマットなどの上で距離を測っていたため木の板の上で少しずれてしまったのだろう。もうすこし時間があればきれいにできたかもしれない。
まず動きの定義では進む距離の目安を決めることによりその何倍かすることで 直線の長さを表すことができた。また曲がる角度がバラバラなのでひとつの角度の 曲がる時間をはかり、その角度を掛け算や割り算を使い表現することにより プログラムがより楽になった。初めに距離と曲がる時間を定義することにより 電池消耗で変化する時間を直すのは定義した数字を変えるだけなので 非常に楽だった。
ロボットが曲がる時のずれがでて、曲がるときは線が繋がらなかった。 それを修正するために、バックなどを取り入れ線のずれを少なくした。 ロボットを作ったりプログラミングなど始めてのことが多く上手く 出来なかった。またあまり時間がかけれなかった。
// 定数で距離など調整 #define L 25 #define NNM 35 //L*sqrt(2) つまり斜めのときの距離 #define NNMn 55 //L*sqrt(5) 斜めの傾き2のときの距離 #define TURN_T 86 //90度回転するのにかかる時間 #define PEN_T 5 //ペンを上げる時間 #define COR_T 10 //使わなかった //まっすぐ与えられた長さを進む void go(int length){ Wait(50); OnFwd(OUT_A); OnFwd(OUT_C); Wait(length); Off(OUT_A+OUT_C); Wait(50); } //まっすぐ与えられた長さを戻る void back(int length){ Wait(50); OnRev(OUT_C); OnRev(OUT_A); Wait(length); Off(OUT_A+OUT_C); Wait(length); } //与えられた角度だけ左に回転する void tl(int angle){ penUP(); go(COR_T); OnFwd(OUT_C); OnRev(OUT_A); Wait(TURN_T*angle/90); Off(OUT_A+OUT_C); back(COR_T); penDOWN(); correct(); } //与えられた角度だけ右に回転する void tr(int angle){ penUP(); go(COR_T); OnFwd(OUT_A); OnRev(OUT_C); Wait(TURN_T*angle/90); Off(OUT_A+OUT_C); back(COR_T); penDOWN(); correct(); } //ペンを上げる void penUP(){ Wait(50); OnFwd(OUT_B); Wait(PEN_T); Off(OUT_B); } //ペンを下げる void penDOWN(){ Wait(50); OnRev(OUT_B); Wait(PEN_T); Off(OUT_B); } //ペンを上下させた後の修正 void correct(){ } task main() { //ear go(2*L); tl(90); go(L); tl(90); go(L); tl(45); go(NNM); tr(15); //why??? //jaw go(NNMn); tl(28); go(NNM); tl(45); go(L); tl(45); go(NNM); tl(20); go(NNMn); tl(30); //ear go(2*L); tr(90); go(L); tr(90); go(L); tr(45); go(NNM); penUP(); go(NNM); tr(45); //mouth penDOWN(); go(3*L); tr(90); penUP(); go(2*L); tr(90); penDOWN(); //eyes go(L); penUP(); go(L); penDOWN(); go(L); }
#define L 20 //A4に入るよう25->20へ #define NNM 28 // Lに伴い変更 #define NNMn 45 //上に同じ #define TURN_T 86 //変化なし #define PEN_T 5 //上に同じ #define COR_T 10 //今回使用 //進んだ後一旦停止してずれや横転を防止 void go(int length){ Wait(50); OnFwd(OUT_A); OnFwd(OUT_C); Wait(length); Off(OUT_A+OUT_C); Wait(50); } //バック。最後に一旦停止 void back(int length){ Wait(50); OnRev(OUT_C); OnRev(OUT_A); Wait(length); Off(OUT_A+OUT_C); Wait(length); } //ペンのずれを防止するため最初にペンを上げ、左回転後にバックし、ペンを下げる void tl(int angle){ penUP(); go(COR_T); OnFwd(OUT_C); OnRev(OUT_A); Wait(TURN_T*angle/90); Off(OUT_A+OUT_C); back(COR_T); penDOWN(); correct(); } //上に同じ ただし右 void tr(int angle){ penUP(); go(COR_T); OnFwd(OUT_A); OnRev(OUT_C); Wait(TURN_T*angle/90); Off(OUT_A+OUT_C); back(COR_T); penDOWN(); correct(); } ペンを上げる void penUP(){ Wait(50); OnFwd(OUT_B); Wait(PEN_T); Off(OUT_B); } ペンを下げる void penDOWN(){ Wait(50); OnRev(OUT_B); Wait(PEN_T); Off(OUT_B); } 今回も不使用 void correct(){ /* OnRev(OUT_A); OnRev(OUT_C); Wait(COR_T); Off(OUT_A+OUT_C); penDOWN(); */ } task main () { //ear go(2*L); tl(90); go(L); tl(90); go(L); tl(45); go(NNM); tr(15); //why??? //jaw go(NNMn); tl(28); go(NNM); tl(45); go(L); tl(45); go(NNM); tl(20); go(NNMn); tl(30); //ear go(2*L); tr(90); go(L); tr(90); go(L); tr(45); go(NNM); penUP(); go(NNM); tr(30); //mouth go(L/2); penDOWN(); go(2*L); tr(90); penUP(); go(2*L); tr(90); penDOWN(); //eyes go(L); penUP(); go(L); penDOWN(); go(L); //hair penUP(); tl(90); go(2*L); tl(135); penDOWN(); go(NNM); tr(90); go(NNM); tl(90); go(NNM); tr(90); go(NNM); }
first code
あごが飛び出した。
second code(髪を追加/定数Lのサイズを変更)
タイヤが引っかかって耳、そして目から髪への移動がうまくいかなかった。
マクロを使い、ハードの変化や調整に対応できるようにした。また、低レベルの操作をまとめて関数を定義しておくことで、main()内の把握をしやすくした。また引数によって調整できるようにしたことで、容易に再利用が可能となり、今後の作業における負担を減らせると考えた。関数で小分けにしたことで、修正をしやすくし生産性をあげたことが時間の節約になった。
具体的には、忘れがちなモータの制御や、回転の際のペンの位置のずれの修正を関数内にまとめ、main()で全体の構成に集中できるように工夫した。マクロは引数チェックが怖かったので定数の置き換えのみに使用した。 電池の残量によって変わる距離や用紙のサイズなどに対応するため、機体の制御にある距離L(時間で表す。マクロ)をおき、それを基準とし比例で距離を表したり、機体の回転を角度で表すことで、結果的に引数をも簡潔にできた。 途中ハードの大幅な変更があったが、なんとか切り抜くことが出来た。 ただ、耳からあごにかけての角度調整で、tl()を使うはずなのに、どうしてなのかtr()でないと期待した動作が得られなかった。
モータを制御する関数をどれほど汎用なものにするか、ということに悩んだ。 void motor(MOTOR m; int length);や、turn(LR lr; int angle);といったようなものも考えたが、これだと低レベルの操作と何も変わらない/わかりにくいので今のコーディングでいいと考えた。 NQCにdoubleが備わっていないということで、小数点の計算が出来ず、精度の悪い回転となってしまった。 また、今回main()内をサブルーチンで整理しなかったのは、次の動きが前の動きによる位置に依存するので、逆にわかりにくいと考えたためである。 今回の課題に十分な時間をかけられなかったことが残念であり、今回の最大の反省点である。
ハードウェアがあらかじめ完成しているケースでは、ソフトの改良に努めるだけ?だが、今回はハードも自分でデザインすることが出来、そのことが生むたくさんの選択肢(手段)の、どれを選ぶかで悩んだ。作業自体はパズルのようで非常に楽しく、いつかMindstreamのようなおもちゃを自作してみたいという新たな目標が出来た。
今回始めてということで楽しかったけれど、最後の方は思いどおりにいかなく つらかった。けどパートナーはこのロボットに対しての知識が多く いろんなことを教えてもらい非常に助かった。もう少し上手くやりたかった。 次の課題は早めから取り組み頑張りたいです。