[[2011b]]
目次
#contents
*メンバー [#vf447df0]
ブラン・・・繊維学部応用生物学系
二宮・・・同、創造工学・根暗で目を見て話せない系
セレン・・・同、応用生物学系。実はブラインドタッチができない
*課題 [#sbe63566]
課題2:黒い線上を動くロボット
ルール
次のような周回コース(黒い線)を動くロボットを作成せよ。
-通常の交差点が2箇所以上ある
-ロータリー型の交差点が1箇所以上ある (ロータリーでは反時計まわりに進む)
-直角に曲がるコーナーおよびそのコーナーをショートカットするコース(点線)が存在する
-急なヘアピンカーブが1箇所以上ある
-スタート地点に目印がある
-黒い線の幅は15〜20mm程度
センサー、モーターはいくつ使ってもよい。プログラムは次の2つ(または3つ)を作成すること。
1.直角のコーナーを通る~
2.直角のコーナーを通らない(近道する)~
3.(3人チームの場合) 1周目は近道を選択せず、2周目は近道を選択するロボットを作る~
ただし、
-速さと正確さを追求すること
-2周目はスタート地点の直前で自動的に止まること
-交差点を曲がる時には、光センサを有効に使うこと(ある地点からの距離や時間だけに頼らないこと)
*コース [#n1dfabf8]
&ref(2011b/A1/課題2右/コース.jpg,80%,コース);~
~
シンプルに条件を満たすコースにした。鋭角のカーブが特徴的なところ。~
~
*ロボット [#naaf3ac0]
-ラインを正確にとらえなぞるため、なるべく小回りの利くロボットを目指した。~
そのため、モーターの位置を工夫して左右のタイヤをなるべく近づけ、さらにギア比を調節してスピードを落とし調整しやすくした。~
&ref(2011b/A1/課題2右/全体3.jpg,60%,全体3); &ref(2011b/A1/課題2右/裏2.jpg,60%,裏2);
~
~
-また、タイヤは二つのみで後ろは滑らせる部品を使ったため、タイヤに摩擦がかかるようにしなければうまく進まない。~
そこで、重心をタイヤの上に持ってくることでタイヤにかかる垂直抗力を増し、摩擦を強くすることにした。~
-しかし、それでも床の状態によって動きが違ってしまった。~
&ref(2011b/A1/課題2右/重心1.jpg,50%,重心1); &ref(2011b/A1/課題2右/重心2.jpg,50%,重心2);~
左図のほうがタイヤに重心がかかり、うまく進むことがわかる
~
~
-センサー部はシンプルに二つの明るさセンサーでラインを挟み込む形にした。タイヤとセンサーの距離が近いのでラインを逃しにくくなった。~
&ref(2011b/A1/課題2右/センサー.jpg,60%,センサー);
~
~
-全体を通して、壊れにくく、分解しやすい構造を目指した。~
*プログラム [#d2683cb3]
**ブラン [#zfd26998]
task_mainの中をなるべくごちゃごちゃさせないために、サブルーチンや関数を多く使った。~
パーツごとに交差点カウントをcross = 0;でリセットすることで、同じ行動を使い回したり周回をリピートで処理できるように工夫した。~
また、難しい鋭角カーブはそこに差し掛かったときだけ片方のセンサーをOFFにして、線をたどりながら角を探すことで解決した。
#define BORDER 40 //センサーの閾値
#define RUN_TIME 1000
int cross = 0;
sub go() //前進
{OnFwd(OUT_A+OUT_C);}
sub back() //後退
{OnRev(OUT_A+OUT_C);}
sub turn_L() //左旋回
{OnFwd(OUT_C);OnRev(OUT_A);}
sub turn_R() //右旋回
{OnFwd(OUT_A);OnRev(OUT_C);}
sub turn_l() //左に進む
{OnFwd(OUT_C);Off(OUT_A);}
sub turn_r() //右に進む
{OnFwd(OUT_A);Off(OUT_C);}
sub count() //交差点カウント
{cross++;PlaySound(SOUND_CLICK);}
sub end() //停止
{Off(OUT_A+OUT_C);PlaySound(SOUND_DOWN);}
void edge() //鋭角カーブ
{
cross = 0;
while(cross!=1)
{
if(SENSOR_1 < BORDER) {turn_L();}
if(SENSOR_3 < BORDER) {turn_R();}
if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();count();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
ClearTimer(0);
while(FastTimer(0) <= 500)
{
if(SENSOR_3 < BORDER) {turn_r();}
if(SENSOR_3 > BORDER) {turn_L();}
}
PlaySound(SOUND_CLICK);
while(SENSOR_3 > BORDER)
{
turn_L();
}
}
void normal(int t) //基本のライントレース
{
cross = 0;
while(cross!=t)
{
if(SENSOR_1 < BORDER) {turn_L();}
if(SENSOR_3 < BORDER) {turn_R();}
if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(30);count();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
PlaySound(SOUND_UP);
}
void rotary() //ロータリーの動き
{
cross = 0;
while(cross!=1)
{
if(SENSOR_1 < BORDER) {turn_L();}
if(SENSOR_3 < BORDER) {turn_R();}
if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_R();Wait(40);go();Wait(30);count();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
while(cross!=2)
{
if(SENSOR_1 < BORDER) {turn_L();}
if(SENSOR_3 < BORDER) {turn_R();}
if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_L();;Wait(30);go();Wait(30);count();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
while(cross!=3)
{
if(SENSOR_1 < BORDER) {turn_L();}
if(SENSOR_3 < BORDER) {turn_R();}
if(SENSOR_1 < BORDER && SENSOR_3 < BORDER){go();Wait(20);turn_R();;Wait(40);go();Wait(30);count();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
PlaySound(SOUND_UP);
}
void hat() //帽子の部分
{
ClearTimer(0);
while(FastTimer(0) <= RUN_TIME)
{
if(SENSOR_1 < BORDER) {turn_l();}
if(SENSOR_3 < BORDER) {turn_r();}
if(SENSOR_1 > BORDER && SENSOR_3 > BORDER){go();}
}
PlaySound(SOUND_UP);
}
task main()
{
int L;
SetSensor(SENSOR_1, SENSOR_LIGHT);
SetSensor(SENSOR_3, SENSOR_LIGHT);
for (L=1; L<=2; L++) //周回数
{
normal(1);
edge();
normal(2);
rotary();
hat();
rotary();
normal(2);
edge();
normal(1);
}
end();
}
**二宮 [#q2bdfcb7]
何故一番冴えない私が両方の道を通らねばならぬのか(一周目通常、二周目近道)・・・早くからいろんな作例を参考に試行錯誤。何回も試すウチに、センサの条件付けを色々と簡略したり出来る事に気がついた。成るべく細部にプログラムを分けて、試験走行も部分的に行えた。なのでタスクメインもすっきり見やすくなった!それにエディタ?の自動字下げをオンにしてなすがままにインデントしてもらったら、それっぽい画面が仕上がった。その過程で気づいた事の一つに「elseの使い辛さ」がある。多分下手に使うよりはif多用した方が簡単で、字数も少ないと思う。また、こだわりとしては最初のバック走行。鋭角なんだからやってみたいと、最初期から考えていたので満足成。結構長くなってしまったが、前回と比べて自分のプログラムに進歩が見えた・・・?のは良かったかな、と。
#define T 40
#define W OUT_A+OUT_C
#define R OnFwd(OUT_A);OnRev(OUT_C);
#define L OnFwd(OUT_C);OnRev(OUT_A);
#define BK OnRev(W);
#define OFF Off(W);
int X = 0;
int CC = 0;
void go(){OnFwd(W);}
void COUNT(){CC++;PlayTone(210,20);}
task main()
{
SetSensor(SENSOR_1, SENSOR_LIGHT);
SetSensor(SENSOR_3, SENSOR_LIGHT);
Wait(7*T);
ASHI();
RUN(2);
roll();//◆◆◆有頂天
PlayTone(1310,20);
ClearTimer(0);
while(FastTimer(0) <= 400 )
{
if(SENSOR_1 < T)
{OnFwd(OUT_C);Off(OUT_A);Wait(40);}
if(SENSOR_3 < T)
{OnFwd(OUT_A);Off(OUT_C);Wait(40);}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
if(SENSOR_1 < T && SENSOR_3 < T )
{
L;
Wait(30);
go();
Wait(30);
}
}
PlayTone(1310,20);
while(FastTimer(0) >= 401 && FastTimer(0) <= 630 )
{
go();
if(SENSOR_1 < T)
{OnFwd(OUT_C);Off(OUT_A);}
if(SENSOR_3 < T)
{OnFwd(OUT_A);Off(OUT_C);}
if(SENSOR_1 < T && SENSOR_3 < T )
{
R;
Wait(45);
go();
Wait(170);
}
}
PlayTone(1320,10);
roll();//◆◆◆有頂天脱出
RUN(2);
hajikko();
RUN(2);
hajikko();
RUN(2);
roll();
ClearTimer(0);
while(FastTimer(0) <=1000 )
{
if(SENSOR_1 < T)
{OnFwd(OUT_C);Off(OUT_A);}
if(SENSOR_3 < T)
{OnFwd(OUT_A);Off(OUT_C);}
if(SENSOR_1 < T && SENSOR_3 < T)
{
PlayTone(910,10);PlayTone(910,10);
go();Wait(26);R;Wait(51);go();Wait(259);COUNT();
R;Wait(80);
}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
PlayTone(910,10);
roll();
RUN(2);
hajikko();
end();
}
void roll() //ちはやロータリング
{
CC = 0;
while(CC!=1)
{
if(SENSOR_1 < T)
{L;}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{
go();
Wait(20);
R;
Wait(40);
go();
Wait(30);
COUNT();
}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
while(CC!=2)
{
go();
if(SENSOR_1 < T)
{L;Wait(14);}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{go();
Wait(20);
L;
Wait(30);
go();
Wait(30);
COUNT();
}
}
while(CC!=3)
{
if(SENSOR_1 < T)
{L;}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{go();
Wait(20);
R;
Wait(40);
go();
Wait(30);
COUNT();
}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
PlayTone(540,15);
}
void ASHI()//アシ
{
ClearTimer(0);
while ( Timer(0) <= 19 )
{
if((SENSOR_1>T) && (SENSOR_3>T))
{BK;}
if( (SENSOR_1>T) && (SENSOR_3<T) )
{R;}
if( (SENSOR_1<T) && (SENSOR_3>T) )
{L;}
if( (SENSOR_1<T) && (SENSOR_3<T) )
{BK;}
}
while ( (Timer(0) >= 19) && ( X <= 0 ) )
{
if((SENSOR_1>T) && (SENSOR_3>T))
{BK;}
if( (SENSOR_1>T) && (SENSOR_3<T) )
{
BK;
Wait(0);
R;
Wait(39);
go();
Wait(34);
X++;
PlayTone(700,80);
}
if( (SENSOR_1<T) && (SENSOR_3>T) )
{L;}
}
}
void hajikko() //つまさきmove'n on
{
CC = 0;
while(CC!=1)
{
if(SENSOR_1 < T)
{L;}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{
go();
Wait(82);
L;
Wait(254);
go();
Wait(47);
COUNT();
}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
}
void RUN(int t) //トレース、、、オン
{
CC = 0;
while(CC!=t)
{
if(SENSOR_1 < T)
{L;}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{go();Wait(50);COUNT();}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
PlaySound(SOUND_UP);
}
void end() ////Pushed Rice!
{
CC = 0;
while(CC!=1)
{
if(SENSOR_1 < T)
{L;}
if(SENSOR_3 < T)
{R;}
if(SENSOR_1 < T && SENSOR_3 < T)
{COUNT();}
if(SENSOR_1 > T && SENSOR_3 > T)
{go();}
}
OFF;
PlayTone(240,15);
PlaySound(SOUND_DOWN);
PlayTone(840,15);
}
■反省~
「タイマーを多用しない方がいい」というのは電池の減りを目の当たりにして痛感。次回ではできるだけ避けたい。大分挙動が異なるので調整が頻繁に必要になったり。皮肉にもここで「プログラムを細かく分けておく」のが活躍。後になるほど恩恵を得た。もしまたライントレースをするなら、床と机など走らせる場所で結果が違わないものにしたい。ーーーこの辺りは講評でも指摘された点だし、練習課題のバンパーで学んだ事。wait実効中に他のプログラムが入らないため終わってみればズレてる、対アクシデントのプログラムは利用されることすらない、というもの。分かってはいる(つもりだ)が・・・これが難しかった。成程、戦車などが無人にならないのはやはりこういう融通が効かない・・・から?
** セレン [#dfc3f2c9]
ポイントごとにカウントを1つずつ増やしていくプログラムなので、左右対称のコースにもかかわらずヘアピンやロータリーの部分が1回目と2回目で別々のプログラムで汎用性はあまりないかも。しかもプログラムが長くなってしまった。~
スピードを上げるために、右左折は全てお互いの車輪を逆方向に回して曲がる方法を採用。~
工夫としてはポイントごとに「ド、レ、ミ、…、シ、ド、シ、…、レ、ド」と鳴るようにしてどのプログラムが作動しているかわかりやすいようにしたつもり。
#define BLACK 40 //閾値
#define SHORTCUT_TIME 300 //近道手前の移動時間
#define STRAIGHT_TIME 600 //2週目に入る前の軌道修正の時間
#define SE(t) PlayTone(t,20); //ポイントで音を鳴らす
#define c 523 //ド
#define d 587 //レ
#define e 659 //ミ
#define f 698 //ファ
#define g 784 //ソ
#define a 880 //ラ
#define b 988 //シ
#define C 1047 //高いド
int count; //カウント
sub go_ahead() //前進
{OnFwd(OUT_A+OUT_C);}
sub go_back() //後退
{OnRev(OUT_A+OUT_C);}
sub spin_right() //右折
{OnFwd(OUT_A); OnRev(OUT_C);}
sub spin_left() //左折
{OnFwd(OUT_C); OnRev(OUT_A);}
void switchback() //スタート〜鋭角
{
while(count==0){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_back();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left(); Wait(30); go_ahead(); Wait(80); count++; SE(c);}
}
}
void hairpin1() //ヘアピン(1)
{
while(count==1){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(30); count++; SE(d);} //Waitで線を通り過ぎないとカウント回数が増えてしまう
}
while(count==2){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(30); count++; SE(e);}
}
}
void enter_rotary() //ロータリー進入
{
while(count==3){
go_ahead();
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{SE(f); go_ahead(); Wait(50); spin_right(); Wait(50); go_ahead(); Wait(10); count++;}
}
}
void rotary1() //ロータリー(1)
{
while(count==4){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(20); count++; SE(g);}
}
while(count==5){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(50); spin_right(); Wait(45); count++; SE(a);}
}
}
void corner1() //直角前
{
ClearTimer(0);
while(count==6 && FastTimer(0)<=SHORTCUT_TIME){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
}
while(count==6 && FastTimer(0)>SHORTCUT_TIME){ //近道進入
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{go_ahead(); Wait(60); spin_left(); Wait(50); go_ahead(); Wait(50); count++; SE(b);}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
}
}
void shortcut() //近道
{
while(count==7){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead(); Wait(20);}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(50); spin_left(); Wait(50); go_ahead(); Wait(10); count++; SE(C);}
}
}
void corner2() //直角後
{
while(count==8){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(50); spin_right(); Wait(50); go_ahead(); Wait(10); count++; SE(b);}
}
}
void rotary2() //ロータリー(2)
{
while(count==9){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(20); count++; SE(a);}
}
while(count==10){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(50); spin_right(); Wait(60); count++; SE(g);}
}
}
void hairpin2() //ヘアピン(2)
{
while(count==11){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(50); count++; SE(f);}
}
while(count==12){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(30); count++; SE(e);}
}
while(count==13){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(120); spin_right(); Wait(100); count++; SE(d);}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead();}
}
}
void straight() //1周目〜2週目
{
ClearTimer(0);
while(count==14 && FastTimer(0)<=STRAIGHT_TIME){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{spin_right();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead();}
}
while(count==14 && FastTimer(0)>STRAIGHT_TIME){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead(); Wait(100); spin_right(); Wait(120); go_ahead(); Wait(70); count=count-13; SE(c);}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{go_ahead();}
}
}
void goal() //ゴール
{
while(count==14){
if(SENSOR_1 > BLACK && SENSOR_3 > BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 > BLACK)
{spin_left();}
if(SENSOR_1 > BLACK && SENSOR_3 <= BLACK)
{go_ahead();}
if(SENSOR_1 <= BLACK && SENSOR_3 <= BLACK)
{Off(OUT_A+OUT_C); SE(c);}
}
}
task main()
{
SetSensor(SENSOR_1,SENSOR_LIGHT);
SetSensor(SENSOR_3,SENSOR_LIGHT);
count = 0;
switchback(); //スタート
hairpin1();
enter_rotary();
rotary1();
corner1();
shortcut();
corner2();
rotary2();
hairpin2();
straight(); //1週目〜2週目
hairpin1();
enter_rotary();
rotary1();
corner1();
shortcut();
corner2();
rotary2();
hairpin2();
goal(); //ゴール
}
*その他(気づいたことなど) [#b3f3ec36]
最後に、コメントがありましたら何でもどうぞ!
- 3人ともマクロ・インライン関数とサブルーチンを使い分ければプログラムのサイズがもっと小さくなるはずです。 -- [[松本]] &new{2012-01-05 (木) 13:52:48};
#comment