目次
課題は、ロボットに缶を探させ、運び、積み上げることである。
詳しくは課題3を参照
私達のグループは、ロボットを一つにまとめることにした。 手前に見えているのがスレイブ側で、その反対側にマスター側のものがある。
缶をつかむ部分は、輪ゴムを使うことによって持ち上げるときに滑り落ちないようにした。 モーターの部分は、角度を指定して回転させると同じ角度だけ回転するようにした。
アームの腕の部分は、歯車を利用してモーターの重さでアームを上げやすくした。 しかし、前方が重すぎて下がってしまう時もあった。
センサーは、超音波センサーと光センサーを同じ場所に取り付けた。 最初は並列にしていたが、超音波センサーが上手く反応しないことがあったのでなんとかして真っ直ぐ付けた。
このロボットの問題点としては、アームの前方が重すぎることとアームの安定感が乏しいことだ。
本体を2つ使っているためマスター側とスレイブ側にわけて書く。 マスター側は、センサー及びタイヤを動かし移動するもの。 スレイブ側はアームの上下及び開閉のためのものである。
/* A -> アームの開閉のモーター OnFwdで開く B -> アームの上下のモーター OnFwdで下ろす */ #define CONN 0 // マスターの接続番号 #define SPEED 40 #define OROSE 11 // アームを降ろさせる #define TOJIRO 12 // 缶を掴ませる #define AGERO 13 // アームを上げさせる #define HIRAKE 14 // 缶を離させる #define TUM 15 // 缶の上まで下ろす
下から5つのものは通信するときのメッセージ。
/* B -> 右のモーター OnFwdで前進 C -> 左のモーター OnFwdで前進 S1 -> 光センサー S2 -> 超音波センサー */ #define CONN 1 // スレーブの接続番号 #define SPEED 50 #define OROSE 11 // アームを降ろさせる #define TOJIRO 12 // 缶を掴ませる #define AGERO 13 // アームを上げさせる #define HIRAKE 14 // 缶を離させる #define TUM 15 // 缶の上まで下ろす #define SIRO0 47 // 白のしきい値 #define SIRO1 54 #define KURO0 42 // 黒のしきい値 #define KURO1 37
白と黒のしきい値はライントレースのためのもの。 その上の5つは通信のためのもの。
task main() { until (BluetoothStatus(CONN) == NO_ERR); while(true){ int msg; ReceiveRemoteNumber(MAILBOX1,true,msg); if (msg == OROSE){ // アームを下ろす Wait(100); RotateMotor(OUT_B,SPEED,360); } if (msg == TOJIRO){ // 缶をつかむ Wait(100); RotateMotor(OUT_A,-SPEED,50); } if (msg == AGERO){ // アームを上げる Wait(100); RotateMotor(OUT_B,-60,600); } if (msg == HIRAKE){ // 缶をはなす Wait(100); RotateMotor(OUT_A,SPEED,50); } if (msg == TUM){ // 二段目まで下ろす Wait(100); RotateMotor(OUT_B,SPEED,120); // 下ろす Wait(100); RotateMotor(OUT_A,SPEED,50); // 開く Wait(100); RotateMotor(OUT_B,SPEED,360); // 下ろす } } }
スレイブ側のプログラムはとても単純で、マスターからメッセージを受け取り、その値によってアームを動かすようにした。
sub line_l() // ライントレース { SetSensorLight(S1); if (SENSOR_1 > SIRO1){ Off(OUT_B); OnFwd(OUT_C,SPEED); } else if (SENSOR_1 > SIRO0){ OnFwd(OUT_B,20); OnFwd(OUT_C,SPEED); } else if (SENSOR_1 > KURO0){ OnFwd(OUT_BC,SPEED); } else if (SENSOR_1 > KURO1){ OnFwd(OUT_B,SPEED); OnFwd(OUT_C,20); } else { OnFwd(OUT_B,SPEED); Off(OUT_C); } }
ラインの左側をトレースするサブルーチン。
sub line_r() // ライントレース { SetSensorLight(S1); if (SENSOR_1 > SIRO1){ Off(OUT_C); OnFwd(OUT_B,SPEED); } else if (SENSOR_1 > SIRO0){ OnFwd(OUT_C,20); OnFwd(OUT_B,SPEED); } else if (SENSOR_1 > KURO0){ OnFwd(OUT_BC,SPEED); } else if (SENSOR_1 > KURO1){ OnFwd(OUT_C,SPEED); OnFwd(OUT_B,20); } else { OnFwd(OUT_C,SPEED); Off(OUT_B); } }
ラインの右側をトレースするサブルーチン。
sub orose(int t) // アームを下ろす { int msg; SendRemoteNumber(CONN,MAILBOX1,OROSE); Wait(t); }
アームを下ろす指示を送るサブルーチン。待ち時間をその場で入れられるようにした。
sub hirake(int t) // アームを開く { int msg; SendRemoteNumber(CONN,MAILBOX1,HIRAKE); Wait(t); }
アームを開く指示を送るサブルーチン。
sub tojiro(int t) // 缶をつかむ { int msg; SendRemoteNumber(CONN,MAILBOX1,TOJIRO); Wait(t); }
アームを閉じる指示を送るサブルーチン。
sub agero(int t) // アームを上げる { int msg; SendRemoteNumber(CONN,MAILBOX1,AGERO); Wait(t); }
アームを上げる指示を送るサブルーチン。
sub tum(int t) // 二段目まで下ろす { int msg; SendRemoteNumber(CONN,MAILBOX1,TUM); Wait(t); }
アームを二段目の位置まで下ろし、缶を離し、一番下まで下ろすことで缶を積む指示を送るサブルーチン。
sub iti() // Eの缶と一番上の缶 { SetSensorLight(S1); SetSensorLowspeed(S2); until (BluetoothStatus(CONN) == NO_ERR); hirake(1000); while(SensorUS(S2) > 10){ // 10cmになるまで両タイヤをシンクロさせて進む OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tojiro(1000); // 缶をつかむ long t0 = CurrentTick(); while(CurrentTick()-t0 < 7000){ // 7秒間ライントレース line_l(); } OnFwd(OUT_B,-40); // 線の右側に回転 OnFwd(OUT_C,40); Wait(700); t0 = CurrentTick(); while(CurrentTick()-t0 < 2500){ // 2.5秒間ライントレース line_r(); } t0 = CurrentTick(); while(CurrentTick()-t0 < 1000){ // 1秒間直進 OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); Wait(500); RotateMotor(OUT_BC,-SPEED,65); // 少し下がる Wait(100); agero(3000); // アームを上げる while(SensorUS(S2) > 15){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tum(3000); // 缶をつむ Wait(500); while(SensorUS(S2) > 10){ // 10cmまで直進 OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); // 以降はゴールに缶を運ぶ動き tojiro(1000); // 缶をつかむ OnFwd(OUT_BC,60); Wait(500); Off(OUT_BC); RotateMotor(OUT_C,SPEED,250); Wait(1000); Off(OUT_BC); OnFwd(OUT_BC,40); Wait(1000); Off(OUT_BC); hirake(1000); }
itiは、A地点からはじめてEの缶と一番上の缶を積み、ゴールまで運ぶサブルーチン。 しかし、成功する確率がとても低かった。
sub ni() // FとTの缶 { SetSensorLight(S1); SetSensorLowspeed(S2); OnRev(OUT_BC,SPEED); Wait(1000); OnFwd(OUT_B,-SPEED); OnFwd(OUT_C,SPEED); Wait(500); until (SensorUS(S2) < 40) Off(OUT_BC); orose(1000); hirake(1000); OnFwdSync(OUT_BC,SPEED,0); until (SensorUS(S2) < 20); tojiro(900); agero(1300); while(SENSOR_1 > SIRO0){ OnFwd(OUT_BC,SPEED); } while(SensorUS(S2) > 20){ line_l(); } Off(OUT_BC); tum(1000); tojiro(1000); OnFwd(OUT_B,SPEED); Off(OUT_C); Wait(100); hirake(1000); agero(1300); }
これは、FとTの缶を運ぶサブルーチンだが、試すことまではできなかった。
sub san() // GとHの缶 { SetSensorLight(S1); SetSensorLowspeed(S2); } sub yon() // 下のカーブと中身の入っている缶 { SetSensorLight(S1); SetSensorLowspeed(S2); }
この二つも案としては次のように作ったが、試すことはできなかった。
sub san() { SetSensorLight(S1); SetSensorLowspeed(S2); OnFwd(OUT_B,-SPEED); OnFwd(OUT_C,SPEED); while(SENSOR_1 < KURO1){} while(SENSOR_1 > SIRO1){} while(SENSOR_1 < KURO1){} while(SensorUS(S2) > 15){ line_l(); } Off(OUT_BC); while(SensorUS(S2) > 10){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tojiro(1000); OnFwd(OUT_B,-SPEED); OnFwd(OUT_C,SPEED); while(SENSOR_1 < KURO1){} while(SENSOR_1 > SIRO1){} while(SENSOR_1 < KURO1){} t0 = CurrentTick(); while(CurrentTick-t0 < 2000)[ line_l(); } Off(OUT_BC); agero(1000); while(SensorUS(S2) > 15){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tum(3000); while(SensorUS(S2) >10){ OnFwdSync(OUT_BC,SPEED,0); } RotateMotor(OUT_B,SPEED,90); RotateMotor(OUT_C,-SPEED,90); Wait(1000); OnFwd(OUT_BC,SPEED); Wait(1000); hirake(1000); } sub yon() { SetSensorLight(S1); SetSensorLowspeed(S2); OnRev(OUT_BC,SPEED); while(SENSOR_1 > KURO1){} OnFwd(OUT_B,-SPEED); OnFwd(OUT_C,SPEED); Wait(200); while(SensorUS(S2) > 20){} Off(OUT_BC); while(SensorUS(S2) >10){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tojiro(1000); OnFwd(OUT_BC,SPEED); Wait(2000); RotateMotor(OUT_B,SPEED,90); RotateMotor(OUT_C,-SPEED,90); Wait(1000); OnFwdSync(OUT_BC,SPEED,0); Wait(6000); Off(OUT_BC); agero(1000); while(SensorUS(S2) > 15){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tum(3000); while(SensorUS(S2) > 10){ OnFwdSync(OUT_BC,SPEED,0); } Off(OUT_BC); tojiro(1000); RotateMotor(OUT_B,SPEED,90); RotateMotor(OUT_C,-SPEED,90); Wait(1000); OnFwdSync(OUT_BC,SPEED,0); Wait(2000); Off(OUT_BC); hirake(1000); }
一通り作っただけなので上手くはいかないと思う。
task main() { iti(); /* ni(); san(); yon(); */ }
これは、単純にした。最初しか試せてなかったのでiti以外は動かないようにしてある。
本番では、一回目は上手く積めず、二回目は前の重みで倒れてしまい缶をひとつも積めなかった。 他の班では、積まずに集めるだけだが点数を取れていた班もあった。 なので、自分の問題解決の方法が間違っていたと思う。 チャレンジは大事だが、まず堅実にできるようにすべきだったと思う。 基礎ができなければ発展も上手くいかず、不安定になってしまう。 これはまさに自分たちのロボットのことだと思った。
このゼミは問題解決の力を養うもので、とても自分のためになったと思う。 それだけでなく、プログラムを作っていくにあたって、自分の予期した通りにいかないことが多々あった。 それが、グループの人に聞いてみるとあっさりわかったり、逆に聞かれるときに「なんで、こんな単純なミスをしているんだろう」と思うこともあった。 自分では気づかないことでも、他の人が気づくことがあって、一人で抱え込んではいけないということを実感した。 いずれ社会に出て行く自分たちにとても大切なことだったと思う。