2.2足歩行ロボットの開発2
TOP

3.RCカーの開発

 ここではここまで学んできたことを踏まえてRCXを2個使い、RCカーを作ってみましょう。

1.RCカーの仕様

今回作成するRCカーは以下のようなものとします。

2.ハードウェアの作成


RCカーの設計図

3.プログラムの解説

 プログラムはRCカー本体のプログラムとRCカーを操作するプロポの二つが必要となります。それではまずプロポのプログラムから見ていきましょう。

3-1.プロポプログラムの解説

ここでは作成ファイル名をrc_propo.cとします。
作成したプログラムrc_propo.c
#include<conio.h>
#include<lnp.h>
#include<dsensor.h>

int main(int argc, char **argv) {
	char sendmsg;
	ds_active(&SENSOR_3);
	ds_rotation_on(&SENSOR_3);
	ds_rotation_set(&SENSOR_3,0);

	cputs("prop");
	while(1){
		if(SENSOR_1<0xf000){ // left
			sendmsg='d';
		}
		else if(SENSOR_2<0xf000){ // right
			sendmsg='e';
		}
		else{
			sendmsg='f';
		}
		send_msg(sendmsg);
		if(ROTATION_3>=7){ // front
			sendmsg='a';
		}
		else if(ROTATION_3<=-7){ // back
			sendmsg='b';
		}
		else{
			sendmsg='c';
		}
		send_msg(sendmsg);
	}
	return 0;
}
 このプログラムはプロポ側のRCXに接続されているセンサー類(タッチセンサー×2、ローテーションセンサー×1)の状態に対応して、RCXの赤外線通信を用いて1文字を送信するという動作をします。送信する文字は全部で6文字あり、それぞれ以下の動作と対応しています。
文字 RCカーの動作
前進
後退
ドライブモーターストップ
ステアリング左
ステアリング右
ステアリング中央
また、ローテーションセンサーの値は5.ローテーションセンサーの使用で作成した"rotation.c"を用いて値を測定し、今回は判定値を±7としてそれ以上(以下)となった場合に文字を出力するようになっています。

3-2.RCカー本体プログラムの解説

ここでは作成ファイル名をrc_car.cとします。
作成したプログラムrc_car.c
このプログラムは少々長いので各関数ごとに解説していきましょう。

3-2-1.メイン関数

int main(int argc, char *argv[]) {
	cputs("on");
	sem_init(&t_motor,0,1);
	t_stop=execi(&stop,0,NULL,100,DEFAULT_STACK_SIZE); // make stop task
	t_st_stop=execi(&st_stop,0,NULL,90,DEFAULT_STACK_SIZE); // make steering stop task
	t_tson=execi(&tson,0,NULL,50,DEFAULT_STACK_SIZE); // make touch task
	t_drive=execi(&drive,0,NULL,10,DEFAULT_STACK_SIZE); // make drive task
	t_steering=execi(&steering,0,NULL,10,DEFAULT_STACK_SIZE); // make steering task
	return 0;
}
 この関数では最初にセマフォの設定をし、各タスクを呼び出しています。セマフォについては前新後退用モーターのみの1つだけ用意してあります。これはドライブ関数とタッチセンサー関数の二つのタスクでこのモーターを使用するためです。各タスクの優先度は以下の通り。
関数名 優先度
stop(ストップ関数) 100
st_stop(ステアリングストップ関数) 90
tson(タッチセンサー関数) 50
drive(ドライブ関数) 10
steering(ステアリング関数) 0

3-2-2.ドライブ関数

iint drive(){ // drive function
	char getmsg;
	while(1){
		wait_event(&rt_dr_wakeup,0); //wait for lnp_rcx_message
		getmsg=lnp_rcx_message;
		clear_msg();
		sem_wait(&t_motor);
		if(getmsg=='a'){
			motor_c_speed(MAX_SPEED);
			motor_c_dir(rev);
		}
		else if(getmsg=='b'){
			motor_c_speed(MAX_SPEED);
			motor_c_dir(fwd);
		}
		else{
			motor_c_dir(off);
		}
		sem_post(&t_motor);
	}
	return 0;
}

wakeup_t rt_dr_wakeup(wakeup_t data){ // lnp check for drive func
	return lnp_rcx_message=='a' || lnp_rcx_message=='b' || lnp_rcx_message=='c';
}
 この関数はプロポからの信号のうち『a,b,c』のどれかを受け取った時にウェイクアップ関数rt_dr_wakeup()からウェイクアップして、各文字に対応した『前進、後退、ストップ』の動作をします。なお、セマフォにより前進後退用モーターを占有するようにしてあります。

3-2-3.ステアリング関数

