chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

まんが入門「ゼロからわかるマンガの作り方」

できたらマンガを描きたいと思っている*1、画力の問題もあるが、ストーリーをどう作ったらいいのかについてまったく分からない。描き方の本はいろいろ出ているけど、ストーリー作りの方法がまったく分からず、Amazonでストーリーで検索すると、比較的評価の高い「ゼロからわかるマンガの作り方」があったので買ってみた。まだ1/3ぐらいしか読んでいないが、、下手でもいいから、まずネームを切れ!と書かれていて、「勘違い」をお題として2ページマンガを作るための手順が書かれていた。2ページなら見開きで8コマ〜12コマが標準らしい。それに倣って、自分も8行(結果は10行)で話を考えた。

  1. おばあさんとアンドロイドは遍路道*2を歩いている
  2. 歩くと道が二つに分かれている
  3. 看板があるが、誰かがいたずらしたのか、鳥の絵になっている
  4. おばあさんはアンドロイドを見るが
  5. アンドロイドは壊れているのかいつも通り喋らない
  6. 遍路マップを見るが電池切れだ
  7. おばあさんはしかたなく、マシな方と思える右側を選ぶ
  8. 歩いているとだんだん険しくなってくる
  9. もう引き返そうかと思ってると開けた場所に出た
  10. そこには「すずめのお宿」と傾いた看板が。。どうみてもワナだった。お宿から人影が見える

最初のネームは「顔まんが」でOKと書かれていたので、ネーム作りを最優先で作ってみた。左右見開きでコマを分割して、上記の各行をコマに割り当てる。割り当てると言いながら、一対一になっておらずずれている。
「21XX年のお遍路」
1ページ目

2ページ目

ネームに色をつけるものかどうかは知らないが、わかりやすい本のおかげで初めてネームができた。見開き2ページだったら失敗もないそうで、次は8ページを3時間で書くらしい。8ページとなるとさすがにもう少し話の広がりがないと無理だろう。小学生時代の、原稿用紙○枚書きなさいという宿題を思い出す。。

■ご参考

*1:自分のOFFの時間は大半Kindleでタダマンガを読んでいる

*2:なぜ遍路か?退職したら遍路に行ってみたいから

遠隔ベルの遅延を調査

もっさり遅い遠隔操作ベルの動作において、どこで遅延しているのかを調査
結論は以下:

  • 1 Clickボタンのクリックからリクエスト送信完了まで4秒かかっている(ボタンの仕様かと)
  • AWSサーバ内の処理は1秒以下

まず、自宅にある機器の時刻の精度がかなり低いのでNTP同期に変更
電波時計を会社に置いてきたので、ラズパイを時計代わりにする
ラズパイの設定:
JSTに変更

ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

NTP同期を有効化
file:/etc/systemd/timesyncd.conf

[Time]
NTP=ntp.jst.mfeed.ad.jp ntp.nict.jp
FallbackNTP=time.google.com

NTP同期有効化*1

timedatectl set-ntp true
systemctl daemon-reload
systemctl restart systemd-timesyncd.service
systemctl status systemd-timesyncd

ESP32側は以下でNTP同期にする

import utime
import ntptime

ntptime.settime()                 # 同期化
print(utime.localtime())        # 時刻表示

計測(自宅内の情報)
ほぼNTP同期しているとして、IoT 1 Clickのボタンを定刻にタイミングを合わせて押してみた。押した直後白点滅が数秒続き、緑点灯に変わって終了する。白点滅はおおよそ4秒かかっている。緑色は送信完了なんだろうと推測されて、ボタンの処理で最大4秒程度かかっているのでは?と推測される。サーバ側のログのタイムスタンプを調べるとサーバ側でいつリクエストを受け取っているか分かるはず

押下 LED:緑 uPy 表示
09:50:30 09:50:34 (2022, 7, 18, 0, 50, 35, 0, 199) (09:50:35)
09:52:00 09:52:04 (2022, 7, 18, 0, 52, 5, 0, 199) (09:52:05)

AWSサーバ側のログを確認
厳密にいうと、各ブロックごとに、リクエストの受信時刻、処理時間、リクエストの送信時刻で構成されるべきですが、そこまで詳細にログ取っていないので、受信時刻と送信時刻が混在しています。基本受信時刻ですが、AWS IoT Coreは送信時刻です。

