そろそろ中堅エンジニアのIT雑記

プログラミングを仕事にして若干、まだまだ新米エンジニアの雑記です。

Raspi天体カメラ

品不足が解消されたみたいなので、RaspberryPi 4とHQカメラを入手しました。
天体撮影用のカメラを作ってみました。

レンズ

天体撮影するに当たって、大事なのはレンズです。
ラズパイHQカメラはC-CSマウントレンズが使えます。
しかし、C-CSマウントは監視カメラなどによく使われるため、あまり日常使用されません。
手持ちのEFマウントレンズが使えるよう、K&F Conceptのマウントアダプタを利用しました。
焦点距離が55mm-200mmのレンズを装着しました。

ラズパイHQカメラのセンササイズをフルサイズ換算すると約5.6倍になります。
従って望遠端の200mmを利用すると1120mm相当の焦点距離を得られます。
これは天体撮影ではかなりメリットです。

筐体

ともかく、撮影をトライしてみたかったので、簡単な3Dプリントで筐体を出力しました。

RaspberryPi

持ち運びを考えて、本体はRaspberryPi Zeroなどでも良かったのですが、撮影後の処理速度を考えてRaspberryPi 4にしました。
RaspberryPi 5が入手できたら、置き換えも検討しています。
SDカードではなく、USB SSDにブートイメージを焼き、起動していいます。

システム構成

プログラム言語はPythonを採用しましたが、撮影コマンドはlibcamera-stillを利用したいため、subprocess.run()を利用しました。
また、フォーカス合わせのためのプレビュー表示はRaspberryPiにVNC接続してlibcamera-helloコマンドを叩くことにしました。
撮影はPythonスクリプトを組み、撮影したJpeg画像をLINEで通知できるようにしています。
Pythonスクリプトの実行はIPhoneからRaspberryPiにSSH接続して実行します。IPhoneのショートカット機能を使って、アイコンをタップするだけで実行できるようにしました。
以上の構成で、IPhoneからアイコンをタップし、LINEでjpeg画像を受け取れるシステムを作成しました。

スクリプト

以下が作成したスクリプトです。

import os           # for base directry
import sys          # for command line argument
import datetime     # for date time string
import time         # for time evaluation
import requests     # for LINE API
import subprocess   # for unix command execution

basedir = os.path.dirname(__file__)

url = "https://notify-api.line.me/api/notify" 
token = "LINE notifyトークン"

start_time = time.time()

t_delta = datetime.timedelta(hours=9)
JST = datetime.timezone(t_delta, 'JST')
now = datetime.datetime.now(JST)
date_str = now.strftime("%Y%m%d")
time_str = now.strftime("%H%M%S")

output_dir = basedir + "/capture/" + date_str
if not os.path.isdir(output_dir):
    os.mkdir(output_dir)

filename = sys.argv[1]  # output file name

exposure_time = float(sys.argv[2])  # exposure time in seconds
exposure_time_micro = exposure_time * 1000000

output_file = output_dir + "/" + filename + "_" + time_str + ".jpg"

subprocess.run(["libcamera-still", \
                            "-o", output_file, \
                            "--shutter", str(exposure_time_micro), \
                            "--gain", "16", \
                            "--immediate"])

headers = {"Authorization" : "Bearer "+ token} 
message =  filename + "_" + time_str + ".jpg was captured.\n" \
           + "exposure time:" + str(exposure_time) + "sec." 
payload = {"message" :  message} 
image = output_file
files = {'imageFile': open(image, 'rb')}
r = requests.post(url, headers = headers, params=payload, files=files)

end_time = time.time()
diff_time = end_time - start_time
print(diff_time)

試し撮り

試し撮りしたオリオン大星雲

自作赤道儀開発【検証・自動シャッター機能 1/】フォトカプラー動作確認

自動シャッター機能の技術検証を行いました。

レリーズ仕組み調査

一眼レフやミラーレスカメラで長時間露光行う際に用いるアクセサリとしてレリーズがあります。
中華品も多く出回っており、筆者も使っていますが、特に問題なく使用できています。
中華レンズを買った際、なぜかおまけで付属してきたものがあり、バラしてみたところ、非常に簡単な仕組みであることがわかりました。
カメラとの接続は3軸オーディオミニプラグで、3軸をそれぞれショートさせることで、AF、シャッターを制御できる仕組みでした。

レリーズの3軸プラグ対応

FocusとGNDをショートさせると、カメラのシャッター半押し状態、ShootとGNDをショートさせるとシャッター全押し状態になります。
ラズパイのGPIOを使って、ShootとGNDをショートさせることができれば、ラズパイから電気的にカメラのシャッターを切ることができます。

