マイコンカーラリーのアナログセンサ

マイコンカーラリーのアナログセンサについて

マイコンカーラリーのラインセンサ(写真で前方に伸びたアームの先についているセンサ)はコース中央の白線をトレースするためのセンサで、デジタルセンサとアナログセンサが使われています。

M-S199:アナログセンサー基板 TypeSとして提供されているセンサには5つのデジタルセンサと白線を挟む位置にある2つのアナログセンサがあります。

取り付け拡大部分(SCITECS_MCR日記)より

LEDとペアで取り付けられているのがデジタルセンサでセンサ取り付けネジの斜め前部分にあるのがアナログセンサとして使う反射型フォトインタラプタ(下図)です。


デジタルセンサはマーカー検出や誤動作防止に使い、アナログセンサで姿勢制御をおこなうことでスムーズな高速走行が可能になります。

アナログセンサの信号をADコンバータの数値で見てみる

アナログセンサの信号はR8CでAD変換して姿勢制御に使います
次のグラフはコースと同じ白線パターン上でアナログセンサを振ってみた時のAD値をグラフにしたものです。
縦軸はAD変換の値で0~1023、横軸は時間でmS単位です。

アナログセンサ回路は次のようになっています。

フォトトランジスタは光の反射が多いほど多く電流を流し出力電圧が下がるため、コースの黒い部分で電圧が高く、白線の部分で電圧が低くなります。

グラフは左右のアナログセンサ(a0,a1)とその差分(ad1-ad0)の値を表示しています。
色の変わり目でスムーズに変化していることが判りますad0とad1の最低値、最高値が違うのは素子特性のバラつきによるものです。

制御プログラムを効率よく開発するための秘訣

制御プログラムで難しいのは上のグラフにあるような素子特性のバラつきや機構の特性によって生じるセンサ信号や挙動の変化をいかにうまく補正するかということです。
ロボットを走らることを繰り返してパラメータを調整する前に、各センサがどのような特性を持つかを把握しておけば問題の解決がずっと容易になります。

上のグラフはCPUボードをUSBでPCに接続してリアルタイムデータをグラフ表示したものです、センサやステアリング部分の挙動を調べるときにはリアルタイムデータを観察する方がプログラムの修正が手早く出来るので便利です。

そして、実際にコースを走行する時のデータはmicroSDに記録して後から解析するという使い分けをすることで開発をより効率的におこなうことが出来ます。

 

 

(続)マイコンカーラリーで1ms毎の高速データログを目指す

試作マイコンカーラリーモータドライブ基板

下のデータを記録する例で実行時間を調べてみました。
このデータは62文字でJMCR事務局が提供しているプログラムライブラリを使ったMicroSD書き込みだと10mSで記録出来る限界のサイズです。

       /* microSD記録処理 */
        if( msdFlag == 1 ) {
            msdPrintf( "%4d,%3d,=\"%4b\",%c,%5d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\r\n",
				line_no,			// 行番号
                pattern,            // パターン番号
                sensor_inp(),       // デジタルセンサ(4bit)
                center_inp() + '0', // デジタルセンサ(中心)
                getAnalogSensor(),  // アナログセンサ
                getServoAngle(),    // ボリューム(ステアリング角度)
				ServoPwm_Buff,		// サーボPWM
                iEncoder,           // ロータリエンコーダ
                motorLF,            // 左前モータ
                motorRF,            // 右前モータ
                motorLR,            // 左後モータ
                motorRR,            // 右後モータ
				ad4			// 坂センサー
            );
            if( ++line_no >= 10000 ) line_no = 0;
        }

まずprintf()を使った書き方、msdPrintfをprintfに置き換えただけです。

      printf( "%4d,%3d,=\"%4b\",%c,%5d,%4d,%4d,%4d,%4d,%4d,%4d,%4d\r\n",
				line_no,			// 行番号
                pattern,            // パターン番号
                sensor_inp(),       // デジタルセンサ(4bit)
                center_inp() + '0', // デジタルセンサ(中心)
                getAnalogSensor(),  // アナログセンサ
                getServoAngle(),    // ボリューム(ステアリング角度)
				ServoPwm_Buff,		// サーボPWM
                iEncoder,           // ロータリエンコーダ
                motorLF,            // 左前モータ
                motorRF,            // 右前モータ
                motorLR,            // 左後モータ
                motorRR,            // 右後モータ
				ad4			// 坂センサー
        );

);

(実測結果)
実行時間 2mS、文字化けでデータが表示されませんでした。
メモリに余裕が無いためかも知れません。

