MicroPythonによる、リアルタイムマイクロコントローラ使用アプリケーションの迅速な開発

著者 Jacob Beningo

Digi-Keyの北米担当編集者 の提供

リアルタイム組み込みシステムは複雑化を極め、難解な32ビットマイクロコントローラに加えて、センサ、アルゴリズム、インターネットプロトコル、さらには非常に幅広いエンドユーザーアプリケーションに関する詳しい知識が必要になっています。より短い開発サイクルで、より多くの機能を開発しなければならない開発チームは、設計のスピードを上げると同時に、新製品にコードを移植できるようにする方法を見つける必要に迫られています。必要なのは、柔軟性の高い統合開発プラットフォームです。

開発プロセスの迅速化に役立つ、特定のマイクロコントローラ専用プラットフォームはいくつか提供されていますが、開発者が1つのマイクロコントローラプロバイダに縛られるという問題があります。また、複数のプラットフォーム間でソフトウェアを移植すると、多くの時間とコストがかかるおそれがあります。

今までにないユニークなソリューションとして広い支持と勢いを得ているのが、低水準のマイクロコントローラハードウェアにPythonなどの高水準プログラミング言語を組み合わせる方法です。その1つがMicroPythonで、複数の異なるマイクロコントローラベンダーの部品で実行できます。また、オープンソースなので、開発者がすぐに使用でき、それぞれの要件に合わせたカスタマイズも可能です。

MicroPython.orgの記載によると、MicroPythonは、Python 3プログラミング言語をコンパクトかつ効率的に実装したもので、マイクロコントローラなどの制限された環境での実行向けに最適化された、Python標準ライブラリの小規模サブセットを含みます。キックスタータープロジェクトとして始まったMicroPythonは、ファンディングに成功しただけでなく、多くの愛用者を育て、産業用システムや宇宙システムなど、さまざまな業種のプロジェクトで効果的に使用されています。

適切なマイクロコントローラの選択

MicroPythonは複数の異なるマイクロコントローラで実行でき、インタープリタの実行に十分なRAM、フラッシュ、処理能力さえあれば、別のマイクロコントローラへの移植にも大きな制限はありません。しかし、MicroPythonの実行に使用するマイクロコントローラには、開発者が知っておくべきいくつかの重要な要件があります。

  • 256KB以上のフラッシュ
  • 16KB以上のRAM
  • 80MHz以上のCPUクロック

これらは一般的な推奨事項であり、アプリケーション要件や、MicroPythonカーネルのカスタマイズにかける時間によっては、上記から逸脱しても構いません。たとえば、256KBよりも大幅に小さいフラッシュを使用するように変更することもできます。上記の推奨事項は、最適な開発を提供するための数値であり、アプリケーションコードを拡張するための余地を残してあります。

MicroPythonはすでに何種類かのマイクロコントローラシリーズに移植されており、これを出発点として新規プラットフォームに移植するか、すでにサポートされているマイクロコントローラを選択することができます。図1に示すのは、MicroPythonのソースコードのメインディレクトリです。ここから、サポートされているマイクロコントローラデバイスを確認できます。次のマイクロコントローラが含まれます。

サンプルフォルダのディレクトリ構造イメージ

図1:サンプルフォルダのディレクトリ構造に、現在MicroPythonをサポートしているマイクロコントローラプラットフォームが示されます。対象プラットフォームには、ARM、CC3200、esp8266、Microchip PIC、STM32があります。(イメージ提供:Beningo Embedded Group)

ルートディレクトリ内の各フォルダは、一般的なドライバと該当するチップファミリのサポートを含む上位フォルダです。それぞれのフォルダ内に、サポートされる複数の開発ボードまたはプロセッサが含まれる場合があります。たとえば、stmhalフォルダは、STMicroelectronicsのSTM32F429 Discovery BoardとSTM32 IoT Discovery Node(STM32L)、Adafruit IndustriesのSTM32F405 pyboardなどの開発ボードをサポートしています。ESP8266フォルダには、AdafruitのESP8266用HuzzahブレイクアウトボードとFeather Huzzah Stack Boardのサポートが含まれています。

MicroPythonを実行できる開発ボードは低コストなので、何種類か購入して、アプリケーションに必要なメモリ、ストレージ容量、処理能力を確認することをお勧めします。たとえば、はじめにSTM32F405 pyboardを使用した後で、将来的な機能とアップグレードを考慮して、最終製品ではSTM32F429に移行することもできます。TM32F429は、2MBのフラッシュ、256KBのRAM、CCMと呼ばれる待ち状態ゼロのRAMを搭載しています。

