Raspberry Pi & 10個の言語でLチカやってみた
はじめに
テントの中から失礼します、CX事業本部のてんとタカハシです!
前回の記事(Rust & Raspberry Pi で温度センサーの値を AWS IoT Core に Pub してみた)を書く際に、Rust を使ってLチカを試したのですが、何だか色んな言語で Raspberry Pi を操作したい欲求に駆られてしまい、こんな素敵な記事を書いてみました。
Raspberry Pi を使った電子工作では、セットアップ不要 かつ ドキュメント豊富な Python がよく使われると思いますが、Python の経験が無い方にとっては、少々ハードルを感じてしまうかもしれません。しかし、この記事を見ればもう大丈夫。だって10個の言語でLチカを試したんだから。読者の方々が触れたことある言語、きっと1つはあるはず。皆様、是非是非安心して、電子工作の第一歩、Lチカを試して楽しんで頂ければなと思います。
各言語のプログラムは下記に置いてありますので、Lチカを試す際はリポジトリをローカルに落として、これから記載する手順に従って実行してみてください。
GitHub - iam326/l-tika-10-languages
今回Lチカで使用する言語の一覧
- Python
- Node.js
- C言語
- Golang
- Rust
- Shell Script
- Java
- PHP
- Ruby
- Perl
Raspberry Pi の環境
Raspberry Pi OS のバージョンは下記の通りです。
$ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 10 (buster) Release: 10 Codename: buster
Raspberry Pi 自体のモデルは、「Raspberry Pi 2 Model B」を使用して記事を書いていますが、今回使用する Pin の配置は、Raspberry Pi 3 or 4 系 と同じになります。
配線
下記の通りの配線してください。
プログラムの流れ
全ての言語共通でプログラムの流れは下記の通りになります。
- LED と接続している GPIO23(物理ピン番号16)を出力モードに設定する
- 無限ループで1秒おきに LED の ON/OFF を切り替えて、チカチカさせる
- Ctrl + C で無限ループを抜ける
- プログラムを終了する
また、プログラムが終了した後も LED が ON になり続ける状態を回避するため、必要に応じて後処理を行います。言語(というより使用するライブラリ)によっては、プログラムの終了と同時に LED を自動 OFF してくれるものもあります。
実装見ていくぞー
Python
定番の Python からやっていきます。こちらはセットアップ不要で動いちゃいます。
import RPi.GPIO as GPIO from time import sleep LED_PIN = 23 GPIO.setmode(GPIO.BCM) GPIO.setup(LED_PIN, GPIO.OUT) try: while True: GPIO.output(LED_PIN, GPIO.HIGH) sleep(1.0) GPIO.output(LED_PIN, GPIO.LOW) sleep(1.0) except KeyboardInterrupt: GPIO.cleanup()
下記の手順でプログラムを実行します。
$ cd python/ $ python3 main.py
使用しているライブラリのドキュメントはこちら。SourceForge - raspberry-gpio-python
Raspberry Pi の公式ドキュメントでは、GPIO Zero
というライブラリを使ったLチカのプログラムが紹介されています。 raspberrypi.org - GPIO in Python
GPIO Zero
知らなかった、今度使って遊んでみようと思います。
Node.js
次は Node.js でやっていきます。Node.js で Raspberry Pi を操作している記事もよく見かける気がしています。
const Gpio = require('onoff').Gpio; const LED_PIN = new Gpio(23, 'out'); process.on('SIGINT', () => { LED_PIN.unexport(); process.exit(); }); setInterval(() => { LED_PIN.writeSync(LED_PIN.readSync() === 0 ? 1 : 0); }, 1000);
npm trends を見て、一番人気がありそうな onoff というライブラリを使用しました。
下記の手順でセットアップ & プログラムを実行します。
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash - $ sudo apt-get install -y nodejs $ node --version v14.6.0 $ npm --version 6.14.6 $ cd nodejs/ $ npm install $ node main.js
C言語
組み込みといえばC言語。こちらはセットアップ不要で動いちゃいます。
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <wiringPi.h> #define LED_PIN 4 int end = 0; void abort_handler(int signal); int main(void) { wiringPiSetup(); pinMode(LED_PIN, OUTPUT); if (signal(SIGINT, abort_handler) == SIG_ERR) { exit(1); } while (!end) { digitalWrite(LED_PIN, HIGH); delay(1000); digitalWrite(LED_PIN, LOW); delay(1000); } return 0; } void abort_handler(int signal) { end = 1; }
WiringPi というライブラリを使用しています。
下記の手順でプログラムを実行します。
$ cd c/ $ gcc -Wall -o main main.c -lwiringPi $ ./main
Golang
C言語と構文が似てる感じの Golang。
package main import ( "time" "gobot.io/x/gobot" "gobot.io/x/gobot/drivers/gpio" "gobot.io/x/gobot/platforms/raspi" ) func main() { r := raspi.NewAdaptor() led := gpio.NewLedDriver(r, "16") work := func() { gobot.Every(1 * time.Second, func() { led.Toggle() }) } robot := gobot.NewRobot("ltika", []gobot.Connection{r}, []gobot.Device{led}, work, ) robot.Start() }
GoBot というロボティックス・IoT向けのフレームワークを使用しています。ドキュメントに書いてあるプログラムそのままで動作しました。ちょっとこのGoBot
面白そうなので、何かの機会で試してみたいなという気持ちになっています。
下記の手順でセットアップ & プログラムを実行します。
$ wget https://golang.org/dl/go1.14.6.linux-armv6l.tar.gz $ sudo tar -C /usr/local -xzf go1.14.6.linux-armv6l.tar.gz $ echo export 'PATH=$PATH:/usr/local/go/bin' >> ~/.profile $ source ~/.profile $ go version go version go1.14.6 linux/arm $ cd golang/ $ go build main.go $ ./main
Rust
この記事を書くきっかけとなった Rust。
use std::error::Error; use std::thread; use std::time::Duration; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use ctrlc; use rppal::gpio::Gpio; const GPIO_LED: u8 = 23; fn main() -> Result<(), Box<dyn Error>> { let mut pin = Gpio::new()?.get(GPIO_LED)?.into_output(); pin.set_reset_on_drop(true); let running = Arc::new(AtomicBool::new(true)); let r = running.clone(); ctrlc::set_handler(move || { r.store(false, Ordering::SeqCst); }).expect("Error setting Ctrl-C handler"); while running.load(Ordering::SeqCst) { pin.set_high(); thread::sleep(Duration::from_millis(1000)); pin.set_low(); thread::sleep(Duration::from_millis(1000)); } Ok(()) }
rppal というクレートを使用しています。
下記の手順でセットアップ & プログラムを実行します。
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh $ source ~/.profile $ cargo --version cargo 1.45.0 (744bd1fbb 2020-06-15) $ cd rust/ltika/ $ cargo run
Ctrl + C らへんの処理はドキュメントのまま書いて動いたのですが、何やってるかはよく分かりませんでした。勉強不足です勉強します。
Shell Script
Shell Script で手軽に Raspberry Pi を制御したいっていうケースはよくありそう。こちらはセットアップ不要で動いちゃいます。
#!/bin/bash set -euo pipefail LED_PIN=23 gpio export $LED_PIN out trap 'gpio unexport $LED_PIN' SIGINT while true do gpio -g write $LED_PIN 1 sleep 1 gpio -g write $LED_PIN 0 sleep 1 done
これも WiringPi を使用しています。gpio
コマンドを使って制御していますね。
下記の手順でプログラムを実行します。
$ cd sh/ $ ./main.sh
Java
調べてみたのですが、Java って組み込みでもよく使われるんですね。
import com.pi4j.io.gpio.GpioController; import com.pi4j.io.gpio.GpioFactory; import com.pi4j.io.gpio.GpioPinDigitalOutput; import com.pi4j.io.gpio.PinState; import com.pi4j.io.gpio.RaspiPin; public class Ltika { public static void main(String[] args) throws InterruptedException { final GpioController gpio = GpioFactory.getInstance(); final GpioPinDigitalOutput pin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_04, "LED", PinState.LOW); pin.setShutdownOptions(true, PinState.LOW); Runtime.getRuntime().addShutdownHook(new Thread( () -> gpio.shutdown() )); while (true) { pin.toggle(); Thread.sleep(1000); } } }
Pi4J というライブラリを使用しています。
下記の手順でセットアップ & プログラムを実行します。
$ sudo apt install default-jdk $ java --version openjdk 11.0.7 2020-04-14 OpenJDK Runtime Environment (build 11.0.7+10-post-Raspbian-3deb10u1) OpenJDK Server VM (build 11.0.7+10-post-Raspbian-3deb10u1, mixed mode) $ curl -sSL https://pi4j.com/install | sudo bash $ cd java/ $ javac -classpath .:classes:/opt/pi4j/lib/'*' -d . Ltika.java $ java -classpath .:classes:/opt/pi4j/lib/'*' Ltika
PHP
PHP でも Raspberry Pi 操作できるよってのは、電子工作のハードルをかなり下げてくれそうなお話。
<?php require_once "vendor/autoload.php"; use PiPHP\GPIO\GPIO; use PiPHP\GPIO\Pin\PinInterface; declare(ticks = 1); pcntl_signal(SIGINT, "signal_handler"); $end = false; $gpio = new GPIO(); $led_pin = $gpio->getOutputPin(23); while (!$end) { $led_pin->setValue(PinInterface::VALUE_HIGH); sleep(1); $led_pin->setValue(PinInterface::VALUE_LOW); sleep(1); } $led_pin->unexport(); function signal_handler($signal) { global $end; switch($signal) { case SIGINT: $end = true; break; default: break; } } ?>
PiPHP/GPIO というライブラリを使用しています。
下記の手順でセットアップ & プログラムを実行します。
$ sudo apt-get install php $ php --version PHP 7.3.19-1~deb10u1 (cli) (built: Jul 5 2020 06:46:45) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.19, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.19-1~deb10u1, Copyright (c) 1999-2018, by Zend Technologies $ curl -sS https://getcomposer.org/installer | php $ sudo mv composer.phar /usr/local/bin/composer $ composer --version Composer version 1.10.9 2020-07-16 12:57:00 $ cd php/ $ composer install $ sudo php main.php
PHP でLチカのやりかたを検索すると、Webページから LED の ON/OFF を制御するみたいな記事が結構出てきます。かなり面白そうなので、これもその内試してみたいなと思いました。
Ruby
Ruby でもやっていきますー。
require 'bundler/setup' require 'pi_piper' led_pin = PiPiper::Pin.new :pin => 23, :direction => :out begin loop do led_pin.on sleep 1 led_pin.off sleep 1 end rescue Interrupt PiPiper::Platform.driver.unexport_pin(23) end
pi_piper というライブラリを使用しています。
下記の手順でセットアップ & プログラムを実行します。
$ sudo apt-get install ruby $ ruby --version ruby 2.5.5p157 (2019-03-15 revision 67260) [arm-linux-gnueabihf] $ sudo apt-get install ruby2.5-dev libssl-dev $ sudo gem install bundler $ gem --version 2.7.6.2 $ bundler -v Bundler version 2.1.4 $ cd ruby/ $ bundle install $ sudo ruby main.rb
Perl
Perl は人生で初めて触りました。cpan
の使い方がよく分からず結構ハマりました。
#! /usr/bin/perl use strict; use warnings; use RPi::WiringPi; use RPi::Const qw(:all); my $end = 0; my $pi = RPi::WiringPi->new; my $led_pin = $pi->pin(23); $led_pin->mode(OUTPUT); sub sigint_handler { $end = 1; } $SIG{'INT'} = 'sigint_handler'; while (!$end) { $led_pin->write(OFF); sleep(1); $led_pin->write(ON); sleep(1); } $pi->cleanup();
これまた WiringPi ですね。
下記の手順でセットアップ & プログラムを実行します。
$ cpan cpan[1]> install RPi::WiringPi cpan[2]> install RPi::Const cpan[3]> exit $ cd perl/ $ perl main.pl
おわりに
今回は、Raspberry Pi & 10個の言語を使ってLチカを試してみましたが、いかがだったでしょうか。個人的には色々なバリエーションを経験することができて、とても楽しかったです。需要があるのか分かりませんが、他の言語を使った第二弾もやりてえなああ〜とか思ったりしています(触ったことないけど Elixir
とか?)。
前の記事でもご紹介しましたが、もっと Raspberry Pi を使った電子工作にチャレンジしてみたいと思った方には、ブルーバックス出版の Raspberry Piで学ぶ電子工作 作る、動かす、しくみがわかる! がオススメです。こちらの本では Python を使って、様々なセンサーを動かしながら、電子工作の基礎を学ぶことができますよ。
では、今回は以上になります。最後まで読んで頂きありがとうございました!