疑似コンソール
2021.03.06
YouTube でも紹介しています。画像をクリックすると再生できます。
今回は、Adafruit 1.3" Color TFT Bonnet for Raspberry Pi を Raspberry Pi Zero WH の疑似コンソールとして使用します。
このLCDを、システムコンソールとして設定することも可能ですが、カーネルドライバーを書き換えてしまうため、元に戻すのが面倒です。
そこで、Pythonアプリケーションからシステムコンソールのように使えるライブラリーを作成します。

Pimoroni のサイトを散策していたときのことです。普段、アクセスすることのない「Gaming & Arcade」のカテゴリーを間違ってぽちっとしてしまい、運よく発見しちゃいました!
ちなみに、画面右側に写っている「Pico Explorer Base」もお買い上げです!

「ボタンとジョイスティックを備えたコンパクトなカラーディスプレイが必要なあなたにぴったりの商品です」と書かれているではありませんか。
システムコンソールを探していたのですが、このデザインの美しさ!買わないわけにはいきません!ぽちっ!
■とても美しい外観

フロントデザインです。

当然の事なのですが、背面には2x20ピンの Raspberry Pi connector が配置されています。
システムコンソールとして使用した場合です。
■Pinouts

・5.0V - Connected to the display backlight
・3.3V - Connected to the display power and also the STEMMA QT / Qwiic connector
・GND - Ground for everything
・SDA & SCL - I2C data for the STEMMA QT / Qwiic connector. Not used by buttons or display
・GPIO26 - Used to turn the backlight on and off.
・GPIO5 & GPIO6 - Connected to the two front buttons. These pins have 10K pullups to 3.3V so when the button is pressed, you will read a LOW voltage on these pins
・GPIO17, GPIO22, GPIO27, GPIO23 - The four directions on the joystick.
・GPIO4 - Joystick center button.
・SCK, MOSI, CE0 & GPIO25 - These are the display control pins. Note that MISO is not connected even though it is a SPI pin because you cannot read back from the display.
・Not used: GPIO12, GPIO13, GPIO16, GPIO19, GPIO20, GPIO21, GPIO18, GPIO24, TXD, RXD, EEDATA, EECLK, MISO, SPI_CE1
■SPIの有効化
$ sudo vi /boot/config.txt
dtparam=spi=on
■動作環境の整備
Adafruit TFT Bonnet のセットアップは下記のようになっています。
Ref.Python Setup
$ sudo pip3 install adafruit-circuitpython-rgb-display
$ sudo apt-get install python3-pip
$ sudo apt-get install ttf-dejavu
$ sudo apt-get install python3-pil
$ sudo apt-get install python3-numpy
※今回はインストールしていません。

→ What is CircuitPython?
Adafruit では実行環境に microPython系の CircuitPython を利用してします。
しかし、これを使うと、汎用性が低下してしまうので、標準の ST7789ライブラリーを用いることにします。
Pimoroni 1.3" SPI LCDのサンプルコードを参考にしました。
PIMORONI 1.3" SPI Colour LCD (240x240) Breakout

AdafruitとPimoroniのLCDで使用するピン番号をみてみました。
| No | Adafruit | Description | Pimoroni |
| 3.3V | 1 | display backlight | 1 |
| 5V | 2 | display power | 2 |
| GND | 6 | | 6 |
| SPI_MOSI | 19(BCM10) | display control | 19(BCM10) |
| SPI_SCLK | 23(BCM11) | display control | 23(BCM11) |
| TFT_DC | 22(BCM25) | display control | 21(BCM9) |
| TFT_CS | 24(CE0/BCM8) | display control | 26(CE1/BCM7) |
| TFT_LITE | 37(BCM26) | backlight on and off | 35(BCM19) |
DCとCSおよびbacklightのピン番号が異なっていることがわかります。
※ジョイスティックやボタンの機能は省いています。
まずは、ST7789ディスプレイドライバ用のモジュールをインストールします。
$ sudo pip3 install st7789
Raspberry Pi OS であれば、st7789 が依存するモジュールはすでにインストール済と思われますが、
必要なら、追加インストールしてください。
$ sudo pip3 install pillow
$ sudo pip3 install numpy
$ sudo pip3 install RPI.GPIO
$ sudo pip3 install spidev

