Elsaの技術日記(徒然なるままに)

主に自分で作ったアプリとかの報告・日記を記載

MENU

Raspberry PiでGPIO制御を行う

今回はいつも調べてしまう、ラズパイでのGPIO制御についてまとめておこうと思います!!
毎度調べるのも手間なので。。。



■環境

今回はraspberry Pi 4を用いて動作確認し、そちらの紹介を行っていきます。

【国内正規代理店品】Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品【RS・OKdo版】

新品価格
¥6,875から
(2020/12/26 21:01時点)

ただ、raspberry Pi 3でも動作する手順になっています。

■ピン配置の確認

まずはraspberry Piのピン配置について記載していきます。
公式(https://www.raspberrypi.org/documentation/usage/gpio/README.md)より、ピン配置はこちら。
f:id:Elsammit:20201226185453p:plain

コマンドによりピン配置の確認ができます。
こちらのコマンドを実行すると、

pinout

こちらのようにピン配置の結果が得られます。
f:id:Elsammit:20201226185806p:plain

■コマンドでのGPIO制御

では早速GPIO制御についてまとめていきたいと思います!!
今回使用するGPIOですが、
out:gpio17
in:gpio27
で設定していきたいと思います!!
gpio**の部分を自分が使用したいgpioの番号をセットすればOKです。

GPIOを制御するにあたって、

/sys/class/gpio

配下に格納されたファイルを操作していきます。

まずは使用するGPIOを定義していきます。
こちらのようにコマンドを実行すればOKです。

echo 27 > /sys/class/gpio/export
echo 17 > /sys/class/gpio/export

すると、/sys/class/gpio配下に
gpio27、gpio17
が追加されているかと思います。

次に、gpio17、gpio27をin outに変更していきたいと思います。
gpio27をinにするには、

echo in > /sys/class/gpio/gpio27/direction

とすればよく、
gpio17をoutにするためには、

echo out > /sys/class/gpio/gpio17/direction

とすればOKです。

■動作確認

では、正しく設定されているか確認してみます。
GPIOのon(1)/off(0)は、

 /sys/class/gpio/gpio17/value
 /sys/class/gpio/gpio27/value

まずはinから!!
あらかじめGPIO17へボタンを接続しておきます。
ボタン押下せずに

cat  /sys/class/gpio/gpio27/value

を実行すると、

0

が表示されるかと思います。
ボタンを押下しながら、

cat  /sys/class/gpio/gpio27/value

を実行すると、

1

が表示され、gpioのinが有効になっていることが確認できます。

次にout!!
あらかじめLEDを接続しておきます。

echo 1 >  /sys/class/gpio/gpio17/value

とするとLEDが点灯し、

echo 0 >  /sys/class/gpio/gpio17/value

とするとLEDが消灯することが確認できるかと思います。

■最後に

今回はコマンドでのGPIO操作を紹介いたしました。
pythonやgo言語、c言語を用いた場合にもそれぞれ手法があるのでそちらについても後で紹介できればいいな?と思っております。
後、イベント駆動についても紹介出来たらいいな~~



Reactで雪を降らせてみる

メリークリスマス!!
f:id:Elsammit:20201225170218p:plain

ただ残念なことに、
コロナウィルスの第3波が来てしまって、遊びに行くことも憚られる状態ですね😢

せっかくのクリスマスなのに、、、
例年ならイルミネーションとかきれいなはずなのに😨

ということで、クリスマスっぽいWebアプリを作ってみることにしました!!
作成はReactを用いました!!



■Reactで雪を降らせる

Reactで雪を降らせるにあたり、snow-fallというAPIを用いました。
https://www.npmjs.com/package/react-snowfall

まずはsnow-fallのセットアップです。
こちらのコマンドを実行!!

sudo npm i react-snowfall
yarn add react-snowfall

では、実際に雪を降らせるコードを作成します。
サンプルコードを利用して、このように作成しました。

import React, { Component } from 'react';
import Snowfall from 'react-snowfall';

export default class Snow extends Component  {
    render() {
        const {position} = this.state;
        const {City} = this.state;
        var Pos = position;
        return (
            <div>
                <div className="layout" style={{ height: 850, width: 1850, background: '#282c34' }}>
                    <Snowfall />
                </div>,
            </div>
        );
    }
  }

snow-fallライブラリを用いれば実装は簡単で、

<Snowfall />

をコールすれば雪を降らせることが可能です!!
今回は背景を黒色にして雪を目立つようにしています。

<div className="layout" style={{ height: 850, width: 1850, background: '#282c34' }}>

こちらを動作させるとこんな感じになります。
f:id:Elsammit:20201225164217g:plain

雪を降らすことが出来ました!!

後、Configurationをセットすれば雪の量や色を変更することが可能になります。
ただ、雪の結晶サイズはどうやら変更できない模様です。。

■メリークリスマスw

雪を降らせることが出来たので、ちょっとクリスマスっぽいアプリを作成してみました!!
作成したアプリを実行するとこんな感じになります。
f:id:Elsammit:20201225164754g:plain

クリスマスっぽいですかね??

コードはこんな感じになります。

import React, { Component } from 'react';
import Snowfall from 'react-snowfall';
import Tokyo from './image/Area1.JPG';
import Yokohama from './image/Area2.JPG';
import Tower from './image/Area3.JPG';
import Santa from './image/santa.png';
import Tide from './image/Tide.png';
import "./snow.css"


export default class Snow extends Component  {

    constructor (props) {
        super(props);
        this.state = {
            position:1600,
            City:Tokyo,
            Count:0,
        };
    }

    SantaMove=()=>{
        var {position} = this.state;
        var Pos = position;
        const {Count} = this.state;
        if(Pos <= 10){
            this.setState({position:1600});
            switch(Count){
                case 0:
                    this.setState({City:Yokohama});
                    this.setState({Count:1});
                    break;
                case 1:
                    this.setState({City:Tower});
                    this.setState({Count:2});   
                    break;
                case 2:
                    this.setState({City:Tokyo});
                    this.setState({Count:0});
                    break; 
                default:
                    this.setState({City:Tokyo});
                    this.setState({Count:0});
                    break;                                                                               
            }
        }else{
            this.setState({position:Pos-20});
        }
    }

    componentDidMount() {
        this.intervalId = setInterval(()=>{
            this.SantaMove();
        }, 200);
    }

    render() {
        const {position} = this.state;
        const {City} = this.state;
        var Pos = position;
        return (
            <div>
                <div className="layout" style={{ height: 850, width: 1850, background: '#282c34' }}>
                    <img src={Santa} alt="Santa" id="santaID" className="santa" style={{left:Pos}}/>
                    <img src={City} alt="City" height="850" width="1850" />
                    <img src={Tide} alt="Tide" className="Tide" />
                    <Snowfall snowflakeCount={300}/>
                </div>,
            </div>
        );
    }
  }

サンタクロースの動作ですが、

    componentDidMount() {
        this.intervalId = setInterval(()=>{
            this.SantaMove();
        }, 200);
    }

により、200ms毎にSantaMove()関数をコールしており、
SantaMove()関数は、

    SantaMove=()=>{
        var {position} = this.state;
        var Pos = position;
        const {Count} = this.state;
        if(Pos <= 10){
            this.setState({position:1600});
            switch(Count){
                case 0:
                    this.setState({City:Yokohama});
                    this.setState({Count:1});
                    break;
                case 1:
                    this.setState({City:Tower});
                    this.setState({Count:2});   
                    break;
                case 2:
                    this.setState({City:Tokyo});
                    this.setState({Count:0});
                    break; 
                default:
                    this.setState({City:Tokyo});
                    this.setState({Count:0});
                    break;                                                                               
            }
        }else{
            this.setState({position:Pos-20});
        }
    }

となります。
20px毎に動かして、10px以下の場合には別の背景に切り替えるような制御となっております。

■最後に

今回は雪を降らせてサンタクロースを動かしてみました!!
ライブラリが用意されていると簡単にアプリを作成させることが出来ますね!!



OpenCVをの用いた画像処理系まとめてみた

今年も後わずかですね!!
年を取るにつれて1年が短く感じます。

5月から始めたこの技術ブログも結構続いていることに自分でも驚いております!!

さて今回は、
今までまとめてきたコードの整理と今後簡単に使えるようにするためにAPI化してみましたので、
その報告です。



■整理したコード格納先

こちらになります。
https://github.com/Elsammit/ImageAPI

■まとめたAPI報告

まずはどんな内容をAPIとして整理したか、です。
一覧にするとこんな感じ。
・ARMaker.py:ARマーカーの作成や読み込み
・BarcodeMaker.py:バーコードの作成と読み込み
・ConvertImgByte.py:画像データのバイト列変換やバイト列から画像データへの変換
・OnlyVideoStreaming.py:ビデオストリーミング
・Overlap.py:画像重畳やRGB分割用API
・PartDetection.py:顔や目などの体の一部検知用API
・VideoStreamAndDetection.py:ビデオストリーミング+体の一部検知用API

■ARマーカーの作成や読み込み

Classとして、
・MakeArMaker:ARマーカー作成
・ReadMaker:ARマーカー読み取り
を用意。
使用例はこんな感じです。

if __name__ == '__main__':
    MakeArMaker = MakeArMaker()
    MakeArMaker.ARGeneratorFile("aaa.jpg",0,150)
    MakeArMaker.MaltiARGenerator("bbb.jpg", 0, 6, 150)

    ReadMaker = ReadMaker()

    cap = cv2.VideoCapture(0)
    while True:
        ret, frame = cap.read()
        ReadMaker.ARReader(frame, None)
        cv2.imshow('drawDetectedMarkers', frame) #マーカが描画された画像を表示

        cv2.waitKey(1) #キーボード入力の受付
    cap.release() #ビデオキャプチャのメモリ解放
    cv2.destroyAllWindows() #すべてのウィンドウを閉じる

■バーコードの作成と読み込み

Classとして、
・BarCodeMaker:バーコード作成と読み取り
を用意。
使用例はこんな感じです。

if __name__ == '__main__':
    BarCodeMaker = BarCodeMaker()

    Num = '9323131312131'
    BarCodeMaker.MakeBarCode("test.jpg", Num)

■画像データのバイト列変換やバイト列から画像データへの変換

Classとして、
・ImgByteChange:画像データとバイト列変換とバイト列から画像データ変換
を用意。
使用例はこんな感じ。

imgByteChange = ImgByteChange()
bt = imgByteChange.ImageToByte("画像データ(例:test.jpg)")
mt = imgByteChange.ByteToImage(bt)

■ビデオストリーミング用API

こちらはただカメラキャプチャ動画をストリーミングするだけのファイルになります。
APIではないので、試しに使ってみる系ですね。

■画像重畳やRGB分割用API

Classとして、
・Overlap:画像重畳
・ImageSeparateComposition:RGB分割、合成
・ImageHistgrams:ヒストグラム作成用
を用意。
ちょっと色々と詰め込みすぎ間が否めないな。。。
後で分けておこうかな??

■顔や目などの体の一部検知用API

Classとして、
・Detections:体の一部を検知するためのAPI
を用意。

目を検知するだけのコードですが、
使用例はこんな感じです。

img1 = cv2.imread('lena.jpg')
m_Detections = Detections()
eye_left, eye_right = m_Detections.EyeDetection("haarcascade_eye.xml", img1)
img1 = m_Detections.DetectionOnRectangle("haarcascade_frontalface_default.xml", img1, 2, (255,0,0))
cv2.imshow("test", img1)

■ビデオストリーミング+体の一部検知用API

Classとして、
・VideoStreamClass:ビデオストリーミングを行ったり、体の一部を検知するためのAPI
を用意。
ストリーミングのみを行ったり、ストリーミング結果を録画したり、、、
体の一部を四角で囲んだりすることができるAPIです。
こちらも色々詰め込みすぎてる気がするけど、、、
基本的にストリーミング系を1つにまとめた感じになっているから、、、
まぁよしとするか!!

使用例はこんな感じになります。

if __name__ == '__main__':
    video = VideoStreamClass()
    #video.VideoStream(None)
    video.VideoWriterInit(30, 640, 480, "test.mp4")
    video.VideoStream(None)

■最後に

ソースコードを整理するのに合わせて初めてAPI化してみました!!
今後、自分でもこちらのAPIを使用してアプリの作成を行っていこうと思います!!

後、まだまだ作成したコードがあるので整理しておこう。
だけど、、、量が多いのよね。今年中に終わるかしら??


カメラキャプチャ画像をバイト列で送受信

前回、Socket通信でやりたいことがあった!!と記載しました。
elsammit-beginnerblg.hatenablog.com

それが、
”カメラキャプチャ画像をバイト列に変換して送信しストリーミング配信を行ってみる”
ことです。
無駄なことだと思いますが、どうしてもやってみたくて調べてみました!!
問題なく動作させることが出来たので、方法をまとめておこうと思います。



■環境

今回こちらの構成で動作させてみました!!
f:id:Elsammit:20201220174102p:plain

前回と同様、ネットワークサーバをRaspberry Pi側に構築し、クライアントをwindows PCを用いました。
今回はpythonを用いるのですが、バージョンはこちらの通りです。
windows PC側Pythonバージョン:3.7.4
Raspberry PiPythonバージョン:3.7.3

またカメラですが、UCAM-C520FBBKを使用しました。

エレコム WEBカメラ マイク内蔵 200万画素 高精細ガラスレンズ ブラック UCAM-C520FBBK

新品価格
¥2,300から
(2020/12/20 18:19時点)


■サーバ側構築

ではまずはサーバ側の構築です。
全体のコードはこちらです。

import socketserver  
import cv2
import numpy  
import socket  
import sys  
  
class TCPHandler(socketserver.BaseRequestHandler):  
    def handle(self):
        self.data = self.request.recv(1024).strip()
        ret, frame=capture.read()
        jpegstring=cv2.imencode('.jpg', frame)[1].tostring()  
        self.request.send(jpegstring)  
  
#hostとportを設定
HOST = 'host名'
PORT = ポート番号

#カメラの設定
capture=cv2.VideoCapture(0)
capture.set(3,320)
capture.set(4,240)
if not capture:  
    print("Could not open camera")  
    sys.exit()
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((HOST, PORT), TCPHandler)  
server.capture=capture  

try:
    server.serve_forever()  
except KeyboardInterrupt:
    pass
server.shutdown()
sys.exit()

やっていることは、画像データをバイト列に変換し前回のsocket通信を実施しているのみです。
簡単には、
①データ受信により、TCPHandlerがコール
②画像データをバイト列に変換

jpegstring=cv2.imencode('.jpg', frame)[1].tostring()  

③バイト列をレスポンス

self.request.send(jpegstring)  

です。

■クライアント側構築

次にクライアント側の構築です。
コード全体はこちら。

import socket  
import numpy  
import cv2  

def getimage():
    #IPアドレスとポート番号は環境に応じて変更
    HOST = '192.168.11.2'
    PORT = 8080
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
    sock.connect((HOST,PORT))   
    sock.send(('a').encode("utf-8"))  
    buf=b''
    recvlen=100  
    while recvlen>0:  
        receivedstr=sock.recv(1024)  
        recvlen=len(receivedstr)  
        buf +=receivedstr
    sock.close()  
    narray=numpy.fromstring(buf,dtype='uint8')  
    return cv2.imdecode(narray,1)  
  
while True:  
    img = getimage()
    cv2.imshow('Capture',img)  
    if cv2.waitKey(100) & 0xFF == ord('q'):
        break

HOST = 'ホスト名'
PORT = ポート番号
getimage()

こちらもsocket通信とバイト列から画像データ変換の組み合わせです。
具体的には、

    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
    sock.connect((HOST,PORT))   
    sock.send(('a').encode("utf-8"))  

でバイト列を要求し、

    recvlen=100  
    while recvlen>0:  
        receivedstr=sock.recv(1024)  
        recvlen=len(receivedstr)  
        buf +=receivedstr

にてバイト列を全て受信。
受信したバイト列を画像データに変換。

    narray=numpy.fromstring(buf,dtype='uint8')  
    return cv2.imdecode(narray,1)  

以上です。

■動作確認

こちらを動作させてみましたが、、、
う~~ん。。。
遅延が目立ちますね。。。

コードは320×240だったのですが、画像サイズを数倍拡大させると
より遅延が目立つようになりました!!

バイトサイズが大きくなるにつれて遅延が大きくなってしまうようですね!!
しかも、jpgからbmpにencodeを変換すると、
数秒の遅延が発生してしまい、ビデオとしては、、、使い物にならないですね😅

制御が単純で分わかりやすいのですが、ちょっと使うシーンは限定されてしまう気がします。
使うとしても制限を守った使い方が必要そうですね。。

■最後に

興味があり、やってみましたが思ったより遅延があり、
gstreamerやffmpegがいかに優秀かわかりました。

時間があったらこれらの制御についても調査してみようと思いました!!



pythonでのネットワークサーバ構築とsocket通信

今回はpythonでのtcp通信についてまとめておこうと思います!!
ちょっとやりたいことがあって調べていたので、それをまとめておくことが目的。



■socket通信とは?

socket通信とは、サーバとクライアントを仮想的な接続により結んで構成された環境のことを言います。
f:id:Elsammit:20201219180709p:plain

具体的には、インターネットはTCP/IPと呼ぶ通信プロトコルを利用しますが、そのTCP/IPを プログラムから利用するには、プログラムの世界とTCP/IPの世界を結ぶ特別な 出入り口が必要となります。
その出入り口となるのがソケット (Socket)であり、TCP/IPのプログラミング上の大きな特徴となっています。
このため、TCP/IP通信をソケット通信と呼ぶこともあります。

■環境

今回の構成はこちら。
f:id:Elsammit:20201219181004p:plain

ネットワークサーバをRaspberry Pi側に構築し、クライアントをwindows PCを用いました。
(逆の方がよかったかも。。。)

今回はpythonを用いるのですが、バージョンはこちらの通りです。
windows PC側Pythonバージョン:3.7.4
Raspberry PiPythonバージョン:3.7.3

■ネットワークサーバ構築

まずはネットワークサーバの構築を行います!!
socket通信を行うためのネットワークサーバの構築を行うにあたり、
"socketserver"と"socket"が必要になるのであらかじめ、

pip install pycopy-socketserver
or 
pip3 install pycopy-socketserver
pip install sockets
or
pip3 install sockets

でインストールを行っておきます。

ネットワークサーバ構築のコードはこちら。

import socketserver  
import socket  

class TCPHandler(socketserver.BaseRequestHandler):      
    def handle(self):
        print(self.request.recv(1024).strip().decode())
        self.request.send(("hello world").encode("utf-8")) 

HOST = 'hostを設定'
PORT = ポート番号を設定 
socketserver.TCPServer.allow_reuse_address = True
server = socketserver.TCPServer((HOST, PORT), TCPHandler)  

try:
    server.serve_forever()  
except KeyboardInterrupt:
    pass
server.shutdown()
sys.exit()
server = socketserver.TCPServer((HOST, PORT), TCPHandler)  

でサーバの初期設定を行い、

server.serve_forever()  

でサーバとして起動・常駐させます。

そしてデータを受信すると、

    def handle(self):
        print(self.request.recv(1024).strip().decode())
        self.request.send(("hello world").encode("utf-8")) 

がコールされます。
受信されたデータはバイト列になっているため、

self.request.recv(1024).strip().decode()

のようにデコードしております。
さらに、送信するデータもバイト列に変換する必要があるので、

("hello world").encode("utf-8")

というように文字列をエンコードしてから送信しています。
※今回はhello worldを固定で送信するようにしています。

■クライアント側構築

クライアント側では"socket"が必要になるのであらかじめ、

pip install sockets
or
pip3 install sockets

でインストールを行っておきます。
そして、、、コードはこちら。

import socket  

HOST = 'hostを設定'
PORT = ポート番号を設定 
sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
sock.connect((HOST,PORT))   
sock.send(('Hello Raspberry').encode("utf-8"))  
    
receivedstr=sock.recv(1024)
print(receivedstr.decode())  

まずは初期設定!!

sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)  
sock.connect((HOST,PORT))   

