아두이노 Arduino/파이썬(Python)

아두이노 온도, 습도 값 파이썬으로 그래프 출력하기, 일정 개수만 출력, 버튼으로 그래프 만들기

끄적끄적아무거나 2024. 1. 18. 09:13
반응형

 

목차

     

     

     

     

     

     

    아두이노 온도, 습도 값 파이썬으로 그래프 출력하기

    앞 포스트에서 제작한 프로젝트와 동일하게 센서 없이 아두이노에서 랜덤으로 온도와 습도를 만들어서 시리얼 통신으로 보냅니다. 아두이노 코드는 아래와 같습니다.

     

    아두이노 코드>>

    void setup() {
      // 시리얼 통신을 시작합니다. 보드에 맞는 속도로 설정하세요.
      Serial.begin(9600);
    }
    
    void loop() {
      // 가상의 온도와 습도 값을 생성합니다.
      // 예를 들어, 온도는 20~30도 사이, 습도는 40~60% 사이의 값으로 설정할 수 있습니다.
      float temperature = 20 + random(100) / 10.0;  // 20.0 ~ 29.9 사이의 값
      float humidity = 40 + random(200) / 10.0;    // 40.0 ~ 59.9 사이의 값
    
      // 시리얼 통신을 통해 온도와 습도 값을 전송합니다.
    //  Serial.print("온도: ");
    //  Serial.print(temperature);
    //  Serial.print(" °C, 습도: ");
    //  Serial.print(humidity);
    //  Serial.println(" %");
      Serial.println(String(temperature) + "," + String(humidity));
    
      // 0.5초 동안 대기합니다.
      delay(500);
    }

     

    특정 범위의 온도와 습도를 랜덤하게 생성하고 serial 통신을 통해 , 컴마 기호로 분리해서 println으로 "\n"과 함께 전송합니다. 

     

     

     

     

     

     

    파이썬으로 일정 개수만 출력, 버튼으로 그래프 만들기

    이번에는 Python으로 별도의 버튼을 만들고 버튼을 클릭하면 그래프가 실행되게 하겠습니다. 그리고 이전에는 그래프에 포인트들이 계속 추가되어 정보가 쌓였는데 이번에는 default로 60개의 포인트에 대한 값만 그래프로 출력하고 사용자가 text box에 숫자를 입력하면 그 숫자만큼 출력되게 만들겠습니다.

     

    파이썬 전체 코드>>

    import tkinter as tk
    import matplotlib.pyplot as plt
    from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
    import serial
    import threading
    
    # 시리얼 포트 설정
    ser = serial.Serial('COM15', 9600)  
    
    # 그래프 창 및 스레드 관리를 위한 변수
    graph_window = None
    thread = None
    continue_reading = False
    max_data_points = 60  # 초기 데이터 포인트 개수
    
    def start_graph():
        global graph_window, thread, continue_reading
    
        if graph_window is not None:
            return  # 이미 그래프 창이 열려 있으면 아무것도 하지 않음
    
        graph_window = tk.Toplevel()
        graph_window.title("Arduino Temperature and Humidity Graph")
    
        # 그래프 설정
        fig, (ax1, ax2) = plt.subplots(2, 1)  # 두 개의 subplot 생성
        temp_line, = ax1.plot([], [], label='Temperature', color='blue')
        humi_line, = ax2.plot([], [], label='Humidity', color='orange')
        ax1.legend(loc='upper left')
        ax2.legend(loc='upper right')
    
        canvas = FigureCanvasTkAgg(fig, master=graph_window)
        widget = canvas.get_tk_widget()
        widget.pack(fill=tk.BOTH, expand=True)
    
        continue_reading = True
    
        # 아두이노에서 데이터 읽는 스레드 시작
        def read_from_arduino():
            x, y_temp, y_humi = [0], [0], [0]
            while continue_reading:
                try:
                    line = ser.readline().decode('utf-8').strip()
                    temperature, humidity = map(float, line.split(','))
                    x.append(x[-1] + 1)
                    y_temp.append(temperature)
                    y_humi.append(humidity)
    
                    # 설정된 데이터 포인트 수만큼 유지
                    if len(x) > max_data_points:
                        x = x[-max_data_points:]
                        y_temp = y_temp[-max_data_points:]
                        y_humi = y_humi[-max_data_points:]
    
                    temp_line.set_xdata(x)
                    temp_line.set_ydata(y_temp)
                    humi_line.set_xdata(x)
                    humi_line.set_ydata(y_humi)
                    ax1.relim()
                    ax1.autoscale_view()
                    ax2.relim()
                    ax2.autoscale_view()
                    canvas.draw()
                except ValueError:
                    pass
    
        thread = threading.Thread(target=read_from_arduino)
        thread.daemon = True
        thread.start()
    
    def close_graph():
        global graph_window, continue_reading
        continue_reading = False
        if graph_window is not None:
            graph_window.destroy()
            graph_window = None
    
    def update_data_points():
        global max_data_points
        try:
            max_data_points = int(data_points_entry.get())
        except ValueError:
            print("Please enter a valid integer for data points.")
    
    # 메인 윈도우 설정
    root = tk.Tk()
    root.title("Arduino Data Viewer")
    
    # 시작 버튼
    start_button = tk.Button(root, text="Start Graph", command=start_graph)
    start_button.pack()
    
    # 종료 버튼
    close_button = tk.Button(root, text="Close Graph", command=close_graph)
    close_button.pack()
    
    # 데이터 포인트 설정
    data_points_label = tk.Label(root, text="Set Data Points:")
    data_points_label.pack()
    data_points_entry = tk.Entry(root)
    data_points_entry.pack()
    data_points_button = tk.Button(root, text="Set", command=update_data_points)
    data_points_button.pack()
    
    root.mainloop()

     

    주석>>

    def read_from_arduino():

    지속적으로 아두이노에서 값을 읽어와야 하기 때문에 threading으로 동작합니다.

     

    global graph_window, thread, continue_reading

    함수 외부에서 영향을 주는 변수 들로 global로 관리 합니다.

     

     

     

     

     

    결과>>

     

     

     

     

    코드 다운로드

    파이썬 코드 다운로드>>

    test00.py
    0.00MB

     

     

    반응형