工作と競馬

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

カテゴリ: 11.電子工作(IoT)

Raspberry piで、scipyをインストールしたとき、

sudo apt-get install scipy

だと、0.18.1がインストールされる。

しかし、バージョンが古いので、

sudo pip install scipy --upgrade

をやるが、途中で止まる???

と思ったが、単に時間がかかっているだけで、1.5時間後くらいに、以下の表示が出て終了した模様。

Successfully built scipy
Installing collected packages: scipy
  Found existing installation: scipy 0.18.1
    Uninstalling scipy-0.18.1:
      Successfully uninstalled scipy-0.18.1
Successfully installed scipy-1.1.0

念のため、バージョンを確認のため、

import scipy
scipy.__version__

をすると 、無事1.1がインストールされていた。

ちなみに、pandasについても同様で、

sudo pip install pandas --upgrade

で時間はかかるが、ちゃんとインストールされた。

概要

AWSのGreengrassを使い、遠隔でGPIOを操作しLEDの点滅ができた。


背景と目的

先日のGreengrass使い始めに続き、ドキュメントに沿っていろいろ試したところ、遠隔でエッジのLambda関数をトリガする方法もわかった。また、エッジのローカルリソース(ドライブや、シリアルポート、GPIOなど)にもアクセスできるとの記述がある。そこで、Raspberry PiのGPIOを遠隔で操作してみることにした。


詳細

0.参考資料

AWSドキュメント内の以下URLを参考にした。GPIOにアクセスできるとの旨が書いてある。

https://docs.aws.amazon.com/ja_jp/greengrass/latest/developerguide/access-local-resources.html


1.Lambda関数

Lambda関数は、基本的にRaspberry Pi上でGPIOをいじるときと同じコード。

# coding:utf-8
import sys
import greengrasssdk
import RPi.GPIO as GPIO
import time
import platform
import os
import logging

# Create a Greengrass Core SDK client.
client = greengrasssdk.client('iot-data')

# GPIOの設定
GPIO_NUM = 4
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_NUM, GPIO.OUT)

def function_handler(event, context):
    try:
        client.publish(topic='LRA/test', payload="Sent from AWS Greengrass Core.")
        GPIO.output(GPIO_NUM, GPIO.HIGH)
        time.sleep(1)
        GPIO.output(GPIO_NUM, GPIO.LOW)
        time.sleep(1)
    except Exception as e:
        logging.error("Experiencing error :{}".format(e))
        client.publish(topic='LRA/test', payload="Experiencing error")
    return


2.リソースの設定

Greengrass>グループ>リソースで、/dev/gpionumというリソースに対して、Lambda関数がアクセスできるように設定した。

リソース


3.サブスクリプションの設定

以下2つを設定した。IoT Cloud側からLRA/test/triggerトピックに、送信することで、Lambdaが呼び出せる。

  • "LRA/test/trigger"トピックをIoT Cloud ⇒ Lambda関数で設定
  • "LRA/test"トピックをLambda関数 ⇒ IoTCloudで設定


4.テスト

以上の設定で、Greengrass CoreにLambdaをデプロイし、IoT Cloud側からLRA/test/triggerトピックにメッセージを送信した。ところ、GPIO4に接続したLEDが1秒間光り、"LRA/test"トピックに、Lambdaからのメッセージが来た。正しく、Lambdaが呼び出せている。


まとめ

AWSのGreengrassを使い、遠隔でGPIOを操作しLEDの点滅ができた。

概要

フルカラーのLEDアレイを作ることにした。今回は、設計を行った。


背景と目的

とある事情で、LEDアレイを作成することになった。まず、仕様を決め、設計する。


詳細

1.仕様

LEDアレイは、各種製品が電子部品屋で売っているのでそれを使えばいいはずなのだが、

  • 5Vのモバイルバッテリーで駆動
  • 取り付け先の寸法にきっちり合わせる必要がある
  • 安く

という仕様を満たす必要があるため、いちいち自作が必要になってしまった。


2.設計

