3本ローラーのスマートトレーナー化(その14)
大きく失敗。
モータードライバーの使い方を間違えていた。
を見たら、PWM制御をおこなう場合のことが丁寧に説明してあった。前進後退で2chを使用し、PWMで1ch、合計3chを使用するのが正しい。これまで試みていたのは、前進/後退のチャンネルにPWMを直接入力していた。出力が上がっていなかったかもしれない。
3ch使用するということは、プログラム上は、メインスレッドとサブスレッドの変数受け渡しが無くなるので、その分、シンプルになるはず(はんだ付けが1か所増えるけど)。
早速、スケッチを書いて、ESP32キットの方で試してみたが何かおかしい。Bluetoothが使えなくなっている。サンプルスケッチのSerialtoBluetoothを入れてもつながらない。bluetooth機能が壊れてしまったようだ。
仕方がないのでケースに入れた本番用ESP32に変更してスケッチを入れようとしたが、USBを認識しない。このエラーは前回も出て、何回か試している内に復帰したことを経験している。今回も何回か試している内(アップロード中にリセットボタンを押すのが効いたみたいだ)にスケッチをアップロードすることができた。しかしながら、思ったように動かない。そのうち、USBをつなぐとパソコン側が再起動されるという症状が出始めた。別のパソコンでも同じ症状。完全に壊れてしまったようだ。これでまともに動くESP32が無くなってしまった。
戦意喪失。
ところが丁度タイミング良く(?)、アリエクスプレスに注文していたサーボモーター(996R互換品)が届く。ネオジム+電磁石のトルクが思ったほど上がらないことが分かった時期に注文していたものだ。壊れてしまったESP32のうち、2chのみ生きている個体があった。これが使えるはず。と思ってやってみたら,思惑通り動くようだ。
スケッチはこちら。
/********************************************************************** Filename : Smart_Trainer2 Description : Control training level of the cycle roller by bluetooth with ESP32 and Servo motor Auther : Ribble CrMo Modification: 2023/02/11 **********************************************************************/ #include "ESP32Servo.h" #include "BluetoothSerial.h" #include "string.h" const int SERVO = 2; // サーボモーターピン int angle = 0; String buffer; BluetoothSerial SerialBT; Servo servo; // サーボクラス void setup() { servo.attach(SERVO); // サーボモーターの制御ピン設定 SerialBT.begin("SmartTrainer2"); //Bluetooth device name } void loop() { if (SerialBT.available()) { buffer = SerialBT.readString(); angle = buffer.toInt(); servo.write(angle); delay(10); } }
これを使って、グロータックオリジナルのネオジム磁石使用の誘導電流式の負荷装置を改造することにする。オリジナルの負荷装置の部品をそのまま使って、設定角度もそのまま実装することを考えた。オリジナルの負荷装置にはネオジム磁石とローラーの距離を一定に固定するための穴が5つ開いている。ローラーに最接近する際の穴を穴1、次の穴を穴2・・・とする(穴5はローラーとの距離が十分離れていて無負荷状態のはず。)。
ノギスで測ってみると、
ヒンジと穴の距離:24.00ミリ
穴1-穴2の距離:3.26ミリ
穴2-穴3の距離:4.62ミリ
穴3-穴4の距離:8.94ミリ
穴4-穴5の距離:7.12ミリ
(参考)
穴1-穴5の距離:21.82ミリ
距離がだんだん大きくなるのは、誘導電流の大きさ(負荷の大きさ)の変化率が磁石とローラーの距離が近いと大きくなることから理屈に合っている。
さて、ここから三角関数で角度が計算できる。穴間の距離をx、ヒンジと穴の距離をl、角度をθとすると、
θ =2*arcsin ((x/2)/l)
よって、角度は
穴1-穴2の角度:8度
穴2-穴3の角度:11度
穴3-穴4の角度:21度
穴4-穴5の角度:17度
(参考)
穴1-穴5の角度:54度
角度を全部足すと57度になって、検算用の穴1-穴5の角度と3度違ってしまうが、計測誤差の範囲ということにしてこの角度で実装する。
運動強度レベル0 穴5 57度
運動強度レベル1 穴4 40度
運動強度レベル2 穴3 19度
運動強度レベル3 穴2 8度
運動強度レベル4 穴1 0度
3本ローラーのスマートトレーナー化(その13)
実装用のEPS32(LOLIN D32 アマゾンで990円)が届いたので、動作確認後、配線してケーズに収めた。ピンが付いていないので配線は簡単だ。この機種はアマゾンの感想にUSBを認識しないとあったが、スケッチをアップロードする際に何度かエラーが出たのが、それだろうと思う。それ以外は満足。前のEPS32と違ってVin(外部電圧入力)という端子が無かった。USB経由で立ち上げると「USB」という端子から5V出ていた(「BAT」という端子からは5V弱)。Vinの代わりにUSBという端子に外部電圧を加えたところ動作したので、これで正解だった。
参考までに裏側から見た端子配置を挙げておく(表側からはピン配置の印刷が見えない。)。
EPS32 LOLIN D32 裏側 | ||||||||||||||||
3V | RESET | VP | VN | 34 | 32 | 33 | 25 | 26 | 27 | 14 | 12 | 13 | EN | USB | BAT | |
A | A | A | DAC1 | DAC2 | ||||||||||||
USB側 | ||||||||||||||||
MOS1 | SCL | SBA | MISO | SCK | ||||||||||||
GND | 23 | 22 | TX0 | RXC | 21 | 19 | 18 | 5 | 17 | 16 | 4 | 0 | 2 | 15 | GND |
ネジ穴の位置が前のEPS32と違うので、収めたといってもねじ止めしていない。おまけにネジも2.5ミリ径のようで合わせるネジもない。ぶらぶらの状態でケースに入っている。
しかしながら、ちゃんと動作することを確認。来週はスマートトレーナー部分を3本ローラーに固定して実際に走ってみよう。
動画はアシスト側(トレーニングレベル:ー9)、電磁石を近づけると回転が早く、遠ざけると遅くなる。全力回転は結構速いがトルクはそれほど強くない。
多分、未だ実用にはならないと思う。トルクを強くするためには、
①ローターに貼り付けたネオジム磁石を増やす(4本⇒8本 コスト900円)。今はネオジム磁石の中間地点でトルクがゼロになる死点があるが、それが解消されるのでトルクが倍増する可能性。
②手作り電磁石をもう一個追加。エナメル線購入費が二千数百円。これもトルクが倍増。
③電圧を上げる(例えば、12V⇒24V)。現行(12V)で手作り電磁石はほんのり暖かくなる程度であるので、まだ、電圧を上げる余地がある。電圧倍増でトルクも倍増。ただし、現行のモータードライバー(公称20W)ではギリギリなのでモータードライバーを購入する必要がある(アマゾンで500円くらいであるのだが、本当か?あと24Vの電源アダプターが必要。これは家にあったかもしれない・・・)。
あと、ホール素子も使ってみよう。ホール素子がうまく行くならオペアンプは必要なくなるので、ケースの中身は更にスカスカになる。
結構、小遣いが無くなっていく。実用にもならないかもしれない。作っても使わないかもしれない・・・が、自分が面白ければ良いのだ。
3本ローラーのスマートトレーナー化(その12)
ショックなことにESP32を一枚壊してしまった。800円の損害である。Lチカ、ADコンバータ機能確認後、ブレッドボード用ピンをはんだごてで外して、リード線を付けてケースに収めたがうんともすんとも言わない。外して確認したところ、ADコンバータは生きているが、GPIO(信号出力)が2CH以外のチャンネルがすべて死んでいた。おそらく、はんだごてを使っている際、知らないうちにに素子を加熱してしまったようだ。
今後は十分注意することにして、ピンがついていないEPS32ボードを追加購入(アマゾンで990円)
しかたないので、トレーニングキットのEPS32を接続してテスト。
まずは、センサーの機能確認。ローラーが回転して磁石が通過するたびに赤青と点滅するのがわかる。
LEDをケース内のモータードライバに接続。極性が適宜切り替わって、各種強度のアシスト/レジストを行わせる。
距離をうまく合わせると回転を続ける。この動画ではトレーニング強度として「-9」(アシスト最大強度)を指定して撮影している。大電磁石とローラーの距離は微妙で、近づけすぎると大電磁石の鉄の部分にネオジム磁石が反応して止まってしまう。
次に大電磁石を手作り電磁石に変更する。大電磁石と違って、余計な「鉄」がないので、ローラーとの距離をギリギリまで接近させることが可能。このため、回転数もトルクも大電磁石より大きい。しかしながら、自転車を3本ローラーにセットすると回転はとまってしまう。その程度のトルク強度である。実走は新しいEPS32が届いてからにする。
手で回してレジスト機能を試す。電源を切ると明らかにレジストが切れたことがわかるのだが、それほど強力ではない。
先日、都内出張の帰り、秋葉原の秋月電子にホールセンサーを見に行った。1個売りは無かったが、5個入り150円で「ホールラッチ SK1816MG-G03-K」を購入。これを使って小電磁石の代わりをつとめさせる予定である。うまくいけば、電源シフト回路もEPS32のADコンバータ機能も使わずに思ったことが実現できる筈。
ホールラッチ SK1816MG-G03-K: センサ一般 秋月電子通商-電子部品・ネット通販 (akizukidenshi.com)
3本ローラーのスマートトレーナー化(その11)
スマートトレーナーには、小電磁石の代わりにホール素子が使えるはず。アマゾンで多種販売されているが、10個売りで800円程度。10個はいらないな。
以下のサイトによるとホール素子には機能的に3つのタイプがあるようだ。
はじめての人でも分かるホールセンサーの原理と種類 | 組込み技術ラボ (macnica.co.jp)
(要件)以下の図は、正の負荷(レジスト)を発生させる場合
(ホール素子のタイプ)
したがって、ラッチタイプまたはアナログ出力タイプのホール素子なら使えそう。
秋月電子でバラ売りしていたら購入しよう。なければ、急がないので中華直輸入。
3本ローラーのスマートトレーナー化(その10)
EPS32を使って作成したスマートトレーナーをコントロールするPC側のソフトをPythonで組んだ。
と言っても、
1.トレーニング表(時間(秒)とトレーニング強度(-9 ~ 9))のテキストファイルを読む。
2.ブルートゥースにトレーニング強度の数値を上記表の時間が経過するまでだけ書き出す。
3.同時に画面上にトレーニングの状態を示す画面を表示する。
というもの。分かってしまえば非常にシンプルなのだが、当方は素人なので、画面表示の仕組み、GUIによるファイル選択、カウントダウンとスレッド処理といったことが一々試行錯誤。特に,、最初は単に「シリアル通信」を使えば良いということに中々気が付かず、ブルートゥース周りを調べて時間をとってしまった。
# トレーニングファイルを読み込み、キャンバスにトレーニングファイルの内容(時間(秒)、レベル)を表示するとともに、シリアルポートに一定時間ごとに書き込む # トレーニングファイルフォーマット # 時間(単位:秒(整数))、半角スペース、運動強度(-9 ~ 9(整数)) # (例) # 1 1 # 3 2 # 4 3 # 2 4 # 1 5 ・・・ # (上記を左詰め(スペース無)にする) import serial import time import tkinter as tk import tkinter.filedialog import threading tm = [] level=[] # シリアル通信(ブルートゥース)設定 # 下記'COM6'はパソコン、接続機器によって異なるので、「設定→デバイス→Bluetoothとその他のデバイス # →その他のBluetoothオプション→COMポート」から確認すること。 ser = serial.Serial('COM8',9600) # ウィンドウ設定 root = tk.Tk() root.title(u"トレーニング") root.geometry("1000x200") root.attributes("-topmost",True) button1 = tk.Button(root, text="Start", command=lambda:start()) button1.place(x=500, y=160) # 終了処理 def finish(): ser.close() root.destroy() # キャンバス作成 canvas = tkinter.Canvas(master=None, width=1000, height=100) # キャンバス表示 canvas.place(x=0, y=0) # ファイル選択 filetypes = [("","*")] target_file = tkinter.filedialog.askopenfilename(filetypes=filetypes, title="ファイルを開く") # ファイル読み込み # 配列 tm に時間、配列 level に運動強度を格納する with open(target_file) as f: lines = f.readlines() for line in lines: line = line.split() tm.append(line[0]) level.append(line[1]) # トレーニングデータの個数 ln = len(tm) # 開いたファイルを閉じる f.close() # メインの関数を定義する def training(): # ループ for i in range(ln): # ブルートゥースに運動強度を書き込み line = ser.write(level[i].encode()) # キャンバスに時間(1秒ごとのカウントダウン付き)、運動強度を表示 jmax = int(tm[i]) for j in range(jmax): canvas.delete("all") canvas.create_text(40, 50, text="時間"+"{:3}".format(jmax-j) +"秒 レベル"+level[i], anchor="w", font=(None,36)) time.sleep(1) # トレーニングファイルの終了処理 if(i==ln-1) : canvas.destroy() # スレッド作成 thread1 = threading.Thread(target=training, daemon=True) # スレッド開始 def start(): button1.destroy() button2 = tk.Button(root, text="Exit", command=lambda:finish()) button2.place(x=500, y=160) thread1.start() # イベントループ canvas.mainloop()
その他、使用する際の注意事項(使う人がいるかどうか知らないけれど・・・)。
1.PythonはAnacondaで入れているのだが、シリアル通信を行うためにpyserialは標準で入ってないので追加でインストール。
Pyserial :: Anaconda.org
2.シリアル通信で使用するCOMポート番号は、パソコンとその使用環境によって異なるので確認して適宜変更(上記プログラムではCOM8)。
(確認方法)
(1)プログラム使用前にEPS32(スマートトレーナー)とブルートゥース接続をしておく。
(2)COMポート番号を確認する。
3.Pyinstallerというのを使って実行形式(exeファイル)にしておけば、一々Pythonを立ち上げなくてもワンクリックで起動できる(オプション-onefileにするとファイルサイズがでかくなって重くなるので、自分だけで使う分には指定しない方が良い。)。
qiita.com
プログラムが正常に作動していることを示す動画がこちら。
youtu.be
この状態でADコンバータが正常に作動していることも併せて確認。
youtu.be
この時のトレーニング表のテキストデータはこちら。各行の一番目の数字が時間(秒)、二番目の数字がトレーニング強度(プラス符号の数字はレジスト、マイナス符号の数字はアシスト、数字が大きいほど強度が大きい)
5 9 4 2 3 1 2 0 3 -1 4 -2 5 -9
3本ローラーのスマートトレーナー化(その9)
一応、動くと思われるプログラムができた。
やはりマルチスレッドの処理を行わなくてはならない。EPS32の場合(多分、Arduinoと違って)、マルチスレッドをOSレベルで動かす仕組みがあるようだ。
解説は以下のサイトを参考とさせていただいた。
ESP32でマルチコアを試す12行 - Qiita
別記事のArduinoのマルチスレッド的なものの解説記事では、スレッド間で変数をどうやって受け渡すのかわからなかったのだが、この記事でグローバル変数を使えばいいことがわかった。この方の一連の記事には、他にキューを使った方法、セマフォ(初耳だった)を使う方法も紹介されている。後に行くほど変数の扱いが厳密になる感じ。大変に勉強になるし、本当はグローバル変数を使わない方が良いという知識は持っているのだが、簡単なので安直にグローバル変数を使うやり方を採用。採用してみて、まずいことがありそうなら他のやり方を試すことにする。
/********************************************************************** Filename : Smart_Trainer Description : Control training level of the cycle roller by bluetooth with ESP32 Auther : Ribble CrMo Modification: 2023/01/03 **********************************************************************/ #include "BluetoothSerial.h" #include "string.h" #define PIN_LED1 0 #define PIN_LED2 2 #define CHN1 0 //define the pwm channel #define CHN2 1 //define the pwm channel #define FRQ 1000 //define the pwm frequency #define PWM_BIT 6 //define the pwm precision #define PIN_ANALOG_IN 4 TaskHandle_t thp[1]; //Task handle for multi-task BluetoothSerial SerialBT; int training_level; void setup() { Serial.begin(115200); ledcSetup(CHN1, FRQ, PWM_BIT); //setup pwm channel ledcSetup(CHN2, FRQ, PWM_BIT); //setup pwm channe2 ledcAttachPin(PIN_LED1, CHN1); //attach the led pin to pwm channel ledcAttachPin(PIN_LED2, CHN2); //attach the led pin to pwm channe2 SerialBT.begin("SmartTrainer"); //Bluetooth device name xTaskCreatePinnedToCore(Core0a, "Core0a", 4096, NULL, 3, &thp[0], 0); } void loop() { int adcVal = analogRead(PIN_ANALOG_IN); //if (Serial.available()) { //Serial.println(training_level); //} if (training_level >= 0) { if (adcVal > 2036) { ledcWrite(CHN1, 7 * training_level); ledcWrite(CHN2, 0); } else if (adcVal < 1836) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 7 * training_level); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (training_level < 0) { if (adcVal > 2036) { ledcWrite(CHN1, 0); ledcWrite(CHN2, -7 * training_level); } else if (adcVal < 1836) { ledcWrite(CHN1, -7 * training_level); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } } void Core0a(void *args) { String buffer; while (1) { delay(1); if (SerialBT.available()) { buffer = SerialBT.readString(); training_level = buffer.toInt(); } delay(20); } }
このプログラムでブルートゥースからの通信を受けてLEDの明るさや切り替えを行いつつ、ADコンバータを使用することもできた。ただし実装はまだこれから。
実は実装用にEPS32開発キットを購入したのだが、ADコンバータが不調で色々やっている内にショートさせてしまい、USBインターフェース部分が壊れた模様(直接5V電源を入れるとまだ動くようだ?)。
トレーニングキットを実装用に転用するのは避けたいので新しいものを入手中。
3本ローラーのスマートトレーナー化(その8)
プログラム(Arduino系のマイコンでは「スケッチ」という。)の処理で行き詰っている。
つまり、
1)ブルートゥースで電磁石の強度やLEDの点滅速度をコントロールするスケッチはうまく動いた(シリアル通信を使えばいい。)。
2)ADコンバータからの入力により、LEDや電磁石をオンオフしたり、極性を変更することはできた。
ところが、
3)ブルートゥースからの指示により、ADコンバータからの入力によりオンオフしている電磁石の強度を変更する。
ことができない。具体的には電磁石の強度は変更できるのだが、ADコンバータからの入力が効いていない。
プログラムの途中で変数を吐き出してやってチェックしたところ、ADコンバータが連続して入力を監視し続けるかと思いきや、最初の1回しか動作していないことがわかった。
おそらく、シリアル通信とADコンバータ処理を同時並行的に実施できないことが原因。疑似的なスレッド処理というのを行う必要があると思われる。
たぶん、こういうやつ。
Arduinoでマルチタスクっぽく実行する方法 - Qiita
備忘録代わりに、動かないプログラムを貼っておく。
/********************************************************************** Filename : Smart_Trainer.ino Description : Smartize Roller Trainer for esp32. Auther : EibbleCrMo Modification: 2022/12/26 **********************************************************************/ #include "BluetoothSerial.h" #include "string.h" #define PIN_LED1 0 #define PIN_LED2 2 #define CHN1 0 //define the pwm channel #define CHN2 1 //define the pwm channel #define FRQ 1000 //define the pwm frequency #define PWM_BIT 6 //define the pwm precision #define PIN_ANALOG_IN 4 BluetoothSerial SerialBT; char buffer[20]; static int count = 0; void setup() { Serial.begin(115200); ledcSetup(CHN1, FRQ, PWM_BIT); //setup pwm channel ledcSetup(CHN2, FRQ, PWM_BIT); //setup pwm channe2 ledcAttachPin(PIN_LED1, CHN1); //attach the led pin to pwm channel ledcAttachPin(PIN_LED2, CHN2); //attach the led pin to pwm channe2 SerialBT.begin("SmartTrainer"); //Bluetooth device name } void loop() { int adcVal; while (SerialBT.available()) { buffer[count] = SerialBT.read(); count++; } if (count > 0) { magnet_drive(buffer); } count = 0; memset(buffer, 0, 20); } void magnet_drive(char *buffer) { int adcVal = analogRead(PIN_ANALOG_IN); Serial.print(adcVal); if (strncmp(buffer, "0", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "1", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 7); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 7); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "2", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 14); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 14); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "3", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 21); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 21); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "4", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 28); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 28); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "5", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 35); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 35); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "6", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 42); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 42); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "7", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 49); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 49); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "8", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 56); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 56); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "9", 1) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 63); ledcWrite(CHN2, 0); } else if (adcVal < 2860) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 63); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-1", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 7); } else if (adcVal < 2860) { ledcWrite(CHN1, 7); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-2", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 14); } else if (adcVal < 2860) { ledcWrite(CHN1, 14); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-3", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 21); } else if (adcVal < 2860) { ledcWrite(CHN1, 21); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-4", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 28); } else if (adcVal < 2860) { ledcWrite(CHN1, 28); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-5", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 35); } else if (adcVal < 2860) { ledcWrite(CHN1, 35); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-6", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 42); } else if (adcVal < 2860) { ledcWrite(CHN1, 42); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-7", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 49); } else if (adcVal < 2860) { ledcWrite(CHN1, 49); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-8", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 56); } else if (adcVal < 2860) { ledcWrite(CHN1, 56); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } if (strncmp(buffer, "-9", 2) == 0) { if (adcVal > 2900) { ledcWrite(CHN1, 0); ledcWrite(CHN2, 63); } else if (adcVal < 2860) { ledcWrite(CHN1, 63); ledcWrite(CHN2, 0); } else { ledcWrite(CHN1, 0); ledcWrite(CHN2, 0); } } }