int steering(){ // steering function
	char getmsg;
	ds_active(&SENSOR_2);
	ds_rotation_on(&SENSOR_2);
	ds_rotation_set(&SENSOR_2,0);
	motor_a_speed(MAX_SPEED);

	while(1){
		wait_event(&rt_st_wakeup,0); //wait for lnp_rcx_message
		getmsg=lnp_rcx_message;
		clear_msg();
		if(getmsg=='d'){
			if(ROTATION_2<65){
				motor_a_dir(fwd);
				msleep(10);
			}
			else
				motor_a_dir(brake);
		}
		else if(getmsg=='e'){
			if(ROTATION_2>-65){
				motor_a_dir(rev);
				msleep(10);
			}
			else
				motor_a_dir(brake);			
		}
		else if(ROTATION_2<-2){
			while(ROTATION_2<=-2){
				motor_a_speed(MAX_SPEED/8);
				motor_a_dir(fwd);
			}
			motor_a_dir(brake);
		}
		else if(ROTATION_2>2){
			while(ROTATION_2>=2){
				motor_a_speed(MAX_SPEED/8);
				motor_a_dir(rev);
			}
			motor_a_dir(brake);
		}
	}
	return 0;
}

wakeup_t rt_st_wakeup(wakeup_t data){ // lnp check for steering func
	return lnp_rcx_message=='d' || lnp_rcx_message=='e' || lnp_rcx_message=='f';
}
 この関数ではプロポからの信号のうち『d,e,f』のどれかを受け取った時にウェイクアップ関数rt_st_wakeup()からウェイクアップして、各文字に対応した『左、右、中央に戻る』の動作をします。特に受け取った文字が'f'であったときは、ローテーションセンサーの値が±2以内に収まるようにステアリング用モーターを回転させるようになっています。ただし、このままでは信号'd'または'e'が入り続けるとステアリングが回りすぎてしまいます。そこでステアリング角を限界点で維持するようなタスクを別に用意しました。それがステアリングストップ関数です。

3-2-4.タッチセンサー関数

int tson(){ // touch sensor function
	motor_c_speed(MAX_SPEED);
	while(1){
		wait_event(&tson_wakeup,0);
		sem_wait(&t_motor);
		if(SENSOR_1<0xf000){
			motor_c_dir(rev);
			msleep(500);
			motor_c_dir(brake);
		}
		else if(SENSOR_3<0xf000){
			motor_c_dir(fwd);
			msleep(500);
			motor_c_dir(brake);
		}
		sem_post(&t_motor);
	}
	return 0;
}

wakeup_t tson_wakeup(wakeup_t data){
	return SENSOR_1<0xf000 || SENSOR_3<0xf000;
}
 この関数は前後のタッチセンサーどちらかが反応した時にウェイクアップ関数tson_wakeup()からウェイクアップして、今きた方向とは逆に500msecだけ進むような動作をします。なお、セマフォにより前進後退用モーターを占有するようにしてあります。また、当たり前ですが、同じく前後用モーターを使用するドライブ関数と比較するとこちらのほうが優先度が高く設定してあり、こちらのタスクのほうが優先されます。

3-2-5.ステアリングストップ関数

int st_stop(){ // steering stop function
	while(1){
		wait_event(&rt_wakeup,0);
		motor_a_dir(brake);
		msleep(50);
	}
	return 0;
}

wakeup_t rt_wakeup(wakeup_t data){
	return ROTATION_2>=65 || ROTATION_2<=-65;
}
 ステアリング関数だけではステアリング角が切れすぎてしまうので、それを防ぐために限界角でとどまるようにするのがこの関数です。ローテーションセンサーの±65という値はステアリング角の限界値です。ローテーションセンサーの値が±65を超えた時にウェイクアップ関数rt_wakeup()からウェイクアップして、ステアリング用モーターを止め、50msec秒sleepするという動作をします。無論、ステアリング関数よりこの関数のほうが優先度は高めに設定してあります。

3-2-6.ストップ関数

int stop(){ // rcx stop function
	int stopchar;
	stopchar=getchar();
	if(stopchar==KEY_RUN){
		cputs("stop");
		killall(100);
	}
	return 0;
}
 最後にこの関数ですが、これはプログラム自体をストップさせるという動作をします。これは2.2足歩行ロボットの開発2で用いたものと同様です。

4.プログラムの実行

 ではこれらのプログラムをコンパイル、ダウンロードしてください。それではいよいよ動かしてみましょう。うまく動くでしょうか?
動いているムービーを乗せておきます。参考にして下さい。

撮影したムービーrc_car.avi(AVI形式)

また、欠点として赤外線の通信可能な範囲がかなり狭いこと、ごくまれにプロポ側から赤外線が発信していないことがあります。赤外線が発信しているかどうか、また届いているかどうかは、RCカー本体のRCX上LCDディスプレイを見て、確認してください。

5.課題

作成したRCカープログラムを改良して、速度を低速と高速の2段階調節できるようにしてみましょう。

プログラム例
RCカー本体用rc_car2.c
プロポ用rc_propo2.c

5.まとめ

 この章ではRCカーの作成について学習しました。ここではbrickOSの機能をフル活用しています。判らないことがあったら前に戻って見直してみてください。また、brickOSを用いてこんなこともできることを知ってください。
2.2足歩行ロボットの開発
TOP