開発者が記述するMicroPythonアプリケーションコードを、必ずしもマイクロコントローラの内蔵フラッシュに格納する必要はありません。MicroPythonカーネルはマイクロコントローラ上に配置する必要がありますが、アプリケーションコードは、Panasonicの microSD 8GBカードなどの外部ストレージメディアに格納できます。外部メモリストレージデバイスにアプリケーションコードを格納すると、マイクロコントローラが使用するメモリを低減し、場合によってはシステム全体のコストを節約できる場合があります。

MicroPythonを実行してみよう

MicroPythonは、Adafruit STM32F405 pyboardにプリインストールされています。ただし、その他の開発キットやカスタムハードウェアでは、MicroPythonソースのダウンロード、ターゲットボード向けのソースのビルド、マイクロコントローラへのソフトウェアのフラッシュ書き込みが必要です。MicroPythonのソースコードはすべてGitHub上にホストされているので、簡単にアクセスできます。ツールチェーンをセットアップして、MicroPythonをビルドできる環境を構成するには、いくつかの手順に従う必要があります。この例では、STM32F429ディスカバリボード向けにMicroPythonをビルドします。

はじめに、Linuxベースの仮想マシンを作成するか、ネイティブのLinuxインストールを使用します。端末からLinuxを使用できるようになったら、次のコマンドを使用して、ARMコンパイラのツールチェーンをインストールします。

sudo apt-get install gcc-arm-none-eabi

 

Linuxを新規インストールする場合、リビジョン管理システムのgitがインストールされない場合があります。次のコマンドを使用すると、端末からgitをインストールできます。

 

sudo apt-get install git

 

gitをインストールしたら、端末で次のコマンドを実行して、MicroPythonソースコードをリポジトリからチェックアウトします。

 

git clone https://github.com/micropython/micropython.git

このプロセスの実行には数分かかる場合がありますが、一連の処理が端末に表示されます(図2)。

MicroPythonリポジトリからローカルファイルシステムへのクローニングのイメージ

図2:MicroPythonリポジトリをローカルファイルシステムにクローニングした後で、ターゲットボード向けにMicroPythonをビルドするか、独自アプリケーション向けにカーネルをカスタマイズできます。(イメージ提供:Beningo Embedded Group)

MicroPythonソースをローカルファイルシステムにクローニングしたら、そのディレクトリに移動し、端末で「cd stmhal」を実行します。stmhalディレクトリには、STM32マイクロコントローラ向けのMicroPythonのmakefileが含まれています。また、「boards」フォルダを表示すると、現在サポートされているすべてのSTM32ボードを確認できます。「boards」フォルダに含まれるボードであれば、どのボードでも端末からビルドを実行できます。たとえば、STM32F4ディスカバリボードをビルドするには、次のコマンドを実行します。

make BOARD=STM32F4DISC

ビルドが終わるまでに数分かかります。ビルドの実行中、デバイスファームウェア更新(DFU)ツールをインストールします。これは、USB経由でマイクロコントローラにMicroPythonをプログラムするために使用します。このツールは、端末で次のコマンドを実行するだけでインストールできます。

sudo apt-get install dfu-util

MicroPythonのビルドが完了し、dfu-utilをインストールしたら、マイクロコントローラにMicroPythonをロードします。はじめに、マイクロコントローラをDFUブートローダモードに移行します。このため、フラッシュからコードを実行する代わりに、リセットで内蔵ブートローダをロードするように、ブートピンを設定します。

マイクロコントローラをブートローラモードにして、USB経由でホストコンピュータに接続したら、次のコマンドで、dfu-utilを使用してMicroPythonをダウンロードできます。

dfu-util -a 0 -d 0483:df11 -D build-STM32F4DISC/firmware.dfu

dfu-utilは、コンパイルプロセスで出力されたdfuファイルを使用します。このプロセスではマイクロコントローラの完全な消去と再プログラムが必要なため、完了までに数分かかります。プロセスの出力は次のようになります(図3)。処理の完了次第、ブートジャンパを内蔵フラッシュからロードするように調整したら、マイクロコントローラをパワーサイクルします。この時点で、ターゲットのマイクロコントローラ上でMicroPythonが実行されています。

dfu-utilを使用した、マイクロコントローラへのMicroPythonのロードのイメージ

図3:dfu-utilを使用した、マイクロコントローラへのMicroPythonのロード。(イメージ提供:Beningo Embedded Group)

センサおよび接続デバイスの接続

