Help us understand the problem. What is going on with this article?

電子ペーパーモジュール入門

はじめに

既製品を組み合わせてなるべく短時間で、
電子ペーパーに表示する内容をカスタマイズ可能なプロトタイプを作成することを目的とします。
あくまでプロトタイプなので、費用やオペレーションコストについては考えません。

用意するもの

Raspberry Pi WH Zero WH

1

似たような製品にRaspberry Pi Zero Wがあります。
Raspberry Pi Zero WHRaspberry Pi Zero Wにピンヘッダが実装されたモデルです。
はんだごてをお持ちでない方にはRaspberry Pi Zero WHをお勧めします。
スイッチサイエンスさんから購入できます。
Raspberry Pi Zero WH - スイッチサイエンス

2.7インチ 264×176 E-Ink 赤/黒/白 3色 電子ペーパーモジュール for RaspberryPi

2

秋葉原の千石電商さんでも購入できます。
ディスプレイのサイズ・色数のバリエーションがあります。
今回は2.7inch/赤・黒・白のモデルを選択しました。
千石電商さんから購入できます。
WaveShare 13357 2.7インチ 264×176 E-Ink 赤/黒/白 3色 電子ペーパーモジュール for RaspberryPi

microSDカード/microUSB端子に対応した電源

Rapsberry Piを使うなら必須のアイテム。
microSDカードは容量が8GB以上のものを使いましょう。
電源は1.2A以上の給電能力が必要です3

(オプショナル)キーボード/miniHDMIケーブル

sshを使わない場合に必要になります。

Raspberry Pi Zero WHをセットアップする

OSはこちらからダウンロードできます。
OSは執筆時点(2020/03/28)で最新のRaspibian Buster Liteを採用しました。

microSDにOSを書き込む手順は「Raspberry Pi セットアップ」などのキーワードで検索していただければ日本語の記事がヒットします。
公式からインストールガイドも公開されていますので載せておきます。
Installing operating system images - Raspberry Pi Documentation

ディスプレイに繋ぐのが面倒な人は、この設定をしておくと初期設定のためにディスプレイに接続する必要がなくなります。
Raspberry Piの無線LANをmicroSDで設定する - Qiita

電子ペーパーモジュールとRaspberry Pi Zero WHを接続する

こんな風に接続します。

別角度から。

サンプルコードを実行する

WaveShare社が公開している公式Wikiの通りに作業します。

ターミナルを開き、以下のコマンドを実行してください。

sudo raspi-config

すると設定画面が表示されます。
「Interfacing Options」を選択、
→「SPI」を選択、
→「Yes」を選択してください。
4

以下のコマンドを実行して再起動します

sudo reboot

必要なライブラリをインストールします。

# install bcm2835 libraries
wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.60.tar.gz
tar zxvf bcm2835-1.60.tar.gz 
cd bcm2835-1.60/
sudo ./configure
sudo make
sudo make check
sudo make install

# install wiringPi libraries
sudo apt-get install wiringpi

# install Python3 libraries
sudo apt-get update
sudo apt-get install python3-pip
sudo apt-get install python3-pil
sudo apt-get install python3-numpy
sudo pip3 install RPi.GPIO
sudo pip3 install spidev

WaveshareさんがGitHubで公開しているリポジトリをクローンします。

sudo git clone https://github.com/waveshare/e-Paper

サンプルコードのあるディレクトリに移動して実行してみましょう。

cd e-Paper/RaspberryPi\&JetsonNano/python/examples
sudo python3 epd_2in7b_test.py

実行時の様子は動画にしましたので、こちらをご覧ください。2分ぐらいあります。
epd_2in7b_test.py

サンプルコード5をみてみましょう。

epd_2in7b_test.py
#!/usr/bin/python
# -*- coding:utf-8 -*-
import sys
import os
picdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'pic')
libdir = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'lib')
if os.path.exists(libdir):
    sys.path.append(libdir)

import logging
from waveshare_epd import epd2in7b
import time
from PIL import Image,ImageDraw,ImageFont
import traceback

logging.basicConfig(level=logging.DEBUG)

