السبت، 15 يناير 2022

معالجة الإشارات الرقمية الحقيقية

 معالجة الإشارات باستخدام السبورة السوداء الرقمية الحقيقية


الأشياء المستخدمة في هذا المشروع

مكونات الأجهزة

Xilinx's portfolio of FPGAs

منصة البرامج الموحدة Xilinx Vitis

قصة

مقدمة

سيستخدم هذا المشروع السبورة الرقمية الحقيقية لتنفيذ سلسلة معالجة إشارة بسيطة باستخدام XDAC و DMA لنقل الإشارات إلى الذاكرة.

إذا لم تكن مألوفًا ، فإن لوحة Real Digital Black هي عبارة عن جهاز Zynq 7007S أحادي النواة وهو مثالي لتعلم تطوير Zynq.



لبدء استخدام السبورة السوداء الرقمية الحقيقية ، فإن أول شيء يتعين علينا القيام به هو تنزيل الأصول من GitHub الرقمي الحقيقي.

من هنا

سيوفر لنا هذا البرامج النصية للتكوين لنظام المعالجة وتكوين تسجيل الوقت و DDR الخاص به.

في هذا المثال ، سنقوم بالاتصال بقنوات XADC المتاحة عبر قنوات XADC المساعدة على واجهة Pmod.



نحن نقوم بذلك لأن واجهة Vp / Vn المخصصة على Blackboard متصلة بمقياس الجهد. هذا بالطبع رائع للتدريس ولكن في هذا المشروع نريد التقاط إشارة حقيقية

إنشاء مشروع Vivado

على عكس العديد من المشاريع السابقة ، لن نبدأ المشروع مستهدفًا لوحة بل مكونًا. قم بإنشاء مشروع جديد باستخدام xc7007sclg400-1



بمجرد إنشاء المشروع ، فإن الخطوة التالية هي إنشاء مخطط كتلة IP Integrator. أضف نظام معالجة Zynq.


لتكوين Zynq PS كما في Blackboard ، نحتاج إلى تطبيق البرنامج النصي الذي قمنا بتنزيله مسبقًا. انقر نقرًا مزدوجًا فوق كتلة Zynq لإعادة التخصيص وتحديد تطبيق التكوين.


في مربع الحوار الذي يظهر ، حدد ملف tcl للإعدادات المسبقة لـ Blackboard وانقر فوق "موافق"


سيؤدي هذا إلى تكوين Zynq PS بشكل صحيح لتكوين Blackboard


بمجرد إغلاق نافذة إعادة التخصيص ، يمكننا إعادة تشغيل أتمتة الكتلة


عند الانتهاء من أتمتة الكتلة ، يجب تكوين نظام معالجة Zynq للاستخدام في تطبيقنا.


لبدء القدرة على تلقي إشارة ، نحتاج إلى إضافة XADC إلى مخطط كتلة IP Integrator



بمجرد إضافة XADC ، فإن المرحلة التالية هي تكوين XADC للاستخدام.


نظرًا لأننا نريد دفق البيانات من XADC واستخدام DMA ، نحتاج إلى تمكين واجهة AXIS Stream.


لقد عطلت أيضًا جميع  الإنذار


أخيرًا ، قمت بتمكين قنوات الإدخال المساعدة المتصلة بـ Pmod


بمجرد توصيل XADC ، قم بتشغيل أتمتة الاتصال لتوصيل XADC بـ Zynq PS باستخدام شبكة AXI Lite.


يجب أن يبدو مخطط الكتلة المكتمل كما يلي.


انقر بزر الماوس الأيمن على قناة Vaux0 وحدد make خارجي


الخطوة التالية هي توصيل خرج AXIS من XADC بإدخال S_AXI في Zynq PS Block.


سيمكن هذا الاتصال Vivado من إنشاء نظام DMA بين XADC ونظام المعالجة.


سيكون المخطط المكتمل كما هو موضح أدناه



قم بتشغيل أتمتة الاتصال وسيتم إضافة اتصال AXI Lite الموجود على DAM إلى شبكة AXI Lite.



سيكون المخطط المكتمل على النحو التالي.


ومع ذلك ، لا يحتوي خرج XADC AXI Stream على جميع الإشارات اللازمة لدعم DMA. لا يتم توفير إشارة TLast في خرج AXIS Stream

سيؤدي ذلك إلى منع DMA من العمل بشكل صحيح ، لذلك نحتاج إلى تحديد إخراج AXIS بين XADC ومدخل DMA


احذف الإشارة

أضف محول مجموعة فرعية AXI

قم بتوصيل هذا بين إخراج XADC AXI Stream وإدخال DMA

أعد تخصيص محول مجموعة AXI الفرعية لتوفير Tlast وإنشائه كل 256 عملية نقل.


بمجرد اكتمال ذلك ، نكون قادرين على التحقق من صحة تصميم الكتلة ، ويجب ألا تكون هناك أخطاء أو تحذيرات خطيرة.


تتمثل المرحلة التالية في إنشاء غلاف HDL للمشروع وإنشاء تدفق البتات. وهذا قد يستغرق بضع دقائق.