電子スイッチ

電圧を印加し、流れる電流を制御する素子といえば、学生時代習ったトランジスタが思いつきました。
さらに詳しく調査をしたところ、フォトカプラーという素子(中身はLEDとトランジスタを組み合わせたもの)が電子スイッチに良いとわかりました。
入力と出力で電気的に断絶しており、カメラに加電圧がかからなくてすみます。
初めて使う部品なので、動作確認を行いました。

フォトカプラー動作確認

使ったフォトカプラーはAmazonで発売している以下です。
Amazon | uxcell フォトカプラー 10個 2.54mm 4ピン DIPマウント PC817 プラスチック製 | フォトカプラ | 産業・研究開発用品 通販
ラズパイ3Bを使った、動作確認回路の回路図は以下になります。

フォトカプラー動作確認回路

ラズパイの動作はシェルを使います。以下のコマンドで出力側LEDが1秒間点滅します。

raspi-gpio set 20 op    # output設定
raspi-gpio set 20 dh    # high出力
sleep 1
raspi-gpio set 20 dl    # low出力

ラズパイレリーズ制御回路

うまくフォトカプラーを動かすことができたので、レリーズを接続した回路を作成しました。
回路図は以下です。

ラズパイレリーズ制御回路図

FOCUSは不要なので、SHOOTと短絡させています。
フォトカプラーのコレクタ、エミッタを逆に接続すると動作しなかったのでご注意ください。

実際に接続したところが以下。上記のシェルを打ち込んで、カメラのシャッターが作動しています。

ラズパイとカメラのレリーズ制御回路接続


これで、赤道儀の回転動作と合わせて、自動でカメラを動かすことができます。
5分間露光を10回行う、などが自動でできるようになりました。

自作赤道儀開発【検証・極軸投入機能 1/】

極軸投入機能の技術検証です。
極軸(北極星)の方角を取得する方法を検討しました。

極軸投入機能調査

市販赤道儀の極軸取得方法を調査したところ、以下の流れのようでした。

  1. 極軸望遠鏡で北極星方面の星景を取得
  2. 緯度・経度・日時から代表的な天体*の星図を取得
  3. 星景と星図の移動角度を算出

* 北極星カシオペア座、北斗七星など

調査結果を受けて、極軸方向の画像を取得した後、画像解析すれば、極軸合わせの移動角度を取得できそうです。

極軸方向画像取得

次の案を思いつきました。検証していきます。

ラズパイカメラモジュールで極軸望遠鏡を制作

ラズパイカメラモジュールで、極軸方向を撮影。
撮影した画像と星図を照合し、移動角度を算出するという流れを考えました。
まずはラズパイカメラモジュールがどのような撮影をできるか、検証しました。
ラズパイカメラモジュールはサードパーティ製の安価なものが、Amazonにたくさんあります。以下を試しました。
https://amzn.asia/d/85pvWsu
筆者のRaspberryPi 3Bでは、以下の手順で撮影することができました。
1. カメラモジュール接続後、以下のコマンドを実行し、legacy cameraをONに設定する。

sudo raspi-config

2. 以下のコマンドで、カメラモジュールが正常に認識されているか確認する。
supported = 1, detected = 1が正常認識。

vcgencmd get_camera

認識しない場合、/boot/config.txtのcamera_auto_detect=1をコメントアウトし、再起動。

3. 以下のコマンドで撮影。

sudo raspistill -o xxx.jpg


撮影できた画像が以下になります。

ラズパイカメラモジュール撮影画像

私室で適当に撮ったものなので、撮影対象が悪いですが、思っていたよりも綺麗に撮れます。未調整で、フラットな部分の色味はおかしいですが。
シャッタースピードは上記コマンドの引数で渡せますので、ある程度は使えそうです。

スマートフォンGPS電子コンパスを利用

スマートフォンにはGPS電子コンパスが搭載されています。
さらにAndroidアプリのSkyマップはスマートフォンを向けた方向の星図を画面に表示できます。
play.google.com
これをうまく利用できれば、ハード面でかなり楽ができます。
天体座標をアプリから取得することはできませんが、Android端末なので、ターミナル環境のあるPCからUSB接続したAndroidスマホに対して、adbコマンドを利用することが可能です。
以下のコマンドで、RaspberryPiからAndroidスマホに表示中の画面スクリーショットを取得することができました。

adb shell screencap -p /sdcard/xxx.png
adb pull /sdcard/xxx.png

移動角度計算

両案で実物の極軸方面画像が取得できますので、画像上から北極星の座標ピクセルを取得できれば、画像中心との距離が極軸合わせの移動距離になります。画像から北極星を見つける方法を検討する必要があります。

