湧々研究所Webページ
HOME > 電動ドリルカー >第3弾 電子工作編
元々はマイコンでモータ制御できないかと考えていたのですが、費用、技術面で行き詰ってしまいました。
マイコンボード(arduino)の勉強もかねて、とりあえず、回転数&時速計を作りました。
電子工作は初心者で、複数桁7セグメントLEDを表示させるのに、とても苦労しました。
マイコンボードは、初心者向けとして「arduino uno」が多く紹介されていたので、これを使うことにしました。
「arduino」は、「アルデュイーノ」と読むようです。
ソフトの開発環境も提供されていて、価格も3,000円程度で購入できます。
ソフト開発の経験はあったので、何とかなるかなという気持ちで始めました。
回転検出用センサーは、ネットでも多く事例が出ていた磁気センサーモジュールを使用しました。
このモジュールは、2種類のタイプがあるようで、磁気に反応したアナログ電圧が入力されるものと、磁気検出時に5Vのデジタル入力できるタイプです。
今回使用したのは、簡単なデジタル入力タイプです。
回路構成です
arduino unoはi/o点数が少ないので、7セグLED(ドットを入れると8セグ)を直接表示させるると、他のSW入力などに使う点数が足りなくなります。
そこで、シフトレジスタ(74HC595)を使って、i/o点数を節約しています。
スナップSWは、回転数[rpm]と時速[km/h]の表示切替えに使います。
回路については、もっといい(正しい?)使い方があるかもしれませんが、一応動作してます。
エクセルで根気よく書きました。
作成したこの基板を、arduinoに重ね置きします。
もっと綺麗に半田できればいいのですが。。

//******************************************
// 時速/RPM 計測・表示プログラム
// ホールセンサ:
// シフトレジスタ:74HC595
// 4桁7セグメントLED
//******************************************

//*************************************
// I/O Pin割り付け
//**************************************
const int PIN_sw = 3; // Speed / RPM 切替えSW

// 74HC595
const int PIN_srclk = 8; // SRCLK (クロック L→H でSERの情報がセット)
const int PIN_rclk = 9; // RCLK (ラッチ L→H で変更が有効)
const int PIN_ser = 10; // SER (入力したいデータ)

// 4桁7セグLED
const int DIG1 = 7; // DIG1を7番ピンに割り当て
const int DIG2 = 6; // DIG2を6番ピンに割り当て
const int DIG3 = 5; // DIG3を5番ピンに割り当て
const int DIG4 = 4; // DIG4を4番ピンに割り当て

//*****************************
// 7セグ配列データ
// 1 = LED on, 0 = LED off
//*****************************
byte seven_leds[12] ={ B11111100, // 0
B01100000, // 1
B11011010, // 2
B11110010, // 3
B01100110, // 4
B10110110, // 5
B10111110, // 6
B11100000, // 7
B11111110, // 8
B11100110, // 9
B00000001, // D.P
B00000000, // OFF
};
//*****************************
// 変数 初期値
//*****************************
int delayTime = 1; // 遅延設定 msec
float speedData = 0; //時速
volatile unsigned long detectCnt= 0; //センサ検出カウント
unsigned long rpm = 0;
unsigned long rpm2 = 0;
unsigned long timeMillisOld;
const float wGea1=12; //Drive 側ギア歯数;
const float wGea2=56; //Driven 側ギア歯数


void setup() {

// シリアル接続 デバッグ用
// Serial.begin(115200);
// Serial.println("--- Started ---"); //スタート表示

//********************************
// 割込み設定(ホールセンサ検出)D2 Pin
//********************************
attachInterrupt(digitalPinToInterrupt(2), magnet_detect, FALLING );//Initialize the intterrupt pin (Arduino digital pin 2)

//*****************************
// Speed / RPM 切替えSW
//*****************************
pinMode(PIN_sw, INPUT);
//*****************************
// 74HC595 シフトレジスタ 割り付け
//*****************************
pinMode(PIN_rclk, OUTPUT);
pinMode(PIN_ser, OUTPUT);
pinMode(PIN_srclk, OUTPUT);

//*****************************
// 4桁7セグLED 割り付け
//*****************************
pinMode(DIG1, OUTPUT); //最上位
pinMode(DIG2, OUTPUT);
pinMode(DIG3, OUTPUT);
pinMode(DIG4, OUTPUT);

digitalWrite(DIG1, HIGH); //1番ピンをHIGH dig1 OFF
digitalWrite(DIG2, HIGH); //2番ピンをHIGH dig2 OFF
digitalWrite(DIG3, HIGH); //3番ピンをHIGH dig3 OFF
digitalWrite(DIG4, HIGH); //3番ピンをHIGH dig4 OFF
func74HC595(11); //信号初期化

// 経過時間計測用変数
timeMillisOld = millis(); //現在値を前回値へ
}

