FatherScorpion's diary

年1更新!...できたらいいなぁ。

ラズパイ起動時にIPアドレスを自動表示させてみる話

はじめに

この記事は東京高専プロコンゼミAdventCalendar② 14日目の記事です。

adventar.org ①もあります。

adventar.org

ラズベリーパイ初心者向けの記事になります。筆者自身も初心者ですので強い人は鼻で笑いながら見て下さい。 暫くは前座が続きますので、記事の本題だけを見たいという方は「IPアドレスゲッターを作ろう」、またはその少し前まで読み飛ばして下さい。

ラズベリーパイって楽しいね

皆さんはRaspberryPi(ラズベリーパイ/ラズパイ)をご存じでしょうか?言わずと知れた小型コンピュータですね。組み込み開発や最近はやりのIoTなんかではよく使われていると思います。最近弊校では組み込みマイスターが行われている事もあり、自分の周りでもラズパイを使っている人を良く見るようになりました。

SSH使ってる?

ところで、皆さんはラズベリーパイをどのように操作しているでしょうか。電源ケーブルを繋いで、キーボードを繋いで、マウスを繋いで、ディスプレイを繋いで...なんて事をしている方も多いかと思います。ラズパイを初めて触った時には、ほとんどの人がこんな感じの事をいちいち準備していると思います。正直、めんどくさいですよね。自分自身もこれがめんどくさくて一時期ラズパイに全く触れなくなった時期もありました。 しかし、周りの強い人達がラズパイを使っているのを見ると、ラズパイ本体に電源コードくらいは刺さっているかもしれませんが、別のノートパソコンかなんかで作業をしていたりしませんか?詳しい説明は省きますが、これはラズパイにノートパソコンからSSH接続というものを行っていて、ラズパイを遠隔操作できるようにしています。これ、実際にやってみると痛感しますがめっちゃ楽です。今まではラズパイのちっちゃい本体に無数のコードを接続して、片付けて、とやっていたのが、「はい、電源コードさしまーす。」「はいノートパソコンでソフト開きまーす。」「はい使えるようになりましたー。」で終わってしまうので作業効率が格段にアップします。片付けも電源を落とすだけですむのでとっても簡単。ぜひまだSSH接続をしてないよーという方は今からでも是非お試しください。

でも、面倒なんでしょう?

しかし、こう思う人もいると思います。「でも、そのSSH接続ってやつをやるためにまた面倒な事をしなければいけないんでしょ?」、と。確かに、「ラズベリーパイ SSH接続」で検索をしてみると、やれ環境変数だの、やれnanoだのvimだの、頭が痛くなるような単語が続きます。実際自分自身、先輩からSSH接続の事を教えて頂いた後に上記のような手段でSSH接続を試み、1カ月近く格闘した末諦めました。このように、成程普通にやればSSH接続とは何とも難しそうです。普通にやれば

そこで登場TeraTerm

TeraTermって何だよ!という話ですが、ようするにSSH接続用のソフトウェアです。使い方は簡単、ソフトを起動して、ラズパイのIPアドレスを打ち込むだけ。予めラズパイ側で少し設定しておくべきこともありますが、インストール時間を含めなければ5分もかかりません。詳しい使い方はネットで調べれば出てくるのでそちらを参照してください。設定のためにラズパイにモニターやらなんやらを繋ぐ必要はありますが、これさえ終わればようやく快適なラズパイライフを送れそうです。

ねえ待ってよ!やっぱりモニター必要だよ!

はい、もう感付いている方もいるかもしれませんが、これでもまだモニターやマウス、キーボードと無縁な生活を送る事はできません。非常に便利なTeraTermですが、こいつを使うには何が必要でしたか?そうですね、IPアドレスです。さて、TeraTermにはIPアドレスの自動補完機能があるので、最後に打ち込んだIPアドレスは覚えておく必要はありません。ですが、最後に使ったIPアドレス以外のIPアドレスを打ち込まなければならない機会もありますね?例えば、

  1. 新しいネットワークに繋いだ時。

  2. 前に繋いだことがある別のネットワークに繋いだ時。

  3. 定期的にIPアドレスが変わる現象が発生した時。

