Yura YuLife

ITエンジニアの覚え書き。

Raspberry Piでスイッチを押すと音楽を再生する

Raspberry Piに接続したタクトスイッチを押すと、音楽を再生するPythonスクリプトです。

ちなみに、上の動画で流れているのは僕のバンドCosmic Time Scaleの曲です。

必要なもの

Raspberry Piとタクトスイッチを接続

こんな感じで配線します。

f:id:yurayur:20160214191937p:plain

GPIOピンは今回は19番を使っていますが、空いていればどのピンでも大丈夫。

スイッチの動作をテスト

以下のスクリプトraspi_gpio_pin.pyとして保存します。

$ python raspi_gpio_pin.pyを実行し、スイッチを押していない時は0、スイッチを押している時は1がコンソールに出力されれば、問題なく配線されています。

スイッチ押下で音楽を再生

以下のスクリプトraspi_play_music.pyとして保存します。

$ python raspi_play_music.pyを実行し、スイッチを押すとSONG_LISTの中からランダムに曲が再生されます。

これを応用すればRaspberry Piで音響さんやDJができますね。

参考URL

Raspberry Piに接続したLCD(ACM1602NI)をPythonで動かす

Raspberry PiにI2Cで接続したLCD(ACM1602NI-FLW-FBW-M01)を、Pythonから動かします。

f:id:yurayur:20160213215623j:plain

ソースコード、セットアップ手順はGitHubにて公開しています。

github.com

必要なもの

Raspberry PiとLCDを接続

LCDにハンダ付け

LCDの基板に7ピンのピンフレームをハンダ付けします。

ブレッドボードにピンを刺した状態でハンダ付けすると、ピンを垂直に固定するのが容易になるのでオススメです。

LCDとRaspberry Piを接続

ブレッドボード上はこんな感じで接続します。

f:id:yurayur:20160213221550j:plain

ちなみに本体側のピンはこちら。

f:id:yurayur:20160213222044j:plain

ここまでできたらRaspberry Piを起動します。

Raspbianの設定

I2Cを有効にする

$ sudo raspi-config

9 Advanced Options から A7 I2C を選択し、 Yes を2回選択します。raspi-configを抜けたらRaspberry Piを再起動します。

必要なライブラリのインストール

$ sudo apt-get install i2c-tools python-smbus

ドライバーのロード

$ sudo modprobe i2c-bcm2708
$ sudo modprobe i2c-dev

I2C Configの編集

/boot/config.txtを開いて以下の行を追記します。

dtparam=i2c_baudrate=50000

ここで再度Raspberry Piを再起動します。

設定の確認

以下のコマンドを実行し、bcm2708がロードされていること、baudrate50000に変更されていることを確認します。

$ dmesg | grep i2c
[    3.787020] bcm2708_i2c 3f804000.i2c: BSC1 Controller at 0x3f804000 (irq 79) (baudrate 50000)
[    3.820524] i2c /dev entries driver

LCDの動作テスト

以下のコマンドを実行し、LCDAと表示されることを確認します。

$ sudo i2cset -y 1 0x50 0x00 0x01
$ sudo i2cset -y 1 0x50 0x00 0x38
$ sudo i2cset -y 1 0x50 0x00 0x0c
$ sudo i2cset -y 1 0x50 0x00 0x06
$ sudo i2cset -y 1 0x50 0x80 0x41

なお、i2csetコマンドの引数の1はI2Cバスの番号、0x50LCDのアドレスです。

通常これらはi2cdetectコマンドで調べられるのですが、このコマンドを実行するとLCDがハングするため絶対に行ってはいけません

PythonからLCDを操作

$ git clone https://github.com/yuma-m/raspi_lcd_acm1602ni.git
$ cd raspi_lcd_acm1602ni
$ sudo python raspi_lcd.py "Hello world!"
$ sudo python raspi_lcd.py "ラズベリーパイデ、" "ニホンゴヲLCDヒョウジ!"

raspi_lcd.pyは引数を1つ、もしくは2つ取ることができ、それぞれが1行目、2行目の表示内容に対応しています。

入力可能な文字は、半角英数記号、半角・全角のカタカナ、一部の特殊文字(千、万、円、Σ、α、βなど)です。

f:id:yurayur:20160213224244j:plain

参考URL

PCがRealSense R200をUSBハブに接続するとPCから認識できない

タイトルの通り。 IntelのRealSense R200をUSBハブやUSB延長ケーブルに接続すると、PCから認識できないことがあります。 これは単純に電力の供給不足が原因です。