いろいろ悩んだ挙句、

を使うことにした。回路図は以下。5Vで各LEDに約15mAが流れるように抵抗を設定。各色のLEDをスイッチングするトランジスタを用意。

回路図

基板上の実装パターンは、以下。これを12個分繰り返す。基板上に、角型フルカラーLEDを配列して実装する。はんだ付け箇所が多くてめんどくさそうだが、仕方ない・・・。

橙が5V、R、G、Bがそれぞれ信号線で、トランジスタのコレクタに接続する。トランジスタはArduinoなどで駆動する予定。そちらの設計はこれから。

配線図

まとめ

フルカラーLEDアレイの設計ができた。次は実装する。

概要

人が近づいたら、サーボモータで壁の照明スイッチを無理やり操作するシステムを製作した。


背景と目的

最近、引っ越しをして住み始めた家では、階段の照明をよく消し忘れる。その結果、一日つけっぱなしという無駄を何度も発生させてしまっているので、改善したい。王道として思いつくのは、人感式の照明に付け替えることだが付け替えるお金をかけたくないのと、引っ越し後工作をしていないせいで無駄でもいいから何かしら工作をしたいという欲求が抑えられないため、消し忘れても自動で消えるシステムをわざわざ作ってみる。


詳細

1.方法の検討

問題の電灯は、階段の2階側と1階側にそれぞれ壁スイッチがあり、押すごとに点灯/消灯が切り替わる。そこで、これを無理やりサーボモータで押すという力技が思いつくが、実は、以前同システムを作ったのでまさにそれが流用できそうである。ただ、そのシステムはIoT系の工作でGoogleHomeから呼び出して動かすものであったが、今回はネット経由で操作する必要はないので、人感センサでトリガしてあげるように変更する。(なんだか、IoTから退化した感じで微妙だが使い道を考えると仕方ない)


以前作成したシステム

DSC_0237


2.設計

ハードウェアは、すべて手持ち品のArduinoNano互換ボードと、人感センサSB412A、サーボモータSG-92Rを組み合わせで間に合わせた。また、壁スイッチは点灯/消灯の状態を知ることができないので、明るさセンサで状態を知る必要もありそうだ。

というわけで、以下のような回路にした。SB412Aが2つあるのは、私の家の階段が途中で折れ曲がっており、1つでは階段全体が検出範囲に入らないためである。SB412Aの出力レベルはArduinoNano互換ボードと厳密には合わないがちゃんとHIGH状態が読み取れたので気にしないことにした。明るさセンサはCdSとし、直列抵抗との分圧点をセンサ出力としてアナログ入力端子に接続。

20180927233430


3.プログラム

非常に簡単なので、コードは割愛するが、おおざっぱに言って、

  • 2つの人感センサ出力のORがTRUEで、暗い場合、サーボモータを動かす
  • 2つの人感センサ出力のORがFALSEで、明るい場合、サーボモータを動かす

だけ。1秒周期で上記ロジックを実行する。ただし、人感センサは1度検出すると30秒程度HIGHが持続するようにしている。サーボモータの駆動は標準ライブラリのServo.hを使用。


4.実装

以下が実装した図。見た目は全然気にしていないので、いずれ家族からクレームが出そうだが、所望の動作はしている。2つの人感センサはそれぞれ1階と2階の階段の初段付近に設置。明るさセンサは2階側の人感センサと並べて設置。

DSC_0571


まとめ

それなりに実用的なシステムができた。今後は見た目をまともにして生活空間に溶け込ませたい。

概要

KiCadとFusion PCBで基板を作ってみた。


背景と目的

KiCadとFusion PCBで基板を作りたくなったので、やってみる。


詳細

0.方針

KiCadの使い方は、Web上にたくさんあるし、本も出ているのでそれを参考にするとして、とりあえず作ってちゃんとうごいたという記録をする。なお、手元にこちらの本があるので参考になった。


1.KiCadで設計

今回作成するのは、ESP-WROOM-32を使った簡単なダッシュボタンとする。

  • ESP-WROOM-32
  • 単3乾電池2本で駆動
  • ボタンは3つ

いきなりだが、作成した回路は以下。ESP-WROOM-32の部品データは、Web上に転がっていると思ったが、意外と見つけるのに苦労したので結局自分で作った。

少し説明しておくと、

  • J2、J4はジャンパ接続部だが、接続した状態でボタンを操作することで、EN、IO0のレベルが変化し、プログラム書き込みモードに入ることができるようになっている。
  • ボタンを押したときにL→Hとなるようにし、スリープ解除トリガになるようにしている。

という感じ。

sch

基板レイアウトは以下。基板設計の知識はないので、見様見真似だが、一般的注意は守ったつもり。

手はんだを想定しているがESP-WROOM-32モジュールの高さ以下で押さえたいので、トランジスタ、コンデンサなどの部品は表面実装型を選択。なので、トランジスタは(SC-59,JEITA)というパッケージのものが見当たらなかったので作成。抵抗はリード部品でも問題ない。タクトスイッチのボタン部分は背が高くてもいいので、手に入りやすいこちらを使用。

pcb


2.Fusion PCBに発注

Fusion PCBは、どうやらスイッチサイエンスPCBの委託先のようだが、かなり安い。今回作る基板は、10cm×5cmに収まり、10枚で十分なので、ただ、表面処理を一応鉛フリー半田レベラーを選択したので、$12.9となった。そして、悲しいことに配送料のほうが高く、$19.15を取られ、全部で$32.05ドル。

2018/7/30に発注したところ、31日には in Productionとメールが届いた。8/3には、出来上がって発送した旨のメールが届いた。というわけで、実質2,3日で発送される様子。ただ、海外から船便?で配送という感じなので、そこから1週間後の8/10に到着。まあ、2週間程度なのでよしとする。


3.出来上がった基板と動作確認

出来上がったものは、以下。当然ながら、目視の限りおかしなところはない。

DSC_0488

さっそく、部品実装してみたのが、以下。1.27mmピッチのESP-WROOM-32を手半田するのはうまくいくか不安だったが、大して難しくなかった。

DSC_0489

そして、Arduinoで、プログラムを書き込んで動作を確認したところ、所望の動作をした!というわけで、自作のIoTダッシュボタンが完成。家中に置いて使える。(ただし、Web側のシステム構築を何もしていない。IFTTTやMicrosoft Flowあたりを使うと簡単にできるかな。)


4.ケースに入れる

タカチのTW5-3-9を使うのを想定して基板を作成しているので、ケースに入れてみた。まずまずよい感じに収まっているのではないだろうか。ボタンが小さいのが少し気になるが、まあいいだろう。

DSC_0490


まとめ

KiCadとFusion PCBで基板を作り、ちゃんと出来上がった。今後も、Fusion PCBを使って基板づくりをしたい。

概要

ESP-WROOM-32からデータをAmbientに送信して可視化することができた。


背景と目的

先日、ESP-WROOM-32にDHT22を接続して温度、湿度を計測することができた。そこで、計測データをWeb上に送信して可視化してみたい。


詳細

1.可視化手段=Ambient

可視化するには、有料、無料含めて様々なものがあるが、今回は無料で使えるAmbientというサービスを使ってみる。私は初めて使うのだが、Web上に情報がさまざまあるため、始めやすそうだ。


2.Ambientのユーザー登録

こちらから、メールアドレスとパスワードだけで登録ができた。ログインすると、コンソール画面になるので、Myチャネルから、チャネルの作成をしておく。そうすると、チャネルID、リードキー、ライトキーなどがもらえる。


3.ESP-WROOM-32のコーディング

3.1 ライブラリの準備

[[サンプル>]]などを参考に、進めてみた。まず、Ambient接続用のArudinoライブラリがあるので、こちらダウンロード。表示がESP8266とあるが、気にしない。Arduinoのライブラリフォルダに置く。


3.2 コーディング

