Raspberry Piをシングルユーザモードで起動する

ユーザ, パスワードを忘れてしまって、パスワードを設定しなおしたい場合や、
起動時の設定を誤ってしまった場合など、シングルユーザモードでRaspberry Piにログインする方法

cmdline.txtをエディタで開き、赤字の部分を追加します。

dwc_otg.lpm_enable=0 init=/bin/sh console=ttyAMA0,115200 \
> kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait logo.nologo
> 

cmdline.txtに、init=/bin/shを追加した上で、
Raspberry Piを起動すると、シングルユーザモードで起動するとのこと。

ただし起動直後は、/以下がreadonlyの状態でマウントされているので、
ファイルの読み込みはできても、変更などを行うことができない。

mount -o remount,rw /

で再マウントを行うことで、読み書きが可能となる。

Arduinoに人感センサ(焦電型赤外線センサ)SE-10を接続する

人感センサ(焦電型赤外線センサ)SE-10

人感センサSE-10は、焦電型赤外線センサを搭載した人体や動物に反応するセンサである。電源を入れて数秒後からセンサ前面周辺を監視し、人体などの35度程度の物体が動くとALARM信号がLOWの状態へと変化する。検知角度は120度である。

Arduinoに接続する

焦電型赤外線センサSE-10は正面から見て左から赤(+B),茶(GND),黒(ALARM)となっており、Arduinoで接続する場合は以下のように接続を行う。赤(+B)と黒(ALARM)との間には10KΩ程度のプルアップ抵抗を入れる。

SE-10ブレッドボード接続図

SE-10のALARM信号は、上の図ではデジタル入力のPin2に入力されている。以下のプログラムは、人感センサーが反応(ALARM信号がLOW)すれば、LEDを点灯させると同時にシリアル通信にて1を送信する処理を行っている。

const int ledPin = 13;
const int pirPin = 2;

void setup() {
  // put your setup code here, to run once:
  // シリアル通信速度
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(pirPin) == LOW) {
    digitalWrite(ledPin, HIGH);
    Serial.println("1");

  } else {
    digitalWrite(ledPin, LOW);
    Serial.println("0");
  }
  delay(1000);
}

Raspberry Pi – Arduino間でシリアル通信を行う

シリアル通信を行うことが可能なscreenコマンドと、
Pythonでシリアル通信を行うことが可能なpython-serialモジュールを
apt-getを利用してRaspberry Piにインストールする

sudo apt-get install screen
sudo apt-get install python-serial

次に、Pythonでシリアル通信スクリプトを作成する

vi serial-arduino.py

このときにファイル名をserial.pyとかいう名前にしてしまうと、
Pythonのserialモジュールと名前が重複してしまい、

AttributeError: ‘module’ object has no attribute ‘Serial’

というエラーがでてしまうので、他の名前にするのが良い。

USBでRaspberry PiとArduinoを接続し、
なんというデバイス名称で認識されているか確認する

dmesg
lsusb

シリアル通信でArduinoから定期的に送られてくるデータをもとに、
JSONファイルを作成するサンプルは以下の通り。

  • カンマ区切りデータの場合
import serial

    def main():
            # デバイス名: /dev/ttyACM0 通信速度: 9600bps
            con=serial.Serial('/dev/ttyACM0', 9600)
            # デバイス名を出力する
            print con.portstr
            while 1:
                    # 1行ごとにデータを取得する
                    str=con.readline()
                    # ファイルに書き込み
                    f = open('/tmp/data.json', 'w')
                    f.write("[{\"data_1\":" + str + "}]")
                    f.close()

    if __name__ == '__main__':
            main()
  • JSON形式の場合
import serial
    import json

    def main():
            # デバイス名: /dev/ttyACM0 通信速度: 9600bps
            con=serial.Serial('/dev/ttyACM0', 9600)
            # デバイス名を出力する
            print con.portstr
            while 1:
                    try:
                            # strという変数名は使用できない
                            strs=con.readline()
                            dec=json.loads(strs)

                            f = open('/tmp/data.json', 'w')
                            f.write(strs)
                            f.close()
                    except KeyError:
                            print "KeyError"
                    except ValueError:
                            print "ValueError"
                    except NameError:
                            print "NameError"

    if __name__ == '__main__':
                    main() 

実行してJSONが吐き出されるか確認する

python serial-arduino.py

Raspberry Piのインストール

Raspberry Piの起動と終了

Raspberry Piの起動

Raspberry Piは、電源を投入すると自動的に起動する
インストール時のログイン名/パスワードは、
以下の通り設定されていて、piユーザにはsudo権限が付与されている

  • user: pi
  • pass: raspberry

