YoctoでRaspberryPi 3B+向けのOSを作ってみる

こんにちは。

私は現在、『ラブライブ!虹ヶ咲学園スクールアイドル同好会』を視聴しています。

天王寺璃奈さんはかわいいですね。
彼女は感情を表に出すのが苦手で、普段はスケッチブックに表情を描き、コミュニケーションをとっています。
また、技術面に明るく、アイドル活動時は顔を覆うディスプレイを自在に制御し、豊かな感情を表現しています。
youtu.be

そんな折、こんなツイートを見かけました。

ハードもソフトも自作している天王寺璃奈さん。OSもカスタマイズしていることでしょう。
きっとYocto Projectを利用しています。
というわけで僕もYoctoを触りたいと思います。

モチベーション

Advent calendar用 兼 仕事の勉強です。
ありふれた内容ですが、まずは人の真似からということで初めてみます。

ちょうどラズパイを持て余していたこともあり、
まずは最小限のラズパイ用OSをYoctoでビルドしてみます。

Yocto Projectとは

簡単に言うと、組み込みシステム向けのLinuxを作るためのツールです。
OSを作るための諸々がまとまっているものという認識でいます。
Yoctoのいい点は、オリジナルの構成を作れること、デファクトスタンダードであることです。
デファクトスタンダード最高。

詳しくは公式や「Yocto とは」でヒットした記事を読んでください。
触ってみたい方は岩松さんの『レシピの作り方入門』がいいと思います。

作業環境

以下の内容をUbuntu20.04 on VirtualBoxに割り当てて作業します。

項目 内容
プロセッサ Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz 8コア
メモリ 10GB
ストレージ SSD 10GB, HDD 1TB

環境構築

まずはYocto Projectを導入していきます。 公式導入手順を参考に、必要なパッケージをインストールしていきます。

$ sudo apt install gawk wget git-core diffstat unzip texinfo gcc-multilib \
build-essential chrpath socat cpio python3 python3-pip python3-pexpect \
xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev \
pylint3 xterm

ビルドツールPokyをcloneします。

$ git clone git://git.yoctoproject.org/poky

ラズパイ用のOSを作るにあたって必要なmeta-raspberrypiをcloneします。
レイヤーはpokyにまとめておきました。

~/poky$ git clone https://github.com/agherzan/meta-raspberrypi.git

ビルド

pokyディレクトリでbuildディレクトリを作成します。

~/poky$ source oe-init-build-env

レイヤ追加

build/conf/bblayers.confに、先ほどcloneしてきたレイヤmeta-raspberrypiを追加します。
これで、ビルドツールbitbakeがレイヤを認識してくれます。

BBLAYERS ?= " \
  /path/to/poky/meta \
  /path/to/poky/meta-poky \
  /path/to/poky/meta-yocto-bsp \
  /path/to/poky/meta-raspberrypi \
  "

対象マシン設定

対象マシンを設定するために、build/conf/local.confを編集します。
私の場合はRaspberry Pi 3B+で、SoCのBCM2837が64bitアーキテクチャを採用しています。 せっかくなので、raspberrypi3-64を採用します。

マシン名は、meta-rasberrypi/docs/layer-contents.mdmeta-rasberrypi/conf/machine/以下で確認できます。

## Supported Machines

* raspberrypi
* raspberrypi0
* raspberrypi0-wifi
* raspberrypi2
* raspberrypi3
* raspberrypi3-64 (64 bit kernel & userspace)
* raspberrypi4
* raspberrypi4-64 (64 bit kernel & userspace)
* raspberrypi-cm (dummy alias for raspberrypi)
* raspberrypi-cm3

マシン名をlocal.confの末尾に追記します。

MACHINE ?= "raspberrypi3-64"

ビルド実行

今回は最小限の構成でビルドします。
天に3回祈って寝ます。結果は追記します。

$ bitbake core-image-minimal

(追記2020/12/03)ビルド成功してました。4時間弱かかりました......

ビルド生成物

ビルドで生成されたファイルを確認します。
生成物は、build/tmp/deploy/images/マシン名以下にあります。
大量にありますが、今回必要なのは
Image,core-image-minimal-raspberrypi3-64.tar.bz2,bcm2837-rpi-3-b-raspberrypi3-64.dtbのみです。
(ファイル名からの判断なので動作確認してません。今microSDがないので......)

