工作と競馬2

電子工作、プログラミング、木工といった工作の記録記事、競馬に関する考察記事を掲載するブログ

PlayStation4(PS4)の純正コントローラを分解する

概要


PlayStation4(PS4)の純正コントローラを分解し、L2/R2ボタン、アナログスティックの構造の確認と、外部から乗っ取って制御する方法を試した。



背景と目的


PlayStation4(PS4)のコントローラを外部から乗っ取って制御してみたいため、中身の構造を確認してできそうかどうか、やってみたくなった。ひとまず、L2/R2ボタンと右ジョイスティックだけ。


詳細


1. 入手

手持ち品は分解したくないため、4000円の中古品をAmazonマーケットプレイスで注文。動作確認済みだが分解痕ありと注意書きがあったので同じようなことをやった人が売り払ったものだろう。たしかに、側面の表蓋と裏蓋の隙間に分解痕があるが、動かしてみたところ正常にゲームができた。問題なし。

f:id:dekuo-03:20201018171727j:plain


2. 分解

2.1 裏蓋、裏蓋を外す

裏蓋には、4つのネジがある。#00のプラスドライバーが合う。ネジを外したらすぐに蓋は取れた。よく見たら爪が折れていた。元の持ち主が分解時に折ったのだろう。まあ、分解自体は楽でいい。

f:id:dekuo-03:20201018171735j:plain

以下が、外した時の外観。USB充電と裏側の光る部分への信号/給電用フレキシブルケーブルが表蓋とつながっている。これを外せば表と裏は取れた。

f:id:dekuo-03:20201018171742j:plain

バッテリーを外し、裏に隠れているネジを外し、さらに、茶色いフレキシブルケーブルを外すと、表蓋と、電子基板が分離できた。

f:id:dekuo-03:20201018171756j:plain


2.2 L2/R2ボタン

ボタンの樹脂部品を外すと、以下のような部分が出てきた。ボタンを押したときに導電性のゴムが、プラスチック製の基板側にある端子同士を導通させる仕組みだ。

f:id:dekuo-03:20201018171805j:plain

2.3 アナログスティック

2軸ジョイスティックと呼ばれる部品のようだ。そのものではないが、以下のような部品。

akizukidenshi.com

縦横それぞれに可変抵抗がついていて、倒した角度に応じて抵抗が変化するので分圧された電圧を読み取れば、操作量がわかるだろう。

f:id:dekuo-03:20201018171823j:plain


3. 制御する

3.1 L2/R2ボタン

これは、導電性のゴムの代わりに、外から導通させてあげればよいので、基板側から2本線を出し、この線同士を接触させてみたところ、実際に操作することができた。ただし、少しチャタリングが気になるので何らかの対策はした方がいいかも?(線を直接触れさせただけなので不安定だっただけかも)

f:id:dekuo-03:20201018171810j:plain


3.2 アナログスティック

操作量に応じて、可変抵抗の分圧点の電圧が変化して、マイコンで読み取られていると思われる。

  • 奥側全倒しのとき 約0.3V
  • 中立(操作なし)のとき 約1.46V
  • 手前側全倒しのとき 約2.7V

だった。なので、分圧点に与えてみたところ、確かに操作できた。というわけで、外からアナログの電圧を与えられるように、線を付けた。

f:id:dekuo-03:20201018171816j:plain


まとめと今後の課題


L2/R2ボタン、アナログスティックを外部から乗っ取って制御する方法が試せた。


boto3でLambda関数を呼び出すinvokeメソッドの引数ClientContextを使い方を確認

概要


boto3でLambda.client.invokeの引数ClientContextを使い方を確認してメモした。



背景と目的


boto3でLambdaを呼び出す際、呼び出し先関数へ渡すペイロードの仕様を変えずに、追加でパラメータを与えたいと思ってboto3のドキュメントを調べたら、invokeの引数ClientContextというものが使えそうだった

boto3.amazonaws.com

なので、使い方を調べてメモする。


詳細


呼び出し側

こちらが参考になった。必要なところだけかいつまんで書く。

  • custom、envというキーを持つJSON化可能な辞書を用意
    • それぞれのキーの値には任意のデータ(あくまでJSON化可能)
  • 辞書をJSON文字列化、バイト列化、base64エンコード、文字列に戻す
  • invokeの引数に渡す

という感じ。例えば、以下。

import boto3
import json
import base64

