onsdag 2. desember 2015

Arduino + OLED + Mikrofon = visuell lydmåler

Etter å ha kjøpt et par oleds, en del Arduinoer og mange sensorer, har jeg lekt en del.En av de første tingene jeg gjorde, var å lage en værstasjon som lastet data fra nettet. Men det var jo data som eksisterte fra før i skyen, Vi vet jo at det regner i bergen i morgen også, så hva er vitsen med værmeldingen?


Pga. dårlig støtte for ESP8266 og OLED måtte jeg teste flere biblioteker
før jeg fant ett som fungerte ( 
https://github.com/squix78/esp8266-oled-ssd1306 ).
Det biblioteket lekte jeg litt med, blant annt tok jeg min thingspeak kode og la inn OLED-biblioteket. Det fungerte for det meste fint. Jeg måtte så pause alt av Arduino en stund pga. jeg ikke hadde tid (eller fritid). Men to ting jeg har laget som tok relativt liten innsats:

1. Arduino parkeringssensor (ultrasonisk sensor)


Første prototype på avstandssensor
tallet er centimeter unna objekt
Avstandssensoren kan man lese om her: https://www.arduino.cc/en/Tutorial/Ping

Min sensor har fire pins, en dedikert for sending av ultrasonisk lyd og en pin dedikert for lesing. Men i praksis gjør min kode det samme som den der, i tillegg til OLED-visning.

#Arduino #oled #distance

En video publisert av @olavxxx

2. Arduino lydmåler

Arduino lydmåleren var litt værre, men etter jeg har fått det til er det ikke så vanskelig det heller.
Problemet med lydmåleren er at den i utgangspunktet ser ut til å ikke virke. Folk på det store Internettet påstår også den har veldig lav følsomhet. Det er nok på grunn av at de ikke har skjønt hvordan den virker.

Det første man må gjøre som alt annet, er å skjønne hvordan det henger sammen og hvorfor det virker (eller ikke virker). Dette er jo vanlige problemstillinger for IT-folk :-P
Fire mikrofoner, men den ene mangler 2903 SMD-chippen...
Kina skylder meg en 2903 SMD-chip.

Jeg kjøpte fire mikrofoner for mikrokontrollere på aliexpress, som vanlig fulgte det ikke med manualer eller koblingsskjemaer, heller ei kabler. Men man vet jo at det skal ha spenning og jord, i tillegg vet man jo at digital er 1 eller 0 og analog er 0-X. Jeg sier der X på grunn av at analog er en variabel verdi som avhenger av innverdien. Mikrofonen støtter både 3.3V og 5V, men 5V vil jo gi høyere tall ut.

Når man kobler det opp og leser ut digital verdi får man 1 eller 0, men det er ikke alt. Man kan (og må) kalibrere mikrofonen. Når man gir mikrofonen strøm og jord, lyser det opp to leds:

  • Strømindikator
  • Lydindikator (deteksjon)
Det man må gjøre er å skru og skru, det tar litt tid.. Rotary switch heter dette. Man må skru helt til lyset forsvinner, man skal bare så vidt skru seg dit. Dette må man gjøre i et rom med "vanlig" lydnivå, uten tale, musikk, tv osv. (ingen bakgrunnstøy). Når det er gjort, kan man teste å klappe, plystre eller noe. Da skal det blinke forsiktig i den ene led mens den andre fortsetter å lyse konstant som alltid.

Når man har kalibrert mikrofonen vil man i praksis ha invertert det digitale signalet. Det har ikke noe å si i praksis, men man kan bruke det digitale signalet til å detektere klapp, knipsing eller annet. Kanskje man vil lage en "secret knock" som låser opp døren eller en mikrofon som skrur ned tvlyden hvis den går over et visst nivå? Det er jo uendelig med muligheter her og fantasien setter forsåvidt grensen.

Mikrofonen i seg selv gir da enten 1 eller 0 på digital, men analog gir som sagt X verdi fra 0. I praksis gir den aldri 0, den har en "baseline" som vil variere etter hvor mye bakgrunnstøy man har i rommet. Dette vil i praksis være den verdien man har når man tar å gjør om kalibrert mikrofon til spenning med formelen:

volts = (lestAnalogVerdi * innSpenning ) / 1024
Jeg valgte å bruke 3.3V på grunn av at den har mindre støy enn 5V. Men dette gir uansett ut et tall etter kalibrering, uten at man lager noen lyder. Tallet er nok veldig lavt, kanskje 0.08. Dette vil jo være "baseline" som man må si er et referanse nullpunkt.

Da tar man for eksempel å ganger dette opp for grafisk visning:
double dspval = ((volts-0.07) * 1024)  ;
Jeg trakk der vekk 0.07 som var min kalibrerte baseline, det vil nok være avvik basert på bakgrunnslyder, mikrofon osv. Samt man justerer på en skrue når man kalibrerer, så tallet vil ikke være statisk. Trikset er å skrive ut verdien i console og se hvilken minimumsverdi man får.

Egentlig burde jeg endre koden min til å ha en "baseline" som en variabel, bare ta vare på laveste verdien og bruke den til å filtrere ut. Det vil jo bety at jeg må ha en måte å rekalibrere, en knapp eller noe.. ("calibrate"). Det er jo ganske enkelt, så lenge knappen holdes inne, kan den lese av lydnivået og lagre laveste nivået den får. Deretter bruker man det som referansenullpunktet.

Det tror jeg at jeg må lage en dag jeg har tid :-) Men det blir sikkert ikke i Desember.
Når det er sagt, så tar jeg jo bare da denne verdien og skriver den til OLEDen. Da bruker jeg funksjoner som fins i u8glib biblioteket.

EKsempel på den grafiske "speedometer"-nålen:
u8g.drawLine(0+dataverdien, 32, 64, 64);
Jeg har da en metode som får inn verdien som skrives i tekst i øvre delen av skjermen, samt jeg har da denne "speedometernålen" som bruker samme inndataverdi.

Det jeg har tenkt at jeg burde lage, var en sanntidsgraf, det er jo ganske enkelt egentlig. Jeg kan jo ikke holde for mye data i en mikrokontroller, men det er jo et 128x64 piksel display, hvor jeg dedikerer 128x32 til tekst og 128x32 til grafen. Men i praksis er det ikke heniktsmessig med 32 datapunkter på grunn av at 1 piksel brede datapunkter blir kanskje litt kornete grafikk. Derfor ser jeg for meg at jeg kan fylle en matrise på kanskje 16 eller kanskje så lite som 8. Med 8 blir det jo 32/8 = 4 piksler bredde som kan gi en "fin bakke" mellom punkter på den lille skjermen.

Jeg har uansett ikke komemt i gang med det enda, er bare en tanke jeg har i hodet :-P Men hvis jeg lager den graf-funksjonen, kan jeg jo bruke den til andre ting også. Miljøstasjonen kan jo vise svevestøv, temperatur, fukt osv.

Her er lydmåleren i praksis i en hverdagslig test: