月別アーカイブ: 2022年5月

ESP-Nowの公式サンプルが動かなかったので調査

環境

  • ESP32-DevKitC V4 × 2個(MasterとSlave)
  • Arduino IDE (Windows Store 1.8.57.0)
  • ボード ESP32 Dev Module(ESP32 Espressif Systems v 1.0.6)

使用サンプル

ESP32 Dev Moduleの「スケッチ例」->「ESP32」->「ESPNow」->「Basic」のMaster/Slaveのセット

\ArduinoData\packages\esp32\hardware\esp32\1.0.6\libraries\ESP32\examples\ESPNow\Basic の MasterとSlave

発生エラー

Slaveのpeerにデータを送るタイミング(esp_now_send)で「違うチャンネルには送れないよ!」と怒られる。

E (838684) ESPNOW: Peer channel is not equal to the home channel, send fail!
Send Status: Invalid Argument

原因

文字通り違うチャンネルには送れないみたい。公式サイトになんとなくそれを前提としていそうなことは書いてあるけど明示してある箇所は見つけていない。(メッセージがそのままなのでまぁ間違いはないんだろう。)ここらみると2020年の冬ぐらいの1.0.5-rc2で変わったのかな?

For example, the destination device doesn’t exist; the channels of the devices are not the same

Masterは自分がDefaultの1チャンネルになっていて送信想定が3チャンネルになっているので引っかかっている。(それはそれとしてサンプルのSlaveはチャンネルが1になっているのにMasterのソースでは3を指定しているのでそこでも不整合が生じている)

対処

チャンネルを合わせればよい。

1chで上げる場合

Slaveは1チャンネルで上がっているので、送信想定を1にしてやればよい

define CHANNEL 1

slave.channel = CHANNEL;

その他チャンネルで上げる場合

Master/Slaveのチャンネルを任意(使用可能は1~13)に指定してやればよい。

Slave(APモード)のチャンネル指定

Slaveは(違和感あるけど)APモードになっていてSoftAP立ち上げの際に指定できる。

define CHANNEL 1 // からの
 bool result = WiFi.softAP(SSID, "Slave_1_Password", CHANNEL, 0);

Master(STAモード)のチャンネル指定

MasterはSTAモードになってる。ここをみるとSTAモードのときはsoft-APもstationモードと一致するらしい。(で。ドキュメントで確認できていないけどESPNowもsoft-APの設定使って動いているみたい。Espressif だとソース見れないみたいだけどM5Stackの方では派生したもの?みれるようなのでそっち追えばわかるかも)

3. ESP32 is limited to only one channel, so when in the soft-AP+station mode, the soft-AP will adjust its channel automatically to be the same as the channel of the ESP32 station.

指定方法の正しい作法はわからなかった。動いたのは以下の操作。

#include <esp_wifi.h>// して

void setup() {
 //の
  WiFi.mode(WIFI_STA);
 // した後に
  esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE); // チャンネルを指定してあげる

その他

チャンネルについて

2.4 GHz 帯の中で微妙に周波数変えて周波数ごとにデータ送るやつ。こことかわかりやすい。日本だと1-13チャンネル使えてESPも1-13指定できる。(多分同じ奴だと思うけど調べてない)チャンネル近いと干渉するので、既存の機器と重なったりしたら変えてみると幸せかもしれない。

少し上のWIFI_SECOND_CHAN_NONEについて

「チャンネル2つ使うとデータが倍の勢いで送受信できる」ってやつを使うかどうかの選択パラメータで使わない(HT20)を指定している。使う(HT40)指定のWIFI_SECOND_CHAN_ABOVEとWIFI_SECOND_CHAN_BELOWもあるけどESPNowには多分反映されないでWifiの方だけにかかわると思う。(とりあえず速さいらんと思うのでちゃんと調べてはいない)

仕事をさぼりやすいように人が来たら画面をコマンドプロンプトに切り替えてみる

やりたいこと

仕事さぼっているのがばれないように、人が近づいたらゲーム画面をコマンドプロンプト等(なんとなく黒くてそれっぽい画面)に切り替えられるようにする

