microbit
micropython

micro:bit で数をそろばん形式に表現してみる

概要

micro:bitで数値をそろばん形式で表現してみました。
最大5桁(正の整数だと0~99999)まで表現することができます。

背景

micro:bitは中心にLEDが5行5列に並んでいて、それを個別に光らせることで文字などを表現しています。5dot x 5dotの画像と同じで、サイズが小さすぎて通常画面に1文字しか入りません。
数字を2桁以上表示させたい場合は、スクロールして表示させますが、最後まで見ないと何桁なのか分からず不便です。たまたま「micro:bitでつくってみよう!コンテスト」があり、子供と話していたらそろばん形式で表現させたらどうかと提案があったので作ってみました。

作成したモノ

micro:bitは開発言語として「Blocks」「JavaScript」「MicroPython」が使用できますが、
個人的にPython勉強中なので「MicroPython」を使用してみました。

from microbit import *

counter = 0
old_counter = ["-1", "-1", "-1", "-1", "-1"]

# disp_mode
#  0 : soroban
#  1 : digit
disp_mode = 0
old_disp_mode = 0

# light level
light_lv_top_on     = 9
light_lv_top_off    = 2
light_lv_bottom_on  = 6
light_lv_bottom_off = 0

def DipsNumSoroban(i_num):
  if i_num >= 100000:
    display.scroll("Error: The digit is too large.")
    return

  num_string = str(i_num)
  num_string = "0" * (5 - len(num_string)) + num_string

  for i in range(5):
    if old_counter[4 - i] != num_string[4 - i]:
      DispDigSoroban(num_string[4 - i], 4 - i)
      old_counter[4 - i] = num_string[4 - i]


def DispDigSoroban(i_digit: str, i_pos_x: int):
  digit = int(i_digit)
  pos_x = int(i_pos_x)

  if digit >= 5:
    display.set_pixel(pos_x, 0, light_lv_top_on)
    digit -= 5
  else:
    display.set_pixel(pos_x, 0, light_lv_top_off)

  if digit >= 1:
    display.set_pixel(pos_x, 1, light_lv_bottom_on)
  else:
    display.set_pixel(pos_x, 1, light_lv_bottom_off)

  if digit >= 2:
    display.set_pixel(pos_x, 2, light_lv_bottom_on)
  else:
    display.set_pixel(pos_x, 2, light_lv_bottom_off)

  if digit >= 3:
    display.set_pixel(pos_x, 3, light_lv_bottom_on)
  else:
    display.set_pixel(pos_x, 3, light_lv_bottom_off)

  if digit == 4:
    display.set_pixel(pos_x, 4, light_lv_bottom_on)
  else:
    display.set_pixel(pos_x, 4, light_lv_bottom_off)

'''
Main Loop
'''
while True:
  if button_a.is_pressed() and button_b.is_pressed():
    # Switch DispMode Soroban <-> Digit
    display.show(Image.YES)
    disp_mode ^= 1
    bit_wait = 0
    sleep(1000)
  else:
    # Count Up or Down
    if button_a.is_pressed():
      if bit_wait < 100:
        # Wait for button A & B simultaneously press
        bit_wait += 1
        continue

      counter += 1

      if is_pressing == False:
        # Detect one click.
        sleep(200)
        is_pressing = True

    elif button_b.is_pressed():
      if bit_wait < 100:
        # Wait for button A & B simultaneously press
        bit_wait += 1
        continue

      counter -= 1

      if is_pressing == False:
        # Detect one click.
        sleep(200)
        is_pressing = True
    else:
      bit_wait = 0
      is_pressing = False

  # Loop Number Max<->Min
  if counter < 0:
    counter = 99999
  elif counter > 99999:
    counter = 0

  if disp_mode == 0:
    DipsNumSoroban(counter)
    if old_disp_mode != disp_mode:
      old_disp_mode = disp_mode
      sleep(1000)
  else:
    display.scroll(str(counter))
    old_counter = ["-1", "-1", "-1", "-1", "-1"]
    sleep(1000)

デモ動画

https://youtu.be/xzM--RKJMqI

雑感など

動かしてみると、大きな数値を読むこと以外に、変化速度が伝わりやすいなと思いました。
単純に「高速に点滅する」=「変化が激しい」という感じです。

初期状態で5珠の位置(Y=0の行)を薄く光らせているのは、暗がりに見たときに桁が分かりやすいかと思ったためです。あと、今対応していないですが、左右2桁づつに分けて2つ数を表現させたい場合、切れ目の部分を消灯させてそれと判定できればという含みもあります。

時間がかかったのは、micro:bitのボタン制御です。ABボタン同時押しで数字の表示形式を変えるようにしたのですが、微妙に押すタイミングがズレたりすると、1回押しと判定され、カウントが変わっちゃったり。あと、1回押しと、押しっぱなしの判定もうまくいかず。ボタンを連打すると、押しっぱなしと判定される場合があり。。。何かうまい方法ご存知の方は教えていただけると嬉しいです。

ボタンの判定について、以下記事で書きました
https://qiita.com/tagetage3/items/c48bab0bb8f614b7af4a

ボタン判定を修正したソースは以下にあります
https://github.com/soramaru777/DispNumSoroban/blob/master/DispNumSoroban1.py

変数の名前やスコープやもろもろ気になるところありますが、あとで暇なとき整理します。。

リンク

micro:bit - 日本公式サイト
http://microbit.org/ja/

「micro:bitでつくってみよう!コンテスト」
http://makezine.jp/blog/2018/04/microbitcontest2018.html

MicroPython - micro:bit
http://microbit-micropython.readthedocs.io/ja/latest/

デモ動画
https://youtu.be/xzM--RKJMqI

以上です。
何か参考になるところがあれば幸いです。