I2C

概要

I2C(I squared C)はフィリップス社で開発されたシリアルバス。正式な呼称はInter-Integrated Circuitの略で表記はI2Cと上付きが本来とのこと。

マスターに対して1つ以上のスレーブを繋ぐことができて、接続はクロック線(SCL)とデータ線(SDA)の2本だけで済む。マスターからスレーブを指定して、Read/Write信号によりデータを書き込んだり読み込んだりすることができる。

原理(マスターからスレーブへの書き込み)

ビットデータの転送

データはクロック信号に同期してビット情報を転送。SCLの立ち上がり開始から立ち下がり開始までの間にデータを転送する。データを変更(H ⇔ L)する場合には、SCLがLの間にSDAを変更する。

スタートコンディション/ストップコンディション

データ転送のためSCLがHの間にSDAは変化させないが、この間にSDAが変化した場合は不正・無効ではなく、スタートコンディション/ストップコンディションの意味を持つ。

SDAがH→Lに変化した場合はスタートコンディションで、SCLがH→LになったあとLの間に最初のビットの準備をする。

SDAがL→Hに変化した場合はストップコンディションで、その前にSCLがLの間にSDAをLにしてストップコンディションの準備をする。

バイトデータの転送

データはバイト単位で転送される。

マスターからスレーブへの書き込みの場合、フォーマットは以下の様になる(スレーブアドレスが7ビットの場合)。

  1. マスターからスタートコンディション、スレーブアドレス7ビット、RW = 0を送信
  2. 指定されたアドレスのスレーブからACK送信→マスターで受信
  3. マスターから1バイトのデータを送信
  4. スレーブがデータ受信後、ACK送信→マスターで受信
  5. 以降、必要バイト数を送信
  6. 送信終了後、マスターからストップコンディション送信

マスターがスレーブのデータを読み込む場合には、フォーマットは以下の様になる。

  1. マスターからスタートコンディション、スレーブアドレス7ビット、RW = 1を送信
  2. 指定されたアドレスのスレーブからACK送信→マスターで受信
  3. スレーブから1バイトのデータを送信
  4. マスターが受信後、ACK送信→スレーブで受信
  5. 以降、必要バイト数を受信
  6. 受信終了後、マスターからストップコンディション送信

スレーブアドレス送信とRW

マスターからスレーブに対してスタートコンディションを送信し、各スレーブが受信体勢に入る。その後マスターからスレーブアドレスを送信する。

スレーブアドレスが7ビットの場合、MSBから順に7ビット送り、最後にRWを1ビットで送る。RW=1のときマスター側が読み取り、RW=0のときマスターからスレーブへ書き込み。

ACK

I2Cのデータは8ビット単位で転送され、その後にACK/NACKが返される。マスターからスレーブへの書き込みの場合ACKはスレーブからバスに発信され、マスターがスレーブから読み出す場合はマスターから発信される。

スレーブアドレス指定の際、選択されたスレーブはACK信号を1ビットのLで返す。選択されなかったスレーブはストップコンディションを待機。何らかの理由でスレーブ側がデータを受け取れなかったときはNAK信号を1ビットのHで返す。

マスターからスレーブへデータを書き込む場合、8ビット目の送信後にSCLをLにし、スレーブからACKを受け取ってから次のデータの送信を開始する。

マスターがスレーブからデータを読み込む場合、アドレスは上記と同じだが、データについてはマスターがデータ受信後にACKを送る。

ただしスレーブ側で次のクロックサイクルに合わせてデータを送るのに間に合わない場合、スレーブ側でSCLを強制的にLにして、マスターでのデータ読み込みを抑制する(クロックストレッチ)。スレーブの準備完了後にクロックストレッチは解除され、データの読み込みが再開される。

I2Cの有効化

Raspberry PiでI2Cを有効化する手順。

  1. コマンドラインでsudo raspi-configを実行
  2. 画面が変わるので、5 Interfacing Optionsを選択
  3. P5 I2Cを選択

I2Cツール

LinuxベースのRaspberry Piで利用可能なツール。

i2cdetect

sudo i2cdetect ...で実行。Raspberry Piで管理者権限を持っているなら、sudoなしでもok。

i2cdetect -V

バージョン確認。

i2cdetect -l

利用可能なバスの一覧を表示。

i2c-1'1'がバス番号になる。

i2cdetect -F [bus]

