مقدمه
به آموزش اجرای یادگیری ماشین با رزبری پای پیکو خوش آمدید. این آموزش، دستورالعملهای گام به گامی را در اختیار شما قرار میدهد؛ از درک اصول یادگیری ماشین گرفته تا ساخت پروژه های هوشمند به همراه تمرینهای عملی و نمونههای واقعی.

تصور کنید بتوانید از قدرت یادگیری ماشین در میکروکنترلرهایی نظیر رزبری پای پیکو استفاده کنید. با ادغام قابلیتهای یادگیری ماشین و رزبری پای پیکو با استفاده از Edge Impulse، میتوانید دنیای جدیدی از امکانات را به روی خود بگشایید.
رزبری پای پیکو یک پلتفرم کمهزینه و در عین حال قدرتمند است و Edge Impulse یک محیط توسعه بصری را برای آموزش و استقرار مدلهای یادگیری ماشین ارائه میدهد. آنها دست در دست هم میتوانند به ایدههای شما—با روشهایی که هرگز فکرش را هم نمیکردید—جامۀ عمل بپوشانند.
آنچه در این آموزش یاد می گیرید
- مفهوم یادگیری ماشین
- نحوه ایجاد مدل از روی فایلها
- اجرای یادگیری ماشین در رزبری پای پیکو
اصول پیادهسازی یادگیری ماشین در رزبری پای پیکو
قبل از اینکه به ساخت مدلهای یادگیری ماشین بپردازیم، ابتدا با اصول اولیه یادگیری ماشین آشنا میشویم. یادگیری ماشین زیرمجموعهای از هوش مصنوعی است و بر توسعه الگوریتمها و مدلهایی تمرکز میکند که میتوانند از دادهها یاد بگیرند و بدون برنامهریزی صریح، پیشبینی کنند یا تصمیم بگیرند.
سه نوع اصلی یادگیری ماشین وجود دارد: یادگیری تحت نظارت، یادگیری بدون نظارت و یادگیری تقویتی. در یادگیری نظارت شده، مدل از دادههای برچسبدار یاد میگیرد، جایی که هر نقطه داده با یک برچسب یا خروجی هدف مرتبط است. از سوی دیگر، یادگیری بدون نظارت، با دادههای بدون برچسب سروکار دارد و هدف آن یافتن الگوها یا ساختار در دادهها است. یادگیری تقویتی، بر یک سیستم مبتنی بر پاداش متکی است، جایی که مدل از طریق آزمون و خطا یاد میگیرد تا پاداش را به حداکثر برساند.

انتخاب الگوریتم یادگیری ماشین برای رزبری پای پیکو و آردوینو
برای اعمال الگوریتمهای یادگیری ماشین در Raspberry Pi Pico و Arduino، درک محدودیتهای این میکروکنترلرها بسیار مهم است. به دلیل قدرت محاسباتی و حافظه محدود آنها، باید الگوریتمهایی را انتخاب کنیم که سبک بوده و برای محیطهایی با محدودیت منابع، بهینه شده باشند.
جمعآوری و آمادهسازی دادهها برای یادگیری ماشین
برای ساخت مدلهای یادگیری ماشین مؤثر، باید دادههای خود را جمعآوری و آماده کنید. جمعآوری دادهها شامل جمعآوری مجموعههای داده مرتبط است که حاوی ویژگیها یا متغیرهایی است که میخواهید مدل شما از آنها یاد بگیرد. این مجموعه داده ها را میتوانید از منابع مختلفی مانند داده¬های آنلاین، دادههای حسگر یا جمعآوری دستی دادهها به دست آورید.
Edge Impulse و نقش آن در ادغام یادگیری ماشین
Edge Impulse یک پلتفرم توسعه پیشرفته است که فرآیند ادغام یادگیری ماشین را با سیستمهای embedded مانند رزبری پای پیکو ساده میکند. این پلتفرم یک رابط کاربرپسند را برای جمعآوری، پیشپردازش، آموزش و استقرار مدلهای یادگیری ماشین به طور مستقیم بر روی دستگاه شما، فراهم میکند.
برای شروع کار با Edge Impulse، به دانش گستردهای از الگوریتمهای یادگیری ماشین یا تخصص کدنویسی نیاز ندارید. این پلتفرم طیف وسیعی از ابزارها و ویژگیها را ارائه میدهد و توسعهدهندگان در تمام سطوح مهارت قادر خواهند بود تا از قدرت یادگیری ماشین استفاده کنند. از جمعآوری دادهها تا استقرار مدل، Edge Impulse کل فرآیند را ساده میکند و برای هر کسی که به ساخت برنامههای کاربردی هوشمند علاقهمند باشد، قابل دسترسی است.