AWS IoT 1 Click AWS Lambda
(called IoT 1 Click)
AWS IoT Core
reportedTime: 2022-07-18T00:50:34.903Z 2022-07-18T09:50:35.702+09:00 2022-07-18 00:50:35.897
reportedTime: 2022-07-18T00:52:05.092Z 2022-07-18T09:52:05.957+09:00 2022-07-18 00:52:06.164

数字だけだと分かりにくいので図式化(送信、受信の線の位置は不正確、遅延を表す”}nnn(ms)”を呼び出し側(送信元)につけていますが、送信元で時間がかかったのか受信側で時間がかかったのか、切り分け未実施)(資料上、ワナが多すぎますかね)。

もっさりの一番の原因はボタンが押されてからリクエストをサーバの送り終わるまでが約4秒かかっており、これが一番の原因。本来1 Clickボタンは、洗剤とか空になりそうになったらボタンを押して発注するためのものなので、リアルタイム性はそれほど求められていないと思う。1 Clickボタンは電池交換ができないので、長期間放置しておいても安定して動作することが優先され、省電力に重点が置かれていると思う。。。多分*2。一方課題と思ったのは、AWS IoT 1 ClickからLambdaのリクエスト受信までが799msecかかっている。Lambdaの起動に時間がかかっているためかと思うが、、AWS内の単純な処理で799msecというのはかなり致命的な印象。使い方を間違っているのかもしれませんが。。リージョンを間違って海外に作った?? リクエストを中継しているだけなのに、処理時間:799msecは仕事だったら許されないだろう。。趣味だから放置
ログから単純に計算すると、AWSサーバ内の処理は994msecかかっている。ボタンクリックからリクエスト投げるまでにボタン~サーバ間で4秒なので、押してから動くまで最低5秒かかる計算。Lambdaの件はおいといて、、4秒遅延は1 Clickのボタンの仕様だからしょうがないかと。

■補足
AWS IoT Coreのログ

2022-07-18T09:50:35.897+09:00
{
    "timestamp": "2022-07-18 00:50:35.897",
    "logLevel": "INFO",
    "traceId": "86146418-bff3-56de-d572-7c5d26dd3844",
    "accountId": "36xxxxxxxxxx74",
    "status": "Success",
    "eventType": "Publish-Out",
    "protocol": "MQTT",
    "topicName": "req/upk/esp32_01",
    "clientId": "esp32_01",
    "principalId": "6bdbcf28690556bba8c6eb89096ea1dc640ad39721faa4517ef130d76c2ba5b5",
    "sourceIp": "121.118.xxx.xxx",
    "sourcePort": 62xxx
}
2022-07-18T09:52:06.164+09:00
{
    "timestamp": "2022-07-18 00:52:06.164",
    "logLevel": "INFO",
    "traceId": "80c69fd1-5bd8-f43c-e312-518ad947d5ba",
    "accountId": "36xxxxxxxxxx74",
    "status": "Success",
    "eventType": "Publish-Out",
    "protocol": "MQTT",
    "topicName": "req/upk/esp32_01",
    "clientId": "esp32_01",
    "principalId": "6bdbcf28690556bba8c6eb89096ea1dc640ad39721faa4517ef130d76c2ba5b5",
    "sourceIp": "121.118.xxx.xxx",
    "sourcePort": 62xxx
}

■追記
単純にLambdaの起動が遅いと書いたけど、計測点が少なく、1-Clickからのリクエスト送信が遅いのか、Lambdaの受信が遅いのかまでは切り分けができていない。1-Clickはボタンからのリクエストを受け取った後、Lambdaをキックするので、その遅延があるのかもしれない(なんだか1-ClickってAWSコンソールも閑散とした印象だし)。切り分けるには、EC2等の常時稼働サーバを立てて、起動オーバーヘッドがない状態と比べる必要があるのかも。しかし、1-ClickはEC2とは連携できないので、、SNSにリクエストを飛ばして時間測るぐらいか。

■追記
処理時間(遅延?)についてもう少し調べたいと思い、、以下の2種類を調べることにした。

AWS IoT 1-Click ----> SMSのタイムスタンプ
EC2-------> Lambda のタイムスタンプ

