目次

書道ロボット

「各自の出身地または氏名の中の一文字(7画以上)をA4用紙の中に書く」ロボットを製作した。

完成した字

(左:練習時、紙を固定したとき) (右:発表時、紙を軽く押さえたとき)

270*360,高(固定) 270*360,高(本番)

ロボット本体

初期ロボットの後ろにペンをつけた構造。ペンは輪ゴムで固定してある。

モータAはペンを持つアームに、モータBは右のタイヤに、モータCは左のタイヤに取り付けた。

ペンの位置は、モータBCの中間と一直線上にある。これが後々役に立った。

360*270,書道ロボット正面

プログラム

サーボモータと、回転数を計算する関数を使って、「移動距離」や「方向変換する角度」を引数にとるサブルーチンを作った。それらを用いてロボットを移動させるため、モータを回す秒数は考えなくて良くなった。モータの回転角度を指定して動かすので、電池の残量による動きの変化も抑えられた(ある程度)

メイン関数以外のプログラム

マクロの定義

方向変換時のスピードは、タイヤの摩擦を減らすことばかり考えた結果、100になった(せざるを得なかった)。このせいで紙をおさえなければ字が書けなくなってしまった。

#define SPEED 30       //前転後転時のスピード
#define WRITE_SPEED 20 //字を書くときのスピード
#define TURN_SPEED 100 //方向変換時のスピード
#define PUT_ANGLE 91   //ペンを上げ下げする時、モータが回転する角度

ペンの上げ下げを行うマクロ「down」と「up」。ペンを二段階に分けて下ろす。一段階目(down1)で「残り20度で接地する」角度まで素早く下ろし、二段階目(down2)で「残りの20度」ゆっくり下ろす。上げるとき(up)は、素早く、一気に一段階で。

#define down1() RotateMotor(OUT_A,-30,PUT_ANGLE-20) 
//ペンを素早く下げる(地面にはつけない)

#define down2() RotateMotor(OUT_A,-5,20)
//ペンをゆっくり地面につける

#define up() RotateMotor(OUT_A,70,PUT_ANGLE); 
//ペンを上げる

文字の倍率を設定するための変数「magni」

「magni×移動距離」移動する、とプログラムすることで、好きな大きさで文字を書けるようにする。

移動にはサブルーチンを使っているため、magniをあちこちにつける必要は無く、3つのサブルーチンにつけるだけで済んだ。

float magni=1.0;          //倍率を設定  例:magni=2.0 → 文字の大きさが2.0倍

270*360,文字をmagni倍 ←文字の倍率を0.5→1.0→1.5→2.0→2.5にした時の大きさの比較

タイヤの回転数を計算する関数「GetAngle_d」「GetAngle_s」

タイヤの回転数を計算するために使う変数

float pen_to_center=17.0; //回転の中心(左右のタイヤの中間)からペンまでの距離
float diameter=5.45;	     //タイヤの直径(cm)
float pi=3.1415;          //円周率
float tire_ang;	     //タイヤの回転する角度(返り値用)

