syouwa-taro が 2023年11月07日07時24分04秒 に編集
コメント無し
本文の変更
# 概要 年と共に耳の高域が落ちテレビの内容が聞きづらくなる。テレビの音を大きくすればよいが、周りに喧しく我慢することになる。内容が聞きづらい人の居る所だけ高域をあげたテレビ音声が届くようにした作品である。 内容は2Wayスピーカシステムで高域には方向が可変できる指向性スピーカーを使う。リスナーからリモコンでスキャンコマンドを受けるとリスナーの角度計測しその角度に高域スピーカー向ける。リスナーの所だけ高域が強調された音が聞こえ、周りは静かで聞きやすいスピーカー。 # システム構成 1. 構成はテレビの音を2Wayスピーカーで鳴らしている。中低域スピーカーは固定で、高域スピーカーは指向性のあるパラメトリックスピーカーを使い、正面から左右にサーボで回転。 2. 人のスキャンはリモコン受光部と赤外線アレーセンサを備え、リモコン信号を一定時間(5秒)受けるとセンサが人の位置を検出し、高域スピーカーがリスナーの正面を向くようサーボが回転する。 (リモコン信号はどのようなフォーマット キーの種類でも受け付ける。長押しのみ受け付けるので通常のリモコン操作では動かず通常の使い方に支障はなく、新しいリモコンが増えることもない) ![キャプションを入力できます](https://camo.elchika.com/f4a7f8e291d806e487b526a2cca1711e791969f1/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f36396464393134632d396432392d343734662d383964612d393830376664386331363265/) ![](https://camo.elchika.com/578f52d45edef09a2404bfe7b6002580953c765d/687474703a2f2f73746f726167652e676f6f676c65617069732e636f6d2f656c6368696b612f76312f757365722f38376461636366622d643365352d343236642d386436312d3538383537333535363238662f63666139313532632d623537382d343032372d386638372d353266303338363331396134/) # キーパーツ | 部品 | 備考 | |:--- |:---| |NANO|Arduino | |ParametoricSpeaker | 秋月実験KIT https://akizukidenshi.com/catalog/g/gK-02617/ | |AMG8833 |赤外線アレーセンサ スイッチサイエンス https://www.switch-science.com/products/3395?_pos=1&_sid=fec692185&_ss=r | |VS18388|赤外リモコン受光ブロック| |MG995|Servoモーター : 大き目ですが回転が遅ければ小型SG90などでもよさそうです。 |L7805|5V三端子レギュレーター Servo用5V(小型ServoでNANO5V出力が使えれば不要)| |SpeakerBOX |テレビの音を聞くスピーカーBOX| |TPA2006| 超小型アンプ 秋月 https://akizukidenshi.com/catalog/g/gK-08161/| |100K~200KVR|中低域SPの音量調整 高域SPとのバランスをとる| # 動画 # @[youtube](https://www.youtube.com/watch?v=Gf4mfZDF5Zw&t=3s) # 感想 # テレビ音声の内容が聞きづらい人に、高域強調することで聞きやすくなる? パラメトリックスピーカーでの実験では多くの人が肯定的であった。作品はリモコン(種類は問わず5秒押し)が送信されるとスピーカーが人を見つけ追尾する電子工作の楽しさがメインでありコストも高く、もっとシンプルにも作れそうです。家族の中一人聞きづらく困っている人に、このような製品を提供する参考となれば幸いです。
[遠くでも障害物があってもよく聞こえるバーチャルスピーカー](https://www.youtube.com/watch?v=V07R_CmRgrI&t=54s) https://www.youtube.com/watch?v=V07R_CmRgrI&t=54s ご視聴もいただければ嬉しいです。
[遠くでも障害物があってもよく聞こえるバーチャルスピーカー](https://www.youtube.com/watch?v=V07R_CmRgrI&t=54s) 参考:パラメトリックスピーカー応用作品
超音波の人体への影響について、いろいろ検証されレポートも出ています。規制する法律はなさそうですが、効果が確認出来る範囲で出力を抑えることが望ましいです。 [強力超音波の安全な利用に向けて:人体への影響](https://www.jstage.jst.go.jp/article/jasj/78/9/78_508/_pdf) [超音波が人体に与える影響](http://humanomics.jp/wp-content/uploads/komatsu.pdf) [パラメトリックスピーカー](https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%A9%E3%83%A1%E3%83%88%E3%83%AA%E3%83%83%E3%82%AF%E3%83%BB%E3%82%B9%E3%83%94%E3%83%BC%E3%82%AB%E3%83%BC) ```arduino:Lチカの例 #define LED_PIN 13 void setup() { pinMode(LED_PIN, OUTPUT); } void loop() { digitalWrite(LED_PIN, HIGH); delay(1000); digitalWrite(LED_PIN, LOW); delay(1000); } ``` ```arduino:よく聞こえる静かなスピーカー #include <Wire.h> #define PCTL 0x00 #define RST 0x01 #define FPSC 0x02 #define INTC 0x03 #define STAT 0x04 //SDA #define SCLR 0x05 //SCL #define AVE 0x07 #define INTHL 0x08 #define TTHL 0x0E #define INT0 0x10 #define T01L 0x80 #define AMG88_ADDR 0x68 // IIC68h:default 69h:jumper //temporaryData to buffer sumtotal IIC ADlow68h ADhigh69h int TMPDAT1[65], TMPDAT2[65], TMPDAT3[65], TMPDATS[65]; int TMPVS[8]; //TemperatureVerticalsum=TMPVS[0]:RRRSum ~ TMPVS[7]:LLLLSum int VSmaxH[3] = {4, 4, 4 }; //サーモセンサ正面 verticalSumax HorizontalAngle ([0]:Servo決定 [1]:Buffer [2]:New = 0:RRRR ~4:center~ 8:LLLL) int TMPVSmax = 0 ; int VSmin = 3000 ; int maxmin ; int SA = 45 ; // ServoAngle Left 0~40度 SP正面40~50度 Right 50度~90度 int RS = 1023 ; //RemoconSignal 0(信号有:送信機正面)~ 1023(信号無) int RSTIM = 0 ; //RemoconSignal Timer 信号がある時間カウント int SCANf = 0 ; //ScanFlg Scan終了まで1を維持 #include <Servo.h> // Servoライブラリの読み込み Servo myservo; // Servoオブジェクトの宣言 const int SV_PIN = 7; // サーボモーターをデジタルピン7に const int PIN_ANALOG_INPUT = 7 ; //リモコン入力をアナログピン7に void setup() { Serial.begin(115200); Wire.begin(); //IIC SCL:A5 SDA:A4 AMG8833(Jumperで変更可能) int fpsc = B00000000;// 1fps datasend(AMG88_ADDR, FPSC, &fpsc, 1); int intc = 0x00; // diff interrpt mode, INT output reactive datasend(AMG88_ADDR, INTC, &intc, 1); // moving average output mode active int tmp = 0x50; datasend(AMG88_ADDR, 0x1F, &tmp, 1); tmp = 0x45; datasend(AMG88_ADDR, 0x1F, &tmp, 1); tmp = 0x57; datasend(AMG88_ADDR, 0x1F, &tmp, 1); tmp = 0x20; datasend(AMG88_ADDR, AVE, &tmp, 1); tmp = 0x00; datasend(AMG88_ADDR, 0x1F, &tmp, 1); int sensorTemp[2]; dataread(AMG88_ADDR, TTHL, sensorTemp, 2); myservo.attach(SV_PIN, 500, 2400); // サーボの割当(パルス幅500~2400msに指定) myservo.write(45); //ServoCenter45度にセット delay(5000); //5秒間で確認 pinMode(2, OUTPUT); //LEDをD2pinに(マイコン内部でLED制限抵抗が付けられるが、命令不明でつかわず) digitalWrite(2,LOW); pinMode(3, OUTPUT); //LED GNDをD3pin digitalWrite(3,LOW); } //setup END void loop() { if (SCANf == 0) //ScanFlg=0の時リモコン受信無限LOOPにはいる ScanFlg=1の時は終了までリモコン受信無限LOOPに入らない {remocon() ;} // Wire library cannnot contain more than 32 bytes in bufffer // 2byte per one data // 2 byte * 16 data * 4 times = 2byte*64point int sensorData[32]; for (int i = 0; i < 4; i++) { // read each 32 bytes dataread(AMG88_ADDR, T01L + i * 0x20, sensorData, 32); for (int l = 0 ; l < 16 ; l++) { int16_t temporaryData = (sensorData[l * 2 + 1] * 256 ) + sensorData[l * 2]; // Vertical_Line 温度ヒストグラム //*** TMPDATSUM();*** 温度Datasum 3Frame合計で安定化 3面のDATAを更新 //Serial.print(temporaryData);Serial.print("TMPDAT3");Serial.println(TMPDAT3[i * 16 + l]); TMPDAT3[i * 16 + l] = TMPDAT2[i * 16 + l]; //2面➦3面 TMPDAT2[i * 16 + l] = TMPDAT1[i * 16 + l]; //1面➦2面 TMPDAT1[i * 16 + l] = temporaryData ; // 新➦1面 TMPDATS[i * 16 + l] = TMPDAT1[i * 16 + l] + TMPDAT2[i * 16 + l] + TMPDAT3[i * 16 + l]; //3面SUM Serial.print(" ");Serial.print(TMPDATS[i * 16 + l]); } //for:I15 END Serial.println(""); } //for:i3 END = 1frame X 3面 complete //*** 温度histgram ∑VerticalLineSum (horizontal angle(0 ~ 7) 毎に縦8ブロック合計を計算) TMPVS[0] = 0; TMPVS[1] = 0; TMPVS[2] = 0; TMPVS[3] = 0; TMPVS[4] = 0; TMPVS[5] = 0; TMPVS[6] = 0; TMPVS[7] = 0; for (int m = 0 ; m < 8 ; m++) //m= 0 ~ 7:水平位置毎に縦一列温度(足~頭)合計する { TMPVS[0] = TMPVS[0]+TMPDATS[0 + m * 8]; //LLLL:sensor左方向温度 TMPVS[1] = TMPVS[1]+TMPDATS[1 + m * 8]; //LLL TMPVS[2] = TMPVS[2]+TMPDATS[2 + m * 8]; //LL TMPVS[3] = TMPVS[3]+TMPDATS[3 + m * 8]; //L TMPVS[4] = TMPVS[4]+TMPDATS[4 + m * 8]; //:sensor正面方向温度:SPのangleをServoでここがMAXになるように向けてゆく TMPVS[5] = TMPVS[5]+TMPDATS[5 + m * 8]; //R TMPVS[6] = TMPVS[6]+TMPDATS[6 + m * 8]; //RR TMPVS[7] = TMPVS[7]+TMPDATS[7 + m * 8]; //RRR:sensor右方向温度 } TMPVS[VSmaxH[0]] = TMPVS[VSmaxH[0]] + 20 ; //ヒストグラムでVSmaxH[0]の温度合計max水平位置のTMPVSに+50のヒステリシスを付ける:チャッタ―防止 Serial.println(""); Serial.println(" 温度vs水平角度 サーモヒストグラム"); Serial.println("LLLL 正面 RRR"); Serial.print(TMPVS[0]);Serial.print(" ");Serial.print(TMPVS[1]);Serial.print(" ");Serial.print(TMPVS[2]); Serial.print(" ");Serial.print(TMPVS[3]);Serial.print(" "); Serial.print(TMPVS[4]);Serial.print(" ");Serial.print(TMPVS[5]);Serial.print(" ");Serial.print(TMPVS[6]); Serial.print(" ");Serial.println(TMPVS[7]); //********1frame Data complete********* objectscan() ; //sensor水平範囲(0:左端~7:右端)でVSmax(=人)をさがす 2frame一致H[1]=H[2])(VSmin:maxと差がない時は人がいない) Serial.print(TMPVSmax);Serial.print("VSmaxH[0]");Serial.print(VSmaxH[0]);Serial.print(" [1]");Serial.print(VSmaxH[1]);Serial.print(" [2]");Serial.print(VSmaxH[2]); Serial.print(" VSmin");Serial.print(VSmin);Serial.print("差");Serial.print(maxmin);Serial.print(" SA");Serial.println(SA); //********TMPVSmax が(sensor水平範囲=3:sensor正面)に来るようにservoを回転 servo() ; delay(20); //delay(50); //delay(100)でチャッタ―(scan発振)防止 } //loop END //**************************************************************************************************** //***************************************************************************************************** void remocon() //Remocon信号 (正面 左右) 有無 判別 { RS = analogRead(PIN_ANALOG_INPUT); if(RS > 900) RSTIM = 0 ; // リモコン信号停止(停止実測:analonRead()=982)するとTimerReset(RSTIM=0秒)しリモコン受信無限ループ開始 while(RSTIM < 5) // リモコン信号有が5秒以下は無限ループでリモコンを受け継ずける { while(RS > 900) //リモコン信号がない(RS>900~1034:実測982)時は無限ループでリモコンを受け続ける { RS = analogRead(PIN_ANALOG_INPUT); Serial.print(RS);Serial.print(" ");Serial.println(RSTIM); } RSTIM++ ; //リモコン信号あり 時間カウント(5秒以上あると受信無限ループを抜ける) delay(1000); } } //リモコン信号5秒以上ありで無限ループから抜ける void datasend(int id, int reg, int *data, int datasize) { Wire.beginTransmission(id); Wire.write(reg); for (int i = 0; i < datasize; i++) { Wire.write(data[i]); } Wire.endTransmission(); } void dataread(int id, int reg, int *data, int datasize) { Wire.beginTransmission(id); Wire.write(reg); Wire.endTransmission(false); Wire.requestFrom(id, datasize, false); for (int i = 0; i < datasize; i++) { data[i] = Wire.read(); } Wire.endTransmission(true); } void objectscan() //Thermosensor縦一列合計のMax Minの値と水平位置(0~7)を特定 { TMPVSmax = 0; VSmaxH[2]=0; VSmin = 3000; //仮初期値設定 for ( int h = 0; h < 8; h++ ) { if (TMPVSmax < TMPVS[h]) {TMPVSmax = TMPVS[h] ; VSmaxH[2] = h ;} //VSmax[2]:NewmaxData if (VSmin > TMPVS[h]) {VSmin = TMPVS[h] ;} //VSmin:NewminData } maxmin = TMPVSmax - VSmin ; if (VSmaxH[1] == VSmaxH[2]) VSmaxH[0] = VSmaxH[1]; //2frame 一致 VSmax[0]に代入 else VSmaxH[1] = VSmaxH[2]; //2frame 一致せず Buffer(=VSmaxH[1])⇐NewData(VSmax[2]) VSmax[0]変更なし } void servo() //Therosensor縦一列合計MaxのSensor水平位置が人の正面(VSmaxH[0]=4)になるようServo angleを向けてゆく { SCANf = 1 ; digitalWrite(2,HIGH); //Scan中は1を立てScan終了までリモコン無限LOOPに入らない LED点灯 if ((maxmin > 30) && (TMPVSmax > 1600)) //ひとがいるmaxmin差>50 and TMPVS>2700 (実測 朝人/3m:1800 1m:昼2700 日差し窓/3m:2000 2300 ) { if (VSmaxH[0] < 4) SA = SA-1 ; //Servo: 人はsensor左 to 人の正面(VSmaxH[0]=4 SA=人のangleまで)へServoで左に向けてゆく else if (VSmaxH[0] >4) SA = SA+1 ; //Servo: 人はsensor右 to 人の正面(VSmaxH[0]=4 SA=人のangleまで)へServoで右に向けてゆく else {SCANf = 0 ; digitalWrite(2,LOW); } //if (VSmaxH[0] == 4 ) //人はsensor正面 SA=人のangle で停止 Scan終了 ScanLED OFF } if (SA <= 0) SA = 0 ; // Servo 0度以下limit :(SP正面-45度左) if (SA >= 90) SA = 90 ; // Servo 90度以上limit:(SP正面+45度右) myservo.write(SA) ; //Servo動かす } //END ```