AWS IoT 1-Clickは受けたイベントをトリガーとしてSMSに飛ばすことができる。ProjectでActionsをSMSに設定してテスト実施、ボタンクリックは、13:07:10で、AWS IoT 1-Clickがイベントを受け取ったのは、13:07:14.449となった。SMSの送信ログは、04:07:15.983。だから、IoT 1-Clickがイベントを受け取ってからSMSが送信するまで、1.534秒かかっている。遅すぎてこれは考察に使ってはいけない気がする*3。あとできることとしては、、EC2のインスタンスからLambdaをキックするのにかかる時間を測ってみるぐらいか。。

AWS IoT 1-Click log SMS Log
reportedTime: 2022-07-18T04:07:14.449Z timestamp:2022-07-18 04:07:15.983


SMSの送信ログ

    "notification": {
        "messageId": "2ec46837-8dfb-587a-ae88-337953484809",
        "timestamp": "2022-07-18 04:07:15.983"
    },

EC2を立てて、以下のプログラムでLambdaを起動して時間を測った

#!/usr/bin/python3
import boto3
import json
import datetime
client = boto3.client('lambda',region_name="ap-northeast-1")

FUNCTION_NAME = "aws_iot_one_click"

message = bytes(json.dumps({"var1" : "value of var1", "var2" : "value of var2"}),"UTF-8")

print("start")
print(datetime.datetime.now())
response = client.invoke(
            FunctionName = FUNCTION_NAME,
            InvocationType = 'RequestResponse',
            Payload = message
)

print("end")
print(datetime.datetime.now())
res = response['Payload'].read()
print(res)

アプリ側の表示は以下、リクエストが完了するまでの時間は、246msと良い値。

$ ./test.py 
start
2022-07-18 05:10:00.386224
end
2022-07-18 05:10:00.633187
b'{"statusCode": 200, "body": "\\"Hello from Lambda!\\""}'

CloudWatchよりLambdaがキックされた時刻は以下

2022-07-18T14:10:00.435+09:00

前回の図はいろいろ言い訳付きで書きましたが、自分の理解整理もかねて、分かっている所、分からない所を極力正確に表現すると以下

Pythonプログラム側で発生するAPI呼び出しの時間、Lambda起動時間、それぞれ単体の時間は測れませんが、プログラムからLambdaの関数を呼び出して、Lambdaが動き始めるまで49msecで収まっているのが分かります。だからまぁLambdaの起動にかかる時間はほぼ無視していいオーバーヘッドかと。。多分。。細かいことを言い出すと、全く使っていない状態からの初期実行と、連続使用状態でまた時間が変わるとか。。うーん。。

Lambdaのオーバーヘッドは2桁msecなのでほぼ無視してよいとなると、、IoT 1-ClickからLambdaが呼び出されるまでの遅延はIoT 1-Clickから出てくるのが遅いということになる。あるいは、、操作ミスしてIoT 1-ClickのEndPointを遠くのリージョンに作ってしまって、IoT 1-ClickとLambdaのネットワーク的な距離が異常に離れているとか。。

*1:参考にした記事:Raspberry Pi(Raspbian)にやっといたほうがいい設定(運用:NTPでの時刻合わせ) 感謝

*2:WiFiブロックは普段止まっていて、ボタン押されてからWiFiが動き出して、IPを取ったりしてるのだろうと思う

*3:あとから分かったのだが、SMSと連携する場合も一旦Lambdaを経由している。裏側で新しいLambda関数が作られそれをキックしている。今回の場合、iot1click_onclick_sms_20220718123611という関数が作られている。だから、、SMSのタイムスタンプで処理時間を考察するのは意味がない

AWS IoT Core等を活用して遠隔操作できるベルを作ってみる

前から作りたいと思っていた、MQTTで制御できるベルを作ってみる*1。使うものは、IoT 1 Clickボタン、ESP32、サーボ、ベル。これらをAWS IoT Coreを使って接続して、IoT 1 Clickを押すとベルが鳴るというもの。
以下はIoT 1 Click(IoT Enterprise)ボタンで、AWS IoT 1-Clickサービスにメッセージを送ることができる。送信されるメッセージの内容は後半ご参照ください。

以下は100均で買った卓上ベル。上のボタンを押すとベルの内側のハンマーがベルを叩いて一回鳴る。結構音が大きい。

