Beauto講座

2011年1月 8日 (土)

本講座サンプルプログラムの利用方法

本講座のサンプルプログラムの利用方法を手順に沿って説明します。

1. VSTONEのVS-WRC003サポートページ内にあるC言語サンプルソースの中から「LEDの点滅」サンプルソース一式をダウンロードし、適当な作業用フォルダに展開します。

Dl_source2. Beauto講座の記事内にあるソースファイルへのリンクを右クリックしてダウンロードします。ここでは6_pid.cを例にとって説明します。

Save_as「LED点滅」のサンプルと同じフォルダに保存します。

Del21

3. 作業用フォルダに保存した「LED点滅」のプロジェクトをHEWで開きます。ウィンドウ左側にはプロジェクトに入っているファイルリストが表示されています。このうちled.cにmain関数が書かれていて、LEDを点滅させる処理を行っています。これを6_pid.cと入れ替えるために、

4. まずHEWのメニューから[プロジェクト]-[ファイルの削除...]を選びます。

Del22led.cをプロジェクトから削除します。

Add15. 次に6_pid.cをプロジェクトに追加します。メニューから[プロジェクト]-[ファイルの追加...]を選びます。新しく開いたウィンドウで6_pid.cを指定します。

Add2プロジェクトにファイルが追加されるとこのように表示されます。

6. VSTONEのサンプルプログラムと同じようにビルド、書き込み等を行います。

| | コメント (0) | トラックバック (0)

2011年1月 7日 (金)

Beauto講座サンプルプログラム訂正

第4回以降のサンプルプログラムに誤りがありましたので訂正(アップロードしたファイルの更新)するとともにお詫びします。以前のバージョンでは関数hgetcがないというリンカエラーが出ます。古いバージョンをダウンロードされた方は再度ダウンロードしてください。

| | コメント (0) | トラックバック (0)

2010年11月28日 (日)

VS-WRC003LVでシリアル通信デバッグを行う

本講座のサンプルがVS-WRC003LVやBeauto Roverでも動作することを確認しました。若干の修正が必要です。

本講座のサンプルをVS-WRC003LVで使う最も簡単な方法は、 VSTONEのサポートページから「無線コントローラVS-C1での操縦 」等のサンプルをダウンロードしてこれを利用することです。 プロジェクトをHEWで開いてmain.cをプロジェクトから削除、本講座のサンプルソース(たとえば6_pid.c)を代わりに追加します。

次に、6_pid.cの #include "vs-wrc003.h" #include "vs-wrc003lv.h" に直してください。

VSTONEのサポートページにVS-WRC003LV シリアルコンバータが公開されました。これを使えば本講座のようにシリアル通信を用いた調整およびデバッグができます。

ただし、少なくとも私の環境では通信速度を19200bpsまで下げた上でパリティなしの設定にする必要がありました。ロボット側で通信速度とパリティの設定を変えるには本講座のサンプルソースの InitSci3(CBR_115200, even, 1);InitSci3(CBR_19200, non, 1); に変更します。また、PCのターミナルソフトでもあわせて設定を行ってください。

なお、現時点においてvs-wrc003lv.cのmtr_run関数には依然としてバグがあります。 前回書いた注意点のようにvs-wrc003lv.cを修正するか、本講座サンプルソースのrun関数から下記2行を消すかのいずれかを行ってください。


void run(int speed, int turn_speed)
{
	// 前進速度+回転速度から左右のモーターのduty比を決める
	int d1 = speed - turn_speed;
	int d2 = speed + turn_speed;

	// 絶対値が127(100%)を超えないようにする
	// duty比が0のとき、Mtr_Runに渡す数は0x80にしてブレーキ動作にする

 	if(d1 > 127) d1 = 127;
	else if(d1 < -127) d1 = -127;
	else if(d1 == 0) d1 = 0x80; // brake  ←  この行を削除 

	if(d2 > 127) d2 = 127;
	else if(d2 < -127) d2 = -127;
	else if(d2 == 0) d2 = 0x80; // brake  ←  この行を削除 

	Mtr_Run(-d1, d2, 0, 0);
}

| | コメント (0) | トラックバック (0)

2010年9月18日 (土)

本講座のサンプルをVS-WRC003LVに移植する場合の注意点

2010年9月18日現在、VSTONEのサポートページで公開されているVS-WRC003LVのサンプルプログラム(「モータ制御サンプル」等、すべて)に含まれるMtr_run関数にはバグがあります。

