Pythonのbytesの生成に関して
勘違いしていたので備忘録。
bytes(255)
は
b'¥xff'
とはならず、
b'¥x00¥x00¥x00 ... ¥x00'
と、255個の¥x00
で満たされたbytesになる。
a = 255 a.to_bytes(1, "big")
とすれば
b'¥xff'
が得られる。
参考
Python pandasのメモ
Python pandasが難しいので、メモ。
データ構造
Series : 1次元のデータ
DataFrame : 2次元のデータ
時間系
Time Series / Date functionality — pandas 0.20.3 documentation
TimestampとPeriodの2種類がある。 Timestampは、ある時点を表す。 Periodは、ある期間を表す。
TimestampをDataFrameのIndexとして取ると、DateTimeIndexとなる。 時系列データはこれで表すと良い。 DateTimeIndexで表現されるデータを処理するための関数群が用意されている。
リサンプリング
pandas.DataFrame.resample()
を使う。
アップサンプリング・ダウンサンプリングともに可能。
リサンプリング時のデータの補完/集計方法はpandas.Resamplerのメソッドとして定義されている。
アップサンプリングの例(線形補間)
import pandas as pd time_index = pd.date_range("2017-10-01 10:00:00", periods=3, freq="S") print(time_index) df = pd.DataFrame([0, 100, 300], index=time_index) print("-----------------------") print("Before resampling") print(df) df_resampled = df.resample("500ms").interpolate("linear") print("-----------------------") print("After resampling") print(df_resampled)
DatetimeIndex(['2017-10-01 10:00:00', '2017-10-01 10:00:01',
'2017-10-01 10:00:02'],
dtype='datetime64[ns]', freq='S')
-----------------------
Before resampling
0
2017-10-01 10:00:00 0
2017-10-01 10:00:01 100
2017-10-01 10:00:02 300
-----------------------
After resampling
0
2017-10-01 10:00:00.000 0.0
2017-10-01 10:00:00.500 50.0
2017-10-01 10:00:01.000 100.0
2017-10-01 10:00:01.500 200.0
2017-10-01 10:00:02.000 300.0
リサンプリングの注意点
サンプリング周期によっては、元データと同じ時間がリサンプリング後に現れない場合がある。(1秒間隔のデータを300ms周期でリサンプリングした場合など )
その場合、リサンプリング後に現れなかった時間のデータは補完されない。
import pandas as pd import matplotlib.pyplot as plt time_index = pd.date_range("2017-10-01 10:00:00", periods=5, freq="S") print(time_index) df = pd.DataFrame([0, 100, 300, 50, 0 ], index=time_index) df_500ms_resample = df.resample("500ms").interpolate("time") print("-----------------------") print("500ms resampling") print(df_500ms_resample) df_300ms_resample = df.resample("300ms").interpolate("time") print("-----------------------") print("300ms resampling") print(df_300ms_resample) plt.clf() df_500ms_resample.plot() df_300ms_resample.plot() plt.show()
DatetimeIndex(['2017-10-01 10:00:00', '2017-10-01 10:00:01',
'2017-10-01 10:00:02', '2017-10-01 10:00:03',
'2017-10-01 10:00:04'],
dtype='datetime64[ns]', freq='S')
-----------------------
500ms resampling
0
2017-10-01 10:00:00.000 0.0
2017-10-01 10:00:00.500 50.0
2017-10-01 10:00:01.000 100.0
2017-10-01 10:00:01.500 200.0
2017-10-01 10:00:02.000 300.0
2017-10-01 10:00:02.500 175.0
2017-10-01 10:00:03.000 50.0
2017-10-01 10:00:03.500 25.0
2017-10-01 10:00:04.000 0.0
-----------------------
300ms resampling
0
2017-10-01 10:00:00.000 0.0
2017-10-01 10:00:00.300 5.0
2017-10-01 10:00:00.600 10.0
2017-10-01 10:00:00.900 15.0
2017-10-01 10:00:01.200 20.0
2017-10-01 10:00:01.500 25.0
2017-10-01 10:00:01.800 30.0
2017-10-01 10:00:02.100 35.0
2017-10-01 10:00:02.400 40.0
2017-10-01 10:00:02.700 45.0
2017-10-01 10:00:03.000 50.0
2017-10-01 10:00:03.300 50.0
2017-10-01 10:00:03.600 50.0
2017-10-01 10:00:03.900 50.0
<matplotlib.figure.Figure at 0x11268e7f0>
500msサンプリング時
300msサンプリング時
これに対する今のところの対策は、一回十分に短いサンプリング周期でアップサンプリングして、その後所望のサンプリング周期にダウンサンプリングするという手法でなんとかなる。
Trelloのカード移動をSlackに通知してくれるbotを作った。
Python3 + Flask + py-trello + slackerでTrelloの更新情報をslackに流す(1) - うごくものづくりのために
Python3 + Flask + py-trello + slackerでTrelloの更新情報をslackに流す(2) - うごくものづくりのために
上記の記事で作成したシステムを整理して、botとしてまとめてGithubで公開しました。
できること
Trelloの指定のボードで、ToDoリストからDoingリストへ、またはDoingリストからDoneリストへのカードの移動があったときに、Slackに任意のメッセージをPostする
できないこと
上記以外のこと
インストール方法、使い方等
Githubのreadmeに書いてあるので、読んでください。 英語がつらいという人はTwitter(@silvie_c)に教えてください… 日本語のreadmeを作るかもしれません。
機能追加はある?
あるかもしれませんが、あまり期待しないで待っていてください。
Python3 + Flask + py-trello + slackerでTrelloの更新情報をslackに流す(2)
前回 の記事で、py-trelloでwebhookの登録をし、Flaskでサーバを立ててTrelloの通知を受け取ることができました。
今回は、拾ってきたTrelloの通知情報をslackに投げるところを作りたいと思います。
ゴール
Trelloのウェルカムボードのカードの移動を、Flaskで作ったサーバにWebhookで通知させる。 サーバに通知がきたら、slackにPostする。
Trelloのwebhookから必要な情報だけを抜き出す
カードの移動に関する通知だけを抜き出す
Trelloのwebhookは、登録したボードに関する更新情報をすべて通知します。 今回必要なのはカードの移動だけなので、通知のうちカードの移動に関するものだけを抽出します。
通知がTrelloのどのアクションと紐付いているかは、webhookで届くデータの以下に格納されています。
action -> display -> translationKey
カードの移動に関する通知の場合は、このフィールドが action_move_card_from_list_to_list
になります。
詳細な情報を抜き出す
今回は、以下の4つのデータを取ってくることにします。
- 移動されたカード名
- 移動前のリスト名
- 移動後のリスト名
- カードを移動させた人の名前
カード移動に関する通知を受け取ると、上の4つの情報を表示するように webhook_server.py
のwebhook()
を変更しました。
webhook_server.webhook()
@app.route('/webhook', methods=['POST']) def webhook(): if request.method == 'POST': action_type = request.json["action"]["display"]["translationKey"] if action_type == "action_move_card_from_list_to_list": card_name = request.json["action"]["data"]["card"]["name"] before_list = request.json["action"]["data"]["listBefore"]["name"] after_list = request.json["action"]["data"]["listAfter"]["name"] user_name = request.json["action"]["memberCreator"]["username"] message = user_name + "さんが「" +card_name + "」を「" + before_list + "」から「" + after_list + "」へ移動しました!" print(message) return '', 200 else: abort(400)
動かすとこんな感じ。
いい感じですね。
slackerを用いてslackに投稿する
Slack API Tokenを取得する
以下のを参考に、SlackBotアカウントの作成を行います。
Slackbotのアカウントができたら、APIトークンを secret_token.py
に追加しておきます。
slack_token = "#Your slack token HERE#" trello_api = "#Your trello API HERE#" trello_token = "#Your trello token HERE#"
実装
slackerライブラリを用いてSlackに投稿する仕組みは、以下の記事を参考にします。
先程実装したwebhook()
の中で表示したメッセージをそのままslackにPOSTしてみます。
webhook_server.py
rom flask import Flask, request, abort from slacker import Slacker import secret_tokens app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): if request.method == 'POST': action_type = request.json["action"]["display"]["translationKey"] if action_type == "action_move_card_from_list_to_list": card_name = request.json["action"]["data"]["card"]["name"] before_list = request.json["action"]["data"]["listBefore"]["name"] after_list = request.json["action"]["data"]["listAfter"]["name"] user_name = request.json["action"]["memberCreator"]["username"] message = user_name + "さんが「" +card_name + "」を「" + before_list + "」から「" + after_list + "」へ移動しました!" # print(message) slack.chat.post_message("sandbox", message, as_user=True) return '', 200 else: abort(400) @app.route("/webhook", methods=["HEAD"]) def webhook_creation(): if request.method == "HEAD": return "", 200 else: abort(400) if __name__ == '__main__': slack = Slacker(secret_tokens.slack_token) app.run(port=5000, host="0.0.0.0")
結果
Trelloでカードを動かした情報を無事Slackに投稿できました!
ゴール達成!
参考
Python3 + Flask + py-trello + slackerでTrelloの更新情報をslackに流す(1)
弊チーム(https://github.com/SSL-Roots/Roots_home/wiki)では、タスクの管理にTrelloを使っています。 また、最近チャットツールとしてslackを導入したので、チームの活動に関する全情報をslack上に集約したいと思っています。
そこで、TrelloでタスクがDoneリストに入ったらslackで報告してくれるbotを作ります。 Trelloとslackの連携は公式でサポートされていますが、通知が英語だし味気ないので、タスク完了したら可愛い女の子が褒めてくれる仕組みにしたいです… ちなみに、RaspberryPi3 上で動かします。
というわけで。
ゴール
Trelloのウェルカムボードのカードの移動を、Flaskで作ったサーバにWebhookで通知させる。 サーバに通知がきたら、slackにPostする。
今回の記事では、Flaskでサーバを立てて、そこにTrello Webhookの通知がくるところまでを目指します。
インストール
Python3, pip3は入ってるという前提です。
sudo pip3 install flask py-trello slacker
Flaskでサーバを用意
Trello Webhookを受け取るためのサーバをFlaskで用意します。
webhook_server.py
from flask import Flask, request, abort import pprint app = Flask(__name__) @app.route('/webhook', methods=['POST']) def webhook(): if request.method == 'POST': pprint.pprint(request.json) return '', 200 else: abort(400) @app.route("/webhook", methods=["HEAD"]) def webhook_creation(): if request.method == "HEAD": return "", 200 else: abort(400) if __name__ == '__main__': app.run(port=5000, host="0.0.0.0")
Trello Webhookの登録
Trello Webhookに、作ったサーバを登録します。 py-trelloを用いてTrello APIにアクセスしますが、その際にAPIキーとトークンが必要になります。 APIキーとトークンの取得方法は、以下のページを参考にしてください。
Trello の Webhook API をPHPで受け取ってみた - きじとら
APIキーとトークンの情報をまとめたsecret_tokens.py
を作っておきましょう。
secret_tokens.py
trello_api = "#Your API Key HERE#" trello_token = "#Your token HERE#"
さて、Webhookの登録をします。 Webhookの登録には、WebhookサーバのURLと、通知をもらいたいアイテム(ボードだったり、カードだったり)のIDが必要です。 py-trelloを使ってアイテムのIDを取得する方法は以下のページに詳しいです。
Python + py-trelloで、Trello APIを使ってみた - メモ的な思考的な
今回は、Trelloに登録したときに必ず存在するはずの、ウェルカムボードを登録します。
trello_regist_webhook.py
from trello import TrelloClient import secret_tokens def main(): server_url = "http://[自分のグローバルIP]:5000/webhook" client = TrelloClient( api_key=secret_tokens.trello_api, token=secret_tokens.trello_token ) all_boards = client.list_boards() for board in all_boards: if board.name == "ウェルカムボード": welcome_board = board break webhook = client.create_hook(callback_url = server_url, id_model = welcome_board.id) if webhook == False: print("Failed webhook registration") else: print("Success!") if __name__ == "__main__": main()
先程作ったwebhook_server.pyを実行させた状態でtrello_regist_webhook.pyを実行すると、Webhookが登録されます。
python3 webhook_server.py & python3 trello_regist_webhook.py
Success!と表示されればWebhookの登録が正しく完了しています。
実験
さて、webhook_server.pyを起動している状態で、Trelloのウェルカムボード上で何かしてみましょう。 試しに、一番左の「やってみる」リストから、真ん中の「やったこと」リストにカードを移動させてみましょう。 すると…
Trelloの更新情報がJSONで送られてきました!
実際は、Python内部では送信されたJSONをパースして辞書形式で持っています。 あとは、必要な情報をその辞書から抜き出してやればOKです。
今回はここまで。 次回はslackに投稿する部分を作って、システムを完成させます。
参考
Python + py-trelloで、Trello APIを使ってみた - メモ的な思考的な
Trello の Webhook API をPHPで受け取ってみた - きじとら
GitHub - sarumont/py-trello: Python API wrapper around Trello's API
trelloのboardにwebhookを登録する - pblog
2017/09/22 記事修正
slackbotライブラリの代わりにslackerライブラリを使うことにしましたので、タイトルを修正。
MakerFaireTokyo2017に出展しました。
8/5,6に行われた、MakerFairTokyo2017に、RoboCup SSLチーム Rootsとして出展してきました!
はじめに、展示に足をお運び頂いた皆様にお礼を伝えたいと思います。
展示を見て笑顔になって頂いたり、「すごいねー」と子供たちが食いついてくれたりしたことが展示者としての何よりの喜びでした。
少しでも皆様にRoboCupSSLの魅力がお伝えできたことを嬉しく思います。興味を持っていただいた方は、ぜひ本当の試合を見にJapanOpenなどの大会にお越しください!
今回の展示は、RoboCup SSL OBチームであるOP-AmPとRootsの共同でRoboCupSSLの実演を行いました。
このような展示会に出向いてRoboCup SSLの実演をしたのは、おそらく僕達が日本で初めてになります。
当然前例のない試みですので、不安だらけでした。
フィールドカメラの画角は足りるのか、画像処理の設定がうまくいくのか、電波は混線しないか等々…
しかし流石、OBチームが2チーム集まっただけあります。苦労はありましたが、OP-AmPさんの協力もあり、大会の際よりもむしろスムーズに設営が終わったのではないでしょうか。
あまりない経験だと思うので、設営に関する情報も後ほどまとめてPublishしようと考えています。
展示は、ロボットの実演やパーツごとの分解展示、動画での紹介を行いました。実演展示は、Rootsがディフェンス、OP-AmPがオフェンスという形で、1−2パスシュートのデモを行いました。また、OP-AmPさんの世界唯一のカーブシュートや、ロボットがボールを所定の位置まで運ぶBall Replacementの実演も行いました。
やはりと言うべきか、お客さんに一番興味を持っていただいたのは実演展示でした。1−2パスシュートが決まる姿を見て、その場で足を止めて見てくださる方が多かったです。
さらにロボットが完全自律でサッカーをしているとわかると、驚くお客さんがたくさん。
普段の大会だとRoboCupをご存知のお客さんが多いので、初めて見る方の反応は非常に新鮮でした。驚いたり笑顔になって頂いていたのが嬉しかったですね。
反省はいろいろありますが、実演展示でOP-AmPさんにおんぶにだっこだったのが、ありがたくも悔しいところです… 次の展示のときまでに対等に渡り合えるように実力をつけないとなぁ…と感じています。
最後になりますが、展示においでいただいた方々、MFT運営の皆様、そしてOP-AmPさん、Rootsのメンバー、本当にありがとうございました。そして、お疲れ様でした!
来年のMFTでまた会いましょう〜!
GoogleProtocolBuffer(C++)で、NULL文字(/0, 0x00)を含むデータをパースする方法
GoogleProtocolBufferのC++版で、NULL文字を含むデータをパースする際にハマったのでメモ。
socket通信のrecv()で受け取ったデータをParseFromString()でパースしようとした際、 データに"0x00"が出現するとヌル文字(\0)だと解釈して、パースが正常終了しませんでした。
結論としては、char型の配列をstring型に変換し、かつ変換の際にサイズを指定してやればOKでした。
/*** 初期設定などなど省略 ***/ char buf[BUF_SIZE]; ProtobufClass proto; // プロトコルバッファのメッセージ解析用インスタンス size_t recv_size; recv_size = recv(sock, buf, sizeof(buf), 0); std::string str(buf, recv_size); proto.ParseFromString(str);