Lambda = boto3.client("lambda")

# JSON化可能なデータ
ctx = {
    "custom": {
        "param1": "value1"
    },
    "env": "env_value"
}
# JSON文字列化とバイト列化
b = json.dumps(ctx).encode("utf-8")
# base64化して文字列に戻す
ClientContext = base64.b64encode(b).decode("utf-8")

# 引数に渡して呼び出し
resp = Lambda.invoke(
    FunctionName=FunctionName,
    Payload=json.dumps(Payload),
    ClientContext=ClientContext
)

呼び出される側

呼び出される側は、引数contextから取り出す。client_contextプロパティの下に、custom、envがそれぞれついている。customは、辞書を入れたので辞書、envは文字列を入れたので文字列と、与えたものがそのまま出てくる。

def lambda_handler(event, context):
    print(context.client_context.custom)
    print(context.client_context.env)

ペイロードの仕様を変えず、contextを使って追加のデータを送ることができた。


まとめと今後の課題


boto3でLambda.client.invokeメソッドの引数ClientContextを使い方を確認してメモした。


IFTTTが有料化するので、Webhooks/LINE Notify連携レシピの代替をAWSで検討する

概要


IFTTTのWebhook+LINE Notify連携の代替として、AWS API Gateway + Lambdaの動作を確認した。



背景と目的


IFTTTが2020年10月6日に有料化するらしい。無料枠が少しだけあるのだが、私の場合そこに収まり切らないので、代替が難しそうなレシピを無料枠に充て、他のものはIFTTTより安く実現できる代替手段を検討している。

最近作成した自動水やり器では、

Webhookチャンネルでデータを受けて、LINEチャンネルでLINEのトークルームに結果通知するレシピ

を使っているが、AWSAPI Gateway+Lambdaに変更できそうに思えるので、ちょっと試しにやってみる。この組み合わせだと、使用規模次第で無料枠に収まる。Microsoft Flowも当然候補だが、すでにAWS使っちゃってるので優先で。


詳細


1. LINE NotifyのAPI

ちょっと調べただけで、

qiita.com

など、たくさんの情報が出てきた。Notifyでトークルームに送信できるAPIが用意されているらしい。とりあえず、上記の例はNode.jsだが、ここではPythonスクリプトを書いて試す。

1.1 トークンの取得

LINE NotifyのAPIをたたくには、LINE NotifyのWebサイトにログインして、トークンの取得が必要。トークルームごとにトークンを取得する必要があるようだ。というわけで、以下のボタンを押して表示されたものをメモ。なお、トークンごとに識別名を任意に与えられるらしく、送信時にメッセージの先頭につくらしい。

f:id:dekuo-03:20201003214709p:plain


2 試しに送信

以下を作成。tokenとmessageは外から与える想定。下の方に、試しに動かすコード。

# coding: utf-8

import requests
import json

def post_LINE_Notify(token, params):

    URL = "https://notify-api.line.me/api/notify"
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Authorization": "Bearer %s" % token
    }
    response = requests.post(URL, data=params, headers=headers)
    ret = {
        "response": json.loads(response.text)
    }
    
    return ret


if __name__ == "__main__":

    token = "取得したトークン"
    params = {
        "message": "これはテストです。" # paramsの中身は、https://notify-bot.line.me/doc/ja/ 参照
    }
    ret = post_LINE_Notify(token, params)
    print(ret)

printした結果は、以下の通り。ステータスコード200が返ってきた。

{'response': {'status': 200, 'message': 'ok'}}

一方、LINEの画面は以下の通り。ちゃんと受信している。 園芸IoTという部分は、トークンを取得する際に、識別名として与えたもの。(自動水やり器の通知用トークルームに送信するのでこんな名前)

f:id:dekuo-03:20201003215907p:plain


3. APIGateway + Lambda

3.1 APIGateway

IFTTTと同じ感じにするため、APIのリソースに、{event}というパスパラメータを用意。 リクエスト統合のapplication/jsonマッピングテンプレートでメソッドリクエストのパススルーを使った場合、Lambdaのevent引数のevent.path.eventに入ってくれる。 (AWSでやるなら、別に互換性持たせずむしろもっといろいろできる仕様にした方がいいかもしれないが)

f:id:dekuo-03:20201003230840p:plain f:id:dekuo-03:20201003230836p:plain


3.2 Lambda

IFTTTでは、本文のJSONでvalue1,2,3を受け取り、パスパラメータでevent名を受け取って、LINE Notify本文を構成する。ここではテストなので、とりあえずパラメータを全部流す。

def lambda_handler(event, context):
    
    token = "取得したトークン"
    params = {
        "message": "event=%s\nvalue1=%s\nvalue2=%s\nvalue3=%s" % \
            (event["params"]["path"]["event"], 
            event["body-json"]["value1"],
            event["body-json"]["value2"],
            event["body-json"]["value3"])
    }
    # 送信
    ret = post_LINE_Notify(token, params)
    
    return ret


3.3 試し実行

f:id:dekuo-03:20201003223843p:plain

LINEの方も、正しく受信できた。

f:id:dekuo-03:20201003230205p:plain

というわけで、一応、API GatewayとLambdaで置き換えできそう。ノンプログラミング環境からの乗り換えにはなるが、発展性があるのでよしとする。


まとめと今後の課題


IFTTTのWebhook+LINE Notify連携の代替として、AWS API Gateway + Lambdaの動作を確認できた。こちらに置き換えようと思う。


リモート水位センサ筐体内温度の上昇を抑えるカバーの効果を検証、2年目稼働状況のまとめ

概要

リモート水位センサ筐体内温度の上昇を抑えるカバーの効果を検証し、期待通りの効果があったことを確認できた。


背景と目的

今年もいよいよ稲刈りの時期が来て、田んぼに水がなくなったため、リモート水位センサも出番が終わった。2年目のシーズンも故障なく無事稼働してくれた。そこで、今年のまとめとして、真夏の筐体内温度上昇を抑えるためのカバー装着効果を検証しておく。


詳細

1. 条件

  • 筐体内温度
    • リモート水位センサシステム内蔵温度計
    • 2019年のデータ
      • 2019/06/28~2019/09/05
    • 2020年のデータ
      • 2020/06/28~2020/09/05
  • 筐体内温度と気温を比較(気象庁データのうち、水位センサ所在地から最も近い地点の温度を使用)


2. 結果

以下の通り、2019年に比べて2020年は温度上昇が抑えられている。特に、日照時間割合が高い、つまり日が照っている状態での温度上昇が抑えられている。なお、日照時間割合が1の場合の平均的な温度は、

  • 2019年: 48℃
  • 2020年: 43℃

と5℃の差となった。事前検証で5~10℃くらいが期待できると書いたが、ほぼその通りになった。

2019年

50℃を頻繁に超えている。

f:id:dekuo-03:20200909233332p:plain

2020年

50℃を超えたのは1度だけ。

f:id:dekuo-03:20200909233336p:plain

比較

すべての日照時間割合のパターンで比較。特に、気温が高いときに、温度上昇が抑えられている。

f:id:dekuo-03:20200909233339p:plain


3. 2年目のまとめ

こちらで、今シーズン開始前にメンテナンスをした内容に沿って書く。

  • 電池容量アップ
    • 使用したエネループが別件でダメージを受けていたらしく、今シーズン開始後早々にくたばってしまった。そのため、通常の乾電池を使用したのだが、その乾電池も怪しいメーカーのものだったらしくあまり持たなかった。再度交換した乾電池は、問題ない。ソーラー発電+リチウムイオン電池蓄電も稼働実績が上がってきているので、来年はソーラーで駆動したい。
  • 水位の分解能調整
    • これは、あまりメリットがなかった。まあ、水位の変化が頻繁に起こるので、わかりやすいといえばわかりやすいが、干上がるか、そうでないかというレベルの判断にはいらなかった。もし、次のモデルを作るようなら、大雑把でいいと思う。
  • 温度上昇を防ぐカバーの装着
    • 上記の通り。十分効果があった。来年もカバー装着する。


まとめと今後の課題

平均的に5℃程度上昇を抑えられ、ほぼ狙い通りの効果が得られたと思う。来年も、装着することにする。


気づいたら、LINEの通話呼び出し(音またはバイブレーション)がされなくなっていたので直した

概要

LINEの通話呼び出しがされなくなっていたので直した。


背景と目的

最近、自分や周りの人のスマホで、LINEの通話がかかってきたときに音もバイブレーションもなく気づけないというトラブルが起きていた。メッセージよりも即時性が求められる通話の呼び出しがされないのは不便なので、ちゃんと呼び出しされるように直す。


詳細

1. 環境

f:id:dekuo-03:20200906214919p:plain


2. 調べる

Web上に何かしら情報はあるだろうと探してみた。以下を見てどうにかなりそうなので、参考にした。

appllio.com


3. 直す

結論から言うと、LINEアプリ内の通知に関する設定を直せばOKだった。 LINEのホーム > 設定 > 通知 と進むと、下の方に通話に関する通知設定がある。私の場合、以下のように音声なしとなっていた。

f:id:dekuo-03:20200906214938p:plain

なので、

  • "アラートを受け取る"を選ぶ
  • "ポップアップ"を有効にする

という2つを行った。

f:id:dekuo-03:20200906215125p:plain

試しに、通話呼び出しをしてみたところ、ちゃんと呼び出されるようになった。(私の場合、呼び出し音はなくしているのでバイブレーションのみ)AQUOSフォン(私のモデルとは違う)を使っている周りの人も同じ設定変更で、ちゃんと呼び出しされるようになった。


4. 呼び出しされなくなった原因

はっきり言って、よくわからない。とはいえ、自分でいじった記憶もないし、周りの人も同じ反応であることを考えると、機種固有機能やソフトウェアアップデートによって、何らかの影響を受けているのではないかという気がしてならない。2であげた参考サイトに、AQUOSフォンでは高度なマナーモードという機能があって、それの影響をほのめかす記述があるのも気になる。とはいえ、LINE内の設定自体が影響を受けるのも考えにくいので、こちらはLINEのアップデートのせいかも?いずれにしろ、原因ははっきりしない。


まとめと今後の課題

LINEの通話呼び出しがされるようになった。とはいえ、もともと設定を変えた記憶がないので、もし本当に勝手に変わっていたとすると、納得がいかないなあ。


ソーラー発電式自動水やり器を作る(5) --- 無動作時消費電力の低減 ---

概要

自動水やり器の無動作時消費電力を低減させるための回路の変更を行い、無駄な消費が減ったことを確認した。


背景と目的

前回完成した自動水やり器だが、陽が落ちてソーラー発電がなくなると、意外と電池の電圧が下がるのが速いことに気づいた。そこで、消費電力を低減させるための回路の変更を行う。


詳細

1. 現状

以下が、ある日の電池電圧の低下の様子。日中よく晴れていたにもかかわらず、明け方には、最大値から0.4V程度下がってしまう。これだと、天候不順が続くと心配だ。

f:id:dekuo-03:20200831215922p:plain


2. 原因

現在の回路構成を調べたところ、

  • 土壌水分センサが無動作時も約5mA消費している
  • ポンプを駆動するリレーモジュールの一次側についているLEDが無動作時も点灯しており、約3mA消費している

ことがわかった。まあ、作っている最中からなんとなく気になっていはいたが、やっぱりそうだった。


3. 変更

3.1 土壌水分センサの電源供給をマイコンのGPIOでON/OFFする

以下が変更後の回路。トランジスタQ2,Q3によるスイッチを構成し、ESP32のIO12をHIGHにしたときだけ出力PWR_MOISTから土壌水分センサに電流が供給されるようにした。これにより、マイコンスリープ中は消費電力はほぼ0。ただ、マイコンでONしてから安定動作するまでのタイムラグを考慮して、ONから計測までの間に少しディレイを入れるように、マイコンのプログラムを変更しておいた。ちゃんと動作している。

f:id:dekuo-03:20200831214119p:plain


3.2 LEDを削除する

LEDは箱に入れてしまえば見えないので、ついていても付いていなくても変わらない。そこで、物理的に削除することにした。


4. 動作確認

変更後は、明らかに夜間でも電池の電圧が下がりにくくなっている。効果は十分あったといえる。※2ポイントだけやけに低い電圧値があるが、これは変更前の日のデータが混ざってしまった編集ミス。

f:id:dekuo-03:20200831215905p:plain


まとめと今後の課題

自動水やり器の無動作時消費電力を低減させることができた。これで悪天候が続いても安心だ。


ソーラー発電式自動水やり器を作る(4) --- マイコンソフトの製作、完成 ---

概要

前回に引き続き、マイコンソフトの製作を行い、システム全体が完成した。


背景と目的

前回に引き続き、マイコンソフトの製作を行い、完成させる。


詳細

1.主な仕様