こんな時です。こんな時には、IPアドレスを知るためにやっぱりモニター等を繋ぐ必要が出てきてしまいますね。 ですが、ですがですよ。1番は仕方ないとしても、2番3番の為に面倒な事をするのは癪なわけですよ。だってラズパイは一度繋いだネットワークには起動時に自動で繋いでくれるのに、そこでわざわざ人間が手間を掛けなければならないとは納得できません。しかも1カ月に1度とかならまだしも、自分のように学校や家など一日に幾つものネットワークにラズパイを接続する身としては結局SSH接続の利点が殆ど消え去ってしまい非常に不服です。パソコン上から同一ネットワークに繋がれている機器のIPアドレスを取得するコマンドを打つという手もありますが、これも何か嫌です。メモを取れば良い?嫌です。 あーあ、こんな時にラズベリーパイのIPアドレスを起動時に自動で表示してくれる何かがあれば便利なのになぁなんて思ってしまいます。皆さんもそう思いますよね? でもそんな限られた用途の物なんてありません。一体どうすれば...。そうだ、無ければ自分で作れば良いのです!

IPアドレスゲッターを作ろう

ここからが本題です。今私の手元には7シグメントLED、つまり数字を表すのに使う全部点灯すると8になる例のアレがあります。こいつをうまく使ってラズパイ起動時にIPアドレスが表示される装置を作ろうと思います。 まずはPhythonでコードを書きます。以下にコードを書きますが、まずはどんな事をしているのかを予め書いておきます。詳細な説明はしませんのでニュアンスで理解して下さい。

① Phythonのターミナルコマンドを打った結果を取得する関数を使い、IPアドレスが含まれた文字列を取得する。

Phython以外にもあるのかもしれませんが、プログラム上でターミナルコマンドを使えるのだなと地味に感動しました。打っているコマンド自体は「ip a show wlan0」で、よくIPアドレスを確認するのに使うコマンドの範囲限定版ですね。ただ、これだけだとIPアドレス以外の文字列も含まれているので、

② 先ほど取得した文字列の中からIPアドレスを抽出する。

文字列操作でIPアドレスだけを取り出して行きます。後は単純に

③ 1秒間隔ぐらいでIPアドレスの数字を順番に表示する。

どうでもいいですが7シグメントLEDって小数点も表現できるんですよね。実はそれを知ったからこそこれを作ろうと思ったまであります。IPアドレスにも小数点(ドット)は含まれてますからね。 また、今回は見逃し防止の為にIPアドレスを2周回すと共に、これが最初だよという事を示す横棒(-)を各周の最初に2秒表示させる事にします。それと、ラズパイの起動直後にはまだインターネットに接続できていないので、10秒プログラムの最初にディレイを挟んでいます。デバッグ用にCtrl+Cで強制終了できるようにもしています。 では以下がコードです。

# -*- coding: utf-8 -*-
import subprocess
import RPi.GPIO as GPIO
import time
time.sleep(10)
cmd = subprocess.check_output(["ip", "a", "show", "wlan0"])

hoge = cmd.find("inet ")
IP = cmd[hoge+5:]
IP = IP[:IP.find("/")]
print(IP)

GPIO.setmode(GPIO.BCM)

GPIO.setup(14,GPIO.OUT)
GPIO.output(14,GPIO.HIGH)
#左下

GPIO.setup(15,GPIO.OUT)
GPIO.output(15,GPIO.HIGH)
#下

GPIO.setup(18,GPIO.OUT)
GPIO.output(18,GPIO.HIGH)
#右下

GPIO.setup(23,GPIO.OUT)
GPIO.output(23,GPIO.HIGH)
#小数点

