Raspberry pi の覚え書き Part3

初版作成  2023.5.7
最終更新  2024.09.13


◆◆ インストール方法 ◆◆


Raspberry Pi Imager というアプリを使う。

https://www.raspberrypi.com/software/

からダウンロードし、exe ファイルをダブルクリックすると
インストールされる。

起動して「インストールする OS」「インストール先ドライブ」を
選択する。

ラズパイ 2B に 32 bit 版を入れてみたが、死ぬほど重い。
32 bit レガシー版はサクサク動くので、古いラズパイ
にはレガシー版を入れた方が良い。

インストール時に以下のものを設定する。

・ユーザー名とパスワード(過去との互換性をとるなら pi)

インストールできるラズパイ

・ラズパイ 2 以降でないと Chrome が起動しないので
 初期バージョンの無印の B は実用的ではない

◆◆ インストール直後の操作 ◆◆


GUI で操作できる。
ネットワークを固定 IP に設定する(実験室は DHCP で固定 IP を設定)
サブネットマスクを設定する項目はない。
default router と name server は 192.168.xx.1  に設定する。

まずやること

ネットワークに接続する

次にやること

# apt update
# apt upgrade (かなり時間がかかる)

以下のアプリをインストールする

emacs (めちゃくちゃ時間がかかる)
telnet
telnetd
ftp
ftpd

telnetd を使えるようにする(レガシーでない raspbian の場合)

/etc/inetd.conf を編集してコメントを外す

# service inetutils-inetd restart
あるいは
# kill -HUP PID_of_inetd

○ 日本語を使えるようにする

# apt install ibus-mozc  (再起動必要)

左上ラズベリーマーク --- preferences --- rasupberry pi config.
--- locale: JP  (再起動必要)

右上のアイコンをクリックし以下の順に選択する。

日本語 - Japanese
日本語 - Mozc

○ ある程度インストールが終わった後にすること
起動時に CLI で起動するようにする


○ ftpd が動作しないことがあった。インストールしているにも
かかわらず、/usr/sbin/in.ftpd が存在しない。

何が効いたかわからないが、
  # apt uninstall ftpd
  # apt upgrade
  # apt install ftpd
で解決した。

○ ラズパイ4 で HDMI に 1024x768 の信号を出力する

/etc/firmware/config.txt に以下を書き込む
どれが効いているのかわからない。
ChatGPT4o に聞いた

hdmi_group=1
hdmi_mode=16
hdmi_force_hotplug=1
hdmi_drive=2
hdmi_save=0

◆◆ .bashrc の変更 ◆◆


キーの入れ替えは wayland の場合は後述

setxkbmap -option ctrl:swapcaps
xmodmap key-file

---- key-file の中身 ----
keycode 49 = Escape
keycode  9 = Zenkaku_Hankaku
-------------------------

export TERM=vt100

alias rm='rm -i'
alias cp='cp -p'
alias ls='ls -F --color=never'
alias ne='emacs -nw'
alias sc='. ~/.bashrc'

export PATH=$PATH:.
export CDPATH=~:/home/pi/public_html:/home/pi/public_html/cgi-bin

--- wayland の場合 ---

./config/wayfare.ini

[input]
xkb_options=ctrl:swapcaps
xkb_model=pc105
xkb_layout=jp
xkb_variant=OADG109A
xkb_symbolds="keycode(9)=Zenkaku_Hankaku+keycode(49)=Escape"


◆◆ apache2 のインストール ◆◆


# apt install apache2

(1) ユーザーディレクトリを使えるようにする

# a2enmod userdir

(2) cgi を使えるようにする

# cd /etc/apache2/mods-enabled
# ln -s ../mods-available/cgi.load .

(3) ユーザーディレクトリを html としているとき
    html ----> public_html のシンボリックリンクを張る

$ cd
$ ln -s public_html html

(4) 設定ファイルの変更点

------------- /etc/apache2/apache2.conf ------------

ServerRoot "/etc/apache2"

