تا به امروز آموزش های متفاوتی با استفاده ماژول ژایرو MPU6050 منتشر شده، در این آموزش قصد داریم با استفاده از ماژول پرکاربرد MPU6050 و همچنین نمایشگر Oled، یک مدل سه بعدی را کنترل کنیم با استفاده از تغییر مقادیر x, y که از ماژول ژایرو بدست میآید. در این آموزش از برد آردوینو نانو به عنوان برد راهانداز استفاده خواهیم کرد. برای آموزش های بیشتر به CiferTech مراجعه کنید، همچنین برای حمایت از من حتما پیج من در اینستاگرام را دنبال کنید. ^-^
ماژول 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 شاهد تغییر زوایای مکعب خواهیم بود.
وسایل موردنیاز
ماژول MPU6050
برد آروینو نانو (Arduino nano)
نمایشگر Oled 0.96
نصب کتابخانه مورد نیاز
ابتدا در نرم افزار Arduino IDE اقدام به نصب کتابخانه مورد نیاز خواهیمکرد. مراحل زیر را دنبال کنید:
- این مسیر را دنبال کنید Sketch > Include Library > Manage Libraries
- کلمه Adafruit SSD1306 را جستجو کنید.
- کتابخانه را نصب کنید.
- سپس کلمه “GFX” را جستجو کنید و آن را نصب کنید.
تست و راهاندازی
در اولین مرحل اتصالات را طبق جدول و شماتیک زیر برقرار کنید، برای راهاندازی قطعات استفاده شده در این آموزش از پروتکل I2C استفاده میکنیم، به این صورت که پین های SCL, SDA به پین های A4, A5 متصل خواهند شد.
خب بعد از برقراری اتصالات، نوبت به کد پروژه میرسد. در ادامه باهم قسمت های مهمی از این کد را بررسی خواهیم کرد. در چند خط اول کتابخانه های مورد نیاز را معرفی میکنیم.
1 2 3 4 |
<span style="font-size: 14px;">#include <SPI.h> #include <Adafruit_SSD1306.h> #include <Adafruit_GFX.h> #include <Wire.h></span> |
در این چند خط راهاندازی های اولیه برای دو ماژول استفاده شده را انجام خواهیم داد، برای مثال مشخص کردن I2C آدرس ها برای هر ماژول و همچنین متغیر های اولیه.
1 2 3 4 5 6 7 |
<span style="font-size: 14px;">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</span> |
اینجا دو متغیر تعریف کردهایم که وظیفه آن ها پردازش خطوط مکعب است،این دلیل که در حرکت مکعب خطوط قبلی باید پاک، و خطوط جدید چاپ شوند.
1 2 |
<span style="font-size: 14px;">int LinestoRender; int OldLinestoRender;</span> |
کد کامل پروژه.
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 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 |
<span style="font-size: 14px;">#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; // بطور پیشفرض 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(); }</span> |
جمع بندی
در این آموزش با استفاده از ماژول MPU6050 و همچنین برد آردوینو نانو و نمایشگر Oled توانستیم با استفاده از مقادیر بدست آمده از ماژول ژایرو یک مکعب 3D را نسبت تغییرات در این مقادیر حرکت دهیم.
- تنظیمات منوی tools در نرم افزار Arduino IDE نیز مانند تصویر زیر است.