次の例は、データごとに数値→文字列変換関数を使った書き方です
書き方は面倒ですが時間は節約できます。

	uart0_putint(line_no);			uart0_putch(',');		// 行番号
        uart0_putint(pattern);          uart0_putch(',');  // パターン番号
        uart0_puthxb(sensor_inp());     uart0_putch(',');  // デジタルセンサ(4bit)
        uart0_putch(center_inp() + (int)'0'); uart0_putch(','); // デジタルセンサ(中心)
        uart0_putint(getAnalogSensor()); uart0_putch(','); // アナログセンサ
        uart0_putint(getServoAngle());  uart0_putch(',');    // ボリューム(ステアリング角度)
	uart0_putint(ServoPwm_Buff); 	uart0_putch(',');	// サーボPWM
        uart0_putint(iEncoder); 		uart0_putch(',');       // ロータリエンコーダ
        uart0_putint(motorLF);          uart0_putch(',');   // 左前モータ
        uart0_putint(motorRF);          uart0_putch(',');   // 右前モータ
        uart0_putint(motorLR);          uart0_putch(',');   // 左後モータ
        uart0_putint(motorRR);          uart0_putch(',');   // 右後モータ
	uart0_putint(ad4);	// 坂センサー	
	uart0_putcrlf(); 	

(実測結果)
約0.4mSでした、メインループの中で1mS毎のデータを出力するのにも使えそうです。

 

次が出力に使ったプログラムです。

/*======================================*/
/* インクルード                         */
/*======================================*/
#include    
#include    "sfr_r838a.h"               /* R8C/38A SFRの定義ファイル    */
#include    "uart0.h"              /* printf関連処理               */


/*======================================*/
/* シンボル定義                         */
/*======================================*/
#define         TX_BUF_SIZE  128 //64      /* 送信バッファサイズ           */
#define    USE_PRINTF

#ifdef USE_PRINTF
/* printf,scanf関係 */
volatile FILE           _iob[4];  // ダミー変数
#endif

/*======================================*/
/* グローバル変数の宣言                 */
/*======================================*/
/* 送信バッファ */
static volatile char    uart0_tx_buf[TX_BUF_SIZE];
static volatile char    *tx_wp = uart0_tx_buf;
static volatile int     tx_ct = 0;

/**********************************************************************************/
/*		RAM
/**********************************************************************************/

#pragma ADDRESS	dtc_fact_s0t	02C0BH			/* DTC vector address of UART0 transfer interruption */
#pragma ADDRESS	dtc_fact_s0r	02C0AH			/* DTC vector address of UART0 receive interruption */

#pragma ADDRESS	dtccr_dtcd0		02C40H			/* Address of DTC control register in dtcd0 */
#pragma ADDRESS	dtbls_dtcd0		02C41H			/* Address of DTC block size register in dtcd0 */
#pragma ADDRESS	dtcct_dtcd0		02C42H			/* Address of DTC transfer count register in dtcd0 */
#pragma ADDRESS	dtrld_dtcd0		02C43H			/* Address of DTC transfer count reload register in dtcd0 */
#pragma ADDRESS	dtsar_dtcd0		02C44H			/* Address of DTC source address register in dtcd0 */
#pragma ADDRESS	dtdar_dtcd0		02C46H			/* Address of DTC destination address register in dtcd0 */

#pragma ADDRESS	dtccr_dtcd1		02C48H			/* Address of DTC control register in dtcd1 */
#pragma ADDRESS	dtbls_dtcd1		02C49H			/* Address of DTC block size register in dtcd1 */
#pragma ADDRESS	dtcct_dtcd1		02C4AH			/* Address of DTC transfer count register in dtcd1 */
#pragma ADDRESS	dtrld_dtcd1		02C4BH			/* Address of DTC transfer count reload register in dtcd1 */
#pragma ADDRESS	dtsar_dtcd1		02C4CH			/* Address of DTC source address register in dtcd1 */
#pragma ADDRESS	dtdar_dtcd1		02C4EH			/* Address of DTC destination address register in dtcd1 */

unsigned char dtc_fact_s0t;						/* Control Data No. of UART0 transmit interruption */
unsigned char dtc_fact_s0r;						/* Control Data No. of UART0 receive interruption */

unsigned char dtccr_dtcd0;						/* DTC control register in dtcd0 */
unsigned char dtbls_dtcd0;						/* DTC block size register in dtcd0 */
unsigned char dtcct_dtcd0;						/* DTC transfer count register in dtcd0 */
unsigned char dtrld_dtcd0;						/* DTC transfer count reload register in dtcd0 */
unsigned short dtsar_dtcd0;						/* DTC source address register in dtcd0 */
unsigned short dtdar_dtcd0;						/* DTC destination address register in dtcd0 */