こちらに記載されているのですが、今回はTCPで通信したかったのでSOCK_STREAMを設定。
https://qiita.com/__init__/items/5c89fa5b37b8c5ed32a4

そして、

sock.send(('Hello Raspberry').encode("utf-8"))  

でサーバへバイト列を送信。
今回はHello Raspberryの文字列をバイト列にエンコードして送信しています。

そして、

receivedstr=sock.recv(1024)

により受信したデータをreceivedstrに格納。
データはバイト列なので、文字列にデコードしてprintでログ出力しております。

■動作確認

始めにサーバ側を起動させた後、クライアント側でコードを実行すると、
【サーバ側】

Hello Raspberry

【クライアント側】

hello world

コマンドプロンプト上に表示されればOKです!!

■最後に

今回の技術を応用してやりたいことが実現出来ました!!
やりたいことが出来て満足😆
後で、応用してできたこともまとめておこうと思います!!



Reactでアニメーション付きリストを表示

今まで作成したアプリやコードの整理真っただ中!!
今年中に終わるかな?🤣

そこで、以前作成したポートフォリオ(なのか)??を整理しつつ少しレイアウトを変更したので、
そこで使用したアニメーション付きリストについてまとめていきたいと思います!!



■事前準備

Reactにてモジュールにアニメーションを付けるために、React Poseを用います。
React Poseはこちらの通り、色々なアニメーションを付与させることができるようになるライブラリとなります。
https://popmotion.io/