「GetAngle_d」... 進みたい距離(cm)から、タイヤの回転数を計算する関数(http://yakushi.shinshu-u.ac.jp/robotics-jr/robotics-jr-2013.pdfの31ページのプログラムを参考にしました)

float GetAngle_d(float distance) {
        //進みたい距離(cm)「distance」から、タイヤの回転数を計算する関数

	tire_ang=(distance)/(diameter*pi)*360.0;  //角度を計算する	
	return tire_ang;	                     //角度を返す(float型)
}

「GetAngle_s」... 方向変換したい角度から、タイヤの回転数を計算する関数(http://yakushi.shinshu-u.ac.jp/robotics-jr/robotics-jr-2013.pdfの31ページにある練習問題62を参考にしました)

float GetAngle_s(float spin_ang) {
	//方向変換したい角度「spin_ang」から、タイヤの回転数を計算する関数

	const float spin_dia=11.4;
	//ロボットがその場で1周回転した時に、タイヤが地面に描く円の直径spin_dia(cm)
	//spin_dia...左右のタイヤの間隔

 	tire_ang=(spin_dia*spin_ang)/(diameter);
	//方向変換したい角度から、タイヤの回転する角度を計算する
        //約分前の式は tire_ang=(spin_dia*pi*(spin_ang/360.0)*360.0)/(diameter*pi)
				                   
	return tire_ang;	//角度を返す(float型)
} 

ロボットを前後に動かすサブルーチン「forward」「reverse」

・サブルーチン「forward」...指定した距離(cm)だけ前転する

sub forward(float fwd){
	RotateMotorEx(OUT_BC,SPEED,GetAngle_d(fwd)*magni,0,true,true);
	//fwd(cm)*magni(倍率)前転  
}

・サブルーチン「reverse」...指定した距離(cm)だけ後転する

sub reverse(float rev) {
	RotateMotorEx(OUT_BC,-SPEED,GetAngle_d(rev)*magni,0,true,true);
	//rev(cm)*magni(倍率)後転
}

GetAngle_dを用いることで、サブルーチン「forward」「reverse」は「前転後転する距離(cm)」をそのまま引数にとることができる。

使用例:3.0cm進みたいとき → forward(3.0)

5.0cm下がりたいとき → reverse(5.0)

ロボットを回転させるサブルーチン「turn」

・サブルーチン「turn」...指定した角度ロボットが回転する

sub turn(float tn,int pl_mi) {	
	//tn(度)方向変換

引数pl_miは、ロボットが右回転するか左回転するかを決める。

	/*pl_mi=1 → 右まわりに回転
	  pl_mi=-1 → 左まわりに回転*/

左右のタイヤを逆向きに回すことで、その場で回転する。

	RotateMotorEx(OUT_BC,TURN_SPEED,GetAngle_s(tn),100*pl_mi,true,true);
	//左右のタイヤの逆向きに回すことで方向変換
	Off(OUT_BC);
	Wait(100);
}

GetAngle_sを用いることで、サブルーチン「turn」は「回転する角度」をそのまま引数にとることができる。

使用例:90度右回転させたいとき → turn(90,1);

ペンの位置を変えずに方向変換するサブルーチン「spin_re」

サブルーチン「spin_re」... ロボットの向きを変えるが、ペンの位置は変えない

引数pl_miは、ロボットが右回転するか左回転するかを決める。

引数spin_angは、方向変換したい角度を決める。

sub spin_re(float spin_ang,int pl_mi) { 
	//「ペンを中心に、spin_ang度回転する」(ときと同じ結果になる)関数
	/*右に回転するとき...pl_mi=1
	  左に回転するとき...pl_mi=-1*/	

「ロボットが回転する時に生じる誤差」を修正するための「gosa1」「gosa2」

	float gosa1=0;	//右に回転するときの誤差「gosa1」
	float gosa2=0;	//左に回転するときの誤差「gosa2」
	if (pl_mi>0) {	//pl_mi>0(右への方向変換のとき)
		gosa1=0.5;	//右へ回転するときの誤差を修正する
	}
	else {			//左への方向変換のとき
		gosa2=0.5;	//左へ回転するときの誤差を修正する
	}

実際に方向変換する動作

       RotateMotorEx(OUT_BC,-50,GetAngle_d(pen_to_center-gosa1),0,true,true);	
 	//pen_to_center-gosa1(cm)後転(gosaは回転の時のズレを調節するため)
 	turn(spin_ang,pl_mi);	//spin_ang(度)回転
	RotateMotorEx(OUT_BC,20,GetAngle_d(pen_to_center-gosa2-gosa1),0,true,true);
	//pen_to_center-gosa2-gosa1(cm)前転
}

・方向変換のとき、ロボットはその場で回転するので、左右のタイヤの間に回転の中心がある。

・回転の中心では、いくら回転しても位置が変わらない。

→ペンを動かさずにロボットの向きを変えたいならば

 峅鹽召涼羶(今回は左右のタイヤの中間)」を「ペンの位置」まで移動させる

▲蹈椒奪箸鮖慊蠅粒囘找鹽召気擦

ペンを、,痢屮撻鵑琉銘屐廚泙念榮阿気擦

とすればよい

 銑を行うと、「ペンを中心に指定の角度回転させた」ときと同じ結果が得られる。

使用例:ペンを中心に右に90度方向変換 → spin_re(90,1);

「spin_re」の説明は、少し分かりづらいと思われる。なので「方向変換の動作を詳しく」の項目で、写真とともに説明する。

字を書くときに使うサブルーチン「write」

サブルーチン「write」... ペンが地面についた状態で、ロボットを前進させることで字を書く

ペンを二段階に分けて下ろすのが特徴。一段階目(down1)では「あと20度で接地する角度」まで素早く下ろし、そこで0.1秒停止する。二段階目(down2)では、「残りの20度」だけゆっくりペンを下ろす。ペンが接地するときに発生する力は、二段階目の「20度分ゆっくり下ろした」ときの力だけなので、ペンは安定した接地が可能。

ペン接地後、指定された距離だけ進む(このとき字を書く)。その後、ペンを上げる。このとき、ペンを素早く、一気に(一段階で)上げることで、無駄なインクが紙に付くのを防ぐ。

sub write(float kaku) //ペンで線を引く
{
	down1();	//ペンを素早く下げる(地面にはつけない)
	Wait(100);
	down2();	//ペンをゆっくり地面につける
	Wait(10);
	RotateMotorEx(OUT_BC,WRITE_SPEED,GetAngle_d(kaku)*magni,0,true,true);
			//WRITE_SPEEDの速さでkaku(cm)進む → kaku(cm)の線を書く
	up();		//ペンを上げる
}

使用例:6.0cmの線を引きたいとき → write(6.0);

「口」を書くためのサブルーチン「kuti」

「高」では「口」を2回書くので、一応サブルーチンにした。

sub kuti(float tate, float yoko) //口の字を書く
	//口の縦の長さ(tate)と、横の長さ(yoko)を引数にとる
{
	write(tate);		//tate(cm)書く
	spin_re(90.0,-1);    //ペンを中心に90度左回転
	write(yoko);	       //yoko(cm)書く
	spin_re(90.0,-1);	//ペンを中心に90度左回転
	write(tate);         // ↓ここから上の繰り返し(repeatを使ったら誤差が出た)
	spin_re(90.0,-1);
	write(yoko);
	spin_re(90.0,-1);
}

使用例:縦の長さ5.0cm、横の長さ10.0cmの「口」を書きたいとき → kuti(5.0,10.0);

方向変換の動作を詳しく

サブルーチン「spin_re」を使ったとき、ロボットが実際にどのような動作をするのかの説明

今回は「90度左回転の方向変換をする」ときを例に説明する。

「spin_re」は、ロボットを回転させつつ、ペンの位置を最初と同じにするのが目的

(左写真:回転の中心の位置、モータBとモータCの間にある)

(右写真:ペンの初期位置)

360*480,回転の中心 360*480,ペンの初期位置

 峅鹽召涼羶粥廚函屮撻鵑琉銘屐廚竜離分だけ後転する

回転の中心を、最初ペンのあった位置まで持っていく。

このとき実行されたプログラム↓↓

	RotateMotorEx(OUT_BC,-50,GetAngle_d(pen_to_center-gosa1),0,true,true);	
	//pen_to_center-gosa1(cm)後転(gosaは回転の時のズレを修正するため)
360*480,後退

▲蹈椒奪箸鮖慊蠅粒囘找鹽召気擦

実際に方向変換したい角度分、回転させる。

このとき実行されたプログラム↓↓

	turn(spin_ang,pl_mi);	//spin_ang(度)回転

360*480,後退時のペンの位置 回転→→ 360*480,回転

「回転の中心」と「ペンの位置」の距離分だけ前転する

ペンを元の位置に戻すため、,撚爾った分の距離を進む。

このときのペンの位置は、最初のペンの位置と同じ。

このとき実行されたプログラム↓↓

	RotateMotorEx(OUT_BC,20,GetAngle_d(pen_to_center-gosa2-gosa1),0,true,true);
	//pen_to_center-gosa2-gosa1(cm)前転(gosaは回転の時のズレを修正するため)

し覯

「ペンを中心にして、指定の角度回転させたとき」と同じ結果が得られる。

270*360,結果

メイン関数(実際に字を書くプログラム)

task main() 
{
	up();             //ペンを地面につけたままスタート
	write(1.0);       //1画目(「亠」の「|」の部分)
			     //2画目の位置(「亠」の「―」の部分)まで移動
	spin_re(90.0,-1);	 	//ペンを中心に90度左回転
	reverse(2.0);	   	 	//2.0(cm)後転
	write(4.0);	    //2画目(「亠」の「―」の部分)
			     //3画目(口の部分)まで移動
	reverse(3.0);    		 //3.0(cm)後転
	spin_re(90.0,1); 		 //ペンを中心に90度右回転
	forward(0.5);     		 //0.5(cm)前転
	kuti(1.0, 2.25);   //「口」の字を書く(4,5,6画目)
			      //7画目(「高」の左下の「|」の部分)まで移動
	forward(1.5);     		//1.5(cm)前転
	spin_re(90.0,-1); 		//ペンを中心に90度左回転
	reverse(1.25);    		//1.25(cm)後転
	spin_re(90.0,1);  	 	//ペンを中心に90度右回転
	write(3.0);        //7画目(「高」の左下の「|」の部分)
		       	      //8画目(真ん中を通る「一」の部分)まで移動
	reverse(3.0);	    		//3.0(cm)後転
	spin_re(90.0,-1);		//ペンを中心に90度左回転
	write(4.75);       //8画目(真ん中を通る「一」の部分)
		              //9画目(右下の「|」の部分)まで移動
	spin_re(90.0,1); 		//ペンを中心に90度右回転
	write(3.0);        //9画目(右下の「|」の部分)
	spin_re(90.0,1);   //ロボットの向きを7画目の「ー」と平行にする
			      //最後の「口」の部分まで移動
	forward(3.5);    		//3.5(cm)前転
	spin_re(90.0,-1);		//ペンを中心に90度左回転
	reverse(2.5);   		//2.5(cm)後転
 	kuti(1.0, 2.25);   //最後の「口」を書く
		
}

工夫点

・サーボモータや、回転角度を計算する関数を使ったことで、「xセンチ進む」「yセンチ下がる」「z度向きを変える」のように長さや角度を指定してロボットを動かせるようになった。サブルーチンの引数に進む距離や回転する角度が書いてあるので、プログラムを見れば、ロボットがどんな動きをしているのかがわかる。

・文字の倍率を設定できるようにした。そのおかげで、文字が紙からはみ出る心配が消えた。

反省点

・紙をおさえないと字が書けなくなってしまった。タイヤの摩擦を減らすためとはいえ、回転スピード100%は流石にやり過ぎだった。

・プログラムがかなり長くなってしまった。必要以上にサブルーチンを使っているので、サブルーチン同士をまとめたりして、数を減らすべきだった(特に、「turn」と「spin_re」は、まとめておくべきだった)

・ロボット製作では全く貢献できなかったので、次回からは貢献できるように頑張りたい。


添付ファイル: fileIMG_1085.JPG 101件 [詳細] fileIMG_1095.JPG 89件 [詳細] fileIMG_1171.JPG 93件 [詳細] fileIMG_1057.JPG 79件 [詳細] fileIMG_1056.JPG 112件 [詳細] fileIMG_1089.JPG 94件 [詳細] fileIMG_1078.JPG 86件 [詳細] fileIMG_1086.JPG 81件 [詳細] fileIMG_1082.JPG 106件 [詳細] fileIMG_1060.JPG 85件 [詳細]

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2015-11-27 (金) 16:05:09