うどん県出身グーナーの呟き

神奈川県在住のグーナーです。プログラムをやっているので勉強していることや作った便利ツールを公開したいと思います。

メカニカルキーボードを買ってみたよ

カニカルキーボードを買ってみたよ

なぜ購入したのか

以前からメカニカルキーボードには興味がありました。 やっぱり打ち心地もキースイッチによってかなり違うし、 キーキャップの種類も様々なので、パソコンを日頃から触る人間として 自分だけのオリジナルキーボード、という単語には中々の魅力を感じていました。

そして、この間のGW、旅行で疲れた体と頭でネットサーフィンをしていた私は ついついポチってしまったのです。

購入したもの一覧

購入したのは以下の2つ

  • キーボード
  • キーキャップ

キーボード

まず、キーボードは以下のものを購入しました。

実際に購入したものは一つ型が古いものですが、上記の赤軸と呼ばれる、メカニカルキーボードのスイッチでも軽いタッチかつ、あまり音がならないものを選んで、たまたま安く売られていたメルカリで購入しました。 f:id:ryo_udon:20190512193113j:plainf:id:ryo_udon:20190512193126j:plainf:id:ryo_udon:20190512193139j:plain

ちなみにスイッチの種類や一般的なキーボード(メンブレンタイプ)との違いについてはこちらをご覧ください。 メカニカルキーボードを購入する上でこのスイッチは凄く重要なので、もし購入される際は一度、家電量販店のゲーミングキーボードのコーナなどで試し打ちをしてみるといいと思います。

私が今回、このキーボードを選んだ理由は主に以下の2つです。

  • 一度ぐらいUSキーボードを買ってみたい
  • コンパクトで取り回しのしやすいキーボードがほしい!!

その中で見つけたのがこのキーボードでした。 Fnの列を削り、5列にしているにもかかわらず、Fnキーを押しながらs,d,f,eを押すことで手を動かすことなくカーソル移動ができるという変態仕様に惚れて購入を決意しました。

キーキャップ

上のような理由で購入するキーボードは決まったのですが、如何せん、

すっごく、地味!!

というわけで、今回はキーボードの購入金額とほぼ同額で以下のキーキャップを購入しました。

f:id:ryo_udon:20190512194917j:plainf:id:ryo_udon:20190512194945j:plainf:id:ryo_udon:20190512195006j:plain

今回はAliExpressで購入しました。 結構これ以外にも色々とデザイン性に富んだラインナップなので、見ているだけで楽しいです。

いざ、装着

では、実際に装着していきます。
今回は、中古品を購入したので、キーキャップを変更するついでに掃除もしたいと思います。 キーキャップの取り外しにはこのような器具を使います。 f:id:ryo_udon:20190512200524j:plain

通常はキーボード購入時、あるいはキーキャップセットを購入した際に付属していますので、購入の際に確認してください。

まずこの器具を使ってバックスペースの部分から外してみます。 f:id:ryo_udon:20190512200230p:plain 今回のスイッチの種類を示す赤い軸と一緒に大きなホコリの塊が出てきました。 これをティッシュでちょこちょこ取ってあげながら一行ずつ付け替えて行きます。 f:id:ryo_udon:20190512200832j:plain

そしてその地味な作業を黙々と進めること5分ほどで、こうなりました。

じゃじゃーん f:id:ryo_udon:20190512201045j:plain

中々いい感じの色合いです。 ただ、お気づきの方もいるかと思いますが、実はこいつ、フランケンシュタインなんです。 そう、私の注意力不足で、まさかのキーのサイズと数が一部足らず、もともとのものを一部そのまま使っています。

実はこのツイートした後に、VとBが逆になっていることに気づき、慌てて修正しました。。。

終わりに

さて、今回早速購入したキーボードでこの記事を書いておりますが、 中々私にちょうどいいキーストロークでかなり気に入っています。 一部、フランケンシュタインになってしまったのが残念ですが、これもいい経験だと思って、 また新しいキーキャップを購入するさいには、サイズや数などについて、しっかり確認してから購入するようにしたいと思います。

Football Analyzer開発日記_その2

Football Analyzer開発日記_その2

github.com

概要

自分でサッカーを分析できるツールを作ろうという見切り発車な企画第二弾。

今回は第一弾にてmatplotlibを使ってフットボールコートを描く方法を説明した続き、そのコートに指定したフォーメーションでプレイヤーを描く部分の紹介になります。

プレイヤーを設置してみよう

まずは実行してみよう

まずは実行してみます。 今回は前回紹介したdrawFootballCourt.py, main.pyに加え、 以下のsetPlayer.pyを使用します

import sys,os
import numpy as np
from drawFootballCourt import *


COURT_SIZE = [72.5, 45]
#POSITION_LIST = "positionName.json"

class PLAYER():
    def __init__(self):
        self.name = ""
        self.uniNum = 0
        self.playerPos = ""
        self.playerID = 0
        self.pos = [0,0]