Guiを開始する場合は、以下のコマンドを実行する

$ startx

Guiの終了は、メニューからログアウトを選択する

Raspberry Piの終了

終了や再起動は、通常のLinuxと同じで、
以下のいずれかのコマンドを実行する

$ sudo reboot
$ sudo shutdown -h now

Rasbperianのセットアップ

Raspberianのインストール

まず、Raspberry Piで使用するSDカードを
SD Formatterを利用して初期化する

SDカードのフォーマット
初期化されたSDカードにNOOBSをコピーする
NOOBSのコピー

Raspberry Pi + Motion + WebCamで動体検知を行う

Raspberry Piに接続したWebCamから映像を取得可能なパッケージはいくつか有名なものが存在するようだが、今回はMotionという動体検知を行うことのできるパッケージを用いて、WebCamの映像を取得してみる。

パッケージのインストール

apt-getから取得することができる

sudo apt-get install motion

設定

今回はMotionをデーモン起動させて常時稼働させる。設定ファイルは以下のように変更した。

# Image width
width 640
# Image height
height 480
# Maximum number of frames to be captured per second.
# フレーム数を大きくしすぎるとRaspberry Piで処理しきれなくなる
framerate 3
# Output 'normal' pictures when motion is detected
# 動体検知時に画像を出力しない
output_pictures off
# Use ffmpeg to encode movies in realtime
# 動体検知時に動画を出力しない
ffmpeg_output_movies off
# Make automated snapshot every N seconds
snapshot_interval 1
# Locate and draw a box around the moving object.
# 動体マーカ
locate_motion_mode on
# Target base directory for pictures and films
target_dir /var/www/html
# File path for snapshots (jpeg or ppm) relative to target_dir
snapshot_filename snapshot
# Restrict stream connections to localhost only
# ローカルホスト以外からのアクセスを許可する
stream_localhost off
# Restrict control connections to localhost only
# ローカルホスト以外からのアクセスを許可する
webcontrol_localhost off

サービスの開始

USBカメラを繋ぎ、認識されていることを確認する。

lsusb

Bus 001 Device 015: ID 0c45:62e0 Microdia MSI Starcam Racer

設定ができたらサービスを開始する。でも正常にサービス開始しない。

sudo service motion start
Apr 20 18:42:55 raspberrypi motion[1410]: Not starting motion daemon, disabled via /etc/default/motion ... (warning).

/etc/default/motionも変更しないといけないらしい。

sudo vi /etc/default/motion

# set to 'yes' to enable the motion daemon
start_motion_daemon=yes

再度、サービス開始。
今度はちゃんと開始された。

sudo service motion start

以下のエラーが発生する場合は、画像の出力先のパーミッションに問題ある場合があるので、パーミッションを変更する。

Apr 20 19:28:15 raspberrypi motion[7929]: [1] [ERR] [ALL] put_picture: Can't write picture to file /var/www/html/snapshot.jpg - check access rights to target directory
                                          Thread is going to finish due to this fatal error:
Apr 20 19:28:15 raspberrypi motion[7929]: [1] [ERR] [EVT] event_image_snapshot: Could not create symbolic link [snapshot.jpg]:

Raspberianをインストール後にすること

Raspberry PiにRaspberianをインストール後、まずすること。普段からDebianを使っている人は違和感ないのかもしれないが、RHEL系で生きているとDebian系の使い勝手が分からなくて苦しい。

ロケールの変更

ロケールを日本語に設定すると文字化けでうまく表示されないので、en_US.UTF-8.UTF-8のままでよいかも。

$ sudo dpkg-reconfigure locales

タイムゾーンの変更

タイムゾーンを東京に変更する。

$ sudo cp -p /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ sudo vi /etc/timezone
Asia/Tokyo

キーボードの設定

日本語キーボードに対応する。

$ sudo vi /etc/default.keyboard

# KEYBOARD CONFIGURATION FILE

# Consult the keyboard(5) manual page.

XKBMODEL="jp106"
XKBLAYOUT="jp"
XKBVARIANT=""
XKBOPTIONS=""

BACKSPACE="guess"

ランレベルの設定

デフォルトだとXWindowが立ち上がるが、これをランレベル3に変更する。

sudo systemctl set-default multi-user.target

固定IPアドレスを設定

Raspbrianのバージョンによって設定方法が異なる。

Raspbrian jessie

固定IPの設定は、/etc/network/interfacesではなく、/etc/dhcpcd.confに追記する。

$ sudo vi /etc/dhcpcd.conf

interface eth0
static ip_address=192.168.0.10/24
static routers=192.168.0.1
static domain_name_servers=192.168.0.1

