logo-site-sefid
Search
Close this search box.
سنسور الکترومکانیکی mems

سیستمهای الکترومکانیکی mems

در این مقاله آموزشی نحوه کار سیستمهای الکترومکانیکی mems ، ژیروسکوپ و مغناطیس سنج و نحوه استفاده از آنها را با بورد آردوینو یاد خواهیم گرفت. همچنین با پردازش IDE با استفاده از سنسورها برخی کاربردهای عملی را ایجاد خواهیم کرد. می توانید فیلم زیر را تماشا کنید یا آموزش کتبی زیر را بخوانید.

توضیح مختصر

سیستمهای الکترومکانیکی mems دستگاه های بسیار کوچکی هستند که از اجزای میکرو متغیر از 0.001 میلی متر تا 0.1 میلی متر تشکیل شده اند. این اجزا از سیلیکون ، پلیمرها ، فلزات و یا سرامیک ساخته شده اند و معمولاً برای تکمیل سیستم با CPU (میکروکنترلر) ترکیب می شوند. اکنون به طور خلاصه نحوه عملکرد هر یک از این سنسورهای Micro-Electro-Mechanical-Systems (MEMS) را توضیح خواهیم داد. در بخش های بعدی آموزش رباتیک ما از این سنسورها به کرات استفاده خواهیم نمود.

شتاب سنج MEMS

شتاب را با اندازه گیری تغییر در ظرفیت اندازه گیری می کند. ساختار آن تقریباً به این شکل است. این شتاب سنج یک توده متصل به یک فنر است که برای حرکت در امتداد یک جهت و صفحات بیرونی ثابت محدود شده است. بنابراین هنگامی که یک شتاب در جهت خاص اعمال می شود ، جرم حرکت می کند و ظرفیت بین صفحات و جرم تغییر می کند. این تغییر ظرفیت اندازه گیری و سپس پردازش می شود و با یک مقدار شتاب خاص مطابقت دارد.

شتاب سنج mems
شتاب سنج mems

ژیروسکوپ MEMS

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

ژیروسکپ mems
ژیروسکپ mems

ساختار کوچک ژیروسکوپ چیزی شبیه به این است. جرمی که دائماً در حال حرکت است ، یا در حال نوسان است ، و هنگامی که نرخ زاویه خارجی اعمال می شود ، یک قسمت انعطاف پذیر از جرم حرکت می کند و باعث تغییر مکان عمود می شود.

ساختار ژيروسکپ mems
ساختار ژيروسکپ mems

مغناطیس سنج MEMS

این میدان مغناطیسی زمین را با استفاده از Hall Effect یا Magneto Resistive Effect اندازه گیری می کند. در واقع تقریباً 90٪ سنسورهای موجود در بازار از اثر هال استفاده می کنند و نحوه کارکرد آن در اینجا است.

Hall Effect 01

اگر صفحه ای رسانا مانند آنچه در عکس نشان داده شده است داشته باشیم و جریان را تنظیم کنیم تا از آن عبور کند ، الکترون ها مستقیماً از یک طرف دیگر صفحه می روند. حال اگر مقداری میدان مغناطیسی به صفحه نزدیک کنیم ، جریان مستقیم را مختل می کنیم و الکترون ها به یک طرف صفحه و قطب های مثبت به سمت دیگر صفحه منحرف می شوند. این بدان معناست که اگر یک ولت متر را بین این دو طرف قرار دهیم ، مقداری ولتاژ بدست خواهیم آورد که به قدرت میدان مغناطیسی و جهت آن بستگی دارد.

عملکرد سنسور مغناطیسی
عملکرد سنسور مغناطیسی

10٪ دیگر سنسورهای موجود در بازار از اثر مقاومت مگنتو استفاده می کنند. این سنسورها از موادی استفاده می کنند که به میدان مغناطیسی حساس هستند و معمولاً از آهن (Fe) و نیکل (Ne) تشکیل شده اند. بنابراین وقتی این مواد در معرض میدان مغناطیسی قرار بگیرند مقاومت آنها را تغییر می دهند.

چنانچه علاقمند به کسب درآمدی سرشار از علاقمندی های خود در حوزه فناوری و رباتیک میباشید میتوانید با کسب نمایندگی رباتیک از صنایع آموزشی چالیک در این حوزه مشغول فعالیت شده و آینده شغلی خود را تضمین نمایید.

آردوینو و سنسورهای  MEMs

خوب اکنون اجازه دهید این سنسورها را به برد Arduino متصل کرده و از آنها استفاده کنیم. به عنوان مثال من از برد  GY-80 استفاده می کنم که دارای سنسورهای زیر است: ADXL345 3 Axis Accelerometer، L3G4200D 3 Axis Gyroscope، MC5883L 3 Axis Magnetometer و همچنین یک فشارسنج و دماسنج که ما در این مقاله استفاده نمی کنیم.

قطعات مورد نیاز را از لینک زیر تهیه کنید

شتاب دهنده 3 محوره ADXL345

2 در 1: ژیروسکوپ و شتاب سنج MPU6050 6-Axis

3 در 1: ژیروسکوپ شتاب دهنده میدان مغناطیسی 9 محور GY-80

3 در 1: ماژول GY-86 10DOF MS5611 HMC5883L MPU6050

آردوینو و سنسورهای mems
آردوینو و سنسورهای mems

این مدار از پروتکل ارتباطی I2C استفاده می کند یعنی ما فقط با دو سیم می توانیم از همه سنسورها استفاده کنیم. بنابراین برای برقراری ارتباط بین آردوینو و سنسورها باید آدرس دستگاه منحصر به فرد آنها و آدرس رجیستر داخلی آنها را برای خارج کردن داده ها بدانیم. این آدرس ها را می توان از دیتا شیت سنسورها یافت:

  • ADXL345  Accelerometer         Datasheet
  • L3G4200D  Gyroscope              Datasheet
  • MC5883L  Magnetometer        Datasheet

ارتباط I2C چیست

گذرگاه ارتباطی I2C بسیار محبوب است و در بسیاری از دستگاه های الکترونیکی بسیار مورد استفاده قرار می گیرد زیرا به راحتی در بسیاری از طراحی های الکترونیکی که نیاز به برقراری ارتباط بین یک اصلی و چندین دستگاه فرعی یا حتی چندین دستگاه اصلی دارد ، به راحتی قابل اجرا است. پیاده سازی آسان با این واقعیت همراه است که برای برقراری ارتباط بین تقریباً 128 (112) دستگاه هنگام استفاده از آدرس دهی 7 بیتی و تقریباً 1024 (1008) دستگاه هنگام استفاده از آدرس دهی 10 بیتی ، فقط دو سیم مورد نیاز است.

چگونه امکان برقراری ارتباط بین بسیاری از دستگاه ها فقط با دو سیم وجود دارد؟ خوب هر دستگاه دارای یک ID از پیش تعیین شده یا یک آدرس دستگاه منحصر به فرد است بنابراین دستگاه اصلی می تواند انتخاب کند که با کدام دستگاه ها ارتباط برقرار شود.

 

به دو سیم Serial Clock (یا SCL) و Serial Data (یا SDA) گفته می شود. خط SCL سیگنال ساعتی است که انتقال داده را بین دستگاه های موجود در گذرگاه I2C هماهنگ کرده و توسط دستگاه اصلی تولید می شود. خط دیگر خط SDA است که داده ها را حمل می کند.

این دو خط “تخلیه آزاد” هستند و این بدان معناست که مقاومتهای کششی باید به آنها متصل شوند تا خطوط بالا باشند زیرا دستگاههای ورودی I2C کم فعال هستند. مقادیر معمولاً مورد استفاده برای مقاومت ها از 2K برای سرعت بالاتر در حدود 400 kbps تا 10K برای سرعت پایین در حدود 100 kbps است.

نوشتن کد سنسورهای mems در آردوینو

حال بیایید کدهای دریافت داده از حسگرها را مشاهده کنیم. ما با شتاب سنج شروع خواهیم کرد و قبل از هر کد توضیحاتی ارائه می شود ، همچنین توضیحات اضافی در توضیحات کد وجود دارد.

کد شتاب سنج آردوینو

ابتدا باید کتابخانه Wire Library را وارد کرده و آدرس های ریجستری سنسور را تعریف کنیم. در بخش راه اندازی ، ما باید Wire Library را شروع کرده و ارتباط سریال را شروع کنیم زیرا ما از نمایشگر سریال برای نمایش نتایج استفاده خواهیم کرد. همچنین در اینجا ما باید سنسور را فعال کنیم یا اندازه گیری را با ارسال بایت مناسب به Power_CTL فعال کنیم و نحوه انجام این کار را در اینجا نشان می دهیم. با استفاده از تابع Wire.beginTransmission () ما انتخاب می کنیم که با کدام سنسور صحبت کنیم ، شتاب سنج 3 محوره. سپس با استفاده از تابع Wire.write () می گوییم با کدام رجیستر داخلی صحبت خواهیم کرد. پس از این بایت مناسب را برای فعال کردن اندازه گیری ارسال خواهیم کرد. با استفاده از تابع Wire.endTransmission () انتقال را پایان می دهیم و این داده ها را به رجیسترها منتقل می کند.

در بخش حلقه باید داده های هر محور را بخوانیم. ما با X – Axis شروع خواهیم کرد. بنابراین ابتدا ما انتخاب خواهیم کرد که با کدام ریجستری ها ارتباط برقرار کنیم ، در این حالت دو ریجستری داخلی X – Axis انتخاب شده. سپس با استفاده از تابع Wire.requestFrom () داده های ارسالی یا دو بایت را از دو ارسال کننده درخواست می کنیم. تابع Wire.available () تعداد بایت های موجود برای بازیابی را برمی گرداند و اگر این تعداد با بایت های درخواست شده ما مطابقت داشته باشد ، در مورد ما 2 بایت ، با استفاده از تابع Wire.read () ما بایت ها را از دو رجیستر می خوانیم در اینجا محور X

داده های خروجی از ریجستری ( محور X ) مکمل هستند ، با X0 به عنوان کم اهمیت ترین بایت و X1 به عنوان مهمترین بایت ، بنابراین ما باید این بایت ها را به مقادیر شناور از -1 به 1 تبدیل کنیم بسته به جهت نسبت X – Axis به شتاب زمین یا گرانش. ما این روش را برای دو محور دیگر تکرار می کنیم و در پایان این مقادیر را روی مانیتور سریال چاپ می کنیم.

#include <Wire.h>
//--- Accelerometer Register Addresses
#define Power_Register 0x2D
#define X_Axis_Register_DATAX0 0x32 // Hexadecima address for the DATAX0 internal register.
#define X_Axis_Register_DATAX1 0x33 // Hexadecima address for the DATAX1 internal register.
#define Y_Axis_Register_DATAY0 0x34 
#define Y_Axis_Register_DATAY1 0x35
#define Z_Axis_Register_DATAZ0 0x36
#define Z_Axis_Register_DATAZ1 0x37
int ADXAddress = 0x53; //Device address in which is also included the 8th bit for selecting the mode, read in this case.
int X0,X1,X_out;
int Y0,Y1,Y_out;
int Z1,Z0,Z_out;
float Xa,Ya,Za;
void setup() {
Wire.begin(); // Initiate the Wire library 
Serial.begin(9600); 
delay(100);
Wire.beginTransmission(ADXAddress);
Wire.write(Power_Register); // Power_CTL Register
// Enable measurement
Wire.write(8); // Bit D3 High for measuring enable (0000 1000)
Wire.endTransmission();
}
void loop() {
// X-axis
Wire.beginTransmission(ADXAddress); // Begin transmission to the Sensor 
//Ask the particular registers for data
Wire.write(X_Axis_Register_DATAX0);
Wire.write(X_Axis_Register_DATAX1); 
Wire.endTransmission(); // Ends the transmission and transmits the data from the two registers
Wire.requestFrom(ADXAddress,2); // Request the transmitted two bytes from the two registers
if(Wire.available()<=2) { // 
X0 = Wire.read(); // Reads the data from the register
X1 = Wire.read();
/* Converting the raw data of the X-Axis into X-Axis Acceleration
- The output data is Two's complement 
- X0 as the least significant byte
- X1 as the most significant byte */ 
X1=X1<<8;
X_out =X0+X1;
Xa=X_out/256.0; // Xa = output value from -1 to +1, Gravity acceleration acting on the X-Axis
}
// Y-Axis
Wire.beginTransmission(ADXAddress); 
Wire.write(Y_Axis_Register_DATAY0);
Wire.write(Y_Axis_Register_DATAY1); 
Wire.endTransmission(); 
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) { 
Y0 = Wire.read();
Y1 = Wire.read();
Y1=Y1<<8;
Y_out =Y0+Y1;
Ya=Y_out/256.0;
}
// Z-Axis
Wire.beginTransmission(ADXAddress); 
Wire.write(Z_Axis_Register_DATAZ0);
Wire.write(Z_Axis_Register_DATAZ1); 
Wire.endTransmission(); 
Wire.requestFrom(ADXAddress,2);
if(Wire.available()<=2) { 
Z0 = Wire.read();
Z1 = Wire.read();
Z1=Z1<<8;
Z_out =Z0+Z1;
Za=Z_out/256.0;
}
// Prints the data on the Serial Monitor
Serial.print("Xa= ");
Serial.print(Xa);
Serial.print(" Ya= ");
Serial.print(Ya);
Serial.print(" Za= ");
Serial.println(Za);
}

 

