t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

GitHubの代替手段、GitBucketをラズパイ3b+に導入して秘匿したいコードを宅サバで管理

GitHubは素晴らしい。
MSが買収して以来Privateリポジトリも無償で使える。

しかしそれでもセキュリティに関するコードや設定ファイル類をネットに公開するには一抹の不安が残る。
いくらPrivateとはいえ、少なくともマイクロソフトがその気になれば、あるいはうっかり流出させるなんてことも無いとは言い切れないのだ。

ということで自宅ネットワーク内にサーバーを建てられないか色々調べていたらGitBucketというツールが良さげだったので導入することにした。普通のgitリモートリポジトリでも良いんだけどGitHubの便利さに慣れてしまうとどうしてもWebUIが欲しくなる。GitLabも自宅サーバーへ導入できるらしいんだけど設定が複雑かつラズパイだと4じゃないとダメみたいなので、2でも3でも導入できそうなGitBucketを選択した。

GitBucketとは

Scala言語で記述されたGit Web プラットフォーム。
gitbucket.github.io

warファイルをダウンロードしてjava vmで動かすだけなのでかなり手軽に導入できる。

導入方法

以下のコマンドを順次実行していく。

#パッケージ一覧を更新しJava8の実行環境をインストール。
sudo apt update
sudo apt install openjdk-8-jre

#実行ユーザーの準備
sudo useradd gitbucket
sudo mkdir /home/gitbucket
sudo chown gitbucket:gitbucket /home/gitbucket

#ダウンロード (記事執筆時点の最新版URLで実行した)
cd /home/gitbucket
sudo wget -O gitbucket.war https://github.com/gitbucket/gitbucket/releases/download/4.38.4/gitbucket.war

#ユーザーを切り替えてテスト実行
sudo su gitbucket
java -jar /home/gitbucket/gitbucket.war --gitbucket.home=/home/gitbucket/

実行してしばらくするとhttp://サーバーip:8080ポートで接続できるようになる。
URL例) http://192.168.1.182:8080/
初期ユーザーはrootでパスワードもroot。
危険なのでAdministratorタイプのユーザーを別で作ったあとはrootを無効化しておこう。
新規ユーザーにAdministratorタイプを指定し忘れてrootを消してしまうと詰むので注意。
その他基本的な使い方は後述。

テスト実行はCtrl+Cで終了させ、次回から自動起動するようにDaemon化する。

以下のように別ポートも指定できる。ただしLinuxセキュリティによって80番での起動はroot権限が必要となっており、ハマリどころなのでおススメしない。

java -jar /home/gitbucket/gitbucket.war --port=3000 --gitbucket.home=/home/gitbucket/

※80番ポートでアクセスしたい場合、後述のiptablesによるNAT機能で80番を8080に転送する方法がおススメ。

Daemon化

# 好きなエディタでサービス用の設定ファイルを作成
sudo vi /etc/systemd/system/gitbucket.service

gitbucket.serviceは新規ファイルの為、以下を記述して保存

[Unit]
Description=GitBucket daemon

[Service]
ExecStart=/bin/su - gitbucket -c "java -jar /home/gitbucket/gitbucket.war --gitbucket.home=/home/gitbucket/"
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target

書き終わったら起動する。

#サービスファイル読み込み、有効化、起動。
sudo systemctl daemon-reload
sudo systemctl enable gitbucket
systemctl start gitbucket

以上でとりあえず、サーバー再起動してもhttp://サーバーip:8080/でアクセスできるようになる。

その他の手段としてはtomcat等を使って稼働させるのが良いんだろうけどデプロイは出来てもうまく稼働してこず、私はtomcatでの使用は諦めた。

80番ポートアクセス

Linuxのセキュリティでアプリを80番ポートで起動するにはroot権限が必要となる。しかしなんでもできるrootアカウントなんかで起動するのはセキュリティ的に良くない。
80番ポートそのものは有効なのでiptablesコマンドで80番ポートにきた通信を8080番ポートにリダイレクトすればhttp://サーバーip/でアクセスできた。