指定したバスで利用可能な機能の一覧を表示。

i2cdetect -y [bus]

指定したバスのデバイスアドレスを表示する。

各行の2桁目がアドレスの上位桁、各列がアドレスの下位桁を表していて、ここではデバイスアドレスが1つ(0x27)確認できる。

ライブラリー

Raspberry PiとPythonでI2Cを扱うためのライブラリーsmbus2について(ドキュメントはこちら)。

sudo pip install smbus2でインストール。SMBusはSystem Management Busの略でI2Cのプロトコルと概ね同じ。

smbus2モジュールのSMBusクラスでバスへアクセスするインスタンスを取得。コンストラクターの引数にはバス番号を指定。バス番号はsudo i2cdetectで確認されたバス番号。

以降、read_bytewrite_byteなど、このインスタンスのメソッドを使う。

 

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は暗めに発光する。

MapLibre – コントロールの追加と表示オプション

実装例

MapLibreの組込みコントロール追加方法。地理院地図ベクトルタイルでの表示例。

記述方法

mapMapインスタンスを参照しているとき、以下の形式で記述。

[コンストラクター]はコントロールのコンストラクターで、[位置指定]top-leftbottom-rightなど

コントロールの種類

NavigationControl
ズーム(+/−)とローテーションのボタン。ローテーションはボタン位置でドラッグすると地図が回転し、ダブルクリックで北が上の位置に戻る。
ScaleControl
スケールを表示する。スケール表示はズームレベルに合わせて変化する。
GeolocateControl
携帯端末などでユーザーの位置を扱う。

表示オプション

showTileBoundaries
trueにセットするとタイル境界を表示させる
showCollisionBoxes
trueにセットすると衝突によりラベルが表示されない場合も境界ボックスを描画する。

 

PHP – cURL

流れ

  1. curl_initでセッションハンドルを得る
  2. ハンドルを使ってcurl_setoptcurl_executeなどを実行する
  3. curl_closeでセッションを閉じる

基本形

curl_initでURLを指定する例

curl_init実行時に引数にURLを与え、そのターゲットに対して実行する例。実行結果は上述と同じ。

実行後、コンソールにサーバーから送られてきたレスポンスが表示される。

curl_setoptでURLを指定する例

curl_initを引数なしで実行後、curl_setoptでURLを指定する例。

ヘッダーも取得

curl_setoptCURLOPT_HEADERtrueに設定すると、レスポンスでヘッダーも取得できる。

実行結果にヘッダーが含まれている。

レスポンスを文字列として受け取る

デフォルトではリクエストに対するレスポンスはコンソールに出力される。

curl_setoptCURLOPT_RETURNTRANSFERtrueに設定すると、curl_execの戻り値としてレスポンスの文字列が返される。このとき画面には出力されない。

POST

  • フォームパラメーターを連想配列で設定する
  • curl_setoptCURLOPT_POSTtrueに設定して、POSTメソッドを指定する
  • curl_setoptCURLOPT_POSTFIELDSとフォームパラメーターの連想配列を指定

フォームパラメーターがセットされている。

 

Vagrant – Django – サーバーエラー

概要

以下のような流れでエラー発生・解決した記録。データベース接続なしでとにかくDjangoのサーバー起動とアクセスを確認。

  • Vagrant上のCentOS7にPython3やvertualenvをインストール
  • 仮想環境上でDjango開発用サーバーを起動
  • Exception発生
  • ひとまずデータベースを切ってサーバー起動
  • ブラウザーから接続できず
  • Vagrantfileを編集してIPアドレス変更
  • DisallowedHostで接続できず
  • settings.pyのALLOWED_HOSTを編集
  • 無事接続

データベースを繋がずにとにかくDjangoの応答までを確認する場合、Vagrant環境では以下のように設定。

  • Vagrantfileでポートマッピングを設定
  • VMでifconfig→eth0のIPアドレスを確認
  • settings.pyのALLOWED_HOSTSにブラウザーでアクセスしたいホスト名、IPアドレスを追加
  • 開発用Webサーバーをeth0のIPアドレスとマップしたポートで起動
  • ALLOWED_HOSTSで許可したホスト/IPアドレスとマップしたポートでアクセス

サーバー起動時エラー発生

Vagrant/CentOS7環境上にPython3virtualenvをインストールして、仮想環境を作成。その環境下でDjangoをインストール

とりあえずテスト用のプロジェクトを作成。

