7セグメントLED

配置図

7セグメントLEDのピン配置は以下の通り(コモンカソードの場合)。

セグメントコード

各セグメントを0で消灯、1で点灯するとして、a~g及びDPを逆順にして0~Fを表示させるビット配列は以下のようになる。

表示 dp g f e d c b a Hex
0 00111111 0x3f
1 00000110 0x06
2 01011011 0x5b
3 01001111 0x4f
4 01100110 0x66
5 01101101 0x6d
6 01111101 0x7d
7 00000111 0x07
8 01111111 0x7f
9 01101111 0x6f
A 01110111 0x77
B 01111100 0x7c
C 00111001 0x39
D 01011110 0x5e
E 01111001 0x79
F 01110001 0x71

GPIOに直接接続

7セグメントLEDの動作を確認するため、以下の様にRaspberry Pi 4BのGPIOに接続した。

点灯テストは以下のコードで行った。

  • LEDの各ピンにGPIOのピンを割り当て
  • 0~9, A~Fの表示に対応するビットパターンを定義
    • ビット配列はdp, g, f, e, d, c, b, aの逆順
  • 16個のパターンを0.5秒ずつ表示
  • パターン表示はビット配列を必要分だけシフトして、ピンに対応するビットが1の場合にセグメントを点灯、0の場合に消灯
  • 終了時に全セグメントを消灯

このような接続の場合、LEDの8つのピンに対応してGPIOのピンも8つ消費される。

より少ないピンの数で7セグメントLEDを接続するためには、シフトレジスターを用いるのが一般的。

 

Raspberry Pi – LEDバーグラフ

概要

LEDバーグラフの実験例。DavinciキットのLEDはピン配置がわからなかったので、まず3.3VとGNDで確認した。

回路図

以下の通り、アレイになっている10個のLEDを3.3Vに抵抗を介して繋ぎ、各ポートに接続。ポートのレベルをHIGHにするとLED消灯、LOWにするとLED点灯になる。

コード

今回はピン番号を物理番号(GPIO.BOARD)で定義している。接続数は多いが独立したLEDを扱うのと同じで、以下の例では短い間隔でLEDを順次点灯・消灯させて、流れるように表示させている。

 

Raspberry Pi – RGB LED


概要

DavinciキットのRGB LEDを試してみる。オリジナルのコードを少し変えて、3色をまとめて扱うするクラスを作ってみた。また、徐々に明るさを変化させてみた。

回路

RGB LEDのピン配置は以下のようになっており、最も長いピンがGNDでRed-GND-Green-Blueの順に配置されている。

回路図は以下の通り。

コマンドラインで以下を実行して、接続を確認。

基本コード

辞書でR/G/Bのピン番号を設定し、周波数を100HzにしてLEDの発色を確認。

クラス化と色変化

3色のLEDをまとめて扱うクラスを定義。

  • コンストラクターでピン番号と周波数を指定してインスタンスを生成
  • startメソッドでPWMの作動開始
  • changeDutyCycleメソッドでデューティー比を変更設定
  • stopメソッドでPWM停止とGPIOのリソース解放

定数COLORSで定義した色を順次発色させている。カラーコードからデューティー比への変換は1つの関数で一括して行っている。

色と輝度の変化

R/G/Bを順に徐々に明滅させる例。カラーコードや変換関数は使わず、直接各色のデューティー比を0~100~0に変化させている。

 

Ruspberry Pi – PWM

概要

Raspberry PiでPWM (Pulse Width Modulation)を使う基本方法を整理する。

  • GPIO.PWMメソッドで、使用するピンと周波数を設定
  • PWM.startメソッドの引数にデューティー比を指定して実行開始
  • PWM.ChangeDutyCycleメソッドの引数でデューティー比を指定して変更

回路

LED点滅と同じ構成で、アノード側の抵抗をGPIO13に、カソードをGNDに接続する。

コード

以下のコードでは、100HzのパルスでLEDを点灯させ、順次輝度を落としている。

要点は以下の通り。

  • 13行目で100HzのPWMをGPIO13に設定
  • 16行目でデューティー比100%でスタートし、2秒点灯
  • 20行目でデューティー比を50%に低減
  • 24行目でデューティー比を10%に低減

この結果、スクリプト実行後LEDが3段階で暗くなっていき、最後に消灯する。