このReact Poseをインストールするためにこちらを実行!!

sudo npm i react-pose

これで事前準備が完了です。

■リストへのアニメーション追加

では本題のアニメーションを付与していこうと思います!!

リストにアニメーションを付与するためのコードはこちらになります。

const sidebarProps = {
    open: {
      x: '10px',
      delayChildren: 300,
      staggerChildren: 100,
    },
    closed: {
      delay: 500,
      staggerChildren: 20,
      x: '-100%'
    }
  };
  
  const itemProps = {
    open: { opacity: 1, y: 0 },
    closed: { opacity: 0, y: 10 }
  };

export default class TopPage extends Component  {
    constructor (props) {
        super(props);
        this.state = {
            isOpen: false,
        };
    }
    toggle = () => this.setState({ isOpen: !this.state.isOpen });
    SelectApp = () =>{
        return(      <div width="250px">
            <button onClick={this.toggle} className="asideSelectButton">Click Here !!</button>
            <SidePanel onClick={this.toggle} className="sidebar"
              pose={this.state.isOpen ? 'open' : 'closed'} >
                <Item className="item" value="WebApp">Webアプリ</Item>
                <Item className="item" value="ImageApp">画像処理</Item>
                <Item className="item" value="Python">python</Item>
                <Item className="item" value="Golang">go言語</Item>
                <Item className="item" value="MachineLearn">機械学習</Item>
            </SidePanel>
          </div>)
    }
}