scrolling-text.py
先に示した対応表を参考に、Pimoroniで使用しているピン番号から、Adafruit用にピン番号を書き換えます。
disp = ST7789.ST7789(
port=0,
cs=ST7789.BG_SPI_CS_FRONT,
dc=9,
backlight=19,
spi_speed_hz=80 * 1000 * 1000
)
↓変更
disp = ST7789.ST7789(
port=0,
cs=ST7789.BG_SPI_CS_BACK,
dc=25,
backlight=26,
spi_speed_hz=80 * 1000 * 1000
)
ST7789.BG_SPI_CS_FRONT は CE1 の指定なので、ST7789.BG_SPI_CS_BACK に変更して CE0 に変更します。
Source code
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
import time
import ST7789
MESSAGE = "Hello World! How are you today?"
# Create ST7789 LCD display class.
disp = ST7789.ST7789(
port=0,
cs=ST7789.BG_SPI_CS_BACK, # BG_SPI_CS_BACK or BG_SPI_CS_FRONT
dc=25,
backlight=26, # 18 for back BG slot, 19 for front BG slot.
spi_speed_hz=80 * 1000 * 1000
)
# Initialize display.
disp.begin()
WIDTH = disp.width
HEIGHT = disp.height
img = Image.new('RGB', (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 30)
size_x, size_y = draw.textsize(MESSAGE, font)
text_x = disp.width
text_y = (80 - size_y) // 2
t_start = time.time()
while True:
x = (time.time() - t_start) * 100
x %= (size_x + disp.width)
draw.rectangle((0, 0, disp.width, 80), (0, 0, 0))
draw.text((int(text_x - x), text_y), MESSAGE, font=font, fill=(255, 255, 255))
disp.display(img)
実行してみましょう。
$ python3 scrolling-text.py

動作確認ができたので、次に疑似コンソール用ライブラリーを作成していきます。
■等幅フォントの確認
システムで利用可能な等幅フォントを確認します。
$ fc-match monospace
LiberationMono-Regular.ttf: "Liberation Mono" "Regular"
フォントの場所は下記の通りです。
/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf
他の等幅フォントを利用したい場合は、適時インストールしてください。
■リングバッファ

File:Ring.buffer.svg - Wikimedia Commons
リングバッファは、予め記憶領域を確保して、読み出し位置と書き込み位置をずらしながら処理を行い、領域の終端に到達したら、領域の先頭に繋げ無限ループ的に利用する仕組みです。
C言語などで開発する場合は、ポインターを使って、テキスト文字列を上書きしていけば済むのですが、Pythonではそういう使い方はできません。
コーディング的に美しくないのですが、リストを使ってリングバッファーっぽいものを実装します。
1.LCDの描画サイズを取得します
disp.begin()
pixel_x = disp.width
pixel_y = disp.height
2.等幅フォントのサイズを取得します
font = ImageFont.truetype("/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf",14)
size_x, size_y = self.draw.textsize("F", font=font)
3.LCDサイズとフォントサイズから1行に表示できる桁数と行数を算出します
col = pixel_x // size_x
row = pixel_y // size_y
4.表示したい文字列を桁数で分割して、複数の配列要素として保存します
line_len = len(msg)
line_num = line_len//col
line_rest = line_len % col
line_from = 0
line_to = col
while line_num > 0:
buffer[pos] = msg[line_from:line_to]
line_from += col
line_to += col
pos += 1
line_num -= 1
if line_rest > 0:
buffer[pos] = msg[line_from:line_len]
pos += 1
5.表示行数未満の場合は、リストの先頭要素から、LCDに描画します
pos_y = 0
draw.rectangle((0, 0, disp.width, disp.height), (0, 0, 0))
for i in range(row):
draw.text((0,pos_y), buffer[start], font=font, fill=(255, 255, 255))
start += 1
pos_y += size_y
if start == row:
start = 0
disp.display(img)
6.再度、表示文字列を追加する場合は、直前に保存した次の配列要素に追加します
この際、配列が末尾に到達した場合には配列の先頭要素から書き換えます
7.更新した配列要素数に応じてリストの途中から循環する形で、LCDを再描画します
6, 7 に関しては短いコードなので、下記のソースを解析してみてください。
疑似コンソール Source code
from PIL import Image, ImageDraw, ImageFont
import ST7789
class Console:
def __init__(self):
# Create ST7789 LCD display class.
self.disp = ST7789.ST7789(
port=0,
cs=ST7789.BG_SPI_CS_BACK,
dc=25,
backlight=26,
spi_speed_hz=80 * 1000 * 1000
)
# Initialize display.
self.disp.begin()
self.pixel_x = self.disp.width
self.pixel_y = self.disp.height
self.img = Image.new('RGB', (self.pixel_x, self.pixel_y), color=(0, 0, 0))
self.draw = ImageDraw.Draw(self.img)
self.size_x, self.size_y = self.getFontSize()
self.col = self.pixel_x // self.size_x
self.row = self.pixel_y // self.size_y
self.buffer = ["" for _ in range(self.row)]
self.pos = 0
self.start = 0
self.scroll = False
def getFontSize(self,fontName=None, fontSize=None):
if fontName is None:
self.font = ImageFont.truetype("/usr/share/fonts/truetype/liberation2/LiberationMono-Regular.ttf",14)
else:
self.font = ImageFont.truetype(fontName, fontSize)
self.size_x, self.size_y = self.draw.textsize("F", font=self.font)
return self.size_x, self.size_y
def print(self, msg):
line_len = len(msg)
line_num = line_len//self.col
line_rest = line_len % self.col
line_from = 0
line_to = self.col
while line_num > 0:
if self.scroll:
self.start += 1
if self.start == self.row:
self.start = 0
self.buffer[self.pos] = msg[line_from:line_to]
line_from += self.col
line_to += self.col
self.pos += 1
if self.pos == self.row:
self.pos = 0
self.scroll = True
line_num -= 1
if line_rest > 0:
if self.scroll:
self.start += 1
if self.start == self.row:
self.start = 0
self.buffer[self.pos] = msg[line_from:line_len]
self.pos += 1
if self.pos == self.row:
self.pos = 0
self.scroll = True
pos_y = 0
self.draw.rectangle((0, 0, self.disp.width, self.disp.height), (0, 0, 0))
for i in range(self.row):
self.draw.text((0,pos_y), self.buffer[self.start], font=self.font, fill=(255, 255, 255))
self.start += 1
pos_y += self.size_y
if self.start == self.row:
self.start = 0
self.disp.display(self.img)
使用する場合は、RingBuffer.py をカレントディレクトリーに置いて下記のように呼び出します。
文字列の描画位置を意識することなしに利用できます。
from RingBuffer import Console
cs = Console()
cs.print(message1)
cs.print(message2)
・・・・・
ソースコードにちょっと手を加えるとこんな感じになります。

メッセージ単位で交互に色分けして表示しています。
このコンソール機能は、Twelite Neural Network 第2回で使用する予定です。
■参考文献
・等幅フォント
・Raspberry Pi(stretch)フォント設定 noto font
・ラズパイでフレームバッファ(/dev/fb0)を使用して、直接ディスプレイ画像を入出力する
・【 fc-match 】コマンド――フォントのマッチングと優先順位を確認する
・原色大辞典
|
Raspberry Pi(ラズベリー パイ)は、ARMプロセッサを搭載したシングルボードコンピュータ。イギリスのラズベリーパイ財団によって開発されている。
たいていのことは100日あれば、うまくいく。長田英知著
「時間がなくて、なかなか自分のやりたいことができない」
「一念発起して何かを始めても、いつも三日坊主で終わってしまう」
「色んなことを先延ばしにしたまま、時間だけが過ぎていく」
そこで本書では、そんな著者が独自に開発した、
まったく新しい目標達成メソッド「100日デザイン」について、
その知識と技術を、余すところなくご紹介します。
まんがで納得ナポレオン・ヒル 思考は現実化する
OLとして雑務をこなす日々に飽き足らず、科学者だった父が残した薬品を商品化すべく、起業を決意した内山麻由(27)。彼女はセミナーで知り合った謎の女性からサポートを得ながら、彼女と二人三脚でナポレオン・ヒルの成功哲学を実践し、さまざまな問題を乗り越えていく。
ヒル博士の<ゴールデンルール>に従い、仕事に、恋に全力疾走する彼女の、成功への物語。
今日は人生最悪で最高の日 1秒で世界を変えるたったひとつの方法 ひすいこたろう著
偉人の伝記を読むと、最悪な日は、不幸な日ではなく、新しい自分が始まる日であることがわかります。最悪な出来事は、自分の人生が、想像を超えて面白くなる兆しなのです。偉人伝を読むことで、このときの不幸があったおかげで、未来にこういう幸せがくるのかと、人生を俯瞰する視線が立ち上がるのです。
ご飯は私を裏切らない heisoku著
辛い現実から目を背けて食べるご飯は、いつも美味しく幸せを届けてくれる。
29歳、中卒、恋人いない歴イコール年齢。バイト以外の職歴もなく、短期バイトを転々とする日々。ぐるぐると思索に耽るけど、ご飯を食べると幸せになれる。奇才の新鋭・heisokuが贈るリアル労働グルメ物語!
【最新版Gemini 3に対応!】できるGemini (できるシリーズ)
Geminiを「最強の知的生産パートナー」として使いこなすための、実践的なノウハウを凝縮した一冊です。
基本的な操作方法から、具体的なビジネスシーンでの活用、日々の業務を自動化するGoogle Workspaceとの連携、さらには自分だけのオリジナルAIを作成する方法まで余すところなく解説します。
Rustプログラミング完全ガイド 他言語との比較で違いが分かる!
Rustの各手法や考え方を幅広く解説!
500以上のサンプルを掲載。実行結果も確認。
全24章の包括的なチュートリアル。
ポチらせる文章術
販売サイト・ネット広告・メルマガ・ブログ・ホームページ・SNS…
全WEB媒体で効果バツグン!
カリスマコピーライターが教える「見てもらう」「買ってもらう」「共感してもらう」すべてに効くネット文章術
小型で便利な Type-C アダプター USB C オス - USB3.1 オスアダプター
Type-C端子のマイコンボードをこのアダプタを介して直接Raspberry Piに挿すことができます。ケーブルなしで便利なツールです。
Divoom Ditoo Pro ワイヤレススピーカー
15W高音質重低音/青軸キーボード/Bluetooth5.3/ピクセルアート 専用アプリ/USB接続/microSDカード
電源供給USBケーブル スリム 【5本セット】
USB電源ケーブル 5V DC電源供給ケーブル スリム 【5本セット】 電源供給 バッテリー 修理 自作 DIY 電子工作 (100cm)
|