MicroPythonなどの高水準プログラミング言語を使用してリアルタイム組み込みソフトウェアを開発する際の最大のメリットは、ソフトウェアが基盤ハードウェアに依存しない点です。つまり、pyboardで実行するように開発したMicroPythonスクリプトをほとんど(またはまったく)変更せずに、ESP8266やSTM32F4ディスカバリボードで実行できます。ここで、基本的なMicroPythonスクリプトを確認してみましょう。このスクリプトは、Bosch Sensortec BMP280気圧および温度センサをI2Cバスに接続し、Microchip TechnologyのRN-42 Bluetoothモジュールを使用して、Bluetoothシリアルリンク経由でデータを送信します。

BMP280はI2Cベースの気圧および温度センサで、I2Cスレーブアドレスは10進数の119です。最も簡単にBMP280をpyboardに接続するには、DFRobotGravityボードを使用します。このボードは、アクセスが容易で堅牢なコネクタを提供し、デバイスへの電力供給とI2Cアクセスを可能にします。開発者は、I2C1バスまたはI2C2バスのどちらかを選択して、Gravityボードに接続します。ボードを接続したら、MicroPythonスクリプト自体は簡単です。

はじめに、pybライブラリからI2Cクラスをインポートします。pybライブラリは、SPI、I2C、UARTなどの、マイクロコントローラのペリフェラル機能へのアクセスを提供します。いずれかのペリフェラルを使用する前に、そのペリフェラルクラスをインスタンス化して、ペリフェラルの制御に使用するオブジェクトを作成します。ペリフェラルクラスを初期化したら、メインのアプリケーションループを開始する前に、デバイスの存在検証などのその他の初期化を実行します。次に、メインのアプリケーションコードで毎秒1回、センサをサンプリングします。以下にサンプルコードを示します(コードリスト1)。

Copy
from pyb import I2C
 
GlobalTemp = 0.0
GlobalBarometer = 0.0
 
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
 
while True:
            SensorSample()
            pyb.delay(1000)
 
def SensorSample():
            #Read the Temperature Data
            TempSample = I2C2.readfrom_mem(119, 0xFA,3)
 
            #Read the Pressure Data
            PressureSample = I2C2.readfrom_mem(119, 0xF7,3)

コードリスト1:I2Cペリフェラルを初期化し、DFRobot Gravityボードと通信して温度および気圧センサのデータを収集するMicroPythonスクリプト。(コード提供:Beningo Embedded Group)

センサデータをサンプリングしただけで何も処理しないのであれば、MicroPythonがどれほど高性能かを示すデモとして非常に有効だとは言えません。多くの開発者チームが直面しているのは、Bluetoothを使用してセンサデバイスをインターネットまたはローカルセンサハブに接続するときの技術的な課題です。

プロジェクトにBluetooth機能を追加する簡単な方法は、RN-42を使用することです。RN-42を接続すると、Bluetooth経由で転送する必要のあるUARTデータをマイクロコントローラから送信するだけで、RN-42がBluetoothスタック全体を処理してくれます(図4)。

MicroPythonを実行するpyboardを、UART経由でRN-42 Bluetoothモジュールに接続したイメージ

図4:MicroPythonを実行するpyboardを、UART経由でRN-42 Bluetoothモジュールに接続します。(イメージ提供:Beningo Embedded Group)

Bluetoothボードを接続したら、非常に簡単なスクリプトを作成するだけで、受信センサデータをBluetooth経由でモバイルデバイスに送信できます。その後で、このデータを保存することも、クラウドに転送して分析することもできます。以下にサンプルスクリプトを示します(コードリスト2)。この例で構成するUART1は、115200bps、8ビット送信、パリティなし、1ストップビットです。

Copy
from pyb import uart
from pyb import I2C
 
GlobalTemp = 0.0
GlobalBarometer = 0.0
 
# Initialize and Instantiate I2C peripheral 2
I2C2 = I2C(2,I2C.MASTER, baudrate=100000)
 
# Configure Uart1 for communication
Uart1 = pyb.UART(1,115200)
Uart1.init(115200, bits=8, parity=None, stop=1)
 
while True:
            SampleSensor()
            pyb.delay(1000)
 
def SensorSample():
            #Read the Temperature Data
            TempSample = I2C2.readfrom_mem(119, 0xFA,3)
 
            #Read the Pressure Data
            PressureSample = I2C2.readfrom_mem(119, 0xF7,3)
 
            #Convert Sample data to string
            data = “#,temperature=”str(TempSample)+”,pressure”+str(PressureSample)+”,#,\n\r”
 
            #Write the data to Bluetooth
            Uart1.write(data)

コードリスト2:UART1を初期化して外部デバイスと通信する、MicroPythonスクリプトの例。(コード提供:Beningo Embedded Group)