#リダイレクト指定
sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080

iptablesはシステムアップデートで影響を受けやすく、アップデート後にサーバーがリブートされていないとエラーが出る場合があるため、エラーが出るときはサーバーのリブート後に再度試してみる。こんなことで小一時間ハマったので要注意。

これでhttp://サーバーip/でアクセスできることを確認する。

次にiptables設定は再起動するとリセットされるので、そうならないようにするパッケージを導入。

#
sudo apt install iptables-persistent
#インストール中に、「保存しますか」的なことを英語で聞かれるので全部Yesで良い。


80番ポートを利用する他の手段としてはcapabilitiesという機能を使って部分的にrootの権能を譲り受けるという手段が用意されているのだが、私はこれで3時間くらいハマった挙句失敗に終わった。
Java仮想マシンにcapabilitiesで権限を与えてみたらポートは利用できたたんだけど別のことが出来なくなったようで、アプリが起動しなくなった。
元に戻すべく色々試したけど結局できなくてOS再インストールする羽目になったので知識がない場合はおススメしない。

後はサーバーリブート後にhttp://サーバーip/でアクセス出来たら導入完了。

使い方

ユーザー作成

まずは右上でサインイン。初期ユーザーはroot、パスワードもroot。

次に以下のように辿ってユーザーを作成する。

このとき、最初に作るユーザーのUser Typeは必ずAdministratorを選択する。
そうしないと脆弱な初期ユーザーであるrootを無効化できない。(すると詰む)

作成できたら右上アイコンからサインアウトし、作ったユーザーで入り直す。
同様にUser Managementからrootをeditしてdisableしておく。

リポジトリ作成

右上のプラスボタンからNew Repositoryで作成できる。
私は作成方法として「Initialize this repository with an empty commit」を選択して作成している。

あとはここでURLをコピーして、ローカルでcloneするだけ。

Pull Request方法

例えばローカルでdevブランチを切って、git push origin devでリモートのdevブランチを更新すると、リポジトリのbranchesメニューから開いた画面でPull Requestを作成できる。

その後のマージ等は大体GitHubと似たような感じ。

画面構成が違うので最初は戸惑うが、基本的に今触ってるページに関連するナビゲーションが左のメニューとして表示されると考えておけばOK。

参考サイト

インストール
qiita.com

Daemon化
blog.k-san.info

iptablesの設定
serverfault.com

iptablesの設定永続化
akira-arets.blogspot.com

※使い方に関してはGitHubに類似しているので特段参考サイト無し。
GitHubについては

今後の計画

ラズパイのストレージが劣化してソースコードが消失する未来を避けたいので、ストレージをRAID1でミラーリングしたい。
どうやらUSBメモリスティックを2本差してRAID化されている事例があるようなので、そちらを参考に色々と試してみたいと思う。

追記

USBメモリRAID計画は失敗に終わった。
1度目は成功したが、再起動後にRAIDをマウントできなかった。
色々と調査を進めたけど実力不足から時期尚早と感じたので大人しくSDカードで使おうと思う。

絶対に起きられる目覚まし時計 運用編 複数の警告音(ウーー・プワーンプワーン・ビーッビーッ・カンカンカン)を合成してみた

今回はこちらの記事の続き
thom.hateblo.jp

起きる時間を超えた時に空襲警報ばりの音を鳴らしたいという要件で、それなりのものが出来たので動画取ってみた。(音量注意)
youtu.be

実際寝てみたけどさすが枕元。。かなりうるさくていい感じ。

元素材はOtoLogic様の「警告音」3種類と、効果音ラボ様の「半鐘」を組み合わせている。
otologic.jp
soundeffect-lab.info

Adobe Auditionでマルチトラックに突っ込んで、完成品をちょうどいいタイミングでカットしただけ。

ハードウェアのレイアウトはこんな感じ。

スピーカーはバファローの1000円のやつを養生テープで止めてるだけ。ダサイので3Dプリンタで何か固定具を作りたいけど面倒なのでまぁとりあえずこれで。

普段使ってるBoseのデスクトップスピーカーに比べるとさすがに1000円だなって音質・音量だけどまぁこれが単なる目覚まし時計であることを考えると豪華なほうか。

停止ボタンは相変わらずブレッドボードに挿したタクト。まぁ使えるからしばらくこれで良しとする。

あといつかやりたいことは。。赤いパトランプ回したり、赤照明で部屋を警告色に染めたり。。かな。
まぁ現時点ではただの妄想だけど。

以上

Raspberry Piで好きな音楽を目覚ましにする ~ 二度寝を楽しむための目覚まし時計

今回はラズパイを使った目覚まし時計を作ってみたのでご紹介。
sshでアクセスしてcronに登録するようなちょっと特殊な仕様なので市販品のようにボタンやつまみでセットするような機能はない。

構想自体は1年以上前にあって、その時はArduinoで作ろうとしてたんだけど色々面倒で放置していた。
thom.hateblo.jp

今回は仕様を変更して好きな音楽ファイルを目覚ましに使いたいので、最初はDFPlayer miniというArduino用のmp3モジュールを使うつもりだったんだけど最近DFPlayer miniはチップ違いのものが複数出回っていて公式ライブラリで動かない。画像と違うものが届くので何度か発注と返品を繰り返して諦めた。

次にラズパイZeroも検討したけどこちらは音楽出力用のジャックがなく、最近のラズパイOSでGPIOからの音楽出力がうまくいかないという記事を見たので断念。結局ラズパイ3B+に落ち着いた。

たかが目覚ましにラズパイ3B+ってのはかなりオーバースペックなんだけど、マイコンと違ってLinux機なのでOSの処理が優秀でかなりシンプルに作れる。時刻はNPTで勝手に合わせてくれるし音楽はaplay呼べば済むし目覚ましのトリガーもcronで済むのでマジで楽。

ハード構成

仮組みではあるが、次のような構成になっている。

ブレッドボードのまま使うつもりはないし停止スイッチが生タクトなのはもう少しなんとかする予定。
スヌーズスイッチだけはロフトベッドから届く位置に付けるので長いコードを繋いでいる。こんなに長くなくていいけどとりあえず仮で。
ラズパイはGPIO17がスヌーズ、GPIO18が停止である。
ボタンはラズパイの内蔵プルアップ抵抗を使うので抵抗器は不要となっている。

コード

アラーム用のコードを先に紹介するのが自然だけど、仕組みの説明上あえて停止ボタン用のコードを先に紹介する。

wokeup.py (停止ボタン用コード)

実はまだあまり作りこんでなくて、次のアラームを鳴らないようにする抑止機能しかない。音楽を止めるのはあくまでスヌーズ。
まぁこのへんはすぐ作りこみできそうなので割愛。出来てから書けばと言われそうだけど、熱が冷めないうちに記事書かないと運用始まったら多分モチベ落ちてるので何卒ご容赦を。

まずGPIOの18番をプルアップ設定し、コールバック関数を指定しておく。
ボタンが押される度にstamp.txtに現在時刻yyyymmddHHMMSSを上書き書き込みするという仕組み。
ただそれだけ。これを使ってどうやって停止になるのかはアラーム機能で説明。

"nohup python wokeup.py &"とコマンド実行しておけばssh抜けてもバックグラウンドで実行されるので、そんな感じで常駐させる想定。
手動でkillするときに他のpythonコードと区別したいのでsetproctitleでプロセスタイトルを付けている。

import setproctitle as sp
import RPi.GPIO as GPIO
import datetime
import time

BUTTON_PIN = 18
sp.setproctitle("wokeup")