プロジェクトで開発用Webサーバーを起動しようとしたところ、エラー発生。SQLiteのバージョンが低いと言っているらしい。

SQLiteを確認したところ、3.7と必要なバージョンより確かに低い。

データベース無効化で再挑戦

そもそもデータベースにはSQLiteではなくMySQLを使っている。またとりあえずの動作確認なので、データベースを設定せずにサーバーを起動してみようと考える。

Laravelでいえば.envファイルにあたる設定ファイルは、Djangoではsettings.pyらしい。その場所を探してみるとプロジェクトディレクトリーと同名のサブディレクトリーにあった。

settings.pyの中のデータベース関係を探して、そこをすべてコメントアウトしてみる。

再度サーバーを起動すると、エラー無く実行された。

ブラウザーで接続不可

サーバーは起動されたが、ブラウザーでhttp://127.0.0.1:8000とするとアクセスできない。

Vagrantのプライベートネットワークに沿った設定とサーバー起動が必要なことを忘れていた。

プライベートネットワーク設定

Vagrantfileの内容を確認・編集

vagrant reloadで再起動し、vagrant sshでCentOS7に入り、ポート設定を見る。

ゲスト側のVMからは10.0.20.15でサーバーを立ち上げ、ホスト側では127.0.0.1で接続する。ポートフォワーディングはホスト・ゲストとも8000

開発用Webサーバーを10.0.20.15:8000で起動。

Djangoで許可されない

ブラウザーでhttp://127.0.0.1:8000http://localhost:8000とするが接続できない。ただしDjangoによって許可されていないらしく、ALLOWED_HOSTSを加えるよう示されている。

ALLOW_HOSTSを編集して接続

settings.pyALLOWED_HOSTSを編集。

ブラウザーからhttp://127.0.0.1:8000あるいはhttp://localhost:8000でアクセスでき、以下のページが表示された。

 

 

 

Linux – bash – シェルプロンプトの変更

プロンプトの書式の確認

Vagrant上のCentOS7でシェルはbash。プロンプトは以下のようになっている。

この書式はPS1変数で設定されている。

それぞれの意味は以下の通り。

  • \u:ユーザー名
  • \h:ホスト名
  • \W:カレントディレクトリー

プロンプトの変更例

$#だけにする

プロンプトの後にスペースを入れておく。

ユーザー名と時刻にする

一部に色を付ける

以下はユーザー名と時刻を表示して、ユーザー名を青にしている(ターミナルではvagrantが青で表示される)。

常時設定する

~/.bashrcexport文を加える。

プロンプト書式に使える記号

以下の記号が使える。

  • \d:日付
  • \h:ホスト名の最初のブロック
  • \H:ドメイン名まで含めたホスト名
  • \s:シェルの名前
  • \t:時間~24時間制
  • \T:時間~12時間制
  • \@:時間~AM/PM形式
  • \u:ユーザー名
  • \w:カレントディレクトリー
  • \W:カレントディレクトリーのベース名
  • \!:コマンドの履歴番号
  • \$:一般ユーザーは$、rootなら#
  • \\:バックスラッシュ

色の設定

色設定はエスケープシーケンスで行う。

  • 設定開始:[ESC]+'['+[色コード]+'m'
  • 設定解除:[ESC]+'['+'39'+'m'

色コードには前景色と背景色がある。

  • 前景色:30~37、90~97
    • 90~97は明るめの色
  • 背景色:40~47
    • 100~107は明るめの色
  • 拡張指定:38
    • 256カラーレベル:38;5;n、48 ;5;n
    • RGB指定:38;2;r;g;b、48;2;r;g;b
  • 色設定解除:39
前景色 背景色
Black 30 40
Red 31 41
Green 32 42
Yellow 33 43
Blue 34 44
Magenta 35 45
Cyan 36 46
White 37 47

 

PHP – 多次元連想配列のソート

概要

キー列が同じ連想配列を要素とする配列の要素を特定のキーに従ってソートするには、以下のようにarray_column()array_multisort()を使う。

問題

以下のような配列があり、この配列の要素をnameageなどで並べ替える方法。

array_multisort()を使う

array_multisort()は第1引数指定した1次元配列の順番に従って、第3引数の配列の要素をソートする。第2引数にはソートの昇順/降順を指定する。

たとえば以下の例では、2つの要素を持つ連想配列の配列を並べ替えている。