GPIO.setup(24,GPIO.OUT)
GPIO.output(24,GPIO.HIGH)
#右上

GPIO.setup(25,GPIO.OUT)
GPIO.output(25,GPIO.HIGH)
#上

GPIO.setup(8,GPIO.OUT)
GPIO.output(8,GPIO.HIGH)
#左上

GPIO.setup(7,GPIO.OUT)
GPIO.output(7,GPIO.HIGH)
#中央

allGPIO = {14, 15, 18, 23, 24, 25, 8, 7}

try:
    for x in range(2):
        for a in allGPIO:
            GPIO.output(a,GPIO.HIGH)
        GPIO.output(7,GPIO.LOW) #最初である事を示す'-'
        time.sleep(2)

        for y in range(len(IP)):
            for b in allGPIO:
                GPIO.output(b,GPIO.HIGH)

            n = IP[y]
            print(n)
            if n == ".":
                GPIO.output(23,GPIO.LOW)
            if n == "0":
                GPIO.output(14,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(25,GPIO.LOW)
                GPIO.output(8,GPIO.LOW)
            if n == "1":
                GPIO.output(18,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
            if n == "2":
                GPIO.output(25,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
                GPIO.output(14,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
            if n == "3":
                GPIO.output(15,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(25,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
            if n == "4":
                GPIO.output(8,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
            if n == "5":
                GPIO.output(25,GPIO.LOW)
                GPIO.output(8,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
            if n == "6":
                GPIO.output(25,GPIO.LOW)
                GPIO.output(8,GPIO.LOW)
                GPIO.output(14,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
            if n == "7":
                GPIO.output(8,GPIO.LOW)
                GPIO.output(25,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
            if n == "8":
                GPIO.output(14,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(25,GPIO.LOW)
                GPIO.output(8,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
            if n == "9":
                GPIO.output(8,GPIO.LOW)
                GPIO.output(25,GPIO.LOW)
                GPIO.output(24,GPIO.LOW)
                GPIO.output(7,GPIO.LOW)
                GPIO.output(18,GPIO.LOW)
                GPIO.output(15,GPIO.LOW)
            time.sleep(1)

except KeyboardInterrupt:
        print("おしまい!")
        GPIO.cleanup()

GPIO.cleanup()

7シグメントLEDとの接続ですが、以下の様になっています。ちなみに共通アノードのやつです。なんだよそれ、という方は調べてみて下さい。多分一瞬で理解できると思います。

14 左下
15 下
18 右下
23 小数点
24 右上
25 上
8  左上
7  中央

左の番号はラズパイのピン番号で、BCM番号です。右側は位置を表しています。左下とか中央とかは何を表しているかというと、小数点を右下に置いた時に、例えば1を点ける時には右上と右下が点くようなイメージです。横棒だと中央だけですね。

さて、最後に起動時にプログラムを実行する方法ですが、全て下記のサイト様を参考にさせて頂きました。そちらを読んで頂ければ簡単に終わると思います。

qiita.com

いざ実戦。

結果は以下の動画を見て下さい。分かりやすいように起動時のディレイを0にして普通のデバッグ時に撮影しています。起動してからの動画も取りはしましたが絵面が地味すぎたので没にしました。ちなみにちゃんと動きますのでご安心を。

ちゃんと動く...?

おっと、何やら動作がおかしいですね...?変な表示だったり、画面上の数字と点灯した数字が合わなかったりしていますね。 実はこれ、左下のLEDが焼き切れています。電子工作初心者故に抵抗を忘れて接続した所一瞬だけ赤色の閃光が走った後に沈黙しました。ちなみに動画では100Ωの抵抗を使っているのでとても眩しいです。1kΩぐらいだとちょうど良くなりました。 本当は新しいLEDを発注していたのですが、記事執筆現在到着していないため壊れたLEDを使用する事になりました。

兎にも角にもこれで記事はお仕舞です。皆さんも電子工作をする際には十分気を付けて下さいね。