さらに、cssはこちらのようにしました。

.sidebar{
    width:320px;
    font-size: 30px;
    background-color: aqua;
}

.item{
  width:200px;
  padding-bottom: 5px;
  display: inline-block;
  padding: 0.5em 1em;
  text-decoration: none;
  border-radius: 30px;
  color: #ffffff;
  background-image: linear-gradient(45deg, #FFC107 0%, #ff8b5f 100%);
  box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.29);
  border-bottom: solid 3px #c58668;
  
}

.item:active {
  -webkit-transform: translateY(4px);
  transform: translateY(4px);
  box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
  border-bottom: none;
}

.asideSelectButton {
    width:300px;
    margin-top:20px;
    margin-left:10px;
    font-size: 30px;
    display: inline-block;
    padding: 0.5em 1em;
    text-decoration: none;
    border-radius: 4px;
    color: #ffffff;
    background-image: linear-gradient(#6795fd 0%, #67ceff 100%);
    box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.29);
    border-bottom: solid 3px #5e7fca;
}

.asideSelectButton:active {
    -webkit-transform: translateY(4px);
    transform: translateY(4px);
    box-shadow: 0px 0px 1px rgba(0, 0, 0, 0.2);
    border-bottom: none;
}

細かい紹介の前にまずは動きから。
f:id:Elsammit:20201217223803g:plain