トラブルシューティング

VBoxの共有フォルダ内で作業していたが、bitbakeが権限的に実行できなかった。
仕様で共有フォルダの権限を変更できないので(グループに入ることで読み書きはできるがbitbakeはnot permittedされる)、
結局、VBoxでHDDを追加、Ubuntuでマウントして作業ディレクトリを移動した。

まとめ

環境構築から記事作成までぶっ通しでやったので疲れた......。
次はGUI(wayland)を追加するのもいいかもしれない。

LoRaモジュール[ES920LR] 使用法(ラズパイ、WindowsPC)

使用機器 ES920LRA1B, ES920EB
https://tokyodevices.jp/items/252
https://tokyodevices.jp/items/253

PC(win)と接続

PCとES920EBをUSBケーブルで接続する

Tera Term設定

  1. TeraTerm起動
  2. 設定>端末 でローカルエコーON, 送信CR+LF
  3. 設定>シリアルポート でボーレート115200に設定

[参考]仕様書などのリンク
https://tokyodevices.jp/items/233

f:id:mats12345:20191211113242p:plain

LoRa設定

コンフィグモード(設定)とオペレーションモード(通信)が存在する。

オペレーションモードで "config" を入力・リセットボタン押下するとコンフィグモードに移行する。

コンフィグモードで "q 2" "w" を入力・リセット押下でオペレーションモード移行

  1. Tera Term設定後、ES920EBのリセットボタン押下
  2. "Select Mode [1.terminal or 2.processor]" と出るので "1" or "2"(好きな方)を入力(再起動時オペレーションモードならコンフィグモードに移行)
  3. 帯域幅・拡散率を設定 "bw 3" "sf 7"とか(相手と一緒ならok)
  4. 通信モード設定 "q 2"入力
  5. 親子を設定 "node 1" または "node 2"入力(1:親 2:子)
  6. 設定を保存 "w"を入力
  7. リセットボタン押下
  8. 好きなメッセージを入力し送信する

相手側で受信が確認できなかった場合、"show" コマンドで IDやPANなどの設定を確認する。

参考
https://ambidata.io/samples/network/lora-2/

エラーメッセージはコマンド仕様書を参照する。 f:id:mats12345:20191211113209p:plain

ラズパイ3と接続

ラズパイとES920EBをUSB接続する
Pythonで制御する

ラズパイ

Python2.7

参考 https://github.com/AmbientDataInc/LoRa-rssi-measure/tree/master/RPi3

lora.pyにLoRa利用系の関数が入ってる

17: self.s = serial.Serial('/dev/serial0', 115200)

の部分を、LoRaを接続したUSBSerialに対応するポートに変更する。

main.pyに動作を書く
while(True):内を書き換える形でコーディングする

続き

更新中

ラズパイ3B+でLEDJ

はじめに

このアカウントを見て興味を持ったのでやってみます。
LEDJ同好会 (@teamLEDJ) | Twitter

用意するもの

  • ラズパイ

  • LEDパネル
    amazonに安いのがありますが、ピカリ館のほうは店舗チェック済みの商品らしいです。
    LEDマトリクスパネル - akibaLED ピカリ館

  • 電源
    定格に合ったACアダプタ切ってLEDパネル付属のコネクタにくっつけました

  • メス-オスのジャンパ線
    またはコネクタ

配線

パネルが1枚の場合は😄のみ配線してください。 github.com

制御ライブラリ導入手順

  1. Raspbian LiteをSDカードに書き込む
    Desktopだといろんなドライバとかライブラリとか設定とかが邪魔して表示が乱れました(原因多すぎてよくわかってない)
    参考 FAQ>Ghosting Issue Examples
    開発者もLiteがいいよって言ってます GitHub - hzeller/rpi-rgb-led-matrix: Controlling up to three chains of 64x64, 32x32, 16x32 or similar RGB LED displays using Raspberry Pi GPIO
    セキュリティの設定などしたら次へ進みましょう

  2. ライブラリのダウンロード
    gitコマンドやUSBなどで任意のディレクトリにrpi-rgb-led-matrixを保存

  3. コンパイル・デモ実行

cd rpi-rgb-led-matrix
make
cat <<EOF | sudo tee /etc/modprobe.d/blacklist-rgb-matrix.conf
>blacklist snd_bcm2835
>EOF
 
