A3の紙に相棒の似顔絵を描くロボットを作成せよ。
今回の課題を解決するのに最低限必要な機能
・ロボット本体とペンを固定する。
・ロボットが方向転換するときに線を描かないようにするためのペンの上げ下げ機構。
1、ペンをロボットの中心に持って来るのは本体の機構上難しい。
2、ペンがロボットの中心に無いため、図形を描くときにプログラムで補正をかけないといけない。
3、モーターとペンホルダーを直結すると力が強すぎて調節が難しい。
4、サンプルの土台の組み方ではペンホルダーと干渉し、ペンを垂直に保てない。
問題点1の解決策:ペンホルダーを作り本体と連結する。ペンの上げ下げはモーターを使う。
問題点2の解決策:プログラムで補正をかける。
問題点3の解決策:ギアを使いペンホルダーの上げ下げのスピードをゆっくりにする。
問題点4の解決策:干渉する部分を前方にずらし、干渉しないようにした。
今回ロボットを動かすプログラムを書くために、直進や左右の回転などの基本的な動作は全て関数としてまとめた。
サブルーチンではなく、関数にした理由は関数を呼び出す際に動作時間を自由に指定するためである。
void go_straight(int t){ //t/100秒前進 OnFwd(OUT_A); OnFwd(OUT_C); Wait(t); Off(OUT_A+OUT_C); Wait(45); }
void back_straight(int t){ //t/100秒後退 OnRev(OUT_A); OnRev(OUT_C); Wait(t); Off(OUT_A+OUT_C); Wait(45); }
void turn_left(int t){ //t/100秒車体の中央を中心として左回転 OnRev(OUT_A); OnFwd(OUT_C); Wait(t); Off(OUT_A+OUT_C); Wait(45); }
void turn2(int t){ //t/100秒左前輪を中心として左回転 OnFwd(OUT_C); Wait(t); Off(OUT_A+OUT_C); Wait(45); }
void turn_right(int t){ //t/100秒車体の中央を中心として右回転 OnFwd(OUT_A); OnRev(OUT_C); Wait(t); Off(OUT_A+OUT_C); Wait(45); }
void pen_up(){ //ペンを上げる OnFwd(OUT_B); Wait(90); Off(OUT_B); }
void pen_down(){ //ペンを下げる OnRev(OUT_B); Wait(90); Off(OUT_B); }
A4右チームは二人とも眼鏡をかけているため、共通部分としてまず
・顔の輪郭
・口
・眼鏡
の3つのパーツを描かせ、そこから
・それぞれの顔の特徴
を描かせ、2つの似顔絵をロボットに描かせることにした。
↑今回の目標の似顔絵(共通部分)
輪郭の円を描く際に関数turn_leftを用いるよりも関数turn2を用いた方が大きい円が描けるため、turn2を用いた。
void nigaoe_rinkaku(){ turn2(815); pen_up(); }
左図:関数turn_leftを用いたときに描かれる円 右図:関数turn2を用いたときに描かれる円
シンプルに直線にした。
void nigaoe_kuchi(){ pen_down(); go_straight(75); pen_up(); }
上図のような眼鏡を描くための行程は
上のような4つに分けられる。このうち、行程1、3は同じ動作によって実現できるので眼鏡を描く行程を下の3つに分けた。
void nigaoe_megane1(){ //行程1、3 pen_down(); go_straight(38); pen_up(); go_straight(38); pen_down(); go_straight(38); pen_up(); }
void nigaoe_megane2(){ //行程2 pen_down(); go_straight(25); pen_up(); go_straight(38); pen_down(); go_straight(38); pen_up(); go_straight(38); pen_down(); go_straight(25); pen_up(); }
void nigaoe_megane3(int len){ //行程4 pen_down(); go_straight(len); pen_up(); }
今回、二つの似顔絵を差別化するために
・鼻
・髪
を描く関数を用意し、プログラムでどちらかを呼び出すか指定できるようにした。
void nigaoe_tokuchou_hana(int len){ //鼻を描く turn_left(220); go_straight(190); turn_right(160); go_straight(175); pen_down(); go_straight(len); pen_up(); }
void nigaoe_tokuchou_kaminoke(){ //髪を描く turn_left(95); go_straight(58); turn_right(92); pen_down(); go_straight(60); pen_up(); back_straight(60); turn_right(40); pen_down(); go_straight(60); pen_up(); back_straight(60); turn_left(80); pen_down(); go_straight(60); pen_up(); }
void nigaoe_tokuchou(int f){ //fの値が0なら鼻、それ以外なら髪を描く if(f==0){ nigaoe_tokuchou_hana(40); }else{ nigaoe_tokuchou_kaminoke(); } }
以上のプログラムは関数であり、これらの関数を呼び出すためのメインプログラムは以下の通り。
task main(){ int i; nigaoe_rinkaku(); go_straight(30); nigaoe_kuchi(); turn2(204); turn_left(95); go_straight(155); nigaoe_megane1(); back_straight(139); turn_right(95); back_straight(5); turn_left(95); nigaoe_megane2(); back_straight(130); turn_right(95); back_straight(5); turn_left(95); nigaoe_megane1(); back_straight(50); turn_right(95); go_straight(55); nigaoe_megane3(25); for(i=0;i<3;i++){ back_straight(30); turn_right(101); go_straight(38); turn_left(100); nigaoe_megane3(25); } nigaoe_tokuchou(0); //この例では鼻を描いている Off(OUT_A+OUT_C); }
ロボットの回転の中心にペンを持ってくることができず、補正するためのプログラムを作るのが大変だった。
同じプログラムでも動かす度に違う絵が描けることがあり、どう修正していいかわからないときがあった。
関数を使うことで、わかりやすいプログラムにすることができたと思う。
何かコメントがありましたらお願いします。
とても丁寧でわかりやすく、いろいろと工夫があるとても良いレポートです。
ただ、一人につき一つのプログラムが必要なので、もう一つ載せてください。 F.I