目的
python3からArduinoへシリアル通信を行い、ある文字列がきたらモーターを振動させるという処理をすること
プログラム(失敗例)
Python
import serial
import time
print('Start')
ser=serial.Serial('COM5',9600)
ser.write("a")
print('Send')
if ser.in_waiting>0:
line = ser.read()
print(line)
ser.close()
Arduino
void setup() {
Serial.begin(19200);
pinMode(8, OUTPUT);
}
void loop() {
byte VibON;
VibON = Serial.read();
switch(VibON){
case 'a':
digitalWrite(8, HIGH);
delay(40);
digitalWrite(8, LOW);
delay(20);
break;
default:
break;
}
delay(1);
}
プログラムの説明
上記のプログラムは正しく動作しないが、一応解説をする。まず、python側でシリアル通信をするためのserialをインポートする。これはデフォルトで入っていたり入っていなかったりするのでない場合は(py -m)pip install pyserialをcmd上で入力すれば入れられる。py -mはWindowsの場合にのみ必要。まずWindowsの不便さでここがうまくいかくて苦労したけどそれは省略。最初からlinux使えばよかた。serial.Serial()の引数は各々帰る。そしてwrite()でArduino側へ送信する。また、Arduinoから返ってきた値を表示するためにread()も書いてある。
Arduino側はいたってシンプルにSerial.read()で読み取ったデータがaならばモーターを振動させるという処理をさせている。しかしこのプログラムで実行しようとするとエラーが出る。
原因解明
Arduino側は普通にコンパイルできるしシリアルポートでaを送ると振動する。python側のエラー文を見ると「byte型で送れや」と怒られている。調べてみるとserialはbyte型しか送れないっぽい。じゃあaをbyte型にするにはb'a'とするだけでいいから直して実行するとエラーは出ないがモーターが動かない。
ser.write("a") → ser.write(b"a")
Arduinoから返っても来ない。わけがわからないのでとりあえず送るものを表示させてみたらb'a'と送っている。byte型で送っているから当たり前なんだけどこれじゃあaではないのでArduino側も振動するはずがない。次になぜArduinoから返ってこないか考える。通信したことを示すランプは光るし大した処理はしていないからよくわからん。とりあえずネットで検索をかけまくる。そしたらポートを開いてから書き込む間に遅延を発生している人がちらほら(全員じゃない)。とりあえず適当に遅延をかけてみたらArduinoから値が返ってきた!!多分処理が追い付かないまま書き込もうとしちゃって結局書き込めてない的な感じかな。
ser=serial.Serial('COM5',9600)
ser.write("a")
↓
import time
ser=serial.Serial('COM5',9600)
time.sleep(2)
ser.write(b"a")
いい感じになってきたのであとはモーターぶるっとさせるだけ。単純に文字列比較だと一生aは送られないからそこを考える。考えた過程とか忘れたので結論char型にして先頭からaを探すという処理をすることで解決した。このプログラム自体は簡単だった。成功プログラムを以下に示す。
プログラム(成功)
Python
import serial
import time
print('Start')
ser=serial.Serial('COM5',9600)
time.sleep(2)
ser.write(b"a")
print('Send')
#time.sleep()
if ser.in_waiting>0:
line = ser.read()
print(line)
ser.close()
Arduino
void setup() {
Serial.begin(9600);
pinMode(8, OUTPUT);
}
void loop() {
if(Serial.available() >0){
int Vib=Serial.available();
char VibON[Vib+1];
for(int i=0; i<Vib; i++){
VibON[i] = Serial.read();
if(VibON[i] == 'a'){
Serial.print(VibON);
digitalWrite(8, HIGH);
delay(1000);
digitalWrite(8, LOW);
delay(20);
}
VibON[Vib]= '\0';
Serial.print(VibON);
}
}
delay(1);
}
今回使ったArduinoは以下。非純正買ってもいいけど変なところで苦労するかも。
おわり。
もしよければ↓ぽちっと↓お願いします。