ロボットにペンを取り付けA3用紙にハート型を描くロボットを作成しなさい。
//ハートを描くプログラム //変数を定義する #define str_time 160 //直進の時間を定義 #define rev_time 225 //180°回転の時間を定義 #define dir_time 75 //方向転換の時間を定義 //スタートはハートの下の尖った部分から。左回転で描く。 task main() { OnFwd(OUT_A+OUT_C); Wait(str_time); //前進 OnRev(OUT_A); Off(OUT_C); Wait(dir_time); //左舷-後進(方向転換 OnRev(OUT_A); OnFwd(OUT_C); Wait(rev_time); //左回転180° OnFwd(OUT_A); Off(OUT_C); Wait(470); //左舷-前進(方向転換180° OnRev(OUT_A); OnFwd(OUT_C); Wait(rev_time); //左回転180° OnRev(OUT_A); Off(OUT_C); Wait(dir_time); //左舷-後進(方向転換 OnFwd(OUT_A+OUT_C); Wait(str_time); //前進 Off(OUT_A+OUT_C); //停止 }
なんといってもペンの固定。これに尽きる。ペンがうまく固定できず、方向転換のときに変な図形を描いてしまったり、ズレてしまったりして非常に困った。如何に回転の中心に正確にペンを固定するかがこの課題のポイントであった。最初は、「回転の中心にペンを固定しなければいけない」ということに
気づかずに、
ただひたすら、ロボにハート型を走行させ、
「おい、全然ハートにならんぞ! マジで先生無理言い過ぎやし!」と悩み、
あげくのはてに授業をさぼってまで、
えんえんそのことをやって結局できずに、だいぶあとになってから回転の中心に固定ということに気づいて、
「あの時俺は何をしていたんだろう?」
と疑問に思うのでした。
というわけでそれにかなりの労力を費やしたので、ハートの形に拘る余裕があまりなかったのが残念なところ。他の班のハートを見て、あぁもう少し回転時間を長くして云々等、色々思うところがあった。
特になし。むしろ前述のようにペン固定に時間を費やしたので工夫できなかったというのが本音。あえて言うならプログラム。まとめて値を指定してあるので、後からハートの形を調整することが容易である。(もう当時のマシンは壊してしまったので、実際はできない)
机の上で動き回るロボットを作成しなさい。 ただし方向変換は机の端に来たときに行うこと。
できるだけ速いロボットを作成すること
//ライントレースプログラム int curr_light; int err_val; int right_val; int left_val; int trr1; #define RUN_time 5 #define trr_light 5 void right_sear() //右側にラインを探す関数 { while(SENSOR_1 > curr_light + trr_light && Timer(0) <= right_val * RUN_time) { OnFwd(OUT_A); OnRev(OUT_C); } } void left_sear() //左側にラインを探す関数 { while(SENSOR_1 > curr_light + trr_light && Timer(0) <= left_val * RUN_time) { OnRev(OUT_A); OnFwd(OUT_C); } } task main() { SetSensor(SENSOR_1, SENSOR_LIGHT); //光センサーを定義 curr_light = SENSOR_1; //黒線の光度を変数に代入 err_val = 0; right_val = 1; left_val = 3; //各変数に初期値代入 /////エラーが無いとき、以下のプログラムを繰り返す///// while(err_val == 0) { while(SENSOR_1 <= curr_light + trr_light ) //黒線にいる間は前進 { OnFwd(OUT_C+OUT_A); } ClearTimer(0); //タイマーをリセット if(left_val == 3) { right_sear(); if(Timer(0) >= RUN_time) //右側を探してラインが無かった場合次から左を最初に探す { trr1 = 1; } left_sear(); if(trr1 == 1) { right_val = 3; left_val =1; } } else { left_sear(); if(Timer(0) >= RUN_time) //左側を探してラインが無かった場合次から右を最初に探す { trr1 = 0; } right_sear(); if(trr1 == 0) { right_val = 1; left_val = 3; } } if(SENSOR_1 > curr_light + trr_light && Timer(0) > 3 * RUN_time) { PlaySound(SOUND_LOW_BEEP); //左右に見つからないときはエラー音を鳴らして停止 Off(OUT_A+OUT_C); err_val = 1; } } }
ここではなんといってもプログラムだろう。Timerとwhileの使い方に苦労した。左回りはできても、右回りができなかったり、少し書き換えただけで、まったく使い物にならなくなったりと、苦労の連続であった。しかしその苦労もあってかかなりプログラムには慣れを覚えることができた。そして高速性を重視するため、カーブが左か右かを認識するプログラムを組もうと画策したが、それで一気に難易度があがって四苦八苦した。しかし、他の班のプログラムを見るとすごいシンプルなのに驚いた。まだまだ洗練できるであろうと思われる。
もちろんそれは、高速性。直線では直進。カーブでは右カーブか左カーブかを認識し、高速で曲がれるようにプログラムした。もちろん左右両方の直角を曲がることも可能である。ただプログラムがだらだら長くなってしまい、他の人が理解できるのかどうかは激しく疑問であるが…。
まず最初に一回転してもっとも明るい方向(懐中電灯の方向)を探し、次に懐中電灯の光を追いかけて進むようなロボットを作成しなさい。
//もっとも明るい方向を向くプログラムII //変数の定義 int max_light ; int curr_light ; int count_; int count_2; //ロボが360度回転に要する時間(床によって違うので… #define rev_time 325 //光量を測定するときに、何回のうちの最大値をとるか #define rep_num 3 //光量を測定する関数を何回実行するか #define exa_num 40 //光を追いかける際、光の最大値よりどれだけ低いときに探索動作を行うか #define sear_ 5 void exa_lig() //光量を測定する関数(rep_num回測ったうちの最大値をとる) { Off(OUT_A+OUT_C); repeat(rep_num){ curr_light = SENSOR_1 ; if(curr_light > max_light) { max_light = curr_light; //もし現在の光量が以前の最大値よりも大きかったら最大値を更新する PlaySound(SOUND_DOUBLE_BEEP); //最大光量が更新されたら音を鳴らす } Wait(5); } } task main() { SetSensor(SENSOR_1, SENSOR_LIGHT); //光センサーを定義 count_ = 0; count_2= 0; curr_light = 0; max_light = 0; while(count_ < exa_num) //少しずつ車体を回して明るさの最大値をとる { OnRev(OUT_A); OnFwd(OUT_C); Wait((rev_time+(rev_time)/3 )/(exa_num )); Off(OUT_A+OUT_C); Wait(20); count_=count_ + 1; exa_lig(); } PlaySound(SOUND_DOWN); Wait(50); //明るさの最大値がとれたら音を鳴らす while(max_light - 3 > SENSOR_1) //明るさが最大に近いと思われる場所を探す { OnRev(OUT_A); OnFwd(OUT_C);Wait(rev_time/35); Off(OUT_A+OUT_C);Wait(50); } PlaySound(SOUND_UP) ; //最大らしき場所が見つかったら音を鳴らして、停止 Off(OUT_A+OUT_C); Wait(100); //↓↓追いかける動作はここから↓↓ while(true){ while(max_light - sear_ < SENSOR_1) //センサーがある程度の光量を捉えているときは前進 { OnFwd(OUT_A+OUT_C); Wait(20); Off(OUT_A+OUT_C); Wait(20); } while(max_light - sear_ >= SENSOR_1 && count_2 <= 5)//光量が減ったら左旋回を5回繰り返して光源を探す { OnRev(OUT_A); OnFwd(OUT_C);Wait(rev_time/35); Off(OUT_A+OUT_C);Wait(20); count_2 = count_2 + 1; } count_2 = 0; while(max_light - sear_ >= SENSOR_1) //左に光源が無いときは右旋回して探す { OnRev(OUT_C); OnFwd(OUT_A);Wait(rev_time/35); Off(OUT_A+OUT_C);Wait(20); } } }
ライントレースと似たようなものだろうと、楽観的にプログラミングに取り組んだが、それが裏目にでた。一番明るいところをを探知することまでは可能だが、"一周回ったことを認識すること""一番明るかった場所を向かせること"の2つに悩んだ。しかも床によって、摩擦力が変わるから、同じ秒数回転させても回る度合いが変わるじゃないか! と若干投げやりになっていたが、それはとりあえず変更しやすいようにして我慢することにしたが、"どうやって明るかった方向を向かせるんだ"ということに悩んだが、1回転を何個かに分けて探すことによって解決した。これを考えているときにタイマーを使えばいいのだと気づいたが、ここまできたらもうタイマーには頼らず作ろうという、無駄な縛りをつけてしまったので余計に苦労してしまった。 あとは"明るい方向"というフレーズにとらわれて、最初は、あんまり明暗の差が無い場合でも明るい方向を向かせなきゃいけない!と意気込んでしまった為に、それがまた無駄な時間を生んでしまった。 そして懐中電灯が家になくて、携帯のフラッシュ機能を使わなければいけなかったことも苦労の1つでしょうか。
それはタイマーを使わずにこの課題を実現したことでしょうか。別に使わなかったからといってそれが名誉なことかといえば全くそんなことはないが、他の班は多分(?)使ってると思うので、勝手にそのへんは自己満足。
インストラクション(説明書)の最後にある「Top Secret」を参考に、音楽を演奏しながら前進し障害物にぶつかったら(あるいは明るい光にあたったら)後退しながら方向を変えるロボットを作成しなさい。ただし移動のためのモータはひとつだけ使うものとし、また前進しているときと後進している時で違う音楽を演奏すること。
//演奏ロボット //ドレミの定義 #define Do 523 #define Re 587 #define Mi 659 #define Fa 698 #define Sol 784 #define La 880 #define Si 988 //音符の定義 #define x1 60 #define x2 20 #define x3 40 //休符の定義 #define y1 60 //方向転換の時間 #define turn_time 50 void Fwd_music() //前進しているときの音楽 { PlayTone(Do,x1); Wait(y1); PlayTone(Re,x2); Wait(y1); PlayTone(Mi,x1); Wait(y1); PlayTone(Do,x2); Wait(y1); PlayTone(Mi,x3); Wait(y1); PlayTone(Do,x3); Wait(y1); PlayTone(Mi,x3); Wait(y1); Wait(3*y1); } void Rev_music() //方向転換しているときの音楽 { PlayTone(Re,x1); Wait(y1); PlayTone(Mi,x2); Wait(y1); PlayTone(Fa,x1); Wait(y1); PlayTone(Re,x2); Wait(y1); PlayTone(Fa,x3); Wait(y1); PlayTone(Re,x3); Wait(y1); PlayTone(Fa,x3); Wait(y1); Wait(3*y1); } /////////ここからメインプログラム//////////// task main() { SetSensor(SENSOR_1, SENSOR_TOUCH); //タッチセンサーの定義 while(true) //以下のプログラムを繰り返す { OnFwd(OUT_C); //センサーが触れるまで音楽を鳴らしつつ前進 while(SENSOR_1 == 0) {Fwd_music();} until(SENSOR_1 == 1); //触れたら方向転換 OnRev(OUT_C); ClearTimer(0); //タイマーをリセット while(Timer(0) <= turn_time) //ターンしている間はターン用音楽を鳴らす {Rev_music();} Wait(turn_time); //ターンする時間の間、プログラムの進行を待つ } } /////////メインプログラムここまで////////////
それはやはり、何の音楽を鳴らそうか迷ったことでしょうか。結局、「鳴らす音楽は重要じゃないからなんでもいーや」ということで、"ドレミの歌の最初の部分だけ"というなんとも質素さ爆発なことになってしまいました。
特になし。あえていうならその質素さ。