본문 바로가기

카테고리 없음

AIOT - 아두이노(6) - pyserial

오늘은 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()