이 블로그는 Web 환경을 이용한 원격 제어 기술에 필요한 지식을 공유 하기 위한 블로그 입니다.
실제 개발과 프로그램 예를 위하여 Raspberry Pi와 Raspberry Pi Pico, ATmega128 보드, Arduino Mega 보드(ATmega2560), WiFi 모듈을 사용 합니다.

python-coding-ex

Python coding example
Python을 이용한 원격 제어(Remote control) Coding 예

    Python 언어를 이용한 프로그램을 이해 하는데 도움이 되는 기본 프로그램 예




  • 필요한 배경 지식
    • HTML: Web pages 작성에 필요한 Markup language
    • JavaScript: Web pages 작성에 필요한 Programming language
    • Python: HTML과 Web의 Programming language
    • Linux OS: Raspberry Pi의 OS 가 Linux 이다.
  • Web page Checkbox와 Button를 이용하여 Server 측의 LED(Server 측)를 제어하는 프로그램 예
    • Raspberry Pi 3와 Python web server(Flask 사용)를 사용한 원격제어 제어 시스템의 구성은 아래와 같다.

    • 필요한 소프트웨어 Tool: Flask, gpiozero
    • 프로그램 예: web-led-control.zip
    • 학습 포인트
      • GET, POST Method를 사용한 Client와 Server 사이의 Data 송수신(JSON format)에 대한 이해
      • Form data(Checkbox)를 JSON format으로 Server에 전송하기.
      • Server 측 GPIO Pin의 상태를 Arry data로 변환하여 JSON format으로 전송하기.
      • HTML 문서에서 버튼을 이용한 JavaScript 함수 실행 하기.
      • JSON format으로 전송된 Data의 내용을 Web page에 표시 하기.
      • 불규칙한 번호로 배열된 GPIO Pin를 Array로 처리 하기

      LED 제어 Web Page 예

      web-led-control.py 프로그램

      
      #!/user/bin/env python3
      # coding=utf8
      from flask import Flask, render_template, request
      from gpiozero import LEDBoard
      
      app = Flask(__name__)
      import json
      import time, threading
      from datetime import datetime
      
      leds = LEDBoard(9, 25, 11, 8, 7, 5, 6, 12)
      # ledList[ ]: LED의 상태를 저장 히기 위한 Array
      #  1, 3번이 Turn on 된 경우: [0,1,0,1,0,0,0,0] 와 같은 값을 갖는다.
      ledList = [0,0,0,0,0,0,0,0]
      ledsLen = len(ledList)
      # 주기적인 제어(Shift, Blinking) Mode
      # 0: 정지, 1: leftRotation, 2: rightRotation, 3: Blinking 
      operationMode = 0
      
      # 이 함수는 0.5Sec 주기로 실행 된다.
      def periodControl():
          global operationMode
          if operationMode == 1:
              leftRotation()  
          if operationMode == 2:
              rightRotation()  
          if operationMode == 3:
              leds.toggle()  			
          threading.Timer(0.5, periodControl).start()
      # 일정 주기로 실행되는 periodControl() 함수를 시작 한다.
      periodControl()
      
      # LED의 한 Bit를 Left rotation 시킨다.
      def leftRotation():
          temp = leds[ledsLen - 1].value
          for i in range(ledsLen - 1, 0, -1):
              if leds[i-1].value == 1:
                  leds[i].on()
              else:
                  leds[i].off()
          if temp == 1:
              leds[0].on()
          else:
              leds[0].off()
      
      # LED의 한 Bit를 Right rotation 시킨다.
      def rightRotation():
          temp = leds[0].value
          for i in range(0, ledsLen - 1):
              if leds[i+1].value == 1:
                  leds[i].on()
              else:
                  leds[i].off()
          if temp == 1:
              leds[ledsLen - 1].on()
          else:
              leds[ledsLen - 1].off()
      
      # Web browser에서 이 Server의 / 에 접속하면 web-led-control.htm 
      # 페이지를 Web browser에 전송 한다.
      # (예: http://Raspberry Pi의 IP 주소:2880/)
      # 2880은 공유기에서 포트포워드 설정한 포트 번호 임. 
      @app.route('/')
      def checkBoxLED():
          return render_template('web-led-control.htm')
      	
      @app.route('/checkBoxLEDControl', methods=['POST'])
      def LEDControl():
          global operationMode
          # Checkbox의 Check list(HTML File에서 Value로 정의 됨)를 갖어 온다.
          checkbox = request.form.getlist('check')
          print('checkbox: ',checkbox)
          # 주기적인 제어(Shift, Blinking)를 정지 한다.
          operationMode = 0
          # LED를 모두 Turn off 한다.
          leds.off()
      
          # Checkbox에 수신된 문자열 List의 내용과 일치 하는 led를 Turn on 한다. 	
          for ledNo in checkbox:
              i = int(ledNo)
              leds[i].on()
      		
          return ('Y');
          
      @app.route('/checkBoxLEDGet', methods=['GET'])
      def LEDGet():
          # GET Data를 갖어 온다. 이 예에서는 이 Data를 사용하지는 않는다.
          getMsg = request.args.get('getLED')
          #print('getMsg: ',getMsg)
      
          # LED의 상태를 Json format으로 Web page에 Return 하기 위하여
          #   ledList[]에 저장 한다.
          for i in range(0, ledsLen):
              ledList[i] = leds[i].value
        
          # LED의 상태를 확인 한다.
          print('ledList: ',ledList)
          return json.dumps({'status':'OK','checkbox':ledList});
                 
      # LED left shift
      @app.route('/ledLeftShift', methods=['GET'])
      def leftShit():
          # GET Data를 갖어 온다. 이 예에서는 이 Data를 사용하지는 않는다.
          getMsg = request.args.get('leftShift')
          #print('getMsg: ',getMsg)
          global operationMode
          leds.off()
          leds[0].on()
          operationMode = 1
      
          return ('Y');
      
      # LED right shift
      @app.route('/ledRightShift', methods=['GET'])
      def rightShift():
          # GET Data를 갖어 온다. 이 예에서는 이 Data를 사용하지는 않는다.
          getMsg = request.args.get('rigthShift')
          #print('getMsg: ',getMsg)
          global operationMode
          leds.off()
          leds[ledsLen - 1].on()
          operationMode = 2
      
          return ('Y');
      
      # LED blinking
      @app.route('/ledBlinking', methods=['GET'])
      def blinking():
          # GET Data를 갖어 온다. 이 예에서는 이 Data를 사용하지는 않는다.
          getMsg = request.args.get('blinking')
          #print('getMsg: ',getMsg)
          global operationMode
          leds.off()
          operationMode = 3
      
          return ('Y');
      
      # LED Stop
      @app.route('/ledClear', methods=['GET'])
      def clear():
          # GET Data를 갖어 온다. 이 예에서는 이 Data를 사용하지는 않는다.
          getMsg = request.args.get('clear')
          #print('getMsg: ',getMsg)
          global operationMode
          leds.off()
          operationMode = 0
      
          return ('Y');
       
      if __name__ == '__main__':
          app.run(host='0.0.0.0', port=2880, debug=True)
      #   app.run(host='0.0.0.0', port=2880, debug=False)  
          

    • 실험을 위한 준비
      • Raspberry Pi의 GPIO 상태를 보기 위한 LED Arary 회로 만들기
        • 아래 회로를 참고하여 LED Arary 모듈을 만든다.

        • Raspberry Pi의 GPIO 출력을 LED로 확인 할 수 있는 회로와 제작된 LED Arary 모듈 예
        • LED Arary 회로 예

          제작된 LED Arary 모듈

      • Raspberry Pi의 GPIO Pin과 LED Pin 연결하기
      • Raspberry Pi GPIO Header의 Pin 배치도를 참고하여 아래와 같이 Raspberry Pi GPIO Header Pin과 LED Arary 모듈을 연결 한다.

        • LED Pin 1번: Header Pin 21번 GPIO 09번
        • LED Pin 2번: Header Pin 22번 GPIO 25번
        • LED Pin 3번: Header Pin 23번 GPIO 11번
        • LED Pin 4번: Header Pin 24번 GPIO 08번
        • LED Pin 5번: Header Pin 26번 GPIO 07번
        • LED Pin 6번: Header Pin 29번 GPIO 05번
        • LED Pin 7번: Header Pin 31번 GPIO 06번
        • LED Pin 8번: Header Pin 32번 GPIO 12번
    • 실험 방법
      • 필요한 소프트웨어 Tool을 설치 한다.
      • 적당한 폴더(예:webapp)에 Server 측 프로그램(web-led-control.py)을 복사하여 web-led-control.py File을 만든다.
      • web-led-control.py 가 있는 폴더에 templates 폴더를 만들고, web-led-control.htm을 복사 한다.
      • Putty로 Raspberry Pi에 Login 하고, web-led-control.py가 있는 폴더로 이동 한다.
      • 다음 명령으로 web-led-control.py를 실행 한다.
      • python3 web-led-control.py

      • Chrome browser를 실행하고 아래 예를 참고하여 Web server에 연결 하면 web-led-control.htm 페이지가 Load 된다.
      • http://Raspberry Pi의 IP 주소:2880/

        2880은 공유기에서 포트포워드로 설정한 포트 번호 이다.

      • 임의의 Checkbox를 Check하고 "LED On/Off Control" 버튼을 클릭 하면, Web page에서 Check된 Checkbox와 대응하는 위치의 LED 가 Turn on 된다.
      • Web page에 있는 제어 버튼을 클릭 한 다음, 실험 보오드에서 LED 상태와 Checkbox를 확인 한다.

      윗 예에서 명령 버튼을 Drop-down list로 변경하여 Drop-down list 응용 능력을 키우기 위한 예 이다.

      필요한 소프트웨어 Tool, 실험을 위한 준비는 윗 예를 참고 할 것.

    • 프로그램 예: web-led-select-control.zip
    • 학습 포인트
      • Drop-down list를 이용한 제어
        • Drop-down list에서 선택된 명령을 Server에서 실행 하고,
        • 현재 Server 측의 상태를 Checkbox에 표시하기.

      Drop-down list를 이용하여 LED를 제어하는 Web Page 예

      web-led-select-control.py 프로그램

      
      #!/user/bin/env python3
      # coding=utf8
      from flask import Flask, render_template, request
      from gpiozero import LEDBoard
      
      app = Flask(__name__)
      import json
      import time, threading
      from datetime import datetime
      
      leds = LEDBoard(9, 25, 11, 8, 7, 5, 6, 12)
      # ledList[ ]: LED의 상태를 저장 히기 위한 Array
      #  1, 3번이 Turn on 된 경우: [0,1,0,1,0,0,0,0] 와 같은 값을 갖는다.
      ledList = [0,0,0,0,0,0,0,0]
      ledsLen = len(ledList)
      # 주기적인 제어(Shift left, Shift right, Blinking) Mode
      # 0: 정지, 1: LeftRotation, 2: RightRotation, 3: Blinking 
      operationMode = 0
      
      # 이 함수는 0.5Sec 주기로 실행 된다.
      def periodControl():
          global operationMode
          if operationMode == 1:
              leftRotation()  
          if operationMode == 2:
              rightRotation()  
          if operationMode == 3:
              leds.toggle()  			
          threading.Timer(0.5, periodControl).start()
      # 일정 주기로 실행되는 periodControl() 함수를 시작 한다.
      periodControl()
      
      # LED의 한 Bit를 Left rotation 시킨다.
      def leftRotation():
          temp = leds[ledsLen - 1].value
          for i in range(ledsLen - 1, 0, -1):
              if leds[i-1].value == 1:
                  leds[i].on()
              else:
                  leds[i].off()
          if temp == 1:
              leds[0].on()
          else:
              leds[0].off()
      
      # LED의 한 Bit를 Right rotation 시킨다.
      def rightRotation():
          temp = leds[0].value
          for i in range(0, ledsLen - 1):
              if leds[i+1].value == 1:
                  leds[i].on()
              else:
                  leds[i].off()
          if temp == 1:
              leds[ledsLen - 1].on()
          else:
              leds[ledsLen - 1].off()
      
      # Web browser에서 이 Server의 / 에 접속하면 web-led-select-control.htm 
      # 페이지를 Web browser에 전송 한다.
      # (예: http://Raspberry Pi의 IP 주소:2880/)
      # 2880은 공유기에서 포트포워드 설정한 포트 번호 임. 
      @app.route('/')
      def checkBoxLED():
          return render_template('web-led-select-control.htm')
      	
      @app.route('/selectLEDControl', methods=['POST'])
      def LEDControl():
          global operationMode
          # Checkbox의 Check list(Check 상태로 HTML File에서 Value로 정의 됨)를 갖어 온다.
          checkbox = request.form.getlist('check')
          print('checkbox: ',checkbox)
          selCommand = request.form.get('selectCommand')
          print('selCommand: ',selCommand)
          # 주기적인 제어(Shift, Blinking)를 정지 한다.
          operationMode = 0
      
          # Set LED
          if selCommand == '1':
              # LED를 모두 Turn off 한다.
              leds.off()
              # Checkbox에 수신된 문자열 List의 내용과 일치 하는 led를 Turn on 한다. 	
              for ledNo in checkbox:
                  i = int(ledNo)
                  leds[i].on()
              print('LED')
              return json.dumps({'command':'1','status':'Y'})
      
          # Get LED status
          if selCommand == '2':
              # LED의 상태를 Json format으로 Web page에 Return 하기 위하여
              #   ledList[]에 저장 한다.
              for i in range(0, ledsLen):
                  ledList[i] = leds[i].value 
              # LED의 상태를 확인 한다.
              print('ledList: ',ledList)
              return json.dumps({'command':'2','status':'Y','checkbox':ledList})
      
          # LED left shift
          if selCommand == '3':
              leds.off()
              leds[0].on()
              operationMode = 1
              return json.dumps({'command':'3','status':'Y'});
      
          # LED right shift
          if selCommand == '4':
              leds.off()
              leds[ledsLen - 1].on()
              operationMode = 2
              return json.dumps({'command':'4','status':'Y'});
      
          # LED blinking
          if selCommand == '5':
              leds.off()
              operationMode = 3
              return json.dumps({'command':'5','status':'Y'});
      
          # LED Clear
          if selCommand == '6':
              leds.off()
              operationMode = 0
              return json.dumps({'command':'6','status':'Y'});
       
      if __name__ == '__main__':
          app.run(host='0.0.0.0', port=2880, debug=True)
      #   app.run(host='0.0.0.0', port=2880, debug=False)
          

    • 실험 방법
      • 적당한 폴더에 Server 측 프로그램(web-led-select-control.py)을 복사하여 web-led-select-control.py File을 만든다.
      • web-led-control.py 가 있는 폴더(예: webapp)에 templates 폴더를 만들고, web-led-select-control.htm을 복사 한다.
      • Putty로 Raspberry Pi에 Login 하고, web-led-select-control.py가 있는 폴더로 이동 한다.
      • 다음 명령으로 web-led-select-control.py를 실행 한다.
      • python3 web-led-select-control.py

      • Chrome browser를 실행하고 아래 예를 참고하여 Web server에 연결 하면 web-led-select-control.htm 페이지가 Load 된다.
      • http://Raspberry Pi의 IP 주소:2880/

        2880은 공유기에서 포트포워드로 설정한 포트 번호 이다.

      • 임의의 Checkbox를 Check하고 Drop-down list에서 "Turn on/off"를 선택하고 "LED Control" 버튼을 클릭하면 , Web page에서 Check된 Checkbox와 대응하는 위치의 LED 가 Turn on 된다.
      • Drop-down list에서 다른 명령도 선택하여 실행 시키고, 실험 보오드에서 LED 상태와 Checkbox를 확인 한다.