یکی از مزایای کلیدی Edge Impulse، مدیریت یکپارچه دادهها و پیشپردازش است. این پلتفرم از طیف وسیعی از سنسورها و انواع دادهها پشتیبانی میکند و به شما امکان میدهد دادهها را از منابع مختلف ضبط و پردازش کنید. چه با دادههای شتابسنج، سیگنالهای صوتی یا ورودیهای تصویر سر و کار داشته باشید، Edge Impulse ابزارهای لازم را برای پیشپردازش دادهها قبل از آموزش مدلهای یادگیری ماشین فراهم میکند. این امر، نیاز به پردازش دستی دادهها را از بین برده و زمان و تلاش شما را در فرآیند توسعه صرفهجویی میکند. علاوه بر این، Edge Impulse یک رابط بصری برای برچسبگذاری و حاشیهنویسی دادهها دارد که ایجاد مجموعه دادههای با کیفیت بالا برای آموزش مدلهای شما را آسانتر میکند.
همانطور که گفتیم ادغام یادگیری ماشین با Raspberry Pi Pico با استفاده از Edge Impulse مزایای بسیاری دارد: تصور کنید بتوانید یک سیستم خانه هوشمند دلخواه بسازید یا رباتی که بتواند به طور مستقل حرکت کند. از این طریق میتوانید برنامههایی را توسعه دهید که زمانی فقط با سختافزارهای پیشرفته و الگوریتمهای پیچیده امکانپذیر بودند.
مزایای انجام یادگیری ماشین با رزبری پای پایکو
یادگیری ماشین با Raspberry Pi Pico مزایای بیشماری را برای توسعه دهندگان و علاقهمندان به همراه دارد. در اینجا به برخی از مزایای کلیدی اشاره میکنیم:
1. پلتفرم کم هزینه: Raspberry Pi Pico یک راهحل مقرون به صرفه برای ساخت سیستمهای embedded ارائه میدهد. با قیمت فقط چند دلار، گزینهای مقرون به صرفه برای علاقمندان، دانشآموزان و حرفهایهاست.
2. محیط توسعه همهکاره: Raspberry Pi Pico —یک محیط توسعه همهکاره— با زبانهای برنامهنویسی مختلف از جمله MicroPython و C/C++ سازگار است. این انعطافپذیری به توسعهدهندگان اجازه میدهد تا زبانی را که با آن راحتتر هستند انتخاب کنند. چه از علاقهمندان به پایتون باشید و چه ترجیح میدهید با C/C++ کار کنید، Raspberry Pi Pico یک محیط آشنا برای توسعه برنامههای کاربردی هوش مصنوعی فراهم میکند.
4. حریم خصوصی و امنیت: با پردازش دادهها به صورت محلی در دستگاه، میتوانید اطمینان حاصل کنید که اطلاعات حساس و خصوصی، ایمن باقی میمانند. این امر به ویژه برای کاربردهایی که دادههای شخصی یا محرمانه را مدیریت میکنند بسیار مهم است.
لوازمی که به آن احتیاج دارید
تشخیص صدا و فرامین صوتی با استفاده از رزبری پای پیکو
فناوری نقطهیابی کلمات کلیدی (Keyword spotting (KWS)) در طیف گستردهای از برنامههای کاربردی روزمره استفاده میشود. با این فناوری میتوانید بدون دست با دستگاه کار کنید (با دستورات صوتی). تشخیص کلمات بیدار کننده معروف OK Google، Alexa، Hey Siri یا Cortana کاربرد خاصی از این فناوریاند، جایی که دستیار هوشمند قبل از شروع به تعامل با دستگاه، به طور مداوم به عبارت جادویی گوش میدهد.
در ادامه، نحوه استفاده از KWS از طریق Edge Impulse را بر روی برد رزبری پای پیکو نشان خواهیم داد:
ابتدا، مدلی را بر اساس ضرایب مغزی فرکانس مل (Mel-frequency cepstral coefficients (MFCC))، که یکی از محبوب ترین ویژگیهای تشخیص گفتار است طراحی خواهیم کرد. سپس، نحوه استخراج MFCCها از نمونههای صوتی و آموزش مدل یادگیری ماشین (ML) را شرح خواهیم داد.
هدف ما نشان دادن چگونگی توسعه یک برنامه کاربردی KWS با Edge Impulse و آشنایی با اکتساب دادههای صوتی از مبدل آنالوگ به دیجیتال (ADC) است.
برای این منظور، دستورالعمل زیر را پیادهسازی میکنیم:
- جمعآوری داده¬های صوتی مرتبط
- استخراج ویژگیهای MFCC از نمونههای صوتی
- طراحی و آموزش مدل شبکه عصبی (Artificial Neural Network (ANN))
- ساخت مدار با Raspberry Pi Pico
- نمونهگیری صدا با ADC و وقفه تایمر
ساخت مدل در محیط Edge Impulse
- به این لینک مراجعه کرده و یک حساب کاربری در سایت Edge Impulse ایجاد کنید
- طبق تصویر زیر، وارد قسمت Projects شده و بر روی دکمه “+Create project” کلیک کنید. نام پروژه خود را انتخاب کرده و بر روی دکمه Create new project بزنید.
- در پنل Dashboard، در قسمت Project info تنظیمات را مطابق تصویر زیر انجام دهید.
- این فایل را دانلود کرده و آن را از حالت فشرده خارج کنید.
در پنل Dashboard، با کلیک بر روی کلید Add existing data پنجره جدیدی باز میشود؛ در آن گزینه Upload data را بزنید. قسمت Upload info category را بر روی Training تنظیم کرده و پس از وارد کردن Label دلخواه، با کلیک بر روی Choose files فایل¬های مرتبط با آن را آپلود کنید.
ما در اینجا، برای فایل¬های پوشه yes، no و unknown، به ترتیب لیبل¬های 01_Yes، 02_No و 03_Unknown را وارد کردیم.
پس از زدن دکمه Upload، فایلها بارگذاری میشوند.
پس از بارگذاری فایلها، طول زمانی کل فایلهای صوتی بارگذاری شده در بالای صفحه Data acquisition درج می شود.
- ر در پنل Impulse design، ابتدا روش استخراج ویژگی¬های (Features) مورد نیاز برای آموزش شبکه عصبی را تعیین میکنیم. برای این منظور، ویژگیهای Mel-frequency cepstral coefficients (MFCC) را به کار می¬گیریم.
همانطور که در تصویر زیر نشان داده شده است، با کلیک بر روی گزینه Create impulse از منوی سمت چپ شروع به طراحی اولین Impulse خود میکنیم:
در بخش Create impulse، مطمئن شوید که فیلد Window size در قسمت Time series data بر روی 1000 میلیثانیه و فیلد window increase بر روی 500 میلیثانیه تنظیم شده باشد.
Window increase پارامتری است که به طور خاص برای کاربرد در Continuous KWS است، جایی که یک جریان صوتی پیوسته وجود دارد و ما نمیدانیم چه زمانی گفتار شروع میشود. در این سناریو، ما باید جریان صوتی را به پنجرهها یا بخشهایی با طول مساوی تقسیم کرده و استنتاج ML را روی هر یک اجرا کنیم. همانطور که در نمودار زیر نشان داده شده، Window size طول زمانی پنجره، و Window increase فاصله زمانی بین دو بخش متوالی است.
مقدار Window size به طول نمونه آموزشی (1 ثانیه) بستگی دارد و ممکن است بر نتایج دقت تأثیر بگذارد. برعکس، مقدار Window increase بر نتایج یادگیری تأثیر نمیگذارد، اما بر احتمال تشخیص درست شروع گفتار تأثیر میگذارد. در واقع، کاهش مقدار Window increase باعث افزایش احتمال تشخیص صحیح شروع گفتار میشود. با این حال، مقدار مناسب Window increase به تأخیر مدل بستگی دارد.
مراحل زیر نحوه طراحی یک بلوک پردازشی برای استخراج ویژگیهای MFCC از نمونههای صوتی ضبط شده را نشان میدهد:
1. کلیک بر روی دکمه Add a processing block و اضافه کردن Audio (MFCC)
2. کلیک بر روی دکمه Add a Learning block و اضافه کردن Classification (Keras)
بلوک Output features مطابق تصویر زیر باید 3 کلاس خروجی را گزارش کند تا شناسایی شوند (01_Yes, 02_No, 03_Unknown).
3. ذخیره ایمپالس با کلیک بر روی دکمه Save Impulse
4. کلیک بر روی MFCC در دسته design Impulse
5.تنظیم پارامترهای موثر بر استخراج ویژگی MFCC
در اینجا میتوانید پارامترهای مؤثر بر استخراج ویژگیهای MFCC مانند تعداد ضرایب مغزی و فیلترهای مثلثی اعمال شده برای مقیاس Mel را تنظیم کنید. در این آموزش، تمام پارامترهای MFCC در مقادیر پیشفرض خود نگهداری میشوند.
در پایین صفحه نیز پارامتری برای مرحله pre-emphasis وجود دارد. مرحله pre-emphasis قبل از تولید یک طیفنگار، با افزایش انرژی در بالاترین فرکانسها برای کاهش اثر نویز انجام میشود. اگر Coefficient value صفر باشد، هیچ تاکید قبلی روی سیگنال ورودی وجود ندارد. در اینجا، پارامتر pre-emphasis در مقدار پیشفرض خود نگهداری میشود.
6. بر روی دکمه Generate features کلیک کنید تا ویژگیهای MFCC را از نمونههای آموزشی استخراج کنید.
Edge Impulse در پایان این فرآیند، پیام Job completed را در خروجی کنسول بر میگرداند.
اکنون ویژگیهای MFCC از تمام نمونههای صوتی ضبط شده استخراج شده است.
مشاهده نتایج استخراج ویژگی¬ها
بعد از استخراج MFCC، برای بررسی مجموعه داده آموزشی تولید شده، میتوانیم مشابه شکل زیر از ابزار Feature explorer و نمودار پراکندگی سه بعدی استفاده کنیم.
از نمودار بالا باید استنباط کنیم که آیا ویژگیهای ورودی برای مساله ما مناسب هستند یا خیر. در صورت مناسب بودن، کلاسهای خروجی (به جز دسته خروجی ناشناخته) باید به خوبی از هم جدا شده باشند.
میتوانید میزان حافظه موقت و مدت زمان پردازش داده را در بخش On-device performance مربوط به MFCC مشاهده کنید.
زمان پردازش (تاخیر) و حداکثر استفاده از RAM (حافظه داده) با توجه به دستگاه مورد نظر انتخاب شده در Dashboard و در قسمت Project info تخمین زده میشوند .
طراحی و آموزش مدل NN
در این دستورالعمل، ما از معماری NN زیر برای تشخیص گفتار استفاده خواهیم کرد:
این مدل دارای دو لایه کانولوشن دو بعدی، یک لایه حذفی و یک لایه کاملاً متصل است که به دنبال آن یک فعالسازی softmax انجام میشود.
ورودی شبکه، ویژگیهای MFCC است که از نمونههای صوتی 1 ثانیهای استخراج شدهاند.
آمادهسازی
برای آماده شدن برای انجام این کار، فقط باید بدانیم چگونه یک NN را در Edge Impulse طراحی و آن را آموزش دهیم.
بسته به بلوک یادگیری انتخاب شده، Edge Impulse از چارچوبهای زیربنایی ML مختلف برای آموزش بهرهبرداری میکند. در این قسمت Edge Impulse برای بلوک یادگیری classification، از TensorFlow به همراه Keras استفاده میکند.
طراحی مدل را میتوان به دو صورت انجام داد:
- حالت بصری (حالت ساده): سریعترین راه بوده و از طریق رابط کاربری (UI) انجام میشود. Edge Impulse برخی از بلوکهای اولیه NN و تنظیمات معماری آن را ارائه میکند؛ بنابراین اگر به تازگی تجربه یادگیری عمیق (DL) را شروع کرده باشید، بسیار مفید خواهند بود.
- حالت کد Keras (حالت تخصصی): اگر بخواهیم کنترل بیشتری روی معماری شبکه داشته باشیم، میتوانیم کد Keras را مستقیماً در مرورگر وب ویرایش کنیم.
مراحل انجام کار
بر روی شبکه عصبی (Keras) در Impulse design کلیک کرده و مراحل بعدی را برای طراحی و آموزش NN ارائه شده در شکل ساختار شبکه عصبی نمایش داده شده دنبال کنید.
1. پیش تنظیم معماری 2D Convolution را انتخاب کنید و لایه Dropout را از بین دو لایه کانولوشن بردارید.
2. با کلیک بر روی علامت ⋮ به حالت Keras (حرفهای) بروید. در قسمت کدنویسی، لایههای MaxPooling2D را حذف کنید:
مطابق کد زیر، گامهای اولین لایه کانولوشن را روی (2،2) قرار دهید.
model.add(Conv2D(8, strides=(2,2), kernel_size=3, activation='relu', kernel_constraint=tf.keras. constraints.MaxNorm(1), padding='same'))
لایه ادغام (pooling layer) یک روش نمونهبرداری فرعی است که اطلاعات منتشر شده در شبکه و خطر overfitting را کاهش میدهد. با این حال، این عملگر ممکن است تاخیر و استفاده از حافظه RAM را افزایش دهد. در دستگاههایی مانند میکروکنترلرها که حافظه محدودی دارند، حافظه یک منبع گرانبها است که باید تا حد امکان بهینه استفاده شود. بنابراین، ایده ما اتخاذ گامهای غیر واحدی در لایههای convolution برای کاهش بعد فضایی است. این رویکرد معمولاً کارایی بیشتری دارد زیرا از محاسبات pooling layer به طور کامل صرف نظر میکنیم، و با توجه به عناصر خروجی کمتر جهت پردازش، میتوانیم لایههای convolution سریعتری داشته باشیم.
3. فرایند آموزش را با کلیک بر روی دکمه Start training شروع کنید:
کنسول خروجی دقت و خطای مجموعه دادههای آموزشی و اعتبارسنجی آن را در طول آموزش پس از هر مرحله گزارش میکند.
در پایان آموزش، میتوانیم عملکرد مدل (دقت و خطا)، ماتریس confusion و عملکرد تخمینی دستگاه را در همان صفحه ارزیابی کنیم.
اگر از دقت مدل راضی نیستید، توصیه میکنیم اطلاعات بیشتری را جمعآوری کنید و دوباره مدل را آموزش دهید.
حال می¬توانید مدل ایجاد شده را به صورت فایل کتابخانه آردوینو دانلود کنید. به این منظور، به قسمت Deployment مراجعه کنید و پس از انتخاب گزینه Arduino library بر روی Build بزنید.
ساخت مدار با Raspberry Pi Pico برای کنترل صوتی LED
Raspberry Pi Pico تنها خود میکروکنترلر را بر روی برد خود دارد. بنابراین، برای انجام کنترل صوتی در این پلت فرم، باید یک مدار ساده بسازیم.
در این قسمت، مداری با Raspberry Pi Pico، یک میکروفون الکتریت با تقویت کننده MAX9814 و دکمه فشاری میسازیم.
معرفی ماژول آمپلیفایر میکروفون الکتریت با MAX9814
میکروفونی که در این آموزش به کار گرفته شده، تقویت کننده میکروفون الکتریت ارزان قیمت MAX9814 است.
سیگنالی که از میکروفون میآید اغلب کوچک است و برای ضبط و تجزیه و تحلیل آن، نیاز به تقویت دارد. به همین دلیل، خروجی میکروفون با تراشه MAX9814 که یک تقویت کننده با کنترل بهره خودکار داخلی (AGC) است تقویت می¬شود. AGC این امکان را به ما میدهد تا گفتار را در محیطهایی که سطح صدای پسزمینه به طور غیرقابل پیشبینی تغییر میکند ضبط کنیم. بنابراین، MAX9814 به طور خودکار میزان تقویت را تنظیم میکند تا صوت مورد نظر ما همیشه متمایز باشد.
تقویتکننده به ولتاژ تغذیه بین 2.7 و 5.5 ولت نیاز دارد و خروجی آنالوگ با ولتاژ پیک به پیک 2V و آفست 1.25 ولت (DC) تولید میکند. بنابراین، میتوان دستگاه را به راحتی به ADC میکروکنترلرهایی که با سطح ولتاژ 3.3 ولت کار می¬کنند متصل کرد.
همانطور که در تصویر زیر نشان داده شده، ماژول میکروفون دارای پنج پایه است.
سیمکشی
مطابق تصویر زیر، سیمکشی را انجام دهید.
نمونهبرداری صدا با ADC و وقفههای تایمر در Raspberry Pi Pico
اکنون تمامی قطعات به برد رزبری پای متصل هستند. تنها کاری که باقی مانده، کدنویسی است.
کد نوشته شده، پس از فشردن کلید فشاری، صوت را به مدت 1 ثانیه ضبط کرده و پس از استخراج ویژگیهای آن، اطلاعات را وارد شبکه عصبی مصنوعی می¬کند و پس از انجام عملیات Classification، نتیجه آن را به صورت متنی در درگاه سریال نمایش می¬دهد.
بنابراین، اولین مرحله، خواندن سیگنال صوتی است. برای این کار، باید از مبدل آنالوگ به دیجیتال (ADC) استفاده کنید. تراشه RP2040 در Raspberry Pi Pico دارای چهار عدد پایه ADC با رزولوشن 12 بیت و حداکثر فرکانس نمونهبرداری 500 کیلوهرتز است.
ADC در حالت one-shot پیکربندی میشود، یعنی به محض اینکه ما درخواست کنیم ADC نمونه را ارائه میدهد.
تایمر جانبی برای ایجاد وقفه در فرکانس مشابه با نرخ نمونهبرداری ADC تنظیم میشود. بنابراین، سرویس وقفه (ISR) مسئول نمونهبرداری از سیگنال دریافتی از میکروفون و ذخیره دادهها در بافر صوتی خواهد بود.
از آنجا که حداکثر فرکانس ADC پانصد کیلوهرتز است، حداقل زمان بین دو تبدیل متوالی 2 میکروثانیه خواهد بود. این محدودیت مشکلی برای ما ایجاد نمیکند زیرا سیگنال صوتی در 16 کیلوهرتز نمونهبرداری میشود.
مراحل پروگرام کردن رزبری پای پیکو در نرمافزار PlatformIO
قبل از ورود به نرمافزار PlatformIO، ابتدا وارد نرمافزار Arduino IDE شوید و در قسمت Tools->Board->Boards manager، عبارت rp2040 mbed را جستجو کنید. سپس نسخۀ مورد نظر را انتخاب کرده و بر روی دکمه Install کلیک کنید. منتظر بمانید تا عملیات نصب پایان یابد. در پایان برنامه Arduino IDE را ببندید.
نرمافزار PlatformIO، یکی از اکستنشنهای Visual Studio Code است.
میتوانید نرمافزار Visual Studio Code را از این لینک دانلود و نصب کنید.
بعد از نصب و اجرای نرمافزار، وارد قسمت Extensions شوید (Ctrl+Shift+X) و در قسمت جستجو، لغت PlatformIO را وارد کنید.
پس از نصب، مراحل زیر را انجام دهید:
- ایجاد پروژه
- کلیک بر روی New Project
- تعیین نام پروژه، نوع برد و فریم ورک
فایلهای مربوط به پروژه شما به صورت پیشفرض در پوشه Documents قرار میگیرند.
- نصب کتابخانه مدل آموزش داده شده
حال فایل کتابخانه مدلی را که دانلود کردید از حالت فشرده خارج کرده و محتویات پوشه src را در مسیر زیر کپی کنید:
Documents->PlatformIO->YOUR PROJECT NAME->src
- وارد کردن کد برنامه
بهPlatformIO برگردید و فایل main.cpp را از فولدر src باز کنید.
حال کد زیر را در آن کپی کنید.
/*
modified on Aug 2, 2023
Modified by Majid Merati from https://github.com/PacktPublishing/TinyML-Cookbook/blob/main/Chapter04/ArduinoSketches/09_kws_raspberrypi_pico.ino
Home<iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted" style="position: absolute; clip: rect(1px, 1px, 1px, 1px);" title="“Home” — Electropeak" src="https://electropeak.com/learn/embed/#?secret=KTH16T9rTr#?secret=LxRUjhNCQn" data-secret="LxRUjhNCQn" width="600" height="338" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
*/
#include "mbed.h"
#include "hardware/adc.h"
// If your target is limited in memory remove this macro to save 10K RAM
#define EIDSP_QUANTIZE_FILTERBANK 0
/* Includes ---------------------------------------------------------------- */
#include <YesOrNo_inferencing.h>
#define ON 1
#define OFF 0
#define PRESSED 0
#define LEDR p9
#define LEDG p8
#define LEDB p7
#define LED_BUILTIN p25
#define BUTTON p10
#define BIAS_MIC 1552 // (1.25V * 4095) / 3.3
#define AUDIO_SAMPLING_RATE 16000.0
#define NUM_YesOrNo 3
#define PROBABILITY_THR 0.5
#define GAIN 1
static mbed::Ticker timer;
static mbed::DigitalOut led_builtin(LED_BUILTIN);
static mbed::DigitalIn button(BUTTON);
/** Audio buffers, pointers and selectors */
typedef struct {
int16_t *buffer;
int16_t *buffer_filtered;
uint8_t buf_ready;
uint32_t buf_count;
uint32_t n_samples;
} inference_t;
static volatile inference_t inference;
static bool debug_nn = false;
static bool debug_audio_raw = true;
static bool test_leds = false; // Set this to true to test the LEDs
static volatile int ix_buffer = 0;
static volatile bool is_buffer_ready = false;
static void adc_setup() {
adc_init();
adc_gpio_init(26);
adc_select_input(0);
}
static void print_raw_audio() {
for(int i = 0; i < EI_CLASSIFIER_RAW_SAMPLE_COUNT; ++i) {
ei_printf("%d\n", inference.buffer[i]);
}
}
void timer_ISR() {
if(ix_buffer < EI_CLASSIFIER_RAW_SAMPLE_COUNT) {
int16_t v = (int16_t)((adc_read() - BIAS_MIC)) * GAIN;
inference.buffer[ix_buffer++] = (int16_t)v;
}
else {
is_buffer_ready = true;
}
}
/**
* @brief Printf function uses vsnprintf and output using Arduino Serial
*
* @param[in] format Variable argument list
*/
void ei_printf(const char *format, ...) {
static char print_buf[1024] = { 0 };
va_list args;
va_start(args, format);
int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
va_end(args);
if (r > 0) {
Serial.write(print_buf);
}
}
/**
* @brief Init inferencing struct and setup/start PDM
*
* @param[in] n_samples The n samples
*
* @return { description_of_the_return_value }
*/
static bool microphone_inference_start(uint32_t n_samples) {
inference.buffer = (int16_t *)malloc(n_samples * sizeof(int16_t));
if(inference.buffer == NULL) {
return false;
}
inference.buf_count = 0;
inference.n_samples = n_samples;
inference.buf_ready = 0;
return true;
}
/**
* @brief Wait on new data
*
* @return True when finished
*/
static bool microphone_inference_record(void) {
unsigned int sampling_period_us = 1000000 / 16000;
ix_buffer = 0;
is_buffer_ready = false;
led_builtin = ON;
timer.attach_us(&timer_ISR, sampling_period_us);
while(!is_buffer_ready);
timer.detach();
led_builtin = OFF;
if(debug_audio_raw) {
print_raw_audio();
}
return true;
}
/**
* Get raw audio signal data
*/
static int microphone_audio_signal_get_data(size_t offset, size_t length, float *out_ptr) {
numpy::int16_to_float(&inference.buffer[offset], out_ptr, length);
return 0;
}
static void microphone_inference_end(void) {
free(inference.buffer);
}
#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_MICROPHONE
#error "Invalid model for current sensor."
#endif
/**
* @brief Arduino setup function
*/
void setup()
{
Serial.begin(115200);
while(!Serial);
adc_setup();
led_builtin = 0;
button.mode(PullUp);
if (microphone_inference_start(EI_CLASSIFIER_RAW_SAMPLE_COUNT) == false) {
ei_printf("ERR: Failed to setup audio sampling\r\n");
return;
}
}
/**
* @brief Arduino main function. Runs the inferencing loop.
*/
void loop()
{
if(button == PRESSED) {
delay(700);
bool m = microphone_inference_record();
if (!m) {
ei_printf("ERR: Failed to record audio...\n");
return;
}
signal_t signal;
signal.total_length = EI_CLASSIFIER_RAW_SAMPLE_COUNT;
signal.get_data = µphone_audio_signal_get_data;
ei_impulse_result_t result = { 0 };
EI_IMPULSE_ERROR r = run_classifier(&signal, &result, debug_nn);
if (r != EI_IMPULSE_OK) {
ei_printf("ERR: Failed to run classifier (%d)\n", r);
return;
}
// print the predictions
ei_printf("Predictions ");
ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
result.timing.dsp, result.timing.classification, result.timing.anomaly);
ei_printf(": \n");
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
ei_printf(" %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
}
// Get the index with higher probability
size_t ix_max = 0;
float pb_max = 0;
for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
if(result.classification[ix].value > pb_max) {
ix_max = ix;
pb_max = result.classification[ix].value;
}
}
if(pb_max > PROBABILITY_THR) {
switch (ix_max){
case 0:
//YOU CAN ADD YOUR FUNCTION HERE
break;
case 1:
//YOU CAN ADD YOUR FUNCTION HERE
break;
case 2:
//YOU CAN ADD YOUR FUNCTION HERE
break;
default:
ei_printf("Error! operator is not correct");
}
while(button == PRESSED);
delay(1000);
}
}
پس از کپی کردن، کمی منتظر بمانید تا کامپایلر c++ کد را بررسی اولیه کند. متوجه خواهید شد که خطاهایی در کد وجود دارد.
خطوطی از کد که در زیر آنها خط قرمز درج شده باشد، طبق نظر کامپایلر خطا دارند.
برای رفع آنها به صورت زیر عمل کنید:
- بر روی پنجره search کلیک کنید. سپس کلید F1 کیبرد را فشار داده و فایل C/C++: Edit Configurations (JSON) را باز کنید. در صفحه باز شده، کدهای نوشته شده را پاک کنید.
- اصلاح آدرس کتابخانه¬ها
کد زیر را در این فایل کپی کنید.
//
// !!! WARNING !!! AUTO-GENERATED FILE!
// PLEASE DO NOT MODIFY IT AND USE "platformio.ini":
// https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
//
{
"configurations": [
{
"name": "PlatformIO",
"includePath": [
"c:/Users/Caferobot9/Documents/PlatformIO/Projects/YesOrNo3/include",
"c:/Users/Caferobot9/Documents/PlatformIO/Projects/YesOrNo3/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated-avr-comp",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/variants/RASPBERRY_PI_PICO",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Camera/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Ethernet/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GC2145",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GPS/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GSM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM01B0",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM0360",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/KernelDebug/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MCUboot/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MLC/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MRI/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/NDP/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Nano33BLE_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Nicla_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/OV7670",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/PDM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Audio/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDCARD/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDRAM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Video/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_lvgl/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/RPC/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SE05X/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SFU/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SPI",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/STM32H747_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Scheduler/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SocketWrapper/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/ThreadDebug/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBAudio",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBHID/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBHOST/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBMIDI",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBMSD/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/WiFi/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Wire",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/doom/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/ea_malloc",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/mbed-memory-status",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/openamp_arduino/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/rpclib/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/syntiant_ilib/src",
""
],
"browse": {
"limitSymbolsToIncludedHeaders": true,
"path": [
"c:/Users/Caferobot9/Documents/PlatformIO/Projects/YesOrNo3/include",
"c:/Users/Caferobot9/Documents/PlatformIO/Projects/YesOrNo3/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/cores/arduino/api/deprecated-avr-comp",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/variants/RASPBERRY_PI_PICO",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Camera/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Ethernet/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GC2145",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GPS/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/GSM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM01B0",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Himax_HM0360",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/KernelDebug/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MCUboot/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MLC/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/MRI/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/NDP/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Nano33BLE_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Nicla_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/OV7670",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/PDM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Audio/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDCARD/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_SDRAM/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_Video/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Portenta_lvgl/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/RPC/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SE05X/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SFU/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SPI",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/STM32H747_System/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Scheduler/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/SocketWrapper/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/ThreadDebug/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBAudio",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBHID/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBHOST/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBMIDI",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/USBMSD/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/WiFi/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/Wire",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/doom/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/ea_malloc",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/mbed-memory-status",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/openamp_arduino/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/rpclib/src",
"C:/Users/Caferobot9/.platformio/packages/framework-arduino-mbed/libraries/syntiant_ilib/src",
""
]
},
"defines": [
"PLATFORMIO=60109",
"ARDUINO_RASPBERRY_PI_PICO",
"ARDUINO_ARCH_RP2040",
"ARM_MATH_CM0PLUS",
"COMPONENT_FLASHIAP=1",
"DEVICE_ANALOGIN=1",
"DEVICE_FLASH=1",
"DEVICE_I2C=1",
"DEVICE_I2CSLAVE=1",
"DEVICE_INTERRUPTIN=1",
"DEVICE_PORT_IN=1",
"DEVICE_PORT_OUT=1",
"DEVICE_PWMOUT=1",
"DEVICE_RESET_REASON=1",
"DEVICE_RTC=1",
"DEVICE_SERIAL=1",
"DEVICE_SERIAL_FC=1",
"DEVICE_SPI=1",
"DEVICE_USBDEVICE=1",
"DEVICE_USTICKER=1",
"DEVICE_WATCHDOG=1",
"MBEDTLS_ENTROPY_NV_SEED",
"MBED_BUILD_TIMESTAMP=1670863580.9430058",
"MBED_MPU_CUSTOM",
"PICO_NO_BINARY_INFO=1",
"PICO_ON_DEVICE=1",
"PICO_RP2040_USB_DEVICE_ENUMERATION_FIX=1",
"PICO_TIME_DEFAULT_ALARM_POOL_DISABLED",
"PICO_UART_ENABLE_CRLF_SUPPORT=0",
"TARGET_CORTEX",
"TARGET_CORTEX_M",
"TARGET_LIKE_CORTEX_M0",
"TARGET_LIKE_MBED",
"TARGET_M0P",
"TARGET_NAME=RASPBERRY_PI_PICO",
"TARGET_RASPBERRYPI",
"TARGET_RASPBERRY_PI_PICO",
"TARGET_RELEASE",
"TARGET_RP2040",
"TARGET_memmap_default",
"TOOLCHAIN_GCC",
"TOOLCHAIN_GCC_ARM",
"__CMSIS_RTOS",
"__CORTEX_M0PLUS",
"__MBED_CMSIS_RTOS_CM",
"__MBED__=1",
"MBED_NO_GLOBAL_USING_DIRECTIVE=1",
"CORE_MAJOR=",
"CORE_MINOR=",
"CORE_PATCH=",
"USE_ARDUINO_PINOUT",
"ARDUINO=10810",
"ARDUINO_ARCH_MBED",
""
],
"cStandard": "gnu11",
"cppStandard": "gnu++14",
"compilerPath": "C:/Users/Caferobot9/.platformio/packages/toolchain-gccarmnoneeabi/bin/arm-none-eabi-gcc.exe",
"compilerArgs": [
"-mcpu=cortex-m0plus",
"-mthumb",
"-iprefixC:UsersCaferobot9.platformiopackagesframework-arduino-mbedcoresarduino",
"@C:UsersCaferobot9.platformiopackagesframework-arduino-mbedvariantsRASPBERRY_PI_PICOincludes.txt",
""
]
}
],
"version": 4
}
• لغت Caferobot9 را انتخاب کرده و Ctrl+H را بر روی کیبرد فشار دهید. در ادامه، نام User خود را در قسمت YOUR USER NAME HERE وارد و دکمه Replace All را بزنید.
برای پیدا کردن نام کاربری دقیق خود در ویندوز، می¬توانید آن را از این مسیر پیدا کنید: <code> C:\Users</code>
پس از انجام اینکار چند لحظه منتظر بمانید تا کامپایلر عملیات مورد نیاز را انجام دهد. سپس بر روی دکمه Build در پایین صفحه کلیک کنید.
در صورتی که مراحل را به درستی طی کرده باشید، عبارات زیر را در خروجی مشاهده خواهید کرد.
حال برد رزبری پای خود را همزمان با نگه داشتن دکمه BOOT روی برد، به کامپیوتر متصل کنید.
در نهایت بر روی دکمه Upload بزنید تا برد رزبری پای پیکوی شما پروگرام شود.
اکنون وارد نرمافزار Arduino IDE شده و پس از انتخاب پورت صحیح، Serial monitor را باز کنید.
سپس کلید متصل به پایه GP10 رزبری پای پیکو را بزنید. مشاهده خواهید کرد که LED روی برد رزبری پای روشن شده و پس از مدت 1 ثانیه خاموش میشود. در این مدت، اگر لغات Yes یا No را بگویید، در درگاه سریال به ترتیب متون زیر را مشاهده خواهید کرد.
همچنین در صورتی که درگاه Serial Plotter را باز کنید و این کار را انجام دهید، سیگنال صوتی حس شده توسط میکروفون نمایش داده خواهد شد.
یک گام جلوتر
در این آموزش، ابتدا با مفهوم هوش مصنوعی و یادگیری ماشین آشنا شدید. سپس با استفاده از رابط گرافیکی جذاب Edge Impulse، مدلی برای تشخیص کلمات کلیدی ساختید و آن را بر روی رزبری پای اجرا کردید.
با استفاده از یادگیری ماشین، شما می¬توانید انواع کارها را بدون انجام محاسبات پیچیده انجام دهید. از جمله آنها میتوان به موارد زیر اشاره کرد:
1- سنسور فیوژن:
در بعضی پروژهها، برای به دست آوردن وضعیت فعلی، از چندین سنسور برای اندازهگیری پارامترهای مختلف استفاده میشود. مثلاً با استفاده از سنسورهای دما، رطوبت، نور محیط و فشار، میتوان وضعیت فعلی آب و هوا را به دست آورد. و در حالت پیشرفتهتر، حتی میتوان وضعیت آب و هوا را پیشبینی کرد.
اما در گذشته، برای این کار از کدهای حاوی محاسبات سنگین استفاده میشد و برای اجرای آن به سختافزار قدرتمند نیاز بود. اما حالا میتوانید با استفاده از ترکیب دادهها با استفاده از یادگیری ماشین، این کار را بسیار سادهتر انجام دهید.
2- تشخیص اشیاء در تصاویر:
بسیاری از کارهای روزمره انسانها بدون مشاهدۀ محیط اطراف امکانپذیر نیستند. تصاویر حاوی اطلاعات بسیاری از محیط است که مغز انسان، بر اساس آن به بدن دستورات لازم را ارسال میکند. بنابراین، دنیای پردازش تصویر کاربرد وسیعی دارد.
با استخراج نقاط شاخص از روی تصاویر حاوی اشیاء مورد نظر و ایجاد مدل از روی آنها، میتوانید سیستم تشخیص اشیاء را متناسب با نیاز خود ایجاد کنید. این تکنولوژی کاربردهای گستردهای دارد: تشخیص شماره پلاک خودرو، شمارش جمعیت، کنترل ترافیک، تبدیل عکس به متن و … .
3- تشخیص ژست و الگوی حرکت:
در حوزه پزشکی و به خصوص در فیزیوتراپی، رباتهایی برای کمک به انسانها جهت بهبود توانایی حرکتی آنها ابداع شدهاند. با استفاده از سنسورهای حرکتی مانند ژیروسکوپ، شتابسنج و مغناطیسسنج در کنار حسگرهای عصبی، میتوانید حرکات دقیق اندام مختلف انسان را رصد کنید. در صورتی که هریک از حرکات مختلف مانند نشستن، برخواستن، راه رفتن، دویدن و غیره را مدلسازی کنید، میتوانید این مدل را با استفاده از یک میکروکنترلر ارزان قیمت عملی کنید.
Comments (2)
سلام وقتتون بخیر
واقعا ممنونم بابت آموزش جالبی که به اشتراک گذاشتید
????
در مورد کار با رزپری پای ۵ هم این آموزش صدق میکنه یا میتوان پردازش بیشتری داشت ؟
با سلام
رزبری پای پیکو یک میکروکنترلر می باشد و رزبری پای های معمولی میکروپروسسور هستند. از این رو از این آموزش برای این موضوع نمیتوانید استفاده بکنید.
برای رزبری پای 5 میتوانید از کد هایی که داخل سیستم عامل های لینوکسی اجرا میشوند استفاده بنمایید.