class TEAM():
    def __init__(self, homeAway):
        self.homeAway = homeAway
        self.member = [PLAYER() for i in range(11)]
        dir = os.path.abspath(__file__)
        #self.positionList = json.loads(dir[:-len("setPlayer.py")] + "positionName.json")
        self.SetPlayerPosition("4231")
        self.teamColor = ""

    def SetPlayerPosition(self, formation):
        lineMemberNum = []
        lineMemberNum.append(1)
        for i in range(len(formation)):
            lineMemberNum.append(int(formation[i]))

        #コートの端からペナルティスポットまでを引いたもの
        verticalLength  = COURT_SIZE[0] - 6.0
        verticalRes     = (verticalLength-5) / (len(lineMemberNum)-1)

        horizontalLength = COURT_SIZE[1] * 2

        i = 0
        memberIDNum = 0
        for memberNum in lineMemberNum:
            horizontalRes = horizontalLength / (memberNum+1)
            x = verticalLength - verticalRes * i
            for j in range(memberNum):
                y = COURT_SIZE[1] - horizontalRes * (j+1)
                self.member[memberIDNum].pos = [x,y]
                memberIDNum += 1
            i += 1


class PLAYER_SERVER():
    def __init__(self, fig, ax):
        self.fig = fig
        self.ax = ax
        self.dc = DRAW_COURT(fig, ax)
        self.dc.DrawCourt()

    def SetFullMember(self):
        self.teams = []
        self.teams.append(TEAM("home"))
        self.teams.append(TEAM("away"))

        self.teams[0].teamColor="red"
        self.teams[1].teamColor="blue"

    def DrawPlayers(self):
        for team in self.teams:
            for member in team.member:
                x = member.pos[0]
                y = member.pos[1]
                if(team.homeAway=="home"):
                    x *= -1
                    y *= -1

                self.dc.DrawPlayerCircle(x,y,team.teamColor)

    def Show(self):
        self.dc.Show()

実行するmain.pyは以下のように変更します。

import matplotlib.pyplot as plt
from setPlayer import *

home = 0
away = 1

# for drawing court
#if __name__ == '__main__':
#    fig, ax = plt.subplots()
#    dc = DRAW_COURT(fig, ax)
#    dc.DrawCourt()
#    dc.Show()

# for drawing player formation
if __name__ == '__main__':
    fig, ax = plt.subplots()
    ps = PLAYER_SERVER(fig, ax)
    ps.SetFullMember()

    ps.teams[home].SetPlayerPosition("4231")
    ps.teams[away].SetPlayerPosition("343")
    ps.DrawPlayers()
    ps.Show()

実際に実行してみると以下のような結果が得られます。 f:id:ryo_udon:20190504141632p:plain

コードの中身を解説

全体の構成としては、第一弾で説明したフットボールを描くDRAW_COURTクラスを持つPLAYER_SERVERがホーム、アウェイのチーム全体のプレイヤーの位置を管理しています。

class PLAYER_SERVER():
    def __init__(self, fig, ax):
        self.fig = fig
        self.ax = ax
        self.dc = DRAW_COURT(fig, ax)
        self.dc.DrawCourt()

    def SetFullMember(self):
        self.teams = []
        self.teams.append(TEAM("home"))
        self.teams.append(TEAM("away"))

        self.teams[0].teamColor="red"
        self.teams[1].teamColor="blue"

    def DrawPlayers(self):
        for team in self.teams:
            for member in team.member:
                x = member.pos[0]
                y = member.pos[1]
                if(team.homeAway=="home"):
                    x *= -1
                    y *= -1

                self.dc.DrawPlayerCircle(x,y,team.teamColor)

    def Show(self):
        self.dc.Show()

チームは別途TEAMというクラスを作成していて、11人のプレイヤーの格納と一括でポジションを設定するSetPlayerPosition()を持っています。
この関数はフィールドのサイズを入力されたフォーメーションの数字列に合わせてプレイヤーを配置します。
例えば4-2-3-1の場合はキーパーも加えた5列でペナルティエリアからハーフウェイラインまでの距離を分割し、
横方向はフィールドの横幅を各ラインの人数で分割して設置するようになっています。
これによって、3-4-3や4-4-2などのキーパーを入れて4列のフォーメーションでも、 一時期話題になった1-1-7(3-4)-1などのネタフォーメーションも表現できるようになっています。

class TEAM():
    def __init__(self, homeAway):
        self.homeAway = homeAway
        self.member = [PLAYER() for i in range(11)]
        dir = os.path.abspath(__file__)
        self.SetPlayerPosition("4231")
        self.teamColor = ""

    def SetPlayerPosition(self, formation):
        lineMemberNum = []
        lineMemberNum.append(1)
        for i in range(len(formation)):
            lineMemberNum.append(int(formation[i]))

        #コートの端からペナルティスポットまでを引いたもの
        verticalLength  = COURT_SIZE[0] - 6.0
        verticalRes     = (verticalLength-5) / (len(lineMemberNum)-1)

        horizontalLength = COURT_SIZE[1] * 2

        i = 0
        memberIDNum = 0
        for memberNum in lineMemberNum:
            horizontalRes = horizontalLength / (memberNum+1)
            x = verticalLength - verticalRes * i
            for j in range(memberNum):
                y = COURT_SIZE[1] - horizontalRes * (j+1)
                self.member[memberIDNum].pos = [x,y]
                memberIDNum += 1
            i += 1

プレイヤーはPLAYERというクラスを別途作って管理しています。
(現在はposしか使っていませんが、追々、プレイするポジションや選手名、背番号なども表示できるようにしたいと考えています。 後、できれば採点などをした際にはその選手のレーティングとMoMには星マークを描く、などの機能を実装していく予定です。)

class PLAYER():
    def __init__(self):
        self.name = ""
        self.uniNum = 0
        self.playerPos = ""
        self.playerID = 0
        self.pos = [0,0]

最後にコート上にプレイヤーを描く関数を紹介します。 まず、丸そのものを描く関数はdrawFootballCourt.pyにあります。

    def DrawPlayerCircle(self, x, y, color):
        circle = plt.Circle( xy=(x,y), radius=2, ec="w", fc=color, fill=True, zorder=2)
        self.ax.add_patch(circle)

中身はただ、matplotlibの円を描く関数を呼び出しているだけです。

今回、プレイヤーを描くために工夫したのは次のPLAYER_SERVE内の DrawPlayers() 関数です。

    def DrawPlayers(self):
        for team in self.teams:
            for member in team.member:
                x = member.pos[0]
                y = member.pos[1]
                if(team.homeAway=="home"):
                    x *= -1
                    y *= -1

                self.dc.DrawPlayerCircle(x,y,team.teamColor)

ここで、チームがhomeかawayかで正負を反転させることで、 プレイヤーの座標を同じ座標系で扱えるようにしました。

このようにした理由は、home, awayで同じサイドを扱おうとしたとき、それぞれでグラフでいうy座標系の条件が反転してしまうのが嫌だったからです。(これは追々、変えるかもしれません)

では最後に、以上のことを考えながら作ってみたものを色々なフォーメーションで試してみたいと思います。

色々なフォーメーションで試してみよう

4-2-3-1 vs 3-4-3 f:id:ryo_udon:20190504141632p:plain 4-3-3 vs 5-3-2 f:id:ryo_udon:20190511174347p:plain 4-4-2 vs 3-5-2 f:id:ryo_udon:20190511174351p:plain ちょっと5の部分をもっとジグザグにしたいなー

終わりに

今回は、まずいプログラムでフィールドとフォーメーションを描いてみました。 次はこの選手をマウスで移動させたり、一人が動くと他の11人も合わせて移動するような機能を作りたいと思います。

(後、もう少しフォーメーションにジグザグ感をプラスしたい)

以上!!

何かアドバイスやコメントなどもお待ちしています。

Football Analyzer開発日記_その1(サッカーコートを描いてみたよの巻)

Football Analyzer開発日記_その1

概要

自分でサッカーを分析できるツールを作ろうという見切り発車な企画第一弾。 まずはpythonの中でも大人気なグラフ作成ツール、matplotlibを使って、 簡単にサッカーのコートとその中にホーム、アウェイ両チームのポジションを描けるプログラムを 作ってみましたので、紹介したいと思います。 f:id:ryo_udon:20190504141632p:plain

github.com

matplotlibとは

matplotlibとはpythonで グラフを描画して画像を作成したり、簡単なアニメーションを作成することが可能なライブラリであり、 pythonが人気言語に数えられる大きな要因の一つとなっています。 基本的なライブラリの使い方は上のリンク先に書いてあるのですが、いざ自分で使おうと思うと いろいろとつまずくことがあるので、その点を踏まえて説明していきたいと思います。

インストール方法

ここではすでにpythonがインストールされていることを前提にお話します。 お使いのパソコンでターミナル(windowsならコマンドプロンプト)を開いていただき、

pip install matplotlib

と入力して貰えればインストールは完了です。 基本的にpythonをインストールした際に自動的にpipもインストールされるはずですが、 もし、pipがないと言われた場合はこちらを参考に インストールしてください。

matplotlibを使ってフットボールコートを描いてみる

コードを実行

drawFootballCourt.py を参照

import matplotlib.pyplot as plt
import numpy as np

COURT_SIZE = [72.5, 45]