sudo update-initramfs -u
sudo reboot
sudo ./demo 

次のようなオプション一覧が表示されれば成功です。

Expected required option -D <demo>
usage: examples-api-use/demo <options> -D <demo-nr> [optional parameter]
Options:
    -D <demo-nr>              : Always needs to be set
    -t <seconds>              : Run for these number of seconds, then exit.
    --led-gpio-mapping=<name> : Name of GPIO mapping used. Default "regular"
    --led-rows=<rows>         : Panel rows. Typically 8, 16, 32 or 64. (Default: 32).
    --led-cols=<cols>         : Panel columns. Typically 32 or 64. (Default: 32).
    --led-chain=<chained>     : Number of daisy-chained panels. (Default: 1).
    --led-parallel=<parallel> : Parallel chains. range=1..3 (Default: 1).
    --led-multiplexing=<0..9> : Mux type: 0=direct; 1=Stripe; 2=Checkered; 3=Spiral; 4=ZStripe; 5=ZnMirrorZStripe; 6=coreman; 7=Kaler2Scan; 8=ZStripeUneven; 9=P10-128x4-Z (Default: 0)
    --led-pixel-mapper        : Semicolon-separated list of pixel-mappers to arrange pixels.
                                Optional params after a colon e.g. "U-mapper;Rotate:90"
                                Available: "Rotate", "U-mapper". Default: ""
    --led-pwm-bits=<1..11>    : PWM bits (Default: 11).
    --led-brightness=<percent>: Brightness in percent (Default: 100).
    --led-scan-mode=<0..1>    : 0 = progressive; 1 = interlaced (Default: 0).
    --led-row-addr-type=<0..2>: 0 = default; 1 = AB-addressed panels; 2 = direct row select(Default: 0).
    --led-show-refresh        : Show refresh rate.
    --led-inverse             : Switch if your matrix has inverse colors on.
    --led-rgb-sequence        : Switch if your matrix has led colors swapped (Default: "RGB")
    --led-pwm-lsb-nanoseconds : PWM Nanoseconds for LSB (Default: 130)
    --led-pwm-dither-bits=<0..2> : Time dithering of lower bits (Default: 0)
    --led-no-hardware-pulse   : Don't use hardware pin-pulse generation.
    --led-slowdown-gpio=<0..2>: Slowdown GPIO. Needed for faster Pis/slower panels (Default: 1).
    --led-daemon              : Make the process run in the background as daemon.
    --led-no-drop-privs       : Don't drop privileges from 'root' after initializing the hardware.
Demos, choosen with -D
    0  - some rotating square
    1  - forward scrolling an image (-m <scroll-ms>)
    2  - backward scrolling an image (-m <scroll-ms>)
    3  - test image: a square
    4  - Pulsing color
    5  - Grayscale Block
    6  - Abelian sandpile model (-m <time-step-ms>)
    7  - Conway's game of life (-m <time-step-ms>)
    8  - Langton's ant (-m <time-step-ms>)
    9  - Volume bars (-m <time-step-ms>)
    10 - Evolution of color (-m <time-step-ms>)
    11 - Brightness pulse generator
Example:
    examples-api-use/demo -t 10 -D 1 runtext.ppm
Scrolls the runtext for 10 seconds

結果

P6-16×32のLEDパネルです。

sudo ./demo -D 0 --led-rows=16 --led-cols=16

f:id:mats12345:20190626113953g:plain

以降

BluetoothWi-Fi使ってスマホかPCをコントローラみたいにしたいな〜

LoRaモジュール(ES920LRA1B)起動まで

EASELが説明書出してますが見落としがあって苦戦したので起動までの流れをまとめます。 説明書と合わせて参考にしてください。

使用機器

ES920LRA1B
https://tokyodevices.jp/items/252

FTDI USBシリアル変換アダプター(5V/3.3V切り替え機能付き)
3.3Vに設定
https://www.switch-science.com/catalog/1032/

USBケーブル

ジャンパ線

10ピン2.54ピッチ(2×5)←→1.27ピッチ(1×10)変換基板 金フラッシュ(4個入)
http://akizukidenshi.com/catalog/g/gP-07380

Win7PC(TeraTerm,FTDI driver)

配線

ラベルを張っている側から見て左上のピンから1~13, 右下から14~26

配線箇所 1(GND),8(TX),9(RX),13(Vcc)
変換基盤を左側のみはんだ付け
FTDI USBシリアル変換アダプターにジャンパ線で接続