بمجرد اكتمال التصميم ، قم بتصدير XSA بما في ذلك تدفق البتات.


تطوير Vitis SW

من Vivado افتح Vitis وحدد مساحة عمل لتطوير البرامج.


قم بإنشاء مشروع تطبيق جديد وحدد XSA الذي تم تصديره للتو من Vivado لتحديد النظام الأساسي.



قم بإنشاء مشروع تطبيق جديد يستهدف معالج A9 الفردي


قم بإنشاء المجال باستخدام نظام تشغيل مستقل


حدد قالب تطبيق hello world.


بمجرد إنشاء المشروع ، نحتاج إلى تحديث برنامج الدفع لتسوية الفواتير (BSP) لاستخدام PS UART1 للاتصالات التسلسلية.


سنستخدم أيضًا نظام البرنامج ،


سيقوم تطبيق البرنامج بالتقاط عينات من XDAC وتخزينها على بطاقة SD. هذا يعني أنه يمكن استخدام بطاقة SD لتخزين البيانات وإتاحة البيانات للتحليل اللاحق إذا رغبت في ذلك.

تطبيق البرنامج في مجمله هو

#include <stdio.h>
#include "platform.h"
#include "xil_printf.h"
#include "stdlib.h"
#include "xsysmon.h"
#include "xaxidma.h"
#include "ff.h"

#define SYSMON_DEVICE_ID XPAR_SYSMON_0_DEVICE_ID
#define DMA_DEV_ID XPAR_AXIDMA_0_DEVICE_ID
#define DDR_BASE_ADDR XPAR_AXIDMA_0_BASEADDR

#define RX_BUFFER_BASE (0x00100000)
#define MAX_PKT_LEN 512 //bytes



XSysMon SysMonInst;

int main()
{
int Status;
u8 xfer_size;
u16 TempData;
int Temp;
int reset_done;
u16 *RxBufferPtr;
u32 value;
u32 addr;
XSysMon_Config *SYSConfigPtr ;
XSysMon* SysMonInstPtr = &SysMonInst;
XAxiDma_Config *CfgPtr;
XAxiDma AxiDma;


UINT NumBytesWritten;
int i,len,position,n;
static FIL fil; /* File object */
static FATFS fatfs; // Pointer to the filesystem object
static char FileName[50] = "XADC.CSV";
static char *SD_File;
char buffer[100] ;
UINT *ByteRead;
FRESULT Res;
TCHAR *Path = "0:/";
u32 BuffCnt;
Res = f_mount(&fatfs, Path, 0); //0 is the mounting option
SD_File = (char *)FileName;

init_platform();

print("Hello World\n\r");

SYSConfigPtr = XSysMon_LookupConfig(SYSMON_DEVICE_ID);
if (SYSConfigPtr == NULL) {
return XST_FAILURE;
}

CfgPtr = XAxiDma_LookupConfig(DMA_DEV_ID);
if (!CfgPtr) {
printf("No config found for %d\r\n", DMA_DEV_ID);
return XST_FAILURE;
}

Status = XAxiDma_CfgInitialize(&AxiDma, CfgPtr);
if (Status != XST_SUCCESS) {
printf("Initialization DMA failed %d\r\n", Status);
return XST_FAILURE;
}

XSysMon_CfgInitialize(SysMonInstPtr, SYSConfigPtr, SYSConfigPtr->BaseAddress);

XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SAFE);
XSysMon_SetAlarmEnables(SysMonInstPtr, 0x0);
XSysMon_SetSeqChEnables(SysMonInstPtr, XSM_SEQ_CH_AUX00);
XSysMon_SetAdcClkDivisor(SysMonInstPtr, 32);
XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_CONTINPASS);
//TempData = XSysMon_GetAdcData(SysMonInstPtr, XSM_CH_TEMP);
//Temp = XSysMon_RawToTemperature(TempData);

RxBufferPtr = (u16 *)RX_BUFFER_BASE;

addr = (u32)RX_BUFFER_BASE;

XAxiDma_Reset(&AxiDma);
reset_done = XAxiDma_ResetIsDone(&AxiDma);

while(reset_done != 1){

}

XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DEVICE_TO_DMA);
XAxiDma_IntrDisable(&AxiDma, XAXIDMA_IRQ_ALL_MASK,XAXIDMA_DMA_TO_DEVICE);



while(1){

Status = XAxiDma_SimpleTransfer(&AxiDma,(u32) RX_BUFFER_BASE,MAX_PKT_LEN, XAXIDMA_DEVICE_TO_DMA);
if (Status != XST_SUCCESS) {
printf("XFER failed %d\r\n", Status);
return XST_FAILURE;

}
while ((XAxiDma_Busy(&AxiDma,XAXIDMA_DEVICE_TO_DMA))){
/* Wait */
}
position = 0;
Xil_DCacheFlushRange((UINTPTR)RxBufferPtr, MAX_PKT_LEN);
Res = f_open(&fil, SD_File, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);
Res = f_lseek(&fil, 0);
for(i=0;i<MAX_PKT_LEN/2;i++){
n=sprintf(buffer, "%d,%04x\r\n",i,RxBufferPtr[i]);
Res = f_lseek(&fil, position); //find ext write position
Res = f_write(&fil, (const void*)buffer, MAX_PKT_LEN,&NumBytesWritten);
len = strlen(buffer);
position=position+len;
}
Res = f_close(&fil);
return 0;
//usleep(1000000);
}
cleanup_platform();
}


