Raspberry Pi でスイッチを使ったLED点灯をしてみた。(Node.js)

今回は、Node.js をインストールした Raspberry Pi を使って、
LED点灯の制御を行ってみました。

概要

スイッチが押されている間だけLEDが点灯するプログラムを作成する。

参考文献

WEB
  1. 第9回「ラズベリーパイで電子工作!Lチカ…の前にLピカ!」
  2. Raspberry PiとNode.jsでLチカ(LEDをチカチカ)させてみよう!
  3. ラズベリーパイのGPIOを、Node.jsで操作してLED光らせてみた!
  4. タクトスイッチを使ってLEDを点灯してみる
  5. Raspberry Pi タクトスイッチの入力を扱う その1
書籍
  1. Raspberry Piで学ぶ電子工作 超小型コンピュータで電子回路を制御する

環境

回路の作成

以下の図の通りに配線を繋ぎます。 f:id:ashiris:20170109205400p:plain 回路の解説は割愛させて頂きます。
参考文献のWEB 5.書籍 1.で詳しい解説が掲載されていますので、
詳細を知りたい方はそちらを参照ください。

プログラム作成

ソースコード
var fs = require('fs');

var GPIO_DIR = '/sys/class/gpio';
var GPIO_PIN_DIR = GPIO_DIR + '/gpio';
var PIN_LIST = [];

//使用したGPIOポートの開放
var cleanUp = function() {
    for (var i=0; i < PIN_LIST.length; i++) {
                fs.writeFileSync(GPIO_DIR + '/unexport', PIN_LIST[i]);
        }
};

//使用するGPIOポートの準備設定
var setUp = function(pin, io) {
        try {
                fs.writeFileSync(GPIO_DIR + '/export', pin);
                PIN_LIST.push(pin);
                fs.writeFileSync(GPIO_PIN_DIR + pin + '/direction', io);
        } catch (e) {
                console.log(e);
                cleanUp();
        }
};

//GPIOの入力状態を取得
var getInput = function(pin) {
        try {
                var cntxt = fs.readFileSync(GPIO_PIN_DIR + pin + '/value');
                return cntxt.toString().split('\n')[0];
        } catch (e) {
                console.log(e);
                cleanUp();
        }
};

//GPIOの出力状態を設定
var setOutput = function(pin, value) {
        try {
                fs.writeFileSync(GPIO_PIN_DIR + pin + '/value', value);
        } catch (e) {
                console.log(e);
                cleanUp();
        }
};

try {
        //GPIO 7を入力に設定する。
        setUp(7, 'in');
        //GPIO 8を出力に設定する。
        setUp(8, 'out');

        //0.01毎にGPIO 7の入力状態を確認し、
        //電流が流れている(スイッチが押されている)場合
        //LEDを点灯させる。
        var moniter = setInterval(function() {
                var value = getInput(7);
                if (value == '1') {
                        //スイッチが押された状態
                        setOutput(8, '1');
                } else {
                        //スイッチが離された状態
                        setOutput(8, '0');
                }
        }, 10);
} catch (e) {
        console.log(e);
        cleanUp();
}

process.on('SIGINT', function() {
        cleanUp();
        process.exit(0);
});

process.on('end', function() {
        cleanUp();
        process.exit(0);
});
コード解説

GPIOの操作について、基本的な内容を簡潔に書くと以下のとおりです。

  • /sys/class/gpio/export にGPIOの番号を書き込むと、その番号のGPIOが使用可能になる。
  • /sys/class/gpio/unexport にGPIOの番号を書き込むと、その番号のGPIOが使用不可能になる。
  • /sys/class/gpio/gpioX/direction (XはGPIO番号)に、
    • 「in」と書き込むと入力としてGPIOが機能する。
    • 「out」と書き込むと出力としてGPIOが機能する。
  • /sys/class/gpio/gpioX/value (XはGPIO番号)の内容が、
    • 「0」である場合は電流が流れていない。(正確には電位が低い)
    • 「1」である場合は電流が流れている。(正確には電位が高い)

Node.js では、ファイルの読み書きは「fs」モジュールを扱う。
読み込みは「readFileSync(ファイル名)」関数を使用し、
書き込みは「writeFileSync(ファイル名, 書き込み内容)」関数を使用する。

注意点は、GPIOの使用後は必ず使用したGPIOを使用不可能状態に戻すことです。
開放したままそのGPIOを使用可能に設定しようとすると、エラーが発生してしまいます。