def main():
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_PIN,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=callback, bouncetime=300)
    
    try:
        while(True):
            time.sleep(1)

    except KeyboardInterrupt:
        print("break")
        GPIO.cleanup()

def callback(channel):
    dt_now = datetime.datetime.now()
    f = open('/home/thom/stamp.txt', 'w')
    f.write(dt_now.strftime('%Y%m%d%H%M%S'))
    f.close()

if __name__ == "__main__":
    main()

alarm.py (アラーム & スヌーズ用コード)

これはcronで実行する想定のコード。つまり8時に起きたければ8時に起動させる。
スヌーズと言ってるけど実は7:00、7:30、8:00、8:15のように4回スヌーズタイミングがほしければそれぞれcron登録するというだけの代物。
市販の目覚ましは5分後にスヌーズとかあるけど、アレ嫌いなんだ。2度寝するなら5分じゃ物足りない。ギリギリまで寝てたいけどギリギリすぎると怖い。余裕をもって起こされた後、あと30分寝させて、さらにもう30分、うーん。。。まだいける、15分!て感じで起きたい人間なのでこういう仕様にした。

実行するとまずstamp.txtから時刻を取得し、現在時刻と比較する。
差が10,800秒以内、つまり3時間以内であればそのままプログラムを終了する。
つまり7:00、7:30、8:00、8:15と設定していても、7時の段階で停止ボタンが押されていれば以降3つのアラームはスキップされるという仕組み。
要するに停止というよりはコード内で指定した時間スキップする機能なので翌日のアラームは普通に鳴る。

過去3時間以内に停止ボタンが押されていなければaplayでwavファイルが繰り返し再生されるが、スヌーズを押すとプログラムが終了される。
スヌーズと言いつつもプログラム的に見れば停止ボタン。cronで次の指定時刻に起動されるので機能としてはスヌーズである。

初回起動時に前回アラームが鳴ってる可能性があるのでalarmおよびaplayをkillした後、自身がalarmを名乗る。(先に名乗ると自分もkillされる。)
ボタンでaplayとプログラムをkillするが、念のためatexitでプログラム終了時にもaplayをkill。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import atexit
import setproctitle as sp
from subprocess import Popen
import sys
import RPi.GPIO as GPIO
import time
from datetime import datetime


BUTTON_PIN = 17