AWS IoT Coreを使って接続するので、IoT 1 Clickボタンでなくても、MQTTにPublishできるコマンドからベルを鳴らすのも可能
アーキテクチャは以下

1 Clickボタンの受け側がIoT Core風のAWS IoT 1-CLickなので、そのままESP32にPublishしたらよさそうなものですが、1 Clickボタンからのイベントを受けてるIoT 1-Clickの仕様がよくわからないので、教科書通りにLamdaを介してIoT CoreにPublishしています。(AWS側のポリシィとして、IoT 1 Clickのバックエンド側(AWS内でのサーバ群)は、IoT Coreとしては使わせない設計と思われる。似ているからといって、そもそもMQTT/IoT Core使ってるかどうかも不明ですし)

バイスセットアップ:
スマフォにアプリ(AWS IoT 1-Click)を入れて、AWS IoT 1Clickデバイスをセットアップする
‎AWS IoT 1-Click on the App Store
やることは、スマフォからBLE経由でAWS IoT 1 Clickに接続して、1Clickのファーム更新とWiFi設定をする。
アプリからデバイス登録もできるのか?と思ったが、登録は行えないようだ*2
IoT 1 Clickの設定:
AWSコンソール(アジアパシフィック)から、1-ClickのデバイスID(DSN: Gnnnn)を打ち込んで登録した。
https://ap-northeast-1.console.aws.amazon.com/iot1click/home?region=ap-northeast-1
アカウントに正しく紐づけできると、AWS IoT 1-Clickのコンソール画面から、Manage>Devicesでたどると、登録したAWS IoT 1 Clickが表示される。デフォルトではDisableなのでEnableに変更する。
1-Clickをクリックすることで何か仕事をさせたい場合は、Projectを設定してProjectに連携内容を定義する。
Manual等しっかり読んでいないので多少ええ加減だが、ProjectはTemplateとPlaceの2種類あって、Templateだけ定義しただけでは、デバイスと処理が紐づかず、Placeで定義することで、デバイスと処理(Lambdaのキック等)が紐づく。

DeviceのEventログには以下のような記録があり、デバイスからはこういった情報が送られるのだろう。。MQTT?HTTP??プロトコルの詳細は分からないが。

{
  "device": {
    "type": "button",
    "deviceId": "G030xxxxxxxxxJPG7",
    "attributes": {},
    "deviceArn": "arn:aws:iot1click:us-west-2:365701690774:devices/G030xxxxxxxJPG7"
  },
  "stdEvent": {
    "clickType": "SINGLE",
    "reportedTime": "2022-07-17T06:22:56.366Z",
    "certificateId": "11272168e9a6b8fedc55f051e788eb161fc90a5370df0c888f0a92c5fcab017a",
    "remainingLife": 97.95000000000023,
    "testMode": true
  }
}

AWS Lambdaの設定(関数定義)
Lambdaには、素の関数を定義して、どのような値が渡されるのか引数を確認 (function名:aws_iot_one_click)

import json

def lambda_handler(event, context):
    # TODO implement
    print(event)
    print(context)
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

引数eventに渡される値は以下であった

>||
{
  'deviceInfo': {
     'deviceId': 'G030xxxxxxJPG7', 
     'type': 'button',
     'remainingLife': 97.8,
     'attributes': {
        'projectRegion': 'ap-northeast-1',
        'projectName': 'ringBell',
        'placementName': 'UPK_2F',
        'deviceTemplateName': 'G030xxxxxxxxJPG7'
     }
  },
 'deviceEvent': {
     'buttonClicked': {
         'clickType': 'SINGLE',
         'reportedTime': '2022-07-17T06:59:21.544Z'
      }
  },
 'placementInfo': {
    'projectName': 'ringBell',
    'placementName': 'UPK_2F',
    'attributes': {
       'UPK Room': '2F'
     },
     'devices': {
        'G030xxxxxxxxJPG7': 'G030xxxxxxxJPG7'
     }
   }
}