کد ژیروسکوپ برای آردوینو

برای بدست آوردن داده ها از ژیروسکوپ ، کدی مشابه کد قبلی خواهیم داشت. بنابراین ابتدا باید آدرس های ثبت و برخی متغیرها را برای داده ها تعریف کنیم. در بخش تنظیمات باید سنسور را با استفاده از CTRL_REG1 در حالت عادی قرار دهیم و همچنین حساسیت سنسور را انتخاب کنیم. برای این مثال حالت حساسیت 2000dps را انتخاب می کنم.

در قسمت حلقه مشابه شتاب سنج ، ما داده های مربوط به محور X ، Y و Z را می خوانیم. سپس داده های خام باید به مقادیر زاویه تبدیل شوند. از صفحه داده سنسور می بینیم که برای حالت حساسیت 2000dps مربوط به یک واحد 70 mdps / رقم است. این بدان معناست که برای بدست آوردن نرخ زاویه ای بر حسب درجه در ثانیه ، باید داده های خروجی خام را در 0.07 ضرب کنیم. اگر نرخ زاویه ای را در زمان ضرب کنیم مقدار زاویه را به ما می دهد. بنابراین ما باید فاصله زمانی هر بخش حلقه را محاسبه کنیم و می توانیم این کار را با استفاده از تابع millis () در بالا و پایین قسمت حلقه انجام دهیم ، و مقدار آن را در این متغیر “dt” ذخیره خواهیم کرد. بنابراین برای هر حلقه اجرا شده ما زاویه را محاسبه کرده و به مقدار نهایی زاویه اضافه می کنیم. همین کار را برای دو محور دیگر انجام خواهیم داد و در پایان نتایج را در مانیتور سریال چاپ خواهیم کرد.

#include <Wire.h>
//--- Gyro Register Addresses
#define Gyro_gX0 0x28 
#define Gyro_gX1 0x29
#define Gyro_gY0 0x2A
#define Gyro_gY1 0x2B
#define Gyro_gZ0 0x2C 
#define Gyro_gZ1 0x2D
int Gyro = 0x69; //Device address in which is also included the 8th bit for selecting the mode, read in this case.
int gX0, gX1, gX_out;
int gY0, gY1, gY_out;
int gZ0, gZ1, gZ_out;
float Xg,Yg,Zg;
float angleX,angleY,angleZ,angleXc,angleYc,angleZc;
unsigned long start, finished, elapsed;
float dt=0.015;
void setup()
{
Wire.begin(); 
Serial.begin(9600); 
delay(100);
Wire.beginTransmission(Gyro);
Wire.write(0x20); // CTRL_REG1 - Power Mode
Wire.write(15); // Normal mode: 15d - 00001111b 
Wire.endTransmission();
Wire.beginTransmission(Gyro);
Wire.write(0x23); // CTRL_REG4 - Sensitivity, Scale Selection
Wire.write(48); // 2000dps: 48d - 00110000b
Wire.endTransmission();
}
void loop()
{
start=millis();
//---- X-Axis
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gX0);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gX0 = Wire.read();
}
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gX1);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gX1 = Wire.read();
}
//---- Y-Axis
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gY0);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gY0 = Wire.read();
}
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gY1);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gY1 = Wire.read();
}
//---- Z-Axis
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gZ0);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gZ0 = Wire.read();
}
Wire.beginTransmission(Gyro); // transmit to device
Wire.write(Gyro_gZ1);
Wire.endTransmission();
Wire.requestFrom(Gyro,1); 
if(Wire.available()<=1) 
{
gZ1 = Wire.read();
}
//---------- X - Axis
// Raw Data
gX1=gX1<<8;
gX_out =gX0+gX1;
// From the datasheet: 70 mdps/digit
Xg=gX_out*0.07; // Angular rate
// Angular_rate * dt = angle
angleXc = Xg*dt;
angleX = angleX + angleXc;
//---------- Y - Axis
gY1=gY1<<8;
gY_out =gY0+gY1;
Yg=gY_out*0.07;
angleYc = Yg*dt;
angleY = angleY + angleYc;
//---------- Z - Axis
gZ1=gZ1<<8;
gZ_out =gZ0+gZ1;
Zg=gZ_out*0.07;
angleZc = Zg*dt;
angleZ = angleZ + angleZc;
// Prints the data on the Serial Monitor
Serial.print("angleX= ");
Serial.print(angleX);
Serial.print(" angleY= ");
Serial.print(angleY);
Serial.print(" angleZ= ");
Serial.println(angleZ);
delay(10);
// Calculating dt
finished=millis();
elapsed=finished-start;
dt=elapsed/1000.0;
start = elapsed = 0;
}

 