以下のコマンドをいろいろ試したけど、新しい設定が全く反映されない。

$ sudo service dhcpcd restart
$ sudo service dhcpcd reload
$ sudo service dhcpcd force-reload
$ sudo service networking restart
$ sudo service ifup@eth0 restart
$ sudo systemctl restart dhcpcd
$ sudo systemctl restart networking
$ sudo systemctl restart ifup@eth0

仕方ないので端末再起動。

$ sudo reboot

Raspbrian wheezy

固定IPの設定は、/etc/network/interfacesに追記する。

$ sudo vi /etc/network/intefeces

インストール直後には、DHCP設定となっているので、固定アドレスとする場合は以下のように変更する。

auto lo

iface lo inet loopback
iface eth0 inet static

address 192.168.0.2
netmask 255.255.255.0
gateway 192.168.0.1

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp

無線LANの設定

Raspberry Piに無線LAN接続する場合は、以下の手順で行う。今回は、PLANEXのGW-USNANO2Aを使用した。

  1. Raspberry PiのUSBポートに挿入
  2. wpa_passphraseコマンドを、/etc/wpa_supplicant/wpa_supplicant.confに出力する
  3. /etc/wpa_supplicant/wpa_supplicant.confに、認証方式などの情報を追記する

WPA2-PSK(AES)の場合は、以下の通りとなる。

]$ sudo wpa_passphrase SSID PASS_PHRASE >> /etc/wpa_supplicant/wpa_supplicant.conf
$ sudo vi /etc/wpa_supplicant/wpa_supplicant.conf

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
        ssid="SSID"
        #psk="PASS_PHRASE"
        psk=xxxxxxxxxxxxxxxxxxxxxxxxxxx
        proto=RSN
        key_mgmt=WPA-PSK
        pairwise=CCMP
        group=CCMP
}

無線LANインタフェースの状況を確認するためには、

iwconfig wlan0

識別できているSSIDの一覧を取得するためには、

iwlist wlan0 scan | grep SSID

                    ESSID:"guest"
                    ESSID:"test"
                    ESSID:""
                    ESSID:"free"
                    ESSID:""

以下のファイルも変更する。
wlan0インタフェースを自動起動設定とし、wlan1インタフェースの無効化している。

]
$ sudo vi /etc/network/interfaces

# interfaces(5) file used by ifup(8) and ifdown(8)

Please note that this file is written to be used with dhcpcd
For static IP, consult /etc/dhcpcd.conf and 'man dhcpcd.conf'

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto lo
iface lo inet loopback

iface eth0 inet manual

auto wlan0
allow-hotplug wlan0
iface wlan0 inet manual
     wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

#allow-hotplug wlan1
#iface wlan1 inet manual
#    wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

パッケージのインストール

必要なパッケージをインストールする。

$ sudo apt-get install chkconfig
$ sudo apt-get install screen
$ sudo apt-get install apache2
$ sudo chkconfig ntp off
$ sudo chkconfig apache2 on

パッケージの更新もしておく。

$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo rpi-update

プロキシ環境でapt-getを実行する場合は、以下のファイルを変更する。

$ sudo vi /etc/apt/apt.conf.d/10proxy

追記内容は以下の通り。

Acquire::http::Proxy "https://192.168.x.x:8080";

Vimの起動モードを変更

Viで矢印キーを押したときにABCDと出てしまう問題は、VimをVi互換モードではなく通常モードで起動することで直る。

~/.vimrcに設定を保存できる。sudoでvimを使うときのために/root/.vimrcにも追記しておく。

$ vi ~/.vimrc

:set nocompatible
:set backspace=indent,eol,start
:set number

~/.vimrcに書ける便利な設定がいろいろあるみたい。

設定 内容
:set nocompatible 通常モード起動
:set backspace=indent,eol,start バックスペースキーの挙動を指定
:set number 行番号を表示

もしくは、Vimのインストールでも直る。

$ sudo apt-get install vim

Raspberry piがRead-Only Filesystemになってしまったときの対処法

Raspberry piの設定ファイルを書き換えても再起動すると、元の内容に戻ってしまい変更が反映されない。

pi@raspberrypi ~ $ dmesg | egrep "readonly|read-only"

[    2.386594] mmc0: host does not support reading read-only switch, assuming write-enable
[    2.526799] EXT4-fs (mmcblk0p6): INFO: recovery required on readonly filesystem
[    3.242388] EXT4-fs (mmcblk0p6): orphan cleanup on readonly fs
[    3.370433] VFS: Mounted root (ext4 filesystem) readonly on device 179:6.

