ESP8266+OLED에 Bad Apple(동영상) 표시

13945 단어 파이썬oledESP8266

개요



ESP8266에 연결된 128x64pixel 흑백 OLED에 동영상을 표시할 수 있었으므로, 그 구성, 구조 등에 대해 설명한다.
이번에 작성한 프로그램은 GitHub에서 공개하고 있는 h-nari/HSES_NODE_OLED_Sample_programs에 NetOLED라는 이름으로 들어있다.



- 동영상: ESP8266+OLED로 Bad Apple (youtube)  (소리가 나옵니다)

배경



ESP8266(ESP-WROOM-02)과 2.4 인치 컬러 LCD을 조합한 기판이나 0.96인치 OLED를 결합한 기판을 작성하고 있다. 이런 기판으로, 언젠가는 동영상을 표시시키고 싶다고 생각하고 있었지만 2.4 인치·칼라 LCD의 쪽은 SPI 접속으로 CPU-LCD간의 속도 넥으로 무리. OLED도 SPI 접속이지만, 이쪽은 화소수가 적기 때문에 시험해 보았다.

메커니즘





ESP8266 측



사용하고 있는 보드는 HSES-NODE-OLED, 회로도도 포함한 기술 정보도 공개하고 있으므로 자세한 것은 제품 페이지를 참조해 받고 싶다.

ESP8266 측에서는, udp 패킷을 수신하고, 포함되는 화상 데이터를, 그대로 OLED에 보내는 프로그램이 움직이고 있다. 이미지 데이터의 포맷은 OLED의 데이터 포맷 그대로이다. 1화면분의 사이즈는 128 x 64/8 = 1024byte 가 되어, udp 패킷 1개로 보낼 수 있다.

sketch_netOLED.ino의 일부

void loop()
{
  if(udp.parsePacket()){
    PacketHeader h;
    int len = udp.read((uint8_t *)&h, sizeof(h));

    if(len < sizeof(h)){
      Serial.printf("Bad length:%d\n",len);
    } else {
      while(udp.available()){
        uint8_t buf[1024];
        int len = udp.read(buf, sizeof(buf));
        oled.writeData(buf, len);
      }
    }
  }
}

PC측



PC측에서는 동영상의 파일을 읽어들여, 일정 주기로 udp 패킷을 송출하는 dispImage.py라고 하는 python의 프로그램이 움직이고 있다. 이것을 다음과 같이 시작하십시오.
$ python dispImage.py -r 30 192.168.0.136 ba_bmp/ba*.bmp

-r 30은 30fps로 이미지를 보내는 지정, 192.168.0.136은 esp8266 기판의 IP 주소, ba_bmp/ba*.bmp는 표시하는 이미지 파일로, 이번에는 Bad Apple 그림자 (니코 니코 동영상, YouTube) 파일을 ffmpeg로 1프레임씩 bmp파일로 변환한 것을 사용했다.

파이썬 라이브러리



Python의 이미지 처리 라이브러리 PIL(Pillow)의 Image 객체에서 128x64dot 흑백 OLED 데이터 포맷으로 변환하는 라이브러리를 준비했다. Image 모드의 변환이나 사이즈의 조정 처리를 제외하면, 아래와 같이 된다
    def make_img_data(self, im, w = 128, h = 64):
        px = im.load()
        bdata = b''
        for page in range(int(h/8)):
            for x in range(w):
                d = 0
                for i in range(8):
                    b = px[x,page*8+i]
                    if b: 
                        d += 1 << i
                bdata += struct.pack('B',d)
        return bdata 

그리고는, 약간의 헤더를 추가해, udp로 보낼 뿐.
    def send_data(self,bdata,frame):
        sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        with closing(sock):
            msg = b'HSESNODE'
            msg += struct.pack('I', frame)
            msg += bdata
            sock.sendto(msg, (self.host, self.port))

    def send_img(self, img, frame = 0):
        self.send_data(self.make_img_data(img), frame)

이미지 파일 준비



이미 쓴 대로 이번에는 동영상 파일을 ffmpeg로, 프레임마다 bmp 파일로 변환해 표시시키고 있다.
이 때, 사이즈의 변환, 종횡비를 보존하기 위한 패딩의 추가 등도 실시하고 있다.
명령줄은 다음과 같습니다.
$ ffmpeg -i bad_apple_mono.mp4 -vf pad=768:384:128:0 -s 128x64 -r 30 -y ba_bmp/ba%04d.bmp

동기화 처리



Windows나 Linux등의 멀티태스킹 OS로, 동영상의 재생과 같은 1정 주기로 실시하는 처리를, 어떻게 할 수 있으면 좋을지 몰랐지만, 어쨌든 처리의 지연이 누적되지 않도록 아래와 같은 프로그램으로 시험해 보았는데, 잘 갔다. 촬영 후 편집으로 Bad Apple의 음성을 합성했지만, 소리 어긋남은 전혀 일어나지 않았다.

dispImage.py의 일부

for file in args['<img_file>']:
    wait = start + period - time.time();
    start += period
    if verbose:
      print(file,wait)
    if(wait > 0):
        im = Image.open(file)
        oled.send_img(im)
        time.sleep(wait)

동작 동영상



표시 데모 프로그램 dispDemo.py의 동영상, Bad Apple 전체를 카메라 고정 그대로 촬영한 동영상도 작성했으므로, 링크를 붙인다.
  • 동영상: NetOLED dispDemo.py 실행 비디오 (youtube)
  • 동영상: ESP8266 + OLED로 Bad Apple 정식 버전 (youtube) (음주의)






  • 마지막으로


  • ESP8266 + OLED로 충분히 고속으로 표시할 수 있는 것을 알았다.
  • 파이썬으로 동영상 재생과 같은 1 정주기 처리를 할 수 있었다.
  • 흑백이지만, 128x64의 해상도가 있으므로, 좀 더 재미있는 표시를 모색해 보고 싶다.
  • 좋은 웹페이지 즐겨찾기