こちらなどを参考に、書いてみた。1分間隔で、DHT22の計測値を送信している。また、注意が必要なのは、WiFiClientSecureは使えない。(Ambientのエンドポイントが、HTTPだからか?)

#include 
#include "Ambient.h"
#include "DHTesp.h"

unsigned int channelId = 数字;
const char* writeKey = "Ambientのコンソールで確認";
const int GPIO_DHT22 = 33;

WiFiClient client; // WiFiClientSecureではだめ
Ambient ambient; // Ambient
DHTesp dht; // DHT22

void setup() {
  
  Serial.begin(115200);
  
  Serial.println("Attempting to connect to SSID: " + String(YOUR_SSID));
  WiFi.begin(YOUR_SSID, PASSWORD); // Wi-Fiモジュールの初期化
  while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(1000); // 1秒ずつ待つ
  }
  Serial.println("Connected to " + String(YOUR_SSID)); // 接続成功通知
  
  // Ambientの初期化
  bool tf = ambient.begin(channelId, writeKey, &client);
  if (!tf) {
    Serial.println("ambient.begin failed.");
  }

  // DHT22初期化
  dht.setup(GPIO_DHT22, DHTesp::DHT22);

}

void loop() {

  // 計測
  TempAndHumidity newValues = dht.getTempAndHumidity();

  // 結果表示
  Serial.println(" T:" + String(newValues.temperature) + " H:" + String(newValues.humidity));

  // データのセット
  ambient.set(1, newValues.temperature); // 温度
  ambient.set(2, newValues.humidity); // 湿度
  
  // 送信
  Serial.println("send...");
  bool tf = ambient.send();
  if (!tf) {
    Serial.println("ambient.send failed.");
  }
  delay(60 * 1000);

}


4.動作確認

コンソールで、送信先チャネルを選び、グラフを作成。今回は、湿度と温度それぞれを時系列で表示してみた。グラフの設定も、送信したデータが表示されている。※なお、途中から大きく数字が変わっているが、前半はダミーのいい加減な数値を送信したためで、後半は本物のセンサ計測値。

(どうでもいいけど、コンソールのデザインのBootstrap感がすごい。まあ、嫌いじゃないけど。)

20180712221733


まとめ

ESP-WROOM-32からデータをAmbientに送信して可視化することができた。非常に簡単なので、ぜひ今後も利用していきたい。

概要

湿温度計DHT22をESP-WROOM-32に接続して、温度と湿度を取得できた。


背景と目的

とある事情で、家の中の温度と湿度を測ってデータを蓄積する必要が出た。そのため、手持ちのESP-WROOM-32に湿温度センサを接続し、動作させる。


詳細

1.使用するデバイス

  • ESP-WROOM-32 DevKitC基板
  • DHT22

DHT22を選択したのは、Amazonで検索したら最初のほうに出てきたのと、ネット上に参考情報がたくさんあったため。(ちなみに、以前DHT11を持っていたのだが、電源逆接続という初歩的なミスで壊してしまったので、どうせならそれより精度の良いものを買ってしまえということで、買ったという経緯もある。)


2.接続方法

DHT22は、動作電圧範囲が最低3.3Vで、ESP-WROOM-32のGPIOレベル(だいたい3.3Vより低くなる)で確実に動作するのかよくわからないので、3.3V/5Vのレベルシフタをかませることにした。ただ、DHT22は独自の単線インターフェースなので、双方向レベルシフタが必要で、いろいろ考えた挙句、以下のような回路になった。(実は、最低動作電圧を多少下回っても動くのかな?やってないのでわからないが)

20180711184326

3.ソフトウェア

3.1 ライブラリのインストール

基本的に、arduino-esp32を使うが、DHT22は、Arduinoライブラリが存在しており、Arduino IDE>スケッチ>ライブラリをインクルード>ライブラリを管理から、インストールできた。

20180710210408

3.2 コーディング

都合もあり詳細は割愛するが、基本的には、以下の簡単なコードで取得できた。

// インクルード
#include "DHTesp.h"