unsigned char dtccr_dtcd1;						/* DTC control register in dtcd1 */
unsigned char dtbls_dtcd1;						/* DTC block size register in dtcd1 */
unsigned char dtcct_dtcd1;						/* DTC transfer count register in dtcd1 */
unsigned char dtrld_dtcd1;						/* DTC transfer count reload register in dtcd1 */
unsigned short dtsar_dtcd1;						/* DTC source address register in dtcd1 */
unsigned short dtdar_dtcd1;						/* DTC destination address register in dtcd1 */

#ifdef USE_PRINTF
/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれるダミー関数        */
/************************************************************************/
int _sget( void ) {    return 0; }

/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれるダミー関数       */
/************************************************************************/
int _sput( int put_data ) {   return put_data; }

/************************************************************************/
/* fgetc(ストリームから1文字入力する)から呼ばれる1文字出力関数         */
/* 引数  出力文字                                                      */
/* 戻り値 正常:1 以上:EOF                                               */
/************************************************************************/
int _pput( int put_data ) {  return put_data;  }
#endif




/************************************************************************/
/* UART0の初期化、及びprintf関係をUART0に割り当て                       */
/* 引数  通信速度                                                      */
/************************************************************************/
void init_uart0( long bps )
{
 	int brg;

#ifdef USE_PRINTF
    stdin->_cnt = stdout->_cnt = stdaux->_cnt = stdprn->_cnt = 0;
    stdin->_flag = _IOREAD;
    stdout->_flag = _IOWRT;
    stdaux->_flag = _IORW;
    stdprn->_flag = _IOWRT;

    stdin->_mod = _TEXT;
    stdout->_mod = _TEXT;
    stdaux->_mod = _BIN;
    stdprn->_mod = _TEXT;

    stdin->_func_in = NULL;
    stdout->_func_in = NULL;
    stdaux->_func_in = NULL;
    stdprn->_func_in = NULL;

    stdin->_func_out = NULL;
    stdout->_func_out = write;
    stdaux->_func_out = write;
    stdprn->_func_out = NULL;
#endif

    brg = (1250000L*10 / bps+5)/10  - 1; /* 四捨五入処理をしている */	
    /* UART0の設定 */
    u0sr = 0x05;                    /* P14=TXD0,P15=RXD0に設定      */
    u0c0 = 0x00;                    /* カウントソース=20MHz         */
    u0c1 = 0x05;                    /* 送信、受信許可                */
    u0brg = brg;                    /* 通信速度 = brg               */
    u0mr = 0x05;                    /* UART0 データ長8bit 1ストップビット  */
	s0tic = 0x00;					/* UART0 transmit interrupt disabled */

    /* Setting DTCD0 registers */
	dtc_fact_s0t = 0;							/* Setting Control Data No. of UART0 transfer interruption to "No. 0" */
	dtccr_dtcd0 = 0x04;							/* Setting DTC control register in DTCD0 at UART0 transfer interruption */
												/* Normal mode is selected */
												/* Source address is incremented */
												/* Destination address is fixed */
												/* Chain transfers is disabled */
	dtbls_dtcd0 = 1;							/* Setting DTC block size register in DTCD0 */
												/* One-byte is set */
	dtcct_dtcd0 = TX_BUF_SIZE-1;			    /* Setting DTC transfer count register in DTCD0 */
												/* Transmit or receive data size minus one is set to transfer */
	dtrld_dtcd0 = 0;							/* Setting DTC transfer count reload register in DTCD0 */
												/* Not used in normal mode */
	dtsar_dtcd0 = (unsigned short )&uart0_tx_buf[1];
												/* Setting DTC source address register in DTCD0 */
												/* DTC source address is set to the address of "uart0_tx_data[1]"*/
	dtdar_dtcd0 = (unsigned short)&u0tbl;		/* Setting DTC destination register in DTCD0 */
												/* DTC destination address is set to the address of "u0tbl" register */

 	/* Setting DTC activation enable registers */
	dtcen0 = 0x00;								/* Activation disabled */
	dtcen1 = 0x00;								/* Activation disabled */
	dtcen2 = 0x00;								/* Activation disabled */
	dtcen3 = 0x00;								/* Activation disabled */
	dtcen4 = 0x00;								/* Activation disabled */
	dtcen5 = 0x00;								/* Activation disabled */
	dtcen6 = 0x00;								/* Activation disabled */
	dtctl = 0x00;								/* Setting DTC activation control register */
												/* Non-maskable interrupts not generated is selected */
}