スクリプトによる実装

スクラッチでスクリプトを以下のように書いても同様の動作をさせることができる。

要点は以下の通り。

  • frequencyにはLED点滅切替えの周波数をHzで指定し、その逆数=周期(秒)をtime_sliceに設定
  • デューティー比duty_ratioを指定し、点灯/点滅の時間をtime_sliceに乗じて算出・設定

たとえばfrequencyが100Hzの場合1サイクルは0.01sec。ここでデューティー比0.3とすると、点灯時間は0.003sec、消灯時間は0.007secとなり、LEDは暗めに発光する。

Raspberry Pi – LED点滅

概要

SunFounderのDa Vinciキットを買ったので、まずLED点滅から勉強。実行の主要部分を強調するため一部簡略化した。流れは以下の通り。

  • LEDと保護抵抗を直列に繋ぎ、アノード側を電源ライン、カソード側をGPIO17に接続
    • GPIO17がHIGH (3.3V)のときは電源電圧とバランスしてLEDが消灯
    • GPIO17がLOW (0V)の時は電流が流れてLEDが点灯
  • MicoroPythonで、GPIO17のHIGH/LOWをタイマーでウェイトさせながら切替え

要点

  • GPIOを制御するライブラリーRPi.GPIOGPIOの名前でインポート
  • GPIO.setmode(GPIO.BCM)でBCMナンバリングモードに設定
  • GPIO.setup(ピン番号, GPIO.OUT, initial=GPIO.HIGH)でGPIO17を出力に設定し、初期レベルをHIGH (LED消灯)に設定
  • GPIO.output(ピン番号, GPIO.HIGH/LOW)で電圧レベルを切替え
  • キーボード割込みにtry~except KeyboardInterrupt~を利用
  • 終了時にGPIO.cleanup()でリソースを解放

回路図

LEDのアノード側に220Ωの抵抗を介して3V3 (3.3V)へ、カソード側はGPIO17に繋ぐ。DavinciのLEDの定格電流は不明だが20mAとすると、この回路の場合はi = 3.3/220で15mAで定格内に納まっている。

回路組み立て

ブレッドボードにGPIO拡張ボードを挿し、Raspiと接続。

テスト

コマンドライン

RaspiのThonnyを立ち上げ、コマンドラインで以下を実行していく。

まずライブラリーのインポート。

エラーが出ず無事にインポートされたので、次はGPIOのモードをBCMにセット。

LEDのピン番号をBCMの17にセット。

GPIO17を出力用にし、初期値をHIGH (3.3V)にセット。

GPIO17の電圧レベルをLOW (0V)にセットし、LEDの点灯を確認。

GPIO17の電圧レベルをHIGHにセットし、LEDの消灯を確認。

スクリプト

とりあえず以下のスクリプトでLEDの点滅を確認。

CTRL-Cでキーボード割込みがあったときに安全に終了するための処理を導入。

SunFounderサイトではsetup()以下をif __name__ == '__main__':ブロックの中に入れているが、これはこのファイルが直接実行されたことを確認するためのもの

接続を反対にする

左記の回路ではLEDのアノード側に3.3Vを供給し、カソードを接続したGPIO17でHIGHの時にLED消灯、LOWの時にLED点灯とした。

一方、以下のようにアノード側の抵抗をGPIO17に接続し、カソードをGNDに接続しても動作させることができる。この場合、GPIO17がHIGHでLED点灯、LOWでLED消灯となる。

コードは以下の通り。GPIO.setup()ではinitialのデフォルトがGPIO.LOWとして明示的に指定していない。

 

Raspberry Pi Pico~導入

概要

Raspberry Pi Picoを導入した記録。導入済みのRaspberry Pi 4Bに接続して、RaspbianのThonnyで動作確認。

購入したもの

Rasberry Pi Pico本体と接続用のUSBケーブル。

本体はプラスチック製のパッケージに入っていて、この上から透明フィルムでカバーされていた。フィルムがケースに貼り付けられているのが両側の耳の部分だけで間はペラペラと隙間が空いていたが、これくらいでも大丈夫なくらい頑丈ということか。

Picoの本体。右側がMicoroBのUSBソケットで、その左側に白いBOOTSELスイッチとLEDがある。

Thonnyの接続テスト

ファームウェアの準備