TeraTermでの操作

設定>シリアルポートから以下のように設定 あと設定>端末からローカルエコーON、送信CR+LF、受信CRに設定

f:id:mats12345:20190618150015p:plain

接続後”1”を入力 ターミナルモードに入る(”2”でプロセッサモード)
コマンド一覧が出るので好きなように設定していく

たぶん “NG 001” (未定義)とか “NG 002”(オプション値以上)が出がち
説明書要参考

次やること

設定、一対一通信

参考

LoRa モジュール ES920LRA1
https://tokyodevices.jp/items/252

特定小電力無線モジュール ES920LR LoRaWAN 仕様ソフトウェア説明書 Version. 1.10 株式会社 EASEL
https://bit.ly/2ZtERkT

Raspberry Pi 3 ModelB+(Zero W)でBluetooth Low Energyのデータ利用

背景

BLE Nano v2→ATMEGA328p(Arduinoとして使ってる)→sakura.io で作ってたBLEレシーバが、横通り過ぎるだけだと1m以内でも検出に難があったので緊急的にラズパイをレシーバとして使う

目標

ラズパイ3B+でBLE機器のBDアドレスを取得する。 GPIOでArduino+sakura.ioにUART送信 できればZero Wでの実装を目指す。

方法

Python2.7

ライブラリ

blog.kakakikikeke.com

あとpyserial

設定

GPIOとBluetoothで同時にシリアル使う Raspberry Pi 3で Bluetoothを生かしつつシリアル通信を有効にする方法(コンソール通信でログイン可能) (ラズパイ3で Bluetoothと UART通信の両方を使える様にする設定方法のまとめ。)

コード

scan.py pybluez/scan.py at master · pybluez/pybluez · GitHub

を元にBDアドレス取得、シリアル送信をできるようにした。やっつけなのでBDアドレスの合計値で照合してるけど、本来はUUIDを取得して照合して9600で送信した方が良いと思う。

from bluetooth.ble import DiscoveryService
import re
import serial
import time
import struct

tags={取得したいBDアドレスの合計値};

def split_n(text, n):
     return [ text[i*n:i*n+n] for i in xrange(len(text)/n) ]

ser = serial.Serial('/dev/ttyS0',38400,timeout=10)
print(ser.portstr)

while True:
        i=0
        postList = []
        service = DiscoveryService()
        devices = service.discover(2)

        for address, name in devices.items():
                address = split_n(address.replace(':', '') ,2)
                sum = 0
                for bd in address:
                        sum += int(bd, 16)

                for t in tags:
                        if t==sum:
                                postList.append(struct.pack("B", (sum>>8)))
                                postList.append(struct.pack("B", (sum&0x00FF)))

        if postList[0] != '\x00':
                ser.write(postList)

結果

問題だった検出距離は20m以上でも問題なく検出できた。 シリアル通信も成功

UUID取得とかわかったら追記するかもしれない

バイナリデータの符号拡張と解決(Arduino,C言語)

概要

Arduinoのソフトウェアシリアル入力で受け取った値をシリアルモニタで表示しようとするとFがめっちゃ出るやつの解決法。

起こったこと

BLEレシーバからソフトウェアシリアルで受けたBLEタグIDの一部'0x88'を出力しようと

char data = BLE.read();
Serial.print(data, HEX);

のように記述するとシリアルモニタに FFFFFF88 と表示され、視認性やその後の計算等に支障が出た。

原因

C言語でchar変数をintにキャストするとき、最上位ビットが '1' であると2の補数表現を維持しようと符号拡張を行う。

参考 marycore.jp

解決法

unsigned char変数に代入しておく

unsigned char data = BLE.read();
Serial.print(data, HEX);

てな感じで記述するとよいと思う。

char → int
0x88 → 0xFFFFFF88

unsigned char → int
0x88 → 0x88

IDなど16進数1byteのデータとして評価したい場合などにはこの方法でOK

まとめ

数値として評価したいときには便利なキャストの仕様だが、案外嵌りやすいので、バイナリデータいじってる人は頭の隅に置いてほしい。

単純なキャストの話なんですが、ArduinoIDEを使って開発しててキャストの話と気付かず"Arduino シリアルモニタ F めっちゃ出る"とかで検索してる人に届いて欲しい……