try:
    logging.info("epd2in7b Demo")

    epd = epd2in7b.EPD()
    logging.info("init and Clear")
    epd.init()
    epd.Clear()
    time.sleep(1)

    # Drawing on the image
    logging.info("Drawing")
    blackimage = Image.new('1', (epd.width, epd.height), 255)  # 255: clear the frame
    redimage = Image.new('1', (epd.width, epd.height), 255)  # 255: clear the frame

    font24 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 24)
    font18 = ImageFont.truetype(os.path.join(picdir, 'Font.ttc'), 18)


    # Drawing on the Horizontal image
    logging.info("1.Drawing on the Horizontal image...")
    HBlackimage = Image.new('1', (epd.height, epd.width), 255)  # 298*126
    HRedimage = Image.new('1', (epd.height, epd.width), 255)  # 298*126    

    drawblack = ImageDraw.Draw(HBlackimage)
    drawred = ImageDraw.Draw(HRedimage)
    drawblack.text((10, 0), 'hello world', font = font24, fill = 0)
    drawblack.text((10, 20), '2.9inch e-Paper', font = font24, fill = 0)
    drawblack.text((150, 0), u'微雪电子', font = font24, fill = 0)    
    drawblack.line((20, 50, 70, 100), fill = 0)
    drawblack.line((70, 50, 20, 100), fill = 0)
    drawblack.rectangle((20, 50, 70, 100), outline = 0)    
    drawred.line((165, 50, 165, 100), fill = 0)
    drawred.line((140, 75, 190, 75), fill = 0)
    drawred.arc((140, 50, 190, 100), 0, 360, fill = 0)
    drawred.rectangle((80, 50, 130, 100), fill = 0)
    drawred.chord((200, 50, 250, 100), 0, 360, fill = 0)
    epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRedimage))
    time.sleep(2)

    # Drawing on the Vertical image
    logging.info("2.Drawing on the Vertical image...")
    LBlackimage = Image.new('1', (epd.width, epd.height), 255)  # 126*298
    LRedimage = Image.new('1', (epd.width, epd.height), 255)  # 126*298
    drawblack = ImageDraw.Draw(LBlackimage)
    drawred = ImageDraw.Draw(LRedimage)

    drawblack.text((2, 0), 'hello world', font = font18, fill = 0)
    drawblack.text((2, 20), '2.9inch epd', font = font18, fill = 0)
    drawblack.text((20, 50), u'微雪电子', font = font18, fill = 0)
    drawblack.line((10, 90, 60, 140), fill = 0)
    drawblack.line((60, 90, 10, 140), fill = 0)
    drawblack.rectangle((10, 90, 60, 140), outline = 0)
    drawred.line((95, 90, 95, 140), fill = 0)
    drawred.line((70, 115, 120, 115), fill = 0)
    drawred.arc((70, 90, 120, 140), 0, 360, fill = 0)
    drawred.rectangle((10, 150, 60, 200), fill = 0)
    drawred.chord((70, 150, 120, 200), 0, 360, fill = 0)
    epd.display(epd.getbuffer(LBlackimage), epd.getbuffer(LRedimage))
    time.sleep(2)

    logging.info("3.read bmp file")
    HBlackimage = Image.open(os.path.join(picdir, '2in7b-b.bmp'))
    HRedimage = Image.open(os.path.join(picdir, '2in7b-r.bmp'))
    epd.display(epd.getbuffer(HBlackimage), epd.getbuffer(HRedimage))
    time.sleep(2)

    logging.info("4.read bmp file on window")
    blackimage1 = Image.new('1', (epd.height, epd.width), 255)  # 298*126
    redimage1 = Image.new('1', (epd.height, epd.width), 255)  # 298*126    
    newimage = Image.open(os.path.join(picdir, '100x100.bmp'))
    blackimage1.paste(newimage, (50,10))    
    epd.display(epd.getbuffer(blackimage1), epd.getbuffer(redimage1))

    logging.info("Clear...")
    epd.init()
    epd.Clear()

    logging.info("Goto Sleep...")
    epd.sleep()

except IOError as e:
    logging.info(e)

except KeyboardInterrupt:    
    logging.info("ctrl + c:")
    epd2in7b.epdconfig.module_exit()
    exit()

電子ペーパーに表示したい内容はPillowのImageオブジェクトで渡してあげればいいことがわかります。
epd.getbuffer()の第一引数には黒で描画したいイメージを、第二引数には赤で描画したいイメージを指定します。

epd.display(epd.getbuffer(LBlackimage), epd.getbuffer(LRedimage))

カスタマイズしてみた

e-tag.jpg

日本語フォントを使うにはImageFontでフォントファイルを読み込みます。

ImageFont Module — Pillow (PIL Fork) 7.0.0 documentation

附録

費用

項目 金額
電子ペーパーモジュール ¥2,590
Raspberry Pi Zero WH ¥1,848
microSDカード 16GB ¥800

microSDカードは価格幅が広いので参考程度に。
合計すると¥5,300ぐらいです。
ここには含めませんでしたが、電源も必要です。

消費電力

公式サイトのFAQをみるとRaspberry Pi Zero WHの平常時の消費電流は0.15Aです。
電源が近くにないような場面ではモバイルバッテリーによる電力供給も考えられますが、
何時間稼働させられるんでしょうか?

Pi Zero Wはモバイルバッテリーでどのくらいの時間動作するか
↑こちらの記事によると、

5200mAhのバッテリーで、Pi Zero W本体のみ動作した時間は28時間42分

と書かれています。たかだか1日しか稼働させられないので用途は限られますね。

別の選択肢として、公式からPoE HATが発売されています。
ただし、対応するモデルはRaspberry Pi 4 Model BとRaspberry Pi 3 Model B+のみです。
これを接続すればイーサネットケーブルで給電できます。

電子ペーパーモジュール使用上の注意

目を通すのを忘れがちなユーザマニュアルに大事なことが書いてあったので一部抜粋して掲載します。
公式ユーザマニュアル

The e-Paper cannot be powered on for long time, you must set e-Paper to sleep mode or power off when it needn’t refresh, otherwise, e-Paper keeps in high voltage status for long time, which will damage e-Paper and cannot be fixed.

電子ペーパーに電圧をかけた状態をキープすると、電子ペーパーがダメージを受けるのでスリープを設定してください。

We suggest you update e-Paper once every 24 hours or at least 10 days to update again. Otherwise, ghost of the last content may cannot be cleared.

毎日1回、最低でも10日に1回は電子ペーパーを更新することを推奨します。
そうしないと、ゴーストが生じる恐れがあります。

The e-Paper cannot refresh directly under sunlight. The refresh steps should be
done indoor

電子ペーパーは日光のあたるところでリフレッシュできません。リフレッシュは屋内でするようにしてください。

NFC対応電子ペーパー

Waveshareさんから電源不要でNFCで表示切替できる製品が発売されています。
4.2inch Passive NFC-Powered e-Paper, No Battery, Wireless Powering & Data Transfer

ryosukeeeee
iOSとかPythonとかraspberry PiとかAWSとか
hands-lab
ハンズラボは小売業特化型ITソリューション企業です。数十万に及ぶ膨大な商品マスタを扱ってきた豊富なノウハウで、お客様の現場に最適なシステムを提案・開発します。 エンジニア募集中
https://www.hands-lab.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした