تا به امروز آموزش های متفاوتی با استفاده ماژول MPU6050 ژایرو منتشر شده، در این آموزش قصد داریم با استفاده از این ماژول پرکاربرد و همچنین نمایشگر Oled، یک مدل سه بعدی را کنترل کنیم با استفاده از تغییر مقادیر x, y که از ماژول ژایرو بدست میآید، وضعیت مدل تغییر میکند. به عبارتی جابجایی سه بعدی سنسور ژایرو به صورت تصویری روی نمایشگر OLED نمایان میشود. در این آموزش از برد آردوینو نانو به عنوان برد راهانداز استفاده خواهیم کرد. در ادامه این آموزش با مرجع تخصصی آردوینو به زبان فارسی، دیجی اسپارک همراه باشید.
ماژول MPU6050 ژایرو
حالا زمان این رسیده با سخت افزار اصلی این آموزش، یعنی MPU6050 بیشتر آشنا بشیم. Mpu6050 دارای یک شتاب سنج سه محوره و یک ژیروسکوپ سه محوره MEMS میباشد. دقت ماژول مبدل آنالوگ به دیجیتال ۱۲ بیت بوده و میتواند مقادیر X ، Y ، Z را در یک زمان اندازه گیری کند. بافر این ماژول از نوع FIFO با ظرفیت ۱۰۲۴ بایت میباشد. این ماژول به عنوان Slave به آردوینو توسط پایههای SCL و SDA متصل میشود. با استفاده از پردازشگر دیجیتال، ۴ خروجی برای دستیابی به دقت قابل توجه، در حرکتهای کند و سریع در سنسور فراهم کرده است. با این روش کاربر میتواند بازه اندازه گیری را متناسب با شتاب یا سرعت تغییر دهد. به همین منظور در قسمت ژیروسکوپ سنسور چهار بازه ۲۵۰±، ۵۰۰±، ۱۰۰۰± و ۲۰۰۰± درجه بر ثانیه و در قسمت شتاب سنج سنسور چهار بازه ۲g، ±۴g، ±۸g، ±۱۶g± برای کاربر قابل انتخاب خواهد بود. توجه داشته باشید که ولتاژ کاری این ماژول ۳ الی ۵ ولت میباشد.
برد آردوینو Arduino
مجموعه برد های آردوینو از جمله برد های توسعه پرطرفدار بین مهندسین امبدد هستند که در مدل های مختلفی از جمله Micro , proMini , Nano , Uno و همچنین Mega قابل تهیه هستند، هسته مرکزی این برد های محبوب از سری AtMega328 می باشد. آردوینو پلتفرم سختافزاری و نرمافزاری متنباز است. همان طور که قبل تر اشاره کردیم، پلتفرم آردوینو شامل یک میکروکنترلر تکبردی متنباز است که قسمت سختافزار آردوینو را تشکیل میدهد. علاوه بر این، پلتفرم آردوینو یک نرمافزار آردوینو IDE که به منظور برنامهنویسی برای بردهای آردوینو طراحی شدهاست و یک بوت لودر نرمافزاری که بر روی میکروکنترلر بارگذاری میشود را در بر میگیرد.
ماژول نمایشگر Oled 1306
معمولا در پروژه های اینترنت اشیا و دیگر پروژه های امبدد از برای نمایش متن و مقادیر مختلف از نمایشگر های Oled استفاده می شود، این ماژول ها بدر انواع مختلق بسته به نوع ذرایور اندازه یافت می شوند که یکی از پرطرفدار ترین آن ها SSD1306 می باشد، این نوع از Oled ها معمولا در اندازه های ۰٫۹۶ و ۱٫۳ اینچ ساخته می شوند همچنین پروتکل ارتباطی Oled ها I2C می باشد.
توضیح تکمیلی
در این آموزش اقدام به کنترل یک مکعب خواهیم کرد، در کد پروژه مکعب را طراحی می کنیم، به این صورت که زوایای مختلف را در کد تعریف و در شرط های برنامه به ازای تغییر مقادیر x, y تغییرات ظاهری مکعب را نیز مشخص خواهیم کرد. و در نهایت شکل معکب را در نمایشگر Oled چاپ می کنیم و تغییر زاویه ماژول MPU شاهد تغییر زوایای مکعب خواهیم بود.
وسایل موردنیاز
برد آروینو نانو
نصب کتابخانه مورد نیاز
ابتدا در نرم افزار Arduino IDE اقدام به نصب کتابخانه مورد نیاز خواهیمکرد. مراحل زیر را دنبال کنید:
- این مسیر را دنبال کنید Sketch > Include Library > Manage Libraries
- کلمه Adafruit SSD1306 را جستجو کنید.
- کتابخانه را نصب کنید.
- سپس کلمه “GFX” را جستجو کنید و آن را نصب کنید.
تست و راه اندازی
در اولین مرحل اتصالات را طبق جدول و شماتیک زیر برقرار کنید، برای راهاندازی قطعات استفاده شده در این آموزش از پروتکل I2C استفاده میکنیم، به این صورت که پین های SCL, SDA به پین های A4, A5 متصل خواهند شد.
خب بعد از برقراری اتصالات، نوبت به کد پروژه میرسد. در ادامه باهم قسمت های مهمی از این کد را بررسی خواهیم کرد. در چند خط اول کتابخانه های مورد نیاز را معرفی میکنیم.
#include <SPI.h> #include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #include <Wire.h>
در این چند خط راهاندازی های اولیه برای دو ماژول استفاده شده را انجام خواهیم داد، برای مثال مشخص کردن I2C آدرس ها برای هر ماژول و همچنین متغیر های اولیه.
const int MPU=0x68; int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); #define OLED_address 0x3c
اینجا دو متغیر تعریف کردهایم که وظیفه آن ها پردازش خطوط مکعب است،این دلیل که در حرکت مکعب خطوط قبلی باید پاک، و خطوط جدید چاپ شوند.
int LinestoRender; int OldLinestoRender;
کد کامل پروژه راه اندازی ماژول MPU6050 با OLED و آردوینو نانو
#include <SPI.h> #include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #include <Wire.h> const int MPU=0x68; int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ; #define OLED_RESET 4 Adafruit_SSD1306 display(OLED_RESET); #define OLED_address 0x3c float xx,xy,xz; float yx,yy,yz; float zx,zy,zz; float fact; int Xan,Yan; int Xoff; int Yoff; int Zoff; struct Point3d { int x; int y; int z; }; struct Point2d { int x; int y; }; int LinestoRender; int OldLinestoRender; struct Line3d { Point3d p0; Point3d p1; }; struct Line2d { Point2d p0; Point2d p1; }; Line3d Lines[12]; //تعداد خطوط قابل پردازش Line2d Render[12]; Line2d ORender[12]; void SetVars(void) { float Xan2,Yan2,Zan2; float s1,s2,s3,c1,c2,c3; Xan2 = Xan / fact; // تبدیل مقادیر زاویه Yan2 = Yan / fact; s1 = sin(Yan2); s2 = sin(Xan2); c1 = cos(Yan2); c2 = cos(Xan2); xx = c1; xy = 0; xz = -s1; yx = (s1 * s2); yy = c2; yz = (c1 * s2); zx = (s1 * c2); zy = -s2; zz = (c1 * c2); } void ProcessLine(struct Line2d *ret,struct Line3d vec) { float zvt1; int xv1,yv1,zv1; float zvt2; int xv2,yv2,zv2; int rx1,ry1; int rx2,ry2; int x1; int y1; int z1; int x2; int y2; int z2; int Ok; x1=vec.p0.x; y1=vec.p0.y; z1=vec.p0.z; x2=vec.p1.x; y2=vec.p1.y; z2=vec.p1.z; Ok=0; // بطور پیشفرض ۰ xv1 = (x1 * xx) + (y1 * xy) + (z1 * xz); yv1 = (x1 * yx) + (y1 * yy) + (z1 * yz); zv1 = (x1 * zx) + (y1 * zy) + (z1 * zz); zvt1 = zv1 - Zoff; if( zvt1 < -5){ rx1 = 256 * (xv1 / zvt1) + Xoff; ry1 = 256 * (yv1 / zvt1) + Yoff; Ok=1; // ok we are alright for point 1. } xv2 = (x2 * xx) + (y2 * xy) + (z2 * xz); yv2 = (x2 * yx) + (y2 * yy) + (z2 * yz); zv2 = (x2 * zx) + (y2 * zy) + (z2 * zz); zvt2 = zv2 - Zoff; if( zvt2 < -5){ rx2 = 256 * (xv2 / zvt2) + Xoff; ry2 = 256 * (yv2 / zvt2) + Yoff; } else { Ok=0; } if(Ok==1){ ret->p0.x=rx1; ret->p0.y=ry1; ret->p1.x=rx2; ret->p1.y=ry2; } } void setup() { Wire.begin(); display.begin(SSD1306_SWITCHCAPVCC, 0x3c); display.clearDisplay(); // پاک کردن صفحه Wire.begin(); fact = 180 / 3.14159265358979323846264338327950; // برای تبدیل زاویه به رادیان Xoff = 60; // محل قرار گیری مکعب در محور x Yoff = 15; // محل قرار گیری مکعب در محور y Zoff = 1300; //اندازه مکعب // Front Face. Lines[0].p0.x=-50; Lines[0].p0.y=-50; Lines[0].p0.z=50; Lines[0].p1.x=50; Lines[0].p1.y=-50; Lines[0].p1.z=50; Lines[1].p0.x=50; Lines[1].p0.y=-50; Lines[1].p0.z=50; Lines[1].p1.x=50; Lines[1].p1.y=50; Lines[1].p1.z=50; Lines[2].p0.x=50; Lines[2].p0.y=50; Lines[2].p0.z=50; Lines[2].p1.x=-50; Lines[2].p1.y=50; Lines[2].p1.z=50; Lines[3].p0.x=-50; Lines[3].p0.y=50; Lines[3].p0.z=50; Lines[3].p1.x=-50; Lines[3].p1.y=-50; Lines[3].p1.z=50; //back face. Lines[4].p0.x=-50; Lines[4].p0.y=-50; Lines[4].p0.z=-50; Lines[4].p1.x=50; Lines[4].p1.y=-50; Lines[4].p1.z=-50; Lines[5].p0.x=50; Lines[5].p0.y=-50; Lines[5].p0.z=-50; Lines[5].p1.x=50; Lines[5].p1.y=50; Lines[5].p1.z=-50; Lines[6].p0.x=50; Lines[6].p0.y=50; Lines[6].p0.z=-50; Lines[6].p1.x=-50; Lines[6].p1.y=50; Lines[6].p1.z=-50; Lines[7].p0.x=-50; Lines[7].p0.y=50; Lines[7].p0.z=-50; Lines[7].p1.x=-50; Lines[7].p1.y=-50; Lines[7].p1.z=-50; // چهار گوشه مکعب. Lines[8].p0.x=-50; Lines[8].p0.y=-50; Lines[8].p0.z=50; Lines[8].p1.x=-50; Lines[8].p1.y=-50; Lines[8].p1.z=-50; Lines[9].p0.x=50; Lines[9].p0.y=-50; Lines[9].p0.z=50; Lines[9].p1.x=50; Lines[9].p1.y=-50; Lines[9].p1.z=-50; Lines[10].p0.x=-50; Lines[10].p0.y=50; Lines[10].p0.z=50; Lines[10].p1.x=-50; Lines[10].p1.y=50; Lines[10].p1.z=-50; Lines[11].p0.x=50; Lines[11].p0.y=50; Lines[11].p0.z=50; Lines[11].p1.x=50; Lines[11].p1.y=50; Lines[11].p1.z=-50; LinestoRender=12; OldLinestoRender=LinestoRender; Wire.beginTransmission(MPU); Wire.write(0x6B); Wire.write(0); // 0 برای بیدار کردن ماژول Wire.endTransmission(true); } /***********************************************************************************************************************************/ void RenderImage( void) { for (int i=0; i<OldLinestoRender; i++ ) { display.drawLine(ORender[i].p0.x,ORender[i].p0.y,ORender[i].p1.x,ORender[i].p1.y, BLACK); // خطوط قدیمی } for (int i=0; i<LinestoRender; i++ ) { display.drawLine(Render[i].p0.x,Render[i].p0.y,Render[i].p1.x,Render[i].p1.y, WHITE); } OldLinestoRender=LinestoRender; Wire.beginTransmission(MPU); Wire.write(0x3B); Wire.endTransmission(true); Wire.requestFrom(MPU,14,true); AcX=Wire.read()<<8|Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L) AcY=Wire.read()<<8|Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L) AcZ=Wire.read()<<8|Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L) Tmp=Wire.read()<<8|Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L) GyX=Wire.read()<<8|Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L) GyY=Wire.read()<<8|Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L) GyZ=Wire.read()<<8|Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L) //delay(10); } void loop() { display.display(); display.clearDisplay(); //برای چرخش مکعب int xOut=0; int yOut=0; xOut = map(AcX,-17000,17000,-50,50); yOut = map(AcY,-17000,17000,-50,50); Xan+=xOut; Yan+=yOut; Yan=Yan % 360; Xan=Xan % 360; SetVars(); for(int i=0; i<LinestoRender ; i++) { ORender[i]=Render[i]; ProcessLine(&Render[i],Lines[i]); } RenderImage(); }
جمع بندی
در این آموزش با استفاده از ماژول MPU6050 و همچنین برد آردوینو نانو و نمایشگر Oled توانستیم با استفاده از مقادیر بدست آمده از ماژول ژایرو یک مکعب ۳D را نسبت تغییرات در این مقادیر حرکت دهیم.
- تنظیمات منوی tools در نرم افزار آردوینو نیز مانند تصویر زیر است.
چنانچه در مراحل راه اندازی و انجام این پروژه با مشکل مواجه شدید، بدون هیچ نگرانی در انتهای همین پست، به صورت ثبت نظر سوالتان را مطرح کنید. من در سریعترین زمان ممکن پاسخ رفع مشکل شما را خواهم داد. همچنین اگر ایرادی در کدها و یا مراحل اجرایی وجود دارند میتوانید از همین طریق اطلاع رسانی کنید.
در پایان نظرات و پیشنهادات خود را با ما درمیان بگذارید و با اشتراک گذاری این آموزش در شبکه های اجتماعی , از وبسایت دیجی اسپارک حمایت کنید.
سلام و خسته نباشید ، بسیار بسیار زیاد از زحمات و ارائه مطالب شما سپاسگزارم ، پیشنهاد داشتم که لطفا در خصوص کد برنامه ها که اتفاقا قسمت مهم پروژه ها هستند نیز توضیحات بیشتری ارائه بفرمایید ، خصوصا در برخی جرئیات و ریزه کاری ها که میتونه راهنمای خوبی برای همه و برای اجرای پروژه های مشابه باشد . تشکر
با سلام و سپاس از شما
معمولا کدهای دیجی اسپارک همگی دارای توضیحات هستند. ولی هرجایی نیاز به راهنمایی داشتید و یا مطلبی گنگ بود، در همین قسمت مطرح کنید.