バイス情報に、プロジェクト情報や場所情報をくっつけてLambdaを呼んでくれているようだ。だから、どの家のどの部屋にあるボタンか?が分かると。
今は1 Clickボタン一つしかないので、デバイスの識別はせずに、Clickイベントがあれば、BELL鳴らすためのmessageをIoT CoreのTopicにPublishする。Publishはboto3を使って行えるようだ。これまでAWS IoT Coreを試作してきたが、場当たり的でTopic/messageの設計がええ加減だったので多少整備する。ベストかどうか全くわからないが、、とりあえず以下
Topic:

reg/<place>/<device_name>    ....制御等の要求
rep/<place>/<device_name>    ....センサ等のレポート

メッセージ:

{
   msg_type :  request | report ,
   request:  <request_string> ,
   report :  <data>
}

ベルを鳴らしたい場合は、、

Topic:  req/upk/esp32_01
Message:
{
   msg_type: request
   request:  ring_bell
}

(String型のダブルクオート省略しています)
AWS IoT Coreに投げるため、Lambdaは以下のように定義

import json
import boto3

TOPIC = "req/upk/esp32_01"

def lambda_handler(event, context):
    # TODO implement
    print("called IoT 1 Click")
    print(event)

    iot = boto3.client('iot-data')
    payload = {
        "msg_type" : "request",
        "request" : "ring_bell"
    }
    iot.publish(topic=TOPIC, payload=json.dumps(payload))

    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

このままだと権限違反でIoT CoreにPublishできなので、LambdaのメソッドにIoT Core Full Accessを付けました
(本当はFullAccess許可ではなく、Publishのみにすべきですが、、まぁ個人のテストなので)

ESP32側はおおよそ以下のソースでAWS IoT Coreと接続できる

from umqtt.simple import MQTTClient
import json

ENDPOINT = b'axxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com'
ID = 'esp32_01'
TOPIC = "req/upk/esp32_01"

KEYFILE = '/certs/private.pem.key'
CERTFILE = "/certs/certificate.pem.crt"

def _cb(topic, msg):
    print("-------- call back ----------")
    print(f"topic:{topic}")
    print(f"msg:{msg}")
    print("-----------------------------")

with open(KEYFILE, 'r') as f:
    key = f.read()

with open(CERTFILE, 'r') as f:
    cert = f.read()

# SSL certificates.
SSL_PARAMS = {'key': key, 'cert': cert, 'server_side': False}
client = MQTTClient(client_id=ID, server=ENDPOINT, port=8883, ssl=True, ssl_params=SSL_PARAMS)

client.set_callback(_cb)
client.connect()
client.subscribe(topic=TOPIC)

while True:
   print("---loop---------------")
   client.wait_msg()

AWS IoT Coreの設定:
AWS IoT Coreでやるべきは、、Policy設定、デバイスの登録と証明書発行である。面倒だったら全部許可のPermissionを紐づけた証明書を発行すれば権限違反でエラーになることはない。動作確認した後で権限を最小にすると。。
後から権限を狭める前提で、、、試作段階では以下のように全許可のPolicyを作成
Policy_name: all_permit_policy

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "*",
      "Resource": "*"
    }
  ]
}

バイス登録の際に、Key(秘密鍵、公開鍵)とCert(Client証明書)が作成されるので、これをDLしてES32に入れる(秘密鍵とClient証明書が必要)。上記のソースをREPLに貼り付けて実行
IoT 1 Clickのボタンを押すと、ESP32のMicroPythonのREPLに以下が表示された。これで、ESP32までは疎通できた。

---loop---------------
-------- call back ----------
topic:b'req/upk/esp32_01'
msg:b'{"msg_type": "request", "request": "ring_bell"}'
-----------------------------

あとは、、サーボ制御を作って、サーボのアームを回してベルを押下させる処理を追加する。また、、一定時間経過後、アームを上げる必要がある。一定時間後ってのがまた面倒だが、、メインループがあるので、時間比較して、アームを戻す処理を追加するか。

MicroPythonの公式ドキュメントにPWMによるサーボ制御サンプルがあるので、これを参照
7. パルス幅変調 — MicroPython 1.19.1 ドキュメント
なお、、サーボのケーブルのうち、赤:+、茶:GND、黄色:信号、らしいので、赤は5V、茶は0Vに接続、黄色は、GPIO12に接続
コードは以下(公式ドキュメントで紹介された角度の最大・最小値とは少しずれており、34-110の幅で制御する)