def main():
    f = open('/home/thom/stamp.txt', 'r')
    data = f.read()
    mydate = datetime.strptime(data, '%Y%m%d%H%M%S')
    td = datetime.now() - mydate
    if td.total_seconds() < 10800:
        print("exit")
        sys.exit()

    global proc
    cmd = "sudo pkill alarm"
    proc = Popen(cmd.strip().split(" "))
    proc.wait()
    cmd = "sudo pkill aplay"
    proc = Popen(cmd.strip().split(" "))
    proc.wait()

    sp.setproctitle("alarm")
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(BUTTON_PIN,GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.add_event_detect(BUTTON_PIN, GPIO.FALLING, callback=callback, bouncetime=300)
    
    try:
        while(True):
            cmd = "aplay /home/thom/th06_05.wav"
            proc = Popen(cmd.strip().split(" "))
            proc.wait()

    except KeyboardInterrupt:
        print("break")
        GPIO.cleanup()

def callback(channel):
    global proc
    print("Close")
    proc.kill()
    sys.exit()

@atexit.register
def force_umplay():
    global proc
    try:
        proc.kill()
    except:
        print("No process running.")

if __name__ == "__main__":
    main()

今後の運用と改良

現状はGoogle Homeを目覚ましに使っているので、とりあえず並行運用してみて安定稼働できそうなら本番稼働させようと思う。
仮運用はとりあえずブレッドボードで。

今後の改良としては停止ボタンで音楽も止まるようにするのと、音楽ファイルのランダム再生機能の実装と、本当に起きなければいけない時間以降は音楽をマジのアラームに切り替える機能の実装がある。

マジで起きなければならない時間を1分でも超過した際には空襲警報ばりのヤバいやつを鳴らしたい。

現在時刻アナウンス機能も欲しいな。そうなるとボタン2ついるか。

LinuxなのでWeb UIでアラーム設定とかもできそう。
Arduinoでの製作を諦めたからにはせめてラズパイのポテンシャルをちゃんと活かしてよりスマートな目覚まし時計を目指していきたい。

以上

DNSサーバー自身のIPを間違ってDNS登録していてトラブった話

今回はただの失敗談。

以前、障害対応でDHCPサーバー 兼 DNSを復旧させたのだが、今回新たにサーバーを増やそうとしてログインを試みるもうまくいかない。
thom.hateblo.jp

パスワードはKeePassで管理してるから完璧なはずなのに。。なぜ。

パスワードリセットすべく以下のサイト等を参考に色々試してみたが、もともとCUIだからかうまくいかず、起動途中で止まってしまう。
ossyaritoori.hatenablog.com

そうこうしているうちにメインPCからDNS接続できなくなってインターネット遮断。。悪夢の再来。。
cmdline.txtを元に戻した後ネットワークに繋ぎ直し、一旦は事なきを得た。

そして翌々日(本日)、サーバーを再構築すべく予備のラズパイ3B+記にRaspberry Pi OSをインストール。
現行のDNS・DHCPサーバーから設定ファイルを救出すべくSDカードをVirtual BOXのLinuxで読み込もうとするもイマイチやり方が分からず断念。
※WindowsではLinuxのファイルシステムは認識しない。

そういや埃をかぶったThinkpadにDebian入ってたことを思い出し、そちらでマウントしたら普通に中身を読めた。
やっぱLinuxでトラブったときはLinux機があると楽だ。

で、設定ファイルの救出が終わって新マシンにコピーしつつ中身をチェックしてみると。。

あ゛あぁぁぁぁぁ!

なんかIP被ってるし!nsはラズパイ3B+で動いているName Server。キミ、そんな中途半端なIPだっけ。。対してrpi4はどう見てもラズパイ4。

CMDBみると案の定。。

DNSのくせに、自分のアドレス間違うとか痛恨のミス。

IPでもアクセスを試したんだけど、そのIPの調べ方がnsに対してpingして表示されたIPなので結局繋いでたのはラズパイ4のアドレスだった。
パスワード失念だと思ったら繋ぎ先違ってて、そりゃパスワード違いますわって話。

てことで、普通に192.168.1.100でアクセスできたのでほとんど完成していた新サーバーは出番なくフォーマットされることになった。
まぁ新サーバーに切り替えて動く保証はないので、従来サーバー続投できてよかった。

以上

分圧回路によってアナログ1ピンで複数スイッチを判別する際の推奨抵抗値を求めるVBAプログラム

Arduino等を使った電子工作で複数スイッチを使いたいとき、スイッチの数だけピンを使ってしまうとあっという間にピンが足りなくなってしまう。

組み込むスイッチ数が多い場合は、抵抗の分圧回路を使ってアナログピンに掛かる電圧を読み取ることで、1つのアナログピンでどのスイッチが押されているのかを判別させることができる。

少々ややこしい話だけど、各スイッチが押されたときの電流経路とAnalog Inputに入る電圧の計算式は次のとおり。

前回作った分圧回路はすべて1kΩの抵抗を使ったが、これだとスイッチが増えるほど電圧差がなだらかになってしまい、ノイズ等の要素で電圧がふらついた際に誤動作する恐れがある。

そこで抵抗の値を以下のようにうまく調整することで、綺麗に電圧を分割して多少ノイズが乘ってもしっかりどのボタンが押されたか判別できるようにしたい。

理想の抵抗値を計算すると5Vの10分割となり0.5V単位で増えるのだが、実際には販売されている抵抗から近い値のものを使うことになるので上記のように小数点以下に誤差が出る。※さらに製品自体の許容誤差もあるので計算通りにはならない。
このあたりの話は、以下のサイトに詳しく掲載されている。感謝。
synapse.kyoto

ただスイッチの個数が変わる度に理想の抵抗値を手計算で求めるのはかなり面倒くさい。
ということで、VBAでプログラムを書いてみた。

コード

Option Explicit

'スイッチ数と抵抗R1の値を以下で調整する。
Const NUMBER_OF_SWITCHS As Integer = 6
Const R1 As Double = 10000

'以下を実行すると上記の条件における推奨の抵抗値を表示する。
Sub PrintRecommendedRegisters()
    Dim ideal_register_values As Collection: Set ideal_register_values = New Collection
    Dim voltage_divider_ratio As Double
    Dim i As Integer
    For i = 0 To NUMBER_OF_SWITCHS - 1
        voltage_divider_ratio = (1 / NUMBER_OF_SWITCHS) * i
        ideal_register_values.Add (voltage_divider_ratio / (1 - voltage_divider_ratio)) * R1
    Next
    
    Debug.Print "R1: " & R1 & "Ω"
    Dim j As Integer
    For j = 2 To ideal_register_values.Count
        Debug.Print "R" & Trim(Str(j)) & ": " & ConvertToE24(ideal_register_values.Item(j) - ideal_register_values.Item(j - 1)) & "Ω"
    Next
    
End Sub

'計算で求めた抵抗値を与えると、実際に購入可能な抵抗値(E24系)から近いものを選択して返す関数
Function ConvertToE24(arg)
    Dim e24 As Variant
    e24 = Array(1, 1.1, 1.2, 1.3, 1.5, 1.6, 1.8, 2, 2.2, 2.4, 2.7, 3, 3.3, 3.6, 3.9, 4.3, 4.7, 5.1, 5.6, 6.2, 6.8, 7.5, 8.2, 9.1)
    Dim c As Collection: Set c = New Collection
    
    Dim exp As Integer
    exp = 0
    Do Until 9.1 * 10 ^ exp > arg
        exp = exp + 1
    Loop
    
    Dim minimum_difference As Double
    minimum_difference = 9.1 * 10 ^ exp
    
    Dim closest_value As Double
    closest_value = 9.1 * 10 ^ exp
    
    Dim j As Integer
    Dim i As Integer
    For j = exp - 1 To exp
        For i = LBound(e24) To UBound(e24)
            Dim difference As Double
            difference = Abs(e24(i) * 10 ^ j - arg)
            If difference < minimum_difference Then
                minimum_difference = difference
                closest_value = e24(i) * 10 ^ j
            End If
        Next
    Next
    
    ConvertToE24 = closest_value
End Function

実行結果

NUMBER_OF_SWITCHSの値とR1の抵抗値を任意の値に変えて実行するとイミディエイトウインドウに推奨抵抗値が表示される。

理想の抵抗値を計算した後、実際に販売されているE24系の抵抗値に数値を丸めて表示している。

リストにまとめてみた

逐一プログラムを動かすのも面倒なので表にしてみた。
これでボタンを使ったプロジェクトで逐一計算する必要がなくなった。

以上

電気の歴史本レビュー:電気発見物語 見えないものが、どのように明らかになったか

今回はこちらの書籍を読んだのでレビュー。

読み始めると面白くて数時間で読破してしまった。

読書のきっかけ

先日から電気回路の学習をしているのだが、キルヒホッフの第一法則(電流則)のところでちょっとした疑問が生まれた。

簡単に言えば、回路のどの点においても入ってくる電流の合計と出ていく電流の合計は等しいっていう法則である。

私が感じた疑問は、こんな当たり前のことがなぜキルヒホッフの第一法則なんていう名前で大層に祭り上げられているんだろうということ。別に深く考えずとも直感的に分かりそうなもんだ。

そこで思い至ったのが、電気は目に見えないから当時は大発見だったのでは?という仮説。このことから電気史的なことに興味を持ちAmazonで評判の良さそうな本を選んでみた次第。

内容

琥珀を摩擦すると物がくっつくという静電気の発見からコンピューターの登場までを扱った電気の歴史本。
登場人物の人柄やエピソードを織り交ぜて、先人の研究を糧として新しい発見が次々となされていく様子が描かれている。

意義

この本の意義については「はじめに」で著者の藤村哲夫さんが述べられている内容がまさにその通りだなというのが読後の感想。
下手に私がああだこうだ書くよりもそのまま引用したほうが伝わりそうなので、私が特に素晴らしいと感じた部分を引用させていただく。

わが国の科学技術教育は、結果だけが重視されて、それに至る道筋が軽視される平面的な教育のように思います。それでは学問が無味乾燥なものになり、身につきません。私は「教育の立体化」を提唱しています。現在の平板な科学技術教育に「歴史」という時間軸を加えることによって、立体的になります。薄っぺらな二次元の教育から、どっしりとした厚みのある三次元の教育になるのです。本書では、その立体化を試みました。すなわち、結果とともにその結果に至るプロセスを重視して記述するようにしました。

特に気に入った部分

P85にこんなことが書かれている。

たしかに偶然が大発見につながることはありますが、それは決して単なる偶然ではありません。いつも問題意識を持って考えている人にのみ偶然の女神はほほえむのです。漠然とものを見ている人には、そのチャンスは与えられません。

まさに問題意識を持ち、仮設を立てて根気よく実験を繰り返した先人達の物語。この姿勢を見ているとモチベーションが沸き上がってくる。
彼らの時代はまさに暗中模索で、電気の単位も、計測の方法もイチから作られてきたのだ。
それらの発見の成果が綺麗に書籍にまとめ上げられて、分かりやすい解説で勉強できている現代人は電気の学習において非常に恵まれた環境にある。
ならば分からんと嘆いている場合ではないな。俺が再発見してやる!くらいの気概で臨まないと。

解消された誤解

電気といえばまず最初の用途が電灯だと思っていたし、電球の発案はエジソンだと思っていた。実際は電信が最初だったし、エジソンは実用的な電球を開発しただけで、元となる電球(1~2時間しか持たない)は別の方が作っている。

もちろんエジソンは素晴らしい仕事をしたと思うけど、歴史を振り返るとこれまで名前も知らなかったような人達も、エジソンに負けず劣らずの素晴らしい働きをしてることが分かる。また電球の改良にはエジソン以外にも多数の研究者が挑戦していたようなことも書かれていた。そう考えると、科学は一部の天才が作ってきたのではなく、古代から無数の研究者によって脈々と受け継がれてきたものだと言える。その研究が実を結んだ人が後世に名を残しているだけで、影の貢献者というのもまた無数にいるんじゃないかと思う。

たとえばAさんがとある現象について方法1で研究してるとして、Bさんは同じことしてもしょうがないからといって方法2を試す。そしたら方法2が当たって有名になったとする。結果的にAさんは推論を外したのかもしれないけど、BさんはAさんが方法1を試しているから方法2に注力したんだと考えると、その研究成果においてAさんも間接的には一定の貢献があったと言えるんじゃないか。
あるいは9割方完成している研究で最後の決めの1手がずっと見つかっていなかったとすると、その最後の1手を発見した人に大きな栄誉が与えられるけど、じゃあ最初に9割完成させた無名の人々の貢献が最後の1手に劣るかというと決してそんなことはない。
影の貢献者が無数にいると述べたのはそういうことである。

ここで言いたいのは、私のような無名の一般人でも常に問題意識を持ち考え続け、そして発信し続けることが社会への貢献に繋がるのではないかということ。私がこの本によって得たモチベーションは、そういうことである。

キルヒホッフの法則に対する疑問はどうなった

そこまで掘り下げた解説はなかったけど、オームの法則の方にちょっとしたヒントがあった。
今では自明とされるオームの法則は、当時ドイツの学会では認められず、その理由が「経験的なものの中には気まぐれが含まれている。理論の裏づけがないものは認められない」という哲学者ヘーゲルの考えを踏襲するヘーゲル一派の主張だった。つまり10000回やって正しくても10001回目でコケる可能性もあるんじゃね?もっとなんかこう哲学的な思考で徹底的に理論作ってこいって話。数学の証明的アプローチは認めるけど統計学的アプローチは許さん的な感じかな。

そう考えると、電気って目に見えないので当時キルヒホッフの法則が受け入れられたというのは結構大きなニュースなのかもしれない。
また、法則っていうと真理の発見!ってイメージを持っていたけど、どうやらそういう感じでもなくて、回路の計算で使う道具としての性格が強いような印象を受けた。道具には名前があった方が便利なのでまぁ当たり前の現象に対して電流則・電圧則という共通言語を生み出した点でも非常に良い貢献だったのかもしれない。

ということで、まだピンと来てない部分はありつつもこの後の計算で使っているうちに馴染むだろうという実感を得たので一旦解決。

総括

さくっと読めて当時の発見の様子にワクワクできる良書だった。
確かに電気に関する理解に奥行がでた気がする。

オームと聞いてドイツ学会での苦労を、ボルトと聞いて異なる金属板で舌を挟むとピリピリするというエピソードからボルタが化学電池のアイデアを閃いた話を、アンペアと聞いてアンペールがエルステッドの論文に興奮し追加実験を行う様子が思い浮かぶ。

電気回路や理論について学習している方に副読本として是非おススメしたい。

以上

電気回路の基本計算式についてチートシートを作ってみた

電気回路の勉強中に公式見たい時にページを行ったり来たりするのが辛いのでチートシートを作ってみた。

勉強中っても序盤も序盤、RPGでたとえるならまだ始まりの村をうろうろしてるレベルなので期待しないで欲しいんだけど、とりあえずこちらが成果物。

こんなのを欲しがる人がいるのかは謎だけど、Slide Shareにも置いてみた。
電気回路の基本計算式チートシート

数式は残念ながら画像なので間違ってても直修正はできない。
MSの数式エディタはちょっと微妙なのでスキルとして学ぶ気になれず、WebのTeXツールで画像出力した為だ。

作り方は、LaTeX to SVGで書いてSVGでダウンロードした後、以下で紹介されている変換スクリプトバッチでemf化した後スライドに取り込んだ。

qiita.com

ちなみに今学習中の書籍はこちら。

約400ページ中、80ページ読み終わったところなのでまだ20%ってところ。

2022年末に実家帰省の際にヒマするといけないからといって買った本なんだけど結局キンドルでラノベとか漫画ばっか読んで未消化だった本。
今回手を付けるきっかけは先日紹介したオペアンプ実験回路。正負両電源を作ってる部分を解析できるようになりたいという動機だ。

まぁなかなか難解で進みも遅いのでRedmineで進捗管理することでなんとかモチベを維持しつつ進める。

今回は分からないところで延々と悩まずに次に進むための工夫として理解度というパラメーターを準備し、理解したセクション数÷全セクション数でパーセンテージを付けることにした。※"%"の出し方が分からないのでとりあえず数値のみ。

理解したセクションには行頭に"k"を付ける。OKの"k"としてよく英語圏で使われてて、テキストステータス管理に楽なので結構重宝してる。
疑問が残ったセクションには行頭に"!"を付けてコメントを残す。

全体を読み終わったときに理解度100%になっていないところを重点的に復習したり別途調べたりする作戦。

飽き症なのでいつまで続くかは不明なんだけど、Redmineで読書管理するとまぁ悪くても3日坊主が10日坊主くらいにはなってる感触があるので、難解な本であっても意義のあるつまみ食い程度の知識は身に付いてると思う。

以上

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。