dmesgで見ると、ファイルシステム全体がReadonlyになっていて、これがファイルがうまく保存されない原因のようだ。起動中にSDカードを抜き出したり、電源を落としたときにファイルシステムが壊れたか。

recovery required on readonly filesystem

というわけでさっそく修復してみる。fsckコマンドで修復してみるも、既にマウントされているのでコマンド実行できないと怒られる。とりあえず早く修復して別の作業に取り掛かりたいので、カーネル起動オプション設定ファイル「cmdline.txt」に、fsckを毎回起動時に実行する設定を追記し、Raspberry Piを再起動。

fsck.mode=force

fsckが走ってとりあえず修復。よかった。

AWS Lambda(1)Lambdaの概要

Lambdaとは

AWS Lambdaは、イベントをトリガにクラウド上で独自のコードを実行させるサービス。EC2インスタンス等の管理が不要で負荷に合わせて自動でスケールアウトすることのできるフルマネージドのサービスである。100ミリ秒単位の処理時間で従量課金される。例えば、画像がアップロードされたタイミングでサムネイル画像を生成したり、DynamoDBへの書き込みタイミングプッシュ通知を行うなどをLambdaを用いて実現できる。イベントの発生元となるAWSリソースは、S3, Kinesis, DynamoDB, Cognitoなどで、Pull/Pushの2種類のイベントモデルが存在する。

コードはブラウザ上で直接編集するか、Zip形式のファイルをアップロードすることで編集可能である。各種ライブラリはZipファイルに含めることで実行が可能となる。

データの永続化やS3DynamoDBを使用する。/tmpも使用できる。

LambdaのIAM権限は、誰がファンクションを実行できるかを記述したInvocation Roleと、どのようなことを実行できるかを記述したExecution Roleの2種類が存在する。

コンテクスト

実行コンテナは、タイムアウト(Timeout)した場合や、”context.done()“が呼び出された場合(Controlled termination)、全ての処理を終了した場合(Default termination)、クラッシュや”process.exit()“した場合に処理を終了する。実行コンテナは、前回の処理からある程度の時間が経過していた場合は新規で作成されるが、前回使用したものを再利用することもある。context.done()を記述することで予想外の実行を防ぐことができる。

内容
context.succeed(Object result) ファンクションおよびコールバックが正常終了
context.fail(Object result) ファンクションおよびコールバックがエラー
context.done(String message, Object result) ファンクションが終了. messageに値が入力されているとエラー
awsRequestId ファンクション呼び出しID
logStreamName CloudWatch LogsのLogストリーム名
clientContext クライアントアプリおよびデバイスの情報
Identity CognitoのIdentity Provider情報

処理の進行を表示する

UIActiveIndicatorView

Storyboad上で「Animating」と「Hides When Stopped」にチェックを入れておくとよい

[_indicator startAnimating];

インジケータのアニメーションが開始される

[_indicator stopAnimating];

インジケータのアニメーションが停止される。Storyboad上で「Hides When Stopped」オプションにチェックを入れている場合は、インジケータが非表示となる

C言語とObjective-C

ファイル構成

クラスファイルはヘッダファイルとソースファイルより構成される。

// SampleCode.h
@interface SampleCode
@end
// SampleCode.m
#import "SampleCode.h"
@implement SampleCode
@end
  • クラスファイルはヘッダファイルとソースファイルより構成される
  • ヘッダファイルには、外部に見せるメソッド(インタフェース)を記述する
  • ソースファイルに、実際のメソッドを実装する

プリプロセッサ

数値や文字列に名前を付けて定数を定義することが出来る

#define TAX_RATE 0.05

ヘッダファイルを読み込む

// 標準ライブラリのみ取り込み
#import <UIKit/UIKit.h>
// カレントディレクトリを検索し、無ければ標準ライブラリを検索する
#import "CustomLib.h"

データ型

自分で定義した列挙型(定数のリスト)の例

// 自身で定義した列挙型をViewState型と定義する
typedef enum {
ViewStateHidden
ViewStateVisible
} ViewState;

メソッド

引数の説明(メッセージキーワード)を記述するのが特徴

-(戻り値の型)メソッド名:(引数1の型)引数1の名前 引数2の説明文:(引数2の型)引数2の名前

インスタンス化の不要なクラスファイルは頭に+をつける

+(戻り値の型)メソッド名:(引数1の型)引数1の名前 引数2の説明文:(引数2の型)引数2の名前

その他

  • selfは自分自身のオブジェクトを意味する
  • initはコンストラクタ(初期化)
  • init内では self = [super init]などとしスーパークラスの初期化を行う。returnではselfを返す