この例の流れは以下のとおり。

  • 第1引数の配列[3, 2, 1]の各要素が$aの各要素に対応している
  • 第2引数で昇順(SORT_ASC)を指定
  • 第3引数の配列がこれに従って並べ替えられ、内容が変更される

なお第1引数と第3引数の次数が等しくない場合はWarningとなり、第3引数の配列は変更されずに処理が進む。

また、第1引数の配列の要素が文字列の場合は辞書順で並べ替えられる。

array_column()

array_multisort()の第1引数に第3引数のあるキー列を選べば、そのキー列に従って並べ替えられる。

問題の配列の'age'のキー列は以下のとおり。

手順

このキー列の値の昇順で元の配列を並べ替えるには、第1引数に上のarray_culumn()を適用すると、'age'の昇順で配列が並べ替えられる。

降順に並べ替えたいときはSORT_DESCを指定する。

 

HTML – input – file

基本形

ファイルアップロードは、FORM要素とINPUT要素のそれぞれで属性の設定が必要。

FORM要素は以下のように記述する。

  • methodPOST
  • enctype属性に"multipart/form-data"を設定する

INPUT要素は以下のように記述する。

  • type属性を"file"に設定する
  • methodPOST
  • name属性を設定する
    • この属性値で言語やフレームワークによってファイルを扱う
    • 以下の例ではname属性値を"file"としている

この場合の動作は以下のとおり。

  • "ファイルを選択"ボタンを押すとダイアログがファイル選択ダイアログが表示される
  • 一度に1つのファイルを選択できる
  • ファイルを選択して"開く"ボタンを押すとファイルがアップロードされる

複数ファイルの選択

基本形ではダイアログで1つのファイルしか選択できない。複数ファイルを選択・アップロードできるようにするには、INPUT要素を以下のように記述する。FORM要素に変更はない。

  • type属性を"file"に設定する
  • methodPOST
  • name属性の値の末尾に[]を付けて配列にする
    • 以下の例ではname属性値を"files[]"としている
  • multiple属性を追加

これによってファイル選択ダイアログで複数のファイルが選択・送信できるようになる。

 

Laravel – ルーティングが効かない

現象

routes/web.phpにルーティングを追加したが、そのルーティングが機能せずブラウザの表示が真っ白になってしまった。

原因

以下のような順番でルーティングを書いたため。

理由

URLに.../products/select_typeが与えられると、まずリソースルーティングのところで.../products/{id}として解釈されてしまい、以降のルーティングに到達しないため。

解決

ルーティングの順番を再考する。基本的に個別ルーティングはリソースルーティングより前に置く。

 

 

PHP – new staticとnew self

概要

staticselfnewと組み合わせることでクラス内でインスタンスを生成する際に使えるが、以下のような違いがある。

  • new staticはそれが実行されるときのクラスのインスタンスを生成する
  • new selfはそれが定義されたときのクラスのインスタンを生成する

参照:static::とself::

準備

以下のようにParentClassとそれを継承したChildClassを準備する。

  • いずれも同じ名前のインスタンスメソッドmethod()を持つ
  • それぞれのクラスはスタティックメソッドparent_method()child_method()を持つ
  • 何れの内容も同じで、以下を実行する
    • (new static)->static_method()
    • (new self)->static_method()

new staticnew selfはクラスのインスタンスを生成する。この例では()->で生成されたインスタンスから直接メソッドを呼び出しているが、$instance = new staticのように一旦変数に参照させて$instance->method()としてもよい。

親クラスのメソッドで生成する場合

親クラスのメソッド内でstaticselfで生成されるインスタンスは親クラスのインスタンス。

子クラスのメソッドで生成する場合

子クラスのメソッド内でstaticselfで生成されるインスタンスは子クラスのインスタンス。

継承元の親クラスのメソッドで生成する場合

子クラスから継承元の親クラスのメソッドを呼んで、その中でstaticselfで生成されるインスタンスは以下の通り。

これらは以下のような動作による。

子クラスから呼ばれた親クラスのスタティックメソッドで以下が実行される。

new staticで生成されるのは、この文が実行されるときにスタティックメソッドを呼び出したChildClassなので、ChildClassのインスタンスが生成されて、そのmethod()が呼ばれる。

new selfで生成されるのは、この文が定義されたParentClassなので、ParentClassのインスタンスが生成されて、そのmethod()が呼ばれる。