この"Click Here!!"を押下すると、

   toggle = () => this.setState({ isOpen: !this.state.isOpen });

が呼び出されてフラグが立ちます。

すると、

pose={this.state.isOpen ? 'open' : 'closed'}

により、poseにopenがセットされます。

open/close時の動作は、

const sidebarProps = {
    open: {
      x: '10px',
      delayChildren: 300,
      staggerChildren: 100,
    },
    closed: {
      delay: 500,
      staggerChildren: 20,
      x: '-100%'
    }
  };
  
  const itemProps = {
    open: { opacity: 1, y: 0 },
    closed: { opacity: 0, y: 10 }
  };

により定義されており、
open時にはリストが表示、close時にはリストが非表示の動作になります。

再度ボタンやリストを押下すると、

   toggle = () => this.setState({ isOpen: !this.state.isOpen });

が再度呼びされ、フラグが落ちてclose動作が走ります。

■最後に

整理するのが思ったより大変です。。しかもこうやって新しいことにも挑戦しているから尚更😅
今年中に整理終わるといいな!!



Raspberry PiへのGoCVインストール

以前LinuxへのGoCVへのインストール手順についてまとめました。
elsammit-beginnerblg.hatenablog.com

こちらの手順を元にRaspberry PiOpenCVをインストールしようとしたのですが、、、
少しハマったのでハマった箇所や解決策についてまとめておこうと思います!!


