2013b/Member/michaegon/Mission2
をテンプレートにして作成
[
トップ
] [
新規
|
一覧
|
検索
|
最終更新
|
ヘルプ
|
ログイン
]
開始行:
目次
#contents
*課題2内容 [#vb71dca6]
>2台のロボットで空き缶を収集し、ゴールに空き缶になるべく...
>
>基本ルール
>競技時間は審判が続行不能と判断するまで、あるいはリタイア...
>図の左下の隅からスタートする。ロボットが紙からはみ出ない...
>空き缶を集めて図の「ゴール」と書かれた円弧と直線で囲まれ...
>なるべく高く空き缶を積み上げる
>運び終わった後、あるいは積み上げた後はロボットはゴールの...
>開始の合図から5秒以内にスタートボタンを押す作業を完了す...
>競技が終了するまで、ロボットに触ったり人間が遠隔で操作し...
>途中でうまく動かなくなった場合、1回限り再スタートするこ...
以上[[2013b/Mission2]]より引用
&aname(map);
コース図
#ref(robocon2013b.png);
*メンバー [#zab397a9]
[[dyuma>2013b/Member/dyuma/Mission2]]~
ロボット製作(+ロボット管理)・プログラミングとどちらもこ...
[[pepo>2013b/Member/pepo/Mission2]]~
ロボットを組ませたら彼の右に出るものはいない。(ただし情...
michaegon~
このページの著者~
プログラムの方をやってます。
*ロボット概要 [#t8caacae]
今回使用したロボットです。胴体がかなり長いです。
#ref(robo2.jpg);
胴体中央のレールに缶が4本まで入るようになっています。
#ref(robo2-1.jpg);
缶をこの腕で殴ってレールに入れる仕組みです。
#ref(robo2-2.jpg);
#ref(robo2-3.jpg);
#ref(robo2-4.jpg);
缶を感知するのにはこの超音波センサーを使います。
#ref(robo2-7.jpg);
レールの後ろから缶が漏れないようにストッパー君がついてい...
#ref(robo2-8.jpg);
缶をレールに詰め込んだら、缶を抑えるための腕で缶を抑えな...
#ref(robo2-5.jpg);
#ref(robo2-6.jpg);
*プログラム概要 [#u38c8111]
** ライントレース部分の仕様 [#bea8657d]
今回もPID制御を利用したライントレースプログラムを組んでみ...
前回の反省を生かしてより安定して成功できるものに改良しま...
PID制御については[[前回>2013b/Member/michaegon/Mission1]]...
***交差点・急カーブ判定 [#dd382873]
基本的なライントレースのプログラムは以下の通りです。
#define SPEED 32
#define KP 1.6
#define KI 0.00002
#define KD 0.8
#define THRESHOLD 50
#define THRESHOLD2 32
#define RIGHT 1
#define LEFT -1
#define DT 1
#define CT 250
int dev[2]; // 偏差
float integral;
// 操作量を返す関数
inline int ope_amount()
{
float pid;
int result;
dev[0]=dev[1]; // 過去の偏差
dev[1]=SENSOR_1-THRESHOLD; // 現在の偏差
if (dev[0]==dev[1]) { // 不要になったらintegralリセット
integral=0;
}
integral+=(dev[1]+dev[0])*DT/2; // 積分計算
pid=KP*dev[1]+KI*integral+KD*(dev[1]-dev[0])/DT; // PID
result=pid; // int型に変換
/*シンクロ率の範囲におさめる*/
if (result>100) {
result=100;
} else if (result<-100) {
result=-100;
}
return result;
}
/*
黒線の、とある側を走行する関数(車線変更つき)
*/
inline void go_xside(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
break;
}
}
}
task main()
{
while (true) {
go_xside(RIGHT);
go_xside(LEFT);
}
}
このプログラムは前回同様、PID制御を使ってライントレースを...
前回は、コースの形状を利用して力技で交差点を突破するプロ...
そこで、今回はもっと成功率が高い交差点通過方法を考えまし...
#ref(cross.png);
今回は閾値をラインの境界上とライン中央付近の2段階に設定...
直線やカーブの外側、緩やかなカーブの内側を走っているとき...
すると、go_xside内のif文が実行されます。
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn); // 通常と...
Wait(CT);
break;
}
このif文では通常ライン内にロボットが入ったとき、ライン外...
そうすることで、ライン中央を斜めに横切ってラインの反対側...
このように、交差点を斜めに横切ってわたりきることができる...
この方法では、前回の力技通過よりもKIなどの値や電池残量な...
↓以上を利用して、今回のために作ったプログラムです。
*** TIRE_main.nxc [#e1f19394]
タイヤを制御してライントレースをする方のメイン部分です。~
#define SPEED 33
#define SPEED2 20
#define KP 7
#define KI 0.002
#define KD 1.8
#define THRESHOLD 20
#define THRESHOLD2 10
#define RIGHT 1
#define LEFT -1
#define DT 1
#define CT 1200
#define ARM 1
#define FIRST_T 5000
void turn_right()
{
OnFwd(OUT_C,SPEED2);
OnFwd(OUT_B,-SPEED2);
}
void turn_left()
{
OnFwd(OUT_B,SPEED2);
OnFwd(OUT_C,-SPEED2);
}
void start_action()
{
// Bluetooth接続の確認
until (BluetoothStatus(ARM)==NO_ERR);
PlaySound(SOUND_UP);
// スタート地点からコースに乗るまで直進
OnFwdSync(OUT_BC,SPEED,0);
until (SENSOR_1<THRESHOLD);
Off(OUT_BC);
}
void can_build2()
{
// 図の右からゴール前の交差点に入るとする
turn_right();
Wait(CT);
Off(OUT_BC);
// 積み上げ指令を送る
SendRemoteNumber(ARM,MAILBOX3,1);
// 積み上げ完了の合図を待つ
int msg;
do {
msg=0;
ReceiveRemoteNumber(MAILBOX4,true,msg);
} while (!msg);
}
void can_build1()
{
// 図の右からゴール前の交差点に入るとする
turn_left();
Wait(CT*4);
Off(OUT_BC);
// ゴール奥へ移動
OnFwd(OUT_BC,SPEED);
Wait(CT*4);
Off(OUT_BC);
// 積み上げ指令を送る
SendRemoteNumber(ARM,MAILBOX3,1);
// 積み上げ完了の合図を待つ
int msg;
do {
msg=0;
ReceiveRemoteNumber(MAILBOX4,true,msg);
} while (!msg);
// バックで交差点まで戻って止まる
OnFwd(OUT_BC,-SPEED);
Wait(CT*5);
Off(OUT_BC);
SendRemoteNumber(ARM,MAILBOX5,1);
}
void end_action()
{
// かなり後ろに下がる
OnFwd(OUT_BC,-SPEED);
Wait(FIRST_T);
turn_right();
Wait(CT);
// コース外へ離脱
OnFwd(OUT_BC,100);
Wait(FIRST_T*2);
PlaySound(SOUND_UP);
}
// 缶があるかどうか判定する関数
int iscan()
{
if (SensorUS(S2)<=10) { // 超音波センサーが10cm以内を感知
return 1;
} else {
return 0;
}
}
// 缶の蹴り上げを命令する関数
void kick()
{
OnFwdSync(OUT_BC,SPEED,0);
Wait(CT);
Float(OUT_BC);
// Bluetoothで通信して蹴り上げを実行
SendRemoteNumber(ARM,MAILBOX1,1);
int msg=0;
do {
ReceiveRemoteNumber(MAILBOX2,true,msg);
} while (!msg);
}
int dev[2];
int flag,count;
float integral;
inline int ope_amount()
{
float pid;
int result;
dev[0]=dev[1]; // 過去の偏差
dev[1]=SENSOR_1-THRESHOLD; // 現在の偏差
if (dev[0]==dev[1]) { // 不要になったらintegralリセット
integral=0;
}
integral+=(dev[1]+dev[0])*DT/2; // 積分計算
pid=KP*dev[1]+KI*integral+KD*(dev[1]-dev[0])/DT; // PID
result=pid; // int型に変換
/*シンクロ率の範囲におさめる*/
if (result>100) {
result=100;
} else if (result<-100) {
result=-100;
}
return result;
}
inline void go_xside(int sgn,int change)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
if (iscan()) {
kick();
count++;
if (count==change) {
flag++;
break;
}
}
}
}
inline void go_xside2(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
count++;
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
}
}
inline void go_xside3(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED2,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
count++;
OnFwdSync(OUT_BC,SPEED2,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
}
}
// 1回目
// 缶を4つ集めてゴール前の交差点に到達するまで
void phase1()
{
count=0;
flag=0;
while (true) {
go_xside(LEFT,4);
if (flag) {
break;
}
go_xside(RIGHT,4);
if (flag) {
break;
}
}
count=0;
flag=0;
while (true) {
go_xside2(LEFT);
if (count==3){
break;
}
go_xside2(RIGHT);
if (count==3){
break;
}
}
Off(OUT_BC);
}
// 2回目
// ゴール前の交差点からスタートし、
// 缶を4つ集めてゴール前の交差点まで戻ってくるところまで
void phase2()
{
turn_right();
Wait(CT*4);
count=0;
// ヘアピンまで
while (true) {
go_xside2(LEFT);
if (count==2) {
break;
}
go_xside2(RIGHT);
if (count==2) {
break;
}
}
// 向こう岸へ移動
Wait(CT*4);
OnFwd(OUT_BC,SPEED);
Wait(FIRST_T);
count=0;
flag=0;
// 缶集め
while (true) {
go_xside(LEFT,4);
if (flag) {
break;
}
go_xside(RIGHT,4);
if (flag) {
break;
}
}
count=0;
// マップ移動
while (true) {
go_xside3(LEFT);
if (count==2) {
break;
}
go_xside3(RIGHT);
if (count==2) {
break;
}
}
Wait(CT);
count=0;
while (true) {
go_xside2(LEFT);
if (count==3) {
break;
}
go_xside2(RIGHT);
if (count==3) {
break;
}
}
Off(OUT_BC);
}
// ライントレース用タイヤ制御側プログラム(MASTER)
//main部分
task main()
{
SetSensorLight(S1);
SetSensorLowspeed(S2);
// スタート地点からコースに乗るまでの行動
start_action();
// 缶集めと缶建てそれぞれ2回ずつ
phase1();
can_build1();
phase2();
can_build2();
// コース外への離脱を定義
end_action();
}
このプログラムでは下のようにコースを回って缶を4つ集めて...
#ref(map2.png);
まずphase1()では上図の?(赤)、?(緑)のように進んでいき...
缶を4つ集め終わるとgo_xside2に切り替わります。この関数で...
can_build1ではまずゴール前の交差点で45度右に旋回してそ...
建て終わったという指示を受け取ると、バックしてゴール前の...
このあと、2回目の缶集めのためにphase2に移ります。
phase2では上図の?(青)のように進んでいきます。~
go_xside関数が働いていて、ゴールから出発した後、ヘアピン...
can_build2では、交差点で右45度に旋回したあと、その場で...
end_actionでは、建てた缶にぶつからないように、十分下がっ...
** 缶を動かす部分の仕様 [#bd227f2c]
*** ARM_main.nxc [#gc20b1f4]
アーム制御をする方のメイン部分です。~
マスターである上のライントレースをするプログラムであるTIR...
#define DT 1
#define CT 250
// 蹴り上げ
void hit()
{
// 蹴り
RotateMotor(OUT_A,100,270);
Wait(3000);
Off(OUT_A);
Wait(DT);
// 戻し
RotateMotor(OUT_A,-20,270);
Wait(3000);
Off(OUT_A);
Wait(DT);
SendResponseNumber(MAILBOX2,1);
PlaySound(SOUND_UP);
}
void build()
{
// 抑えアームを動かす
RotateMotor(OUT_C,20,120);
Wait(CT);
Off(OUT_C);
// 上げる
ResetTachoCount(OUT_B);
while (MotorTachoCount(OUT_B)>-20) {
OnFwdReg(OUT_B,-15,OUT_REGMODE_SPEED);
PlaySound(SOUND_UP);
}
Off(OUT_B);
// 抑え外す
RotateMotor(OUT_C,-20,120);
Wait(CT);
Off(OUT_C);
// 建て終わりの合図
SendResponseNumber(MAILBOX4,1);
// 収納合図を待つ
int ord=0;
do {
ReceiveRemoteNumber(MAILBOX5,true,ord);
} while (!ord);
// 収納
ResetTachoCount(OUT_B);
while (MotorTachoCount(OUT_B)<30) {
OnFwdReg(OUT_B,1,OUT_REGMODE_SPEED);
PlaySound(SOUND_DOWN);
}
Off(OUT_B);
Wait(DT);
}
// アーム部main
task main()
{
int msg;
while (true) {
msg=0;
// 蹴り上げを指令を確認
ReceiveRemoteNumber(MAILBOX1,true,msg);
if (msg) {
msg=0;
hit();
}
// 缶建ての指令を確認
ReceiveRemoteNumber(MAILBOX3,true,msg);
if (msg) {
msg=0;
build();
}
}
}
缶を集める段階では、マスターの方が缶を見つけると、缶をレ...
#ref(robo2-4.jpg);
缶を建てる段階になると、マスターの方から指示が送られてき...
関数buildでは、建てるときにタワーの下の方を支えるための腕...
#ref(robo2-6.jpg);
缶を建て終えたらマスターの方に指示を送ります。この指示を...
格納作業が終わると、マスター側に指示を出して、再び缶集め...
*実際に動かしてみた... [#x7f1c2ad]
上ではずいぶんスムーズに館を建てる作業までいけるようなこ...
缶を蹴りいれて缶を集める作業は予想以上にうまくいきました...
また、本体が重すぎて後輪が滑らかに動かずにそもそもうまく...
缶を建てる作業についても、缶を倒さないようにゆっくりとレ...
*反省点・改善点 [#p4525d91]
**ロボットについて [#r5322306]
実際に動かしてみると全然うまくいきませんでした。~
これを改善するには、まずロボットをもっと余裕のある設計に...
たとえば、後輪をもっと強化して、ライントレースに支障が出...
また、缶を建てるときにレールを上げるため動力としてモータ...
**プログラムについて [#nbbe1536]
ライントレース部分については、前回の課題の時よりもより安...
缶を建てる部分についても、結構大雑把な動作になっていたと...
終了行:
目次
#contents
*課題2内容 [#vb71dca6]
>2台のロボットで空き缶を収集し、ゴールに空き缶になるべく...
>
>基本ルール
>競技時間は審判が続行不能と判断するまで、あるいはリタイア...
>図の左下の隅からスタートする。ロボットが紙からはみ出ない...
>空き缶を集めて図の「ゴール」と書かれた円弧と直線で囲まれ...
>なるべく高く空き缶を積み上げる
>運び終わった後、あるいは積み上げた後はロボットはゴールの...
>開始の合図から5秒以内にスタートボタンを押す作業を完了す...
>競技が終了するまで、ロボットに触ったり人間が遠隔で操作し...
>途中でうまく動かなくなった場合、1回限り再スタートするこ...
以上[[2013b/Mission2]]より引用
&aname(map);
コース図
#ref(robocon2013b.png);
*メンバー [#zab397a9]
[[dyuma>2013b/Member/dyuma/Mission2]]~
ロボット製作(+ロボット管理)・プログラミングとどちらもこ...
[[pepo>2013b/Member/pepo/Mission2]]~
ロボットを組ませたら彼の右に出るものはいない。(ただし情...
michaegon~
このページの著者~
プログラムの方をやってます。
*ロボット概要 [#t8caacae]
今回使用したロボットです。胴体がかなり長いです。
#ref(robo2.jpg);
胴体中央のレールに缶が4本まで入るようになっています。
#ref(robo2-1.jpg);
缶をこの腕で殴ってレールに入れる仕組みです。
#ref(robo2-2.jpg);
#ref(robo2-3.jpg);
#ref(robo2-4.jpg);
缶を感知するのにはこの超音波センサーを使います。
#ref(robo2-7.jpg);
レールの後ろから缶が漏れないようにストッパー君がついてい...
#ref(robo2-8.jpg);
缶をレールに詰め込んだら、缶を抑えるための腕で缶を抑えな...
#ref(robo2-5.jpg);
#ref(robo2-6.jpg);
*プログラム概要 [#u38c8111]
** ライントレース部分の仕様 [#bea8657d]
今回もPID制御を利用したライントレースプログラムを組んでみ...
前回の反省を生かしてより安定して成功できるものに改良しま...
PID制御については[[前回>2013b/Member/michaegon/Mission1]]...
***交差点・急カーブ判定 [#dd382873]
基本的なライントレースのプログラムは以下の通りです。
#define SPEED 32
#define KP 1.6
#define KI 0.00002
#define KD 0.8
#define THRESHOLD 50
#define THRESHOLD2 32
#define RIGHT 1
#define LEFT -1
#define DT 1
#define CT 250
int dev[2]; // 偏差
float integral;
// 操作量を返す関数
inline int ope_amount()
{
float pid;
int result;
dev[0]=dev[1]; // 過去の偏差
dev[1]=SENSOR_1-THRESHOLD; // 現在の偏差
if (dev[0]==dev[1]) { // 不要になったらintegralリセット
integral=0;
}
integral+=(dev[1]+dev[0])*DT/2; // 積分計算
pid=KP*dev[1]+KI*integral+KD*(dev[1]-dev[0])/DT; // PID
result=pid; // int型に変換
/*シンクロ率の範囲におさめる*/
if (result>100) {
result=100;
} else if (result<-100) {
result=-100;
}
return result;
}
/*
黒線の、とある側を走行する関数(車線変更つき)
*/
inline void go_xside(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
break;
}
}
}
task main()
{
while (true) {
go_xside(RIGHT);
go_xside(LEFT);
}
}
このプログラムは前回同様、PID制御を使ってライントレースを...
前回は、コースの形状を利用して力技で交差点を突破するプロ...
そこで、今回はもっと成功率が高い交差点通過方法を考えまし...
#ref(cross.png);
今回は閾値をラインの境界上とライン中央付近の2段階に設定...
直線やカーブの外側、緩やかなカーブの内側を走っているとき...
すると、go_xside内のif文が実行されます。
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn); // 通常と...
Wait(CT);
break;
}
このif文では通常ライン内にロボットが入ったとき、ライン外...
そうすることで、ライン中央を斜めに横切ってラインの反対側...
このように、交差点を斜めに横切ってわたりきることができる...
この方法では、前回の力技通過よりもKIなどの値や電池残量な...
↓以上を利用して、今回のために作ったプログラムです。
*** TIRE_main.nxc [#e1f19394]
タイヤを制御してライントレースをする方のメイン部分です。~
#define SPEED 33
#define SPEED2 20
#define KP 7
#define KI 0.002
#define KD 1.8
#define THRESHOLD 20
#define THRESHOLD2 10
#define RIGHT 1
#define LEFT -1
#define DT 1
#define CT 1200
#define ARM 1
#define FIRST_T 5000
void turn_right()
{
OnFwd(OUT_C,SPEED2);
OnFwd(OUT_B,-SPEED2);
}
void turn_left()
{
OnFwd(OUT_B,SPEED2);
OnFwd(OUT_C,-SPEED2);
}
void start_action()
{
// Bluetooth接続の確認
until (BluetoothStatus(ARM)==NO_ERR);
PlaySound(SOUND_UP);
// スタート地点からコースに乗るまで直進
OnFwdSync(OUT_BC,SPEED,0);
until (SENSOR_1<THRESHOLD);
Off(OUT_BC);
}
void can_build2()
{
// 図の右からゴール前の交差点に入るとする
turn_right();
Wait(CT);
Off(OUT_BC);
// 積み上げ指令を送る
SendRemoteNumber(ARM,MAILBOX3,1);
// 積み上げ完了の合図を待つ
int msg;
do {
msg=0;
ReceiveRemoteNumber(MAILBOX4,true,msg);
} while (!msg);
}
void can_build1()
{
// 図の右からゴール前の交差点に入るとする
turn_left();
Wait(CT*4);
Off(OUT_BC);
// ゴール奥へ移動
OnFwd(OUT_BC,SPEED);
Wait(CT*4);
Off(OUT_BC);
// 積み上げ指令を送る
SendRemoteNumber(ARM,MAILBOX3,1);
// 積み上げ完了の合図を待つ
int msg;
do {
msg=0;
ReceiveRemoteNumber(MAILBOX4,true,msg);
} while (!msg);
// バックで交差点まで戻って止まる
OnFwd(OUT_BC,-SPEED);
Wait(CT*5);
Off(OUT_BC);
SendRemoteNumber(ARM,MAILBOX5,1);
}
void end_action()
{
// かなり後ろに下がる
OnFwd(OUT_BC,-SPEED);
Wait(FIRST_T);
turn_right();
Wait(CT);
// コース外へ離脱
OnFwd(OUT_BC,100);
Wait(FIRST_T*2);
PlaySound(SOUND_UP);
}
// 缶があるかどうか判定する関数
int iscan()
{
if (SensorUS(S2)<=10) { // 超音波センサーが10cm以内を感知
return 1;
} else {
return 0;
}
}
// 缶の蹴り上げを命令する関数
void kick()
{
OnFwdSync(OUT_BC,SPEED,0);
Wait(CT);
Float(OUT_BC);
// Bluetoothで通信して蹴り上げを実行
SendRemoteNumber(ARM,MAILBOX1,1);
int msg=0;
do {
ReceiveRemoteNumber(MAILBOX2,true,msg);
} while (!msg);
}
int dev[2];
int flag,count;
float integral;
inline int ope_amount()
{
float pid;
int result;
dev[0]=dev[1]; // 過去の偏差
dev[1]=SENSOR_1-THRESHOLD; // 現在の偏差
if (dev[0]==dev[1]) { // 不要になったらintegralリセット
integral=0;
}
integral+=(dev[1]+dev[0])*DT/2; // 積分計算
pid=KP*dev[1]+KI*integral+KD*(dev[1]-dev[0])/DT; // PID
result=pid; // int型に変換
/*シンクロ率の範囲におさめる*/
if (result>100) {
result=100;
} else if (result<-100) {
result=-100;
}
return result;
}
inline void go_xside(int sgn,int change)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
if (iscan()) {
kick();
count++;
if (count==change) {
flag++;
break;
}
}
}
}
inline void go_xside2(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
count++;
OnFwdSync(OUT_BC,SPEED,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
}
}
inline void go_xside3(int sgn)
{
while (true) {
OnFwdSync(OUT_BC,SPEED2,ope_amount()*sgn);
Wait(DT);
if (SENSOR_1<THRESHOLD2) {
count++;
OnFwdSync(OUT_BC,SPEED2,-ope_amount()*sgn);
Wait(CT);
PlaySound(SOUND_UP);
break;
}
}
}
// 1回目
// 缶を4つ集めてゴール前の交差点に到達するまで
void phase1()
{
count=0;
flag=0;
while (true) {
go_xside(LEFT,4);
if (flag) {
break;
}
go_xside(RIGHT,4);
if (flag) {
break;
}
}
count=0;
flag=0;
while (true) {
go_xside2(LEFT);
if (count==3){
break;
}
go_xside2(RIGHT);
if (count==3){
break;
}
}
Off(OUT_BC);
}
// 2回目
// ゴール前の交差点からスタートし、
// 缶を4つ集めてゴール前の交差点まで戻ってくるところまで
void phase2()
{
turn_right();
Wait(CT*4);
count=0;
// ヘアピンまで
while (true) {
go_xside2(LEFT);
if (count==2) {
break;
}
go_xside2(RIGHT);
if (count==2) {
break;
}
}
// 向こう岸へ移動
Wait(CT*4);
OnFwd(OUT_BC,SPEED);
Wait(FIRST_T);
count=0;
flag=0;
// 缶集め
while (true) {
go_xside(LEFT,4);
if (flag) {
break;
}
go_xside(RIGHT,4);
if (flag) {
break;
}
}
count=0;
// マップ移動
while (true) {
go_xside3(LEFT);
if (count==2) {
break;
}
go_xside3(RIGHT);
if (count==2) {
break;
}
}
Wait(CT);
count=0;
while (true) {
go_xside2(LEFT);
if (count==3) {
break;
}
go_xside2(RIGHT);
if (count==3) {
break;
}
}
Off(OUT_BC);
}
// ライントレース用タイヤ制御側プログラム(MASTER)
//main部分
task main()
{
SetSensorLight(S1);
SetSensorLowspeed(S2);
// スタート地点からコースに乗るまでの行動
start_action();
// 缶集めと缶建てそれぞれ2回ずつ
phase1();
can_build1();
phase2();
can_build2();
// コース外への離脱を定義
end_action();
}
このプログラムでは下のようにコースを回って缶を4つ集めて...
#ref(map2.png);
まずphase1()では上図の?(赤)、?(緑)のように進んでいき...
缶を4つ集め終わるとgo_xside2に切り替わります。この関数で...
can_build1ではまずゴール前の交差点で45度右に旋回してそ...
建て終わったという指示を受け取ると、バックしてゴール前の...
このあと、2回目の缶集めのためにphase2に移ります。
phase2では上図の?(青)のように進んでいきます。~
go_xside関数が働いていて、ゴールから出発した後、ヘアピン...
can_build2では、交差点で右45度に旋回したあと、その場で...
end_actionでは、建てた缶にぶつからないように、十分下がっ...
** 缶を動かす部分の仕様 [#bd227f2c]
*** ARM_main.nxc [#gc20b1f4]
アーム制御をする方のメイン部分です。~
マスターである上のライントレースをするプログラムであるTIR...
#define DT 1
#define CT 250
// 蹴り上げ
void hit()
{
// 蹴り
RotateMotor(OUT_A,100,270);
Wait(3000);
Off(OUT_A);
Wait(DT);
// 戻し
RotateMotor(OUT_A,-20,270);
Wait(3000);
Off(OUT_A);
Wait(DT);
SendResponseNumber(MAILBOX2,1);
PlaySound(SOUND_UP);
}
void build()
{
// 抑えアームを動かす
RotateMotor(OUT_C,20,120);
Wait(CT);
Off(OUT_C);
// 上げる
ResetTachoCount(OUT_B);
while (MotorTachoCount(OUT_B)>-20) {
OnFwdReg(OUT_B,-15,OUT_REGMODE_SPEED);
PlaySound(SOUND_UP);
}
Off(OUT_B);
// 抑え外す
RotateMotor(OUT_C,-20,120);
Wait(CT);
Off(OUT_C);
// 建て終わりの合図
SendResponseNumber(MAILBOX4,1);
// 収納合図を待つ
int ord=0;
do {
ReceiveRemoteNumber(MAILBOX5,true,ord);
} while (!ord);
// 収納
ResetTachoCount(OUT_B);
while (MotorTachoCount(OUT_B)<30) {
OnFwdReg(OUT_B,1,OUT_REGMODE_SPEED);
PlaySound(SOUND_DOWN);
}
Off(OUT_B);
Wait(DT);
}
// アーム部main
task main()
{
int msg;
while (true) {
msg=0;
// 蹴り上げを指令を確認
ReceiveRemoteNumber(MAILBOX1,true,msg);
if (msg) {
msg=0;
hit();
}
// 缶建ての指令を確認
ReceiveRemoteNumber(MAILBOX3,true,msg);
if (msg) {
msg=0;
build();
}
}
}
缶を集める段階では、マスターの方が缶を見つけると、缶をレ...
#ref(robo2-4.jpg);
缶を建てる段階になると、マスターの方から指示が送られてき...
関数buildでは、建てるときにタワーの下の方を支えるための腕...
#ref(robo2-6.jpg);
缶を建て終えたらマスターの方に指示を送ります。この指示を...
格納作業が終わると、マスター側に指示を出して、再び缶集め...
*実際に動かしてみた... [#x7f1c2ad]
上ではずいぶんスムーズに館を建てる作業までいけるようなこ...
缶を蹴りいれて缶を集める作業は予想以上にうまくいきました...
また、本体が重すぎて後輪が滑らかに動かずにそもそもうまく...
缶を建てる作業についても、缶を倒さないようにゆっくりとレ...
*反省点・改善点 [#p4525d91]
**ロボットについて [#r5322306]
実際に動かしてみると全然うまくいきませんでした。~
これを改善するには、まずロボットをもっと余裕のある設計に...
たとえば、後輪をもっと強化して、ライントレースに支障が出...
また、缶を建てるときにレールを上げるため動力としてモータ...
**プログラムについて [#nbbe1536]
ライントレース部分については、前回の課題の時よりもより安...
缶を建てる部分についても、結構大雑把な動作になっていたと...
ページ名: