目次
#contents
* 書道ロボット [#kc6aef55]
「各自の出身地または氏名の中の一文字(7画以上)をA4用紙の中に書く」ロボットを製作した。
完成した字
(左:練習時、紙を固定したとき) (右:発表時、紙を軽く押さえたとき)
&ref(2015b/Member/rmsun/Mission1/IMG_1057.JPG,270*360,高(固定));
&ref(2015b/Member/rmsun/Mission1/IMG_1171.JPG,270*360,高(本番));
* ロボット本体 [#cec79a4d]
初期ロボットの後ろにペンをつけた構造。ペンは輪ゴムで固定してある。
モータAはペンを持つアームに、モータBは右のタイヤに、モータCは左のタイヤに取り付けた。
ペンの位置は、モータBCの中間と一直線上にある。これが後々役に立った。
#ref(2015b/Member/rmsun/Mission1/IMG_1060.JPG,360*270,書道ロボット正面)
*プログラム [#m32e30bc]
サーボモータと、回転数を計算する関数を使って、「移動距離」や「方向変換する角度」を引数にとるサブルーチンを作った。それらを用いてロボットを移動させるため、モータを回す秒数は考えなくて良くなった。モータの回転角度を指定して動かすので、電池の残量による動きの変化も抑えられた(ある程度)
**メイン関数以外のプログラム [#wb572dc0]
***マクロの定義 [#ca3c85e6]
方向変換時のスピードは、タイヤの摩擦を減らすことばかり考えた結果、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」 [#y2c1419e]
「magni×移動距離」移動する、とプログラムすることで、好きな大きさで文字を書けるようにする。
移動にはサブルーチンを使っているため、magniをあちこちにつける必要は無く、3つのサブルーチンにつけるだけで済んだ。
float magni=1.0; //倍率を設定 例:magni=2.0 → 文字の大きさが2.0倍
&ref(2015b/Member/rmsun/Mission1/IMG_1056.JPG,270*360,文字をmagni倍);
←文字の倍率を0.5→1.0→1.5→2.0→2.5にした時の大きさの比較
***タイヤの回転数を計算する関数「GetAngle_d」「GetAngle_s」 [#rbfc594a]
タイヤの回転数を計算するために使う変数
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」 [#k7fa5963]
・サブルーチン「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」 [#q2d85e44]
・サブルーチン「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」 [#d4c2619e]
サブルーチン「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」 [#x81c3f00]
サブルーチン「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」 [#k0ad77bc]
「高」では「口」を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);
**方向変換の動作を詳しく [#f0fe2ef5]
サブルーチン「spin_re」を使ったとき、ロボットが実際にどのような動作をするのかの説明
今回は「90度左回転の方向変換をする」ときを例に説明する。
「spin_re」は、ロボットを回転させつつ、ペンの位置を最初と同じにするのが目的
(左写真:回転の中心の位置、モータBとモータCの間にある)
(右写真:ペンの初期位置)
&ref(2015b/Member/rmsun/Mission1/IMG_1078.JPG,360*480,回転の中心);
&ref(2015b/Member/rmsun/Mission1/IMG_1082.JPG,360*480,ペンの初期位置);
***� 峅鹽召涼羶粥廚函屮撻鵑琉銘屐廚竜�離分だけ後転する [#v6e2c55b]
回転の中心を、最初ペンのあった位置まで持っていく。
このとき実行されたプログラム↓↓
RotateMotorEx(OUT_BC,-50,GetAngle_d(pen_to_center-gosa1),0,true,true);
//pen_to_center-gosa1(cm)後転(gosaは回転の時のズレを修正するため)
#ref(2015b/Member/rmsun/Mission1/IMG_1085.JPG,360*480,後退)
***�▲蹈椒奪箸鮖慊蠅粒囘找鹽召気擦� [#b0a71654]
実際に方向変換したい角度分、回転させる。
このとき実行されたプログラム↓↓
turn(spin_ang,pl_mi); //spin_ang(度)回転
&ref(2015b/Member/rmsun/Mission1/IMG_1086.JPG,360*480,後退時のペンの位置);
回転→→
&ref(2015b/Member/rmsun/Mission1/IMG_1089.JPG,360*480,回転);
***��「回転の中心」と「ペンの位置」の距離分だけ前転する [#a584e47f]
ペンを元の位置に戻すため、�,撚爾�った分の距離を進む。
このときのペンの位置は、最初のペンの位置と同じ。
このとき実行されたプログラム↓↓
RotateMotorEx(OUT_BC,20,GetAngle_d(pen_to_center-gosa2-gosa1),0,true,true);
//pen_to_center-gosa2-gosa1(cm)前転(gosaは回転の時のズレを修正するため)
***�し覯� [#h5e0c8c4]
「ペンを中心にして、指定の角度回転させたとき」と同じ結果が得られる。
#ref(2015b/Member/rmsun/Mission1/IMG_1095.JPG,270*360,結果)
**メイン関数(実際に字を書くプログラム) [#m0a26da1]
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); //最後の「口」を書く
}
*使うと思っていたサブルーチン「harai」 [#i93f8fa2]
今回書いた字の「高」には、曲線がなかった。そのため、曲線の移動をする「harai」は出番が無かった。なので、今回のプログラムには含まれていないが、これがあった方が書ける字の幅は広がる。
「harai」... 左右のタイヤ(モータ)をどれだけ同期させるかで、ロボットの曲がり具合を決めて線を引く(字を書く)
sub harai(float ha, int angl) {
/*angl>0...右斜めへの「はらい」
angl<0...左斜めへの「はらい」*/
down1(); //ペンを素早く下げる(地面にはつけない)
Wait(100);
down2(); //ペンをゆっくり地面につける
Wait(10);
RotateMotorEx(OUT_BC,SPEED,GetAngle_d(ha),angl,true,true);
//anglは「左右のタイヤの同期」の調整のため
//ha(cm)前転
up(); //ペンを上げる
RotateMotorEx(OUT_BC,-SPEED,GetAngle_d(ha),angl,true,true);
//「字を書いた距離」分戻って、ロボットの向きを元に戻す
}
*工夫点 [#k7ba3fac]
・サーボモータや、回転角度を計算する関数を使ったことで、「xセンチ進む」「yセンチ下がる」「z度向きを変える」のように長さや角度を指定してロボットを動かせるようになった。サブルーチンの引数に進む距離や回転する角度が書いてあるので、プログラムを見れば、ロボットがどんな動きをしているのかがわかる。
・文字の倍率を設定できるようにした。そのおかげで、文字が紙からはみ出る心配が消えた。
*反省点 [#y108e50d]
・紙をおさえないと字が書けなくなってしまった。タイヤの摩擦を減らすためとはいえ、回転スピード100%は流石にやり過ぎだった。
・プログラムがかなり長くなってしまった。必要以上にサブルーチンを使っているので、サブルーチン同士をまとめたりして、数を減らすべきだった(特に、「turn」と「spin_re」は、まとめておくべきだった)
・ロボット製作では全く貢献できなかったので、次回からは貢献できるように頑張りたい。