LED点灯の主要部分は、setInterval内の記述です。
スイッチが押された状態ではGPIO 7の電位が高くなるので、
0.01秒間隔でGPIO 7の状態を確認し電位が高ければ、
GPIO 8から電流が流れるようにしています。
スイッチを離された状態は、その逆に設定すれば良いだけです。

後書き

スイッチの状態を判断する処理をsetIntervalではなく、
できれば Node.js っぽくイベントを拾って行いたかったのですがうまくいきませんでした。
「fs.watch」関数でファイル変更イベントが拾えませんでした。

いろいろ調べていたら「Node.jsでRaspberryPiのGPIOを良しなにする方法」という記事を見つけました。
どうやら方法はあるみたいです。
時間ができたらそちらを学習してみようかな。

Node.js のプロセス処理を少し学ぶ

IoT をする前に Node.js のプロセス処理について
簡単に学習することにした。

概要

プログラム開始後にキー入力待機状態にし、
入力ごとに以下のように処理を実行させる。
* 「end」と入力するとプログラムを終了する。
* それ以外の場合、「Input: XXXXX」(XXXXX は入力値)と表示する。

<参考文献>

プログラムの内容

ソースコード
// eventsPra.js

var fs = require('fs'); 

// キーの入力待ち状態にする。
process.stdin.resume();
process.stdin.setEncoding('utf8');

// 標準入力終了時のイベント処理
process.stdin.on('end', function() {
    console.log('END!!');
});

// 入力された1行を読み込んだ時のイベント処理
process.stdin.on('data', function(inputData) {
    // 末尾の改行を取り除く。
    var input = inputData.slice(0, -1);
    if (input == 'end') {
        // end が入力された場合、プロセスを終了する。
        process.exit(0);
    } else {
        console.log('Input: ' + input);
    }
});

// Ctrl + C が入力された場合のイベント処理
process.on('SIGINT', function() {
    console.log('Ctrl+C!!');
    // プロセスを終了する。
    process.exit(0);
});

// プロセス終了時のイベント処理
process.on('exit', function() {
    console.log('EXIT!!');
});
挙動確認

プログラムを実行してみる。

//入力
abc
end
//出力
Input: abc
EXIT!!

次に、プログラム実行中に「Ctrl+C」と入力すると、

^CCtrl+C!!
EXIT!!

と表示される。
また、プログラム実行中に「Ctrl+D」と入力すると、

END!!
EXIT!!

と表示される。

考察

標準入力からの入力待ちにするには、
process.stdin.resume() の呼び出しが必要です。
そして標準入力のイベント処理は、
「process.stdin.on(イベント名, コールバック関数)」で設定します。
キー入力はイベント名「data」で、
入力値はコールバック関数の第1引数に渡されるようです。
また、「Ctlr+C」と入力するとプロセスに「SIGINT」のシグナルが送られるので、
「Ctrl+C」の入力はこのイベントを拾うことで設定できます。
ただし、「SIGINT」のリスナの登録を行うとプログラム終了の処理が
働かなくなるので、明示的にプロセスを終了させる必要があります。

後書き

今回の内容を踏まえて、次回はLEDの点灯制御を行っていこうかと思います。

Raspberry Pi に Node.js をインストール

概要

先日設定した Raspberry Pi に Node.js をインストールしてみる。

環境

目次

  1. Node.js のインストール
    <参考文献>
  2. 動作確認

1. Node.js のインストール

公式サイトよりインストールする。
Node.js のバージョンを確認し、以下の通りにイントールを行う。