Pythonアプリケーションはハードウェアプラットフォームへのコード移植が容易なだけでなく、実装済みの共通ライブラリと機能を使用するので、開発者は迅速に開発を進められます。上記アプリケーションの構築は1時間以内で完了できますが、水準の極めて低いソフトウェアで開発を始めて水準を上げていく場合、場合によっては1週間以上かかります。

リアルタイムソフトウェア開発に関するヒント

MicroPythonを使用した組み込みアプリケーションは簡単に開発できますが、システムからリアルタイム性能を得るのはそれほど簡単ではない場合があります。MicroPythonには、コードの簡略化と再利用が大幅に簡単になるというメリットがありますが、いくつかの興味深い事実とライブラリを理解していない限り、予測可能な一定のタイミングをシステムから取得することは難しいかもしれません。

MicroPythonはバックグラウンドで実行されるガベージコレクタを提供しており、ヒープなどのメモリリソースを管理します。このガベージコレクタの動作は非決定的なので、決定的な動作を想定している場合、時間による影響が大きいセクションでガベージコレクタが実行を開始すると、問題になるおそれがあります。このような状況を避けるための推奨事項がいくつかあります。

1番目は、ガベージコレクションライブラリ「gc」をインポートし、enableメソッドとdisableメソッドを使用して、ガベージコレクタを有効化または無効化するタイミングを開発者側で制御する方法です。タイミングが重要なセクションの前にガベージコレクションを無効化しておき、後から再度有効化することができます(コードリスト3)。

Copy
import gc
 
gc.disable()
 
#My time critical code
 
gc.enable()

コードリスト3:時間が重要なセクションの前に、MicroPythonのガベージコレクタを無効化します。(コード提供:Beningo Embedded Group)

2番目に、開発者がガベージコレクションのプロセスを制御する方法があります。開発者がオブジェクトを作成して破棄するとき、ヒープ上にメモリを割り当てます。ガベージコレクタは実行時にこの未使用領域を解放します。この実行間隔は不定期なので、開発者がcollectメソッドを使用して定期的にガベージコレクションを実行することで、ヒープ領域がガベージでいっぱいにならないようにすることができます。この場合、ガベージコレクションの実行時間を10ミリ秒から1ミリ秒未満まで短縮できます。また、手動でガベージコレクションを呼び出すと、非決定的なタイミングで実行されるコードをアプリケーション側で確実にコントロールできます。これにより、ガベージコレクションの実行タイミングをアプリケーション側で決定して、リアルタイム性能を確保できます。

リアルタイムコードの記述に関するその他のベストプラクティスには、以下が挙げられます。

  • 事前割り当て済みのバッファを通信チャネルで使用する
  • 通信ペリフェラルの使用時に、readintoメソッドを使用する
  • ###を使用した従来のPython文書化手法を使用しない
  • 実行時のオブジェクト作成および破棄を最小限にする
  • アプリケーション実行時間を監視する

このほかの「ベストプラクティス」の詳細については、こちらからMicroPythonの最適化に関するドキュメントをご覧ください。

まとめ

MicroPythonは、基盤となるマイクロコントローラハードウェアに依存せずにリアルタイム組み込みアプリケーションを実装したいと考える開発者にとって、魅力的なプラットフォームです。開発者は、MicroPythonで提供された標準ライブラリを使用して高水準のPythonスクリプトを作成し、サポートされる任意のマイクロコントローラで実行できます。これには、次を含む数多くのメリットがあります。

  • アプリケーションの再利用性が高くなる
  • 市場投入までの時間を短縮できる
  • アプリケーションとハードウェアを分離できる

MicroPythonはあらゆるアプリケーションに最適というわけではありませんが、産業用および宇宙システムのアプリケーションやプロトタイピング、概念実証では、これまでに高い効果を発揮しています。 

免責条項:このウェブサイト上で、さまざまな著者および/またはフォーラム参加者によって表明された意見、信念や視点は、Digi-Key Electronicsの意見、信念および視点またはDigi-Key Electronicsの公式な方針を必ずしも反映するものではありません。

著者について

Jacob Beningo

Jacob Beningo氏は組み込みソフトウェアコンサルタントで、現在、製品の品質、コスト、市場投入までの時間を改善することで、ビジネスを劇的に変革するために数十か国以上のお客様と作業しています。同氏は、組み込みソフトウェア開発技術に関する200以上の記事を発表しており、引っ張りだこのスピーカーでありテクニカルトレーナです。ミシガン大学のエンジニアリングマスターを含む3つの学位を取得しています。気楽にjacob@beningo.comにメールするか、彼のウェブサイトwww.beningo.comから連絡してみてください。そして毎月のEmbedded Bytes Newsletterにサインアップしましょう。

出版者について

Digi-Keyの北米担当編集者