■環境

・デバイスRaspberry Pi 4
・OS:Raspbian GNU/Linux 10 (buster)
・GoCV:go version go1.15.6 linux/arm

【国内正規代理店品】Raspberry Pi4 ModelB 4GB ラズベリーパイ4 技適対応品【RS・OKdo版】

新品価格
¥6,875から
(2020/12/15 22:29時点)

■ハマった箇所

以前まとめた手順通り、

go get -u -d gocv.io/x/gocv

を実行の上、

export PKG_CONFIG_PATH="/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH"

にてパスを通し、/usr/local/lib/pkgconfig配下のopencv4.pcを下記の通り編集します。
※もしopencv4.pcが存在しなければ新規で作成。

prefix=/usr/local
exec_prefix=${prefix}
includedir=${prefix}/include
libdir=${exec_prefix}/lib

Name: opencv4
Description: The opencv library
Version: 4.0.0
Cflags: -I${includedir}/opencv4
Libs: -L${libdir} -lopencv_aruco -lopencv_bgsegm -lopencv_bioinspired -lopencv_calib3d -lopencv_ccalib -lopencv_core -lopencv_datasets -lopencv_dnn -lopencv_dnn_objdetect -lopencv_dpm -lopencv_face -lopencv_features2d -lopencv_flann -lopencv_fuzzy -lopencv_gapi -lopencv_hfs -lopencv_highgui -lopencv_img_hash -lopencv_imgcodecs -lopencv_imgproc -lopencv_line_descriptor -lopencv_ml -lopencv_objdetect -lopencv_optflow -lopencv_phase_unwrapping -lopencv_photo -lopencv_plot -lopencv_reg -lopencv_rgbd -lopencv_saliency -lopencv_shape -lopencv_stereo -lopencv_stitching -lopencv_structured_light -lopencv_superres -lopencv_surface_matching -lopencv_text -lopencv_tracking -lopencv_video -lopencv_videoio -lopencv_videostab -lopencv_xfeatures2d -lopencv_ximgproc -lopencv_xobjdetect -lopencv_xphoto

そして、、、

cd $GOPATH/src/gocv.io/x/gocv
sudo make install

を実行!!

しばらくしたところビルドエラー。。。
ログを確認したところ、

../../../../gocv.io/x/gocv/core.go:2008: type [1073741824]C.struct_Point larger than address space
../../../../gocv.io/x/gocv/core.go:2008: type [1073741824]C.struct_Point too large

といったエラーが発生。

■解決策

先ほどの指摘されたコードは、

tmpslice := (*[1 << 30]*C.char)(unsafe.Pointer(strs.strs))[:length:length]

となります。
どうやら32bit OSである場合、

1 << 30

だとアドレスの範囲を超えてしまう(オーバー)してしまうようです。
このためこちらを、

1 << 20

に変更!!

そして再度、

sudo make install

を実行!!
問題なくエラーが発生せずにインストール成功しました。

■最後に

Raspberry PiでもGoCVのインストールが出来ました。
Go言語はドライバ制御も出来るようなので、Go言語での画像や制御系の処理を作ってみたいなと思います。