#<Directory /home/user-name/public_html/>
#    AllowOverride Limit Options FileInfo AuthConfig
#    Options FollowSymLinks
#    Require all granted
#</Directory>

#<FilesMatch "~$">
#    Require all denied
#</FilesMatch>

---------- /etc/apache2/sites-available/000-default.conf --------

ServerName   xxx.yyy.nara-edu.ac.jp
ServerAdmin  zzz@nara.edu.ac.jp

を設定(省略可)

Include conf-available/serve-cgi-bin.conf
を確認

---------- /etc/apache2/conf-available/serve-cgi-bin.conf --------

       <IfDefine ENABLE_USR_LIB_CGI_BIN>
                ScriptAlias /cgi-bin/ /home/pi/public_html/cgi-bin/
                <Directory "/home/pi/public_html/cgi-bin">
                        AllowOverride None
                        Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
                        Require all granted
                        AddHandler cgi-script .py  <---- ここに必要! なぜか mime.conf に書いても効かない
                </Directory>
        </IfDefine>

---------- /etc/apache2/mods-available/mime.conf ----

AddHandler cgi-script .py

なぜか効かない。

(5) /var/www/html/index.html の変更

以下のように書き換える。

<html>
  <head>
    <meta http-equiv="Refresh" content="0;URL=/~pi/">
    <title>top page</title>
  </head>
  <body>
  </body>
</html>

(6) apache2 の自動起動の on/off

  # update-rc.d -f apache2 remove      自動起動停止  /etc/rc2.d/... が削除
  # update-rc.d apache2 defaults       自動起動復活

apache2 の起動

  # apachectl start
  # apachectl stop
  # apachectl restart

(7) ファイルのパーミッション

~/public_html/             755
~/public_html/index.html   644
~/public_html/cgi-bin/     755
~/public_html/cgi-bin/*.py 755

(8) CGI を実行可能にする

# visudo

最後に以下を付加

www-data ALL=(ALL) NOPASSWD: ALL      apache2 用
nobody ALL=(ALL) NOPASSWD: ALL    python http.server 用

◆◆ シリアル通信 ◆◆


ラズパイのバージョンによってデバイス名が変わる
pi2 まで /dev/ttyAMA0
pi3 以降 /dev/serial0

# raspi-config

シリアルコンソールとシリアル通信は別らしい。

シリアルコンソールを off にしないと、
シリアル通信の受信文字が化ける

Interface options --- Serial port

would you like a login shell to be accessible over serial: no
would you like the serial port hardware to be enabled: yes

serial port hardware to be enabled:yes の
指示は以下のファイルに書き込まれる

/boot/config.txt            2023.5.7 のバージョン レガシーバージョン
/boot/firmware/config.txt   2024.7.22 のバージョン

enable_uart=1

login shell ....over serial: no  の結果が
どこに書き込まれるかは不明


◆◆ python による http サーバ ◆◆


python2:  python -m CGIHTTPServer 80    ファイル閲覧, CGI 実行 OK
python3:  python -m http.server 80      ファイル閲覧のみ

python3 で CGI を使う方法は以下の通り

# python start_cgi_server.py

start_cgi_server.py の中身 (ChatGPT4o が作った)
------------------
#!/usr/bin/python

import os
from http.server import HTTPServer, CGIHTTPRequestHandler

class CustomHTTPServer(HTTPServer):
    def server_bind(self):
        HTTPServer.server_bind(self)
        self.server_name = "localhost"
        self.server_port = self.server_address[1]

PORT = 80
DIRECTORY = "/home/pi/public_html"

os.chdir(DIRECTORY)

server = CustomHTTPServer(("", PORT), CGIHTTPRequestHandler)
print(f"Serving at port {PORT}")
server.serve_forever()
------------------

自動起動したいときは rc.local に以下のように書き込む

(cd /home/pi/public_html; python start_cgi_server.py >> /var/tmp/web.log 2>&1 &)



◆◆ 外付け HDD の接続(ext4) 2019.7.31 ◆◆


参考
http://sooch.hatenablog.com/entry/2017/03/26/061032

1. デバイス名の確認

  # blkid

2. フォーマット

  # fdisk /dev/sda

  Command (m for help): d   パーティション削除
  Selected partition 1

  Command (m for help): p   確認

  Command (m for help): n   パーティション作成
                            enter を押すとデフォルト値が入る

  Command (m for help): p   確認
  Command (m for help): w   書き出して終了

  # mkfs.ext4 /dev/sda1

  enter を押すとデフォルト値が入る

3. マウント

  # mount /dev/sda1 /mnt

/etc/rc.local に書き込む

リブートした時に自動的に接続されてしまう
/etc/fstab に書くより、
mount コマンドを /etc/rc.local に書く方が
良いと思う。

◆◆ nfs の設定 ◆◆


  $ sudo apt install nfs-common         <-- client
  $ sudo apt install nfs-kernel-server  <-- server
  $ sudo apt install rpcbind            <-- server

・クライアント

----- /etc/rc.local -----

mount -t nfs machine-name:/home/user-name/dir /home/user-name/dir

--------------------------

・サーバー

----- /etc/exports ----

/home/user-name/html   macine-name(rw,sync,no_subtree_check) machine-name2(rw,sync,no_subtree_check)
/etc/apache2      machine-name(rw,sync,no_subtree_check)
/var/log/apache2  machine-name(rw,sync,no_subtree_check)

-------- /etc/rc.local --------------

service rpcbind start
service nfs-kernel-server restart

# nfs-kernel-server start ではダメ。restart
# 下記の設定でも同じ

# systemctl start rpcbind.service
# systemctl restart nfs-kernel-server.service

--------------------------------------

サーバーを動かすのに色々と苦労した。

# service nfs-kernel-server start

ではダメ。restart が必要。

export 状況の確認は

# exportfs

サービスの状況は

# service nfs-kernel-server status

で確認する。しかし、rpcbind, nfs-kernel-server ともに
active であるにもかかわらず、接続できなかった。
restart に気がつくのに時間がかかった。

参考サイト
https://hermemo.com/archives/1312

このサイトがなかったら、解決できなかった。

◆◆ samba のインストールと設定 ◆◆


linux2.txt を参照

ユーザー名を指定しての接続は

\\192.168.xx.yy\user-name

としてわざとエラーを出し、
「その他」をクリックして
「別のアカウントを使用する」を選ぶ。

windows と samba のパスワードが同一の場合は、
いきなりログイン出来てしまう。

smbpasswd でパスワードを変更すると、
linux のログインパスワードと samba のパスワードの
両方が変わる。

passwd でパスワードを変更すると、linux のパスワード
だけが変わる。

いろいろといじっているうちに、telnet でログインすると
途中で止まるようになってしまった。止まっても ^C でログイン出来る。
リブートしたらなおった。謎。

◆◆ php のインストールと設定 ◆◆


pi.txt を参照

ファイル名は ○○.php
パーミッションを 666 にすることを忘れないように!!!


◆◆ 温湿度センサ DHT11 の使い方 ◆◆


○ 接続

DHT11 の詳しい説明はデータシートを参照
http://akizukidenshi.com/download/ds/aosong/DHT11_20180119.pdf

DHT11 は 4 個端子がある。使うのは 3 個
1 Vcc
2 Data
3 NC
4 Gnd

電源 DC 3.3V ~ 5.5 V
3.3 V で運用するときはケーブルの長さは可能な限り短くする。

Data ピンは 4.7k でプルアップ

Data 端子は入出力兼用という不思議な接続法である。
Data 端子の波形をオシロで見ると、
0 V と Vcc の 2 値をとるパルスである。
Vcc = 5 V に設定すると、パルス波形の立ち上がりがなまる。

ネットを見ると、Vcc = 5 V のサイトと Vcc = 3.3 V の
サイトの 2 つの接続法がある。

実験してみると、どちらでも動作するが、ラズパイの
入力端子に 5 V をかけるのは良くないと思われるので、
私は 3.3 V で運用する。

○ ライブラリのインストール

# apt-get install git
# git clone https://github.com/szazo/DHT11_Python.git

これ以外にもライブラリがあるようだ。
https://se-lina.hatenablog.com/entry/2022/03/07/182723
によると、以下のライブラリがあるらしい。
git clone https://github.com/adafruit/Adafruit_Python_DHT.git

○ サンプルプログラム

DHT11_Python のフォルダで実行する。
import dht11 を実行すると dht11/__init__.py を見に行く。
その他のフォルダで実行するときは、__init__.py を当該フォルダ
にコピーし、ファイル名を dht11.py にリネームする。

以下のプログラムは Data は GPIO14 (8番端子) に
接続する場合である。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import RPi.GPIO as GPIO
import time, datetime
import dht11

GPIO.setwarnings(True)
GPIO.setmode(GPIO.BCM)

instance = dht11.DHT11(pin=14)

while True:
    result = instance.read()
    if result.is_valid():
        temp = result.temperature
        humid = result.humidity
        print(temp, humid)
    time.sleep(1)

◆◆ 温湿度センサ DHT20 の使い方 ◆◆


DHT20 の方が精度が良いらしい。
温度 ±0.5 ℃
湿度 ±3 %

DHT11 は
温度 ±2 ℃
湿度 ±5 %

接続は I2C なので、ラズパイの設定で I2C を on に
しておく。

# raspi-config

Pi     DHT20
1 (3.3V) --- 1
3 (SDA)----- 2
5 (SCL)----- 3
9 (Gnd)----- 4

穴が空いている面を上に、下向きに端子が伸びるように
配置して左から順番に 1-4

サンプルプログラム
参照:https://s-design-tokyo.com/use-dht20-raspberrypi/

import smbus, time

send = [0xac, 0x33, 0x00]

i2c = smbus.SMBus(1)
address = 0x38

time.sleep(0.2)
ret = i2c.read_byte_data(address, 0x71)

while True:
    time.sleep(0.01)
    i2c.write_i2c_block_data(address, 0x00, send)
    time.sleep(0.08)
    data = i2c.read_i2c_block_data(address, 0x00, 0x07)

    humid = data[1] <<12 | data[2] << 4 | (( data[3] & 0xf0 ) >> 4 )
    temp = ((data[3] & 0x0f) << 16 ) | data[4] << 8 | data[5]

    humid2 = humid /  2**20 * 100
    temp2  = temp  /  2**20 * 200  - 50

    print("湿度 = {:3.0f} %    温度 = {:4.1f} 度".format(humid2, temp2))

    time.sleep(1)

◆◆ cron の実行フォルダ ◆◆


ホームディレクトリで実行される。
ファイルを扱うときに、スクリプトのあるフォルダを読み書きしたい時は、
スクリプトの存在するフォルダを

script_path = os.path.abspath(os.path.dirname(__file__))

のように取得してスクリプト内で処理するか、
cron 内で

(cd /home/pi/xxx/script-path ; ./script-fname )

のように cd してから実行する。

◆◆ python-opencv モジュールのインストール ◆◆


# apt install libopencv-dev
# apt install python3-opencv

以下の pip3 を使う方法は
エラーが出てインストールできない

(1) pip をアップグレードする
   python3 -m pip install --upgrade pip

(2) インストール元を指定する
   pip3 install opencv-python -i https://pypi.doubanio.com/simple/

常にミラーサーバを使う場合は

.config/pip/pip.conf  の中を以下のように書く

[global]
index-url = https://pypi.doubanio.com/simple/

(3) sudo を付ける

sudo pip3 install opencv-python


◆◆ ラズパイA を 2024 年にインストール 2024.8.27 ◆◆


ラズパイA の再インストールを Rapberry Pi Imager v1.8.5 を
使って行う。

これまで使っていた SD カードに Raspberry Pi Imager で書き込もうと
すると、パーティションを変えることができないというエラーがでる。

SD Card Formatter でクイックフォーマットすると、
書き込めるようになる。

Raspbian のレガシー版をインストールする。
X が起動した状態では、非常に重く、実用的な速度では動かない。
ドロップダウンメニューの項目を 1 個選ぶだけで、そのメニューが
表示されるまでに 10 分程度かかる。

レガシー Lite 版をインストールするとよさそうに見えるが、
なぜかキーボードが使えない。

レガシー版をインストールし、Wifi に接続することに成功したなら、
ターミナル内で raspi-config を起動し、
System Options で Boot/Auto Login で Console Autologin を選択
してリブートする。

これまで使っていた Wifi アダプタ
IO Data WN-G150UM(2016 年購入)は使えない。
lsusb では認識するが、iwlist wlan0 scan を実行すると
周辺の Wifi ルータを認識しない。

2015 年頃の NOOBS_1_3_4 をインストールすると、
その Wifi アダプタを認識する。
しかし apt update でエラーが出る。
/etc/apt/sources.list の 1 行目に以下を
加えると apt update のエラーは回避できる。

deb http://raspbian.raspberrypi.org/raspbian/ bullseye main contrib non-free rpi

bullseye のところは Debian のバージョンによって変更する。
deb7:wheezy   deb10:buster    deb11:bullseye

しかし、telnetd, telnet がエラーで入らない。

結論として、古い NOOBS は使えない。
ゆえに IO Data WN-G150UM(2016 年購入)は使えない(認識しない)。

     ----------

Wifi アダプタは
Elecom WDC-150SU2M (2020 年頃購入)を試したところ
繋がった。しかし、SD card が数日後に壊れて
再度インストールすると認識はするが、接続できない。

Planex GW-USNano2 を使う。

以下の 2 個のファイルを編集する。

・/etc/wpa_supplicant/wpa_supplicant.conf

以下を追加
network={
   ssid="rx....."
   psk="passwd"
}

・/etc/dhcpcd.conf

以下を追加
interface wlan0
static ip_address=192.168.0.201/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8 8.8.4.4

# systemctl restart wpa_supplicant
# systemctl restart dhcpcd
# ifconfig

ネットワークの設定をするときに使ったコマンドを以下に記す。
どれが役に立ったのかよく分からない。

# iwlist wlan0 scan
# ip link set wlan0 down
# ip link set wlan0 up
# ip addr add 192.168.0.201/24 dev wlan0
# dhclient wlan0
# wpa_supplicant -c /etc/wpa_supplicant/wpa_supplicant.conf -i wlan0
# iwconfig wlan0 essid "ssd-id" key s:password
# journalctl -u dhcpcd
# journalctl -u wpa_supplicant

Web サーバは python の HTTPServer CGIHTTPRequestHandler
モジュールを使う方法と apache2 を使う方法がある。
python のモジュールは非常に反応が遅かったり、
ハングアップしたり、安定性が悪い。
apache2 の方が圧倒的に安定している。

     ----------

ネットワークに繋がって CLI で再起動したら、

# apt update
# apt install telnetd

あとはリモートから接続して telnet, ftpd, ftp, emacs を
インストールし、設定を行う。

apache2 のインストールはその後で行う。

シリアルを使うには raspi-config --- Interface Options
--- Serial Port で
シリアルコンソール no
シリアルポート yes
に設定する。

◆◆ ラズパイ4 のインストール 64 bit 版 2024.9.10 ◆◆


起動して Wifi の国を JP にセットする

再起動する <---- これが重要
        こうしないとネットに接続するメニューが出てこない

# apt update
# apt upgrade (非常に時間がかかる)

◆◆ I2C の照度センサ bh1750 の使い方 ◆◆


addr を GND に接続すると 0x23
3.3 V に接続すると 0x5c

・raspi-config で I2C を有効にしておく

2 つ方法がある

(1) adafruit-circuitpython-bh1750 を使う
(2) 使わない

(1) のときモジュールのインストールが必要。以下のように
 --break-system-packages をつけないとエラーがでる。

$ pip install adafruit-circuitpython-bh1750 --break-system-packages

import board, adafruit_bh1750

i2c = board.I2C()
bh1750 = adafruit_bh150.BH1750(i2c)
value = bh1750.lux

(2) のとき

import time, smbus

i2c = smbus.SMBus(1)
bh1750_address = 0x23  # addr = GND のとき

i2c.write_byte(bh1750_address, 0x01) # power on
time.sleep(0.2)
i2c.write_byte(bh1750_address, 0x07) # register reset
time.sleep(0.2)
i2c.write_byte(bh1750_address, 0x10) # high reso mode
time.sleep(0.2)

data = i2c.read_i2c_block_data(bh1750_address, 0x10)
lux = ( data[0] << 8 | data[1] ) / 1.2
print(f"Light level: {lux:.0f} lux")

◆◆ DHT20 と bh1750 の併用 ◆◆


(1) adafruit_bh1750 使用

import time
import board
import adafruit_bh1750
import smbus

# I2C for BH1750 (light sensor)
i2c_bus = board.I2C()  # SDA and SCL are automatically detected
bh1750 = adafruit_bh1750.BH1750(i2c_bus)

# I2C for DHT20 (temperature and humidity sensor)
i2c = smbus.SMBus(1)
dht20_address = 0x38
send = [0xac, 0x33, 0x00]

# Initialize DHT20 sensor
time.sleep(0.2)
i2c.read_byte_data(dht20_address, 0x71)  # Initialize DHT20

while True:
    # Read BH1750 lux value
    lux = bh1750.lux
    print(f"Light level: {lux} lux")

    # Read DHT20 temperature and humidity values
    time.sleep(0.01)
    i2c.write_i2c_block_data(dht20_address, 0x00, send)
    time.sleep(0.08)
    data = i2c.read_i2c_block_data(dht20_address, 0x00, 7)

    # Calculate humidity and temperature
    humid = data[1] << 12 | data[2] << 4 | ((data[3] & 0xf0) >> 4)
    temp = ((data[3] & 0x0f) << 16) | data[4] << 8 | data[5]

    humid2 = humid / 2**20 * 100
    temp2 = temp / 2**20 * 200 - 50

    print(f"Humidity: {humid2:.2f}%")
    print(f"Temperature: {temp2:.2f}°C")

    # Wait before next reading
    time.sleep(1)

(2) adafruit のライブラリ不使用

#!/usr/bin/python

import time
import smbus

# init_bh1750() の 6 行は全て必要
# 怠ると adafruit ライブラリ使用のプログラムの終了直後に実行すると
# 1 個目のデータがおかしくなる。

def init_bh1750():
    i2c.write_byte(bh1750_address, 0x01) # power on
    time.sleep(0.2)
    i2c.write_byte(bh1750_address, 0x07) # register reset
    time.sleep(0.2)
    i2c.write_byte(bh1750_address, 0x10) # high reso mode
    time.sleep(0.2)

def read_bh1750():
    data = i2c.read_i2c_block_data(bh1750_address, 0x10)
    lux = ( data[0] << 8 | data[1] ) / 1.2
    return lux

def init_dht20():
    time.sleep(0.2)
    i2c.read_byte_data(dht20_address, 0x71)

def read_dht20():
    time.sleep(0.01)
    i2c.write_i2c_block_data(dht20_address, 0x00, \
        [0xac, 0x33, 0x00])
    time.sleep(0.08)
    data = i2c.read_i2c_block_data(dht20_address, 0x00, 7)

    humid = data[1] << 12 | data[2] << 4 | \
            ((data[3] & 0xf0) >> 4)
    temp = ((data[3] & 0x0f) << 16) | data[4] << 8 | data[5]

    humid2 = humid / 2**20 * 100
    temp2 = temp / 2**20 * 200 - 50

    return(humid2, temp2)

# global variable
i2c = smbus.SMBus(1)
dht20_address = 0x38
bh1750_address = 0x23  # addr = GND のとき

init_dht20()
init_bh1750()

while True:
    (humid, temp) = read_dht20()
    lux = read_bh1750()

    print(f"Light level: {lux:.0f} lux")
    print(f"Humidity: {humid:.1f} %")
    print(f"Temperature: {temp:.1f} °C")

    # Wait before next reading
    print("")
    time.sleep(1)