wget https://nodejs.org/dist/v4.7.1/node-v4.7.1-linux-armv7l.tar.gz
tar -xvf node-v4.7.1-linux-armv7l.tar.gz
sudo cp -R node-v4.7.1-linux-armv7l/* /usr/local/

バージョンの確認をする。

node -v

「v4.7.1」と表示され、インストールできたことを確認。

2. 動作確認

動作確認のために、標準出力とファイル書き込みを行うコードを作成。

// test.js

console.log('start!');

var fs = require('fs');

// test.txt ファイルに書き込みを行う。
fs.writeFileSync('test.txt', 'This is a test.');

console.log('end!');

作成したコードを実行する。

node test.js

コンソールに「start!」「end!」が表示される。
また、test.txt が作成され、「This is a test.」と書き込まれる。

後書き

特に問題なく Node.js の環境が整いました。
今後は Raspberry Pi と Node.js を使った IoT を行っていこうかなと思います。

Raspberry pi の初期設定(Arch linux)

概要

以前使用していた Raspberry pi を起動したところ、
起動途中で落ちて再起動…と繰り返して起動できなかった。
なので、初期から設定し直すことにした。

以前と同様に Raspbian をインストールしようとしたら、
何故か途中で異常終了してしまうので断念した。
Ubuntu や他のOSも試したのだが途中で異常が起こる。
SDカード相性が悪い分けてはなさそうなのだが何故なのか?
SDカードの相性

結局、Arch linux のインストールに行き着いた。

環境

  • SDカード設定用 Linuxマシン(4.8.2-1-ARCH)
  • SDカード(SanDisk Ultra PLUS microSDHC UHS-I カード 16G class10)
  • Raspberry Pi 2 Model B

目次

  1. SDカード設定
    <参考文献>
  2. 初期設定
    <参考文献>

1. SDカード設定

公式サイトの通りにSDカードに Arch linux のイメージファイルを書き込むだけである。

以下、SDカード設定用のLinuxマシン上で root ユーザになって作業を行う。

SDカードの確認
fdisk -l

SDカードのディスクが表示される(例:/dev/mmcblk0)ので、
公式サイトの「/dev/sdX」を表示されたディスクに読み替えて作業する。

パーティション
fdisk /dev/mmcblk0

fdisk のプロンプトが起動するので以下を行う。

  1. o 入力、p 入力
  2. n 入力、p 入力、1 入力
  3. 最初のセレクタは何も入力せずエンター押下
  4. 最後のセレクタは +100M と入力
  5. t 入力、c 入力
  6. n 入力、p 入力、2 入力
  7. 最初と最後の両セレクタとも何も入力せずエンター押下
  8. w 入力
SDカードの再確認
fdisk -l

パーティションされたデバイスが表示される。(例: /dev/mmcblk0p1, /dev/mmcblk0p2)
公式サイトの「/dev/sdX1」「/dev/sdX2」を表示されたデバイスに読み替える。

フォーマット
mkfs.vfat /dev/mmcblk0p1
mkdir boot
mount /dev/mmcblk0p1 boot
mkfs.ext4 /dev/mmcblk0p2
mkdir root
mount /dev/mmcblk0p2 root
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-2-latest.tar.gz
bsdtar -xpf ArchLinuxARM-rpi-2-latest.tar.gz -C root
sync
mv root/boot/* boot
umount boot root

LinuxマシンからSDカードを抜いて、
Raspberry Pi に挿して起動すれば立ち上がる。
初期状態では、root ユーザのパスワードは root になっている。

2. 初期設定

初期設定の参考サイトはたくさんあるので、
適宜必要な設定を参照すればよい。

キーボード設定
loadkeys jp106
echo "KEYMAP=jp106" > /etc/vconsole.conf
ローカル設定
vi /dev/locale.gen

en_US.UTF-8 UTF-8、ja_JP.UTF-8 UTF-8コメントアウトを外す。

locale-gen
echo "LANG=en_US.UTF-8" > /etc/locale.conf
export "LANG=en_US.UTF-8"
時刻設定
unlink /etc/localtime
ln -s /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
ホスト名設定
hostnamectl set-hostname XXXXXX

XXXXXX に自身のホスト名を入力。

有線LAN設定

DHCPを利用するので設定はデフォルトのまま。
IPv6の無効化だけしておく。

vi /etc/sysctl.d/40-ipv6.conf

# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.all.disable_ipv6 = 1
ミラーサーバ設定
vi /etc/pacman.d/mirrorlist

台湾、シンガポールの Server をファイル先頭にコピーし、
コメントアウトしておく。 アップデートして、リブートする。

pacman -Syu
reboot
sudo設定
pacman -S sudo

インストール後、wheelグループの権限を設定する。

visudo

「%wheel ALL=(ALL) ALL」のコメントアウトを外す。

ユーザ作成
useradd -m -g wheel XXXX
passwd XXXX

XXXX にユーザ名を入力する。

後書き

無線LAN設定をして置きたかったのだが、
設定すると Raspberry Pi の再起動時に異常終了する。
いくつか設定を試したがいずれも原因不明の異常終了が発生した。
(無線アダプターの相性とかあるのか?)
有線LANが繋がるのでとりあえずよしとする。

開始

ブログ開始

2017年が始まりました。 今年の目標は何にしようとあれやこれや思い巡らしていましたが、特に思い浮かぶことはなくブログでも始めて見るかと安易な発想に終着しました。

書く記事の内容をどうするかというのが当面の目標ですが、おそらくプログラミング関連の内容が多くなるでしょう。

四苦八苦しつつ頑張っていこうと思います。
今年も宜しくお願いします。