سيوفر لنا هذا ملف CSV على بطاقة SD للعينات من XADC.

يتم إحتوائه
هذا المشروع عبارة عن مقدمة لطيفة وبسيطة لـ Real Digital Blackboard ويوضح كيف يمكننا بسهولة البدء والتشغيل والعمل باستخدام أمثلة بسيطة لمعالجة الإشارات.

يمكننا بالطبع أن نضيف إلى ذلك باستخدام Vitis HLS إذا أردنا القيام بمعالجة الإشارات.



الجمعة، 3 ديسمبر 2021

تعرف على اردوينو أونو ميني اصدار محدود

 تحقق الإنجاز الكبير في المبيعات ولادة نسخة صغيرة من UNO ، بلمسات نهائية باللونين الأسود والذهبي اللافت للنظر - وحتى أنها تتميز بدبابيس مسبوكة


أعلنت شركة Arduino عن احتفالها بلوحة تطوير Arduino UNO الكلاسيكية من خلال إطلاق متغير مضغوط للغاية باللون الأسود الأنيق ، Arduino UNO Mini Limited Edition.

يوضح فريق Arduino تصميمه الجديد الجديد: "أولاً وقبل كل شيء ، إنها UNO مثل أي دولة أخرى". "إنها (تقريبًا) نفس المواصفات ، مع نفس المعالج ، ووحدات التثبيت ، والأداء الذي جعل UNO مشهورًا للغاية. ولكن هناك بعض التعديلات الرائعة التي نعتقد أنها ستحبها."


يظهر القرص الأول على الفور: لقد تحول نظام ألوان Arduino الأيقوني إلى اللون الأسود والذهبي ، بينما تقلصت مساحة اللوحة إلى نصف حجم سابقتها - وهذا يعني بالطبع أن Arduino UNO لا يتوافق جهاز Mini بشكل مباشر مع الدروع المصممة لـ UNO الأصلي ، على الرغم من محاكاة التباعد السيئ السمعة بين رؤوس الدبوس الخاصة به. بالإضافة إلى رؤوس الدبوس الأنثوية ، تشتمل اللوحة على رؤوس دبوس غير مأهولة ودبابيس مسبوكة على حوافها - مما يجعلها قابلة للتركيب على السطح كوحدة نمطية ، إذا رغب أي شخص في لحامها.


قرص آخر هو التحول إلى USB Type-C ، بدلاً من USB Type-B كامل الحجم. في مكان آخر ، المواصفات لم تتغير: إنها مدفوعة بشريحة Microchip ATmega328 ثمانية بت متحكم يعمل بسرعة 16 ميجا هرتز مع 2 كيلو بايت من ذاكرة الوصول العشوائي الثابتة (SRAM) ، 32 كيلو بايت من الفلاش ، و 1 كيلو بايت من EEPROM ، هناك 14 منفذ إدخال / إخراج رقمي ، ستة منها دعم تعديل عرض النبضة (PWM) وستة مدخلات تناظرية. تعمل اللوحة بمستوى منطقي 5 فولت ، ويمكن تشغيلها من جهد إدخال يتراوح بين 6 إلى 20 فولت - أو من موصل USB من النوع C الخاص بها.



لقد أصبح اللوح الأيقوني ، الذي تم إطلاقه لأول مرة في عام 2010 ، مرادفًا لـ Arduino نفسها ، "كتب فريق Arduino عن Uno الأصلي. إنه مثل الشركة والمجلس مرتبطان ارتباطًا وثيقًا في أذهان الصناع في جميع أنحاء العالم. بالنسبة للكثيرين ، Arduino هي UNO. لقد باعت UNO الآن أكثر من 10 ملايين وحدة. لذلك أردنا شيئًا رائعًا للاحتفال بهذا الإنجاز الجديد للوحة المصنّعة. وهذا الشيء هو UNO Mini Limited Edition. "


لم يؤكد Arduino مدى محدودية إصدار Arduino UNO Mini Limited Edition ، ولكنه يقبل الطلبات المسبقة للوحة بسعر 45 دولارًا في متجر Arduino أثناء نفاد الإمدادات. تشتمل جميع الطلبات على أرقام تسلسلية فردية وعبوات قابلة للتحصيل ، مع إدراج يضم توقيعات فريق Arduino.




الجمعة، 26 نوفمبر 2021

اجراء العمليات الحسابية بدون اللمس

 يمكّنك بهذا السوار من إجراء العمليات الحسابية الأساسية على الفور بمجرد الإشارة إلى ما تريده في الهواء




