概要
ハッカソンでRaspberry Piとカメラ、Grove Pi+スターターキット、kintoneを活用することになり、Raspberry Piのセットアップと初期設定について調べました。
結果、OpenCVをPython3で使う設定とGrove Pi+設定でトラブルはありましたが、Raspberry Piとカメラ、Grove Pi+スターターキット、Python library to access kintone の設定ができました。
使用する機器について(2020/01/03 Amazonで調査)
最新のRaspberry Pi 4はGrove Piのサポートに含まれないため、今回はRaspberry Pi 3を使用しています。
そもそもRaspberry Pi 4は高価で、今回の用途にはそこまでのスペックが必要ないでしょう。
今回の調査で用いた機器(一部同等品含む)
Amazonで全て購入して20,408円前後で試すことができます。
Raspberry Pi3 Model B ボード&ケースセット 3ple Decker対応 (Clear)-Physical Computing Lab(6,100円)
https://www.amazon.co.jp/dp/B01CSFZ4JG/
SanDisk microSDHC ULTRA 16GB 80MB/s SDSQUNS-016G Class10(465円)
https://www.amazon.co.jp/dp/B074B4P7KD/
Grove Pi+ スターターキット 初心者向け Raspberry Pi A+,B,B+&2,3適用 CE認証(6,100円)
https://www.amazon.co.jp/dp/B07H9PFWHW/
US電源アダプタ オン/オフスイッチ ケーブル 5V 2.5A ラズベリーパイ3に対応 軽量 携帯便利(464円)
https://www.amazon.co.jp/dp/B07CYNGG4C/
カメラモジュール 感光チップOV5647センサー 5M画素 Raspberry Pi 1 2 3 Model B B A+対応(780円)
https://www.amazon.co.jp/dp/B07G572B3R/
Raspberry Piの設定
OSのセットアップ
以下より最新のOSをダウンロードしました。
https://www.raspberrypi.org/downloads/raspbian/
使用したOSイメージは以下です。
Raspbian Buster with desktop
・Version: September 2019
・Release date: 2019-09-26
・Kernel version: 4.19
OSをSDカードにセットアップする方法などは省略します。
詳しく知りたい方は以下を参照ください。
Raspberry Pi 初期設定 Windows( @sigma7641 さん)
https://qiita.com/sigma7641/items/995c7bb07eab408b9d0e
Raspberry Pi 初期設定 Mac( @skkojiko さん)
https://qiita.com/skkojiko/items/a7e342a8ab53b409fe6a
コマンドラインテキストエディタについて
作業はsshで接続し、コマンドラインで行います。
コマンドラインのテキストエディタはnanoで説明しますが、使い方は以下を参照ください。
GNU nanoを使いこなす( @snct_hu さん)
https://qiita.com/snct_hu/items/971d512c26dd8b3a3b3c
固定IPの設定
先ず最初にsshで接続しやすくするため固定IPを設定します。
$ sudo nano /etc/dhcpcd.conf
(IPアドレスは適切な内容に変更して、以下の設定を追加)
interface eth0
static ip_address=192.168.0.111/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1 8.8.8.8
無線LANの設定は以下を参照ください。
Raspberry Piの無線LAN設定をコマンドラインで行う( @mym さん)
https://qiita.com/mym/items/468d2cdb30d756b6df24
OSの基本設定
OSの基本設定はraspi-configを使って行います。
$ sudo raspi-config
今回は、以下を設定しています。
1 Change User Password
4 Localisation Options
-> I1 Change Locale -> ja_JP.UTF-8 UTF-8
-> I2 Change Timezone -> Asia -> Tokyo
-> I3 Change Keyboard Layout -> 適宜
-> I4 Change Wi-fi Country -> JP Japan5 Interfacing Options
-> P1 Camera -> Enable
-> P4 SPI -> Enable
-> P5 I2C -> Enable8 Update
設定後はOSを最新の状態にUPDATEします。
$ sudo apt-get update
$ sudo apt-get upgrade
Raspberry Pi カメラ設定
Raspberry Pi カメラの設定は以下を参照ください。
Raspberry Pi カメラで写真・ビデオを撮影する
https://iotdiyclub.net/raspberry-pi-using-camera-1/
基本的な設定完了後、PythonのOpenCV(画像編集ライブラリィ)用の設定を行います。
$ sudo modprobe bcm2835-v4l2
$ sudo nano /etc/modules
bcm2835-v4l2
$ sudo apt-get install libopencv-dev python-opencv
OpenCVの詳細については以下を参照ください。
OpenCV
https://opencv.org/
Python版 OpenCVの基本
https://cvtech.cc/py-opencv/
画像処理入門講座 : OpenCVとPythonで始める画像処理
https://postd.cc/image-processing-101/
Python3を使う場合は以下の設定を行います。
$ sudo apt-get install libhdf5-dev libhdf5-serial-dev libhdf5-103
$ sudo apt-get install libqtgui4 libqtwebkit4 libqt4-test python3-pyqt5
$ sudo apt-get install libatlas-base-dev
$ sudo apt-get install libjasper-dev
$ pip3 install opencv-python
OpenCVをPython3でそのまま利用すると import cv2 でエラーになります。
このエラーを回避するため、ロードするライブラリィを追加します。
$ nano .bashrc
export LD_PRELOAD=/usr/lib/arm-linux-gnueabihf/libatomic.so.1
$ source .bashrc
Grove Pi+の設定
Grove Pi+のRaspberry Pi への取り付けは以下を参考にしてください。
GrovePi+
https://www.switch-science.com/catalog/2129/
Grove Pi+のソフトウェアの設定は以下を参考に行います。
Setting Up The Software
https://www.dexterindustries.com/GrovePi/get-started-with-the-grovepi/setting-software/
$ curl -kL dexterindustries.com/update_grovepi | bash
$ sudo reboot
$ cd /home/pi/Dexter
$ git clone https://github.com/DexterInd/GrovePi
$ cd /home/pi/Dexter/GrovePi/Script
$ sudo chmod +x install.sh
$ sudo ./install.sh
インストール後に問題なければi2cdetectコマンドで以下のようにI2Cの04ポートが確認できます。
$ sudo i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- 04 -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Grove Pi+設定後、OSやインストール済のソフト更新を行う apt-get upgrade でパッケージ依存関係に問題が発生しエラーになります。
このエラーを回避するため、以下を実行します。
$ sudo apt-get --fix-broken upgrade
実際に動くか試験するため、以下を参考に付属のGrove LEDをGrove Pi+のD4ポートに配線します。
http://wiki.seeedstudio.com/Grove-Red_LED/#play-with-raspberry-pi-with-grovepi_plus
配線後に、以下のバージョン表示や、LEDの点滅を試験して問題がないか確認します。
$ python /home/pi/Dexter/GrovePi/Software/Python/grovepi.py
library supports this fw versions: 1.3.0
$ python /home/pi/Dexter/GrovePi/Software/Python/grove_led_blink.py
This example will blink a Grove LED connected to the GrovePi+ on the port labeled D4.
If you're having trouble seeing the LED blink, be sure to check the LED connection and the port number.
You may also try reversing the direction of the LED on the sensor.
Connect the LED to the port labele D4!
LED ON!
LED OFF!
LED ON!
LED OFF!
LED ON!
LED OFF!
Grove Pi+のライブラリィ不具合
2020/02/02 時点で以下のGrove Pi+のライブラリィ 1.3.0 のファイルに不具合があり、多くのサンプルが動きません。
/home/pi/Dexter/GrovePi/Software/Python/grovepi.py
https://github.com/DexterInd/GrovePi/blob/master/Software/Python/grovepi.py
例えば grove_button.py は、0でボタンOFF、1でボタンONを表示するプログラムですが、実行すると以下の表示になります。
$ python /home/pi/Dexter/GrovePi/Software/Python/grove_button.py
255
255
255
255
255
255
grovepi.pyのI2Cの読み込み部分に不具合があり、修正する必要があります。
以下にgrovepi.pyの修正箇所を説明します。
227行目read_identified_i2c_block()while文が永久ループするため削除
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
data = read_i2c_block(no_bytes + 1)
return data
246行目analogRead()のnumber配列要素番号を修正
# Read analog value from Pin
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[1] * 256 + number[2]
284行目ultrasonicRead()のnumber配列要素番号を修正
# Read value from Grove Ultrasonic
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[1] * 256 + number[2])
320行目dht()のnumber配列要素番号、no_bytes変数値を修正
# Read and return temperature and humidity from Grove DHT Pro
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 9)
if p_version==2:
h=''
for element in (number[1:5]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[5:9]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[1:5])
h_val=bytearray(number[5:9])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
上記の修正後に以下を実行すると、期待通りの結果を得ることができました。
$ python /home/pi/Dexter/GrovePi/Software/Python/grove_button.py
0
0
1
1
1
0
0
Python library to access kintoneの設定
$ pip install pykintone
$ pip3 install pykintone
node-redの設定(必要な場合のみ)
node-redの設定は以下のように行います。
$ sudo apt-get install nodered
$ npm install node-red-grovepi-nodes
$ npm install node-red-contrib-kintone
$ sudo systemctl enable nodered.service
$ sudo service nodered start
ブラウザで http://Raspberry PiのIPアドレス:1880/ にアクセスするとnode-redが利用できます。
詳細は以下を参照ください。
Node-RED Raspberry Piで実行する
https://nodered.jp/docs/getting-started/raspberrypi
リモートディスクトップの設定(必要な場合のみ)
リモートディスクトップの設定は以下のように行います。
$ sudo apt-get install xrdp
$ cd /etc/xrdp/
$ sudo wget http://w.vmeta.jp/temp/km-0411.ini
$ sudo ln -s km-0411.ini km-e0010411.ini
$ sudo ln -s km-0411.ini km-e0200411.ini
$ sudo ln -s km-0411.ini km-e0210411.ini
$ sudo service xrdp restart
Raspberry PiのIPアドレスで以下のようにリモートディスクトップに接続できます。
詳細は以下を参照ください。
Windowsパソコンからraspberrypi3にリモートデスクトップで接続する( @t114 さん)
https://qiita.com/t114/items/bfac508504b9a6b7570d
参考
ラズパイでpython3にopencvを入れたらエラーが出た【対処法】( @XM03 さん)
https://qiita.com/XM03/items/48463fd910470b226f22
Raspberry Pi Projects for the GrovePi.
https://www.dexterindustries.com/GrovePi/projects-for-the-raspberry-pi/
https://www.dexterindustries.com/GrovePi/get-started-with-the-grovepi/setting-software/
Grove - LED
https://www.seeedstudio.com/Grove-Green-LED.html
http://wiki.seeedstudio.com/Grove-Red_LED/#play-with-raspberry-pi-with-grovepi_plus
Grove - Button(ボタン)
https://www.seeedstudio.com/Grove-Button.html
http://wiki.seeedstudio.com/Grove-Button/#play-with-raspberry-piwith-grovepi_plus
Node-RED Raspberry Piで実行する
https://nodered.jp/docs/getting-started/raspberrypi
Windowsパソコンからraspberrypi3にリモートデスクトップで接続する( @t114 さん)
https://qiita.com/t114/items/bfac508504b9a6b7570d
GitHub icoxfog417/pykintone
https://github.com/icoxfog417/pykintone
grovepi.py の不具合修正(227行以降)
(Y.K Bug fixes) の記載部分に修正あり
(前略)
# Read I2C block from the GrovePi
def read_i2c_block(no_bytes = max_recv_size):
data = data_not_available_cmd
counter = 0
while data[0] in [data_not_available_cmd[0], 255] and counter < 3:
try:
data = i2c.read_list(reg = None, len = no_bytes)
time.sleep(0.002 + additional_waiting)
if counter > 0:
counter = 0
except:
counter += 1
time.sleep(0.003)
return data
# (Y.K Bug fixes)
def read_identified_i2c_block(read_command_id, no_bytes):
data = [-1]
data = read_i2c_block(no_bytes + 1)
return data
# Arduino Digital Read
def digitalRead(pin):
write_i2c_block(dRead_cmd + [pin, unused, unused])
data = read_identified_i2c_block( dRead_cmd, no_bytes = 1)[0]
return data
# Arduino Digital Write
def digitalWrite(pin, value):
write_i2c_block(dWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read analog value from Pin (Y.K Bug fixes)
def analogRead(pin):
write_i2c_block(aRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(aRead_cmd, no_bytes = 2)
return number[1] * 256 + number[2]
# Write PWM
def analogWrite(pin, value):
write_i2c_block(aWrite_cmd + [pin, value, unused])
read_i2c_block(no_bytes = 1)
return 1
# Setting Up Pin mode on Arduino
def pinMode(pin, mode):
if mode == "OUTPUT":
write_i2c_block(pMode_cmd + [pin, 1, unused])
elif mode == "INPUT":
write_i2c_block(pMode_cmd + [pin, 0, unused])
read_i2c_block(no_bytes = 1)
return 1
# Read temp in Celsius from Grove Temperature Sensor
def temp(pin, model = '1.0'):
# each of the sensor revisions use different thermistors, each with their own B value constant
if model == '1.2':
bValue = 4250 # sensor v1.2 uses thermistor ??? (assuming NCP18WF104F03RC until SeeedStudio clarifies)
elif model == '1.1':
bValue = 4250 # sensor v1.1 uses thermistor NCP18WF104F03RC
else:
bValue = 3975 # sensor v1.0 uses thermistor TTC3A103*39H
a = analogRead(pin)
resistance = (float)(1023 - a) * 10000 / a
t = (float)(1 / (math.log(resistance / 10000) / bValue + 1 / 298.15) - 273.15)
return t
# Read value from Grove Ultrasonic (Y.K Bug fixes)
def ultrasonicRead(pin):
write_i2c_block(uRead_cmd + [pin, unused, unused])
number = read_identified_i2c_block(uRead_cmd, no_bytes = 2)
return (number[1] * 256 + number[2])
# Read the firmware version
def version():
write_i2c_block(version_cmd + [unused, unused, unused])
number = read_identified_i2c_block(version_cmd, no_bytes = 3)
return "%s.%s.%s" % (number[0], number[1], number[2])
# Read Grove Accelerometer (+/- 1.5g) XYZ value
# Need to investigate why this reports what was read with the previous command
# Doesn't look to be implemented on the GrovePi
def acc_xyz():
write_i2c_block(acc_xyz_cmd + [unused, unused, unused])
number = read_identified_i2c_block(acc_xyz_cmd, no_bytes = 3)
if number[1] > 32:
number[1] = - (number[1] - 224)
if number[2] > 32:
number[2] = - (number[2] - 224)
if number[3] > 32:
number[3] = - (number[3] - 224)
return (number[0], number[1], number[2])
# Read from Grove RTC
# Doesn't look to be implemented on the GrovePi
def rtc_getTime():
write_i2c_block(rtc_getTime_cmd + [unused, unused, unused])
number = read_i2c_block()
return number
# Read and return temperature and humidity from Grove DHT Pro (Y.K Bug fixes)
def dht(pin, module_type):
write_i2c_block(dht_temp_cmd + [pin, module_type, unused])
number = read_identified_i2c_block(dht_temp_cmd, no_bytes = 9)
if p_version==2:
h=''
for element in (number[1:5]):
h+=chr(element)
t_val=struct.unpack('f', h)
t = round(t_val[0], 2)
h = ''
for element in (number[5:9]):
h+=chr(element)
hum_val=struct.unpack('f',h)
hum = round(hum_val[0], 2)
else:
t_val=bytearray(number[1:5])
h_val=bytearray(number[5:9])
t=round(struct.unpack('f',t_val)[0],2)
hum=round(struct.unpack('f',h_val)[0],2)
if t > -100.0 and t <150.0 and hum >= 0.0 and hum<=100.0:
return [t, hum]
else:
return [float('nan'),float('nan')]
(後略)