[[2016b/Member]]

#contents

* 概要 [#k332b24c]
今回の[[課題:http://yakushi.shinshu-u.ac.jp/robotics/?2016b%2FMission1]]は書道ロボットである.
今回の[[課題:http://yakushi.shinshu-u.ac.jp/robotics/?2016b%2FMission1]]は書道ロボットである.

一般的なローバーにペンをつけただけでは,H/Wは簡単でもS/Wで困難を極めるので,縦軸を動くロボットと横軸を動くロボット,そしてペンの昇降装置をつくり,それぞれに役割を分担させることにした.こうすることでコーディングが簡単になる.
一般的なローバーにペンをつけただけでは,H/Wは簡単でもS/Wで困難を極めるので,縦軸を動くロボットと横軸を動くロボット,そしてペンの昇降装置をつくり,それぞれに役割を分担させることにした.こうすることでコーディングが簡単になる.

加えて,このタイプのロボットであれば(理論上は)描画する線の角度なども,バッテリーの電圧に依存することなく常に一定になる(但し最終的な文字の大きさは変化する).

* ハードウェアについて [#fe7dae33]

#ref(2016b/Member/ta.kashi/Mission1/Fig_001.JPG,80%,完成したロボット)

もともとは自動車工場などで稼働しているような「アームロボット」型のものを作る予定だっただが,部品点数の少なさやS/Wが複雑になりすぎることが判明したので断念した.
もともとは自動車工場などで稼働しているような「アームロボット」型のものを作る予定だっただが,部品点数の少なさやS/Wが複雑になりすぎることが判明したので断念した.

かわって,冒頭で記した通り,縦軸(以降Y軸と呼ぶ)を動くローバーロボットに高架を接続し,その上に,横軸(以降X軸と呼ぶ)を動くローバーロボットを走らせる.そのローバーロボットにペンの昇降を制御するアームを取り付け,Y軸移動,X軸移動,ペンの昇降をそれぞれ独立して制御するようにした.
かわって,冒頭で記した通り,縦軸(以降Y軸と呼ぶ)を動くローバーロボットに高架を接続し,その上に,横軸(以降X軸と呼ぶ)を動くローバーロボットを走らせる.そのローバーロボットにペンの昇降を制御するアームを取り付け,Y軸移動,X軸移動,ペンの昇降をそれぞれ独立して制御するようにした.

** Y軸制御ロボット [#w18d7065]

#ref(2016b/Member/ta.kashi/Mission1/Fig_002.JPG,80%,Y軸制御ロボット)


写真の通り,基本的なローバーロボットに高架を接続した.
写真の通り,基本的なローバーロボットに高架を接続したものである.

ローバーロボット本体に関しては途中で曲がらずに,より直線的に移動する必要があり,また,高架にアーム付きローバーロボット(重い)が乗ることを考え,できるだけ安定する必要がある.そのためにホイールスペースをできるだけ長くとった.
ローバーロボット本体に関しては途中で曲がらずに,できるかぎり直線的に移動する必要があり,また,高架にアーム付きローバーロボット(重い)が乗ることを考え,できるだけ安定する必要がある.そのためにホイールスペースをできるだけ長くとった.

また,ローバーロボットと反対側を支える支柱はできるだけ滑らかに動作し,引っかかることのないようにしなければならなかったため,あえてタイヤ(ゴム)を外したが,あまり改善されなかった.
また,ローバーロボットと反対側を支える支柱はできるだけ滑らかに動作し,引っかかることのないようにしなければならなかったため,あえてタイヤ(ゴム)を外したが,あまり改善されなかった.

高架部分は長いブロックを使用し,重さに耐えられるようにした.途中つなぎ目部分で段差があるが,動作に支障はなかった.
高架部分は長いブロックを使用し,重さに耐えられるようにした.途中つなぎ目部分で段差があるが,動作に支障はなかった.

** X軸制御/ペン昇降ロボット [#bf60eca9]

#ref(2016b/Member/ta.kashi/Mission1/Fig_003.JPG,80%,X軸制御/ペン昇降ロボット)


基本的なローバーロボットであるが,車輪の幅が高架の幅と一致するようになっている.また,動作時の振動や通信ケーブルのねじれによって脱輪することのないように,ロボット下側にガイドを取り付けた.
#ref(2016b/Member/ta.kashi/Mission1/Fig_004.JPG,50%,ガイド)
基本的なローバーロボットであるが,車輪の幅が高架の幅と一致するようになっている.また,動作時の振動や通信ケーブルのねじれによって脱輪することのないように,ロボット下側にガイドを取り付けた.

Y軸制御ロボットを作った段階で部品が不足していたため,アームの取り付けにはかなり無理をしている(ただし動作に支障はなかった).
#ref(2016b/Member/ta.kashi/Mission1/Fig_004.JPG,80%,ガイド)

当初は,ペンの昇降は"4211510"と呼ばれる部品(ねじ状の部品)を使い,エレベーターのように行う予定であったが,部品の不足と重量の問題で断念し,かわりにモーターにペンを取り付けるだけのシンプルな構成にした.これによって部品を大幅に節約できるが,ペン先を紙面に対して垂直に当てられないため,ペンを降ろす際の力加減によっては,これが動作時の微妙なずれの原因となるようである.これはS/Wによるキャリブレーションで解決している.
Y軸制御ロボットを作った段階で部品が不足していたため,アーム部分の取り付けにはかなり無理をしている(ただし動作に支障はなかった).

当初は,ペンの昇降は"4211510"と呼ばれる部品(ねじ状の部品)を使い,エレベーターのように行う予定であったが,部品の不足と重量の問題で断念し,かわりにモーターにペンを取り付けるだけのシンプルな構成にした.これによって部品を大幅に節約できるが,ペン先を紙面に対して垂直に当てられないため,ペンを降ろす際の力加減によっては,これが動作時の微妙なずれの原因となるようである.これはS/Wによるキャリブレーションで解決している.

* ソフトウェアについて [#x786cf6a]

課題では「7画以上の漢字」を書く必要があるが,H/Wの仕様上斜めに線を描くことが難しい(実際に試したが無視できないほどの誤差が生じてしまった)ので,極力水平・垂直な線の多い文字を選ぶ必要がある.今回は「車」「豆」という文字を選んだ.
課題では「7画以上の漢字」を書く必要があるが,H/Wの仕様上斜めに線を描くことが難しい(実際に試したが無視できないほどの誤差が生じてしまった)ので,極力水平・垂直な線の多い文字を選ぶ必要がある.今回は「車」「豆」という文字を選んだ.

以下がそのコード(「車」)である.
以下がそのコード(「車」)である.結果は[[こちら>#r55c21f1]]を参照.

 //OUT_A -> Y軸移動(縦)
 //OUT_B -> X軸移動(横)
 //OUT_C -> Z軸移動(ペン)
 
 #define MP_XY 20				//モーターの強さは20に固定
 #define MP_Z 10					//ただしペンの昇降は弱めにする
 
 sub X_ML(int time)				//X軸左方向
 {
 	OnRev(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub X_MR(int time)				//X軸右方向
 {
 	OnFwd(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_UP(int time)				//Y軸上方向
 {
 	OnRev(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_DWN(int time)				//Y軸下方向
 {
 	OnFwd(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_UP()					//ペンをあげる
 {
 	RotateMotor(OUT_C,MP_Z,-20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_DWN()					//ペンをおろす
 {
 	RotateMotor(OUT_C,MP_Z,20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 task main()
 {
 	
 	/*
 	"Z_DWN()"から"Z_UP()"までの動作で線を描画する.
 	それ以外の動作は移動のみで,実際に描画はしない.
 	
 	ペン先を紙面に当てた状態で実行すること.
 	*/
 	
 	Z_UP();
 	
 	Z_DWN();X_MR(1000);Z_UP();
 	
 	Y_DWN(200);
 	
 	Z_DWN();X_ML(1000);Y_DWN(600);Z_UP();
 	
 	Y_UP(600);X_MR(1000);
 	
 	Z_DWN();Y_DWN(600);Z_UP();
 		
 	Y_UP(400);
 	
 	Z_DWN();X_ML(1200);Z_UP();
 		
 	Y_DWN(400);
 	
 	Z_DWN();X_MR(1200);Z_UP();
 	
 	Y_DWN(300);
 		
 	Z_DWN();X_ML(1200);Z_UP();
 	
 	Y_UP(1500);X_MR(600);
 	
 	Z_DWN();Y_DWN(1600);Z_UP();
 }



** モーターの対応 [#nf95a1f0]

 //OUT_A -> Y軸移動(縦)
 //OUT_B -> X軸移動(横)
 //OUT_C -> Z軸移動(ペン)

これは,それぞれの出力が対応するモーターを示している(コメント).
これは,それぞれの出力が対応するモーターを示している(コメント).

** モーターのトルクを定義 [#d3f0263b]

 #define MP_XY 20				//モーターの強さは20に固定
 #define MP_Z 10					//ただしペンの昇降は弱めにする

これは,モーターのトルクをマクロ置換している(MP=Moter Power).
これは,モーターのトルクをマクロ置換している(MP=Moter Power).

H/Wの動作,特に,ペンの昇降についてはゆっくりと行わないと誤差の原因となる.X軸制御/ペン昇降ロボットについては,あまり高速に動作させると高架から脱輪することもあった.
H/Wの動作,特に,ペンの昇降についてはゆっくりと行わないと誤差の原因となる.X軸制御/ペン昇降ロボットについては,あまり高速に動作させると高架から脱輪することもあった.

** 各種動作の定義 [#i2b29751]

 sub X_ML(int time)				//X軸左方向
 {
 	OnRev(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub X_MR(int time)				//X軸右方向
 {
 	OnFwd(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }

これは,X軸方向の移動をsubroutineとして定義したものである.
これは,X軸方向の移動をsubroutineとして定義したものである.

動作時間(=移動距離)を引数としている.動作後には1秒間静止するようにしている.これは,振動によるズレを防ぐためである.
動作時間(=移動距離)を引数としている.動作後には1秒間静止するようにしている.これは,振動によるズレを防ぐためである.

以下も同様

 sub Y_UP(int time)				//Y軸上方向
 {
 	OnRev(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_DWN(int time)				//Y軸下方向
 {
 	OnFwd(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_UP()					//ペンをあげる
 {
 	RotateMotor(OUT_C,MP_Z,-20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_DWN()					//ペンをおろす
 {
 	RotateMotor(OUT_C,MP_Z,20);
 	Off(OUT_ABC);Wait(1000);
 }

ペンの昇降についてはOnFwd(OnRev)ではなく,回転の角度を指定できるRotateMotorを使用した.
ペンの昇降についてはOnFwd(OnRev)ではなく,回転の角度を指定できるRotateMotorを使用した.

** task main() [#s7e23c40]

 task main()
 {
 	
 	/*
 	"Z_DWN()"から"Z_UP()"までの動作で線を描画する.
 	それ以外の動作は移動のみで,実際に描画はしない.
 	
 	ペン先を紙面に当てた状態で実行すること.
 	*/
 	
 	Z_UP();
 	
 	Z_DWN();X_MR(1000);Z_UP();
 	
 	Y_DWN(200);
 	
 	Z_DWN();X_ML(1000);Y_DWN(600);Z_UP();
 	
 	Y_UP(600);X_MR(1000);
 	
 	Z_DWN();Y_DWN(600);Z_UP();
 		
 	Y_UP(400);
 	
 	Z_DWN();X_ML(1200);Z_UP();
 		
 	Y_DWN(400);
 	
 	Z_DWN();X_MR(1200);Z_UP();
 	
 	Y_DWN(300);
 		
 	Z_DWN();X_ML(1200);Z_UP();
 	
 	Y_UP(1500);X_MR(600);
 	
 	Z_DWN();Y_DWN(1600);Z_UP();
 }

最初はペン先を紙面に当てた状態にしておく.これは,線を描く際に確実にペン先を紙面に当てるためである.プログラムを実行すると同時にペン先は指定した角度(20度)上昇する.
最初はペン先を紙面に当てた状態にしておく.これは,線を描く際に確実にペン先を紙面に当てるためである.プログラムを実行すると同時にペン先は指定した角度(20度)上昇する.

以降,Z_DWN()でペン先が紙面に当たり,Z_UP()でペン先が離れるわけなので,Z_DWN()からZ_UP()で挟まれた部分は実際に紙面に描画され,それ以外は描画されない,ただの移動となる(ペン先は空中を移動する).
以降,Z_DWN()でペン先が紙面に当たり,Z_UP()でペン先が離れるわけなので,Z_DWN()からZ_UP()で挟まれた部分は実際に紙面に描画され,それ以外は描画されない,ただの移動となる(ペン先は空中を移動する).

注意する点は,特にY軸方向に描画する際に,図のように手前方向へ移動するのはOKだが,奥方向はNGである(線がかすれてしまう).
注意する点は,特にY軸方向に描画する際に,図のように手前方向へ移動するのはOKだが,奥方向はNGである(線がかすれてしまう).

#ref(2016b/Member/ta.kashi/Mission1/Fig_005.JPG,80%,ペン先の移動)

移動量が一致しないところもあるが,これは実際に紙面に描画する際のズレを考慮した結果である.

** 別のコード [#a97277bb]

「車」以外にも「豆」という漢字も書くことができた.
「車」以外にも「豆」という漢字も書くことができた.結果は[[こちら>#ia154883]]を参照.

 //OUT_A _> Y軸移動(縦)
 //OUT_B _> X軸移動(横)
 //OUT_C _> Z軸移動(ペン)
 
 #define MP_XY 20				//モーターの強さは20に固定
 #define MP_Z 10					//ただしペンの昇降は弱めにする
 
 sub X_ML(int time)				//X軸左方向き
 {
 	OnRev(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub X_MR(int time)				//X軸右方向
 {
 	OnFwd(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_UP(int time)				//Y軸上方向
 {
 	OnRev(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_DWN(int time)				//Y軸下方向
 {
 	OnFwd(OUT_A,MP_XY);Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_UP()					//ペンをあげる
 {
 	RotateMotor(OUT_C,MP_Z,-20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_DWN()					//ペンをおろす
 {
 	RotateMotor(OUT_C,MP_Z,20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 task main()
 {
 	/*
 	"Z_DWN()"から"Z_UP()"までの動作で線を描画する.
 	それ以外の動作は移動のみで,実際に描画はしない.
 	
 	ペン先を紙面に当てた状態で実行すること.
 	*/
 	
 	Z_UP();
 	
 	Z_DWN();X_MR(1000);Z_UP();
 	
 	Y_DWN(300);X_ML(300);
 	
 	Z_DWN();X_ML(700);Y_DWN(400);X_MR(800);Z_UP();
 	
 	Y_UP(400);
 	
 	Z_DWN();Y_DWN(400);Z_UP();
 	
 	X_ML(600);Y_DWN(200);
 	
 	Z_DWN();Y_DWN(400);Z_UP();
 	
 	X_MR(500);Y_UP(400);
 	
 	Z_DWN();Y_DWN(400);Z_UP();
 	
 	X_ML(800);Y_DWN(200);
 	
 	Z_DWN();X_MR(1200);Z_UP();
 }

* プリンターのような動作も [#l8b06310]

インクジェットプリンターのように動作させ,文字(やイラスト)を描画することもできる.この場合,Y軸制御ロボットがプリンターの紙送り機能を,X軸制御/ペン昇降ロボットがプリンターのヘッドの役割をなす.
インクジェットプリンターのように動作させ,文字(やイラスト)を描画することもできる.この場合,Y軸制御ロボットがプリンターの紙送り機能を,X軸制御/ペン昇降ロボットがプリンターのヘッドの役割をなす.

下図のように,文字を20x20のドットに分割して考える.
この場合,斜めの線や曲線を多用した文字でも容易に描写できる.

下図のように,文字を20x20のドットに分割して考える.

#ref(2016b/Member/ta.kashi/Mission1/Fig_006.JPG,80%,デザイン)

以下がそのコードである.
以下がそのコードである.結果は[[こちら>#c65845b7]]を参照.

 //OUT_A _> Y軸移動(縦)
 //OUT_B _> X軸移動(横)
 //OUT_C _> Z軸移動(ペン)
 
 #define MP_XY 20				//モーターの強さは20に固定
 #define MP_Z 10					//ただしペンの昇降は弱めにする
 
 sub X_ML(int time)				//X軸左方向に走査
 {
 	OnRev(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub X_MR(int time)				//X軸右方向に走査
 {
 	OnFwd(OUT_B,MP_XY);
 	Wait(time);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Y_DWN()					//Y軸方向に1単位進む
 {
 	OnFwd(OUT_A,MP_XY);Wait(200);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_UP()					//ペンをあげる
 {
 	RotateMotor(OUT_C,MP_Z,-20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 sub Z_DWN()					//ペンをおろす
 {
 	RotateMotor(OUT_C,MP_Z,20);
 	Off(OUT_ABC);Wait(1000);
 }
 
 task main()
 {
 	Z_UP();
 	
 	//1行目
 	X_ML(2050);
 	Y_DWN();
 	
 	//2行目	
 	X_MR(150);
 	Z_DWN();X_MR(1800);Z_UP();
 	X_MR(100);
 	Y_DWN();
 	
 	//3行目
 	X_ML(150);
 	Z_DWN();X_ML(1800);Z_UP();
 	X_ML(100);
 	Y_DWN();
 	
 	//4行目
 	X_MR(50);
 	Z_DWN();X_MR(200);Z_UP();
 	X_MR(1400);
 	Z_DWN();X_MR(200);Z_UP();
 	X_MR(100);
 	Y_DWN();
 	
 	//5行目
 	X_ML(1350);
 	Z_DWN();X_ML(200);Z_UP();
 	X_ML(500);
 	Y_DWN();
 	
 	//6行目
 	X_MR(450);
 	Z_DWN();X_MR(1100);Z_UP();
 	X_MR(400);
 	Y_DWN();
 	
 	//7行目
 	X_ML(450);
 	Z_DWN();X_ML(1100);Z_UP();
 	X_ML(400);
 	Y_DWN();
 	
 	//8行目
 	X_MR(450);
 	Z_DWN();X_MR(200);Z_UP();
 	X_MR(1300);
 	Y_DWN();
 	
 	//9行目
 	X_ML(1350);
 	Z_DWN();X_ML(200);Z_UP();
 	X_ML(500);
 	Y_DWN();
 	
 	//10行目
 	X_MR(450);
 	Z_DWN();X_MR(200);Z_UP();
 	X_MR(1300);
 	Y_DWN();
 	
 	//11行目
 	X_ML(450);
 	Z_DWN();X_ML(1100);Z_UP();
 	X_ML(400);
 	Y_DWN();
 	
 	//12行目
 	X_MR(450);
 	Z_DWN();X_MR(1100);Z_UP();
 	X_MR(400);
 	Y_DWN();
 	
 	//13行目
 	X_ML(450);
 	Z_DWN();X_ML(200);Z_UP();
 	X_ML(700);
 	Z_DWN();X_ML(200);Z_UP();
 	X_ML(500);
 	Y_DWN();
 	
 	//14行目
 	X_MR(1350);
 	Z_DWN();X_MR(200);Z_UP();
 	X_MR(400);
 	Y_DWN();
 	
 	//15行目
 	X_ML(250);
 	Z_DWN(),X_ML(1600);Z_UP();
 	X_ML(200);
 	Y_DWN();
 	
 	//16行目
 	X_MR(150);
 	Z_DWN(),X_MR(1600);Z_UP();
 	X_MR(200);
 	Y_DWN();
 	
 	//17行目
 	X_ML(450);
 	Z_DWN(),X_ML(200);Z_UP();
 	X_ML(1400);
 	Y_DWN();
 	
 	//18行目
 	X_MR(750);
 	Z_DWN(),X_MR(800);Z_UP();
 	X_MR(400);
 	Y_DWN();
 	
 	//19行目
 	X_ML(450);
 	Z_DWN(),X_ML(800);Z_UP();
 	X_ML(800);
 	Y_DWN();
 	
 	//20行目
 	X_MR(1950);
 }

* 結果 [#g0d32be8]

** 「豆」 [#ia154883]

#ref(2016b/Member/ta.kashi/Mission1/Fig_007.JPG,80%,デザイン)

** 「車」 [#r55c21f1]

#ref(2016b/Member/ta.kashi/Mission1/Fig_008.JPG,80%,デザイン)

** 「写」 [#c65845b7]

#ref(2016b/Member/ta.kashi/Mission1/Fig_009.JPG,80%,デザイン)

走査線の間隔が広いのでわかりにくいが,以下のように「写」と描画されている.Y軸の間隔をもっと小さくすればよいが,そこまで細かい制御はできなかった.

#ref(2016b/Member/ta.kashi/Mission1/Fig_010.JPG,80%,デザイン)

* 感想と反省 [#s0168e40]

mindstormシリーズは,実は小学生の時に使ったことがあり,簡単な茶運び人形程度のものであれば作ったことがあった.しかしその際はGUIでコードの記述を行っていたのに対し,今回はCライクな言語で記述する必要があった.GUIに比べて動作が視覚的に確認しづらいという点では苦労したが,プログラミングに対する理解が深まった.

H/Wでは,特に動作毎の微妙な誤差に悩まされたが,それも部品の調整やS/Wの調整で減らすことができた.


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS