サーボ動作ブロック(モジュール)
続いてサーボ動作をさせる部分を作ります。
このサーボ動作ブロックの部分を作ることになります。
数値が入力されれば、その数値に応じてサーボが角度に回転するという機能に。
いろいろなとこから出てくる数値をサーボ動作ブロックに入力するだけでサーボ回転の制御が出来るモジュールです。
”出てきた数値”とは、 ボリュームだったり、センサだったりと、いろいろなモジュールから出てくる数値を、入力すればサーボ回転の制御ができるような数値入力範囲にします。数値の入力範囲を可変にし、設定できるようにします。
プログラム
ラジコンサーボを動かす で使用した設定を汎用性のある関数に改良したものです。
タイマーW初期化関数
ini_DrvSarvo2M()
これを最初に実行し、レジスタの初期設定をします。
タイマーWの機能を使用するので、作り出されるパルスはここでのタイマーW設定周波数の影響を受けます。ini関数で必ず2M設定する必要があります。
この関数は引数で設定を変えられるようにせず、必ず2Mで型どおりを実行する関数にしました。 サーボパルスの周期を20msに固定しています (これは引数設定で可変にしないことにしました)
パルス発生関数
DrvSarvo2M( struct sarvo sv, int inp, int div)
AD_Vlm(int div)関数はあらかじめ、divの値が 4,8,・・・ と決めて、その数値にすることで入力する範囲が決まりました。
ここでDrvSarvo2Mはその範囲を自由に設定できるようにしました。
この サーボ動作ブロックの 数値入力 の範囲を設定可能に。
渡す引数は3つ
サーボの最大、最小パルス範囲設定
struct sarvo サーボ名
struct sarvo s3003;
のように適当な名前で構造体変数を宣言し(ここでは s3003)
3003.ang_max = 最大パルス
s3003.ang_min = 最小パルス
にサーボモーターの最大、最小パルスを入れ、制御するサーボの上、下限値を設定し、s3003を 引数1番目にします。
引数3番目 divに入力する数値の最大値を入れ、0~divのスケールをつくり
引数2番目 inpにそのスケール範囲(0~div)内の目標値を渡します。
引数inpに入力された数値に応じたパルスにして出す。
例)
DrvSarvo2M( struct sarvo sv, int inp, int div)
目標値 inp:50 div:100にすると
→ DrvSarvo2M( s3003, 50, 100 )
最小パルス 最大パルス
↓ ↓
0 div:100
入力範囲は 0 - 100 (0のとき最小パルスを出力、100で最大パルスを出力)
- inp:50 なのでちょうど 入力範囲0 - 100の中間の位置にサーボが回転する
- inp:100 すると 最大値 s3003.ang_max に回転する(3003.ang_maxのパルスを出力)
- inp: 0 にすると 最小値 s3003.ang_min に回転する(3003.ang_minのパルスを出力)
のように使えるようにしました。
関数内部で ハードウエアリミットとして、最大パルス2.3 最小パルス1.4
それに対応する GRB値も 4600、1400 として この範囲以上のパルスは出力できないようにしています。
説明が複雑になりますが、使い方は割と簡単でなかなか使えそうな関数です。
デバッガでのエミュレーション用 プログラム
#include
struct sarvo{
float ang_max;
float ang_min;
};
int GRB;
void ini_DrvSarvo2M(){
TW.TMRW.BYTE=0x01; // FTIOB端子をPWM出力に設定
TW.TCRW.BYTE=0xB2; // マッチAでカウンタクリア、内部クロックの1/8( 2MHz ) FTIOBの初期値は1
TW.TCNT=0x0000; // TCNの初期化
TW.GRA=20000; // 20mS (50Hz)
TW.GRB=3000; // 1.5mS
}
void DrvSarvo2M(struct sarvo sv,int inp,int div){
/**********************************
機能 = 引数inpの数字に応じてサーボを回転させる
引数:div:スケール ,inp:目標値 ,struct sarvo:サーボ最大最小パルス
返値:なし
動作:サーボ回転
***********************************/
int GRout;
long GRmax;
long GRmin;
long p;
//範囲外処理
if(sv.ang_max > 2.3 || sv.ang_min < 0.7) {return;} //何もせずに返る
GRmax=(int)2000*sv.ang_max;
GRmin=(int)2000*sv.ang_min;
GRmax=GRmax*100;//少数演算用100倍long
GRmin=GRmin*100;//少数演算用100倍long
p=( ((GRmax-GRmin)/div)*inp ); //
GRout=(p + GRmin )/100;
//範囲外処理
if(GRout > 4600 || GRout < 1400) {return;}
GRB=GRout; //デバッグ出力
}
int main(void){
struct sarvo s3003;
s3003.ang_max=2.0;
s3003.ang_min=1.0;
DrvSarvo2M(s3003, 50, 100); //実行結果 GRB=3000
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 100, 100); //実行結果 GRB=4000
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 0, 63); //実行結果 GRB=2000
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 31, 63); //実行結果 GRB=2983
printf( "GRB=%d\n", GRB );
}
GRBの数値をサーボ用パルスに対応するように計算して作り出せばいいので、要するにスケール変換の要領です。
周期は TW.GRA=20000 10msにしてあるので、
算出したGRBをTW.GRBに入れるとサーボパルスが発生します。
このタイマー初期化では ○ms×2000=GRB用の数値に変換できます。
if(sv.ang_max > 2.3 || sv.ang_min < 0.7) {return;}
サーボの最大、最小パルスの範囲外処理。これは範囲外のパルスをサーボに入力しないためです。
その数値は、だいたいどのサーボもこんな程度だろうという数値にしています。
(構造体sv - ang_max、ang_min でサーボ範囲を入力しています。
ここだけfloat型にしています。ムダのようですが、ここは少数入力にしたくて・・)
入力値をGRBに与える数値への変換後に再び、範囲外処理をしています。
変換で何か変な数値となっても、やはり範囲外の動きになるパルスを出力しないため。
GRmax=GRmax*100;//少数演算用100倍long
GRmin=GRmin*100;//少数演算用100倍long
p=( ((GRmax-GRmin)/div)*inp ); //
GRout=(p + GRmin )/100;
引数div:スケール最大値 の変換処理部分。
割り算すると少数になることがありますが、小数以下2桁程度あればいいので、
ここだけのために小数型のfloatなどは使わず、100倍して整数で割り算し、あとで100で割る方法です。
本来は小数型など使わず、整数型でやるべきところです。
これはデバッガでのエミュレーション用なので 初期化関数
ini_DrvSarvo2M() は使用しません。
実行結果
実行してGRBがどのようになるかみると
s3003.ang_max=2.0;
s3003.ang_min=1.0; として 50、100にして見た値を見ると
50で中間 100で上限に目論見通りなりました。
(GRB=4000でタイマーWがパルス2.0msを出す)
DrvSarvo2M(s3003, 50, 100); //実行結果 GRB=3000 (1.5ms)
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 100, 100); //実行結果 GRB=4000(2.0ms)
printf( "GRB=%d\n", GRB );
② スケールを div:63 として 0、31にして見た値を見ると
0 で スケールの下限に
31 で だいたい中間値に
DrvSarvo2M(s3003, 0, 63); //実行結果 GRB=2000 (1.0ms)
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 31, 63); //実行結果 GRB=2983(約1.5ms)
printf( "GRB=%d\n", GRB );
● サーボの上限、下限値を変更
続いて サーボの範囲も変更してみます。
struct sarvo s3003;
s3003.ang_max=1.5;
s3003.ang_min=1.0;
サーボの最大パルスを1.5ms(GRBで3000)の数値にします。これ以上の数値は出力しないはずです。
サーボの範囲 変更
int main(void)
{
struct sarvo s3003;
s3003.ang_max=1.5;
s3003.ang_min=1.0;
DrvSarvo2M(s3003, 100, 100); //実行結果 GRB=3000 (1.5ms)
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 0, 100); //実行結果 GRB=2000 (1.0ms)
printf( "GRB=%d\n", GRB );
DrvSarvo2M(s3003, 50, 100); //実行結果 GRB=2500 (1.25ms)
printf( "GRB=%d\n", GRB );
}
スケールの最大、最小にすると 最大3000 最小2000 中間2500 と目標通り機能しています。
それでは次にボリュームとつなげてみます。
- twtter
- google+
- hatena