در قسمت سی و سوم از آموزش آردوینو به بررسی اندازهگیری فاصله پرداختیم. در این قسمت قصد داریم درباره تشخیص ارتعاش و تشخیص صدا صحبت کنیم.
یک سنسور Piezo به لرزش واکنش نشان میدهد. این سنسور زمانی بهترین عملکرد را دارد که به یک سطح بزرگتر که دچار لرزش میشود متصل شود. شکل 1 نحوهٔ اتصال را نشان میدهد:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* piezo sketch * lights an LED when the Piezo is tapped */ const int sensorPin = 0; // the analog pin connected to the sensor const int ledPin = LED_BUILTIN; // pin connected to LED const int THRESHOLD = 100; void setup() { pinMode(ledPin, OUTPUT); } void loop() { int val = analogRead(sensorPin); if (val >= THRESHOLD) { digitalWrite(ledPin, HIGH); delay(100); // to make the LED visible } else digitalWrite(ledPin, LOW); } |
سنسور پیزو (Piezo) که به آن سنسور ضربه یا Knock Sensor هم گفته میشود، در پاسخ به فشار مکانیکی، ولتاژ تولید میکند. هرچه فشار واردشده بیشتر باشد، ولتاژ خروجی آن نیز بیشتر خواهد بود. این سنسور دارای قطب مثبت و منفی است؛ سیم مثبت (معمولاً قرمز یا علامت “+”) به ورودی آنالوگ وصل میشود و سیم منفی (معمولاً سیاه یا علامت “–”) به زمین (GND) متصل میشود. یک مقاومت با مقدار زیاد (۱ مگااهم) بهصورت موازی با سنسور قرار میگیرد. این مقاومت برای محافظت از پایههای آردوینو در برابر جریان یا ولتاژ بیش از حد استفاده میشود.
شکل 1: اتصالات سنسور ناک (ضربه)
ولتاژ توسط تابع analogRead آردوینو شناسایی میشود تا یک LED را روشن کند. مقدار THRESHOLD سطحی را که از سنسور دریافت میشود و باعث روشنشدن LED میگردد تعیین میکند.
سنسورهای Piezo را میتوان هم در قابهای پلاستیکی و هم بهصورت دیسکهای فلزی بدون پوشش با دو سیم متصل خریداری کرد.
قطعات داخلی هر دو یکسان هستند؛ هر کدام را که با پروژهتان سازگارتر است استفاده کنید.
برخی سنسورها، مانند Piezo، را میتوان با آردوینو راهاندازی کرد تا همان چیزی را تولید کنند که قادر به شناسایی آن هستند.
در قسمتهای بعدی درباره استفاده از پیزو برای تولید صدا توضیحات بیشتری خواهیم داد.
در این آموزش از برد توسعه BOB-12758 برای میکروفن الکتریت شرکت SparkFun استفاده میشود.
برد را مطابق شکل 2 وصل کرده و کد را روی آن بارگذاری کنید.
اگر از برد ۳٫۳ ولتی استفاده میکنید، باید پایه VCC میکروفن را به ۳٫۳ ولت متصل کنید، نه به ۵ ولت.
شکل 2: اتصالات برد میکروفن
الایدی داخلی زمانی روشن میشود که نزدیک میکروفن دست بزنید، فریاد بزنید یا موسیقی بلند پخش کنید.
ممکن است لازم باشد آستانه (Threshold) را تنظیم کنید— برای این کار از Serial Monitor استفاده کنید تا مقادیر بالا و پایین را ببینید، سپس مقدار آستانه را طوری تغییر دهید که بین مقادیر بالای هنگام وجود صدا و مقادیر پایین در زمان سکوت یا صدای کم قرار بگیرد.
کد تغییریافته را روی برد آپلود کرده و دوباره امتحان کنید.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | /* microphone sketch * SparkFun breakout board for Electret Microphone is connected to analog pin 0 */ const int micPin = A0; // Microphone connected to analog 0 const int ledPin = LED_BUILTIN; // the code will flash the built-in LED const int middleValue = 512; // the middle of the range of analog values const int numberOfSamples = 128; // how many readings will be taken each time int sample; // the value read from microphone each time long signal; // the reading once you have removed DC offset long newReading; // the average of that loop of readings long runningAverage = 0; // the running average of calculated values const int averagedOver = 16; // how quickly new values affect running avg // bigger numbers mean slower const int threshold = 400; // at what level the light turns on void setup() { pinMode(ledPin, OUTPUT); Serial.begin(9600); } void loop() { long sumOfSquares = 0; for (int i=0; i<numberOfSamples; i++) { // take many readings and average them sample = analogRead(micPin); // take a reading signal = (sample - middleValue); // work out its offset from the center signal *= signal; // square it sumOfSquares += signal; // add to the total } newReading = sumOfSquares/numberOfSamples; // calculate running average runningAverage=(((averagedOver-1)*runningAverage)+newReading)/averagedOver; Serial.print("new:"); Serial.print(newReading); Serial.print(","); Serial.print("running:"); Serial.println(runningAverage); if (runningAverage > threshold){ // is average more than the threshold? digitalWrite(ledPin, HIGH); // if it is turn on the LED } else { digitalWrite(ledPin, LOW); // if it isn't turn the LED off } } |
یک میکروفن سیگنالهای الکتریکی بسیار ضعیفی تولید میکند. اگر آن را مستقیماً به پایه آردوینو وصل کنید، هیچ تغییر قابلتشخیصی دریافت نخواهید کرد.
این سیگنال باید ابتدا تقویت شود تا آردوینو بتواند از آن استفاده کند.
برد SparkFun میکروفن را به همراه یک مدار تقویتکننده داخلی دارد که سیگنال را تا سطحی که آردوینو بتواند بخواند، تقویت میکند.
میکروفون سیگنالهای الکتریکی بسیار ضعیفی تولید میکند. اگر آن را مستقیماً به پایه (پین) آردوینو وصل کنید، هیچ تغییر قابل شناساییای دریافت نخواهید کرد. این سیگنال باید ابتدا تقویت شود تا برای آردوینو قابلاستفاده باشد. برد SparkFun یک میکروفون به همراه یک مدار تقویتکننده در خود دارد که سیگنال را تا سطحی که آردوینو بتواند بخواند، تقویت میکند.
ازآنجاکه در این پروژه یک سیگنال صوتی را میخوانید، لازم است محاسبات اضافهای انجام دهید تا بتوانید اطلاعات مفیدی به دست آورید. سیگنال صوتی نسبتاً سریع تغییر میکند و مقداری که تابع analogRead برمیگرداند، بستگی دارد به اینکه در کدام نقطه از موج در حال نوسان اندازهگیری انجام شود.
اگر با استفاده از analogRead آشنا نیستید، به قسمتهای قبلی مراجعه کنید. شکل 3 یک نمونه موج برای یک تُن صوتی را نشان میدهد. همانطور که زمان از چپ به راست پیش میرود، ولتاژ به شکلی منظم بالا و پایین میرود. اگر در سه لحظهٔ مشخصشده روی شکل اندازهگیری انجام دهید، سه مقدار متفاوت خواهید گرفت. اگر این مقادیر را برای تصمیمگیری استفاده کنید، ممکن است به اشتباه نتیجه بگیرید که سیگنال در وسط بلندتر شده است.
برای یک اندازهگیری دقیق، باید چندین بار و در فاصلههای زمانی کوتاه از هم نمونهبرداری کنید. با بزرگتر شدن سیگنال، قلهها و فرورفتگیها (قلهها و فرورفتگیها (troughs)) نیز بیشتر میشوند. اختلاف بین پایینترین نقطهٔ یک فرورفتگی و بالاترین نقطهٔ یک قله را دامنه (Amplitude) سیگنال مینامند، و این دامنه هرچه سیگنال بلندتر شود، افزایش پیدا میکند.
شکل 3: سیگنال صوتی که در سه نقطه اندازهگیری شده است
برای اندازهگیری اندازهٔ قلهها و درهها، باید اختلاف بین ولتاژ نقطهٔ میانی و سطح قلهها و درهها را اندازه بگیرید.
میتوانید این مقدار میانی را مانند یک خط تصور کنید که درست در وسط بالاترین قله و پایینترین دره قرار گرفته است (همانطور که در شکل 4 نشان داده شده است).
این خط نشاندهندهٔ افست DC سیگنال است؛ یعنی مقدار DC زمانی که هیچ قله یا درهای وجود ندارد.
اگر مقدار افست DC را از مقادیر analogRead خود کم کنید، مقدار دامنهٔ سیگنال را به دست خواهید آورد.
شکل 4: سیگنال صوتی همراه با نمایش انحراف DC (نقطهٔ میانی سیگنال)
با بلندتر شدن صدا، میانگین اندازهٔ این مقادیر افزایش مییابد، اما چون برخی از آنها منفی هستند؛ یعنی جایی که سیگنال پایینتر از انحراف DC افت کرده است. این مقادیر مثبت و منفی همدیگر را خنثی میکنند و میانگین تمایل پیدا میکند که به صفر نزدیک شود.
برای حل این مشکل، هر مقدار را به توان دو میرسانیم (یعنی آن را در خودش ضرب میکنیم). این کار باعث میشود همهٔ مقادیر مثبت شوند و همچنین تفاوت بین تغییرات کوچک را بیشتر میکند که به شما کمک میکند تغییرات را بهتر ارزیابی کنید. حالا میانگین مقدارها بالا و پایین خواهد رفت، درست همانطور که دامنهٔ سیگنال تغییر میکند.
برای انجام محاسبه، باید بدانیم چه مقداری را بهعنوان انحراف DC استفاده کنیم. برای بهدستآوردن یک سیگنال تمیز، مدار تقویتکنندهٔ میکروفون طوری طراحی شده است که انحراف DC تا حد ممکن به وسط بازهٔ ولتاژ قابلاندازهگیری نزدیک باشد، تا سیگنال بتواند تا حد امکان بزرگ شود بدون اینکه دچار اعوجاج (Distortion) شود.
کد این فرض را در نظر میگیرد و مقدار 512 را بهعنوان انحراف DC استفاده میکند (که دقیقاً وسط بازهٔ ورودی آنالوگ از 0 تا 1023 است). هر بار که برنامه (Sketch) میانگین مقادیر به توان دو رسیده را برای محاسبهٔ یک خوانش جدید به دست میآورد، میانگین متحرک (Running Average) را بهروزرسانی میکند.
محاسبهٔ میانگین متحرک به این صورت است: ابتدا میانگین متحرک فعلی در مقدار averagedOver – 1 ضرب میشود. وقتی مقدار averagedOver برابر با 16 باشد، میانگین فعلی با وزن 15 محاسبه میشود. سپس مقدار جدید (با وزن 1) اضافه شده و حاصل بر averagedOver تقسیم میشود تا میانگین وزنی به دست آید. فرمول به شکل زیر است:
(currentAverage * 15 + newReading)/16
برنامه (Sketch) مقادیر خوانش جدید و میانگین متحرک را بهگونهای چاپ میکند که بتوانید آنها را با ابزار Serial Plotter از منوی Tools → Serial Plotter مشاهده کنید. شما میتوانید رابطه بین خوانش جدید و میانگین متحرک را در شکل 5 ببینید.
میانگین متحرک کمتر نوسانی و پیکمانند است، یعنی LED برای مدت کافی روشن میماند تا کسی بتواند آن را ببیند، بهجای اینکه فقط در یک پیک کوتاه و سریع چشمک بزند.
شکل 5: مقادیر خوانش جدید و میانگین متحرک نمایش داده شده در Serial Plotter
مقادیر متغیرهایی که در بالای برنامه (Sketch) قرار دارند، قابلتغییر هستند (درصورتیکه برنامه بهخوبی برای سطح صدای موردنظر شما واکنش نشان نداد.)
مقدار numberOfSamples روی ۱۲۸ تنظیم شده است — اگر این مقدار خیلی کوچک باشد، میانگین ممکن است به اندازهٔ کافی چرخههای کامل موج را پوشش ندهد و در نتیجه خوانشها نوسانی و نامنظم شوند. اگر مقدار خیلی زیاد باشد، میانگینگیری در بازهٔ زمانی طولانیتری انجام میشود و صدای خیلی کوتاه ممکن است نادیده گرفته شود؛ چون تغییر کافی ایجاد نمیکند وقتی تعداد زیادی خوانش با هم میانگین گرفته میشوند. همچنین ممکن است تأخیر قابلتوجهی بین صدای ایجاد شده و روشنشدن چراغ به وجود بیاید.
ثابتهایی که در محاسبات استفاده میشوند، مانند numberOfSamples و averagedOver، معمولاً بهصورت توانهای عدد ۲ تنظیم شدهاند (۱۲۸ و ۱۶ به ترتیب). بهتر است برای این مقادیر از اعدادی استفاده کنید که از توانهای ۲ (۲^n) (مثل 128 و 16) باشند تا بهترین عملکرد و سرعت را داشته باشید.
با اینکه مقادیر محاسبه شده بهخوبی برای تشخیص سطح صدا کار میکنند، میتوانید برنامه را تغییر دهید تا با روشهای استاندارد اندازهگیری سطح صدا (دسیبل) همخوانی داشته باشد.
اول، باید نحوهٔ محاسبهی newReading را تغییر دهید و جذر میانگین را بگیرید که به آن ریشه میانگین مربعات Root Mean Square یا RMS گفته میشود. سپس، میخواهید لگاریتم معمولی logarithm پایه ۱۰ هر دو مقدار را بگیرید و آن را در ۲۰ ضرب کنید تا مقدار دسیبل به دست آید.
البته بدون کالیبراسیون، این روش احتمالاً دقت بالایی نخواهد داشت، اما یک نقطهٔ شروع مناسب است.
1 2 3 4 5 6 | newReading = sqrt(sumOfSquares/numberOfSamples); // calculate running average runningAverage=(((averagedOver-1)*runningAverage)+newReading)/averagedOver; Serial.print("new:"); Serial.print(20*log10(newReading)); Serial.print(","); Serial.print("running:"); Serial.println(20*log10(runningAverage)); |
همچنین لازم است آستانه (threshold) را به مقداری خیلی پایینتر تغییر دهید:
1 | const int threshold = 30; // at what level the light turns on |
من کاپیتان آردوینو، اسمم میلاده و اینجا هستم تا تجربیاتم در رابطه با آردوینو رو با شما به اشتراک بزارم!
نویسنده شو !
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.