シリアル通信

PythonとArduinoを連携して、シリアル通信で値を送り合う。

Windows環境を想定している。Macだともうちょっと簡単。

Pythonと連携するとこんなことができる!

  • Arduinoで集めたデータをグラフにして分析
  • Arduinoから集めたデータをもとにWebと連携、ブラウザの自動操作
  • ネットから情報を取得してArduinoの動作を変える

Anacondaのインストール

WindowsでPythonを使うために、Anacondaというツールで環境を構築する。
https://www.javadrive.jp/python/install/index5.html

Pyserialのインストール

Anaconda Promptを開き、以下のように入力する。

pip install pyserial

これでPythonでシリアル通信が使えるようになった。
コマンドラインでUNIXと同じようにPythonを実行できる。
python3ではなくpythonで実行する。

python ファイル名.py

Windowsでlsに相当するコマンドはdircdは同じように動作する。

ArduinoからPythonに値を送る

Arduino IDEを開き、以下のプログラムを実行する。
これは、制作した基盤の可変抵抗を回すとアナログ入力の値が変わるプログラム。

int analogInputPin = 5;
/** 初期設定の関数 一度だけ実行される */
void setup() {
  Serial.begin(9600);
}
/** 定期的に実行される関数 頻度はdelay関数で調整 */
void loop(){
  int val = analogRead(analogInputPin);
  Serial.println(val); // PCに結果を送信
  delay(200);
}

シリアルモニタを見て、可変抵抗を回すと値が変わることを確認する
また、シリアルポートが何番かを確認しておく。

次に、Pythonのファイルを作成する。
参考: https://haizairenmei.com/2019/11/13/pyserial-arduino/

import serial
ser = serial.Serial('COM6', 9600) # ここのポート番号を変更
ser.readline()
while True:
  val_arduino = ser.readline()
  val_decoded = int(repr(val_arduino.decode())[1:-5])
  print(val_decoded)
ser.close()

このプログラムを実行すると、Arduinoのシリアルモニタと同じように数字が表示される。

PythonからArduinoに値を送る

intの値は、文字列として1桁ずつ送ることができる。

int led1 = 6;
int led2 = 5;
int led3 = 3;
int input = -1;
int add = 0;
int val = 0;

void setup() {
  Serial.begin(9600);
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
}

void loop() {
  input = Serial.read();
  if(input!=-1){
   switch(input){
     case '0':
       add = 0 + add*10;
       break;
     case '1':
       add = 1 + add*10;
       break;
     case '2':
       add = 2 + add*10;
       break;
     case '3':
       add = 3 + add*10;
       break;
     case '4':
       add = 4 + add*10;
       break;
     case '5':
       add = 5 + add*10;
       break;
     case '6':
       add = 6 + add*10;
       break;
     case '7':
       add = 7 + add*10;
       break;
     case '8':
       add = 8 + add*10;
       break;
     case '9':
       add = 9 + add*10;
       break;
     case 'a':
       val = add;
       add = 0;
       break;
     default:
        break;
    }
  }
  // ここまででvalが送られた

  // valが30以上のとき右のLEDをHIGH
  if(val >= 30){
    digitalWrite(led1, HIGH);
    digitalWrite(led2, LOW);
    digitalWrite(led3, LOW);
  }
  // valが20-29のとき真ん中のLEDをHIGH
  else if(val >= 20){
    digitalWrite(led1, LOW);
    digitalWrite(led2, HIGH);
    digitalWrite(led3, LOW);
  }
  // valが1-19のとき左のLEDをHIGH
  else if(val > 0){
    digitalWrite(led1, LOW);
    digitalWrite(led2, LOW);
    digitalWrite(led3, HIGH);
  }
}
import serial
import time

ser =serial.Serial("COM3", 9600) # ここのポート番号を変更
time.sleep(2)
val = 100 # ここの値を変更すると、Arduinoの挙動が変わる
a = str(val) + 'a'
ser.write(bytes(a,'utf-8'))
ser.close()

応用: APIの活用

Pythonで気象庁から明日の最高気温を取得し、それによって点灯するLEDを変える。
https://news.mynavi.jp/article/zeropython-75/
ネット上には、APIといって色々な情報がプログラミングしやすい形式でダウンロードできる仕組みがある。
今回は気象庁のAPIを利用する。JSONという形式で天気予報がダウンロードできる。
JSONはPythonでリストのように利用できる。
まずはURLにアクセスし、中身を見てみるとよい。

明日の最高気温が30度以上か、20度以上か、それ以外かによってArduino基盤の点灯するLEDを変える。
Arduinoのプログラムはそのまま

import serial
import time

import urllib.request as req
import json

# JSONをダウンロード
url = 'https://www.jma.go.jp/bosai/forecast/data/forecast/010000.json'
filename = 'tenki.json'
req.urlretrieve(url, filename)

with open('tenki.json', 'r', encoding="UTF-8") as f:
  data = json.load(f)

nagoya_data = data[11]
nagoya_tomorrow_temps = nagoya_data["srf"]["timeSeries"][2]["areas"]["temps"]
print(nagoya_tomorrow_temps) # 明日の名古屋の[最低気温, 最高気温]


ser =serial.Serial("COM3", 9600)
time.sleep(2)
val = nagoya_tomorrow_temps[1] # 明日の名古屋の最高気温
a = val + 'a'
ser.write(bytes(a,'utf-8'))
ser.close()

Pythonでは、ブラウザの自動操作ができる。
ブラウザの自動操作
IFTTTを使うことで、LINEなどと連携できる。
LINE, メールとの連携