IoT開発向けPythonマイコン M5Stack実験室
[M5Stack親切マニュアル]
1行ずつ動かしながら開発できる対話型プログラミング
- 著者・講師: 田口 海詩/Uta taguchi
- 企画編集・主催: ZEPエンジニアリング株式会社
- 関連製品:[VOD/KIT] Python×実習キット×スマホでできる!ESP32マイコン活用術
- 関連製品:[VOD/KIT]STM32マイコン&Wi-Fiモジュールで学ぶ C/C++プログラミング入門
- 関連製品:[VOD/KIT]実習キットでできる!ラズパイPicoでマイコン入門
- 関連製品:[VOD/Pi KIT]ラズベリー・パイで学ぶLinux&Pythonプログラミング超入門
- 関連製品:[VOD/KIT]M5Stackで一緒に作ろう!IoTセンシング・エッジ×クラウド連携システム開発[改訂版]
- 関連製品:[VOD/Pi3A KIT]ラズパイ・キットで学ぶLinux I/Oボードの作り方・探し方・動かし方
- 関連製品:[VOD/Pi KIT]ラズベリー・パイで学ぶLinux&Pythonプログラミング超入門
- 関連製品:[VOD/PiZero KIT]Python×ラズパイで初めての量子コンピュータ
- 関連製品:[VOD/Pi400 KIT]SLAMロボット&ラズパイ付き!ROSプログラミング超入門
- 関連製品:[VOD/Pi KIT]ラズパイ×Pythonで動かして学ぶモータ制御入門
- 関連記事:ラズベリー・パイ Picoマイコン入門 C言語開発環境の構築
高校生にも勧められる!今どきのマイコン開発は英語より断然簡単!
テレビ,冷蔵庫,洗濯機からNintendo Switch,自動車,医療機器まで,電気を使うシステムにはほぼすべて,そのアプリに最適化された小さなコンピュータ「マイコン」が入っています.
スマホやパソコンに入っているコンピュータは,インターネットを通じて情報をやりとりしたり,その処理のために最適化されています.「マイコン」は,温度や振動などの物理信号を拾うセンサを使って計測したり,モータを回したりするときに便利に利用できる汎用的なコンピュータ・チップです.
電気ポットと冷蔵庫では,マイコンが果たすべき機能が違います.電気ポットの開発者は,温度をモニタして水温が下がったらヒータがONするように,そしてボタンが押されたら給水用のモータを回すような機能をコンピュータに組み入れます.
スマホの中のコンピュータは,入手したときからメーカでその動作が決められていますが,マイコンは設計者の意のままに動作を決めることができます.
マイコンの動作を設定するときの作業は次のとおりです.
- パソコンにマイコン設定用の専用アプリをインストールして起動する
- 専用の言語を使って動作をテキストで記述する.「ボタンが押されたらLEDを点灯させる」と日本語で書くことはできないが,英語より文法も単語も少なく断然簡単.これをプログラミングという
- 記述したテキストをマイコンがわかる言語(機械語)に専用アプリで変換する(コンパイルと呼ぶ).マイコンは1と0のデータ列(バイナリ・コード)しか理解できない
- USB付きの専用書き込みツールをパソコンに接続する.一方をマイコンに接続する
- 専用アプリを使って,変換したデータ列をマイコンに流し込む
マイコンの設定方法は,年々改良されていてものすごく簡単になりました.本稿では,Python言語を使って,M5Stackという最新のマイコン・キットを動かします.
前述の(3)~(5)の作業は不要です.Pythonで動作を記述して実行すると,すぐにマイコンが応答して動いて見せてくれます.もし記述が間違っていれば,正直なマイコンは,違う動きをしたり,動かなかったりしますから,すぐに自分の誤りを訂正することができます.効率よく試行錯誤できるこのしくみは,初学者にとても有効です.〈ZEPマガジン編集部〉
IoT開発用小型コンピュータ・キット“M5Stack”のすすめ
スマホやテレビにNintendo Switch,Suicaカード,時計に至るまで,ぼくらの周りには,マイコンを用いた電化製品がたくさん存在しています.インターネットにつながるIoT(Internet of Things)デバイスにももちろんマイコンが搭載されています.
マイコンは,エレクトロニクスの専門家しか使えない特殊で難しいデバイスと思っているかもしれませんが,それはまったくの誤解です.今どきのマイコンは,高性能で安価で,開発環境もとてもよくできています.高校生,いや中学生や小学生でも動かすことができます.
がんがんトライ&エラーできる対話型開発
プロの開発現場では,「C(シー)」という世界の定番言語を使って,何百,何千,何万行という記述(ソースコードという)をマイコンに書き込みながら,狙ったとおりの動きをするかどうかを確認しています.しかしどんなに優れたエンジニアでも,何万行もあるプログラムをいきなりマイコンに書き込んで動かなったら,間違い箇所を見つけ出すのに四苦八苦するものです.
この問題を解決する方法に,1行ずつプログラムをマイコンで動かすことができる対話型の開発環境があります.1~数行のごく短い記述を書いてマイコンに投げかけると,マイコンがそのまで動いてくれて,結果を返してくれます.
ケース入りだからプロ顔負けの製品開発が可能
写真1に示すのは,対話型開発が可能な最新のマイコン・キット M5Stackです.液晶ディスプレイとボタンを備えていて,通販で3,500円ほどで入手できます.
ケースを開けると,Wi-Fi通信が可能な安価な高性能マイコン“ESPシリーズ(Espressif Systems製)”やSDカード・スロット,USBコネクタを搭載したCoreと呼ばれる基板が出てきます(写真2).
写真3に示すように,上下左右の四辺には,外部回路と接続できるヘッダ・コネクタがあります.オーディオ用D-Aコンバータやモータ制御など,自分で作った回路を継ぎ足していくと,プロ顔負けのディスプレイ搭載ウェアラブル製品を開発することができます.
コンパクトでケースに入っていますから,しゃれおつなカフェでシステム開発…なんて絵も悪くないですね.「怪しい奴」と白い目で見られる心配はないでしょう(と思います).
Python言語を機械語に翻訳するファームウェア“MicroPython”
マイコンの開発言語は,今も昔も「C」が標準です.C言語は,マイコンの一連の動作を記述した後,ソースコードをまとめてバイナリ・コードに変換する処理(コンパイルという)を行います.
Python言語をCPUが解釈できる機械語に翻訳するインタープリタ・ファームウェア“MicroPython”をマイコン内のメモリに常駐させておけば,Pythonで書いたソースコードをパソコンからUSB経由でそのまま読み込ませて動かすことができるようになります.
実際には,M5Stackとパソコンを用意したら,MicroPythonの公式ホームページ(図1)からMicroPythonファームウェア(無料)を入手し,M5Stackに搭載されたESPマイコンの内蔵フラッシュ・メモリに書き込む準備が必要です.MicroPythonファームウェアとは,Python言語で記述されたソースコードを機械語に翻訳するソフトウェアのことです.「インタープリタ」と呼びます.
図1 マイコンと対話しながら開発を進められる翻訳ファームウェア MicroPythonのホームページからは,さまざまなマイコン用のファームウェアや使い方のドキュメントを入手できる |
さらに,パソコンに,M5Stackと逐次通信するためのアプリケーション「シェル」をインストールします.シェルは,実行したプログラムの結果を表示したり,マイコンにソースコードの一部を直接送ったりする働きがあります.
このしくみによって,1行ずつトライ&エラーを繰り返せるので,間違いを素早く特定しながらプログラムを仕上げていくことができます.
パソコンと切り離してマイコン単体で動作させることもできる
プログラム名をmain.pyと変更して,M5Stackのフラッシュ・メモリに保存すると,M5Stack単体でも動作させることができます.
MicroPythonの開発環境をセットアップする
Python用IDE“Thonny”のすすめ
次のマイコンの開発作業はすべてパソコン上で行います.
- ソースコードの作成(コーディングという)
- マイコンの内蔵フラッシュ・メモリへのデータ転送
- プログラムの実行と結果の表示
- ソースコードの修正(デバッグという)
通常は,これらの一連の作業を1つのアプリケーション上で行います.これを統合開発環境(IDE :Integrated Development Environment)と呼びます.Python言語を使って,M5Stackのプログラミング開発をするなら,Python専用のIDE“Thonny”がおすすめです.
図2に示すのは,M5StackとPython言語を使う対話型開発環境の全体像です.統合開発環境“Thonny”を起動したら,Python言語を使ってソースコードを記述し,M5Stackに転送してプログラムを実行します.
繰り返しますが,Python言語で書いたソースコードは,あらかじめテキスト・データとしてメモリに書き込んでおき,翻訳ファームウェア(インタープリタ)で1行ずつ解釈して(バイナリ・コードに変換し,逐次実行します.
M5Stackとパソコンは,USBで接続しますが,それだけでは通信ができません.あらかじめ,M5Stackに搭載されているUSBブリッジIC CP2104(シリコン・ラボラトリーズ社)の制御ソフトウェア(ドライバ)をパソコンにインストールしておく必要があります.
開発環境のセットアップ
大きな流れ
- MicroPythonファームウェアの入手
- ESP32マイコン書き込みツールの入手
- COMポート・ドライバの入手・インストール
- MicroPythonファームウェアをM5Stackに書き込む
- 統合開発環境Thonnyソフトウェアの入手・インストール
- M5StackとパソコンをUSBケーブルで接続
(1)MicroPythonファームウェアの入手
M5Stackに書き込むESP32マイコン用のMicroPythonファームウェアをダウンロードします.具体的には,Git-Hub(ギットハブと読む)のloboris/MicroPythonページ(図3)から,“loboris/MicroPython”というビルドずみ実行ファイル(バイナリ・ファイル)をダウンロードします.このファームウェアは使用方法が記載されたマニュアルが充実しています.
図3 M5Stackに搭載されているESP32マイコン用MicroPythonファームウェア LoBo MicroPythonをGit-Hubから入手する |
Git-Hubには世界中のプログラマが投稿したソースコードやビルドずみの実行ファイルが無数にあり利用できる |
ビルド済み実行ファイルは,“MicroPython_BUILD”フォルダ内にあります.フォルダにはビルド条件の異なるファームウェアが複数格納されています.今回は“esp32_all”を使います.複数のファイルが1つにまとめられた“MicroPython_LoBo_esp32_all.zip”をダウンロードして展開(解凍)すると,図4に示す4つのバイナリ・ファイルが得られます.
図4 ESP32マイコン用MicroPythonファーウェア“MicroPython_LoBo_esp32_all.zip”を入手したら解凍する |
①~④のバイナリ・ファイルをM5StackのESP32に書き込む |
なお,Git-Hubは世界中のエンジニアが作ったプログラムや関連情報のデータベースです.誰でもここにアクセスして,情報を入手し利用することができます.
(2)ESP32マイコン書き込みツールの入手
M5Stackに搭載されたESP32マイコンのフラッシュ・メモリに,Lobo MicroPythonファームウェアを書き込むときは,ESP32マイコンのメーカ(Espressif Systems)が提供する書き込みツール“Flash Download Tools”を使います.
Espressif Systems社のホームページから,Flash Download Toolsをダウンロードしてください(図5).ダウンロードが終わると,図6に示すファイル群が得られます.
(a)Espressif Systems社のホームページにアクセスする |
---|
(b)書き込みツールをダウンロードする |
図5 MicroPythonファームウェアをESPマイコンに書き込むためのツールもダウンロードする |
Espressif Systems社のホームページから[Support]-[Download]-[Tools]を選ぶと,“Flash Download Tools”をダウンロードするページが開く. |
(3)パソコンにUSBブリッジICのドライバをインストール
USBを介して,パソコンからM5Stackにデータを送信したり,逆に受信したりするためには,M5Stackに搭載されているUSBブリッジIC CP2104(シリコン・ラボラトリーズ)を制御するソフトウェア(ドライバ)が,パソコンにインストールされていなければなりません.
シリコン・ラボラトリーズ社のホームページから,“CP210x USB - UART ブリッジ VCPドライバ”をダウンロードして,パソコンにインストールしてください(図7).
図7 M5Stackに搭載されているUSB通信IC CP2104とデータを送受するためのソフトウェア“USB-UARTブリッジVCPドライバ”をパソコンにインストールする |
(4)M5StackにMicroPythonファームウェアを書き込む
- MicroPythonファームウェア “loboris/MicroPython”
- ESPマイコン書き込みツール“Flash Download Tools”
- COMポート・ドライバ“CP210x USB - UART ブリッジ VCPドライバ”
のセットアップが完了したら,M5Stackに搭載されているESP32の内蔵フラッシュ・メモリにMicroPythonファームウェアを書き込みます.
Flash_download_toolを起動すると,図8(a)に示す画面が立ち上がります.[ESP32 DownloadTool]を選ぶと,図8(b)の書き込みツール設定画面が開きます.表1に示す4つのファイル名を選択して,フラッシュ・メモリのオフセット値を図8(b)の所定の位置に入力してください.フォルダ名に日本語が入っていると書き込みファイルが上手く読み込めない場合があるので,フォルダ名には英数字を用いてください.
どんなマイコンも,電源が入り起動すると,CPUが決められた番地のメモリに命令を取りに行き処理をし始めます.オフセット値とは,MicroPythonファームウェアのバイナリ・データを書き込むメモリの最初の番地です.
Flash_download_toolは,最初にM5Stackとの「通信COM:番号」を選択します.次に,消去ボタン(ERASE)を押します.消去が完了すると,書き込み開始ボタン[START]を押します.書き込み状況はステータスに表示されるので,書き込みが終わるまでゆっくり待ちましょう.
(5)パソコンに統合開発環境Thonnyソフトウェアをインストールする
Thonnyのホームページ(図9)を開くと,右上部にWindows版,Mac版,Linux版のダウンロード・リンクが示されています.
図9 Pythonの統合開発環境 Thonnyをダウンロードしてインストールする |
Windowsを使っているならWindows版を選んでください.リンクをクリックして,インストール実行ファイルがダウンロードされたら,そのまま実行します.
(6)M5StackとパソコンをUSBケーブルで接続
Thonnyのインストールが終了したら,M5StackとパソコンをUSBケーブルで接続してください.
Thonnyの起動アイコンをクリックすると,図10に示す起動画面が開きます.シェル画面に“>>>”が現れないときは,COMポート設定がされていないので,次の手順で設定します.
図10 Thonny上でPythonが動くかどうかをチェックする |
ThonnyのREPLシェルにプロンプト“>>>”が現れていれば,M5Stackに書き込んだPython-機械語インタープリタ“MicroPython”との接続に成功している |
Thonnyの起動画面から[Run]-[Select interpreter]を選びます.すると,図11に示すCOMポート設定画面が開きます.または[Tools]-[Options...],そして[Interpreter]タブを選んでも同じ画面が開きます.
図11の「Port選択欄」で,接続しているM5StackのCOMポート番号を選んで[OK]を押します.図10に示すように,シェルに“>>>”という記号が表示されたら,M5Stackとの接続は完了しています.これでM5Stackは,Python言語で書いたソースコードを受け入れることができます.
初めてのマイコン・プログラミング
パソコンで開発環境を立ち上げる
MicroPython開発環境“Thonny”を起動すると,2つのウインドウが上下に開きます(図12).
上部は,Python言語でソースコードを記述したり,実行したりするときに利用します.「コード・エディタ」と呼びます.
下部は,M5Stackに直接コマンドを送ったり,プログラムの実行結果を表示したりするときに利用します.「シェル」と呼びます.
コード・エディタで記述したPythonプログラムを実行した後に,シェルでPythonソースコードを追加して動かすことも可能です.
マイコンに直接命令を送ることができるシェルの機能のおかげで,複雑な処理も短時間で完成させることができるでしょう.
液晶ディスプレイに“Hellow World”を表示させてみよう
コード・エディタを使って,Pythonプログラムを実行してみましょう.
コード・エディタに新規のプログラムを記述するときは,[New]アイコンを押します.開発がある程度進み,プログラムを保存したいときは[Save]アイコン,過去に保存したプログラムをThonnyに読み出したいときは,[Open]アイコンを押します.
“Hello World”の文字をM5Stackの液晶ディスプレイに表示するPythonプログラム“HelloWorld.py”をコード・エディタ上で1つ1つ手作業で記述して実行してみましょう.
[New]アイコンを押して,新しいテキスト・エディタのファイルを開き,図13に示すHello World表示のプログラムを正確に入力してください.MicroPythonは,大文字と小文字を区別します.
図13 M5Stackの液晶ディスプレイに“Hello World”という文字列を表示させるPythonのソースコードを手打ちしてほしい |
プログラミングに慣れるためには手入力がとても有効なので,ぜひ挑戦してほしい |
書き終えたら[Save]アイコンを押して,パソコンの適当なフォルダに,ファイル名(N)を“HelloWorld”,ファイルの種類(T)を“Python files”として保存してください(“HelloWorld.py”という名前のファイルができる).
このファイルをロードするときは[Open]アイコンを押します.[Open]アイコンを押すと,ファイルをパソコン上から読み込むのか,M5Stackのフラッシュ・メモリ上から読み込むのかを聞いてきます(図14).[This computer]を選んで,プログラム“HelloWorld.py”をロードします.
プログラムを実行する前に,[STOP]アイコンまたはCtrlキー+F2キーを押して,ソフトウェア・リセットを実行します.すると,すべての命令が一度リセットされます.
シェルのウインドウに,“>>>”という記号が表示されたら,実行アイコン「▲」を押します.に示すように,“Hello World”という文字が,M5Stackの液晶ディスプレイに表示されたら成功です.
MicroPythonファームウェアを組み込んだM5StackとパソコンをUSBケーブルで接続して,Thonnyを起動します.するとシェルにプロンプト“>>>”が表示されます(図15).これは,M5Stackは,Pythonで記述されたソースコードを受け入れる準備が整っていることを意味します.
最初に簡単なソースコードを入力してみましょう.
図16に示すように,シェルの“>>>”に“1+1”と書き込んでリターンを押してください.シェルに演算結果の“2”が表示されるでしょう.この“1+1”の演算はパソコン内ではなく,M5Stack内のESP32マイコンが実行したことに注意してください.
パソコンからPythonで記述されたソースコードがM5StackのESP32マイコンに送り込まれ,ESP32マイコンはこのソースコードをバイナリ・コードに変換して実行しました.そして,演算結果をパソコンに送り返しました.
このように,シェルを使えば,自分の記述した文字をM5Stackに直接送り込んで,ESP32マイコンを操作できます.
足し算したいときは,例えば“c = a+b”というふうに記述します.a,b,cは,さまざまな値になる代表値なので「変数」と呼びます.さらに,a,b,cが数の場合には数値型変数と呼びます.テキストが変数として入る場合は,文字型変数と呼びます.
数値型変数には次の2種類あります.
どちらを選ぶかによって,マイコンの演算効率が変わるため,通常はコーディングの最初の部分で選択し定義します.しかしPythonは,数値型変数が発生した時点で,数値の状態からどちらの型にするかを自動で判別して定義してくれます.これを「動的型付け」と呼んでいます.例えば,演算する数値に浮動小数が含まれていたり,割り算が含まれていたりしたら,結果の変数は浮動小数点型に自動で選択されます.
Pythonが変数を動的型付けするところを実際に見てみましょう
図17に示すように,シェルから“a=1,b=1.0”と入力して,ESP32マイコンに,“c=a+a,d=a+b,e=a*a,f=a/a”という演算を実行させてみます.
cは,1という整数どうしの足し合わせなので,cも整数です.dは,1という整数と1.0という浮動小数の足し合わせなので浮動小数です.結果を見ると,“c=2,d=2.0”となっています.同じように,eは整数どうしの掛け算なので整数です.fは,整数どうしの演算ですが,割り算なので浮動小数になります.結果は,“e=1,f=1.0”になります.
このようにPythonは,整数型か浮動小数型なのかを数値で判断して,変数型を自動的に定義します.
図18に示すように,シェルの“>>>”から“type(変数名)”と入力すると,整数型は“int”,浮動小数型は“float”と表示され,変数の型を調べることができます.
続いて,コード・エディタを使って,ソースコードを一括実行します.コード・エディタを使えば,シェルではできなかったソースコードの保存[Save]や読み込み[Open]も可能です.
図19(a)に示すのは,さきほど紹介した“Hello World”を表示するソースコードです.十数行の短いものです.
1~4行目の’’’~’’’で囲んだ部分は自分用のメモです.M5Stackはこの部分を無視します.Python系の言語では,プログラム処理に関係しないコメント文をプログラム内に記述できます.
5行目は,ディスプレイを制御する関数モジュール“display”を読み込んでいます(インポートという).5行目の“#”もコメント命令です.#”以降がコメントです.
6~9行目は,M5Stackの液晶ディスプレイの表示モードの設定です.initメソッドを使って,ディスプレイの種類やESP32マイコンとの接続ピン番号などを設定します.意味は次のとおりです.
文字や絵など,実際の表示情報は,10~12行目の3行で指定します.
10行目のtft.clear()メソッドで画面の文字や絵をすべて消します.
11行目で表示するフォント(tft.FONT_DejaVu24)の設定を行います.
12行目で(80,100)の位置に,“Hello World”という文字を表示します,デフォルトの文字色は緑色ですが,“Hello World”の後ろに“,tft.設定色”を追加すると,文字の色を変えることができます.
Thonnyのシェルを使うと,コード・エディタでPythonプログラムを実行した後に,ソースコードを追加して実行することができます.
“Hello World”をディスプレイに表示するプログラム[図19(b)]を実行した後に,図20(a)に示すように,シェルから追加で文字表示する命令を実行すると,図20(b)のように.“Hello World”の下に“MicroPython”と言う文字列が追加されます.
Python系言語では,sinやlogなどの関数を集めたものを「モジュール」と呼んでいます.同様にMicroPythonファームウェアも,モジュールを備えています.
図21に示すように,シェルから“help('modules')”と入力すると,Pythonが標準で備えているモジュールの一覧が表示されます.
これらを使うときは,ソースコードの冒頭でimport命令を使って宣言します.モジュールを宣言しないで,関数を使おうとするとエラーが出ます.
数学関数モジュール“math”をimport命令で宣言し,mathモジュールにある“sin”を使ってみましょう.シェルでmathモジュールをインポートして,sin(π/2)を計算します.
図22(a)では,数学関数モジュール“math”をインポートしています.sin()はメソッドで,sin(π/2)は“math.sin(math.pi/2)”と記述します.()の中で,もう一度,mathモジュールを呼び出して,piメソッドを利用して3.14を得ています.
実行すると,M5Stackが計算を実行して,シェルに“1.0”という答えを帰してきます.一度リセット[STOP]を押して,再度sin(π/2)を計算してみてください.
mathモジュールをインポートしないで,sin(π/2)を計算を実行すると,図22(b)のようにエラーが発生します.MicroPythonでは,[STOP]アイコンを押していったんインタープリタ処理を停止させると,今までインポートしたモジュールはすべて破棄されます.この状態になると,mathモジュールのsinメソッドはもう使えません.使うとエラーが発生します.
モジュールをインポートする方法はほかにもあり,図22(c)に示すように「from モジュール名 import 関数名」というふうにも記述できます.“from math import sin,pi”と記述して,モジュールの中で必要なメソッドだけをインポートすると,モジュール名が省略されソースコードが見やすくなります.例えば,sin関数は“sin(pi/2)”というふうにシンプルに記述できます.
MicroPythonモジュールの使い方の詳細は,loboris/MicroPython公式ホームページが参考になります(図23).
図24(a)は,mathモジュールのsin関数を使ってsin波形の表示を行うPythonのソースコードです.
1行目で,演算関数モジュール“math”と時間管理モジュール“utime”をインポートします.
2行目では,for文を使って,0~360°まで15°ずつ変化させています.
3~5行目のインデントされた部分は,処理が繰り返されます.3行目でsinの値[°]を計算します.sinを計算するときに,math.radians ()関数を使って角度[°]をラジアン[rad]に変換します.print関数を使って演算結果(5行目)をシェルに表示します.文字列フォーマット’{0:1.3f}’.format(y)を使って,シェルに表示する数値の桁数を制限しています.
文字列フォーマットは,表示する数値を見やすくするときに使います.文字列フォーマットで用いる“1.3f”は,浮動小数型数値を整数部1桁,小数部3桁の形にすることを意味しています.
4行目で0.2秒間の停止(スリープ)を命令しています.これは,Thonnyが波形をプロット表示し終えるまでの待ち時間です.Thonnyの[View]-[plotter]と選ぶと,シェルに表示された数値をもとに波形が表示されます.
5行目の“print”と書くことで,M5Stackは0~360°まで15°きざみで計算をして結果をシェルに送り返してきます.
Thonnyには,シェルに表示された数値をグラフ化する機能“Plotter”が備わっています.Thonnyの起動画面にて,[View]-[Plotter]を選ぶと起動します[図24(b)].
パソコンやスマホが搭載するCPUと異なり,マイコンには電気信号を入出力する多くの周辺回路「ペリフェラル」が備わっています.
Pythonには,これらのペリフェラルを動かすために,“machine”モジュールというライブラリが備わっています.
(a)に示すように,M5Stackは3つの押しボタンを装備しており,これらは,M5Stackの内部でESP32マイコンのGPIO端子(GPIO37~GPIO39)に接続されています[図25(b)].
各ボタンと連動するスイッチ回路は,3.3V電源にプルアップされた状態でESP32マイコンの各GPIO端子に接続されています.ボタンのスイッチを押さないと,GPIO端子には3.3V,つまりHレベル(1)が入力されます.ボタンを押すと,GPIO端子には0V,つまりLレベル(0)が入力されます.マイコンは,GPIO端子の電位をチェックすれば,ボタンが押されたかどうかを判断することができます.
図26(a)に,Button Aが押されたかどうかを検出するソースコードを示します.Button Aを押すと,シェルに“Button A”と表示されるプログラムです.押していない間は“No Push”と表示されます.
1行目で,machineモジュールのPinメソッドをインポートしています.この記述で,M5StackはButton Aに接続されているGPIO端子(39番ピン)の状態を読みに行きます.
2行目で,時間を管理のutimeモジュールをインポートしています.
3行目で,ボタンAの信号をGPIO39ピンで取得するための設定を行います.
4行目以下は,while文を使って,5~9行目を延々と繰り返します.走り出したら止まらない設定です.5~9行目を延々と繰り返します.
5~9行目は,if~else文を使ってボタンが押されたか,押されていないかを判断して,処理を切り換えています.ボタンAが押されると0,つまり“L”になるので,5行目のif文で判断して,6行目のシェルに“Button A”と表示する処理を行います.それ以外は“No Push”と表示します.シェルに“Button A”を表示するときは,“\r”を使って左に詰めて表示し,“end=’ ’”を使って改行を行い,命令を付け加えます.
このような処理を行うと,毎回シェルの同じ場所に表示されるようになり,見やすくなります.ボタンAが押されていない場合は,else文以下の表示が行われ,“No Pμsh”が表示されます.
if~else文が終了すると,0.1秒スリープして(9行目),再び5行目に戻り,同様の動作を繰り返します.このように一定時間ごとにボタン状態を見に行く制御方法を「ポーリング方式」と呼びます.
特別な処理を記述しなければ,プログラムは上から下に向かって順次実行されます.
「制御文」を使うと,その流れを変えることができます.例えば,同じ処理を複数回繰り返したり,条件によって演算処理を切り換えたりできます.ボタンAが押されたらプログラムAを起動し,ボタンBが押されたらプログラムBを起動するということができるのです.センサの計測値によって,演算式を切り換えることも可能です.
よく使う制御文は次の3つです.
①for文 ②while文 ③if文
これらを上手に活用すると,プログラムで複雑な動作を実現できます.
図27に示すのは,決められた処理を複数回繰り返したいときに利用するfor文の基本型式です.「変数」に「範囲」の値が順次代入され,「処理文」に記述した命令が繰り返されます.連続した範囲を表す方法としてよくrange関数を用います.
range関数の表記方法は上記の2とおりです.引数“step”は省略でき,省略すると1と自動的に判断されます.
図28~図30は,for文を用いた繰り返し動作のプログラムの例で,range関数を使って変数iの範囲を決めています.range関数の表記方法は,
図28と図29はどちらも,変数iに,0から4まで1ずつ増す値が入力されつつ,“print(i)”を5回繰り返すプログラムです.
“range(start, stop, step)”の“step”を省略すると,“step”は自動的に1が代入されます.図30に示すように,“step”に-1を代入すると,“start”の値が1ずつ減少します.
図29は“range(start,stop[,step])”という文法を使った記述です.変数の範囲は同じく“0,1,2,3,4”です.
図30の“range(5,0,-1)”も,“range(start,stop[,step])”の表示方法です.Stepが-1になっていて減少を表します.変数の範囲は“5,4,3,2,1”です.
制御文の行の最後に“:(コロン)”を付けると,次の行以降からインデントが挿入されます.インデントをやめるまでの部分に記述された命令が処理範囲になります.
C言語では,処理範囲を“中括弧{ }”で記述します.Python系言語のインデントはC言語の{ }と同じ意味合いですが,C言語よりも少ない行数で記述できます.
図31に示すのは,ある決めた条件が満たされたら,特定の処理を繰り返すwhile文の基本型式です.「条件式」に記述した内容が満たされている(True)なら,「処理」に記述した内容が実行されます.条件式が満たされていない(False)なら,処理部分は実行されません.インデントを挿入した行からやめた行までが処理範囲と判断されます.
表2に,条件式に記述できる比較演算子を示します.処理部分を繰り返す条件を自由に設定できます.andやorなどの論理演算子を組み合わせれば,複数の条件を組み合わせることも可能です.
図32に示すのは,シェルに表示された数字が1ずつ大きくなるカウントアップ・タイマのソースコードです.while True制御文は,いったん処理が始まると,Thonnyの[STOP]アイコンを押して強制終了しないと止まりません.
1行目で,時間管理のutimeモジュールをインポートしています.
2行目で,“t=0”と値を決めて,3行目以降はwhile文で以下4~6行目を繰り返します.while文の条件式はTrueなので,延々とループを繰り返します.
4行目で,tに1を加算して,5行目でシェルに表示します.1秒待ってまた1を加算してシェルに表示します.シェルに表示する際は,“\r”と“end=’ ’”という記述を追加しているため,いつもシェルの同じ場所に数字が表示されます.
図33に示すのは,条件によって処理の内容を切り換える制御文の基本型式です.
“if”,“elif”,“else”の3つの予約語を使います.ifやelifの後に記述した「条件文」に合致したら,次の行の「処理」を実行します.制御文の最後には必ず“:(コロン)”を添えます.コロンを付けた次の行から,インデントを挿入して「処理」を記述します.インデントを挿入した行からやめた行までが処理範囲と判断されます.
図34に示すのは,数字を大きさで仕分けするプログラムです.Thonnyの実行ボタン「▶」を押すと,80以上ならA,50~79ならB,49以下ならCというふうに乱数の大きさが分類されてシェルに表示されます.
1行目で,0~100の数字のように乱数を発生させるモジュールrandomモジュールをインポートしています.
2行目で,0~100までの整数をランダムに発生させる変数 n を設定しています.
3~8行目で,if~elif~else文を使って,変数nの値をA,B,Cにランク付けしています.
3行目で,80以上はA,5行目で80未満で50以上をBと判断しています.
7行目のelseは,3行目と5行目で該当しない場合にCになります.
よく使う一連の処理を関数にして登録しておくと,プログラムがシンプルで見やすくなります.またシェルに,登録しておいた独自関数を1行記述して呼び出すと,本来複数行を要する処理が一括で実行されます.
図35に独自の関数を定義する制御文「def」の基本形式を示します.
図36に示すのは,M5Stackの液晶ディスプレイに表示された数値が1ずつ小さくなるプログラムです.
1行目で,表示用の“displayモジュール”と時間を管理する“utimeモジュール”をインポートします.
2行目でディスプレイを使用する設定を行います.
3~6行目は,次の4つを設定します.
7行目で表示するフォントの大きさなどを指定しています.“dist”が大きさを変える変数です.今回は7セグメント数字を使います.
7セグメント文字の大きさは,引数のdistとwidthの数値で設定できます.
8行目から12行目までは関数の定義です.
8行目は,カウントダウン関数“cd(n)”です.括弧の中のnは,関数内で演算に使用するために引き渡す値です.引数はいくつでもOKです.今回はcだけです.その処理の内容は,続く9~12行目にfor文を使って,引数で引き渡されたnから1ずつ減らす,というふうに記述しています.
10行目ではディスプレイの表示を消しています.
11行目では,(120,80)の位置に変数iを7セグメントのフォント文字で表示します.
12行目の“utime.sleep(1)”は「1秒停止せよ」という命令です.1秒間スリープして変数iが0になるまで繰り返します.この行まではすべてモジュール設定や関数定義です.
実際のメインのプログラムは,13行目のcd(10)だけです.cd(10)が実行されると,関数cdが呼び出され引数n=10として関数に引き渡され,そして関数cdの動作を行います.
写真5にプログラムを実行したところを示します.処理が終わると,シェルにプロンプト“>>>”が表示されます.
写真6に示すのは,複数のフルカラーLEDを実装した電飾モジュール「NeoPixel」です.1個のフルカラーLEDチップ(WS2812B,Worldsemi製)は,赤色,緑色,青色の3個のLED素子と,シリアル・データ通信とLEDの点灯を制御する回路が一体になっています.このチップを複数個搭載したテープ状,リング状,パネル状のものが製品化されています.
ESP32マイコンから,シリアル・データを送り込むことで,点灯させるLEDを指定したり,そのLEDの色や輝度を変えたりできます.
Pythonは,NeoPixel専用のライブラリを標準で備えています.マイコン・ビギナの第一歩といえば「Lチカ」ですが,ここでは「Neoピカ」をやってみます.
図37に,M5StackとNeoPixelに搭載されている16個のカラーLED “WS2812B”との接続を示します.
WS2812Bは,VDD,Dout,VSS,Dinの4つの端子を備えています.16個の各LEDチップのDout端子とDin端子は,シリアルで数珠繋ぎになっています.つまり,1番目のLEDチップ(LED1)のDout端子は次段のLEDチップ(LED2)のDin端子に接続されています.続くLEDチップも同様に接続されています.最大1024個のLEDを接続できます(今回は16個).
図38に示すのは,16個の各LEDチップに配信される制御データのタイミングです.
1つのLEDチップに,赤色(8ビット),緑色(8ビット),青色(8ビット)の点灯制御データ(全24ビット)を用意して配ります.LED1は,Din端子から入力されたシリアル・データの先頭24ビット分を自分用に取り込みます.残りをDout端子からLED2のDin端子に向けて送り出します.LED2も同様に,先頭の24ビットを自分用に取り込み,残りをLED3に送り出します.WS2812Bは,24ビットのデータを解釈して,赤色,緑色,青色の各LEDの輝度を調節します.
M5Stackから送出する,16個のLEDの点灯制御データの間隔は50μs以下にします.間隔が50μs以上になると,WS2812Bが「データの転送動作は終了した」と判断して,送られてくるデータを次のLEDに転送する処理を停止します.
図37に示したように,3本の配線を使ってM5StackとNeoPixcelを次のように接続します.写真7に外観を示します.
前述のようにPythonは,NeoPixelの各LEDチップにシリアル・データを配信する専用の命令を“machine”モジュールのメソッドに備えています.
ハードウェアの制御ライブラリ「machineモジュール」をソースコードの冒頭で呼び出し(インポート)ます.続けて,制御命令(メソッド)を使って引数を指定することで,点灯させたいLEDの位置番号を選んだり,色を付けたり,明るさを調整したりすることができます.
図39に示すのは,LED1を赤色に光らせるプログラムです.
赤(R),緑(G),青(B)の光量のバランスを変えると,紫色や黄色などの中間色で光らせることができます.LEDの制御命令は,“set(pos,color)”メソッドで指定します.“pos”は,LEDの位置番号を示す引数です.今回使ったNeoPixelは16個のLEDチップを備えているので,1~16の整数値になります.引数“color”には,RGBカラー・コード(#rrggbbの形式)を入力します.これは,赤(8ビット,0~255),緑(8ビット,0~255),青(8ビット,0~255)の各光量を表す24ビットの値です.
よく使う色は,“np.指定職”を使って簡単に設定できます.次の15色が定義されています.BLACKは消灯を意味しています.
1行目で,自作ハードウェア制御モジュール“machine”と時間管理モジュール“utime”をインポートします.
2行目は,NeoPixelを制御する関数(メソッド)を呼び出しています.「NeoPixelの16個のカラーLEDの制御線は,ESP32マイコンのGPIO22端子に接続されているよ」と,M5Stackに教えています.
この設定を行うと,16個の全LEDに「消灯せよ」という命令が自動的に配られます.これは“np.clear()”メソッドと同じ処理です.
3行目の“utime.sleep_ms(1)”は「1ms間プログラムを静止せよ」という命令です.16個の全LEDチップに制御信号を送られるまでに数百μsかかるため,NeoPixelに命令を送った後,1ms程度の待ち時間を設けます.
4行目では,1番目の位置のLEDに赤色の制御データを送ります.
プログラムが終了すると,1番目のLEDが赤く光ります.この状態のまま[STOP]アイコンを押さなければ,インポートしたモジュールやNeoPixelの設定はアクティブ状態が保たれるので,シェルからnp.setメソッドを使って各位置LEDの色を設定できます.
図39に示すプログラムを動かして,Thonnyのシェルから次のコマンドを入力してください.“>>> np.set(1,np.指定色)”の記述を書き換えると,LED1の発光色が変化します(写真8).同様にシェルを使って,LED2やLED3の色を変化させてみてください.
動画1は,1番のLEDの色を赤や緑色に変化させる実験動画です.
続いて,for文を使ってソースコードを記述して,16個の全LEDを好きな色に点灯させてみましょう.図40に示すのは,奇数番号のLED(LED1,LED3,LED5…)を赤色に,偶数番号のLED(LED2,LED4…)を緑色に点灯させるプログラムです(写真9).
1行目で,machineモジュール,utimeモジュールをインポートし,NeoPixelの初期設定を行っています.
3行目で,プログラムを1ms間休止させます.NeoPixel初期設定に数百μsかかるからです.
4~8行目では,for文を使ってNeoPixelに色設定データを送っています.for文は“range(start,stop,step)”関数を使って変数iの範囲を指定します.startには1,stopには16,stepには2,変数iに1,3,5…15という奇数が入ります.
5行目で奇数番目の位置のLEDを赤色にセットし,7行目で偶数番目の位置のLEDを緑色に設定します.6行目と8行目の1ms間の停止は,NeoPixelの全LEDチップに制御データを配る(数百μs)のを待っています.
前述のとおり,LEDの発光は“set(pos,color)”メソッドで制御できます.
メソッドの第1引数(pos)は,LEDの位置番号です.LED1を点灯させたいときは“pos=1”,LED16を点灯させたいときは“pos=16”と記述します.
図41に示すのは,まずLED1を赤色に点灯させ,続けてLED1を消灯して,LED2を赤色に点灯させ,これを繰り返すプログラムです.for文を使って引数“pos”を1から16まで変更します,“pos”が16になったら,また1に戻します.実験結果を写真10に示します.
1~3行目までは,NeoPixelの初期設定です.
4行目で,“while 1:”と記述して,whileの制御文を常に1(True)に設定しています.これで,いったん走り出したら止まらなくなります.
5行目以降は,変数iの値をrange関数で1~16まで変化させるfor文です.6~9行目のインデントされた部分がfor文が有効な範囲です.
6行目のnp.clearメソッドで,16個すべてのLEDを消します.1ms停止した後,8行目でfor文の変数i番目のLEDを赤色に光らせます.
この状態で0.2秒間停止して,6行目のfor文の最初の動作に戻ります.変数iが16になったら一連の動作が終了します.whileの条件文が1なので,最初からfor文が繰り返されます.いったん走り出したらもう止まりません.
実験②は,LED1,LED2,LED3というふうに光るLEDを時計方向に移り変わらせました.これを逆回転,つまり反時計方向に回転させてみます.
実験②では,“for i in range(1,17,1):”と記述して,発光するLEDを1番から16番に1つずつカウントアップしていましたから,これを“for i in range(17,1,-1):”に書き換えてカウントダウンすればよさそうです.
図42のように“for i in range(17,1,-1):”とシェルに記述してリターンを押してください.インデントが自動的に挿入されるので,print(i)命令を記述して,変数iをシェルに表示して確認します.インデントが挿入される制御文の処理範囲を確定させると,勝手にfor文が起動して変数iが表示されます.
iは16から1になるのだろう,と期待していたのに,17から2に変化していました.これではLED1は消えたままです.
図43に示します.“for i in range(16,0,-1):”と記述します.図41のソースコードとほぼ同じですが,5行目のfor文のrange関数の引数が違います.
range関数の引数をstart= 16, stop= 0, step= -1 に設定すると,for文の変数iが“16,15,…2,1”というふうに-1ずつ減り,LEDの発光位置が反時計方向に回ります.
M5Stackが備えるAのボタンを押したら全LEDが赤色に,Bのボタンを押したら全LEDが緑色に,Cのボタンを押したら全LEDが青色に点灯するプログラムを作ってみましょう.
図44にソースコードを,写真11に実験のようすを示します.
1~11行目は,モジュールのインポート文やボタンが押されたときの動作を定義する制御文です.15~17行目は,ボタンが押されたときの動作を記述しています.
1行目で,machineモジュールと utimeモジュールをインポートします.
2行目の“from…”の箇所で,machineモジュールのPinメソッドをインポートします.
3行目と4行目で,NeoPixelを制御できるように設定します.
5~10行目はボタンが押されたときに実行する関数を定義しています.ボタンAが押されたときは関数BtA(p),ボタンBが押されたときは関数BtB(p),ボタンCが押されたときは関数BtC(p)が実行されます.各関数の引数pは,押されたボタン状態の情報が入っています.引数pから押されたボタンの情報を取り出して,関数の内部処理に使うこともできます.今回は使用しません.
各ボタンが押されたときに光る色を引数として,color(設定色)関数を実行するです.color関数の引数で設定色を指定すると,NeoPixelの16個のLEDがすべて設定色で光ります.
11~14行目はcolor関数の記述です.
11行目でcolor関数を定義します.引数は1つでc(設定色のカラー・コード)とします.12行目のfor文を使って,16個すべてのLEDに引数cのカラー・コードを設定データとして送ります.
15~17行目は,A,B,Cの各ボタンのON/OFF状態をマイコンのGPIO端子に伝えて,ボタンが押されたら,プログラムの処理に割り入って指定の関数を処理するように設定しています.ハードウェア端子でソフトウェア処理の流れに割り入ることを「外部割り込み」と呼びます.この方法を利用することで各ボタンの端子を常時監視する必要がなくなります.
15行目は,ボタンAがつながるピン番号(39),ピンの使用モード(入力:Pin.IN)を設定しています.割り込み設定を行う時はピン設定以外に“handler”と“trigger”の引数を設定します.
GPIOピンの2つの引数“handler”と“trigger”を使って初期設定すると,ボタンが押されたことをマイコンが検知するようになります.“handler”は,割り込みが発生したときに呼び出す関数(BtA)です.“trigger”は,トリガをかける条件を設定する引数です.“trigger=Pin.IRQ_RISING”と記述すると,信号が立ち上がったとき,つまりボタンから指が離されたときにトリガをかける,というふうに動作します.“handler”は,トリガ検出後に起動する関数を指定しており,A,B,Cの各ボタンごとに変えています.
(a)“HelloWorld.py”と表示される
(b)実験動画
写真4 図13のPythonソースコード“HelloWorld.py”を実行したところ
M5Stackの液晶ディスプレイに“Hello World”という文字列が表示される
よく使う関数
1. マイコンに1行ずつソースコードを処理させてみよう
マイコンに“1+1”の計算をお願いする
整数か浮動小数かを自動判定してくれる
2. マイコンに一括で全ソースを実行させてみよう
ソースコードの説明
(a)このように記述すると…
(b)“Hello World”と表示される
図19 コード・エディタを使って記述した一連のプログラムを一括して実行する
液晶ディスプレイに“Hello World”という文字列を表示するプログラムを一括処理する.“display”モジュールをインポートして初期設定を行った
コード・エディタとシェルの併用
(a)このように記述すると…
(b)“Hello World"の下に“MicroPython”という文字が追加される
図20 シェルを使うとコードを追加できる
開発環境Thonnyのコード・エディタでいったんプログラムを実行したあと,シェルを使ってプログラムを追加実行できる
3. M5Stackにsinやlogなどの計算をさせてみよう
ソースコードの冒頭で「関数ライブラリを読み込め」と宣言する
図21 Pythonが備えるモジュールのいろいろ
Pythonでは関数を集めたプログラムをモジュールと呼ぶ.シェルに“help('modules')”と入力すると,Pythonが備える標準モジュールの一覧が表示される.ソースコードの冒頭にインポート文を記述すれば利用できる
マイコンにsinの計算を実行させる
(a)演算モジュール“math”を読み込んで,sin(π/2)を計算せよ」と入力してみた
(b)モジュールを読み込まずに,Sin(n/2)を計算させようとするとエラーが出る
(c)このように命令を記述することもできる
図22 Pythonが備える数学関数モジュールを使ってみる
モジュールは“import”命令を使って呼び出す.この前処理をしないでメソッドを実行するとエラーが出る
4. M5Stackが計算した結果をThonnyで取り込んでグラフ化してみる
(a)ソースコード
(b)計算結果
図24 M5Stackにsinを計算させてみた
“print( )”を使うと,シェルに演算結果が表示される.さらにThonnyのPlotter機能を使うと波形も表示される
5. マイコンの入出力端子を制御して電気信号を出し入れしてみよう
周辺回路と信号を入出力するための関数を使う
M5Stackのボタンを押すと,シェルに“Button A”と表示されるプログラムを作る
(a)外観
(b)M5Stack内部の回路
図25 M5Stackの押しボタンとESP32マイコンの接続
M5Stackの押しボタンはESP32マイコンのGPIO端子に接続されている.GPIOピンの変換を読み取ることで,ESP32マイコンはボタンが押されたかどうかを判断する
ソースコードの説明
図26 押しボタンが押されたかどうかを検出する関数“machine”
ボタンAに接続されたGPIO端子(39ピン)のH/Lを0.1秒ごとに調べて,ボタンが押されたと判断したらThonnyのシェルに“Button A”と表示する
よく使うPythonの制御文
処理の繰り返し
①for文
②while文
(a)ソースコード
(b)実行結果
図32 While文で記述したカウントアップ・タイマ
数字(t)が0から1ずつ大きくなっていくプログラム.while文の条件式が真(True)の場合,whileループ範囲を実行する.ここに示すプログラムは,条件式がTrueになっているため,リセットを掛けるまで無限に制御範囲を実行する
③if文
プログラムの説明
関数をカスタム定義する「def文」
プログラムの説明
電子回路を制御してみよう
フルカラー電飾リング「NeoPixel」を光らせる
数珠つなぎの16個のLEDの色や点灯を自在に制御する
M5Stackから全16個のLEDチップに点灯制御データを配る
図38 NeoPixelの全16個のLEDチップに配信される制御データ
各LEDチップには24ビット・データ(GRBの順で各8ビット)がシリアルで配られる.M5Stackから,1番目のLEDチップのDin端子に制御信号をシリアルで入力する.最初の24ビットは1番目のLEDが抜き取り,残りを2番目のLEDに送る.2番目以降のLEDも同じ動作をする
実験① LED1を赤色に光らせる
[手順1]ハードウェアの準備
[手順2]ソースコードを記述する
プログラムの説明
[手順3]やってみよう
動画1 M5StackでNeoPixcelの1つのLEDチップを赤色や緑色,青色に光らせる
プログラムの説明
実験② LEDを1個だけ点灯させて時計方向に回転させる
プログラムの説明
実験③ LEDを1個だけ点灯させて反時計方向に回転させる
間違ったプログラム
正解のプログラム
実験④ M5Stackのボタンで発光色を変える
ボタンが押されたら関数を指定して起動する
プログラムの説明
参考文献・ウェブサイト
(c)2021 Uta Taguchi All Right Reserved.