#
# Remote Bell system w/ ESP32 + AWS IoT Core (20220717)
#
from umqtt.simple import MQTTClient
import machine
import utime

SERVO_PIN = 12
ARM_MIN = 34
ARM_MAX = 110

ENDPOINT = b'axxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com'
ID = 'esp32_01'
TOPIC = "req/upk/esp32_01"

KEYFILE = '/certs/6bb5.priv'
CERTFILE = "/certs/6bb5.crt"

servo = machine.PWM(machine.Pin(12), freq=50)
servo.duty(ARM_MIN)

def _cb(topic, msg):
    print("-------- call back ----------")
    print(f"topic:{topic}")
    print(f"msg:{msg}")
    print("-----------------------------")
    servo.duty(ARM_MAX)
    utime.sleep(0.3)
    servo.duty(ARM_MIN)

with open(KEYFILE, 'r') as f:
    key = f.read()

with open(CERTFILE, 'r') as f:
    cert = f.read()

# SSL certificates.
SSL_PARAMS = {'key': key, 'cert': cert, 'server_side': False}
client = MQTTClient(client_id=ID, server=ENDPOINT, port=8883, ssl=True, ssl_params=SSL_PARAMS)

client.set_callback(_cb)
client.connect()
client.subscribe(topic=TOPIC)


while True:
   print("---loop---------------")
   client.wait_msg()

AWS IoT 1 clickボタンを押すとIoT Core経由でESP32に接続されたサーボが動くところまでは確認できた。あとは、アームとベルの位置を調整して、ベルのボタンを押せるようにすれば、鳴るはず。。機構の調整が面倒だ。
カムとかの機構を作るのはやったことなく、工具や部材もないので、アームに金属類をぶら下げて、アームをぐるっと回して金属部で叩くようにした。収まり感が非常に悪いが、鳴ることは鳴る。以下は出来上がったシステム全景(収まり感わるし)

ビデオ撮りました。応答速度等ご参考に。手間かかった*3割には取れ高少ないです。。
www.youtube.com
もっさり遅いので、どこで時間かかってるのか調べるつもりです。もっさり感に加え、サーボのギアの音が結構でかくて、ベル鳴らすまでもないという感じです。

■追記
試作段階では動くことを優先してIoT CoreのPolicyを全許可にしていた。動作確認できたので、少し権限を絞る。今は以下のPolicyを利用

  • 接続許可デバイス名:esp32_01
  • サブスクライブ許可トピック:req/upk/esp32_01
  • 受信許可トピック:req/upk/esp32_01
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:ap-northeast-1:36xxxxxxx74:client/esp32_01"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Subscribe"
      ],
      "Resource": "arn:aws:iot:ap-northeast-1:36xxxxxxxx74:topicfilter/req/upk/esp32_01"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Receive"
      ],
      "Resource": "arn:aws:iot:ap-northeast-1:36xxxxxxx74:topic/req/upk/esp32_01"
    }
  ]
}

■参考URL
mqtt simple2のサンプル
micropython-umqtt.simple2/example_sub.py at master · fizista/micropython-umqtt.simple2 · GitHub

*1:ビルドが終わるとベルで知らせてほしい

*2:後から分かったのだが、まずProjectを設定して、Projectにデバイスを紐づける流れになるようだった。Documentとか読んでいないので、Projectありきというのが分からなかった

*3:過去の試作を流用しつつ、休み休みで4~5Hぐらいか

Blender勉強中

Blenderで3Dキャラクタを作りたいと思っていて、本屋に見に行ったがどれも非常に手間暇かけた手順が多かった。その中で、比較的簡単に作っている本があったので買ってみた(今からはじめるBlender3)。頭の3Dモデルなんか簡単そうに作ってるけど、なかなか本のようにはいかない。いじってるうちにどんどん違うキャラクターになっているという。。

自分で作った3DキャラクタでVR-Charに行ってみたいが、このモデルで行くと驚かれるだろう。。しかもMeta Quest2の場合、表示できるポリゴン数がかなり少ないようなので、そもそも着れないかもしれない。

RaspberryPi Pico W

WiFi機能付きのPicoが出て、機能的にはESP32とほぼ同等になったのではないか