自作赤道儀開発【検証・設計-動作装置】

ステッピングモーター制御を検証しました。

部品

ArduinoのCNCシールドは3Dプリンタを制御ために3つのモータードライバを搭載できるものが、安価で入手できます。
モータードライバはA4988が安価です。
www.amazon.co.jp

CNCシールドには12~36V の直流電圧入力端子があります。この端子はモータドライバを経由し、ステッピングモータへの電力供給に使われます。
12VのDC出力があるモバイルバッテリーを利用することにしました。
5V/2.4AのUSB出力もありますので、Arduinoへの電源供給も同時に行えます。
www.amazon.co.jp

ステッピングモーターは大きさと入手性からNEMA17を選びました。
型番は17HS4023です。
スペックシートは以下になります。

定格電流 0.7A
ステップ角 1.8 deg./ step
トルク 14 N cm

モータードライバ設定

A4988ドライバは可変抵抗がついており、ステッピングモータへの入力電圧を調整して使用するのですが、入力電圧の計算式は以下の記事を参考にしました。
asumin-home.com

今回利用した17HS4023のステッピングモータの定格電流は0.7Aなので、以下の数式で算出しました。ステップは1/16を選択したので、最後に1.0を乗じます。


 \displaystyle
V_{REF} = 0.8 \times 0.7 \times 1.0 = 0.56 [V]
CNCシールドに搭載したA4988ドライバの可変抵抗をテスターで測りながら、上記の電圧に調整します。
ちなみに、検証時に利用していたステッピングモータ、17HS4401の定格電流は1.7Aで、1.36Vの入力電圧となるのですが、今回使用したモータドライバでは1.2V以上に印加できず、使用を諦めました。DRV8825というモータードライバならもう少し定格電流が高くても大丈夫そうです。

ピンアサイン調査

上記部品をArduinoの接続すると、Arduinoからステッピングモータを制御できるようになります。
Arduinoのスケッチプログラムで、特定ピンにHIGH/LOWを書き込みます。
CNCボードとArduinoのピンアサインを調査したところ、以下となりました。

ピン番号 ピン種別
2 X軸ステップ
3 Y軸ステップ
4 Z軸ステップ
5 X軸方向
6 Y軸方向
7 Z軸方向
8 ネーブル

ピン種別の内容は以下となります。

ピン種別 内容
ステップ ステッピングモータのパルス入力
方向 ステッピングモータの回転方向
ネーブル ピン出力をOUTPUTにすることで、その他のピン出力を有効にする

自作赤道儀開発【基本設計】

今回から設計です。

接続系統

システム接続系統図です。

接続系統図

制御サーバ

各種デバイスの制御、操作入出力を行う制御サーバを用意します。
入出力が多いRaspberry Piを制御装置に選びました。家に余っていた3Bを使うことにします。
Raspberry Pi OSはDebianベースなので、個人的に扱いやすいです。aptやbashがそのまま使えます。
ソフトウェアはC++, Python, Shellスクリプトで開発します。

動作装置

赤道儀の回転動作、軸投入にはステッピングモーターを利用します。
ステッピングモーターArduino UNOとCNCシールドで制御します。
3Dプリンター用のArduino CNCシールドが安価で手に入り、3個のステッピングモーターを制御できます。
https://www.amazon.co.jp/KKHMF-3D%E3%83%97%E3%83%AA%E3%83%B3%E3%82%BF%E3%83%BC-CNC%E3%82%AD%E3%83%83%E3%83%88-Arduino%E3%81%AB%E4%BA%A4%E6%8F%9B-Arduino%E3%81%A8%E4%BA%92%E6%8F%9B/dp/B07R5R3927/www.amazon.co.jp
日周運動用の 1軸回転と、軸合わせ用の2軸回転にちょうど良いです。
ソフトウェアはArduino Cで開発します。

カメラ装置

天体投入用の装置です。
ラズパイで制御するカメラモジュールやAndroidスマホを利用する予定です。
本装置で撮影した天体の画像を画像認識にかけ座標ピクセルを取得する、といったことを想定しています。

レリーズ装置

カメラを制御するレリーズです。
レリーズを制御するための電子回路を作成し、ラズパイのGPIOで制御します。

GPS装置

未定ですが、GPSから位置情報取得します。

コンポーネント設計

システムコンポーネント図です。

コンポーネント

システム制御機能

赤道儀システムの状態遷移、各プログラムの制御を行なう。

日周運動機能

日周運動追随に関する処理について、Arduinoと通信、レリーズ制御を行なう。

極軸投入機能