RealSenseなどの深度センサでは、赤外線レーザーによってパターンを照射し、赤外線カメラによってそのパターンの歪みを読み取ることで深度を計算しています。 このレーザーの照射に電力が必要なため、ハブなどに接続すると電力不足で正しく起動しないことがあります。

解決策としては以下のような方法が挙げられます。

  • ACアダプタ付きのUSBハブを利用する
  • PCのUSB 3.0ポートに直接接続する
  • USB延長ケーブルを複数直列に接続しない

2016年2月9日 追記

2つのポートから電力を供給できる、Y字のUSBケーブルっていうのがあるんですね。

こんなの。

参考URL

PythonでGoogle Drive API v3を利用して画像のアップロード

PythonGoogle Drive API v3を利用して、 GoogleDriveにフォルダを作成し、ローカルのフォルダ内の画像をアップロードするスクリプトです。

環境

Google Drive APIの有効化と認証情報の取得

プロジェクトの作成

https://console.developers.google.com/start/api?id=drive のページから、新しいプロジェクトを作成するか、既存のプロジェクトを選択して「続行」をクリックします。

f:id:yurayur:20160129154438p:plain

Google Driveが有効化されました、と表示されたら「認証情報に進む」をクリックします

f:id:yurayur:20160129154449p:plain

認証情報の作成

「新しい認証情報」から「OAuth クライアントID」をクリックします

f:id:yurayur:20160129154502p:plain

アプリケーションの種類は「その他」を選択し、適当な名前を入力します

f:id:yurayur:20160129154513p:plain

「作成」をクリックし、次の画面では「OK」をクリックします

f:id:yurayur:20160129154526p:plain

認証情報のダウンロード

作成した認証情報の「JSONをダウンロード」をクリックします

f:id:yurayur:20160129161136p:plain

JSONファイルをダウンロードし、ファイル名をclient_secret.jsonとして保存します

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

以下のコマンドを実行します。

$ sudo pip install --upgrade google-api-python-client

スクリプトの作成

以下のスクリプトupload.pyとして保存し、IMG_DIR等の変数の値を設定します。

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

from __future__ import print_function
import httplib2
import os
import sys

from apiclient import discovery
import oauth2client
from oauth2client import client
from oauth2client import tools
from apiclient.http import MediaFileUpload

import glob

# アップロードする画像の入っているフォルダ
IMG_DIR = '/path/to/image/dir/'

# アップロードするファイルの拡張子
EXTENSION = 'jpg'

# アップロードするファイルのMIMEタイプ
MIME_TYPE = 'image/jpeg'

# Google Driveに作成するフォルダ名
DRIVE_DIR = 'hoge'

# client_secret.jsonの保存先
CLIENT_SECRET_FILE = '/path/to/client_secret.json'

# アップロード先の親フォルダのID
# Google Driveでフォルダを開いた時のURLの末尾がフォルダID
# https://drive.google.com/drive/folders/ここがフォルダID
FOLDER_ID = 'フォルダIDを入力'

# アプリケーション名
APPLICATION_NAME = '先ほど入力した名前'

# Google Driveにファイルの作成と、当該アプリで作成したファイルを取得できる権限(変更不要)
# その他の権限は以下のURLを参照: https://developers.google.com/drive/v3/web/about-auth
SCOPES = 'https://www.googleapis.com/auth/drive.file'


try:
    import argparse
    flags = argparse.ArgumentParser(parents=[tools.argparser]).parse_args()
except ImportError:
    flags = None


