似顔絵を描くロボットを作る

概要

絵を描くロボットの作成ということで、様々な方法を考え、その中の一つをLEGOを使って組み立てた。今回使った方法は、長いアームを左右に振る動きと、前後の動きで絵を描くものである。これにより、ロボット自体の単純・軽量化を狙うことができた。その反面、アーム部が弱点になってしまったりプログラムが難化したりと欠点も多かった。

動作について

筆記部の動作は前後移動、アームの回転のみで行われる。極座標系のような動きで、範囲内であれば理論上はどのような線でも描画することができる。(図1)

ただし、nxcでは三角関数は使えないので、あらかじめ動作させる座標と対応した値を計算し、プログラムを書く必要がある。

式は、理論上では以下のようになる。

θ:回転角
W:進む距離

X:目標地点のx座標
Y:目標地点のy座標
A:アームの長さ

θ = -cos^(-1) (X/A)
W = Y-sqrt(A^2-X^2)

round.png(図1)

ロボット設計

構想について

consept.png

最初に、どのようなロボットを作るかを考えた。前述の方法で動作させることができるように、いくつのモータが必要か、どの方向に取り付けるべきかを考えた。

実機について

cart.jpg

まず、ロボットの土台となる台車部を制作した。このロボットは前後方向にのみ動けばいいので、駆動輪二輪と自由輪二輪の計四輪駆動とした。

rotate1.jpgrotate2.jpg

次に、左右に振る方向のモーターを取り付けた。90度回転させたので苦労した上に、それに見合う強度は得られなかった。

arm.jpg

最後に、アーム部を制作した。紙の端まで届くように長くした。また、自重で筆記できるように先を若干重くした。

利点・欠点

このロボットの利点としては、次の点が挙げられる

欠点としては次の点が挙げられる

結果

face.jpg

顔の形にし、一応の完成を見ることができた。懸念したとおり、アーム部分が脆弱になってしまい、ブレが大きくなってしまった。また、空中の旋回と筆記中の旋回の誤差が思ったよりも大きくなってしまった。

プログラム

アームの上げ下げ

まず、アームの上げ下げ用のサブルーチンを作成した。

上げるサブルーチン

sub up(){
	OnRev(OUT_C,45); //アームを上方向に45の力で動作させる
	Wait(200);       //200ms続ける
	Off(OUT_C);      //オフにする
}

下げるサブルーチン

sub down(){
	OnFwd(OUT_C,5);  //アームを下方向に5の力で動作させる
	Wait(300);       //300ms続ける
	Float(OUT_C);    //アームを自然に降下させる
	Wait(300);       //完全に下りるよう、300ms待つ
}

アームの移動

アームの移動には、正確性を高めるためにRotateMotor(PORT, SPEED, θ);関数を使った。しかしながら、この関数は特性としてモーターの回転が終わるまで次の動作に移らないので、タスクを用いて左右移動、前後進移動を同時に行えるようにした。

int movingstr=1;                //前後に動いているかのフラグ
int movingtur=1;                //左右に動いているかのフラグ
sub up(){
	OnRev(OUT_C,45);         //アームを上方向に45の力で動作させる
	Wait(200);               //200ms続ける
	Off(OUT_C);              //オフにする
}
sub down(){
	OnFwd(OUT_C,5);          //アームを下方向に5の力で動作させる
	Wait(300);               //300ms続ける
	Float(OUT_C);            //アームを自然に降下させる
	Wait(300);               //完全に下りるよう、300ms待つ
}
task straight(){
	down();                  //アームを下ろす

	movingstr=1;             //現在動いていることを指示する
	RotateMotor(OUT_A,50,75);//前方向に75°タイヤが回転する分動く
	movingstr=0;             //動作が終わったことを示す
	Off(OUT_A);              //オフにする
	while(movingtur);        //左右方向の動作の停止を待つ
	Wait(100);               //同期ずれを防ぐため、100ms待つ

	up();                    //アームを上げる
}
task turn(){
	Wait(600);               //アームを下ろす間待つ

	movingtur=1;             //現在動いていることを支持する
	Wait(50);                //前後方向は実際の発進までラグがあるので待つ
	RotateMotor(OUT_B,30,10);//10°アームを回転させる
	movingtur=0;             //動作が終わったことを示す
	Off(OUT_B);              //オフにする
	while(movingstr);        //前後方向の動作の停止を待つ
	Wait(100);               //同期ずれを防ぐため、100ms待つ

	Wait(200);               //アームを上げる間待つ
}
task main(){
	Precedes(straight,turn); //タスクを登録
}

プログラム全文

計算が煩雑であり、コードが長くなるので外部プログラムを作成し、生成した。

int movingstr=1;
int movingtur=1;
sub up(){	
	OnRev(OUT_C,45);
	Wait(200);
	Off(OUT_C);
}
sub down(){	
	OnFwd(OUT_C,5);
	Wait(300);
	Float(OUT_C);
	Wait(300);
}
task straight(){
	down();

	movingstr=1;
	RotateMotor(OUT_A,50,75);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,166);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,31);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,22);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,-50,47);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,-50,27);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,204);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,50,62);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,145);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,8);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,-50,33);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,1);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,28);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,7);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,3);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,-50,19);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,4);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,34);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,-50,14);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,23);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,50,16);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,-50,8);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,50,1);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,50,18);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,-50,8);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,46);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,-50,18);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	up();

	movingstr=1;
	RotateMotor(OUT_A,-50,16);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	down();

	movingstr=1;
	RotateMotor(OUT_A,-50,16);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

	movingstr=1;
	RotateMotor(OUT_A,50,22);
	movingstr=0;
	Off(OUT_A);
	while(movingtur);
	Wait(100);

}
task turn(){
	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,10);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,4);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,3);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,11);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,2);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,10);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,2);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,4);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,0,0);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,0,0);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,0,0);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,6);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,0,0);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,7);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,7);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,3);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,1);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,3);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,3);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,1);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,8);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,0,0);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(200);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,-30,4);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	Wait(600);
	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,4);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

	movingtur=1;
	Wait(50);
	RotateMotor(OUT_B,30,5);
	movingtur=0;
	Off(OUT_B);
	while(movingstr);
	Wait(100);

}
task main(){
	Precedes(straight,turn);
}

感想

ナカムラ

思った以上に難しく、様々な障壁があるものだと思った。

第一の障壁はロボット設計で、アームやロボット自信の強度を上げるのには苦労した。第二の障壁はプログラムで、動作するはずだと思って作っても実機では簡単に動いてくれず、何回も手直しをすることになった。最後の障壁は時間だった。何回も手直しをするたびに時間を消費し、作業時間はとてつもない長さになてしまった。

しかしながら、少しずつ直し、無事に動いた時の感動は大きいものだった。直しては改善されず、落胆した分だけ正常に動作した時の喜びは大きかった。

今回は初めての課題ということでスケジュールに追われることが多く、作成期間がとても長くなってしまった。しかし、これも経験の一つとして覚えておきたい。

コメント



添付ファイル: fileface.jpg 313件 [詳細] filerotate2.jpg 357件 [詳細] filerotate1.jpg 317件 [詳細] filecart.jpg 119件 [詳細] filearm.jpg 316件 [詳細] fileconsept.png 306件 [詳細] fileround.png 330件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-12-05 (月) 12:59:24