この関数はBeauto Chaser用に書いたプログラムをVS-WRC003LVでも変わらず使えるようにするため(互換性のため)のものです。ブレーキ動作をあらわす0x80を入れた場合の動作が間違っていて、モーターが100%に近い速度で回りだします。本講座のプログラムのようにブレーキをよく使う場合には致命的ですので注意してください。

この関数を使用する場合はvs-wrc003lv.cの56行目から62行目を次のように修正してください。

修正前

  void Mtr_Run(BYTE mt1,BYTE mt2,BYTE mt3,BYTE mt4){
        if(mt1 == 0x80)
!               mt1 == 0;
        if(mt2 == 0x80)
!               mt2 == 0;
        if(mt3 == 0x80)
!               mt3 == 0;
        if(mt4 == 0x80)
!               mt4 == 0;

修正後

  void Mtr_Run(BYTE mt1,BYTE mt2,BYTE mt3,BYTE mt4){
        if(mt1 == 0x80)
!               mt1 = 0;
        if(mt2 == 0x80)
!               mt2 = 0;
        if(mt3 == 0x80)
!               mt3 = 0;
        if(mt4 == 0x80)
!               mt4 = 0;

なおVS-WRC003LVのモータードライバはフリーの動作ができないようになっており、Mtr_runやMtr_run_lvに0を指定してもフリーではなくブレーキになります。本講座のサンプルプログラムをVS-WRC003LVに応用する際、第5回、第6回のrun関数にある「0の場合0x80にする特別な場合わけ」は必要なくなります。

もうひとつの重要なことですが、VS-WRC003LVはPCからシリアルポートとして認識させることができません。そのため本講座で説明したような対話的デバッグや調整ができません。理論上、回路構成としてはシリアルポートとして使うこともできるようになっていますので、公式サポートが出るかどうか様子を見ることにしましょう。

| | コメント (0) | トラックバック (0)

2010年8月23日 (月)

Beauto ステップアップ講座6 PID制御器を用いたライントレース

第3回では、Beauto Builderのようなソフトを使ったフローチャート式プログラミングと本講座での考え方の違いについて述べました。

  1. 動作時間の指定はしない
  2. 条件判断ではなく実数の計算による

今回はこのうち2.についてです。

Beauto Builderのようなフローチャート式プログラミングツールでは「右センサーが一定以上の値で反応したら」等、YesかNoで表せる条件に従って分岐するのが制御プログラムの主要な構造となります。前回まではこれと同じ発想で、センサーから得た情報を3種類に場合分けして行動を選択していました。そのため、直線の線上を走り続けているときでも、ずれがある値より大きくなった瞬間に今までと大きく異なる動きをしようとします。このためロボットの動きがギクシャクしたものになってしまいます。微妙なずれを微妙に調整しながら滑らかに走行するのには向いていません。より多くの場合分けをすれば多少改善されるかもしれませんが、本質的には変わりません。

今回から扱うのは、連続な量を読み取り、そのまま連続的なモーター指令値に変換するという考え方です。用いる基本的な道具は条件判断ではなく、四則演算、特に乗算です。


void line_trace(int speed, float Kp, float Kd)
{
	float prev_line_pos = 0.0;  //前回のラインの位置
	while(1) {
		// 正規化したセンサ値の計算、ライン位置の計算などは省略
		// ・・・(中略)・・・
		line_pos = ・・・;
		
		run(speed, Kp * line_pos + Kd * (line_pos - prev_line_pos)); // (1)

		// ・・・(中略)・・・

		Sync();
		prev_line_pos = line_pos;        // 前回ライン位置として記憶する (2)
	}

(1)がライントレースの制御をおこなっている部分です。場合分けはありません。順番に見ていきましょう。

runへの第1引数、前進速度は一定でspeedにしています。これによりロボットは常に前へ進みます。

第2引数の第1項Kp * line_posは、ラインからのずれに比例したちからで旋回させるためのものです。ラインから大きくずれればずれるほど速く回転して中央に戻ろうとします。なお、ライン位置に掛かる比例定数Kpは適当に調整する必要があります。本講座では、ラインが左に見えるときline_posは負、runの第2引数は左回転(反時計回り)させたいとき正と決めました。そのためKpは負の数でなければなりません。正にするとラインから逃げるロボットになります(是非一度試してみてください)。

第2項についてですが、まずprev_line_posはこのwhileループについて1回前の繰り返しのときのline_posを記憶しています。(2)がそれを行っています。このため(line_pos - prev_line_pos)は、「前回からラインの位置がどれだけ変化したか」、つまりロボットから見てラインが移動する速度になります。これを用いて第2項のKd * (line_pos - prev_line_pos)はラインが移動する速度に比例したちからでロボットを旋回させようとします。ロボットが右回転している時に左回転の力を加えることになり、左右に振れるのを抑えるように働きます。また、ラインに対して平行でないと平行にする方向の力を発生しますので、折れ線や急なコーナーでロボットが線に対して斜めになったときにも効果を発揮します。このKdも同様に負でなければなりません。

最後に、2つの項の効果が両方とも出るように足し算します。

今回説明した制御方式だけでは急すぎるカーブや直角コーナーには対応できません。すべてのセンサーが線から外れ、線を見失ってしまったときにはライン位置が正しく計算できないためです。急なカーブに対してはKpを大きくするか、あるいはセンサー数を増やして検知範囲を広くすることで線を見失いにくくするという対処が考えられます。しかし直角コーナーは無理です。その他、何かの拍子に線から外れた場合も考慮して何らかの対策を別途記述しておく必要があります。

一例として、線から外れたら線のあると思われる方向にもっと強く旋回するという方法があります。これを実現するには、線がどちらにあるか、もっと正確には「もし次の瞬間に線から外れたとしたらどちらに外れた可能性が高いか」を常に判断し、記憶しておく必要があります。センサーが3個以上あれば比較的簡単に実現できます。センサーが2個だと検知範囲が狭いので、確実性の面で少し難しくなります。

サンプルプログラム
使い方・変更点

基本的な使い方は前回までと同じです。パラメータがspeed、Kp、Kdの3つに変更されています。deadband、turn_speedは今回の制御方式では使わないのでなくしました。

すべてのセンサーが線から外れた時を考慮した処理の一例として、停止して走行を終了するようにしました。センサー数を変更する場合はこの部分も変更する必要があります。このままではちょっと急なカーブでもすぐコースアウトして止まってしまいます。このような部分は「条件判断して処理を選ぶ」という点でBeauto Builderを使うフローチャート式プログラミングと同じですので、適宜工夫してみてください。


  (line_trace関数内)

		if(sval[0] < 0.3 && sval[1] < 0.3) { //どのセンサーも白い床の上にあるとき
			break;  //ライントレース終了
		}

また、USBケーブルを外してからスタートできるように、基板上のスイッチをスタートボタンにしました。設定画面で何も入力せず[Enter]を押すとReady.と表示されます。この後スイッチを押すと走り出します。


(main関数内)
		//何も入力せずEnterを押すと設定モード終了
		SciStrTx("Ready,\r\n", 8);
		//ボタンを押すとスタート
		while(!getSW());

USBケーブルを抜き差しした場合は、再度通信できるようにするためにターミナルソフトで切断と接続の操作を行ってください。

走行の様子

電源4.8V、Aギア(減速比12.7:1)という条件で試したところではspeed=80くらいまではコースアウトせず走れました。直線ではあまり揺れずにまっすぐ走り、カーブも止まらず滑らかに回れているということで、第1回で掲げた目標は達成できたのではないかと思います。

次回予告

今回説明した制御方式は一般にPID制御と呼ばれるものの仲間に入ります。PID制御からIをなくしたものなので特にPD制御と呼ぶこともあります。次回、このPID制御と本講座の内容の関係について解説します。なぜこのような制御方式をするのか、またなぜこの制御方式でうまくいくのかについて解説したいと思っています。

なおPID制御に関する日本語版Wikipediaの記事はこの記事執筆時点でいくつか曖昧で不適切な点がありそのせいで分かりにくいものになっています。もし見るなら英語版をお勧めします。ついでですが、英語版PID Controllerの冒頭にある図は制御理論で使われるブロック線図というものです。見た目が似ているかも知れませんが、フローチャートとは違います。本講座の意図はこの図に集約されているので、この図を使って次回説明する予定です。

| | コメント (0) | トラックバック (0)

2010年8月21日 (土)

Beauto ステップアップ講座5 前進成分と回転成分の足し算

前回まででON-OFF制御器を作成し、その挙動をパラメータによって調整できるようにしました。ラインを捉えることはできるものの、前に進んでいませんでした。今回から前に進むようにします。

前進しながら左右方向に旋回もするという動作をわかりやすく記述するため、今回からMtr_Run関数に左右の車輪の速度(モーターのduty比)を明示的に書くのではなく、「前進速度」と「回転速度」とに分けて指定するようにします。サンプルプログラムではrunという関数がこれを行います。


void run(int speed, int turn_speed)
{
	int d1 = speed - turn_speed; // (1)
int d2 = speed + turn_speed;

// 絶対値が127(100%)を超えないようにする (2)
// duty比が0のとき、Mtr_Runに渡す数は0x80にしてブレーキ動作にする
if(d1 > 127) d1 = 127;
else if(d1 < -127) d1 = -127;
else if(d1 == 0) d1 = 0x80; // brake   
(3)
if(d2 > 127) d2 = 127;
else if(d2 < -127) d2 = -127;
else if(d2 == 0) d2 = 0x80; // brake

Mtr_Run(-d1, d2, 0, 0);     // (4)
}

(1)の部分で左右の車輪の速度を計算します。

  • 左の車輪の速度=(前進速度)-(回転速度)
  • 右の車輪の速度=(前進速度)+(回転速度)

例えば前進速度80、回転速度30の時は左右の車輪の速度は上の計算式よりそれぞれ50、110となります。こうすると左に旋回しながら前進することになります。

(4)では実際にMtr_Run関数を呼び出してモーターの出力を変えます。左右の車輪でモーターは逆向きになるので1番目の引数は-d1として回転方向を逆、つまりd1が正のとき左モーターがロボットを前進させる方向に回るようにしています。このあたりはロボットの機械設計と電気配線に合わせて変更する必要があります。
※とはいえ実は旋回速度や前進速度に負の値を設定することでつじつまあわせができてしまいますが。
run(80, 30)とすると最終的に、Mtr_Run(-50, 110, 0, 0)を実行することになります。

(2)は、speed=100、turn_speed=100のような大きな値を指定した時にd1やd2の値が127を超えてしまう場合、127で頭打ちにするための処理です。マイナス方向も同様です。頭打ちにした場合、厳密には回転速度、前進速度ともに希望した値になりません。ゆっくり走る場合は影響しませんが、留意しておいてください。

(3)はMtr_Runの仕様上の特別処理です。第3回 の余談として書いたことですが、Mtr_Runの仕様では0はフリー、0x80はブレーキとなっているのでd1やd2の計算結果が0になったときは0x80に直します。

このrun関数を使うとON-OFF制御によるライントレース部分はこのように書けます。なお、speedという変数を追加してあります。旋回も直進も第1引数が共通になっていることに注目してください。

	if(line_pos < -deadband) {        // ラインが左側にあるとき
run(speed, turn_speed);       // 左回転(反時計回り)しながら進む
} else if(deadband < line_pos) {  // ラインが右側にあるとき
run(speed, -turn_speed);      // 右回転(時計回り)しながら進む
} else {                          // ラインが大体真ん中にあるとき
run(speed, 0);                // まっすぐ進む
}

サンプルプログラム

使い方は前回とほぼ同じです。パラメータ調整画面に前進速度speedを追加し、また上の説明を反映してline_trace関数の仕様を変更しました。第3引数に前進速度speedを指定するようになっています。

パラメータを変えて挙動の違いを見てください。Aギア(減速比12.7:1)、電源4.8Vの条件で試したところではspeedが30くらいまではうまく走ることができました。

ラインから外れた場合の処理は入っていません。コースからある程度以上外れると大抵は直進して暴走しますので気をつけてください。本来は線から外れたら停止するか、線に復帰するようにすべきです。本講座でも余裕があれば後からいくつかの方法を説明します。

次回はPID制御の考え方を取り入れたライントレースについて説明します。

| | コメント (0) | トラックバック (0)

Beauto ステップアップ講座4 対話形式パラメータ調整画面の作成

パラメータといえば数学では「媒介変数」というものですが、ロボットのプログラミングではロボットの挙動を間接的に決めるための数値、という意味合いです。たとえば前回の「許容するライン中央からのずれ幅」や「ロボットを回転させる速度」もパラメータといえます。

最適なパラメータはロボットの設計、更には部品の個体差、コースの状況によって違います。今回は対話形式でのパラメータ調整を行う方法を紹介します。

今回はロボットのプログラミングというよりは次回以降の準備ですので、先にプログラムを示した上で必要な部分を説明します。

使い方

ビルド方法は第1回を参考にしてください。

まず前回同様、センサー調整を行います。センサー全部を黒い線の上に載せてスペースキーを押し、続いてセンサー全部を白い床の上に移動させてスペースキーを押します。

するとパラメータ調整画面が表示されます。


1. deadband=0.200000
2. turn speed=127
>

これは変更するパラメータを選ぶ画面です。現在のパラメータの値を表示しています。deadbandは中央からどのくらいずれたら復帰しようとするか、turn speedは復帰動作で車体を回転させる速度です。たとえば線から外れた時の回転速度を変えたい場合は2[Enter]と操作します。すると

value=

と表示されますので変更後の値を入力してください。たとえば60[enter]と入力します。パラメータ一覧に戻ります。変更されたのを確認してください。

パラメータを選ぶ画面、「>」に対して[Enter]のみを入力すると調整モードを終了します。

調整モード終了後、スペースキーを押すとライン追従動作を開始します。ロボットをラインの上に置いて動作を確認してください。[Esc]キーを押すとライン追従動作を終了し、パラメータ調整画面に戻ります。

パラメータによってロボットの動きが変わるのを確認してください。

解説

ライン追従のプログラムはline_traceという名前の関数にまとめました。中のプログラムは前回とほとんど同じです。違いはturn_speed=回転速度とdeadband不感帯幅を引数として受け取り、それに応じた動作をする点です。例えば車体を回転させるようにモーターを駆動する部分は次のようになっています。

Mtr_Run(turn_speed, turn_speed, 0, 0); // 車体を左回転させる

パラメータ設定のメニューに相当する部分です。


while(1) {
int i;
char buf[80];
// 設定メニューを表示する
sprintf(buf, "1. deadband=%f\r\n2. turn speed=%d\r\n>",
        deadband, turn_speed);
SciStrTx(buf, strlen(buf));

// どの値を調整するか入力する
if(inputDecInt(&i) == 0) {
//何も入力せずEnterを押した場合
break;
} else {
//何かが選択された場合
SciStrTx("value=", 6);
switch(i) {
case 1:
inputDecFloat(&deadband);
break;
case 2:
inputDecInt(&turn_speed);
break;
}
}
}

シリアル通信から数値を入力できるようにするため、inputDecIntinputDecFloatという関数を用意しました。

  inputDecInt
  シリアル通信から整数を入力する
 
  引数:
  int *dst    結果を格納する変数のアドレス
 
  戻り値:
  正常に1つの整数を読み取れたら1、
  そうでないとき(たとえば何も入れずEnter)は0。

inputDecFloat(&deadband);のように使います。呼び出されると(シリアル通信の)入力待ちになります。Enterを押すと変数deadbandに入力した数が入ります。1文字も数字がなかった場合、例えばabc[Enter]と入力した場合や[Enter]のみを入力した場合はdeadbandの値は変わりません。

&はアドレス演算子というものです。詳しくは大抵のC言語の入門書の関数呼び出しおよびポインタに関する項に載っていますので割愛します。

| | コメント (0) | トラックバック (0)

2010年7月11日 (日)

Beauto ステップアップ講座3 ON-OFF制御器

注意

VS-WRC003に搭載されているモータードライバICは、使用条件によっては発熱、更には壊れる場合があります。異常動作や過度の発熱が見られた場合はロボットの電源を切ってください。本項目のサンプルプログラムはモーターの正逆転を頻繁に切り替えるため、注意が必要です。下のImpress Robot Watchのページも参考にしてください。

http://robot.watch.impress.co.jp/docs/column/vstone/20090623_295673.html

本講座(当ブログにて「Beauto講座」カテゴリーに分類されている記事)の文章およびサンプルプログラムを使用した結果のロボットの破損等について筆者は責任を負いませんのであらかじめご了承ください。

私の推測では、初期のBeauto Chaserに採用されていたモーターは通常のFA-130で1.5V用のため、4.8Vや6.0Vの電源で使用するとモータードライバの許容できる電流を超えて発熱や破壊を招くのではないかと思います。私の持っているBeauto Chaserではモーターの巻線抵抗が通常のFA-130より大きく、より高い電圧用のモーターに変更された模様です。4.8V電源で使用してきましたがドライバの発熱はほとんどありません。※このあたりのDCモーターの特性についてもまた改めて説明したく思っています。

Beauto Builderでのライントレースとの違い

本講座のプログラムの考え方は,Beauto Builder等を使ってフローチャートの形で動作手順を記述するものとは全く異なります.

  1. 動作時間の指定はしない
  2. 条件判断ではなく実数の計算による

2については次回以降説明します。まずは1について。

Beauto Builderではモーターへの指令はたとえば「直進を0.5秒」というように,動作の種類+時間を指定するようになっています.この例の場合0.5秒の間はセンサーが変化を検知しても関係なくモーターを回し続けます.

本講座で紹介する方法ではセンサーの情報とモーターの出力を常に連動させます。そのために十分短い時間ごとにセンサーを読み取る→計算する→モーター出力を変化させるという処理を繰り返します。次のような構造のプログラムで実現できます。

while(1) {
   センサーを読む
   センサーの値をもとに次のモーターへの指令を計算する
   モーターに指令する
   余った時間待機する
}

最後の「余った時間待機」はVS-WRCのサンプルプログラムで提供されているSync()関数で実現できます。Sync関数は先にInit関数(同サンプルプログラムで提供)で指定した制御周期の時間が経過するまで実行を止めます。繰り返しの周期を一定にするために必要です。周期を一定にすると便利な理由は次々回以降説明する予定です。

センサーを読む部分は前回説明しました。あとはセンサーの値からどのようにモーターへの指令を計算するかだけ決めれば完成します。一番簡単な方法として、右にずれていたら左に、左にずれていたら右に車体を回転させるようにしてみましょう。

使い方

ビルド方法は前回、前々回を参考にしてください。

センサー2個用となっています。4個使用する場合は前回のプログラムを元に、下の「解説」にあるソースリストを適切な箇所に書き足す等で対応してください。※センサーの値を直接使わず、前回示したline_posを使うため今回追加部分はこのままで対応可能です。

まず前回同様、センサー調整を行います。センサー全部を黒い線の上に載せてスペースキーを押し、続いてセンサー全部を白い床の上に移動させてスペースキーを押します。

ラインが進行方向になるようにロボットをライン上に置き、更にもう1回スペースキーを押すとライン追従動作を始めます。今回のプログラムはいわば「前進速度が0のライントレース」であるため放っておいても動きませんが、ロボットのセンサーを左右にずらすと中央に復帰するように回転しようとします。

動作中更に何かキーを押すと正規化センサー値とライン位置が表示されます(前回を参照)。

なお、センサーの取り付け方、モーターの配線方法によってはライン追従ではなくてラインから逃げるようになってしまいます。プログラムのMtr_Runの引数を逆にする等で対処してください。なお参考までに、サンプルプログラムは次の組み方をしたBeauto Chaserに合わせて作りました。

  • センサーは一番左のものをCN4(AN1)に接続
  • 右車輪モーターをCN1に、左車輪モーターをCN2に接続
  • ギアボックスの減速比はタイプA(注:BやDでは車輪の回転方向がAと逆になります)
  • ギアボックスはモーターと反対側を前方に向けて取り付け

解説

前回のプログラムのwhileループ内、ライン位置を計算する部分の直後にモータードライバへの指令を追加しています。

        line_pos = (sval[0] * (-1) + sval[1] * 1) / sum;

        if(line_pos < -0.2) {          // (1)ラインが左側にあるとき
            Mtr_Run(50, 50, 0, 0);     // (2)車体を左回転させる
        } else if(0.2 < line_pos) {    // (3)ラインが右側にあるとき
            Mtr_Run(-50, -50, 0, 0);   // (4)車体を右回転させる
        } else {                       // ラインが大体真ん中にあるとき
            Mtr_Run(0x80, 0x80, 0, 0); // (5)ブレーキをかける
        }
        // 中略
        Sync();
    }

3通りの場合分けです。せっかく実数でライン位置を計算したのにもったいないのですが、その点は次回以降順次改善していきます。

ラインが大体真ん中にあるときはブレーキを掛けます。ここの0x80を0に変更すると、ブレーキではなくてフリー状態になり、若干動作が変わります。興味のある方は試してみてください。効果が分かりにくい時はロボットを浮かせて車輪を空転させるとはっきりわかります。

(1)と(3)にある-0.2と0.2で、ラインが「大体真ん中」とは中央からどれだけずれた状態までを言うのかを決めています。これを-0.1と0.1等にするとより厳密に真ん中にあわせようとします。また(2)と(4)の50、-50はモーターをどれだけの速さで回そうとするかを決めます。絶対値を大きく(最大127)するとより力強く動きます。但しあまり大きくすると行き過ぎて左右にがたがた震えるようになる場合があります。(1)(3)の数値を小さくした場合も同様です。

このように数値を少し変えてみて動作を見る度にプログラムを書き込むのは大変です。次回はこのような試行錯誤をもう少し簡単に出来るようにします。

余談: DCモーターのPWM制御について簡単に補足

モーターのPWM制御はよく「スイッチのONとOFFを高速で繰り返す」と説明されますが、これは半分間違っています。確かにこの通りにする場合もありますが、Beauto Chaserのような自動制御ロボットのモーター制御では「モーターを電池に繋げるのと、モーターの端子同士をショートさせて電磁ブレーキを掛けるのを交互に高速で繰り返す」という方式をとる場面が多いのです。理由の一つは加速と減速を対称に行うためです。本当にスイッチをOFFしてモーターの端子に何も繋がない状態にしてしまうと、モーター自身は回転を止める力を出さないのです。機械的な摩擦のために徐々に減速はしますが、それでも電源ONで加速したときと比べてずっと長い時間が掛かります。

VS-WRC003のサンプルプログラムにあるMtr_Run関数で64(最大値である127の半分)を指定すると、半分の時間正転で、残り半分の時間ブレーキを掛けるという動作になります(実際は少しの時間フリーになりますが)。他の数値でもOFFの時間はブレーキを掛けています。そのため-1と1の間は0ではなく、ブレーキ動作として定義されている0x80の方が自然につながるのです。

なお、VS-WRC003LVではモータードライバ回路の設計上、フリーの動作ができません。Mtr_RunやMtr_Run_lv関数で0を指定するとブレーキがかかります。

| | コメント (0) | トラックバック (0)

2010年5月16日 (日)

Beauto ステップアップ講座2 ライン位置の計算

スムーズなライントレースのためには、ロボットがラインからどれだけずれているかを細かく得ることが必要です。本講座では2個以上のセンサーを横一列に並べて設置し、これらを使ってラインの位置を計算する方法について説明します。

後々便利なように、ラインの位置と各々のセンサーの位置はいずれも、センサー群の中心を原点として右を正とする1次元の座標で表します。ラインの位置といいましたが、これはいわば「センサー群のなす直線と、ラインの交点」の位置であって、ラインが右に向かって伸びているのか、左に向かって伸びているのかは無視します。

複数のセンサー値からライン位置を計算するための一つの簡易的方法として、正規化したセンサー値に比例した質量の仮想的な「おもり」が各センサーの位置に乗っていると考え、そのときの重心を考えます。例えば2個のセンサーが-1.0cm、1.0cmの位置にあり、それぞれ0.6、0.3という値が出ているとします。仮想的なおもりを載せた時の重心の位置は

2_line_pos_ex1_3

-0.33cmの位置です。この重心をラインの位置と見なします。実際には必ずしも一致しませんが、ある程度滑らかに変化すればよしとします。理由は次回以降説明します。

一般化して書くと次のようになります。高校物理の力学で出てくる重心の式です。なお分母が零になる場合も考えられますが、これはすべてのセンサーがラインから外れている状態で、別処理が必要なので本講座では扱いません。

2_line_pos_gen

N
センサーの個数
p_k
k番目センサーの位置
s_k
k番目センサーの正規化後の値
サンプルプログラム

センサー2個用と4個用を用意しました。2個の場合はAN1とAN2に、4個の場合はAN1から4に赤外線センサーを接続して使用します。赤外線センサーは一列に番号順に並べてロボットに取り付けます。間隔は隣り合う2個が同時にラインを検知できる程度まで狭くします。センサーの検知範囲は地面からの高さによって変化するので、結果を見ながら調節してください。

アンカー(リンクの文字列)を右クリック→ファイルに保存して使用してください。

使い方

まず前回同様、センサー調整を行います。センサー全部を黒い線の上に載せてスペースキーを押し、続いてセンサー全部を白い床の上に移動させてスペースキーを押します。この後何かキーを押すと、4個または2個の正規化センサー値と、上記の式により求めたライン位置が表示されます。

 0.13  0.92 : 0.76
0.15  0.97 : 0.73
0.23  0.92 : 0.60

なお、上の説明ではセンサーおよびラインの位置にセンチメートルという単位を使いましたが、実際のセンサーの物理的な位置は本講座のライントレースでは使いません。そのためセンサーの幅を正確に測定してプログラムに反映させる必要はありません。サンプルプログラムでは左右の端にあるセンサーの位置を-1.0および1.0としています。

値を見ながらロボットを回転させてライン位置が零になるようにしてみてください。ロボットを見ると、センサーの真ん中がラインの上に載っているはずです。次回はこの動作をロボットに自動で行わせます。

| | コメント (0) | トラックバック (0)

2010年5月 5日 (水)

Beautoステップアップ講座1 センサー値の標準化とキャリブレーション

Beauto Chaserでスムーズなライントレースをする方法について連載形式で説明していきます。対象はBeauto ChaserでC言語プログラミングを始めた人を主に想定します。目標は、直線では左右に振れずに走り、カーブは半径200mmくらいまでは止まらずスムーズに通過することとします。ただし直角コーナーやコースから外れたときの復帰処理などは扱わない予定です。プログラミングにはC言語、開発環境にはHEWとH8S,H8/300 Standard Toolchainを用い、センサーやモーターを駆動する関数はVstoneにより公開されているサンプルプログラムの関数を使って説明します。

おことわり

本講座は私が個人の趣味として書いている文書であり、ヴイストン株式会社とは関係ありません。本講座の内容、プログラム、画像についてはできるだけ良いものにするように努めていきますが、これらを利用したことによる損害については私は一切の責任を負いません。またリンク先の情報、サンプルプログラムは情報提供元による注意書きに同意した上で利用してください。

第一回目: センサー値の標準化とキャリブレーション

Beautoでライントレースをする場合、一般的には赤外線センサーを使って反射光の強さを読み取り、床の白黒を見分けます。反射光は床が白だと強く、黒だと弱くなるわけですが、同じ白でも次のような要因によって変化します。

  1. 周囲の明るさ
  2. 床の素材
  3. 床面に対するセンサーの取り付け角度
  4. センサーと床の距離
  5. 床の色の微妙な違い

走行中に床が上下したり床の汚れによって色が微妙に異なったりするのは対処が難しいですが、センサーの取り付け方を変更した場合の再調整=3と4、コース全体に共通する1と2にはある程度対処できるような仕組みを作ります。

まず走行前に2種類の床の色(ライン上のときと、ラインのない床面上のとき)に応じたセンサーの値を記録します。その上で実際の走行時、ラインの上にセンサーがあるかどうかの判定等をする際、直接A/D変換で得られた値を使わず次の式で計算される値yを使います。

Normalized_sensor_value

  • F=(ライン上のときのA/D変換結果)
  • B=(ラインのない床面上のときのA/D変換結果)
  • x=(現在得られたA/D変換結果)

yはライン上のとき1.0に近い値、そうでないときに0.0に近い値になります。

プログラムの例を示します。初期化、A/D変換、シリアル通信などはVstoneのサポートページで公開されているVS-WRCのサンプルプログラムで提供されている関数を利用することを想定しています。「無線コントローラVS-C1での操縦 」ソース一式のプロジェクトを利用し、メインのソース(GamePad_A.c)と入れ替えると簡単にビルドできます。

使い方

プログラムを書き込み、電源を入れなおしてプログラムを実行開始します。PCのターミナルソフトでCPUボードと通信できる状態にします(115200bps、8bit、パリティeven)。センサーが完全に線の上になるようにロボットを置いてPCのスペースキーを押します。ブザーが高い音で鳴り、ラインの色を記憶したことを知らせます。次にロボットを移動させてセンサーを床の地の色部分に置き、再度スペースキーを押します。ブザーが低い音で鳴ります。以上でセンサー調整モードが終了し、LED1がセンサーの状態を表示するようになります。また、何かキーを押すと現在のセンサー出力のA/D変換結果と正規化後の値が並べて表示されます。やり直すときはCPUボードの電源再投入、ターミナルソフトの再接続を行ってください。

なお実際の競技会ではPCを持ちこんで調整できない場合もありますので、押しボタンスイッチでセンサー調整の指示をできるようにするのが良いでしょう。私の場合は長押しでセンサーの値を記憶、短く押すとスタートというようにしています。YouTubeに載せたTributeの映像の最初の方でその様子が見られます。長押しの判定等はまた別に機会があれば説明します。

余談

上でセンサー調整と書いた操作はよくセンサーのキャリブレーションと呼ばれます。キャリブレーション(calibration)というのはセンサーの性質を表す何らかの数値(parameter)を実測によって求めることです。床ラインセンサーに限らず一般的な用語です。たとえばガラス管に水銀を入れた温度計を作ったとします。水銀の柱が温度の1次関数にしたがって伸び縮みすると仮定します。この温度計にはまだ目盛りをつけていないので、どこが何℃かわかりません。そのためまず温度が正確にわかる状態にして目盛りをつけます。たとえば氷水に漬けたときを0℃、沸騰している湯に漬けたときを100℃というふうに。この作業がキャリブレーションに相当します。この測定によって1℃あたりの目盛幅(比例係数)と0℃の位置(切片)がわかります。

| | コメント (0) | トラックバック (0)