الأشياء المستخدمة في هذا المشروع

BeagleBoard.org PocketBeagle

مستشعر DFRobot 6 DOF - MPU6050

Adafruit PiOLED - 128x32 أحادية اللون OLED

Jupyter notebook

Amazon Web Services Cloud9

طابعة ثلاثية الأبعاد (عامة)

قصة

قصة

أنا أعمل في معمل للأبحاث وأخلع القفازات لمجرد إجراء بعض العمليات الحسابية الأساسية على هاتفي يبدو دائمًا أنه غير فعال للغاية ومزعج نوعًا ما ، لأنه بمجرد خلع القفازات ، فإنه يعد كابوسًا لإعادة ارتدائها بعد ذلك مباشرة. لذلك ، صممت هذه الآلة الحاسبة للإيماءات التي تتيح لي إجراء كل تلك الحسابات الأساسية دون الحاجة إلى خلع القفازات أو القلق بشأن تلويث هاتفي. لقد أردت أيضًا الغوص في tinyML لفترة من الوقت الآن ، لذلك شعرت أن هذا المشروع مناسب لتنفيذ أول مشروع TFLite على PocketBeagle.


تعليمات البناء

من وجهة نظر الأجهزة ، هذا المشروع بسيط جدًا ، كل ما تحتاجه هو PocketBeagle و MPU6050 IMU وشاشة OLED. نظرًا لأن PocketBeagle قد يكون نظامًا أساسيًا غير مألوف للبعض منكم ، فأنا أرفق الرسم التخطيطي الخاص به هنا. يتوافق الجزء العلوي من الرسم البياني مع منفذ micro-USB.







قم بتوصيل Power Rail بـ P1_14 و / أو P2_23
قم بتوصيل السكة الأرضية بـ P1_16 و / أو P2_21
قم بتوصيل SCL من P1_28 إلى BreadBoard
قم بتوصيل SDA من P1_26 إلى BreadBoard
تستخدم كل من شاشة OLED و MPU6050 I2C ، لذلك قم بتوصيل SCL و SDA كما هو موضح في العبوات وفي الرسم التخطيطي
قم بملاءمة MPU6050 و PocketBeagle والشاشة في الهيكل المطبوع ثلاثي الأبعاد
يجب أن يبدو المنتج النهائي مثل هذا (على الرغم من أن إدارة الكابلات الخاصة بك قد تكون أفضل من إدارة الكابلات الخاصة به)



الشفرة
هناك 4 مستندات رئيسية في المستودع مرتبطة في نهاية المشروع ، بالإضافة إلى ملفين إضافيين مطلوبين لتكوين دبابيس PocketBeagle وتشغيل البرنامج النصي.

اكتساب

بجمع بيانات التسريع والجيروسكوب الخام من MPU6050. لقد قمت بتعيين عتبة تسريع 2Gs لاكتشاف وقت بدء إيماءة ما ، وبعد ذلك أقوم بجمع 350 عينة ثابتة ، تقابل حوالي ثانيتين ، لجعلها متسقة وسهلة الإدخال في نموذج TensorFlow لاحقًا.

التصور والتحويل الموجي

تتكون البيانات الأولية من IMU من 350 عينة بحيث يمكنها التقاط الحركة بأكملها ، ومع ذلك ، لا نحتاج حقًا إلى العديد من العينات لالتقاط الجوهر العام للحركة بشكل كامل. وهنا يأتي دور التحويل المويجي. ما يفعله هو الحفاظ على شكل الإشارة ، مع تغيير امتدادها الزمني ، مما يقلل بشكل أساسي من عدد العينات ، مع فقدان ضئيل للإشارة المفيدة. (cA1، cD1) تكون نتائج التحويل المويجي متجهين: أحدهما بمعامِلات تقريبية ، والآخر بمعامِلات تفصيلية. يضاعف هذا عدد الميزات المتاحة للتصنيف ، عن طريق تقسيم الإشارة إلى إشارتين منفصلتين. يمكننا أيضًا إنشاء المزيد من الميزات باستخدام موجات مختلفة (cA2 ، cD2).




تصور البيانات: يولدipynb أيضًا تصورات للبيانات الكاملة التي تم جمعها لإيماءة سمحت لي بتحليل كيف تبدو الإيماءات المختلفة كإشارة وتكييف حركات يدي.



تدريب نموذج التعلم الآلي

تم العثور على جميع معالجة البيانات والتدريب النموذجي في TrainingModel.ipynb في الريبو. يحتوي إطار البيانات من تحويل wavelet على 24 عمودًا ، بما يتوافق مع 6 أعمدة بيانات أولية مضروبًا في نتيجتين لكل تحويل مويجي مرة تحولين. تم تسوية مجموعة البيانات أولاً ، مع تعيين القيم من 0 إلى 1 ، ثم تم تسوية القيم في متجه واحد لكل إيماءة ، لتسهيل التكامل مع TensorFlow.
normalwavedata = (fullwavedata - fullwavedata.min()) / (fullwavedata.max()-fullwavedata.min())
formatwavedata = pd.DataFrame()