やりたいことは以下。

  • 一定時間ごとに起動し、それ以外の時間はできるだけ消費電力を下げるためスリープする
  • 土壌水分センサ、BME280、水瓶の水位センサでそれぞれ計測を行う
  • 土壌水分センサの値が一定値を上回る=乾燥している場合、ポンプを動かす
  • ポンプを動かした場合には、IFTTTを使ってLINEに通知する
  • 水位センサで水瓶の水切れを検出した場合は、IFTTTを使って通知する
  • 起動ごとに、センサの計測値をIFTTTを使ってGoogleスプレッドシートに記録する


2.実装

具体的なコードは割愛するが、方法を大まかにメモ。

2.1 一定時間ごとに起動、動作完了後スリープ

この動きは、過去に作ったリモート水位センサと同じなのでそれに倣って、一定期間のディープスリープをすればOK。

dekuo-03.hatenablog.jp


2.2 土壌水分センサ、BME280、水位センサの計測

土壌水分センサはアナログ入力、BME280はI2C、水位センサはGPIOを読み取ればよい。BME280だけちょっと困ったのは、BME280があまりにもいろいろなところで使われているせいか、Arduino用のライブラリだけでやたらと数があること。何が決め手ということもないが、今回はスイッチサイエンスが公開しているものを使用した。

github.com

基本的に、サンプルコードと同じ流れなので特に変わった部分はないが、最初ちょっと違うサンプルを見ていてうまく動かず躓いた。I2Cをbeginして、bme280の初期設定をして、readTrimメソッドを呼ぶという手順を忘れない。

  // BME280初期化
  Wire.begin();
  bme280.setMode(
    BME280_ADDRESS, //I2C Address
    1, //Temperature oversampling x 1
    1, //Pressure oversampling x 1
    1, //Humidity oversampling x 1
    3, //Normal mode
    5, //Tstandby 1000ms
    0, //Filter off
    0  //3-wire SPI Disable
  );
  bme280.readTrim();


2.3 土壌水分センサの値が一定値を上回る=乾燥している場合、ポンプを動かす

アナログ入力の値を読み取って、基準よりも大きければ乾燥している。その基準をどこにするかだが、以下が販売元が公開している空気中と水中での値で校正する方法。まあ、とはいえ毎回校正できるわけではないので、生の値で適当に1つ基準を決めた。その値より大きい値であれば乾燥していると判断して、ポンプを動かす。ポンプは、GPIO出力を一定時間HIGHにするだけ。

wiki.dfrobot.com


2.4 ポンプを動かした場合には、IFTTTを使ってLINEに通知する

給水したら、LINEで通知を受ければちゃんと IFTTTを使ってLINEに通知するには、thisにWebhookチャンネルのRecieve a web requestトリガー、thatにLINEのsend a messageアクションを選択。ESP32からは、JSONボディを作ってWebhooksチャンネルのエンドポイントに投げればよい。WiFiだとか、HTTPSリクエストについては、Arduino-esp32のWiFiClientSecureライブラリのサンプルの通りやればよい。 通知内容は、

f:id:dekuo-03:20200828000317p:plain


2.5 水位センサで水瓶の水切れを検出した場合は、IFTTTを使って通知する

水切れについても、同様に通知すれば水瓶自体に給水するタイミングを知ることができて便利。 やり方は、2.4と同じ。

f:id:dekuo-03:20200828000332p:plain


2.6 起動ごとに、センサの計測値、電池電圧などをIFTTTを使ってGoogleスプレッドシートに記録する

電池電圧は、アナログ入力を読む。AD変換値と電圧の対応は回路構成から決まる。 これもIFTTTを使って、thisにWebhooksチャンネルのRecieve a web requestトリガー、thatにGoogleスプレッドシートチャンネルのAdd row to spreadsheetアクション。IFTTT連携の注意点として、Googleドライブ内のパスに日本語が入っているとうまくいかないので、日本語の入らないパスにシートを置く。シート名も日本語が入らないように。

以下のような感じで溜まっていく。センサ値がたくさんあるが、IFTTTのWebhooksチャンネルは一度に3種類までしか送れないので、センサ計測値、水やり実施有無、電池電圧に分けて記録。

f:id:dekuo-03:20200828000800p:plain


ここまでで全体が完成した。ソーラー充電を含めてちゃんと動くか、しばらく試運転していこうと思う。


まとめと今後の課題

自動水やり器が完成した。