class DRAW_COURT():
    def __init__(self, fig, ax):
        self.fig = fig
        self.ax = ax

    def DrawCourt(self):
        self.ax.set_xlim( -COURT_SIZE[0], COURT_SIZE[0])
        self.ax.set_ylim( -COURT_SIZE[1], COURT_SIZE[1])
        self.ax.set_aspect("equal")
        self.fig.set_facecolor("white")
        self.ax.set_facecolor("green")
        self.ax.set_alpha(0.7)
        plt.tick_params(labelbottom=False,
                        labelleft=False,
                        labelright=False,
                        labeltop=False)
        self.DrawCourtCircle()
        self.DrawCourtLine()

    def DrawCourtCircle(self):
        #センターサークル
        circle = plt.Circle( xy=(0,0), radius=9.150, ec='w', fc='w', fill=False, zorder=1)
        self.ax.add_patch(circle)

        #ペナルティスポット
        circle = plt.Circle( xy=( 61.5, 0), radius=0.5, ec="k", fc="k", fill=True, zorder=1)
        self.ax.add_patch(circle)
        circle = plt.Circle( xy=(-61.5, 0), radius=0.5, ec="k", fc="k", fill=True, zorder=1)
        self.ax.add_patch(circle)

    def DrawPlayerCircle(self, x, y, color):
        circle = plt.Circle( xy=(x,y), radius=2, ec="w", fc=color, fill=True, zorder=2)
        self.ax.add_patch(circle)


    def DrawCourtLine(self):
        #センターライン
        self.DrawLine( 0, 0,-COURT_SIZE[1], COURT_SIZE[1], zo=1)

        #ゴールエリア
        self.DrawLine( 67.0, 67.0,-9.16, 9.16, zo=1)
        self.DrawLine(-67.0,-67.0,-9.16, 9.16, zo=1)
        self.DrawLine( 67.0, COURT_SIZE[0], 9.16, 9.16, zo=1)
        self.DrawLine( 67.0, COURT_SIZE[0],-9.16,-9.16, zo=1)
        self.DrawLine(-67.0,-COURT_SIZE[0], 9.16, 9.16, zo=1)
        self.DrawLine(-67.0,-COURT_SIZE[0],-9.16,-9.16, zo=1)

        #ペナルティエリア
        self.DrawLine( 56.0, 56.0,-20.16, 20.16, zo=1)
        self.DrawLine(-56.0,-56.0,-20.16, 20.16, zo=1)
        self.DrawLine( 56.0, COURT_SIZE[0], 20.16, 20.16, zo=1)
        self.DrawLine( 56.0, COURT_SIZE[0],-20.16,-20.16, zo=1)
        self.DrawLine(-56.0,-COURT_SIZE[0], 20.16, 20.16, zo=1)
        self.DrawLine(-56.0,-COURT_SIZE[0],-20.16,-20.16, zo=1)


    def DrawLine(self, x1, x2, y1, y2, color="w-", zo=3):
        line = plt.plot([x1,x2],[y1,y2],color,lw=2, zorder=zo)


    def Show(self):
        plt.show()

実行部分が main.py を以下の状態にしてもらうとこちらのような結果が得られます。

import matplotlib.pyplot as plt
from setPlayer import *

# for drawing court
if __name__ == '__main__':
    fig, ax = plt.subplots()
    dc = DRAW_COURT(fig, ax)
    dc.DrawCourt()
    dc.Show()

# for drawing player formation
#if __name__ == '__main__':
#    fig, ax = plt.subplots()
#    ps = PLAYER_SERVER(fig, ax)
#    ps.SetFullMember()
#    ps.teams[0].SetPlayerPosition("4231")
#    ps.teams[1].SetPlayerPosition("343")
#    ps.DrawPlayers()
#    ps.Show()

コードの中身を解説

描画領域の宣言

まず、matplotlibは以下のような仕組みで描画を行っています。 詳細はこちらのページに載っていますが、ここでは簡単に説明します。

まず、main.pyの中から説明します。

import matplotlib.pyplot as plt
# for drawing court
if __name__ == '__main__':
    fig, ax = plt.subplots()

まず一行目の

import matplotlib.pyplot as plt

このpythonプログラムにmatplotlibの点や線などをプロットする ライブラリをpltという名前で呼び出しています。 この

import *** as ~~~

という呼び出し方はpythonでは良く使われるので覚えているといいと思います。 次に、

# for drawing court
if __name__ == '__main__':
    fig, ax = plt.subplots()

この部分で今回、グラフを描画するウィンドウ(Figure)とそのウィンドウの中でグラフを描くエリアを示す(Axes)を宣言しています。 ここではグラフを一つしか描かないため、引数は何も指定していませんが、 もし1つのウィンドウに例えば縦2列、横2列でグラフを描きたい場合は、

fig, ax_lst = plt.subplots(2, 2)

と、宣言するとax_lstの中にaxesがリストで格納されます。

描画時の初期設定

描画の初期設定は drawFootballCourt.py の中では

    def DrawCourt(self):
        self.ax.set_xlim( -COURT_SIZE[0], COURT_SIZE[0])
        self.ax.set_ylim( -COURT_SIZE[1], COURT_SIZE[1])
        self.ax.set_aspect("equal")
        self.fig.set_facecolor("white")
        self.ax.set_facecolor("green")
        self.ax.set_alpha(0.7)
        plt.tick_params(labelbottom=False,
                        labelleft=False,
                        labelright=False,
                        labeltop=False)

このDrawCourt()関数の中でいろいろと宣言しています。 まず、

