2021年4月30日金曜日

WS2812BなLEDリングを買ってみた

 たまたまAliexpressを見ていたらフルカラーシリアルLEDが12個乗ったLEDリングが1.25ドルで売っていたのでついポチってしまった。

端子などの付属品も一切ついてなかった。しかし安いぞ…
搭載チップはWS2812Bらしい。

CJMCU-2812B-12
ちゃんとLED一つ一つにセラコンがついていた。NeoPixel Ringに似てるけど一回り大きい。
内径35mm、外形50mmだった。
CJMCU-2812B-12
裏面には2.54ピッチでパットが出ているのみ。CJMCU-2812B-12っぽい?

とりあえずこのままだと動作確認もしにくいのでコネクタを付けてみた。
ちょうど手持ちのXHコネクタがピッチぴったりである。
コネクタのピンを曲げてこんな感じにハンダしてみた。

とりえずArduinoでのNeoPixelライブラリで動作確認してみた。RGBのLEDを抵抗で色調調節するよりは全灯でもきれいに光るなぁ。
配線も簡単で便利だ。




2021年4月17日土曜日

MJPG-Streamerの代替としてµStreamerを試してみた。

 前にMJPG-StreamerでWiFiなFPVカメラにすると遅延がどのぐらい出るのかを試してみたんだけど、そのときは解像度320x240の15FPSで行けそうなぐらいだった。
µStreamerを使うとカメラのハードウェアエンコード機能を使えたりするらしいので、この機能でどのぐらい低遅延になるのかを試してみた。

µStreamerはラズパイに最適化されていてラズパイカメラでもMJPG-Streamerより性能が出るらしいんだけど今回は前回試したときと同じBeagleBone BlueとUVC対応Webカメラで試してみた。

まずはBBBlueのOSのアップデート。だいぶ放置していたので今回はeMMCのOSをまるごとアップデートすることに。OSはこちらからダウンロードした。
今回はeMMCのOSをまるごと入れ替えたかったので、consoleフォルダの中のbone-eMMC-flasherから始まるイメージファイルを使用した。ダウンロード後に解凍するとimgファイルができるのでラズパイ用の書込ツールでimgファイルを適当なSDカードに書き込んだ。

あとはBeagleBone Blueに差し込んでSDボタンを押しながら電源を入れるだけ。LEDが5分ぐらい流れたあとに全点灯して少しするとLEDが消えるので、LEDが全部消えたら(ACアダプタ使用時は緑色だけついた状態)電源を抜いてmicroSDカードを抜いて完成。

電源を入れるとeMMCから新しいOSが起動する。

次に本題のμStreamerをビルドする。MJPG-Streamerのようにapt-getだけでは入れられなかったのでGithubの手順通りにビルドした。手順と一緒にMJPG-streamerとの比較が乗ってるので置き換えを狙っていそうな感じ?確かにMJPG-streamerはラズパイではよく使用例があるんだけどあんまり更新されてなさそうだし…

まずは必要なパッケージをインストール

sudo apt-get update
sudo apt-get install build-essential libevent-dev libjpeg-dev libbsd-dev make usbutils

ustreamer本体をダウンロードしてビルド

git clone --depth=1 https://github.com/pikvm/ustreamer
cd ustreamer
make

ビルドに2分ぐらいかかった。

Webカメラを繋げて起動してみる。BeagleBone BlueにACアダプタ接続するの忘れずに(ACアダプタかバッテリがないとUSBポートの電圧が不安定でカメラがうまく起動できない)
今回は前回と同じくC270を使用した。これも一応MJPEGのハードウェアエンコード対応しているらしい。

./ustreamer -m MJPEG -c HW -f 15 -s 0.0.0.0 -p 8080

これでUSBとBeagleBoneをPCに繋いでる場合はhttp://192.168.7.2:8080にアクセスするとµStreamerのページが表示されるはず。
/streamをクリックすると映像が見れる。

デフォルトの640x480でも結構レスポンスが良さそうなので前回同様測定してみた。

解像度640x480の15FPSでも0.25秒だった。ちなみに1280x720でも0.23秒だったのでハードウェアエンコードが効いている感じがある。さらにはFPSを30に上げてみても0.25秒だったので、ハードウェアエンコードができる設定であれば帯域が十分にあれば変わらなそう。(25FPSとかに設定してもC270の設定にないのでFPS30に自動で変更されている)
ちなみにCPU使用率は720Pの30FPS設定でも10%ぐらいだった。

H264のハードウェアエンコード対応のカメラだったら帯域を食わなくていいのかなぁ
でもお高い…
ちなみにSJ4000をUSBカメラモードで使うと遅延が0.31秒ぐらいの遅延だったのでカメラによっても遅延が変わるっぽい。

やっぱりFPVとかやるなら広角レンズのほうが良さそう。C270にワイドレンズつけてもそこまで広がらないからなんかいいのないかなぁ。

μStreamerの方はビルドが面倒かもしれないけどすぐビルドが終わるし、使い勝手もMJPG-streamerとあまり変わらないので置き換えアプリケーションとしてはいいかもしれない。ラズパイに最適化されているらしいので今度はラズパイカメラでh.264での遅延を試してみようかな。

2021年4月10日土曜日

Arduinoでi2cスレーブデバイスを作ってみる

 Arduino同士でI2Cのマスタとスレーブとして通信するとき、よくシリアル通信みたいな使い方を見かけるんだけど、I2C接続のセンサとかみたいにI2Cのレジスタを指定して読み書きできないか試してみた。

いろんなサンプルを見ているとI2C通信って一番最初にレジスタのアドレスを送って、その後に書き込みたいデータを送っているような感じ。読み込みの際も最初は読み込みたい先頭のアドレスを送っている感じ?

というわけでレジスタの範囲を指定して読み書きできるようなスケッチを作ってみた。

#include <Arduino.h>
#include <Wire.h>

#define SLAVE_ADDRESS 0x38

#define DEBUG
//#define DISABLE_INTERNAL_PULLUP

//使用するレジスタ範囲指定
#define I2C_REG_ROW 3
#define I2C_REG_COL 4
uint8_t I2C_REG[I2C_REG_ROW][I2C_REG_COL];

//読み書きするレジスタアドレス
uint8_t REG_SELECTED;

//i2c受信イベント
void receiveEvent(int _length) {
  //1byte目を読み込む(レジスタアドレス指定)
  REG_SELECTED = Wire.read();
  uint8_t startRow = REG_SELECTED >> 4;
  uint8_t startCol = (REG_SELECTED & 0x0F);
  
  #ifdef DEBUG
  Serial.print("REG:");
  Serial.println(REG_SELECTED, HEX);
  #endif
  
  while (Wire.available() > 0) {
    if(startRow < I2C_REG_ROW && startCol < I2C_REG_COL){
      I2C_REG[startRow][startCol] = Wire.read();
      #ifdef DEBUG
      Serial.print("Write:");
      Serial.println(I2C_REG[startRow][startCol], HEX);
      #endif
    }else{
      Wire.read();
    }
    ++startCol;
  }
}


void requestEvent() {
  uint8_t startRow = REG_SELECTED >> 4;
  uint8_t startCol = (REG_SELECTED & 0x0F);
  if(startRow < I2C_REG_ROW && startCol < I2C_REG_COL){
    Wire.write(&I2C_REG[startRow][startCol], I2C_REG_COL - startCol);
  }
}


void setup() {
  //SlaveでWireライブラリを初期化
  Wire.begin(SLAVE_ADDRESS);
  //イベント設定
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  
  //内蔵プルアップ無効にする場合
  #ifdef DISABLE_INTERNAL_PULLUP
  pinMode(SDA, INPUT);
  pinMode(SCL, INPUT);
  #endif
  
  #ifdef DEBUG
  Serial.begin(115200);
  #endif
}

void loop() {
  
}

とりあえずArduino UNOとかのAtmega 328pデバイスで動くはず。

