오늘은 pyserial을 통해 파이썬으로 아두이노를 작동시키는 프로그램을 만들어보겠습니다.
우선 cmd에서 pip install pyserial을 입력해 설치해줍니다.
다음은 미리 작성한 아두이노 코드를 IDE에 입력해줍니다.
#include <Servo.h>
#include "DHT.h"
#define LED_RED 5
#define LED_GREEN 6
#define LED_BLUE 11
#define SERVO_PIN 8
#define PIEZO_BUZZER 3
#define BUTTON_1 4
#define BUTTON_2 7
#define VR_PIN A0
#define BRIGHT_PIN A1
#define DHTPIN 2
#define DHTTYPE DHT11
Servo myservo;
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
myservo.attach(SERVO_PIN);
pinMode(BUTTON_1, INPUT);
pinMode(BUTTON_2, INPUT);
dht.begin();
}
void loop() {
if (Serial.available() > 0)
{
String strRead = Serial.readStringUntil('\n');
if (strRead.indexOf("RGB=") != -1)
{
int commaIndex1 = strRead.indexOf(",");
int commaIndex2 = strRead.indexOf(",", commaIndex1 + 1);
int redValue = strRead.substring(4, commaIndex1).toInt();
int greenValue = strRead.substring(commaIndex1 + 1, commaIndex2).toInt();
int blueValue = strRead.substring(commaIndex2 + 1, strRead.length()).toInt();
LedSet(redValue, greenValue, blueValue);
Serial.println("OKRGB");
}
else if (strRead.indexOf("SERVO=") != -1)
{
int servoDigree = strRead.substring(6, strRead.length()).toInt();
if (servoDigree <= 180)
{
myservo.write(servoDigree);
Serial.println("OKSERVO");
}
else Serial.println("error digree");
}
else if (strRead.indexOf("BUZZER=") != -1)
{
float bzFreq = strRead.substring(7, strRead.length()).toFloat();
setBuzzer(bzFreq);
}
else if (strRead.indexOf("VR=?") != -1)
{
Serial.print("VR=");
Serial.println(analogRead(VR_PIN));
}
else if (strRead.indexOf("BRIGHT=?") != -1)
{
Serial.print("BRIGHT=");
Serial.println(analogRead(BRIGHT_PIN));
}
else if (strRead.indexOf("TEMPERATURE=?") != -1)
{
sendTemperature();
}
else if (strRead.indexOf("HUMIDITY=?") != -1)
{
sendHumidity();
}
}
if (btn1() == 1) Serial.println("BUTTON1=CLICK");
if (btn2() == 1) Serial.println("BUTTON2=CLICK");
}
void LedSet(int red, int green, int blue)
{
analogWrite(LED_RED, red);
analogWrite(LED_GREEN, green);
analogWrite(LED_BLUE, blue);
}
void setBuzzer(int freq)
{
if (freq > 31)
{
tone(PIEZO_BUZZER, freq);
Serial.println("OKBUZZER");
}
else
{
noTone(PIEZO_BUZZER);
Serial.println("OKBUZZER");
}
}
int btn1()
{
static int currBtn = 0;
static int prevBtn = 0;
currBtn = digitalRead(BUTTON_1);
if (currBtn != prevBtn)
{
prevBtn = currBtn;
if (currBtn == 1)
{
return 1;
}
delay(50);
}
return 0;
}
int btn2()
{
static int currBtn = 0;
static int prevBtn = 0;
currBtn = digitalRead(BUTTON_2);
if (currBtn != prevBtn)
{
prevBtn = currBtn;
if (currBtn == 1)
{
return 1;
}
delay(50);
}
return 0;
}
void sendTemperature()
{
float temperature = dht.readTemperature();
if (!isnan(temperature))
{
Serial.print("TEMPERATURE=");
Serial.println(temperature);
}
else
{
Serial.print("TEMPERATURE=");
Serial.println(0);
}
}
void sendHumidity()
{
float humidity = dht.readHumidity();
if (!isnan(humidity))
{
Serial.print("HUMIDITY=");
Serial.println(humidity);
}
else
{
Serial.print("HUMIDITY=");
Serial.println(0);
}
}
다양한 아두이노 모듈을 작동시키거나 값을 반환하는 코드입니다.
회로 구성은 사진을 첨부하겠습니다.
이제 파이썬을 통해 작동하는 프로그램을 만들어보겠습니다.
첫번째 예제로 원하는 명령을 입력받아 그에 맞는 응답을 출력시키는 프로그램입니다.
# 파이썬 input 명령으로 원하는 명령을 보내면 그에 맞는 응답이 출력되는 프로그램
import time
import serial
import serial.tools.list_ports
import threading
isDone = False
isFirst = True
def serial_read_thread():
global isDone
while True:
read_data = my_serial.readline()
if read_data :
print(read_data.decode())
isDone = True
def main():
global isDone
global isFirst
try:
while True:
if isDone or isFirst :
comm = input("write serial command : ")
my_serial.write( comm.encode() )
isDone = False
isFirst = False
except KeyboardInterrupt:
pass
if __name__ == '__main__':
ports = list(serial.tools.list_ports.comports())
for p in ports:
if 'Arduino Uno' in p.description:
print(f"{p} 포트에 연결하였습니다.")
my_serial = serial.Serial(p.device, baudrate=9600, timeout=1.0)
time.sleep(2.0)
t1 = threading.Thread(target=serial_read_thread)
t1.daemon = True
t1.start()
main()
my_serial.close()
두번째 예제는 온습도 값을 요청하여 csv형태로 기록하는 프로그램입니다.
# 파이썬으로 온습도센서 값 요청하여 csv 형태로 기록하기
import time
import serial
import serial.tools.list_ports
import threading
import datetime
import csv
def send_temp() :
sendData = f"TEMPERATURE=?\n"
my_serial.write( sendData.encode())
def send_humi() :
sendData = f"HUMIDITY=?\n"
my_serial.write( sendData.encode())
serial_receive_data = ""
temperature = ""
humidity = ""
def serial_read_thread() :
global serial_receive_data
while True:
read_data = my_serial.readline()
serial_receive_data = read_data.decode()
def send_vr_bright_2sec() :
#2초 마다 재귀 호출을 하는 스레드 생성
t2 = threading.Timer(2, send_vr_bright_2sec)
t2.daemon = True
t2.start()
send_temp()
time.sleep(1)
send_humi()
def main() :
try:
send_vr_bright_2sec()
global serial_receive_data
global temperature
global humidity
now = datetime.datetime.now()
now_day_time = now.strftime('%Y-%m-%d %H:%M:%S')
while True:
if "TEMPERATURE=" in serial_receive_data:
print("온도:",serial_receive_data[12:])
temperature = serial_receive_data[12:-2]
serial_receive_data=""
elif "HUMIDITY=" in serial_receive_data:
print("습도:",serial_receive_data[9:])
humidity = serial_receive_data[9:-2]
serial_receive_data=""
f = open('./1502.csv', 'a', newline='')
writer = csv.writer(f) # 내가 연 파일에 csv 형식의 쓰기를 하기 위한 객체
if temperature != "":
writer.writerow([now_day_time, 'TEMP', temperature])
temperature = ""
if humidity != "":
writer.writerow([now_day_time, 'HUMI', humidity])
humidity = ""
f.close()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
ports = list(serial.tools.list_ports.comports())
for p in ports:
if 'Arduino Uno' in p.description:
print(f"{p} 포트에 연결하였습니다.")
my_serial = serial.Serial(p.device, baudrate=9600, timeout=1.0)
time.sleep(2.0)
t1 = threading.Thread(target=serial_read_thread)
t1.daemon = True
t1.start()
main()
my_serial.close()