self.ax.set_xlim( -COURT_SIZE[0], COURT_SIZE[0])
self.ax.set_ylim( -COURT_SIZE[1], COURT_SIZE[1])

では、グラフのx軸(横軸)、y軸(縦軸)の表示範囲を指定しています。 今回はグラフ全体を使ってフットボールコートを描きたいと思っているので、 COURT_SIZE の中に縦、横のコートの半分のサイズを配列として格納しています。

次にこちらの4行についてです。

self.ax.set_aspect("equal")
self.fig.set_facecolor("white")
self.ax.set_facecolor("green")
self.ax.set_alpha(0.7)

set_aspect("equal") はx,y軸の分解能を実際のピクセルで同じ幅にするという宣言です。 matplotlibの場合、これを宣言しないとx,yそれぞれで分解能が違うグラフが描かれるようになっています。 次に、ax.set_facecolor(), fig.set_facecolor() についてです。 これについては字の通り、figure, axesそれぞれの色を設定しています。 今回はfigureを白、axesを緑に設定しています。 set_alpha()は透明度を設定する部分になるので、これはあくまで好みになります。

最後に、軸に目盛りをつけない設定を以下の通りにしています。

plt.tick_params(labelbottom=False,
                labelleft=False,
                labelright=False,
                labeltop=False)

これも字の通り、グラフの上下左右の軸には何も表示してほしくないのでFalse を設定しています。

描画時の初期設定は以上になります。

センターサークルを描く

センターサークルとペナルティスポットを描くのが以下の関数になります。

    def DrawCourtCircle(self):
        #センターサークル
        circle = plt.Circle( xy=(0,0), radius=9.150, ec='w', fc='w', fill=False, zorder=1)
        self.ax.add_patch(circle)

        #ペナルティスポット
        circle = plt.Circle( xy=( 61.5, 0), radius=0.5, ec="k", fc="k", fill=True, zorder=1)
        self.ax.add_patch(circle)

        circle = plt.Circle( xy=(-61.5, 0), radius=0.5, ec="k", fc="k", fill=True, zorder=1)
        self.ax.add_patch(circle)

大まかに流れを説明するとmatplotlibのCircleを描く関数を呼び出し、 各種パラメータを設定した後、返り値として返ってきた構造体を axesに加えています。 matplotlibで複数の図形を描く際、add_patch() にて追加された図形の構造体が自動的に描画される仕様になっています。

今回はセンターサークルなどの円に加え、プレイヤーを示す円形もこの関数を利用しています。 plt.Circle() 内のパラメータを簡単に説明すると、

ec 外枠の色
fc 塗りつぶし部分の色
fill 塗りつぶすかどうか
zorder 描く優先順位

ここで一番重要なのがzorderです。

zorderは描く優先順位を示しており、数字が大きいほど優先順位が高くなります。 なので、センターサークルやこの後に説明するラインはなるべく低い数字を設定しています。 これをしなければ、ラインと重なったプレイヤーの丸がラインの下に潜りこむというなんとも微妙な見栄えになってしまいます。 これは単純にグラフを描く際にも使うことが多いので覚えておいても損はないかと思います。

次にラインを引いて行きます

ラインを引いてみる

    def DrawCourtLine(self):
        #センターライン
        self.DrawLine( 0, 0,-COURT_SIZE[1], COURT_SIZE[1], zo=1)

        #ゴールエリア
        self.DrawLine( 67.0, 67.0,-9.16, 9.16, zo=1)
        self.DrawLine(-67.0,-67.0,-9.16, 9.16, zo=1)
        self.DrawLine( 67.0, COURT_SIZE[0], 9.16, 9.16, zo=1)
        self.DrawLine( 67.0, COURT_SIZE[0],-9.16,-9.16, zo=1)
        self.DrawLine(-67.0,-COURT_SIZE[0], 9.16, 9.16, zo=1)
        self.DrawLine(-67.0,-COURT_SIZE[0],-9.16,-9.16, zo=1)

        #ペナルティエリア
        self.DrawLine( 56.0, 56.0,-20.16, 20.16, zo=1)
        self.DrawLine(-56.0,-56.0,-20.16, 20.16, zo=1)
        self.DrawLine( 56.0, COURT_SIZE[0], 20.16, 20.16, zo=1)
        self.DrawLine( 56.0, COURT_SIZE[0],-20.16,-20.16, zo=1)
        self.DrawLine(-56.0,-COURT_SIZE[0], 20.16, 20.16, zo=1)
        self.DrawLine(-56.0,-COURT_SIZE[0],-20.16,-20.16, zo=1)

これまでいろいろと説明してきましたが、ここが一番簡単な箇所になります。 というのも、この関数のなかではネットで調べた寸法をもとに線を引く関数を呼び出しているだけです。 今回はlinewidth(線の幅)を固定にしたかったので、別途DrawLineという関数を設けています。

ここまでを実行してみる

ここまで説明したソースコードを実行してみると以下の実行結果が得られます。 f:id:ryo_udon:20190504141525p:plain

コートにプレイヤーを配置してみる

少し長くなってしまったので、別の記事として後日投稿します。

London渡航記その2(2018/12/22) 前半

London渡航記その2(2018/12/22)

概要

これはしがない社会人2年目の男が単身ロンドンに旅立ち、生サッカー観戦に興奮し、スタジアム観戦に興奮し、 物価に絶望した、渡航記の2日目になります。

初めての朝ロンドン

到着翌日、いきなりメインイベントがやってきました。そう、エミレーツでの初観戦です! あまりに興奮しすぎてランチタイムキックオフなのにまさかの午前7時に起床、8時にはホテルを出てしまった私はとりあえず初めての朝のロンドンを散歩することにしました。 f:id:ryo_udon:20190414144439j:plain うん。いい雰囲気。さすがは歴史の街。夜もいいけど朝もいいよね。 と思いながら何も考えず歩いて、 f:id:ryo_udon:20190414144552j:plain 電車乗ると f:id:ryo_udon:20190414144605j:plainf:id:ryo_udon:20190414144620j:plain

自然と足が向いてました、Emirates Stadiumに実は一番近いと噂のHolloway Road駅(ちなみに試合当日は下車専用になるようです)

途中に、往年の名選手や現在所属選手のサイン入りユニフォームがずらりと並ぶギャラリーを眺め、道草を食いつつ、(まだ時間前なのに開けてくれてありがとうございました!) f:id:ryo_udon:20190414144807j:plainf:id:ryo_udon:20190414144823j:plain

ついにたどり着いたのが、

我らがホーム!!

とりあえず思ったのは、

デカイ(小並感)

しばらく呆然と眺めて堪能した後、まだショップがopenしていなかったのでとりあえずスタジアム周辺を散策をすることにしました。

そうしたらあるわあるわ、そこかしこに撮影スポットが。 f:id:ryo_udon:20190414161751j:plain まずはベルカンプ大先生とパシャリ。 f:id:ryo_udon:20190414162527j:plain f:id:ryo_udon:20190414182022j:plain

キングをパシャリ(意外と大きいのね) f:id:ryo_udon:20190414182134j:plainf:id:ryo_udon:20190414182151j:plain

スタジアムの外壁にはこのような往年の名選手のプロフィールが描かれており、意外な経歴などをしれてかなり勉強になります。 f:id:ryo_udon:20190414163013j:plainf:id:ryo_udon:20190414185230j:plainf:id:ryo_udon:20190414185246j:plain

ひとまずぐるりと一周した私は、(一周するのに1時間かかりました。スタジアムの周りをランニングしている人に三回は抜かれました。)

スタジアム西側の近辺の街を散策することに。

まずは有名なARSENALのモニュメントをパシャリ。 f:id:ryo_udon:20190414185538j:plain

このあたりの赤レンガの多い街並みも中々ロンドンという雰囲気があっていい感じ。 f:id:ryo_udon:20190414185555j:plain

朝のひんやりとした空気の中、ぶらぶらと歩いているとふと路上に転がるあるものが目に入りました。 f:id:ryo_udon:20190414185839j:plain ん?

f:id:ryo_udon:20190414185912j:plain

んん?

こ、これは、これはあれですよ。

うちのファンタジスタとか親方とかフェラーリ大好きなエースや頭がイかれてると噂のCBがシーズン前に吸っていたという笑気ガスとかいうやつですよ。

本当にあったんだなー

閑静な住宅街で変なものにテンションが上がる25歳。

そんなよくわからないテンションのまま、トレイラのネーム入りサードユニフォームやマフラー、トレーニングウェアなどを大量購入し、

さあ! 念願のエミレーツ・スタジアムだ!!

Raspberry PI 起動時に自動的にPythonを実行させる方法

概要

先日投稿したTeamMakerですが、現在私はRaspberry Piにて運用しています。 ryo-udon.hatenadiary.jp

github.com

ただ最近、OSの問題か、電源の問題か、Raspberry Piが何もしていないのに落ちていることがあります。 なので、今回はその対策として、Raspberry Pi起動時にPythonを自動的に実行する方法と Pythonの処理が通信の途絶などで誤って終了した際に自動的に再起動してくれるスクリプトを勉強したので紹介したいと思います。

Systemd

今回はLinuxの起動処理やシステムを管理するSystemdという機能を利用します。 こちらを参考にさせていただきました。

そもそもSystemdとは何か。DevelopersIOさんで調べたところ、以下のようにありました。

Systemdは、サービスを1つのシェルスクリプトではなくUnitという単位で管理し、設定ファイルとして持ちます。 このため処理を細分化でき個別に実効することが可能です。また処理ごとの依存関係を明確にすることが出来ます。 さらに処理が細分化されているということは、並列での実行も可能になります。例えばAの処理の後にBとCを並列実行する、 というようなきめ細やかな設定が可能になります。