for idx, gesture in enumerate(gestures):
for i in range(1, num_samples+1):

index = idx*num_samples*wavelen + (i-1) * wavelen
wavedataf = normalwavedata.iloc[index:index+wavelen].to_numpy().flatten().tolist()
formatwavedata[idx*num_samples+i-1] = wavedataf
del wavedataf

formatwavedata = formatwavedata.transpose().to_numpy()

بعد ذلك ، تم تقسيم مجموعة البيانات إلى 3 أجزاء: التدريب (70٪) ، الاختبار (15٪) ، التحقق (15٪). لقد استخدمت التقسيم العشوائي الطبقي بدلاً من الانقسام النموذجي test_train. نظرًا لأن مجموعة بيانات التدريب الخاصة بي كانت صغيرة جدًا ، فقد كان هناك الكثير من التباين استنادًا إلى الإيماءات التي كانت أكثر انتشارًا أثناء التدريب ، لذا فإن التبديل الطبقي يضمن نفس التوزيع للإيماءات في جميع الأجزاء.

from sklearn.model_selection import StratifiedShuffleSplit

testsplit = StratifiedShuffleSplit(n_splits = 1, test_size = 0.15)
valsplit = StratifiedShuffleSplit(n_splits = 1, test_size = 0.15/0.85)

for train_index, test_index in testsplit.split(formatwavedata, labels):
X_train, X_test = formatwavedata[train_index], formatwavedata[test_index]
y_train, y_test = labels[train_index], labels[test_index]

for train_index, val_index in valsplit.split(X_train, y_train):
X_train, X_val = X_train[train_index], X_train[val_index]
y_train, y_val = y_train[train_index], y_train[val_index]

بالنسبة للنموذج الفعلي ، استخدمت نموذج Keras المتسلسل من TensorFlow. بعد بعض تحسين المعلمات ، وصلت إلى بنية النموذج الحالية الخاصة بي ، والتي توفر حل وسط جيد بين الدقة والحجم (نظرًا لأننا نعمل على SoC ، نريد أن يكون النموذج صغيرًا نسبيًا للحصول على أداء جيد). تمت إضافة طبقات التسرب لكل طبقة عصبية مخفية من أجل منع فرط احتواء مجموعة بيانات التدريب

opt = tf.keras.optimizers.Adam(learning_rate=0.0001)
model = None
model = tf.keras.Sequential()
model.add(tf.keras.layers.Dense(1024, activation='relu', name='data')) # relu is used for performance
model.add(tf.keras.layers.Dropout(0.25)) #dropout layers help prevent overfitting
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Dense(1024, activation='relu'))
model.add(tf.keras.layers.Dropout(0.25))
model.add(tf.keras.layers.Dense(len(gestures), activation='softmax', name='result'))
model.compile(optimizer=opt,
loss=tf.keras.losses.SparseCategoricalCrossentropy(),
metrics=[tf.keras.metrics.SparseCategoricalAccuracy()])

على الرغم من أن بيانات الإيماءات الأولية بدت صاخبة ومعقدة تمامًا ، إلا أنه بعد معالجة البيانات وتدريب الشبكة العصبية ، لا يزال النموذج يحقق دقة تزيد عن 90٪ في بيانات الاختبار.



لتسخير قوة TinyML حقًا ، تحتاج إلى جعل النموذج متوافقًا مع PocketBeagle. لقد قمت بتحويل النموذج إلى نموذج TensorFlowLite.
converter = tf.lite.TFLiteConverter.from_keras_model(model)
tflite_model = converter.convert()


الاستدلال أثناء التنقل

يحتوي ملف الشفرة الأخير في المستودع ، Forecast.py على رمز مشابه لما فعلته أعلاه. يكتسب البيانات باستخدام نفس الإجراء مثل الاستحواذ ، ثم يقوم بإجراء تحويلات المويجات والتطبيع ، والفرق الوحيد هو أنني قمت بتحسين الكود لاستخدام NumPy في الغالب لـ PocketBeagle. لتشغيل الاستنتاج الفعلي ، تحتاج أولاً إلى تخصيص الموترات من النموذج

interpreter = tf.lite.Interpreter(model_path='test_model.tflite')

interpreter.allocate_tensors()

input_details = interpreter.get_input_details()
output_details = interpreter.get_output_details()
بعد ذلك ، يمكنك فقط تمرير البيانات إلى المترجم الفوري وسوف ينتج مصفوفة بثقة كل توقع.
input_data = np.float32(np.resize(gesturewave, (1, 1152)))
interpreter.set_tensor(input_details[0]['index'], input_data)

interpreter.invoke()

output_data = interpreter.get_tensor(output_details[0]['index'])

تعليمات العملية
تم إعداد الجهاز لتشغيل كود الاستدلال عند الإقلاع ، لذلك تحتاج فقط إلى توصيل PocketBeagle ، وبعد الانتظار لبضع دقائق ، يجب أن يكون جاهزًا للتنبؤ بالإيماءات. يكون تدفق الآلة الحاسبة كما يلي:

