目次
以下ルール
以下努力義務
紙上の描きたい場所を走行してペンを上下させるだけで描けそうな「紙の上を走行するロボ」を作成することにした。
ver1.0から反省しバージョンアップ。後輪をキャスターからヒントを得て作り直しました。
輪郭以外の顔のパーツを直線だけで構成することで
輪郭を書く→(紙の外に出て位置を調整→ペンを上下させつつまっすぐに紙上を通り抜ける)→以下()内繰り返し
という手順によって紙をずらすことなく似顔絵が描ける。
予定図は↓
顔の形にするのに必死で似てるかどうかとか問題にできなかった。 鼻の形も妥協している。
//AとCのモーターをOffで止める void OFF(){ Off(OUT_A+OUT_C); } //整数値を引数に取ってその秒数分直進させる関数 void go_straight(int t){ OnFwd(OUT_A+OUT_C); Wait(t); } /*整数値を引数に取ってその秒数分 左のタイヤを固定して右のタイヤを正回転させ左折させる関数*/ void turn_left(int t){ OnFwd(OUT_C);Off(OUT_A); Wait(t); } /*整数値を引数に取ってその秒数分 右のタイヤを固定して左のタイヤを正解点させ右折させる関数*/ void turn_right(int t){ OnFwd(OUT_A);Off(OUT_C); Wait(t); } //整数値を引数にとってその秒数分右回転で超信地旋回させる関数 void right_PivotTurn(int t){ OnFwd(OUT_A);OnRev(OUT_C); Wait(t); OFF(); } //整数値を引数にとってその秒数分左回転で超信地旋回させる関数 void left_PivotTurn(int t){ OnFwd(OUT_C);OnRev(OUT_A); Wait(t); OFF(); } //ペンを上げる関数 void pen_up(){ OnRev(OUT_B); Wait(015); Off(OUT_B); } //ペンを下げる関数 void pen_down(){ OnFwd(OUT_B); Wait(015); Off(OUT_B); } //メインルーチン task main(){ int i; //輪郭を描く pen_down(); for(i=0;i<2;i++){ go_straight(050); turn_right(210); } pen_up(); //位置を調整 go_straight(010); turn_right(090); go_straight(200); //目を描く right_PivotTurn(105); go_straight(140); pen_down(); go_straight(010); pen_up(); go_straight(005); pen_down(); go_straight(010); pen_up(); go_straight(150); OFF(); //位置を調整 left_PivotTurn(055); go_straight(065); left_PivotTurn(055); //口を描く go_straight(140); pen_down(); go_straight(030); pen_up(); go_straight(180); //位置を調整 right_PivotTurn(050); go_straight(150); right_PivotTurn(050); go_straight(190); right_PivotTurn(050); //鼻を書く go_straight(165); pen_down(); go_straight(005); pen_up(); go_straight(200); OFF(); }
とりあえず
描くときの方針としては、
ことにしました。なんか少し複雑な気がしましたがこの時点では無視しました。
顔の輪郭から、髪の毛までは一筆書きです。しかしながら、お絵かきロボットは旋回軸と筆が紙に描く部分がが約3cmずれているので下記のようにただタイヤを反転させるだけではうまくいきません。
そこで以下のようにお絵かきロボットを動かすことにしました。
まず、折れ曲がり地点で筆を上げた後、旋回軸が折れ曲がり地点と重なるように前進させます。
旋回させます。
折り返し地点に筆が来るように後進させます。そのあと筆を下して前進。
こうすることで(理論上は)綺麗な折れ線が書け(るはずであり)ます。
実はこの時点で、360度が何秒旋回すればいいのか、直進1秒が何センチ進むかを計測しておけば簡単に完成だと思っていました。
そして実行した結果は以下のとおり。
なんということでしょう。想像以上のひどさです。(実はこの絵、顔の輪郭は修正されている時のものなので、はじめはもっとひどいものでした)
そんなこんなで修正したのがこれになります。
目は始め三角形の予定でしたが、心が折れたためにボツにしました(線が想像以上に太いためうまくかけてもごちゃごちゃになるとの判断もありました)。
あと、ロボット自体が紙からはみ出すと、大きく紙がずれるので、絵自体は小さめになっています。
書きながら直進、右旋回、左旋回の3つを関数にして書きました。
書くときは直進しかしないので関数に。
旋回は方針に書きましたように前進→旋回→後進を一セットとしていますので関数を使った方がよいと判断しました。
ですがこのため調整の時、後進した直後に前進をするなど無駄な動きをするようになってしまいました(修正するのが面倒くさいとも言う。「実際旋回して直進書き」と言う動きをなるべく1行で済ましていたので、ごちゃごちゃさせたくありませんでした)。
ちなみに角度、直進時間の定義ですが調整の結果使わなくなった物と一つしか使わない物は抜きましたので、刃こぼれを起こしています(ちなみに最初は定義を23個も使っていました)。
#define mae OnFwd(OUT_A+OUT_C);Wait(15);Off(OUT_A+OUT_C); //旋回時の微調整 #define usiro OnRev(OUT_A+OUT_C);Wait(13);Off(OUT_A+OUT_C); //旋回時の微調整 //15度=8.75 #define p 28 //45度 #define r 43 //75度 #define s 53 //90度 #define t 78 //120度 #define u 95 //150度 #define a 60 //直進時間 #define b 42 // #define c 23 // #define d 40 // #define e 20 // #define f 28 // #define h 12 // void migi(int x) //筆を動かさないで右旋回 { mae;OnFwd(OUT_A);OnRev(OUT_C);Wait(x);Off(OUT_A+OUT_C);usiro; } void hidari(int x) //筆を動かさないで左旋回 { mae;OnFwd(OUT_C);OnRev(OUT_A);Wait(x);Off(OUT_A+OUT_C);usiro; } void kaku(int y) //書きながら前進 { OnFwd(OUT_B);Wait(8);Off(OUT_B); //筆を下げる OnFwd(OUT_A+OUT_C);Wait(y);Off(OUT_A+OUT_C); OnRev(OUT_B);Wait(8);Off(OUT_B); //筆を上げる } task main() //メインタスク44 { //顔 kaku(a); hidari(p);kaku(b); hidari(s);kaku(b); hidari(p);kaku(a); //髪 usiro;migi(u);usiro;kaku(c); usiro;migi(u);usiro;kaku(d); mae;hidari(t);mae;kaku(e); usiro;migi(82);usiro;kaku(f); hidari(r);kaku(d); usiro;migi(u);usiro;kaku(c); //目に移動 migi(t); OnFwd(OUT_A+OUT_C);Wait(30);Off(OUT_A+OUT_C); //左目の上を描く hidari(r);kaku(h); OnFwd(OUT_A+OUT_C);Wait(h);Off(OUT_A+OUT_C); //次は右目。下側も描く。 kaku(h); //口まで移動 migi(s); OnFwd(OUT_A+OUT_C);Wait(e);Off(OUT_A+OUT_C); migi(s); OnFwd(OUT_A+OUT_C);Wait(h);Off(OUT_A+OUT_C); //まっすぐな口 kaku(h); //鼻まで移動 migi(t); OnFwd(OUT_A+OUT_C);Wait(f);Off(OUT_A+OUT_C); //真っ直ぐな鼻 usiro;hidari(17);kaku(9); }