つまりは処理ごとに .serviceというファイルを /lib/systemd/system/ 以下に作成してあげれば起動時や デバイスを差し込んだ際にプログラムを設定することができます。

serviceファイルの作成

まずは /lib/systemd/system/の中に.serviceファイルを作成します。 ここでserviceファイルの名前は任意なので、この記事の中では TeamMaker.serviceと記述する TeamMakerの部分を任意の名前にしてください。

sudo vim /lib/systemd/system/TeamMaker.service
[Unit]
Description = TeamMaker

[Service]
ExecStart=/usr/local/bin/python3 /home/pi/workspace/Discord_Python/discord_python/src/main.py
Restart=always
Type=simple

[Install]
WantedBy=multi-user.target

[Unit]の Descriptionではその処理の詳細を書きます。 今回は指定していませんが、この[Unit]の中ではafterbeforeなどを

after=test.service

のように記述することで、他の処理の後に実行という設定ができます。 この他にも同じ使い方でRequireWantsなどを使うことで、依存関係を表現することができます。

[Service]の中では主に実行コマンドを記述します。 ExecStartに実行コマンドを記入します。 今回はpython3でTeamMaker.pyを実行します。 なので実行するpythonを指定し、実行するpythonプログラムのフルパスを指定しています。 Restartはプロセスの再起動です。 一応、エラーが発報されても再実行するスクリプトを後で紹介しますが、念の為常に再実行するように設定しておきます。

[Install]ではシンボリックリンクの設定をしています。 Wantedbyは.watsディレクトリにシンボリックリンクを貼る

詳しくはこちらのメモ書きなどを見てください。

Subprocess

今回はこちらの質問への回答を参考にしました。

import os,sys
import time
import subprocess

COMMAND  = "python3"
SRC_NAME = "TeamMaker.py"

dir = os.path.abspath(__file__)
proc = subprocess.Popen([COMMAND, dir[:-len("main.py")] + SRC_NAME])
while True:
    ecode = proc.poll()
    if ecode is None:
        time.sleep(2)
    elif ecode == 0:
        print('NORMAL END')
        print('NEXT' + '-'*10)
        proc = subprocess.Popen([ COMMAND, SRC_NAME])
    else:
        print('ERROR')
        print('RESTARTING' + '='*10)
        proc = subprocess.Popen([ COMMAND, SRC_NAME])

subprocessモジュールはターミナル上で実行するコマンドを実行することができます。また、proc.poll()の返り値をみることでエラーも確認できますので、今回はこれを利用します

このスクリプトの内容は凄くシンプルです。

proc = subprocess.Popen([COMMAND, dir[:-len("main.py")] + SRC_NAME])

この部分で何度も再起動させるpythonプログラムと実行方法を指定します。 今回は実行方法には"python3"を、実行対象には絶対パスでTeamMaker.pyを指定しています。 その後、

ecode = proc.poll()

にてエラーコードを取得します。 ecode == Noneが実行中 ecode == 0というのは正常終了、 それ意外がエラーになります。

これによって処理が突然落ちてしまっても再度起動されるようになります。

終わりに

これでTeamMakerの運用環境はほぼほぼ作り終えたので、今後はサッカー分析ツールを作成していきたいと思います。

やりたいことリスト

python

TeamMakerに新機能追加

*トーナメント表作成
*トーナメントの進捗更新
リーグ戦の表を作成
リーグ戦の得点、勝ち点計算
リーグ戦、トーナメントの混合
使用するチームをランダムで設定
*用途ごとにブランチ分け

*リモート起動する機能

matplotlib + animation + mouse control

qiita.com yura2.hateblo.jp -> さらに+ オブジェクトの移動速度を変更

Python細々としたところ

  • python実行時のoptionをhelpで表示できるようにする

GUI

tkinter, pyqt5など

人認識

映像から二次元の図へ変換

マウスコントロール

www.lisz-works.com

Google Colaboratory

colab.research.google.com

C++

VS

並列処理

クラス図

今時、クラス図を描いてコーディングというのも時代遅れ感があるが、 システム全体の説明を簡単に図示できるようになりたい。

ロンドン渡航記まとめ(その1) 2018/12/20 ~ 2018/12/21

London渡航記その1(2018/12/20 ~ 2018/12/21)

概要

これはしがない社会人2年目の男が単身ロンドンに旅立ち、生サッカー観戦に興奮し、スタジアム観戦に興奮し、 物価に絶望した、渡航記になります。

なぜロンドンへ

そもそもなぜロンドンへ行ったのかというと、理由は唯一つ。

エミレーツスタジアムアーセナルが見たい!!

社会人になった二年前に最初のリフレッシュ休暇でロンドンに行くと固く誓った私は待ちました。待ち続けました。誰にも文句を言われずにロンドンにはばたける日を。

そしてついに昨年末、やっとタイミングがあいロンドンに渡ったわけであります。

事前準備

事前準備と作りはしましたが、特に何もしていません。