極軸方向を計算し、雲台方向制御に関する処理について、Arduinoと通信を行う。

自動投入機能

対象天体の方向を計算し、雲台方向制御に関する処理について、Arduinoと通信を行う。

Arduinoスケッチ

運動のモード制御を行なう。
ステッピングモーターの日周運動追随回転、雲台方向制御を行なう。

自作赤道儀開発【要件定義】

天体撮影を行うための機材、赤道儀を自作することにしましたので、その記録です。

背景

1年ほど前から写真撮影が趣味になりました。
撮影対象としては航空機と星景写真。
※星景写真:星空と風景の同時撮影

天の川 (FUJIFILM X-A5, 18mm/f2.8, ISO3200, 阿智村)

そこそこの機材で綺麗に撮れていたので満足していましたが、星景写真撮影は更なる欲が出てきました。
星景写真は広角レンズで空をできるだけ広範囲に短いシャッター速度(長くても20sec)で撮っていました。
この条件では、日本一暗いと言われている天体観測の聖地阿智村で、上記の天の川がなんとか撮れました。
これより上のレベルの撮影となると、具体的な天体、銀河や星雲の撮影になります。
天体からの光量を稼ぐためにシャッター速度をより遅くしたいのですが、遅くすると地球の日周運動による影響で、撮影対象の天体が移動し、線のように映ってしまいます。
これを補うための機材が赤道儀です。
天体の動きに合わせて、カメラの方向を徐々に動かしてくれます。
原理は非常に単純で、24時間で360度カメラを動かします。
赤道儀は各メーカーから発売されておりますが、持ち運びに便利なポータブルタイプから、天体望遠鏡とセットになっていて、天体への導入機能になっているものまで、ピンキリです。値段は数万円〜です。
これであれば自分のスキルでもできそうと思い、開発を始めました。

また、ここ数年、本格的なシステム開発プロジェクトに従事しており、一通りの開発フェーズを体験したので、復習のために、要件定義〜設計〜開発〜試験を確認する目的もあります。
実際は、新しく習得する知識技術が多々あるので、設計〜試作〜試験を繰り返す開発を想定しています。

要件定義

まずはどのような赤道儀を作るか、要件定義です。

天体の日周運動を追随する

赤道儀としての最低限の機能です。Arduinoとステッピングモータで実現します。
本要件の開発が主になります。

極軸投入を行う

赤道儀の回転運動は極軸(天球の回転軸)を北極星に向ける必要があります。
これを極軸合わせと呼びますが、極軸合わせの精度が、日周運動追随の精度に大きく影響します。
極軸合わせを補佐する機構が必要になります。

カメラのシャッターを制御する

大体のカメラは30sec以上のシャッター速度で撮影する場合(BULK撮影)、レリーズというカメラに接続するボタンを利用します。
レリーズは分解したところ三軸イヤフォンジャックのショートで制御しているようだったので、シャッターの制御もできそうと思い、要件に追加しました。

また、以下は上記が完成した後の改良要件ですが、できそうな気がするので挙げておきます。

極軸の自動投入を行う

極軸の方位角、仰角を取得し、赤道儀を載せた雲台を動かすことで実現可能と判断しました。

任意の天体の自動投入を行う

極軸の自動投入ができるのであれば、任意の天体への自動投入も可能と判断しました。
また、事前調査で、天体の諸データはインターネットで取得できそうでした。

GPSによる位置補正

自動投入には自位置の座標データが必要ですが、GPSによる位置データ取得を試みます。

終わりに

今回はひとまず要件定義を思いつくままに挙げました。
実際はもう少し開発が進んでおり、ある程度の進捗があるので、随時投稿していきたいと思います。

良いソースコードを書くための心得

段ボールの中から引っ張り出してきた、ソースコードの作法に関する書籍から、大事そうな考えをメモ。

良いコードの定義

  • 保守性が高い→理解しやすい
  • 素早く動作する
  • 正確に動作する
  • 無駄な部分がない→ラクできる!
  • コードは理解しやすくなければいけない。
  • コードは他の人が最短時間で理解できるように書かなければいけない。

- Keep it simple!

良いコードの価値

  • プロジェクトを強力に推し進める。
  • プログラマとしての評価が高まる。
  • 仕事に満足感や自信が持てるようになる。

- ラクができる!

リファクタリング

リファクタリングはソフトウェア品質を高める

  1. リファクタリングは設計を改善する
  2. リファクタリングはソフトを理解しやすくする
  3. リファクタリングはバグを見つけ出す
  4. リファクタリングはより速くプログラミングできる

参考

  1. リーダブルコード
  2. 良いコードを書く技術
  3. リファクタリング