Paho MQTTでリモートでシャッターを切れるカメラを作ってみました。撮った写真もMQTTで送られてきます。
2015/2/28 UPDATE!!
##カメラ側の設定
まずは、デバイス(カメラ)側のスクリプト
ハードウエアとして、Raspberry Pi B+に専用のカメラモジュールをつけています。
remotecam.py 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| import paho.mqtt.client as mqtt import os def on_connect(client, userdata, rc): print("Connected with result code "+str(rc)) client.subscribe("my/device/stillcam/command") def on_message(client, userdata, msg): cmd = str(msg.payload) print(msg.topic+" "+str(msg.payload)) if cmd == "shoot": print "Say cheeees!" dummy = os.system("raspistill -w 1024 -h 768 -t 10 -o /run/shm/temp.jpg") dummy = os.system("mosquitto_pub -h my.broker.jp -t my/device/stillcam -f /run/shm/temp.jpg") client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("my.broker.jp", 1883, 60) client.loop_forever()
|
パブリッシュ設定したメッセージが来ると、on_messageがコールされます。
メッセージが”shoot”だったら、osコマンド”raspistill”を実行して写真を撮ります。
さらにそのデータをosコマンド”mosquitto_pub”でパブリッシュします。
ちょっと格好悪いですけど、MQTTで写真データを送るのにmosquittoを使っています。ざっくり試した感じですと、paho-mqttではバイナリのペイロードをうまくハンドリングできないようで、多分なんか設定があるのだと思います。探してみます。
2015/2/11追記:
####上記のバイナリデータのハンドリングの件ですが、うまく行かない理由は私のスキル不足です。多分python内部での変数のデータ扱いをうまく変換してやる必要が有りそうです。 只今勉強中。
2015/2/28 追記:
上記、バイナリデータの送信の件ですが、
実際に出てくるエラーは
UnicodeDecodeError: 'ascii' codec can't decode
というものでしたので、そのまま検索をかけてみると、デコードがうまく行っていない、旨のエラーのようです。
であれば、変換をしないように設定すればいいのかなあ、どうするのかなあ、と思いつつソースコードを(わからないなりに)眺めていると、
http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.python.git/tree/src/paho/mqtt/client.py1 2 3 4 5 6 7 8
| if isinstance(payload, str): upayload = payload.encode('utf-8') payloadlen = len(upayload) elif isinstance(payload, bytearray): payloadlen = len(payload) elif isinstance(payload, unicode): upayload = payload.encode('utf-8') payloadlen = len(upayload)
|
という記述を見つけ、payloadのタイプによってエンコードを分けていることがわかりました。bytearray
なら何もせずにそのままのデータが送られるのでbytearray
にすればいい。
再び検索して、読み込んだファイルをbytearray型で変数に代入する方法を調べ、結果として次のようなソースコードになりました。
replace with 'mosquitto_pub ......'1 2 3 4 5 6
| with open('/run/shm/temp.jpg', 'rb') as source: payload_pub = bytearray(source.read()) client.publish(topic_root+topic_pub, payload_pub)
|
これで無事バイナリファイルを送信することが出来ました。
USBのカメラを使う場合はraspistillのコマンドを適宜変更すればいいかと思います。
このスクリプトを実行可能に設定して、実行させます。これで待ち受け状態。
##コントローラ側
別のPCでは、
- シャッターを切るコマンドを発行する
- 送られてきた写真のデータを保管する
という作業があります。
まずは、送られてきたデータを保管するスクリプトを作ります。
photo_sub.py1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| import paho.mqtt.client as mqtt import datetime def on_connect(client, userdata, rc): print("Connected with result code "+str(rc)) client.subscribe("my/device/stillcam") def on_message(client, userdata, msg): filename = "./image/" + datetime.datetime.today().strftime("%H%M%S%f") + ".jpg" outfile=open( filename , 'w') outfile.write(msg.payload) print "subscribe: " + filename outfile.close client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message client.connect("my.broker.jp", 1883, 60) client.loop_forever()
|
このスクリプトでは、my/device/stillcamというトピックにパブリッシュされたデータを取り込んでファイル名(タイムスタンプ)をつけて保存します。
このスクリプトを実行して、データを待ち受けます。
最後にシャッタを切るコマンドを送ります。
とりあえずは、コマンドラインからです。
1
| $ mosquitto_pub -h my.broker.jp -t my/device/stillcam/command -m "shoot"
|
これで、メッセージ”shoot”をトリガにして、写真を撮影し、それを転送して保存するまでの一連の作業が行われます。
デバイス側の処理負荷を確認するため1秒に1回シャッターを切る動作を続けて見ました。
結果的には、カメラと転送の処理で数%程度の負荷のようです。
ちなみにこのカメラ、この設定では1秒間隔以上のスピードで連続して撮影することはできませんでした。
カメラがRaspi用のモジュールですので、かなりオーバーヘッドが小さい感じもします。
CPU的には処理が軽くていいのですが、ハードウエア的には取り回しが悪く、ちょっといまいちな感じもします。
応用のシーンによりますが、今回私が想定しているケースでは使いにくいです。
あとで、USBcamでやってみようと思います。