// DHTespクラスインスタンスを作成
DHTesp dht;

// 初期化
dht.setup(GPIOピン番号, DHTesp::DHT22);

// 計測
TempAndHumidity newValues = dht.getTempAndHumidity();

// 結果表示
Serial.println(" T:" + String(newValues.temperature) + " H:" + String(newValues.humidity));

4.動作確認

以下が、動作確認した様子。暑くて30度を越えているが、手持ちの別の温度計もほぼ同じような値であり、湿度も自分の住んでいるエリアのリアルタイム湿度と比較してほぼ同じだったので、正しく動作しているようだ。

 T:30.90 H:54.90


まとめ

DHT22をESP-WROOM-32に接続して、動作させることができた。次は、Web上に蓄積する。

概要

ここに、概要を2行くらいで書きます。


背景と目的

先日、Raspberry Piで、Webアクセスをするプログラムを動かしたところ、レスポンスが遅かったので、解決策を調べる。


詳細

1.症状

  • Pythonのurllib2を使ってプログラムを書いていたときに起こった
  • 試しにcurlでアクセスを試したところ、同様に遅い(約5秒)
  • pingも遅い(1発目のレスポンスが来るまで、2発目以降は1秒ごと)

という状況だった。

2.調査

そこで、Web上でいろいろ調べた結果わかったのは、

 ipv6のDNSに接続しに行ってタイムアウトし、ipv4のDNSに接続しなおしている

ということのようだった。

3.対策

こちらなどを見ると、curlの引数に、-4という、ipv4だけを使うようにするオプションがある。そこで、-4という引数を付けたところ、素早くレスポンスが帰ってきた。

というわけで、ipv6のDNSに接続しに行ってタイムアウトするのを防ぐためには、

 curlで-4という引数を付ける

でよい。

ただし、この対策は根本治癒ではないので、curlが使えない状況などがあるとまずい。(私の場合Pythonでプログラムを作ってきてしまっていたのでsubprocessで、curlを実行しレスポンスをもらうという方法でどうにか乗り切れた。)


まとめ

Webアクセスが妙に遅い場合、ipv6のDNSに接続しに行ってタイムアウトを疑ってみて、curlの-4オプションをつけて早くなればそれが原因と推定できる。

概要

ラズパイ上に立てたWebサーバ(Apache)に対して、クロスドメインアクセスできるように設定を行い、した。


背景と目的

ラズパイ上に立てたWebサーバに対して、クロスドメインアクセスする必要が出たので、実装してその方法をメモる。


詳細

0.条件

  1. ラズベリーパイ上にApache(バージョンApache/2.4.25 (Raspbian))をインストールして、Webサーバを稼働
  2. ラズパイ上のサーバには、テスト用として何らかのJSONを返すCGIスクリプトを配置
  3. ラズパイのWebサーバと異なるドメインを持つWebサーバ上に、HTMLファイルを配置
  4. 上記HTMLでは、jquery(ajax)にて、ラズパイのCGIスクリプトにアクセス→ここでクロスドメインアクセスが発生


1.apache2.confの設定

まず、headers.loadというモジュールを有効化。

sudo cp /etc/apache2/mods-available/headers.load /etc/apache2/mods-enabled/headers.load

/etc/apache2/apache2.confの末尾に、以下を追記。


<Location /usr/lib/cgi-bin>   
      Header set Access-Control-Allow-Headers "Content-Type"
      Header set Access-Control-Allow-Origin "*"
</Location>


Apache2を再起動。

sudo service apache2 restart


2.テスト用サイト

以下のテスト用HTMLファイルを作成し、ラズパイのWebサーバとは異なるドメインを持つWebサーバなどに配置する。私の場合、AWSのS3に配置して公開。


<html>
<head>
    <meta charset="utf-8">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
</head>
<body>
    <p id="message"></p>
    <script>
        window.onload = function () {
            $.ajax({
                url: "http://{ラズパイのIPアドレス}/cgi-bin/test.cgi",
                type: "GET",
                success: successCallback,
                error: errorCallback
            });
            function successCallback(data, dataType) {
                $("#message").text(JSON.stringify(data));
            }
            function errorCallback(err) {
                window.alert(err);
            }
        }
    </script>