کد مغناطیس سنج آردوینو

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

سپس باید داده های خام را به مقدار میدان مغناطیسی یا واحدهای گاوس تبدیل کنیم. از صفحه داده سنسور می بینیم که حالت حساسیت پیش فرض 0.92mG / رقم است. این بدان معناست که برای بدست آوردن میدان مغناطیسی زمین در واحدهای گاوس ، باید داده های خام را در 0.00092 ضرب کنیم. در پایان مقادیر را روی مانیتور سریال چاپ خواهیم کرد.

#include <Wire.h> //I2C Arduino Library
#define Magnetometer_mX0 0x03 
#define Magnetometer_mX1 0x04 
#define Magnetometer_mZ0 0x05 
#define Magnetometer_mZ1 0x06 
#define Magnetometer_mY0 0x07 
#define Magnetometer_mY1 0x08 
int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;
float Xm,Ym,Zm;
#define Magnetometer 0x1E //I2C 7bit address of HMC5883
void setup(){
//Initialize Serial and I2C communications
Serial.begin(9600);
Wire.begin();
delay(100);
Wire.beginTransmission(Magnetometer); 
Wire.write(0x02); // Select mode register
Wire.write(0x00); // Continuous measurement mode
Wire.endTransmission();
}
void loop(){
//---- X-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mX0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mX1 = Wire.read();
}
//---- Y-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mY0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mY1 = Wire.read();
}
//---- Z-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mZ0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1); 
if(Wire.available()<=1) 
{
mZ1 = Wire.read();
}
//---- X-Axis
mX1=mX1<<8;
mX_out =mX0+mX1; // Raw data
// From the datasheet: 0.92 mG/digit
Xm = mX_out*0.00092; // Gauss unit
//* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.
//---- Y-Axis
mY1=mY1<<8;
mY_out =mY0+mY1;
Ym = mY_out*0.00092;
//---- Z-Axis
mZ1=mZ1<<8;
mZ_out =mZ0+mZ1;
Zm = mZ_out*0.00092;
//Print out values of each axis
Serial.print("x: ");
Serial.print(Xm);
Serial.print(" y: ");
Serial.print(Ym);
Serial.print(" z: ");
Serial.println(Zm);
delay(50);
}

 

رضا قنبری
متخصص آموزش رباتیک

رضا قنبری هستم متخصص آموزش رباتیک با بیش از 10 سال سابقه فعالیت در ایران

این مطلب را به اشتراک بگذارید

ماژول کاهنده

ماژول كاهنده قبل از خواندن مقاله ماژول كاهنده بهتر است در نظر داشته باشید مقالاتی که با عنوان ماژول در سایت قرار گرفته اند از

ماژول تشخیص دود و گاز

ماژول تشخیص دود و گاز قبل از خواندن این مقاله بهتر است در نظر داشته باشید مقالاتی که با عنوان ماژول در سایت قرار گرفته

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *