UMEHOSHI ITA TOP PAGE    COMPUTER SHIEN LAB

androidのスマフォを介した遠隔操作

概要

次のイメージのように、モータ、ギアなどを取り付けました。

次にこのページで示したように部品を追加した[UMEHOSHI ITA]を取り付けます。

[UMEHOSHI ITA]とスマフォをUSBで接続します。(接続により電源が供給されてD1のダイオードが点灯します。
点灯しなければケーブルの接続が失敗していることとなります。)
そして、このページで紹介したように 「umehoshiアプリ」を起動して、USBを認識させます。

このページで紹介した[UMEHOSHI ITA]のプログラムを 応用して以下のようなプログラムで動作します。 (参考
Timer2の割り込みは、デフォルトで何もしない処理になっています。 それを置き換えて、一定時間(time2Count のカウントアップがstopCount以上になるまで )経過したら モータを停止する動作にしています。(コマンドを受信しなくてもこの時間で停止させています)

なお低電圧で比較的大きな電流を使うモータを使うと、一方のモータにエネルギーが偏って、一方のモータしか回らないケースがあるようです。 それに対応するようにCN6、CN6のモータ交互にONする方法ができるように  の部分を追加しています。
この部分でTimer2の割り込みでoneMCountもカウントアップしています。 oneMCountの値はoneCN6の負〜oneCN7の正の値の間で行われおり、 oneMCountが負であればCN6が有効(CN7が無効)、正であればCN7が有効(CN6が無効)として、モータを交互に印加する制御です。
このモータ交互制御は、oneCN6に設定を0にすることで無効にできます。

#include <xc.h> // app_pwm.c
#include "common.h"

#define AdrStart	0x80005000	// アプリの起動時の初期ルーチンのアドレス
#define AdrTimer2	0x80005B00	// 指定時間後にモータ停止のTimer2用アドレス
#define AdrForward	0x80005200	// モータ前進ルーチンのアドレス
#define AdrGoBack	0x80005300	// モータ後進ルーチンのアドレス
#define AdrRight	0x80005400	// モータ右回転ルーチンのアドレス
#define AdrLeft 	0x80005500	// モータ左回転ルーチンのアドレス
#define AdrUpLeft	0x80005600	// モータ左デューティ幅アップ
#define AdrDownLeft	0x80005700	// モータ左デューティ幅ダウン
#define AdrUpRight	0x80005800	// モータ右デューティ幅アップ
#define AdrDownRight	0x80005900	// モータ右デューティ幅ダウン
#define AdrStop		0x80005A00	// モータ停止

#define UPDAOWN 0x1000	// デューティ幅の変更で使う値(この値を加算又は減算)

// 左右のモータで、進行にバラツキがある場合、下記初期設定を調整して合わせる。
int cn6PWM = 0x0DFFF;	// 現在の左デューティ幅で、初期設定
int cn7PWM = 0x0FFFF;	// 現在の右デューティ幅で、初期設定

int time2Count = 0;//Timer2割り込みでカウントアップ(下記stopCountまでカウント)
int stopCount = 0x500;// time2CountがstopCount以上で、time2CountがをゼロにしてモータをOFF
// 上記設定値で、モータを動かしてから止めるまでの時間が決まります

// 下記は、モータを片方ずつ交互に使う時に0以外を指定する。(低圧高電流型モータで使う場合あり)
int oneMCount = 0;// oneCN6〜oneCN7の間で、oneCN6が負でTimer2でカウントアップ
int oneCN6 = -50;// CN6のONタイミングを負のTimer2でカウント数で指定
int oneCN7 = 50; // CN7のONタイミングをTimer2でカウント数で指定


void setCN6(int d);// 左用 CN6コネクタの制御 dの値 0停止, 1:正転, -1:逆転
void setCN7(int d);// 右用 CN7コネクタの制御 dの値 0停止, 1:正転, -1:逆転
void stop();// PWM を停止

__attribute__((address( AdrStart  ))) void start (void);
void start()
{
	PORTBCLR = 0b0110000000001100;//モータ関連ポート(14,13,3,2)をゼロにする

	// 初期化ルーチン(リセット時の処理)を設定
	( (uint32_t *)_HANDLES)[_IDX_INIT_SUB_FUNC] =  (uint32_t ) AdrStart;
	__asm__ ("NOP");

	IEC0CLR = 0x00000200;//T2IE Timer2 Enable(割込みを不可)");
	( (uint32_t *)_HANDLES)[_IDX_TIMER_2_FUNC] =  (uint32_t ) AdrTimer2;//割り込み処理の置き換え
	PR2=0x8FFF;// 上記割り込み処理の周期設定
	IEC0SET = 0x00000200;//T2IE Timer2 Enable(割込み許可)");
	
	_set_pwd_mode(1); // PWM モードへ変更
	T2CONbits.ON = 1; //Timer2の機能を有効

	time2Count =0;
	_RB15 = 0;
}

// タイマーで(stopCount 値に達するまで)の時間ごとに、モータを停止する。
// (モータがオンで、移動し続けないようにする考慮で、無くてもよい処理?)
__attribute__((address( AdrTimer2))) void timer2(void);
void timer2()
{
	IFS0CLR = 0x00000200; // Clear the timer interrupt status flag
	if( ++time2Count >= stopCount ){
		stop();// PWM パルス幅を0
		_RB15 = 0; // LED1消灯
	}
	// CN6,CN7のモータを交互に使う
	if(oneCN6 < 0 && oneMCount++ < 0){
		OC5CONbits.ON=OC1CONbits.ON=1; // PWM CN6有効
		OC3CONbits.ON=OC4CONbits.ON=0; // PWM CN7無効

	} else if(oneCN6 < 0 && oneCN7 > 0){
		OC5CONbits.ON=OC1CONbits.ON=0; // PWM CN6無効
		OC3CONbits.ON=OC4CONbits.ON=1; // PWM CN7有効
		if( oneMCount > oneCN7){
			oneMCount = oneCN6;
		}
	}
}

// モータを停止する。
__attribute__((address( AdrStop))) void stop(void);
void stop()
{
	//time2Count = 0;
	OC5RS = OC1RS = OC4RS = OC3RS = 0;// モータすべてをOFF
}


// モータ前進ルーチン
__attribute__((address( AdrForward  ))) void forward(void);
void forward()
{
	time2Count = 0;
	setCN6( 1 );// 左正転
	setCN7( 1 );// 右正転
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// モータ後進ルーチン
__attribute__((address( AdrGoBack ))) void goback(void);
void goback()
{
	time2Count = 0;
	setCN6( -1 );// 左逆転
	setCN7( -1 );// 右逆転
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// モータ右回転ルーチン
__attribute__((address( AdrRight ))) void right(void);
void right()
{
	time2Count = 0;
	setCN6( 1 );// 左正転
	setCN7( -1 );// 右逆転
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// モータ左回転ルーチン
__attribute__((address( AdrLeft ))) void left(void);
void left()
{
	time2Count = 0;
	setCN6( -1 );// 左逆転
	setCN7( 1 );// 右正転
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// モータ左デューティ幅アップルーチン
__attribute__((address( AdrUpLeft ))) void upleft(void);
void upleft()
{
	_send_hex_low( cn6PWM );
	if( cn6PWM +UPDAOWN <= 0x0ffff){
		cn6PWM += UPDAOWN ;
		_send_string(" Left UP\r\n");
	} else {
		_send_string(" Left FULL\r\n");
	}
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}


// モータ左デューティ幅ダウンルーチン
__attribute__((address( AdrDownLeft ))) void downleft(void);
void downleft()
{
	_send_hex_low( cn6PWM );
	if( cn6PWM - UPDAOWN >= 0){
		cn6PWM -= UPDAOWN ;
		_send_string(" Left DOWN\r\n");
	} else {
		_send_string(" Left Minimum\r\n");
	}
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

//モータ右デューティ幅アップ
__attribute__((address( AdrUpRight ))) void upright(void);
void upright()
{
	_send_hex_low( cn7PWM );
	if( cn7PWM +UPDAOWN <= 0x0ffff){
		cn7PWM += UPDAOWN ;
		_send_string(" Right UP\r\n");
	} else {
		_send_string(" Right FULL\r\n");
	}
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// モータ右デューティ幅ダウン
__attribute__((address( AdrDownRight ))) void downright(void);
void downright()
{
	_send_hex_low( cn7PWM );
	if( cn7PWM -UPDAOWN >= 0){
		cn7PWM -= UPDAOWN ;
		_send_string(" Right DOWN\r\n");
	} else {
		_send_string("Right Minimum\r\n");
	}
	_RB15 = ! _RB15;//確認用のLED1点灯反転
}

// CN6(左側) コネクタの制御 dの値 0停止, 1:正転, -1:逆転
void setCN6( int d){
	time2Count=0;
	OC5RS = 0x0;	// CN6[1-2]制御(RB2)
	OC1RS = 0x0;	// CN6[3-4]制御(RB3)
	if(d==1){
		OC5RS = cn6PWM;	// CN6[1-2]制御(RB2)
		OC1RS = 0x0;	// CN6[3-4]制御(RB3)
	} else if(d==-1){
		OC5RS = 0x0;	// CN6[1-2]制御(RB2)
		OC1RS = cn6PWM;	// CN6[3-4]制御(RB3)
	}
}

// CN7(右側) コネクタの制御 dの値 0停止, 1:正転, -1:逆転
void setCN7( int d){
	time2Count=0;
	OC4RS = 0x0;	// CN7[3-4]制御(RB13)
	OC3RS = 0x0;	// CN7[1-2]制御(RB14)
	if(d==1){
		OC4RS = cn7PWM;	// CN7[3-4]制御(RB13)
		OC3RS = 0x0;	// CN7[1-2]制御(RB14)
	} else if(d==-1){
		OC4RS = 0x0;	// CN7[3-4]制御(RB13)
		OC3RS = cn7PWM;	// CN7[1-2]制御(RB14)
	}
}

上記のcn6PWMとcn7PWMのそれぞれが、CN6とCN7のデューティ幅で、初期設定が異なっていますが、 これは、モータやギアの違いを吸収させるために、存在しています。作成したマシンによって左右の違いがある場合、 この設定で変更できるようにしてみました。
別途に、それぞれのPWMのデューティ幅を増減するメソッドを用意してみました。

下記はビルドして[UMEHOSHI ITA]とUSBで繋いだ後、プログラムを転送して0x80005000番地のstart関数を[Excute]ボタンで実行し、
次に[Execte Address]の設定を0x80005200番地に変更してから[Excute]ボタンクリックしているイメージです。(これでforward関数が実行します)
(なお、下記ではExcuteボタン左のコンボボックスに#defineで定義される各関数のエントリーポイントのアドレスが並んでいます。
 しかし実際にはこのような並びではありません。一度実行したアドレスだけが並びます。)

モータが繋がっていれば、 上記実行により2つのモータが前進の回転を一定時間回転して止まるはずです。
一定時間とは、=1/(40e6)*(PR2+1)*stopCount=1/(40e6)*(0x8fff+1)*0x500=約1.2秒です。


次に、ここで示したように、「umehoshi」ツールが受け取る形式(.umh)にします。
(.umh)のファイル形態にすることで、次のように「umehoshi」ツールを介して[UMEHOSHI ITA]のWifi環境で遠隔操作ができるようになります。

このWifiによりTCPで、(.umh)のファイル転送の遠隔操作をするためには、この拡張子の先頭行にボタンの表示文字列の1行を書いて、 次行に送信したい命令を列挙するだけです。
例えば、「PWM_LOAD」の表示文字列の1行を書いて、上記でビルドしたコード(app.pwm.c.hex)の内容をコピー貼り付けし、 最後に「R00800050000061」の文字列を追加した次の「uPwmLoad.umh」を作ります。 この正確なコードは このページに示します。

PWM_LOAD
S048000800000FFDF000083
  ・・・ここは省略してます・・・
S108000538C001480008008000000000000000000000024
R00800050000061

これは「umehoshi」ツールにおいて、「PWM_LOAD」ボタン操作でプログラムをロードしてそのstart()関数を実行させる内容です。
このコード内の0x80005200番地にあるforward関数を実行する時に使うuGoForward.umhを示します。(前進のボタン用です)

Forward
R0080005200005F

上記のR0080005200005Fは、「UME専用Hexコマンド」の文字列で、 0x80005200番地の関数を実行させるコードです。
このコードは、次のように「umehoshiEdit」ツールで、[communication]メニューの[Command exec]を選んで、 Execute Addressの箇所を0x80005200の表現に編集して、[Excute]ボタンをクリックすると、「message」タグに現れるので、 それをコピー貼り付けするとよいでしょう。

同様に作った、後進、右回転、左回転、・・・の各コードのファイルもこのページに示します。
このようなファイルを用意すれば、ここで示したように 「umehoshiEdit」ツールから「umehoshiアプリ」へ、
または 「umehoshiアプリ」から他の「umehoshiアプリ」へTCP通信へファイル転送することで遠隔操作ができるようになります。

下記で動かしているyoutube動画リンクです