Raspberry Pi Pico – Raspberry Pi
Raspberry Pi Documentation - Raspberry Pi Pico and Pico W
https://datasheets.raspberrypi.com/picow/connecting-to-the-internet-with-pico-w.pdf
https://datasheets.raspberrypi.com/picow/PicoW-A4-Pinout.pdf

Picoと同様に、MicroPythonが動くようで、WiFiについては、
仕様書「Connecting to the Internet with Raspberry Pi Pico W」
3.6. Connecting to a wireless network
より、以下のコードで接続できるらしい。

import network
import time

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect('Wireless Network', 'The Password')

while not wlan.isconnected() and wlan.status() >= 0:
print("Waiting to connect:")
time.sleep(1)

print(wlan.ifconfig())

ESP32とほとんど同じ表記と思われる。
WiFiを使いたい場合は、pico-w用ファームを使う必要があるのでは?と思われ、Nightly Buildのみの状況のようです。
MicroPython - Python for microcontrollers


CircuitPythonはPicoに対応したバージョンが以前からリリースされているが、WiFi対応になっているのかどうか不明
多分、、pico-w用のCircuitPythonがリリースされるのではなかろうか。
Raspberry Pi Pico WH - Pico Wireless with Headers Soldered : ID 5544 : $7.00 : Adafruit Industries, Unique & fun DIY electronics and kits

memo
PyPI · The Python Package Index

作りかけて放置したFlutterアプリをもう少し作る(スマートメータ表示アプリ)

昨日、定年サポートアプリを久しぶりにビルドして、スマフォアプリももうちょっと作り込まないとなーと思ったので、作りかけで放置してたFlutterによる電力データ表示アプリをもう少し仕上げることにした。

前回のアプリの実装状態

作り込みたい機能
1. スマフォアプリを起動したら電力値がMQTTで配信開始されるようにする(自動化が難しかったらボタン押下)
2. 最新データ取得機能(待ってられない場合に、更新ボタンを押したら最新の電力データがグラフに反映される)
3. スマフォからのアクセスがなくなったら、MQTTによる配信を自動で止める

経緯
かつて、自宅のメータをスマートメータに変えて、電力データを取れるようにNature remo E Liteを入れて、AWS LambdaからNature社のWebAPIを叩いて自宅の電力データを取得して、AWS IoT Coreを使ってMQTTで配信してスマフォで見るところまでは作った。
が、、ビジュアルに訴えるにはサンプリング周期を30秒程度で行う必要があり、ずっと30秒で上記経路を動かしているとお金がかかってしょうがない。だから、1時間周期でCRONで走らせて積算値をS3に蓄える*1以外、MQTT配信は止めていた。スマフォで見たい時だけ30秒周期のCRONを走らせてMQTT配信して、見たくなくなったらCRONを止めるというあり得ない仕様であった。利用者にMQTT配信のOn/Offをさせるのではなく、スマフォアプリの接続状態を感知して自動で配信のOn/Offするように仕込みたい。

■追記
久しぶりにFlutter動かそうと思ったらどうやってビルドしていたか、テストはEmulatorだったか実機だったかも忘れた。普段Flutter使っていたら当たり前のことだけど、時間が経つと当たり前の知識が消失している。暗黙知(俺)というやつか。暗黙知は時間が経つと消えてしまう。だから、、当たり前でもビルド手順とかインストール手順とかはメモに残すか、batch でシェル化しておかないと思い出せない。Terminalのhistoryコマンドでも当時の操作記録は古すぎて出てこないだろう。。

■追記
iOSのshellでgrepしてみた。当時の操作履歴が残っていた。なるほど、、こういうコマンドだったか。。
(理解しやすくなるよう上下入れ替えています)

$ history 0 | grep flutter
   67  flutter emulators
   69  flutter devices
   84  flutter build
   85  flutter build ios
   68  flutter emulators --launch iOS
   73  flutter emulators --list
   74  flutter emulators 
   70  flutter run -d iPhone
   75  flutter run --release

iPhoneMacに接続した状態で、command historyを頼りに以下を実行した。

flutter run

iPhoneには画面が表示されて、AWS IoT Coreには接続できた(Client証明書も生きてるようだ)

利用者の立場では困惑しかないだろうが、定期収集のCRONをユーザがOn/Offする仕様で実装。以下がCRON制御付きの画面(update, start , stop のボタンが増えている)

本来、これらの操作は自動化できるはずなので、今後改定する

テストしている際、IoT Coreに接続できない時があり以下のエラーが出る。エラーメッセージが、Failed host lookupなので、ホスト名が解決できないか、ホストに到達できないような言いぶりだ。なぜだろうか。エラーになる前にすでに先方から怒られているような。。

flutter: 1-2022-07-10 16:23:35.769250 -- MqttConnectionKeepAlive::pingRequired - restarting ping timer
flutter: 1-2022-07-10 16:23:35.948536 -- MqttConnectionBase::_onError - calling disconnected callback
flutter: *** in fail ***
flutter: SocketException: Failed host lookup: 'a3xxxxxxxt-ats.iot.ap-northeast-1.amazonaws.com' (OS Error: nodename nor servname provided, or not known, errno = 8)
flutter: 1-2022-07-10 16:23:35.968145 -- MqttConnectionHandlerBase::disconnect - entered
flutter: 1-2022-07-10 16:23:35.970955 -- MqttConnectionHandlerBase::_performConnectionDisconnect entered
flutter: 1-2022-07-10 16:23:35.980196 -- MqttConnectionKeepAlive::stop - stopping keep alive
flutter: *** disconnected ***
flutter: Subscribing to the topic:[topic_1]
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: mqtt-client::ConnectionException: The connection must be in the Connected state in order to perform this operation.
#0      MqttClient.subscribe (package:mqtt_client/src/mqtt_client.dart:345:7)
#1      _MyHomePageState._connect (package:awsiot/main.dart:182:12)
<asynchronous suspension>

原因は、スマフォ内でWiFiと正常に接続できない状況になっていたため。電波をつかんでいるアイコンは出ているが、アプリによるのか、疎通できない場合がある。スマフォのWiFiをOff/Onしたら正常化した

IoT Coreに向けてMQTTで topic: viewer/requestで投げると IoT CoreのMessage RoutingのruleにマッチしてLambdaがキックされるようにした。Lambdaは以下のような内容で、1分定期CRON(execute_every_1min)のOn/Offを制御できるようにした。On/Offを手動で操作しないといけないのがなんともイマイチだけど、スマフォからできるようになったので、今日のところはここまで

import json
import boto3
client = boto3.client('events')
RULE_NAME = 'execute_every_1min'

def lambda_handler(event, context):
    global client
    
    # TODO implement
    print("----!!!!-------")
    print(event)
    # 
    if event['msgType'] == 'request':
        if event['request'] == 'start_CRON':
            print('going enable')
            client.enable_rule(Name=RULE_NAME)
        elif event['request'] == 'stop_CRON':
            print('going disable')
            client.disable_rule(Name=RULE_NAME)
            
    return {
        'statusCode': 200,
        'body': json.dumps('Hello from Lambda!')
    }

MQTTで電力データを表示、CRONをOn/Offするフローまとめ

<CRON On/Off>
[SmartPhone]--(pub)-->[IoT Core]--(Route)-->[Lambda]--->[EventBridge]

<Report>
[EventBridge]-->[Lambda]  [Nature API]   [IoT Core]     [SmartPhone]  
                   |--------->|             |               |
                   |<---------|             |               |
                   |----------------------> |               |
                                            |----(pub)----> |

Flutter CLIメモ

% flutter build ios     // release版のビルド
% flutter install        // iPhoneへのインストール

■課題
安定してMQTTブローカと接続できない印象で、本当にCRON制御できているか、かなり不安なので、状態報告機能を強化したい。このままでは任せられない。

*1:データレークというやつでしょうか

Blender. Low polygon modeling

Youtubeの動画を見ながら頭部のモデリングをやってみる。ロボット風にするのか、ある程度リアルにするのか、やりながら分からずにやっている。いちど頭蓋骨をスケッチした方がいいのか。。このモデルは今後どうなるのだろうか。。終着点も分からず。(ボーンを入れたら表情を作れるのだろうか。。)

Blender 3D Tutorial: Absolute Beginner Poly Editing Modeling for a Basic Head. - YouTube
胴体のモデリング(エディットモード)(その2) < モデリング < 簡単な3DCGの制作 | Blender入門(3.0 / 3.1 / 3.2版)