ロボットコンテスト・7班+14班(03・2・7)
ー課題ー
引越しロボットの作成:障害物を避けながら紙コップを台から台へ移動させる。
詳しくは
ー作成過程ー
はじめはロボットを二台に分け、一台が障害物をすべてどかし、もう一台が紙コップを運ぶという方法を考えていた。そうすることで紙コップを運ぶロボットはライントレースをする必要も無く、直線的に移動できるので時間の短縮になると思っていたからだ。しかし、この案は途中で却下(泣)というのも、障害物であるジュースの缶の色が統一されていないためライトセンサーが使いにくいと判断したわが班はタッチセンサーを使うことにした、が、正確に障害物の位置を特定することができず、さらには障害物に当たる前に壁などに当たってしまい誤作動を起こすこともあった。そして、この方法では採点基準の「二台のRCXの協調」などの点数が得られない可能性があることなども考えられた。そのためこの方法を断念した。
そこで、一台で作業をするロボットの作成にとりかかった。
ロボットで工夫した点は、伸びるアームと回転するボディー。伸びるアームは奥にある紙コップをいかに効率よく取るかという観点から考え付いたのだが、作ってみると意外に難しかった。アームの先にはさみを開閉させるためのモーターが付いているためその重さからアームが伸びた状態のときはかなりバランスが悪く修正に苦労した。同様に回転するボディーもそのバランスと強度を保つのに多くの苦労を強いられた。一番大きなタイヤを支えに用いることでひとまず倒れない程度のバランスを保つことはできた。そして、二台のRCXの相互交信も最後までいまいち上手くいかなかった。ロボットのバランス等の都合上、どうしてもRCXを上下の位置関係に付けざるを得なかったため上手く交信ができなかった。コンテスト当日も上手く通信できたりできなかったりとその確率は100%とならなかった。
ープログラムー
プログラム1は主にアームの動作を制御した上側のRCXのプログラムでプログラム2はライントレースなど主に移動に関する動作を制御した下側のRCXのプログラムとなっている。
「プログラム1」
//上側RCXのメイン
//ハサミを出すマクロ
#define reach_hand until (SENSOR_3) OnRev(OUT_A); Off(OUT_A);
//ハサミをしまうマクロ
#define put_hand until (SENSOR_1) OnFwd(OUT_A); Off(OUT_A);
int GetMes;
int countnum; //行きか帰りかを奇数か偶数かで判断
task main(){
countnum = 1;
//タッチセンサー1:ハサミをしまう方向のストッパー
SetSensor(SENSOR_1, SENSOR_TOUCH);
//タッチセンサー3:ハサミを出す方向のストッパー
SetSensor(SENSOR_3, SENSOR_TOUCH);
//初期処理
myResetState();
//3往復分繰り返す
//こちらは1往復で1ループ
for (; countnum<=3; countnum++){
//紙コップをつかむ
myCatchCup();
//下部に、紙コップをつかんだという
//メッセージ(2)を送信。
mySendMessage(2);
//下部から、紙コップを放せる状態になったという
//メッセージ(4)を待つ
until (GetMes==1)
myWaitMessage(4);
//初期化
GetMes = 0;
ClearMessage();
//紙コップを放す
myReleaseCup();
Wait(50);
//下部に、紙コップを放したという
//メッセージ(2)を送信。
mySendMessage(2);
//下部から、紙コップをつかめる状態になったという
//メッセージ(4)を待つ
until (GetMes==1)
myWaitMessage(4);
//初期化
GetMes = 0;
ClearMessage();
}
}
//紙コップをつかむ動作をする
sub myCatchCup(){
//1回目(移動元の中心の紙コップ)は
//近いのでハサミを出さない
if (countnum!=1){
//ハサミを出す
reach_hand;
Wait(50);
}
//ハサミを閉じる
OnRev(OUT_C);
Wait(50);
if (countnum!=1){
//ハサミをしまう
put_hand;
Wait(50);
}
}
//紙コップをはなす動作をする
sub myReleaseCup(){
//2回目と3回目(移動先の両端の紙コップ)は
//近いのでハサミを出さない
if (countnum==1){
//ハサミを出す
reach_hand;
Wait(50);
}
//ハサミを開く
OnFwd(OUT_C);
Wait(50);
if (countnum==1){
//ハサミをしまう
put_hand;
Wait(50);
}
}
//初期状態にする
//ハサミをしまって、広げた状態
sub myResetState(){
//ハサミをしまう
put_hand;
//ハサミを広げる
OnFwd(OUT_C);
Wait(50);
}
//下側にメッセージを送信
//引数:n=送信する整数
void mySendMessage(int n){
ClearTimer(0);
while (Timer(0)<30){
SendMessage(n);
//Wait(25); //断続的に送る
}
}
//下側からのメッセージを待つ(待機)
//引数:n=受信する整数
void myWaitMessage(int n){
ClearMessage();
until (Message()!=0); //上部からの送信を待つ
if (Message()==n){
GetMes = 1;
} else{
GetMes = 0;
}
}
「プログラム2」
//下側RCXのメイン
//容量の事を考えると関数よりサブルーチンを使いたいが、
//サブルーチンでグローバル変数を使うより、関数で引数を
//用いた方がだいぶわかりやすいので、関数を用いた。
#define THRESHOLD 40 //ライントレース用
#define FORWARD 0 //前進後退
#define BACKWARD 1
#define RIGHT 0 //回転
#define LEFT 1
#define U_TURN_TIME90 148 //上部を90°回転するときの時間
#define U_TURN_TIME180 260 //上部を180°回転するときの時間
#define L_TURN_TIME90 169 //下部を90°回転するときの時間
#define L_TURN_TIME180 340 //下部を180°回転するときの時間
#define LR_SHIFT_TIME 150 //左右にシフトするときの時間
#define FB_SHIFT_TIME1 50 //前後にシフトするときの時間1
#define FB_SHIFT_TIME2 160 //前後にシフトするときの時間
int GetMes;
int countnum; //行き来の回数カウント用
task main(){
GetMes = 0;
countnum = 1;
int deg; //上部、下部を回転させる角度
//ライトセンサー1:左側
SetSensor(SENSOR_1, SENSOR_LIGHT);
//ライトセンサー3:右側
SetSensor(SENSOR_3, SENSOR_LIGHT);
//タッチセンサー2:前面の衝突判定用
SetSensor(SENSOR_2, SENSOR_TOUCH);
//3往復分繰り返す
//こちらは行くのに1ループ、帰るのにも1ループ。
for (; countnum<=5; countnum++){
//上部から、紙コップをつかんだ、または放した
//というメッセージ(2)を待つ
until (GetMes==1)
myWaitMessage(2);
//初期化
GetMes = 0;
ClearMessage();
//2往復目以降は、平行移動の処理をする
if (countnum>2){
switch (countnum){
case 3:
//上部を90°回転させる
myRotateUpper(U_TURN_TIME90, RIGHT);
//左右に平行移動する
myShift(LR_SHIFT_TIME, BACKWARD);
//下部を90°回転する
myRotateLower(L_TURN_TIME90, RIGHT);
break;
case 4:
case 5:
//上部を90°回転させる
myRotateUpper(U_TURN_TIME90, LEFT);
//左右に平行移動する
myShift(LR_SHIFT_TIME, BACKWARD);
//下部を90°回転する
myRotateLower(L_TURN_TIME90, LEFT);
break;
}
} else{
//1回目のみ上部を180°回転させる
myRotateUpper(U_TURN_TIME180, RIGHT);
}
//ライントレースを開始
myTrace();
//下部を回転するためにバックする
myShift(FB_SHIFT_TIME1, BACKWARD);
//壁にあたったところで条件分岐
switch (countnum){
case 1:
//下部を180°回転する
myRotateLower(L_TURN_TIME180, RIGHT);
//再び前進する
//180°回転したので、またOnRev()
myShift(FB_SHIFT_TIME2, BACKWARD);
//上部を180°回転させる
myRotateUpper(U_TURN_TIME180, RIGHT);
break;
case 2:
case 5:
//下部を90°回転する
myRotateLower(L_TURN_TIME90, RIGHT);
//左右に平行移動する
myShift(LR_SHIFT_TIME, FORWARD);
//上部を90°回転させる
myRotateUpper(U_TURN_TIME90, LEFT);
curDrc = 1;
break;
case 3:
case 4:
//下部を90°回転する
myRotateLower(L_TURN_TIME90, LEFT);
//左右に平行移動する
myShift(LR_SHIFT_TIME, FORWARD);
//上部を90°回転させる
myRotateUpper(U_TURN_TIME90, RIGHT);
curDrc = 0;
break;
}
//上部に、紙コップを放せる(奇数)、またはつかめる(偶数)
//状態になったというメッセージ(4)を送信
mySendMessage(4);
}
}
//前後、左右に直線移動
//引数:t=時間、drc=前後か左右か
void myShift(int t, int drc){
ClearTimer(2);
while (FastTimer(2)=THRESHOLD)
OnRev(OUT_A);
}
while (SENSOR_3=THRESHOLD)
OnRev(OUT_C);
}
}
Off(OUT_A+OUT_C);
Wait(50);
}
//上側にメッセージを送信
//引数:n=送信する整数
void mySendMessage(int n){
ClearTimer(0);
while (Timer(0)<30){ //上部からの返信を待つ
SendMessage(n);
//Wait(25); //断続的に送る
}
}
//上側からのメッセージを待つ(待機)
//引数:n=受信する整数
void myWaitMessage(int n){
ClearMessage();
until (Message()!=0); //上部からの送信を待つ
if (Message()==n){
GetMes = 1;
} else{
GetMes = 0;
}
}
Photo
わが班のロボットの全体像。とにかく安定性を保つためにキャタピラを使用した。また、ライントレースの性能をよくするために黒い線を挟むように二つ使用した。はさみには滑り止めとしてタイヤを付けた。
後方に出っ張った部分がギアの回転で前方に伸びていってアーム全体が伸びて奥の紙コップをつかめるようにした。当日はあまり上手くいかなかったのが残念。
移動中はバランスを保つためにアームを縮めた状態で移動できるようにプログラムした。
最後に(感想)
コンテストに関してはもう少し上手くいくかなと思っていたがロボットのバランスやRCXの通信、紙コップをつかむ動作などいくつかの問題点が完璧に解決できなかったために三つすべての紙コップを運べなかったのが残念。しかし他の班の結果などを見ると似たような結果で各班ごとにロボットやプログラムに苦労しているんだなと感じた。僕たちの班はプログラムに関しては素人の集まりだったのではじめはその意味を理解するのに苦労をした。ロボコンのプログラムも一緒に協力した7班の中に詳しい人がいたためプログラムに関してはほとんどその人任せとなってしまったのが少し残念だった。しかし、講義を通してプログラムがどういうものかを知ることができ、完璧とはいえないがこのNQCというプログラミングを学べたことはよかった。また、ロボットに関しては、みんなでアイデアを出し合い童心に返った気持ちで楽しく作成できたことはよかった。僕たちの班はみんなが勉強を必要としたために誰かが突出してがんばったという感じはせず、各自がやれることを一生懸命やった気がする。その中で、グループ内でのコミュニケーションもしっかりととることができ、最後まで四人でこの講義を受けれたことが一番よかったと思う。