アプリとサービスのすすめ

アプリやIT系のサービスを中心に書いていきます。たまに副業やビジネス関係の情報なども気ままにつづります

Arduino UnoとPCをシリアル通信させる方法と参考コード集まとめ【hardware】

ArduinoとPCとの情報のやりとりはシリアル通信でする。このサイトを参考にした。

深層学習(DNN)にはシリアル通信は必須なので、やり方とデモもかねて動かしたコードをまとめていく。

f:id:trafalbad:20200526161410j:plain

目次
1.Arduino Unoのシリアル通信の設定
2.Arduino UnoからPCへのデータ送信
3.PCからArduino Unoへのデータ送信



1.Arduinoのシリアル通信の設定

Arduino for Macを起動して、[ツール]-[シリアルボード~]で表示されてるパスを取得して確認。
f:id:trafalbad:20200526161555p:plain

# シリアル通信できるか確認
$ sudo pip install pyserial
$ python3
>>>import serial
>>>ser = serial.Serial("/dev/cu.usbmodem14301")
>>>print(ser)
Serial<id=0x106a8f710, open=True>(port='/dev/cu.usbmodem14301', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)

>>>ser.close()
>>>exit()

シリアル通信ができてる。





2.Arduino UnoからPCへのデータ送信

f:id:trafalbad:20200526161623j:plain

0~9までの数字を一秒おきに送信


Arduinoから1秒毎にカウントされる値がPCに送られる。
通信中はArduinoのTXと書かれた通信用LEDが一秒毎に点滅する。

serial_send.ino

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
}

void loop() {
 static int count=0;
 Serial.print(count);
 count ++;
 if(count == 10)
   count = 0;
 delay(1000);
}


serial_receive1.py

# -*- coding: utf-8 -*-
import serial
import time
wait_second = 5.0
total_number = 10
ser = serial.Serial("/dev/cu.usbmodem14301", timeout=0.5)
time.sleep(wait_second)
for i in range(total_number):
   line = ser.read()
   print(line)
ser.close()
# 実行
$ python3 serial_receive1.py
>>>
b'0'
b'1'
b'2'
~
b'5'

f:id:trafalbad:20200526161707g:plain



1~10までを読みこんで表示


ser.read()関数で一文字ごとに読み込んで表示。

serial_receive2.py

# -*- coding: utf-8 -*-
import serial
import time

wait_second = 5.0
total_number = 10 
with serial.Serial("/dev/cu.usbmodem14301") as ser:
   time.sleep(wait_second)
   for i in range(total_number):
       line = ser.read()
       print(line)
# 実行
$ python3 serial_receive2.py
>>>
b'0'
b'1'
b'2'
~
b'8'
b'9'
# ファルダ構造
$ tree Serial_receive
>>>
Serial_receive
├── serial_send
│   └── serial_send.ino
├── serial_receive1.py
└── serial_receive2.py




データロガー



データロガーは「Arduinoで計測したデータをPCに送って、PCでそのデータを保存する」こと。

試しに一秒おきに

0, 0, 0.00
1, 1, 2.00

と0, 1, 2, 3と増えるデータをArduinoからPCに送信して、テキストファイル(data.txt)に保存してみる。

serial_datalogger.ino

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
}

void loop() {
 static int count=0;
 Serial.print(count);
 Serial.print(',');
 Serial.print(count);
 Serial.print(',');
 Serial.println(count*2.0);
 count ++;
 if(count == 10)
   count = 0;
 delay(1000);
}


serial_datalogger.py

# -*- coding: utf-8 -*-
import serial
import time
wait_second = 12.0

with serial.Serial('/dev/cu.usbmodem14301', timeout=0.5) as ser:
   time.sleep(wait_second)
   with open('data.txt', 'w') as f:
       for i in range(10):
           line = ser.readline()
           line = line.rstrip().decode('utf-8')
           print(line)
           f.write((line)+'\n')
# 実行
$ python3 serial_datalogger.py
>>>
0,0,0.00
1,1,2.00
2,2,4.008,8,16.00
9,9,18.00


データがうまく保存できないならtime.sleep()の時間を増やすのがコツ

# ファルダ構造
$ tree Serial_datalogger

Serial_datalogger
├── data.txt
├── serial_datalogger
│   └── serial_datalogger.ino
└── serial_datalogger.py




3.PCからArduino Unoへのデータ送信

今度は逆にPCからArduinoへ文字や数値を送信する。
これを使えばDNNで得た学習モデルを使って、Arduinoを含めたラズパイとかの電子工作を動かせる。

f:id:trafalbad:20200526161758j:plain

バイト文字の送信



void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
 pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
 if(Serial.available()>0){
   char c = Serial.read();
   if(c=='a')
         digitalWrite(LED_BUILTIN,HIGH);
   else if(c=='b')
         digitalWrite(LED_BUILTIN,LOW);
 }
}
# -*- coding: utf-8 -*-
import serial
import time

with serial.Serial('/dev/cu.usbmodem14301') as ser:
   time.sleep(5.0)
   for i in range(5):
       ser.write(b'a')
       time.sleep(1.0)
       ser.write(b'b')
       time.sleep(1.0)


受信した変数が’a’なら確認用LEDを点灯、’b’なら確認用LED消灯。

‘a’を送信し、1秒待ち、’b’を送信して1秒待つを5回繰り返す。

Arduinoの確認用LEDが5回点滅する。
f:id:trafalbad:20200526161831g:plain





数値の送信



0~255の数値を送ってLEDの明るさを変化させる(もっと大きい数値(500とか1500)も送信可能)。

デジタル9番ピンを使ってLEDの明るさを変える。
serial_receive_value.ino

int pin_number = 9;

void setup() {
 int signal_speed = 9600;
 Serial.begin(signal_speed);
 pinMode(pin_number, OUTPUT);
}

void loop() {
 if(Serial.available()>0){
   long int v = Serial.parseInt();
   analogWrite(pin_number, v);
 }
}


Serial.available()関数は浮動小数点値を受け取る。

LEDがだんだん明るくなる=>消える

を5回繰り返す(0~255までの値を送る)。
serial_receive_value.py

# -*- coding: utf-8 -*-
import serial
import time

wait_second = 0.01
with serial.Serial('/dev/cu.usbmodem14301') as ser:
   time.sleep(5.0)
   for i in range(5):
       for j in range(255):
           ser.write((str(j)+'\n').encode('utf-8'))
           time.sleep(wait_second)  # 0.01秒待つ
# 実行
$ python3 serial_send_value.py

f:id:trafalbad:20200526161855g:plain

$ tree serial_receive_value
>>>
serial_receive_value
├── serial_receive_value.ino
└── serial_receive_value.py

これでArduinoを使って深層学習ができる。


速度とかとはultra96v2と比較して劣るものの、Arduino Unoは動かすのはかなり簡単だった。


f:id:trafalbad:20200526163409j:plain