以下の手順でThonnyの接続環境を整えた。

  1. Raspberry Pi親機を起動しておく
  2. PicoのBOOTSELスイッチを押しながら、PicoとPi親機をUSBで接続
  3. Picoがリムーバブルディスクとして認識されるのでファイルマネージャーで開く
  4. /media/pi/RPI-RP2ディレクトリーが開き、INDEX.HTMとINDO_UF2.TXTの2つのファイルが入っている
  5. INDEX.HTMをダブルクリックしてRaspberry Pi Documentationのページを表示し、MicroPythonのファームウェアをダウンロード
  6. ダウンロードされた拡張子uf2のファイルをINDEX.HTMLと同じディレクトリーにコピー

Thonny接続テスト

  1. Thonny右下のPython表示をクリックしてMycroPython (Raspberry Pi Pico)に変更
  2. 以下のコードを書いてローカルに保存、実行
  3. 点灯を確認(左下の緑色LEDが点灯している)
  4. led.value(0)に変更して実行してLEDを消灯
  5. 以下のコードでLEDのON/OFF点滅を確認

Picoの自動実行

自動実行方法

Picoにmain.pyファイルが保存されていると、電源接続後にその内容を実行する。

Thonnyを使っている場合、親機で実行確認後に同じ内容のファイルをmain.pyとしてPicoに保存する。

自動実行内容の編集・削除

main.pyを持つPicoからこのファイルを削除したり、別の内容に書き換えたい場合には、ThonnyのメニューからRunStop/Restart backendを指定。

停止後にmain.pyを削除したり書き換えた後、再度Stop/Restart backendで動作を開始させる。

注意点

BOOTSELは初期化

  • BOOTSELを押しながらPicoを接続するとPicoの内容が初期化される
  • 初期化後に環境を構築すると、以後はBOOTSELを押さずに接続してその環境で実行できる
  • 逆に言えば、BOOTSELで接続すると前の環境は消えてしまう

ファームウェアを入れるとRPI-RP2は見えなくなる

  • BOOTSEL直後はPicoがリムーバブルディスクとして/media/pi/RPI-RP2で確認できる
  • ここでたとえばMicroPythonのファームウェアを入れると/media/piの中が空になり、RPI-RP2は見えなくなる

ThonnyでPico側のファイルを確認できる

  • ただしローカルで作成したPythonコードはPicoと接続しているThonnyによってPicoに転送されている
  • これを確認するには、ThonnyをReguler modeで起動し、表示(View)でファイル(Files)をチェックする

 

Raspberry Pi~導入

概要

Raspberry Piを導入した記録。

KSYショップでRaspberry Pi 4のスターターキットを購入。OSはSDHCカードにインストール済みだったので、接続するだけで起動。OS書き込みからでもよかったが、品薄が続く中で本体購入可能なこのキットを選択。

ついでにKVMスイッチを介して、WindowsマシンとRaspberry Piを切り替えられるようにした。

購入したキット

KSYのPi4 B 4GB スターター キット 6点セット V4で、以下の内容。

  • KSY Raspberry Pi 4 Model B 4GB
  • Piケース OKdo 3ピース for 4B 透明
  • USB電源アダプター 5V 3A Type C 1.5m
  • OS書込済み Apacer microSDHC 32GB CL10 UHS-I
  • HDMIケーブル HDMI(A)-micro(D)
  • ヒートシンク 40x30x6 熱伝テープ付 for Pi

開封後のパーツ。ケースにOKdoのロゴ。

包装から出したパーツ。本体には技適マークもプリントされている。説明書は通常の注意書きレベル。

組み立て

ヒートシンク

ヒートシンクの熱伝導シートを始めにCPUに貼り付けたが、この後両面テープのヒートシンク側をはがすのに苦労した。

ケース

OKdo製のこのケースは3つに分かれている。

まず下側のケースに、コネクター位置を合わせながら本体を取り付ける。

起動

ひとまずメインマシンのモニター、マウス、キーボードを外してRaspiに接続。ACアダプターを接続して暫くすると起動。

起動後のwelcomeダイアログ。この後、locale選択や画面余白の調整などの設定へ進む。

更新にはちょっと時間がかかり、以下のようなエラーが出たがそのまま進む。更新のバージョンがstableからoldstableに変更されたということらしい。

