Edited at

PC-Arduino間 Python経由 シリアル通信備忘録


目的

本稿の目的は, Python を用いて Arduino とシリアル通信を行い, 更に同通信により得た値を数値として処理できるようにすることである.


目標


  • PC側から Arduino にデータを送信, その内容に応じて Arduino の動作を変化させる

  • PCが, Arduino から受信したデータを数値的に処理できるようにする


具体的目標


  • PCから文字データを送信し, ArduinoのLEDの明滅を操作するプログラムを組む

  • 超音波距離センサ HC-SR04 から得たデータから数値を取り出すプログラムを組む

  • 上記プログラム言語には Python 3.x を利用する


準備


  • Arduino Uno Rev.3

  • USBケーブル

  • LED

  • ジャンパワイヤ 4本

  • HC-SR04

  • Python 3.x , Arduino IDE

  • Python モジュール : PySerial


環境


  • Windowsだがおそらく汎用的なので省略


PC → Arduino シリアル通信


  1. Arduino の13番ピンとGNDにLEDをつなげる


    • LEDの足が長いほうが13番, 短い方はGND



  2. 以下のプログラム Serial_Com_LED.ino をArdino IDEで書いて, Arduino に書き込む

    一旦このプログラムをArduino IDE上で実行し, シリアルモニタを用いてLEDの明滅を制御できるか確認する

  3. 以下のプログラムSerial_Com_LED.pyを作成する



  4. Serial_Com_LED.pyを実行すると, Arduino IDEで実行した際と同様の動作が得られる


Serial_Com_LED.ino

void setup(){

pinMode(13,OUTPUT); //13番ピンを出力に設定

Serial.begin(9600);//シリアル通信のレートを9600に設定
}

void loop(){

int inputchar; //入力状態の読み取りに使う

inputchar = Serial.read(); //シリアル通信で送信された値を読み取る

if(inputchar!=-1){
switch(inputchar){
case 's':
digitalWrite(13,HIGH);
break;

case 'q':
digitalWrite(13,LOW);
break;
}
}
else{
}
}



Serial_Com_LED.py

#coding:utf-8


#シリアル通信で文字をArduino側に送信
#aが押されたら通信を中止するプログラム

import serial #モジュール名はpyserialだが, importする際はserialである

def main():
with serial.Serial('COM3',9600,timeout=1) as ser:
while True:
flag=bytes(input(),'utf-8')

#シリアル通信で文字を送信する際は, byte文字列に変換する
#input()する際の文字列はutf-8

ser.write(flag)

#シリアル通信:送信

if(flag==bytes('a','utf-8')):
break;
ser.close()

if __name__ == "__main__":
main()



Arduino → PC シリアル通信


  1. ピン接続

    ジャンパワイヤとブレッドボードを用いてそれぞれ以下のように接続する

Arduino
HC-SR04

5V
Vcc

GND
GND

Pin-9
Trig

Pin-10
Echo


  1. 以下の.ino, .py プログラムを書き込む


Serial_Com_Sonic.ino

#define echoPin 10 // Echo Pin

#define trigPin 9 // Trigger Pin

double Duration = 0; //受信した間隔
double Distance = 0; //距離
void setup() {
Serial.begin( 9600 );
pinMode( echoPin, INPUT );
pinMode( trigPin, OUTPUT );
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite( trigPin, HIGH ); //超音波を出力
delayMicroseconds( 10 ); //
digitalWrite( trigPin, LOW );
Duration = pulseIn( echoPin, HIGH ); //センサからの入力
if (Duration > 0) {
Duration = Duration/2; //往復距離を半分にする
Distance = Duration*340*100/1000000; // 音速を340m/sに設定
Serial.println(Distance);
}
delay(500);
}



Serial_Com_Sonic.py

#coding utf-8

import serial
import re
def main():
with serial.Serial('COM3',9600,timeout=1) as ser:

while True:
c = ser.readline()
d = re.findall('[0-9]+\.+[0-9]',str(c),flags=0)
d = [float(i) for i in d]
for i in range(0, len(d)): #要素を1つずつ順番に出力します
print(d[i])
print
ser.close()

if __name__=="__main__":
main()



実行

HC-SR04 についてのプログラムで, list型ではなく, float型を返させるのに苦労しました

原理はわかりませんがとりあえず動いたので良しとします


  • 以下の手続きを踏んでいる



    • ser.readline()で, serial.Serial...の出力を一行分読み込む


    • d = re.findall... で正規表現によって所望の出力を得る

    • re.findallが返す値の型はlist(str)であるため


      • リストから文字列を得る

      • floatに変換






引用, 参考