/************************************************************************/
/* 1文字ダイレクト出力                                                           */
/* writeとの干渉に注意                                                  */
/************************************************************************/
void uart0_conout( char c )
{
    while( ti_u0c1 == 0 ) ;
    u0tbl = c;
}


/**********************************************************************
* DTCでuart0送信 printfで呼び出される関数名を使用                                             *
************************************************************************/
int write( int c )
{
//	uart0_putch((char)c);
//    return 1;
// p4_5 = 1;
    if( ((char)c == '\n')||( TX_BUF_SIZE-1 <= tx_ct ) ){
		*tx_wp++ = '\n';
		tx_ct++;
    	if(dtcen14 == 1){	/* An activation disabled in UART0 transmission interrupt ? */
    	    tx_wp = &uart0_tx_buf[0];
    	    tx_ct = 0;
		    return 0;
	    }
 	    dtcct_dtcd0 = tx_ct-1;	            /* Setting DTC transfer count register in DTCD0 */
											/* Transmit or receive data size minus one is set to transfer */
	    dtsar_dtcd0 = (unsigned short)&uart0_tx_buf[1];
											/* Setting DTC source address register in DTCD0 */
											/* DTC source address is set */
	    dtcen14 = 1;						/* Activation enabled in UART0 transmission interrupt */
	    te_u0c1 = 1;						/* Transmission enabled in UART0 */
	    while(ti_u0c1 == 0);				/* Wating for no data in U0TB register */
	    u0tbl = uart0_tx_buf[0];			/* Set transmission first data */
        tx_ct = 0;
        tx_wp = uart0_tx_buf;
    }else{
        *tx_wp++ = (char)c;
        tx_ct++;
    }
//p4_5 = 0;
    return 1;   // TRUE
}

/**********************************************************************
*  uart0 CRLF出力                                            *
************************************************************************/
void uart0_putcrlf(void)
{
  write('\r');
  write('\n'); 
}

/**********************************************************************
*  uart0 文字列出力                                            *
************************************************************************/
void uart0_puts(char * s)
{
  int i;
  
  for(i=0; i<256; i++){
    //write((int)*s++);
	uart0_putch(*s++);
    if( !*s )break;
  }
}

/**********************************************************************
*  uart0 2桁16進出力                                         *
************************************************************************/
void uart0_puthex(unsigned char n)
{
    write((int)(n < 10 ? n + '0' : n + 'A' - 10)); } void uart0_puthxb(unsigned char n) { uart0_puthex(n >> 4);
    uart0_puthex(n & 0x0f);
}

/**********************************************************************
*  uart0 4桁16進出力                                         *
************************************************************************/
void uart0_puthxw(unsigned short n)
{
    uart0_puthxb((unsigned char)(n >> 8));
    uart0_puthxb((unsigned char)(n & 0xff));
}

/**********************************************************************
*  uart0 8桁16進出力                                         *
************************************************************************/
void uart0_puthxl(unsigned long n)
{
    uart0_puthxw((unsigned short)(n >> 16));
    uart0_puthxw((unsigned short)(n & 0xffff));
}

/**********************************************************************
*  uart0 10進出力                                         *
************************************************************************/
void uart0_putint(int n)
{
    int n0;
    int i,j;

	if( n < 0 ){
	    write((int)'-');
	    n = -n;
	}
    n0 = 10;
    for(i=0;i < 8 ; i++){
        if(n < n0)break;
        n0 *= 10;
    }
    for(j=0; j <= i; j++){
        n0 /= 10;
        write((int)((n / n0) + '0'));
        n %= n0;
    }
}

void mon_putlong(long n)
{
    long n0;
    int i,j;

	if( n < 0 ){
	    write((int)'-');
	    n = -n;
	}
    n0 = 10;
    for(i=0;i < 8 ; i++){
        if(n < n0)break;
        n0 *= 10;
    }
    for(j=0; j <= i; j++){
        n0 /= 10;
        write((int)((n / n0) + '0'));
        n %= n0;
    }
}


/**********************************************************************
*  数値を文字列に変換して uart0から出力
*  u : 出力する数値
*  len : 文字列の長さ
*  radix : 基数 2,10,16等                                        *
************************************************************************/
const char XStr[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

void uart0_ltoa(unsigned long u, int len, int radix)
{
  int i;

  if(16<radix) radix = 16;
  for(i=0; i < len; i++){
	write((int)XStr[u % radix]);
	u /= radix;
  }
}