この後KVMスイッチに繋ぎ変えて、無事にメインマシンとの切替えに成功。

コンソールからlsb_releas -aコマンドで確認したところ、OSはRaspbian GNU/Linux (buster)となっていた。

 

JS/ES – Promise

非同期実行の簡単な例

以下の例では2つのブロックが非同期に実行され、コードが書かれた順番ではなく実行時間の短い順に出力される。

Promiseによる実行順序の保証

基本形

Promiseオブジェクト.then()

この基本形では、以下の手順で処理間を同期させる。

  1. Promiseオブジェクト生成
    • 生成時の引数で渡す無名関数に先行処理を記述
    • 無名関数の引数で処理終了を発行する関数(resolve)を受け取り
    • 先行処理終了のところでresolve関数を実行
  2. Promiseオブジェクトのthenメソッドを記述
    • thenメソッドの引数で渡す無名処理に後続処理を記述
    • この後続処理は、先行処理のresolve関数が実行された後に実行される

処理完了のための関数名は任意だが、staticメソッドと同じ関数名のresolveが使われる。

以下の例では、Promise・・・・・・・・・・・・・無名関数の引数をresolveとして受け取り、resolve関数を300ms待機後の表示の後に実行している。

そしてその実行後に100ms待機の処理が実行される。

Promiseオブジェクトのthenメソッドには引数に無名関数を指定する。Promiseオブジェクトで設定したresolveメソッドが実行された後に引数の無名関数が実行される。

以下の例では、上のPromiseオブジェクトで設定した300ms待機後の表示の後に、thenメソッドで設定した100ms待機・表示が実行される。

new Promise~then

生成したPromiseオブジェクトから直接thenメソッドを実行してもよい。

Promiseオブジェクトを返す

優先実行させたい処理をPromiseオブジェクトとして、そのインスタンスを関数の戻り値とする書き方。関数にthenメソッドが適用できる。

resolveで値を渡す

resolve関数に引数を渡し、これをthenメソッドで受け取ることができる。

thenのチェイン

thenメソッドを連ねてシリアルに実行させる書き方。後続を持つthenメソッドの戻り値をPromiseオブジェクトとするのがミソ。

reject

Promiseの処理で何らかの問題が生じた場合にrejectすることができる。この場合、resolveが実行されないのでthenは処理されず、直近のcatchが呼ばれる。

以下の例ではPromiseオブジェクトで300msのブロックの最後でrejectが実行され、thenメソッドは実行されずにcatchメソッドが実行される。

 

Promise.all~全ての実行を待機

 

MapLibre – Popup

概要

クリック位置に地物(Feature)があれば、その属性をポップアップで表示する。ここでは地理院ベクトルタイルを表示させた地図に地物を表示させ、これらをクリックしたときにその属性を表示させている。

クリック時の地物の捕捉方法はこちらを参照。

実装例

内容

Popupには任意のHTMLを書けるが、ここではqueryRenderedFeaturesで取得した地物の属性を出力している。複数の地物が捕捉された場合、その分だけのポップアップが表示される。Popupは内容に合わせて幅や高さが調整される。

Popup生成時の引数で、クリック時の消去をfalseにして、スタイル設定用のHTMLクラス名を設定している。

その後、生成したPopupインスタンスの位置と表示内容をセットして、地図に貼り付けている。

ポップアップ内で桁を揃えるためのスタイルは、head要素内で定義している。

 

MapLibre – ソースの地物を捕捉する

概要

地図上でマウスクリックしてaddSourceaddLayerで表示した地物(Feature)を捕捉する。

  • FeatureCollectionの個々のFeature'properties'で属性を設定
  • map.on('click', ...)でマウスクリックを捕捉
  • クリック位置で地物を表示したレイヤ上の地物があれば、その属性等をコンソールに表示

実装例

内容

  • FeatureCollectionで2つのPointを定義し、それぞれのidとnameを属性として設定している
  • Pointのレンダリングは青い丸としている
  • クリック時のリスナーをmap.on('click', ...)で登録している
  • クリック位置のFeature群をqueryRenceredFeaturesで取得している
    • 第2引数で取得対象のソースがあるレイヤーを限定している
  • 取得したFeature群をforEachで1つずつ取り出して表示
    • このとき取り出した1つのfeatureundefinedでない場合だけ表示させている