void loop() {
int sw;
int intvl;

sw = digitalRead( PIN_sw); // SPEED-RPM 切替えSW

if (detectCnt > 1){ // 1回だとスムーズに回転数が変化しなかったので

// 回転数 rpm
intvl = millis()-timeMillisOld; //[ms] 経過時間

noInterrupts(); // detectCntが変化しない様に割込み禁止
rpm2 = detectCnt * 60000 / intvl ; // 計測点(タイヤ側)の[rpm]
detectCnt=0;
interrupts(); //割り込み開始

rpm = rpm2 * wGea2 /wGea1; //計測点は、タイヤ軸の為、ギヤ比を考慮して、ドリルの回転数にする

// 時速換算 タイヤ径:350mm
speedData = rpm2 * 3.14 * 0.35 * 60 / 1000; //[km/h]

// Serial.print("Cnt: ");
// Serial.print(detectCnt);
// Serial.print(" intvl: ");
// Serial.print(intvl);
// Serial.print(" RPM: ");
// Serial.print(rpm);
// Serial.print(" Speed: ");
// Serial.println(speedData);

timeMillisOld = millis(); //次回用
}
else if((millis()-timeMillisOld) >3000){ // 3s以上経過?
//一定時間入力がなければ、0をセット
speedData = 0;
rpm = 0;
}

if(sw==1){
func7SegLED(speedData,1); //時速表示 小数点あり
}else{
func7SegLED((float)rpm,0); //回転数表示 小数点なし
}
}

//****************************
// 割込み処理 ホールセンサ検出
//****************************
void magnet_detect(){//
detectCnt++;
}

//****************************
// 74HC595 シフトレジスタへ表示データセット
//****************************
void func74HC595(int x)
{
digitalWrite(PIN_rclk, LOW); //RCLKをLowにする

shiftOut(PIN_ser, PIN_srclk, LSBFIRST, seven_leds[x]); // 1バイト分のデータを1ビットずつ「シフトアウト」する

digitalWrite(PIN_rclk, HIGH); //RCLKをHighにして出力を有効にする
}

void func7SegLED(float floatData,int sw){
//*************************************
// sw 0:小数点あり、1:整数(正)
//*************************************
float floatData2;
int x1data,x10data,x100data,x1000data,intData;

// 時速/回転数 表示切替え
if (sw==1){ //小数点あり(時速)?
floatData2 = floatData * 10;
}else{
floatData2 = floatData;
}
// 上下限チェック
if (floatData2 < 0 ){
floatData2 = 0.0;
}
if (floatData2 > 9999){
floatData2=9999;
}
intData = (int)floatData2;
x1data = intData % 10; //1桁目
intData = intData / 10;
x10data = intData % 10; //2桁目
intData = intData / 10;
x100data = intData % 10; //3桁目
intData = intData / 10;
x1000data = intData % 10; //4桁目

// Serial.print("x1:");
// Serial.print(x1data);
// Serial.print(" x10:");
// Serial.print(x10data);
// Serial.print(" x100:");
// Serial.print(x100data);
// Serial.print(" x1000:");
// Serial.println(x1000data);

//****DIG1(4桁目 1000の位)の表示************
delay(delayTime);
digitalWrite(DIG1, LOW);
digitalWrite(DIG2, HIGH);
digitalWrite(DIG3, HIGH);
digitalWrite(DIG4, HIGH);
if (x1000data == 0){ // 上位桁が0のときは表示なし
x1000data=11; //LED off
}
func74HC595(x1000data);
delay(delayTime);
func74HC595(11); // 消しておかないと次の桁へ値が回り込む(薄く光ってしまう)!

// ***** DIG2(3桁目 100の位)の表示 *********
delay(delayTime);
digitalWrite(DIG1, HIGH);
digitalWrite(DIG2, LOW);
digitalWrite(DIG3, HIGH);
digitalWrite(DIG4, HIGH);
if ((x1000data == 11) and (x100data == 0)){ // 上位桁全てが0のときは表示なし
x100data=11; //LED off
}
func74HC595(x100data);
delay(delayTime);
func74HC595(11);

// ***** DIG3(2桁目 10の位)の表示 *********
delay(delayTime);
digitalWrite(DIG1, HIGH);
digitalWrite(DIG2, HIGH);
digitalWrite(DIG3, LOW);
digitalWrite(DIG4, HIGH);
if(sw==0){ // 小数点なし?
if ((x1000data == 11) and (x100data == 11) and (x10data == 0)){ // 上位桁全てが0のときは表示なし
x10data=11; //LED off
}
}
func74HC595(x10data);
delay(delayTime);
func74HC595(11);

if (sw==1){ // 小数点あり?
//[.]を付ける
func74HC595(10);
delay(delayTime);
func74HC595(11);
}

// ***** DIG4(1桁目 1の位)の表示 *********
delay(delayTime);
digitalWrite(DIG1, HIGH);
digitalWrite(DIG2, HIGH);
digitalWrite(DIG3, HIGH);
digitalWrite(DIG4, LOW);
func74HC595(x1data);
delay(delayTime);
func74HC595(11);
}
このプログラムで動作させています。
1回転検出毎の所要時間を計測し、回転数[rpm]と時速[km/h]を計算しています。
プログラムは、回転検出時のセンサー信号を、割込み処理内でカウントアップし、メインループで所要時間による計算後にそのカウント値をリセットする内容です。

7セグLEDの表示では、当初、綺麗な表示ができなく、相当時間を使ってしまいました。
複数桁の7セグLEDでは、注意しないと最初に表示した桁表示の値が、次の桁で出力する数値に重なり、その部分が薄く光ってしまいます。
次の桁の表示を行う前に、今出力した桁の値をリセットする必要がありました。
気が付くまで回路の見直しやら、シフトレジスタの交換など、時間を費やしてしまいました。
上が、数値1234の出力で、1を出力した後、リセットなしで、2を出力したときの表示です。
2の表示桁で、1の表示が重なって、薄く光っています。
下は、リセットを出力した後、2の表示を行い、綺麗に表示できているところです。
ダッシュボードの製作です。
水道パイプのデカいやつです。
DIYショップで思いついて、購入しました。
ハンドルのベースに取付たのですが、電動ドリルの回転を上げるとかなり振動します。
磁気センサーの取付位置は、タイヤ回転部分にしました。
この位置だと、タイヤ回転数になってしまうので、電動ドリルの回転数にするために、ギア比で逆算しています。
ギヤ比は、ドライブ側歯数:12丁、ドリブン側歯数:56丁です。
タイヤ側に付いてる黒いパーツは磁石です。
これが磁気センサーに接近して、回転検出になります。
タイヤを空転させた状態で、アクセルをMAX踏み続け、表示した最高の回転数は2500[rpm]程度でした。
電動ドリルの最高回転数は、2600rpmですが、タイヤが空転している状態とはいえ、ここまで回転が上がるとは思ってなかったです。
タイヤの回転数は、2500 x 12 / 56 = 535.7 [rpm] となり、磁気センサーの検出周期の最速は、112msぐらいになりました。

今回は、いつものコースで走らせていません。
運転手(孫)が意識して、スピードを出しても危ないので、近所の安全なところで、低速モードで走ってもらいます。
電子部品の単価は安くて、私みたいに初めての人は、どうしてもセットで注文してしまいます。
今回の工作にあたって、パーツなどを集めましたが、工作終了後も在庫豊富です。
この先、電子工作も趣味にします。