class GoogleDriveUploader:
    def __init__(self):
        self.credentials = self.get_credentials()
        self.http = self.credentials.authorize(httplib2.Http())
        self.service = discovery.build('drive', 'v3', http=self.http)

        # /path/to/dir/*.jpg に一致するファイルを探しに行く
        self.file_path = os.path.join(IMG_DIR, '*.' + EXTENSION)
        self.files = glob.glob(self.file_path)
        if not self.files:
            print("No files to upload.")
            sys.exit()

    def get_credentials(self):
        u'''APIのQuickstartのコードのコピペ

        https://developers.google.com/drive/v3/web/quickstart/python
        初回実行時のみブラウザに認証画面が表示され、
        認証すると~/.credentials/に認証情報が保存される
        2回目以降は保存された認証情報を利用してアクセスする
        '''
        home_dir = os.path.expanduser('~')
        credential_dir = os.path.join(home_dir, '.credentials')
        if not os.path.exists(credential_dir):
            os.makedirs(credential_dir)
        credential_path = os.path.join(credential_dir,
                                       'drive-python-quickstart.json')

        store = oauth2client.file.Storage(credential_path)
        credentials = store.get()
        if not credentials or credentials.invalid:
            flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
            flow.user_agent = APPLICATION_NAME
            if flags:
                credentials = tools.run_flow(flow, store, flags)
            else:
                # Needed only for compatibility with Python 2.6
                credentials = tools.run(flow, store)
                print('Storing credentials to ' + credential_path)
        return credentials

    def create_folder(self):
        u'''Google Driveにフォルダを作成する'''
        print("Create folder: %s" % (DRIVE_DIR))
        file_metadata = {
            'name': DRIVE_DIR,
            'mimeType': 'application/vnd.google-apps.folder',
            # マイドライブ直下にフォルダを作成する場合は次の行をコメントアウト
            'parents': [FOLDER_ID],
        }
        folder = self.service.files().create(body=file_metadata,
                                             fields='id').execute()
        # 作成されたフォルダのID
        self.sub_folder_id = folder.get('id')

    def upload_file(self, file_name):
        u'''ファイルをアップロードする'''
        media_body = MediaFileUpload(file_name, mimetype=MIME_TYPE, resumable=True)
        body = {
            'name': os.path.split(file_name)[-1],
            'mimeType': MIME_TYPE,
            # マイドライブ直下にファイルをアップロードする場合は次の行をコメントアウト
            'parents': [self.sub_folder_id],
        }
        self.service.files().create(body=body, media_body=media_body).execute()

    def upload_all_images(self):
        u'''フォルダ内のファイルを全てアップロードする'''
        # マイドライブ直下にファイルをアップロードする場合は次の行もコメントアウト
        self.create_folder()
        for file_name in self.files:
            print('upload: ' + file_name)
            self.upload_file(file_name)

if __name__ == '__main__':
    uploader = GoogleDriveUploader()
    uploader.upload_all_images()

スクリプトの実行

$ python upload.py

Storing credentials to ~/.credentials/drive-python-quickstart.json
Create folder: hoge
upload: hoge1.jpg
upload: hoge2.jpg
...

マイドライブ を開いて、フォルダが作成されてとファイルがアップロードされていることが確認できれば成功です。

参考URL

シェルスクリプトで日付が有効かをチェックし、開始・終了日間でループする

シェルスクリプトで、特定の日付間のログのみを抽出する等の処理をする際に、日付でループするコードの例です。

サンプルコード

loop_date.sh

#!/bin/bash

# 有効な日付ではない場合は終了する関数
function check_date() {
    date -d "$1" || exit 1
    return 0
}

# 引数の数をチェック
if [ $# -ne 2 ]; then
    echo "使い方: ./loop_date.sh 開始日[YYYYMMDD] 終了日[YYYYMMDD]"
    exit 1
fi

# 日付が有効かをチェック
check_date $1
check_date $2

# 開始日 < 終了日になっているかをチェック
if [ $1 -gt $2 ]; then
    echo "開始日は終了日よりも前にしてください"
    exit 1
fi

BEGIN=$1
END=$2
CURRENT=$BEGIN

# 開始日〜終了日までループ
while true; do
    # ここに日付毎の処理を書く
    echo "処理: $CURRENT"

    if [ "$CURRENT" = "$END" ]
    then
    break
    fi

    # 日付を1日インクリメント
    CURRENT=$(date -d "$CURRENT 1day" "+%Y%m%d")
done

動作例

$ ./loop_date.sh 20151201 20151205
2015年 12月  1日 火曜日 00:00:00 JST
2015年 12月  5日 土曜日 00:00:00 JST
処理: 20151201
処理: 20151202
処理: 20151203
処理: 20151204
処理: 20151205

$ ./loop_date.sh 20151130 20151201
2015年 11月 30日 月曜日 00:00:00 JST
2015年 12月  1日 火曜日 00:00:00 JST
処理: 20151130
処理: 20151201

$ ./loop_date.sh 20151131 20151205
date: `20151131' は無効な日付です

$ ./loop_date.sh 20151205 20151201
2015年 12月  5日 土曜日 00:00:00 JST
2015年 12月  1日 火曜日 00:00:00 JST
開始日は終了日よりも前にしてください

$ ./loop_date.sh
使い方: ./date_loop.sh 開始日[YYYYMMDD] 終了日[YYYYMMDD]

参考URL