旅程は12/20 ~ 12/28までの6泊9日で、 ただ、航空券とホテルとスタジアムのチケットを取っただけです(一応、空いた日用のツアーを何個か申し込みましたが)。

ばらばらにとってもいいのですが、私は海外旅行は大体こちらでいつも航空券とホテルを予約しています。

自分でやってもいいのですが、面倒くさがりかつかなり細かく調整してくださる旅工房さんを愛用しています。

チケットについてはもともとRed Memberになっていたので、ただポチポチするだけでした。 正直、僕には猿さん以上にわかりやす書く自信がないので詳しくはこちらをご覧ください。

ただ、今後はHISさんが毎試合スコアブックを付けるほどのガチグーナー笹木香利さんと一緒にエミレーツ観戦する笹旅なるものが今年も計画中らしいので、そちらを利用したほうがいいかも。なにせ、HISさんはArsenal FCと提携していますからね。おそらくかなりいい席で見ることができます。

後、忘れてはいけないのがコンセント。 イギリスは日本とは形状が違うので、変換器が必要になります。(こんな感じです) という訳で、私はとりあえずあまり大きくなく、色々な国でも使えるものをと思い、 以下の変換器を購入しました。

もっと安いものもありましたが、USBポートをかなり使うので、2つでは心もとないと思い、4つついている、この商品にしました。

さて、これでほぼ準備は完了。あとは当日を待つのみ。

出発当日

早めに仕事を上がり、羽田空港に到着。あまりにも興奮しすぎて着いてのは出発の4時間前。 ポチポチ持参した携帯ゲーム機(Vitaだよ!生産終了したレアものだよ!)で時間を潰しつつ、

さあ出発!

経由地ドーハに到着

飛行機に12時間ぐらい縦にも横にも揺られた後についたのが経由地のドーハ(今回カタール航空を使用) ドーハはこんな感じでした。

ドン!

f:id:ryo_udon:20190407152110j:plain
ドーハ空港内1
写真の上にある通路はモノレールでした。

ドン!

f:id:ryo_udon:20190407152126j:plain
空港内ホール
よくわからないモニュメントが多い空港でした。

驚いたのは、空港の中に鷹を肩に乗っけた王族みたいな人がいたこと。

写真をとってもいいのかな?などと迷ったけど、「無礼者! 首をはねろ!」になりたくなかったので そこは自重し、おとなしくハンバーガを食べて搭乗口で待つことにしました。

だけど、いつまで経っても案内されない。 あれ? なんで? と直ぐ側にいたおじさん(訛り的にフランス?)と話をしているとこんな放送が聞こえてきました。

" 只今、ガトウィック空港でドローンが飛んでいるため飛行機が飛べません "

僕とおじさん、ポカーン。 すぐ横にいた女の子二人を連れた家族もポカーン。 向かいでサンドイッチを食べていたおじさんも咥えたまま、え?

そう、日本でどのぐらい話題になったかわからないですが、これですよ、これ。

結局さらに二時間待って、なんとか出発できることに。 (しばらくドローンを見るたびに破壊衝動を抑えるのが大変でした)

とりあえず、いろいろとありましたが、これでなんとかロンドンに向かうことができました。

待ちに待ったロンドン到着

本当なら正午に着くはずが、ガトウィックに到着したのは午後5時半。

とはいってもこれを見ればテンションは上がる上がる。

これで興奮しすぎたんでしょうね。 こんな出来事がありました。

皆さん、お気をつけを!

ロンドン市内へ

ガトウィック空港からロンドン市内まではGatwick Expressを利用しました。 僕はしらなかったのですが、オンラインで予約をすると10%安くなるようです。時間は40分、定価料金は20ポンド程度。 電車の中はwi-fiが完備されているので、もしSIMなどを買う方は、空港ではなく、市内で買ってもいいと思います。

そして着いたのがVictoria駅。

f:id:ryo_udon:20190407153317j:plainf:id:ryo_udon:20190407153332j:plain
Victoria Station

歴史を感じます。

ホテルへ

今回滞在したホテルはこちら。かなり日本人の方が利用されているようでした。

最寄りがRussell Square駅でヒースロー空港からは乗り換えなしで行ける+King's Cross駅まで一駅とかなり交通の便がよく、 そして、なにより、Emirates Stadiumまでたったの4駅なのです!!

グーナーはもう、ここに泊まるしかないですね!

そして一日目はホテル下のパブでフィッシュアンドチップスとビールでFinish!!

一日目まとめ

というわけで、中々波乱の1日目でした。f:id:ryo_udon:20190407155337j:plain

ちなみにTubeという愛称で親しまれているロンドンの地下鉄ですが、都営大江戸線並みかそれよりもさらに深いです。 なので、絶対に階段を登ろうと考えないでください。

その2に続く

/*コードブロックに言語名を表示*/ pre.code:before { content: attr(data-lang); display: inline-block; background: white; color: #666; padding: 3px; position: absolute; margin-left: -10px; margin-top: -30px; } pre.code { padding-top: 30px !important; }