全部のレジスタ使いたいわけじゃなかったので使用できるレジスタの範囲を2次元配列でI2C_REG_ROWとI2C_REG_COLで指定する形にしてみた。もっときれいな実装方法あるかもしれないけど…
レジスタの範囲指定は0x00起点で何行、何列みたいな指定。
素人プログラムなのでおかしいところとか上手く動かないかもしれないところがあるかもしれない。

動作確認はRaspberry Pi 3BとArduino Microで行った。
ラズパイは3.3V、Arduinoは5Vなのでレベル変換するか、Arduino側の内蔵プルアップを無効にして(#define DISABLE_INTERNAL_PULLUPのコメントアウトを外す)Raspberry PiのI2Cに直結しても行けるかも?(無保証)
今回はレベルコンバータのLVCNV-I2Cを使用してテストを行った。A側にArduino、B側にラズパイをつなぐ。

ラズパイで"i2cdetect -y 1"をしてみる。

するとこんな感じでArduinoが認識された。Arduino側にはFFが送られてきていた。
i2cdetectは全アドレスにFFを送ってデバイスとしての応答があるかどうかを見ている?

次はi2cdumpしてみる

スケッチで指定したレジスタ範囲以外も全部0が送られている。
特に何も送らなければ0として認識するのかな。
つぎはi2csetで0x10から4Byte分適当なデータを書き込んでからdumpしてみる。
ちゃんと書き込んだのが読めてる。ちなみにレジスタ範囲指定外に書き込んでも無視されるはず。

とりあえず必要な機能が揃ったのでこれでいいかなー
レジスタをloop内とかで書き換えてもちゃんとi2c経由で読めるのかは未確認だけど…
これでI2C接続のモータドライバとか作ってラズパイで遊んだりできるかも。センサとかつければセンサの値を処理してからラズパイに渡したりもできるし。
昔使っていたI2Cのモータドライバより高性能なものが作れそう。

ちなみにESP32は今のところ標準ライブラリではi2cスレーブになれないらしいので、外部ライブラリを使う必要あるみたい。

2021年3月14日日曜日

CF-NX4をSSD化してみた

 友人がコスパが良いノパソを欲しがっていたので中古のLet's noteをSSD化してみた。CF-NX4のi5モデル、メモリ8GB、SSD250GBにすればそこそこ使えそうだし。

SSDは変なもたつきがあると嫌なのでDRAMキャシュ付きでそこそこ安いやつを探していたらサムスンの860 Evoがやすかったのでこれの250GBにしてみた。

本当は500GBにしたかったところだったんだけど予算の関係で…

中古のCF-NX4の方はHDDにOSがクリーンインストールされている状態だったので今回はSSDにOSをクリーンインストールする形にした。
このPC、HDDはバッテリーを外したところにネジが一本あってこの蓋をスライドすると出てくる模様。
スライドしたカバーを取るのに少し苦労したけど、カバーを取ると白いテープ的なのがあるのでこれを引っ張り出す。
このテープを引っ張るとHDDが抜けてくる。

あとはSSDにこのテープを張り替えて逆の手順で突っ込むだけ。
突っ込むときはスポンジが邪魔をするのでポイントカードのようなある程度硬いものでスポンジを抑えながら突っ込むと楽だった。

あとは起動してF2連打でBIOSに入ってUEFIを有効にしてWindows 10をクリーンインストールして完成!
ドライバはWindows Updateからほぼ入ったので公式サイトからWindows 8.1用の純正アプリケーションをそこそこ入れて完成。Windows 10でも動いた。

3万円でこのクラスのPCならまあまあコスパ高いんじゃないかなぁ。軽いし。
ちなみにこの個体は4GBのメモリが増設されていたのでもともと8GBでお買い得だった。


2021年3月13日土曜日

XiaomiのBluetooth温湿度計2を買ってみた

 AliexpressでたまたまXiaomi Mijiaの温湿度計2が安かったので買ってみた。BLEに対応しているやつ。品番でいうとLYWSD03MMCで、小さくて安いやつ。送料込み400円ぐらいだった。

レビューに紹介画像より小さいっていうのが書いてあったのでサイズは確認していたんだけど、パッケージからして小さい。
裏面には仕様も書いてある。電池はCR2032っぽい。

付属品は説明書と両面テープ。両面テープでどっかに貼り付けられるぐらいかるい。

電池は裏蓋のにドライバーを突っ込むところがあるのでここにマイナスドライバーをつっこんでパカッと開く感じ。
電池入りだったので透明のシートを抜いたら起動した。

Bluetoothで接続する場合はMi Homeアプリを入れてBluetoothをオンにしておくと勝手に認識するので初期設定を済ませる。
アプリでは1秒ぐらいごとに最新の温湿度が見られる。そんでもってログ機能は1時間に1回ログしてるっぽい?

Pythonでデータを読めるようにしていたり、カスタムファームウェアもあるようなので改造ベースにも面白そう。







2021年3月6日土曜日

UPnPでESP32から自動でルータのポート開放してみた。

 インターネットに繋いだESP32からクラウドにデータを上げたりする分にはルータのポートを開けなくてもデータをサーバに蓄積することができるんだけど、ESP32-CAMのようにESP32自体をサーバにして運用するときはどうしてもルータのポートを開けないとインターネット越しにアクセスできない。

ESP32側から簡単にポートを開けられるようにUPnPでルータのポートを開けてみた。これならいちいちルータの設定画面を開かなくてもいいし、手軽に設置できるはず。

使用させてもらったライブラリはUPnP_Generic Library

これはArduino上のいろんなデバイスに対応しているUPnPライブラリで、ESP32とかESP8266用に開発されたTinyUPnPを改良して対応ボードを増やした形らしい。最近のルーターはだいたい対応していると思うけどポートを開けたい対象のルーターはUPnP対応ルータが必要。あと2重ルータになってたりするとうまくいかないかも。

SimpleServerESP32のサンプルスケッチを動かしてみたがポートがうまく開かない…

他のライブラリを使ってみたりとかはしてみたんだけども、どうにもルータのUPnPには到達できてるのにうまくポートが開かない。ルータ側で見ていると一瞬開いてるようにも見えるんだけどすぐ消えてしまう状態…

フォーラムを読んでいると同じようにハマっている人がいるようで、最終的にはLEASE_DURATIONを0にすることでうまく動かすことができた。サンプルスケッチのデフォルトでは36000(秒)に設定されていた。ルータとの相性もあるのかもしれないけど、DD-WRT環境化ではこれを0にすることでうまくポートが開けられるようになった。LEASE_DURATIONは有効期限なので、0にすると有効期限無しの設定になってしまうが、ESP32側から不要になったら消すようにすればいいかもしれない。

ルータ側で設定を削除した場合は、一旦UPnPを無効にして有効にし直すか再起動しないともう一回追加できなかった。これはDD-WRTの仕様かも。

あとはDDNSとかでIPアドレス変わったのに対応できればサーバとして一通りの機能が搭載できるんじゃないかな…

DDNS自体は定期的にURL読み込めば良さそうだし。

2021年2月28日日曜日

USB PD対応充電器から12Vを取るケーブルを作ってみた

 AliexpressでUSB PDの充電器から任意の電圧が取れるアダプタが売っていたので買ってみた。USB PD Decoyとかいうやつ。

メスタイプのものは安くたくさん出てるんだけど、メスタイプだとUSB PDケーブルが必要なので充電器に直接させるようにオスタイプのものを購入してみた。
電源を取り出すためのパッドは裏側に用意されている。

抵抗を取り外したりジャンパーしたりするだけで5V,9V,12V,20Vが取り出せる模様。
まぁ充電器側もほしい電圧に対応してる必要があるけど…

デフォルトで20Vだったので抵抗を一個取り外して12Vにしてみた。
1005の抵抗だったので斜めカットC2.0の小手先でサクッと取れた。

あとは余っていた5.5/2.1なDCジャック付きのケーブルをハンダして完成。これでUSB PDの充電器から12Vが取れる!
この前作った3.5インチHDDをつなぐアダプタとかもこれで使えるから便利だな。USB PD充電器は65Wのものをもっているので12Vだと3A取り出せるので便利だなぁ。