ارسم الرقم الأول في الهواء
حرك معصمك (يؤدي هذا إلى تقدم الآلة الحاسبة إلى محدد المشغل)
ارسم رقمًا من 1 إلى 5 لتحديد العامل الذي تريده
ارسم الرقم الثاني في الهواء
حرك معصمك مرة أخرى لحساب النتيجة

الخطوات التالية
على الرغم من أن النموذج يحقق أثناء التدريب دقة تزيد عن 90٪ في بيانات الاختبار ، عند استخدام الجهاز فعليًا وتنفيذ الإيماءات ، تكون الدقة أقل بالتأكيد ، ويرجع ذلك على الأرجح إلى الاختلاف المتأصل في كيفية تنفيذ الإيماءات المختلفة ومدى ضجيج الإشارة هو. إن جمع المزيد من بيانات التدريب من عدة أشخاص يقومون بالإيماءات سيسمح للشبكة بتعميم تعلمها بشكل أفضل على الإيماءات. يمكن أيضًا تنفيذ المزيد من عوامل التشغيل للآلة الحاسبة وطريقة أفضل لاختيارها في التكرار المستقبلي لهذا المشروع. حتى ذلك الحين ، أعتقد أن الإضافة الأكثر أهمية ستكون إنشاء غلاف أفضل يسمح بقراءات أكثر اتساقًا وتثبيت شاشة OLED.

نظرًا لأن الجهاز يُلبس كسوار معصم ، فإن إضافة شكل من أشكال جهاز القياس الحيوي (مثل PPG) ، سيسمح باستخدام جهاز مشابه لمراقبة الحالة الصحية أو النشاط البدني من خلال تدريب النموذج على معايير مختلفة.

الأجزاء والمرفقات المخصصة


















السبت، 20 نوفمبر 2021

مراقبة مستويات ثاني أكسيد الكربون والتحكم في تدفق الهواء باستخدام محطة Wio

 يراقب هذا الجهاز مستوى ثاني أكسيد الكربون في غرفة المعيشة أو غرفة النوم ويتحكم في مروحة تهوية لتحسين تدفق الهواء.



الأشياء المستخدمة في هذا المشروع
مكون الأجهزة

Wio Terminal: ATSAMD51 Core with Realtek
seeed grove relay
Seeed Grove - مستشعر ثاني أكسيد الكربون ودرجة الحرارة والرطوبة - SCD41
Generic مروحة تعمل بالطاقة USB
أسلاك العبور (عامة)

قصة
ملخص
ثاني أكسيد الكربون (CO2) هو رابع أكثر الغازات وفرة في الغلاف الجوي للأرض. يعتبر ثاني أكسيد الكربون نتيجة ثانوية لوظيفة الخلية الطبيعية عندما يتم استنشاقه خارج الجسم. كما يتم إنتاجه عند حرق الوقود الأحفوري أو تحلل الغطاء النباتي. يمكن أن تحتوي التربة السطحية في بعض الأحيان على تركيزات عالية من هذا الغاز ، من النباتات المتحللة أو التغيرات الكيميائية في الصخور الأساسية.

نقيس مستوى ثاني أكسيد الكربون بوحدات جزء في المليون. يخبرنا هذا الرقم عن عدد أجزاء ثاني أكسيد الكربون الموجودة في مليون جزء من الهواء. على سبيل المثال ، إذا كان ثاني أكسيد الكربون يبلغ 800 جزء في المليون ، فهذا يعني أنه في مليون جزء من الهواء يوجد 800 جسيم من ثاني أكسيد الكربون.

يمكن أن ينتج عن التعرض لثاني أكسيد الكربون مجموعة متنوعة من الآثار الصحية. قد يشمل ذلك الصداع ، والدوخة ، والأرق ، والشعور بالوخز أو الوخز بالإبر ، وصعوبة التنفس ، والتعرق ، والتعب ، وزيادة معدل ضربات القلب ، وارتفاع ضغط الدم ، والغيبوبة ، والاختناق ، والتشنجات.

مستويات ثاني أكسيد الكربون في الهواء والمشاكل الصحية المحتملة هي:

