もよいめも

不定期更新ものづくりブログ

【Arduino】シリアル通信でラジコンもどきを作る!

さあ、前回に続きまして今回はシリアル通信の応用として、Arduino間シリアル通信を用いた有線ラジコンを作ってみようと思います。
ちなみに、こんな感じになります。


www.youtube.com

回路~受信側~

必要な部品

・ユニバーサル基板 ×1
https://akizukidenshi.com/catalog/g/gP-03230/

・モータードライバー [TC78H653FTG]×2
https://akizukidenshi.com/catalog/g/gK-14746/

・ターミナルブロック ×5
https://akizukidenshi.com/catalog/g/gP-01306/

・USBコネクタDIP化キット ×1
https://akizukidenshi.com/catalog/g/gK-07429/

Arduino Nano
・メスピンヘッダ 適量
・スズメッキ線 適量

モータードライバーは秋月電子のTC78H653FTGをDIP化した基板を使用します。
今回の使用方法だと以下の接続になります。(裏面)

f:id:moyoi:20210327102646j:plain
モータードライバー配線


汎用性のために結構めんどくさい回路になっています。頑張ってください。
ちなみに白線はジャンパ?です。
それと、電源の線が近い部分があるので、ショートしていないかよく確認してから電源を投入してください。

f:id:moyoi:20210324200406p:plain
回路図1
f:id:moyoi:20210324202227j:plain
基板表
f:id:moyoi:20210324202220j:plain
基板裏

部品を挿して配線したらこんな感じ


f:id:moyoi:20210325113442j:plain

上から出てるのが電源とUSB、横から出てるのがモーターの線です。

回路~送信側~

まずは受信基板に接続が出来るようにケーブルを作りましょう。今回はUSBコネクタを使用していますので、もちろんUSBを使います。
USB自作キット的なものを使用して配線してもいいですが、簡単に済ませたいならそのへんのUSBの通信ケーブルをぶった切って先をピンヘッダに変えます。

f:id:moyoi:20210325094929j:plain

送信側の回路は別に難しくもないのでブレッドボード上で仮組します

f:id:moyoi:20210325104002p:plain
送信側の回路

中央?のピンヘッダ部に先ほど作ったUSBケーブルのピンヘッダをぶっさして受信基板に接続しますが、市販のUSBケーブルをぶった切ってケーブルを作った人はTX,RXが逆になっていることも考えられるので注意してください。

プログラム

受信側

とりあえずモーターを2つだけ動かしてみます。

byte data[2];//受信データを入れる配列

//*****モーターを動かす関数を定義*****
/*
motorNum モーター番号 1~4
direction モーター回転方向 true false
power モーター出力強さ 0~255
*/
//モーターナンバー(1~4)の4番はPWM出力ピンに繋がっていないため、パワーの設定は255のみです。
void motor(int motorNum, bool direction, int power) {
  switch (motorNum) {
  case 1:
    if (direction) {
      analogWrite(3, power);
      analogWrite(5, 0);
    } else {
      analogWrite(3, 0);
      analogWrite(5, power);
    }
    break;
  case 2:
    if (direction) {
      analogWrite(6, power);
      analogWrite(9, 0);
    } else {
        analogWrite(6, 0);
        analogWrite(9, power);
    }
  break;
  case 3:
    if (direction) {
      analogWrite(10, power);
      analogWrite(11, 0);
    } else {
      analogWrite(10, 0);
      analogWrite(11, power);
    }
  break;
  case 4:
    if (direction) {
      digitalWrite(8, HIGH);
      digitalWrite(12, LOW);
    } else {
      digitalWrite(8, LOW);
      digitalWrite(12, HIGH);
    }
  break;
  }
}

//*****モーターを止める関数を定義*****
/*
motorNum モーター番号 0~4
*/
//モーターナンバーの0番はすべてのモーターが停止します。
void motorStop(int motorNum){
  switch (motorNum) {
  case 0:
    analogWrite(3, 0);
    analogWrite(5, 0);
    analogWrite(6, 0);
    analogWrite(9, 0);
    analogWrite(10, 0);
    analogWrite(11, 0);
    digitalWrite(8, LOW);
    digitalWrite(12, LOW);
  break;
  case 1:
    analogWrite(3, 0);
    analogWrite(5, 0);
    break;
  case 2:
    analogWrite(6, 0);
    analogWrite(9, 0);
  break;
  case 3:
    analogWrite(10, 0);
    analogWrite(11, 0);
  break;
  case 4:
    digitalWrite(8, LOW);
    digitalWrite(12, LOW);
  break;
  }
}

void setup() {
  Serial.begin(9600);
  //PWMの出力にピンの宣言は必要ないが、8,12はデジタル出力で使用するため宣言が必要
  pinMode(8, OUTPUT);
  pinMode(12, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {//受信データがある場合
    Serial.readBytes(data, 2);//受信データを読み込んで配列[data]に代入

    //モーター1を動かす
    if (bitRead(data[0], 0) == 1) {//受信データの1byteの0番目の1bitを読みだして1だった場合モーター1を2パワー255で動かす
      motor(1,true,255);
    } else if (bitRead(data[0], 1) == 1) {
      motor(1,true,100);
    } else {
      motorStop(1);
    }

    //モーター2を動かす
    if (bitRead(data[0], 2) == 1) {
      motor(2,true,255);
    } else if (bitRead(data[0], 3) == 1) {
      motor(2,true,100);
    } else {
      motorStop(2);
    }
    //受信データを表示する
    //受信データをシリアルモニタで確認できます。
    for (int i = 0; i < 8; i++) {
      Serial.print(bitRead(data[0], i));//受信データの1byte目の0~7番目の1bitを読みだして表示
    }
    for (int i = 0; i < 8; i++) {
      Serial.print(bitRead(data[1], i));//受信データの2byte目の0~7番目の1bitを読みだして表示
    }
    Serial.println();//改行
  }
}

送信側

D13のピンはプルアップした状態だとおかしくなるので使っていません。
D2~D12までの10ピンは送信する感じです。

byte data[2];//送信するデータの配列を宣言

void setup() {
  Serial.begin(9600);
  for (int i = 2; i <= 12; i++) {//1~12番ピンを入力およびプルアップとして設定
    pinMode(i, INPUT_PULLUP);
  }
}

void loop() {
  data[0] = 0;//送信データの初期化
  data[1] = 0;
  for (int i = 0; i < 8; i++) {
    if (digitalRead(i + 2) == LOW) {//ピンがLOWになったらそのピンに応じたbitを1にする
      bitSet(data[0], i);
    }
  }
  for (int i = 0; i < 3; i++) {
    if (digitalRead(i + 10) == LOW) {
      bitSet(data[1], i);
    }
  }
  Serial.write(data, 2);//データを送信
  delay(100);
}