</body>
</html>



3.動作確認

2.で作成したHTMLのURLにブラウザでアクセスしたところ、以下のように表示され、正しく動作した。(CGIは、時刻をJSONで返すだけのスクリプトとしている)

{"datetime":"2018-06-23 17:27:54"}


まとめ

無事、クロスドメインアクセスすることができた。

概要

ESP-WROOM-32で、スリープからスイッチを押して復帰するプログラムを作成し、正しく動作することを確認した。


背景と目的

ESP-WROOM-32で、複数のスイッチのうちいずれかを押したらスリープから復帰させ、なおかつどれが押されたか認識したい。なので、サンプルプログラム等を参考に、プログラムを組み動作確認してみる。


詳細

0.試す条件

  • ESP-WROOM-32 DevKit-C
  • スイッチをGPIO32,34,35に接続(押したらHIGH)


1.コーディング

今回やりたいことは、

  • 3つのスイッチのいずれかを押したら、sleepから復帰し、押されたスイッチを認識する

である。ドキュメントを読む限り、External wakeup (ext1)でできそうだ。そして、サンプルプログラムがあるので、基本骨格は、ExternalWakeUp.inoとして、いくつか変更を加える。

なお、

  • ESP_EXT1_WAKEUP_ALL_LOW = 監視対象のGPIOすべてがLOW
  • ESP_EXT1_WAKEUP_ANY_HIGH = 監視対象のGPIOいずれかがHIGH

といういずれかの動作モードしか選べないので、スイッチを押すとLOWになる複数の入力のいずれかを検出というのは難しい。(手元にそういう構成で作ってしまったハードがあって使えないことが分かりがっかり。。。)

まず、スイッチを接続するGPIOピンが3つあるので、

#define BUTTON_PIN_BITMASK 0xD00000000 // 2^32, 2^34 2^35なので、0b1101 0000 ...

とする。そして、wakeupのトリガになったピンが分かるように、esp_sleep_get_ext1_wakeup_statusなる関数を用いて、シリアルにピン番号を表示する関数を作成し、setup関数内で、print_wakeup_reasonの後に呼び出す。

void print_wakeup_pin(){

  uint64_t wakeup_pin = esp_sleep_get_ext1_wakeup_status();

  if (wakeup_pin & 0x100000000) {
    Serial.println(32);
  }
  if (wakeup_pin & 0x400000000) {
    Serial.println(34);
  }
  if (wakeup_pin & 0x800000000) {
    Serial.println(35);
  }
  
}

そして、ext0を無効、ext1を有効にするため、setup関数内で、

//esp_sleep_enable_ext0_wakeup(GPIO_NUM_33,1);
//If you were to use ext1, you would use it like
esp_sleep_enable_ext1_wakeup(BUTTON_PIN_BITMASK, ESP_EXT1_WAKEUP_ANY_HIGH);

とする。なお、悲しいことにサンプルプログラムは、古いAPIを修正し忘れたのか、esp_deep_sleep_enable_ext1_wakeupという間違った関数名になっていてそのままではエラーになるので、esp_sleep_enable_ext1_wakeupに修正すること。


2.動作確認

上記変更をしたプログラムを書き込み立ち上げると、

Boot number: 1
Wakeup was not caused by deep sleep
Going to sleep now

となり、wakeupではない旨とsleepに移行した旨が表示される。そして、GPIO32に接続したスイッチを押したところ、

Boot number: 2
Wakeup caused by external signal using RTC_CNTL
32
Going to sleep now

となり、正しく押したSWを認識できている。34、35も同様だった。ということで正しく動作することが分かった。

また、消費電流もスイッチを押した直後少し増えて、スリープになったら減少(電源のメータの読みなのでいい加減)したのでちゃんと動いていそう。


まとめ

正しく動作させることができた。

このページのトップヘ