400 جزء في المليون: متوسط ​​مستوى الهواء الخارجي.
400-1000 جزء في المليون: المستوى النموذجي الموجود في الأماكن المشغولة مع تبادل هواء جيد.
1000-2000 جزء في المليون: المستوى المرتبط بشكاوى النعاس وسوء الهواء.
2000-5000 جزء في المليون: المستوى المرتبط بالصداع والنعاس والهواء الراكد ، الذي لا معنى له ، وخانق. قد يحدث أيضًا ضعف التركيز وفقدان الانتباه وزيادة معدل ضربات القلب والغثيان الطفيف.
5000 جزء في المليون: يشير هذا إلى ظروف جوية غير معتادة حيث يمكن أيضًا وجود مستويات عالية من الغازات الأخرى. يمكن أن يحدث سمية أو نقص الأكسجين. هذا هو حد التعرض المسموح به للتعرضات اليومية في مكان العمل.
40000 جزء في المليون: هذا المستوى ضار على الفور بسبب نقص الأكسجين.
في هذا المشروع ، قمت ببناء جهاز بسيط ومحمول باستخدام Seeed Wio Terminal الذي يعرض مستوى ثاني أكسيد الكربون الداخلي ودرجة الحرارة والنسبة المئوية للرطوبة النسبية على شاشة LCD الخاصة به. عندما يتم تجاوز مستوى ثاني أكسيد الكربون بقيمة حدية محددة ، يبدأ الجرس المدمج في إصدار صفير ويتم تشغيل مروحة تهوية تعمل بجهد 5 فولت عبر USB للحفاظ على استمرار الدورة وتقليل مستويات ثاني أكسيد الكربون. هذا الجهاز مفيد خاصة أثناء النوم عندما يمكن أن يرتفع مستوى ثاني أكسيد الكربون بسبب ضعف دوران الهواء ويمكن أن يؤثر على الصحة.

تم تصميم هذا المشروع وفقًا لمتطلباتي الخاصة في غرفة النوم حيث تأثر تدفق الهواء بشدة ولكن لم يكن لدي أي فكرة عنه وبعد العمل في مشروع آخر لجمع البيانات تم الكشف عن أن دوران الهواء في غرفة النوم لم يكن جيدًا وأن مستوى ثاني أكسيد الكربون كان في ازدياد خلال الليل.

إعداد الأجهزة
سنستخدم مستشعر Grove CO2 (SCD41) لقياس مستوى ثاني أكسيد الكربون. SCD41 من Sensirion عبارة عن مستشعر ثاني أكسيد الكربون عالي الجودة قائم على الصور الصوتية قادر على اكتشاف 0 إلى 40000 جزء في المليون بدقة عالية تزيد عن 400-5000 جزء في المليون ± (40 جزء في المليون + 5٪).





o التحكم في مروحة التهوية ، سنستخدم Grove Relay الذي يتم تشغيله بواسطة 5V من رؤوس Wio الطرفية ذات 40 سنًا. يتم استخدام فاصل USB الصغير B لتوصيل المروحة ومصدر الطاقة من Grove Relay. الاتصال الأرضي مأخوذ من رؤوس Wio Terminal. يمكن العثور على مخطط الأسلاك في قسم المخططات.




بيئة التطوير
تم تطوير التطبيق وتصنيفه ووميضه باستخدام Arduino IDE. يرجى تنزيل أحدث إصدار من Arduino IDE واتباع التعليمات للتثبيت من هنا: https://www.arduino.cc/en/software. لتثبيت مكتبة Wio Terminal board ، افتح Arduino IDE ، وانقر فوق ملف> تفضيلات ، وانسخ عنوان URL أدناه إلى عناوين URL الإضافية لـ Boards Manager:





انقر فوق أدوات> لوحة> مدير مجلس الإدارة والبحث في Wio Terminal وانقر فوق تثبيت.





لتثبيت مكتبة مستشعر Grove CO2 (SCD41) ، انقر فوق Tools> Manage Libraries ... لفتح Library Manager والبحث في Sensirion I2C Scd4x وانقر فوق تثبيت..



لا نحتاج إلى تثبيت أي مكتبة لـ Grove Relay التي تعمل بواسطة دبابيس GPIO الرقمية.

الشفرة
#include <SPI.h>
#include <Wire.h>
#include <TFT_eSPI.h>
#include <SensirionI2CScd4x.h>

#include "icon_thermometer.h"
#include "icon_humidity.h"
#include "icon_co2.h"

#define CO2_THRESHOLD 1200

SensirionI2CScd4x scd4x;
TFT_eSPI tft = TFT_eSPI();

unsigned int prev_time = 0;
bool alarm = false;

void printUint16Hex(uint16_t value)
{
Serial.print(value < 4096 ? "0" : "");
Serial.print(value < 256 ? "0" : "");
Serial.print(value < 16 ? "0" : "");
Serial.print(value, HEX);
}

void printSerialNumber(uint16_t serial0, uint16_t serial1, uint16_t serial2)
{
Serial.print("Serial: 0x");
printUint16Hex(serial0);
printUint16Hex(serial1);
printUint16Hex(serial2);
Serial.println();
}

void setup() {

Serial.begin(115200);

pinMode(WIO_5S_PRESS, INPUT_PULLUP);
pinMode(WIO_BUZZER, OUTPUT);
pinMode(D0, OUTPUT); // Relay
digitalWrite(D0, LOW);

tft.init();
tft.setRotation(3);
tft.setTextFont(4);
tft.fillScreen(TFT_BLACK);

Wire.begin();
uint16_t error;
char errorMessage[256];

scd4x.begin(Wire);

// stop potentially previously started measurement
error = scd4x.stopPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute stopPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
tft.print(errorMessage);
}

uint16_t serial0;
uint16_t serial1;
uint16_t serial2;

error = scd4x.getSerialNumber(serial0, serial1, serial2);
if (error) {
Serial.print("Error trying to execute getSerialNumber(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
tft.print(errorMessage);
} else {
printSerialNumber(serial0, serial1, serial2);
}

// Start Measurement
error = scd4x.startPeriodicMeasurement();
if (error) {
Serial.print("Error trying to execute startPeriodicMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
tft.print(errorMessage);
}

Serial.println("Waiting for first measurement... (5 sec)");
tft.setCursor(100, 80);
tft.print("Waiting...");
delay(5000);
tft.fillScreen(TFT_BLACK);
tft.drawXBitmap(20, 20, icon_co2_bits, icon_co2_width, icon_co2_height, TFT_YELLOW);
tft.drawXBitmap(20, 90, icon_therm_bits, icon_therm_width, icon_therm_height, TFT_RED);
tft.drawXBitmap(20, 160, icon_hum_bits, icon_hum_width, icon_hum_height, TFT_CYAN);

}

uint16_t prev_co2 = 0;
void loop()
{

unsigned long curr_time = millis();

if ((curr_time - prev_time) > 5000) {
prev_time = curr_time;

uint16_t error;
char errorMessage[256];

// Read Measurement
uint16_t co2;
float temperature;
float humidity;

error = scd4x.readMeasurement(co2, temperature, humidity);
if (error) {
Serial.print("Error trying to execute readMeasurement(): ");
errorToString(error, errorMessage, 256);
Serial.println(errorMessage);
tft.print(errorMessage);
} else if (co2 == 0) {
Serial.println("Invalid sample detected, skipping.");
} else {
if (co2 > CO2_THRESHOLD) {
alarm = true;
} else {
alarm = false;
}
Serial.print("Co2:");
Serial.print(co2);
Serial.print("\t");
Serial.print("Temperature:");
Serial.print(temperature);
Serial.print("\t");
Serial.print("Humidity:");
Serial.println(humidity);

// clear previous value by setting black font color
tft.setTextFont(6);
tft.setCursor(90, 30);
tft.setTextColor(TFT_BLACK, TFT_BLACK);
tft.print(prev_co2);
tft.setTextFont(4);
tft.print("ppm");

tft.setTextFont(6);
tft.setCursor(90, 30);
tft.setTextColor(TFT_YELLOW, TFT_BLACK);
tft.print(co2);
tft.setTextFont(4);
tft.print("ppm");
prev_co2 = co2;

char temp[5];
sprintf(temp, "%0.1f", temperature);
tft.setCursor(90, 100);
tft.setTextFont(6);
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.print(temp);
tft.setTextFont(4);
tft.print("`C");

char hum[5];
sprintf(hum, "%0.1f", humidity);
tft.setCursor(90, 170);
tft.setTextFont(6);
tft.setTextColor(TFT_CYAN, TFT_BLACK);
tft.print(hum);
tft.setTextFont(4);
tft.print("RH");
}
}


if (digitalRead(WIO_5S_PRESS) == LOW) {
alarm = false;
}

if (alarm) {
analogWrite(WIO_BUZZER, 128);
delay(1000);
analogWrite(WIO_BUZZER, 0);
delay(700);
digitalWrite(D0, HIGH); // Relay Switch on
} else {
digitalWrite(D0, LOW); // Relay Switch off
}

delay(300);
}

يمكن تنزيل حزمة الأكواد من مستودع Github: https://github.com/metanav/WioTerminal_CO2_Monitoring/archive/refs/heads/main.zip. بعد التنزيل ، قم بفك ضغط الحزمة وافتح Wio_Terminal_CO2_Monitor / Wio_Terminal_CO2_Monitor.ino رسم تخطيطي في Arduino IDE وانقر على Sketch> تحميل لتجميع / تحميل البرنامج الثابت.

عرض
يتم تحديث قراءات المستشعر إلى شاشة Wio Terminal LCD بفاصل 5 دقائق. تم تنزيل صور الرموز المجانية لثاني أكسيد الكربون ودرجة الحرارة والرطوبة من Flaticon وتم تحويلها إلى X BitMap (XBM) ، وهو تنسيق صورة ثنائية نص عادي ، باستخدام برنامج Convertio



استنتاج
يحتوي هذا الجهاز على العديد من الاحتمالات الأخرى مثل أنه يمكننا جمع بيانات المستشعر البيئي المتسلسل الزمني وحفظها باستخدام وحدة بطاقة SD المدمجة والتي يمكن استخدامها لمزيد من التحليل لاتجاهات مستويات ثاني أكسيد الكربون أو العثور على الحالات الشاذة. يمكن توصيله بالخدمات السحابية باستخدام وحدة Wifi المدمجة.

أود أن أشكر SeeedStudio لتصنيع مثل هذه الخيارات الرائعة من أجهزة الاستشعار البيئية مثل وحدات Grove التي يسهل دمجها في معظم لوحات التطوير باستخدام موصل Grove أو Qwiic / Stemma باستخدام محول. أيضًا ، Wio Terminal هي لوحة تطوير صديقة للمبتدئين للنماذج الأولية السريعة