CircuitPythonの紹介

144Labの入江田です。

https://tech.144lab.com/entry/papyr にも書きましたが、 最近、CircuitPythonをいろんなデバイスで試しています。

CircuitPythonリポジトリ

f:id:irieda:20191001171911p:plain

なぜCircuitPythonは作られたの?

組み込み向けPythonとしてpython-on-a-chipを始めとしてMicroPythonという歴史ある実装があるにもかかわらずMicroPythonをフォークしてCircuitPythonは生まれました。

CircuitPythonはボードベンダであるAdafruitが作りました。 Adafruitは自社製品向けに調整済みのCircuitPythonをリリースすることで より教育に優しいPythonによる開発環境を提供していく考えのようです。

  • これまでの類似製品よりもより組み込み初心者をターゲットにしています
  • ドキュメンテーションの一元化で初心者への教育に優しい
  • ボードサポートやドライバーの関係を単純化しサポートボードの追加を効率化しました
  • USBマスストレージ疑似ファイルシステム経由で開発できるものを中心にサポートボードを強化していきます
  • ATSAMDシリーズおよびUSBサポート付きマイコンへの対応を強化、AdafruitのExpressシリーズなどがそれに該当します
  • シリアル経由でコードを書き込む(ampyサポート)しかないものは順次廃止(v4にてESP8266サポートは廃止されました)

要するにつまづきにくいPython開発環境を提供することにフォーカスしたMicroPythonの派生バージョンということなのです。

CircuitPythonはなにが嬉しいの?

  • Arduino以前の組み込み開発ってどうしても面倒なところがなくせなかった
    • マイコンごとに電話帳のようなスペックシートを片手に開発
    • 似て異なる部分が山のようにあるのでパターンのように見えて実際は細かい調整を開発者ごとに手でやっていた
    • マイコンターゲット、ボード、デバッガ、開発環境、開発言語処理系が別々のベンダが提供していてバラバラのドキュメントを読み合わせる必要があった
    • 必要な場合、専用OS、SDKミドルウェア、ドライバーも別ドキュメント
  • ArduinoはボードにArduinoCoreブートローダーさえ入っていてシリアルポートドライバーさえあればあとは全部用意してくれたのが画期的だった
  • MycroPythonはArduinoの利点に加えて疑似ファイルシステム(以下「疑似FS」)を持ち、Python言語で書けるという利便性を提供します
  • CircuitPythonではさらにシリアルポートドライバーも不要でUSBストレージの形で疑似FSへのアクセス機能を提供します
    • ドキュメントはボード専用部分からCircuitPythonの使い方までをトータルでAdafruitのドキュメントで統一されてる
    • PythonコードをUSBストレージに見えるフォルダに投げ込むだけ
    • 開発環境は好みのエディタで十分
    • もちろんPython向け統合開発環境を使うのも良い
    • 複数ファイルを利用する際の関係性はPythonを学べば単純で理解しやすいし、それをほとんどそのまま疑似ファイルシステムに置くだけで動いちゃう
    • ボードサポートからチュートリアルまで一つのドキュメントサイトで追うことができます
    • BLEサポートを追加してきたので比較的容易にBLEアプリケーションが書けちゃう
    • また、AdafruitのGitHubリポジトリには豊富なドライバーやライブラリ、サンプルコードがあるのでとても参考になる

まとめると開発速度は

従来の組み込み開発手法 <<< Arduino << MicroPython < CircuitPython

といったところでしょうか。 カバーされているフィーチャーは

従来の組み込み開発手法(100%) > Arduino(90%) >>> MicroPython = CircuitPython

で、Python系では手続き的に書けるというところに主眼をおいたフィーチャーだけをサポートします。割り込み(DMAなど)や電源制御といったあたりはサポートしません。また、アウトプットの性能(パフォーマンス、省サイズともに)は

従来の組み込み開発手法 > Arduino > MicroPython = CircuitPython

こんな感じですね。足りない性能はワンランク上のマイコンをチョイスすることである程度カバーできます。

従来の組み込み開発手法の最大のメリットは苦労する代わりに「ターゲットマイコン選定の自由度に制約がない」というところですね。(もちろん不慣れなターゲットを選べばそれだけ苦労も増えるのですが)

入門のしやすさから評価されつつあって、すこしづつですが、サポートボードもAdafruitだけじゃなくなってきています。

https://circuitpython.org/downloads

SparkFun, Electronut Labsなどが参入しています。

CircuitPythonのコアモジュール構成

https://circuitpython.readthedocs.io/en/latest/shared-bindings/index.html

PC向けPythonと似た役割のモジュール

  • sys
  • os
  • time
  • math
  • random

ハード依存のモジュール

  • microcontroller
  • board

microcontrollerはマイコンチップ依存定義のモジュール。 boardはmicrocontrollerをベースにしたボード依存定義モジュール。

入出力用モジュール

  • digitalio
  • analogio
  • pulseio
  • frequencyio
  • bitbangio
  • busio
  • bleio
  • terminalio
  • displayio
  • fontio
  • etc...

bitbangiobusioは同じ目的でI2CやSPIバス機能のモジュールですが、前者はCPUパワーでバスエミュレーションし、後者はハードウェアサポートがある場合のみ利用可能です。

その他のモジュール

ここに周辺装置向けライブラリアーカイブがあります。 https://circuitpython.org/libraries

これらの必要なライブラリだけをターゲットの /lib/フォルダ配下に入れることで利用可能になります。

インタラクティブモード

接続方法

$ screen /dev/tty.usbserial#### 115200

コードが動作中ならCtrl+Cで止めれます。その時Enterキーを押すことでインタラクティブモードに入ることができます。

Auto-reload is on. Simply save files over USB to run them or enter REPL to disable.

Press any key to enter the REPL. Use CTRL-D to reload.
Adafruit CircuitPython 4.0.1 on 2019-05-22; SparkFun Pro nRF52840 Mini with nRF52840
>>> import sys
>>> sys.path
['', '/', '.frozen', '/lib']
>>> 

sys.pathを確認してもらえば、CIRCUITPYボリューム(ドライブ)のルートやその直下のlibフォルダがライブラリを探す対象になっていることが確認できます。 ちなみにfrozenというのはCircuitPythonの標準ライブラリをアーカイブしたものです。

サンプルを動かす

CircuitPythonは4.0.1安定版を前提にしています。

bleペリフェラルサンプル

CIRCUITPY/ble_sample.py

import bleio

# Create a Characteristic.
characteristic = bleio.Characteristic(bleio.UUID(0x2919), read=True, notify=True)

# Create a Service providing that one Characteristic.
service = bleio.Service(bleio.UUID(0x180F), [characteristic])

# Create a peripheral and start it up.
periph = bleio.Peripheral([service])

while True:
    periph.start_advertising()
    while not periph.connected:
        pass

    print("connected")

    while periph.connected:
        pass

    print("disconnected")
    periph.stop_advertising()

動作確認

インタラクティブモードで動作確認できます。

> import ble_sample

この状態でスマホからnRF Connectアプリ等でスキャン&接続してみたり切断してみたりすることができると思います。

便利なライブラリ

https://github.com/adafruit/Adafruit_CircuitPython_Bundle

リリースファイルページ にてライブラリとライブラリを使ったサンプルがあります。

CIRCUITPY/libフォルダを作成してその配下に必要なライブラリを入れておくと起動スクリプトからimport可能になります。

BME280デバイスをつないで環境センサデータを読み出す例 CIRCUITPY/lib/adafruit_bme280.mpyをおいておき、 以下のようなコードをおいておくと、 インタラクティブモードで動作確認できます。

CIRCUITPY/sample.py

import time
import board
import busio
import adafruit_bme280

i2c = busio.I2C(board.SCL, board.SDA)
bme280 = adafruit_bme280.Adafruit_BME280_I2C(i2c)
bme280.sea_level_pressure = 1013.25
bme280.mode = adafruit_bme280.MODE_NORMAL
bme280.standby_period = adafruit_bme280.STANDBY_TC_500
bme280.iir_filter = adafruit_bme280.IIR_FILTER_X16
bme280.overscan_pressure = adafruit_bme280.OVERSCAN_X16
bme280.overscan_humidity = adafruit_bme280.OVERSCAN_X1
bme280.overscan_temperature = adafruit_bme280.OVERSCAN_X2
time.sleep(1.0)

print("Temperature: %0.1f C" % bme280.temperature)
print("Humidity: %0.1f %%" % bme280.humidity)
print("Pressure: %0.1f hPa" % bme280.pressure)
print("Altitude = %0.2f meters" % bme280.altitude)

動作確認

> import sample
Temperature: 20.0 C
Humidity: 40.0 %
Pressure: 999.0 hPa
Altitude = 50.0 meters

自動起動

給電したときに自動的に起動するようにするには 起動対象のスクリプトファイル名を「code.py」か「main.py」にします。 その状態から動作を止めるのは若干コツがいります。

以上でも止まらないような場合はFlashストレージを初期化する必要があったりします。

Adafruit-Blinka

https://pypi.org/project/Adafruit-Blinka/

こちらを使うと、LinuxベースのマシンでCircuitPythonの互換モジュールを利用できます。 つまり、RaspberryPiやDockerエミュレーションコンテナなどでPoCを作成し、マイコンターゲットのCircuitPython上に移植するという形を取れば、最小の修正で移植可能になる。

アルゴリズムの検証をDocker上で済ましておくという手法が使えます。

ポーティングのコスト

nRF52840派生モジュールやATSAMD21/51を載せたボードは近年たくさんリリースされていますが、これらはチップコア単体の機能でCircuitPythonの要件を満たせているので、殆どの場合既存のリリース済みのCircuitPythonをインストールして動作させることができます。

ブートローダーの専有する1〜2ボタン、ボードのアセットの差分くらいしか異なる点はなく、ちゃんとした調整もそんなに大きくコストが掛かりません。

マイコンがサポート済みと同じものであるうちはボードサポート程度であれば大きく調整コストがかからないということです。 (また、ブートローダーさえ適合するのならCircuitPython自体は完全に整合するものでなくとも動作します。ボードサポート部分をアプリケーション毎に書くという方法で。)

Cによる拡張

  • Cによる拡張ができれば割り込みやDMA利用や電源制御なども可能です
  • CircuitPython本体ごと追加拡張モジュールと一緒にビルドが必須です
  • そうなってくるとCircuitPythonのお手軽さ自体は無意味になるのでおすすめはしません
  • あくまで用意された機能セットだけでPoCを作るのに向いています
  • 機能不足を感じたら早めにArduinoやmbed、PlatformIO、チップセットSDK利用などに切り替えていくのが良いでしょう

まとめ

CircuitPythonはハードウェア制御の入門やPoC作成に向いています。導入も対応ボードであればほとんど躓くことはないでしょう。 Python自体もプログラミング入門者にやさしいので、取っ掛かりでとにかく動くところまでを追うのには最適だと思います。