C++勉強メモ

やりそうなエラー

stringリテラルの設定もれ

string型のリテラルはincludeとnamespace設定がいる

忘れた場合のエラーメッセージは

vscode

ユーザー定義のリテラル演算子が見つかりませんC/C++(2486)

gcc

chap3.cpp:4:18: error: unable to find string literal operator ‘operator""s’ with ‘const char [6]’, ‘long unsigned int’ arguments
4 | std::cout << "hoge\n"s;
| ^~~~~~~~~
make: *** [Makefile:6: chap3.o] Error 1

補足

C++11でリテラル演算子をユーザー定義できるようになったとのこと。自分で定義するなら

ただし、自作する場合はアンスコ(_)で始めろと。

試しに自作したら

上でも動いた

Found orphan containers

docker-composeを新たに作成して実行したところ以下のワーニングが出た。

WARNING: Found orphan containers (proxy_letsencrypt-nginx-proxy-companion_1, nginx-proxy) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.

こちらにあるように他のdocker-composeとの名前重複が原因。

]新しいdocker-composeだとドキュメントによると以下のようにname要素(top level element)が存在し名前重複を避けられるそう。ただ、一時期バグがあって使えない時期もある模様。

対応していないと思われる私の環境では以下のエラー

ERROR: The Compose file './docker-compose.yml' is invalid because:
Invalid top-level property "name". Valid top-level sections for this Compose file are: version, services, networks, volumes, secrets, configs, and extensions starting with "x-".

現在の環境は長く使わない予定なので他の暫定対処を選択する。

環境変数にCOMPOSE_PROJECT_NAMEを指定しても同じ効果があるそうなので。docker-compose.ymlと同じディレクトリに.envを以下内容で作成。

COMPOSE_PROJECT_NAME=momoyama_shop

そしてdocker-compose buildをすると以下のように指定したcompose_project_nameを持つイメージが作成された。

Building front
Step 1/2 : FROM nginx
---> 92b11f67642b
Step 2/2 : RUN echo 'server_tokens off;\n' > /etc/nginx/conf.d/my_default.conf
---> Using cache
---> 597e7dfaab23

Successfully built 597e7dfaab23
Successfully tagged momoyama_shop_front:latest

自宅用通知マシン作成(5)

前回の続き

スタックチャンがしゃべれるようになったので、次は外部からしゃべる指令を出す端末のバージョンアップ。呼び出しは予約確認のための自宅用通知マシンと兼用。

エッジ検出処理&疑似的な並列処理はこちらに大体まとめた感じ。

メインのループ(Arduinoのloop関数)は並行処理するループ(yoyakuCheckLoop,yobidashiCheckLoop)をそれぞれ呼び出しyobidashiCheckLoopの中でボタンが押されている判定をして押されていたらネットワーク越しにスタックチャンがしゃべるURLをたたいてしゃべらせる。

最初はPOSTで叩こうとしたけどPOSTの引数違うぞみたいなエラーメッセージが出たのでとりいそぎGETメソッド(5秒も調べていない)

メインのループの中でyobidashiCheckLoopを呼び出し。下に張った中のyobidashiCheckLoopでやっていることはこちらに大体まとめた感じ。で、execYobidashi(開発環境ならexecDevYobidashi)で、httpsのリクエストを投げているだけ。セキュリティ的なものはつけていないのでそのまま叩ける。

一応全体

続けてネットワーク回り

ESP8266でエッジ検出処理

やりたいこと

ボタンを押したときにそれを検出して処理をしたい。ループの中とかで検出処理をごにょごにょやるのはつらいのでボタン検知の割り込み処理を試す。LOWからHIGHになったとき(立ち上がりエッジ:RISING)や逆にHIGHからLOW(立ち下がりエッジ:FALLING)になった時を検出するやつ。

概要

void ICACHE_RAM_ATTR shopYobidashiCallback() {
  Serial.println("working");
}
void setup() {
  pinMode(INPUT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(INPUT_PIN), shopYobidashiCallback, FALLING);
}

割り込みが効くGPIOでattachInterruptを呼び出し。GPIOがどれかはちゃんと確認していない。(データシート参照)とりあえず、12は効いて1-15が効くと思う。

呼び出し元

attachInterrupt(割り込み番号,コールバック関数名,検出エッジ)の引数。

割り込み番号はdigitalPinToInterrupt(ピン番号)で取得できる。

コールバック関数名はそのまま関数名

検出エッジはLOW/CHANGING/RISING/FALLINGが選べる模様。LOWはLOWの時常に。実際に試したのはFALLINGのみ。(参照 ESPでなくArduinoのドキュメントなので少し違うかもしれない)

コールバック

ドキュメントはこちら

コールバックには関数をRAM上に配置する指定のIRAM_ATTRまたはICACHE_RAM_ATTR(多分こっちはDupricated)がいる。

つけ忘れると下みたいなメッセージが出て再起動するはず。

ISR not in IRAM!

User exception (panic/abort/assert)
--------------- CUT HERE FOR EXCEPTION DECODER ---------------

Abort called

>>>stack>>>

ctx: cont

RAMにない=Flashにあるとそっちの書き込みとかぶってだめよという事らしい。

その他制限として

  • delay() or yield()を読んだり内部で使うものを使用できない
  • 1ms以上かかる処理をすると不安定orクラッシュ引き起こす。よって、時間かかる処理は他でして極力そのためのフラグ操作など推奨。フラグはvolatileつける(参照
  • ヒープ操作は不具合起こしえる。malloc最小限にしてreallocとfreeは使うなと。stringやvectorも要注意。詳細はドキュメント。
  • C++のnewやdeleteも

あとは、ドキュメントに書いてないけどコールバックの宣言は使う前に。

チャタリング対策

立ち上がり、立ち上がりを検出したいが変化した時に押しているのか押していないのか中間の状態を経由するのでその際に何度もコールバック関数が呼ばれてしまう。(参照

今ブレッドボードでやっているけどイメージは下。

0件だよ
0
working
working
working
working
working
working
working
working

呼ばれたときの処理で出力される”working”が一回であってほしいが何度も出力される。

参照先に色々な対策があるが、ソフトウェアで対策できれば楽。今回の使用用途としては押されたときにあるURLをたたければよい。また、即時に何度も呼ばれなくてもよい。なので、エッジ検出後一定期間その状態が続いていれば処理を実行するとすればよい。

  1. ボタン押す
  2. 最初の立ち上がり/立下りを検出後最初数100msはチャタリングしているかもしれないので読み飛ばす
  3. その後、100ms間隔で数回状態が継続していたら押されていると判断する

みたいな感じで今回は大丈夫。

ソフトウェア的にやらないなら積分回路組んだり、ラッチ回路組んだり、いいスイッチ使ったりとあるが要件厳しくなければソフトで切り抜けた方が大体良い気がする。(というかそういう要件に収めたい)

で、ループからボタン検知と状況確認の並行処理しようとしたらESP8266はスレッドなかった。並行処理するためにFreeRTOSいれる。FreeRTOSを使おうと思ったら「ESP8266などいまさら開発する暇ないんじゃ!」とのお言葉。ESP32-C3なら使えるらしい。

ループ切り替えながらやる。2つの処理があるけど、時間はざっくりでよい。

下のイメージになった。

コールバック(shopYobidashiCallback)はフラグの設定のみ

メインのループ(Arduinoのloop関数)は並行処理するループ(yoyakuCheckLoop,yobidashiCheckLoop)をそれぞれ呼び出しのみ。

yobidashiCheckInterval 経過していなかったらスキップする処理を入れつつチェックをいれる。yobidashiCheckLoopが走っている間はもう一個の処理(yoyakuCheckLoop)は順番回ってこない。

ESP8266には基本INPUT_PULLDOWNなかった。

ESP8266(ESP-WROOM-02)で内部プルダウン使おうと思ったら怒られた。

C:\Users\kitam\git\yobidashi\client\home_yobidashi\home_yobidashi.ino:109:22: error: 'INPUT_PULLDOWN' was not declared in this scope; did you mean 'INPUT_PULLDOWN_16'?
109 | pinMode(INPUT_PIN, INPUT_PULLDOWN);
| ^~~~~~~~~~~~~~
| INPUT_PULLDOWN_16

ESP8266のGPIO1から15にはPULL_DOWN抵抗はない。INPUT/OUTPUT/INPUT_PULLUPのいずれか指定。

GPIO16だけプルダウン抵抗がある。GPIO16はディープスリープ用の特別なやつ。指定する場合はINPUT_PULLDOWN_16。

https://links2004.github.io/Arduino/dc/d6f/md_esp8266_doc_reference.html

ブレッドボードの配線的にPULL_DOWNの方が指しやすかっただけなのでおとなしくPULL_UP使う。

自宅用通知マシン作成(4)

音声関連クラス化

見通しが悪くなりそうなので音声周りは別クラスに。多分まだ予想してない改造をしそなのでパラメーター渡すとか考えずに単純な別ファイル化だけ。(StackSpeaker.h)

呼び出しは

しておいて使いたいところで

通信

次に外部から呼び出せるようにserver機能を持たせる。店の外から呼び出す計画のでまずはhttpでそのまま外からつなげられるようする。そのうちリバースプロキシの後ろに隠すかもしれないけどとりあえずルーターにNAPTでさばかせておく。

wifi周り

スマートコンフィグ使おうかと考えたけど、ip指定で起動するときにデフォゲとサブネット与えないといけなかった。そいつらをしっかりと渡すとなると外から与えてスマートコンフィグの意味なくなるか、一回目の接続で取れた値を使用と面倒になりそう。というわけでおとなしく明示的に指定することにした。

と、サンプルにありそうなやつそのまま

server周り

これもよくありそうなやつ。

WebServer.hつかって、呼び出し処理があったら音声を流す処理を行う。

handleYobidashiの中で、speaker#stopVoice/speaker#startVoiceを直接呼んでいるので同期処理になっている。音声が流れ終わってから呼び出し側にはレスポンス返る。使うケース次第では非同期呼び出しにするためにさらにスレッドを呼ぶ形にする方が良い場合は多そう。

続き 呼び出し側の自宅端末バージョンアップ

M5Unified_StackChanを参考にした際のメモ

MP3_with_ESP8266Audio.inoを参考に音声出力をしていたが音がとんだり画面にノイズ?が入ったりとしていた。ツイッターで呟いたらタカヲさん(@mongonta555)から参考情報を教えてもらった。

こちらで音が出るようになった。リンク先レポジトリのメモ書きを残す。なお、M5Unified_StackChanにはあるが試していないものもある。

対象音声フォーマット

readmeにはwavとなっているけどmp3用

バッファ処理

MP3_with_ESP8266Audioにはなかったbuffer処理が入っている。下のあたり

音声ファイルのサンプリングレート

readmeには”wavファイルのサンプリング周波数は16khzか24khzにしてください。”とある。ffmpegで16khzか24khzに変換したかったが、26khzが生成されて直し方がわからなかったので26khzを受け入れて試験。サンプリングレートじゃなくてビットレートが26kbpsだった。

スピーカーのコンフィグ指定

下のようにいくつか指定が入っている。

sample_rate は出来上がったファイルに合わせてみた。

task_priorityは同じコアでの処理優先順位。数時大きい数が優先順位高くたしか23が最大値。m5avaterの中で2が使われているはずなので使っているライブラリの範囲では3にしとけば最優先のはず。

dma_buf_count /dma_buf_len はよくわかっていない。

task_pinned_core は処理をさせるCPUコアの指定(PRO_APP_NUMデフォルトで、もう一個がPRO_APP_NUM)。M5Unified_StackChanではPRO_CPU_NUMを使っていたがデフォルトでも音質違いが分からなかったのでデフォルトに戻してある。

  auto spk_cfg = M5.Speaker.config();
  spk_cfg.sample_rate = 26000;
  spk_cfg.task_priority = 23;
  spk_cfg.dma_buf_count = 20;
  spk_cfg.dma_buf_len = 128;
  //spk_cfg.task_pinned_core = PRO_CPU_NUM;
  M5.Speaker.config(spk_cfg);

ファイルクローズ処理

mp3.stop()の中でもoutやfileのクローズが呼ばれているのでソフトウェア的にはfileやoutのクローズ処理はいらないはず。ただし、どこかのサイト(メモってなかったら出典探せなくなった)で下みたいな書き方の方がスピーカーの最初の音が小さくなるみたいなことが書かれていたのでそちらに合わせた。ちなみに、スピーカーの最初の音とはスピーカーに電源が入る時のボッみたいな音。その違いが分からなかったが、こだわるところでもないので合わせておく。

補足

比較をしていないけどもともと使っていたのが160kbpsの3分というファイルだったのでそいつの影響が大きい気がしなくもない。

3Dプリンターでモデルの特定の場所が出なくなった

OpenSCADでモデル作成からstl出力。Repetier-HostV2.2.4というソフトでスライス&プリンタ操作をしている。使用しているプリンターはIUSEというアマゾンで安かった数年前のもの。

The object is not manifold.
This essentially means, that it is not watertight.
This normally causes problems during slicing, resulting in unwanted results.
We strongly advice to repair the model.

気付いたら上のエラーメッセージがRepetier-Hostにガッツリ出ている。しばらく出力していないモデルだけど昔は気づかなかった。

モデルがwatertight(防水?)でないのでうまくいかんかも知らんので修理しろと。watertightでないはモデルの部品が隙間なく並んでいても、重なる部分がないみたいな状態。1cmの立方体から1cmずらして立方体を置いたら隙間なく隣り合ってはいるけどかぶっている部分がないみたいな状態のはず。

なお、OpenSCADでは昔からnot manifoldという旨のメッセージが出ていたけど実際には出力されるから問題なしと放置していた。

いかにも修理ボタンがRepetier-Hostのエラーメッセージの横に出ているのでボタンを押してやると「オブジェクトは多様状態です」といかにも治った雰囲気のメッセージに変わった。

ところが実際に出力するとうまく出力されないと書こうとしたが、出力されたgcodeをRepetier-Hostのgcodeエディタから保存しオンラインシミュレーターで確認するといけそうなのが出力された。

とりあえず印刷中。ちゃんとOpenSCADでmanifoldにしてやってと書こうとしたが、gcode確認してうまく修理ボタンでなおったらそれでしのぐというのもありかもしれない。

結果が出たら追記する。->結果出た下に

manifoldにしてやらないでも動きそうなgcodeで通常通りに出力された。悪いgcodeと比較しようと思ったが何もしないでも動きそうなgcodeが現状出力されている。また、昔のうまくいかなかったときのgcodeは保存していないどころか観点になくチェックもしていない。

現時点では追加で調べられることもないので様子を見る。(調査いったん終了)

ArduinoIDE2系のキャッシュされたコンパイル済みファイルの消し方

ちょっと面倒。こちらをみると他の方法もあるみたいだけどガッツリ手動削除のほうで(以下の手法もリンク先が元)

消し方

ArduinoIDEのFile->Preference->Setting->Show verbose output duringのcompileにチェックを入れる

そのあとコンパイル実行。

outputに”Using previously compiled file ~”と”Using precompiled core ~”が出力される。その中にある目当てのクラスの場所が出ているはずなので検索。

対象のキャッシュを削除(面倒なら丸ごとフォルダでもいけるはず)

自分のけしたいやつはだけでなくて同じフォルダにいた他のやつも必要だったけどログ取り忘れた。

けしてっやて同じく他のも

Avatar.cppの~はすでに定義済みでうんぬんかんぬんというエラーメッセージだった。Avatar.cppとAvater.oも削除した。(コンパイルされたものがまとめて詰まっているobjs.aを見る作りな気がするのでそっちを削除してもよかったかも)

再度IDEからコンパイル実行(IDEの再起動等はいらないはず)

Show verbose output duringはかなり遅い気がするので好みで元の設定に。

一応発端

動きを調べようとライブラリフォルダのソースをフォルダ内で一旦コピーしてArduinoIDEからビルドした。ところAvatar – コピー.cppもコンパイルされインクルードガードなく(?)重複定義になった。

こんな配置で

PS C:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src> ls

    Directory: C:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----

-a---          2024/03/07    14:40            261 Accessory.h
-a---          2024/03/07    14:40           8007 Avatar - コピー.cpp
-a---          2024/03/07    14:40           8007 Avatar.cpp

コンパイル(IDEのまるっとアップロード)実行

c:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src/Avatar.cpp:233: multiple definition of `m5avatar::Avatar::getColorPalette() const'; C:\Users\kitam\AppData\Local\Temp\arduino\sketches\24ABF9CB78656DF99B51FAEF43A95CDD\libraries\M5Stack_Avatar\objs.a(Avatar - �R�s�[.cpp.o):c:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src/Avatar - �R�s�[.cpp:233: first defined here
c:/users/kitam/appdata/local/arduino15/packages/m5stack/tools/xtensa-esp32-elf-gcc/esp-2021r2-patch5-8.4.0/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld.exe: C:\Users\kitam\AppData\Local\Temp\arduino\sketches\24ABF9CB78656DF99B51FAEF43A95CDD\libraries\M5Stack_Avatar\objs.a(Avatar.cpp.o): in function `m5avatar::Avatar::setColorPalette(m5avatar::ColorPalette)':
c:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src/Avatar.cpp:231: multiple definition of `m5avatar::Avatar::setColorPalette(m5avatar::ColorPalette)'; C:\Users\kitam\AppData\Local\Temp\arduino\sketches\24ABF9CB78656DF99B51FAEF43A95CDD\libraries\M5Stack_Avatar\objs.a(Avatar - �R�s�[.cpp.o):c:\Users\kitam\Documents\Arduino\libraries\M5Stack_Avatar\src/Avatar - �R�s�[.cpp:231: first defined here

自宅用通知マシン作成(3)

スタックチャン風呼び出しマシン作製の続き。(これから書く)

音声の出し方はこちらでしらべて手を付けられそうになった。

まずは出し方で調べた音声用のAudioOutputM5Speakerを別ファイルに切り出し。サンプルソースほぼそのまんま。ただ、他の人とクラス名かぶりそうなのでネームスペースだけ切っておいた。

ファイル名指定したらファイル流す、止める関数追加

void stopVoice() {
  if (mp3.isRunning()) mp3.stop();
}

void startVoice(const char *filename) {
  file.open(filename);
  mp3.begin(&file, &out);
}

セットアップの中でavater.initしてループの中でボタン押されたらストップ&スタートでとりあえず音楽は流れる。が、途切れがち。CPUコア1にだいぶ頑張らせているからかな?

avater.initの中から呼ばれる描画タスクはどちらもcore1で動いている。音声もcore1。今のところ使ってないけどcore0はwifiで結構使うみたいなので開けておきたい。

CPU負荷が原因ならmp3からcpuに優しいwavにしたらいいじゃないと試してみたけど状況は悪化。ファイル形式変更の道もつらそうなのでやはりmp3で頑張ってみる。

試しにスピーカーで使うCPUをcore0に変えても状況は変わらず。もしかしてCPUのせいじゃない??

タカヲさんからサンプルを教えてもらったので一旦こちらを試す。

このあとは調べ中。タカヲさんの調べながら(おわったら?)書き足す->試したときのメモこちら

続きはこちら

EpeaAudioOutputM5Speaker.h)