必要要素

  • 人が近づいたことを検知する
  • コマンドプロンプト画面でゲーム画面を隠す

実装方針

人が近づいたことを検知する

何かのセンサーで人が近づいたことを検知すればOK。手持ちセンサーでそこそこの距離を測れる超音波距離センサー(HC-SR04)があったのでそいつを利用。角度は15度とほぼ正面しか測れないけどとりあえずこいつで。

コマンドプロンプト画面でゲーム画面を隠す

キーボード入力をマイコン(Raspberry Pi PICO)で自動化する。ライブラリを使ったら簡単にできるらしいできた。

実装技術

Circuit PythonだとAdafruitのライブラリで超音波距離センサーとキーボード入力もそろっていたのでCircuit Pythonを使った。

開発環境(エディタ?)

最初はVS Codeで開発しようとしたけどPICO開発用のPICO-goが新しいVSCodeだと使えないのでメジャーどころのThonnyにした。

なお、こちらにあるようにVSCodeのバージョンを1.65.2に落としたら動くはず。(いったんうごいていたけど油断していたらVSCodeのバージョンアップ走っていて使えなくなっていたので面倒になった。)

また、こちらにあるようにForkされたPico-goをビルドしてもよい模様。

実装

Circuit Pythonのインストール

公式からダウンロードしてインストール。(参考

コマンドプロンプト画面でゲーム画面を隠す

(ライブラリのインストール説明の都合でコマンドプロントから説明)

こちらを参考にHIDのライブラリをインストール。

Windowsでコマンドプロンプトを全画面起動するキー操作は以下。ついでになにかそれっぽい情報を出すためにDir結果も表示(実際に打つとわかりやすい)

  1. Windowsボタン(プログラムの検索画面を開く)
  2. “cmd”キー入力後 Enter (コマンドプロンプト起動)
  3. “dir” キー入力後Enter(Dir実行。ぱっとみそれっぽい情報を表示するため。)
  4. Alt押しながらEnter(コマンドプロンプト全画面か)

Windowsの反応時間を見なくてはいけないかもしれないのでちょいちょいスリープを入れているけど待ちが必要かはわからない。

なお、キーボードの種類指定できるけど日本語はなさげなので必要なら自分で書くか探さないといけない。

人が近づいたことを検知する

こちらからadafruit_hcsr04ライブラリをインストール。HIDの時と同じようにPICOのlibディレクトリにいれればよい。(adafruit_hcsr04.pyで最低限動くはず)

ハードとしてはPICOとhcsr04をジャンパーでつなぐ。

GP5とGP6はプログラムでGPIOピンなら任意指定に変更可能。ピンの役割はこちら

PICOHCSR04
VBUSvcc
GNDgnd
GP5trig
GP6echo

以下で値はとれる

import adafruit_hcsr04
sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP5, echo_pin=board.GP6)
distance = sonar.distance

取り急ぎプログラムべたばり

何個もコマンドプロンプト立ち上げたり荒いけど使いながら調整する。プログラムもおもむろに書き直す。(HIDの試験用だったのでこのまま解体されるかもかも)

import microcontroller

import usb_hid
from adafruit_hid.keyboard import Keyboard
from adafruit_hid.keyboard_layout_us import KeyboardLayoutUS

from adafruit_hid.keycode import Keycode

import time
import board
import adafruit_hcsr04

keyboard = Keyboard(usb_hid.devices)
layout = KeyboardLayoutUS(keyboard)

sonar = adafruit_hcsr04.HCSR04(trigger_pin=board.GP5, echo_pin=board.GP6)
time.sleep(1)

while True:
    try:
        distance = sonar.distance
        if distance < 150:
            print('かくせ')
            
            keyboard.send(Keycode.WINDOWS)
            time.sleep(0.2)
            
            layout.write('cmd')
            time.sleep(0.1)
            keyboard.send(Keycode.ENTER)
            time.sleep(0.2)
            
            layout.write('dir\n')
            
            time.sleep(0.2)
            keyboard.send(Keycode.ALT,Keycode.ENTER)
            
        else:
            print("OK")
        
    except RuntimeError:
        print("Retrying!")
    time.sleep(2)