ماژول سنجش حرکت MPU-6050
ماژول MPU-6050 با شتابسنج و ژیروسکوپ سهمحور را از طریق I2C به آردوینو وصل میکنید، با کتابخانهٔ Adafruit MPU6050 دادهٔ شتاب و سرعت زاویهای را میخوانید و مفهوم واحد g و درجه بر ثانیه را درمییابید.
آنچه در این درس میآموزید
- نقش شتابسنج و ژیروسکوپ در یک واحد سنجش اینرسی (IMU) را توضیح دهید
- MPU-6050 را روی گذرگاه I2C با آدرس درست راهاندازی کنید
- شتاب را در واحد m/s² و سرعت زاویهای را در درجه بر ثانیه در سریال مانیتور بخوانید
فهرست مطالب
تا حالا پرسیدهاید گوشی شما چطور میفهمد آن را چرخاندهاید یا کدامسو نگه داشتهاید؟ پاسخ یک چیپ به نام IMU است: واحد سنجش اینرسی (Inertial Measurement Unit) که حرکت و چرخش را حس میکند. MPU-6050 پرکاربردترین IMU آموزشی دنیاست؛ در یک بستهٔ کوچک، یک شتابسنج (Accelerometer) سهمحور و یک ژیروسکوپ (Gyroscope) سهمحور دارد و فقط با دو سیم داده با آردوینو حرف میزند. رباتهای متعادلشونده، کنترلکنندههای پروازی و گیمپدها همه از همین جنس سنسور استفاده میکنند. در این درس MPU-6050 را سیمکشی میکنید، کتابخانهٔ رسمی Adafruit را نصب میکنید و اولین دادههای حرکتیتان را در سریال مانیتور میبینید.
داخل چیپ چه خبر است؟
تراشهٔ اصلی ماژول، MPU-6050 از InvenSense است و دو حسگر را یکجا دارد:
- شتابسنج سهمحور نیروی شتاب را روی محورهای X و Y و Z میسنجد. نکتهٔ کلیدی: جاذبهٔ زمین هم شتاب است! پس وقتی ماژول ساکن روی میز است، شتابسنج همان نیرویی را که زمین به شما وارد میکند نشان میدهد — این بعدها برای یافتن زاویه به کار میآید.
- ژیروسکوپ سهمحور سرعت زاویهای چرخش دور هر محور را میسنجد؛ یعنی نه «الان چند درجه چرخیدهام»، بلکه «الان با چه سرعتی میچرخم».
MPU-6050 یک پردازندهٔ داخلی به نام DMP (Motion Processing Unit) هم دارد که محاسبات ترکیب داده (Fusion) را خودش انجام میدهد؛ کار با آن به کتابخانههای سختتر نیاز دارد و در این درس مقدمه را میگیرید و ادامهٔ مسیر با خودتان است.
دادهها روی گذرگاه I2C رد و بدل میشود. اگر با این گذرگاه و اسکنر آدرس کار نکردهاید، اول درس پروتکل I2C را ببینید و برگردید؛ آنجا یاد گرفتهاید که SDA و SCL روی Uno کدام پینها هستند و چطور آدرس دستگاه را پیدا کنید.
آدرس و جامپر AD0
هر دستگاه I2C یک آدرس دارد. MPU-6050 با پایینبودن پایهٔ AD0 روی آدرس 0x68 پاسخ میدهد و اگر AD0 را به 3.3V وصل کنید، به 0x69 تغییر میکند. روی اکثر بردشکنهای GY-521، پایهٔ AD0 از قبل با مقاومت به GND رفته است؛ پس همان 0x68 را خواهید داشت. اگر روزی دو MPU-6050 را روی یک گذرگاه گذاشتید، راهحل همین AD0 است: یکی 0x68 و دیگری 0x69.
پینها و مشخصات
| پین | نقش |
|---|---|
| VCC | تغذیه؛ بردشکن رگولاتور دارد و ۳ تا ۵ ولت میپذیرد |
| GND | زمین |
| SCL | خط ساعت I2C |
| SDA | خط دادهٔ I2C |
| XDA / XCL | گذرگاه I2C کمکی برای اتصال حسگر بیرونی (مغناطیسسنج)؛ در این درس بلااستفاده |
| AD0 | انتخاب آدرس: به GND یعنی 0x68، به VCC یعنی 0x69 |
| INT | خروجی وقفه؛ برای دادهٔ آماده (در این درس بلااستفاده) |
| مشخصه | مقدار |
|---|---|
| پروتکل | I2C تا ۴۰۰ کیلوهرتز |
| آدرس | 0x68 (پیشفرض) یا 0x69 |
| بازهٔ شتابسنج | ±۲ تا ±۱۶ g (قابل تنظیم) |
| بازهٔ ژیروسکوپ | ±۲۵۰ تا ±۲۰۰۰ درجه بر ثانیه |
| دماسنج داخلی | دارد؛ برای جبران دمایی |
سیمکشی
| آردوینو Uno | ماژول MPU-6050 (GY-521) |
|---|---|
| 5V | VCC |
| GND | GND |
| A5 | SCL |
| A4 | SDA |
روی Uno، خطوط I2C از پینهای A4 (SDA) و A5 (SCL) بیرون آمدهاند. بردشکن GY-521 با 5V تغذیه میشود چون رگولاتور روی برد دارد؛ اما تراشهٔ داخلش 3.3 ولتی است و سطح منطقی I2C آن هم همین است — رگولاتور و مقاومتهای بالاکشِ روی برد این تفاوت را مدیریت میکنند.
نصب کتابخانه
دو بسته از Library Manager لازم است و هر دو رسمیاند:
- در Arduino IDE به Tools ← Manage Libraries بروید (یا آیکن کتابخانه در نوار کناری).
- عبارت
Adafruit MPU6050را جستوجو کنید و بستهٔ Adafruit MPU6050 را نصب کنید. - پنجرهٔ وابستگیها (Dependencies) را با Install All تأیید کنید تا Adafruit Unified Sensor و Adafruit BusIO هم نصب شوند. اگر پنجره نیامد، این دو را جداگانه جستوجو و نصب کنید.
بدون Adafruit Unified Sensor، کامپایل با خطای پیدا نشدن Adafruit_Sensor متوقف میشود.
اسکچ کامل: خواندن شتاب و چرخش
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
Adafruit_MPU6050 mpu;
void setup() {
Serial.begin(9600);
if (!mpu.begin()) {
Serial.println("MPU6050 connection failed");
while (1) delay(10);
}
mpu.setAccelerometerRange(MPU6050_RANGE_2_G);
mpu.setGyroRange(MPU6050_RANGE_250_DEG);
Serial.println("MPU6050 ready");
}
void loop() {
sensors_event_t a, g, temp;
mpu.getEvent(&a, &g, &temp);
Serial.print("Acc X: ");
Serial.print(a.acceleration.x, 2);
Serial.print(" Y: ");
Serial.print(a.acceleration.y, 2);
Serial.print(" Z: ");
Serial.print(a.acceleration.z, 2);
Serial.println(" m/s2");
Serial.print("Gyro X: ");
Serial.print(g.gyro.x * 180.0 / PI, 1);
Serial.print(" Y: ");
Serial.print(g.gyro.y * 180.0 / PI, 1);
Serial.print(" Z: ");
Serial.print(g.gyro.z * 180.0 / PI, 1);
Serial.println(" deg/s");
Serial.println();
delay(500);
}توضیح نکتههای تازه:
mpu.begin()— اگر راهاندازی شکست بخورد (سیمکشی، آدرس یا تغذیه)، پیام MPU6050 connection failed چاپ میشود و برنامه در حلقهٔ بینهایت میماند؛ این رفتار عمدی است تا دادهٔ غلط تولید نشود.setAccelerometerRange(MPU6050_RANGE_2_G)— کمترین بازه، بیشترین دقت را میدهد؛ برای آزمایشهای اتاق کافی است.mpu.getEvent(&a, &g, &temp)— یک فراخوان، سه مقدار میآورد: شتاب، سرعت زاویهای و دما. کتابخانهٔ Adafruit شتاب را مستقیم بر حسب m/s² میدهد.g.gyro.x * 180.0 / PI— کتابخانه سرعت زاویهای را بر حسب رادیان بر ثانیه میدهد؛ ضریب ۱۸۰ تقسیم بر عدد پی، آن را به درجه بر ثانیه تبدیل میکند که برای درک آسانتر است.
ماژول را ساکن و صاف روی میز بگذارید. خروجی سریال مانیتور چنین است (مقادیر با موقعیت شما کمی فرق میکند؛ قالب خط و عدد نزدیک ۹٫۸۱ برای Z قطعی است):
MPU6050 ready Acc X: 0.12 Y: -0.03 Z: 9.81 m/s2 Gyro X: 0.1 Y: -0.2 Z: 0.0 deg/s
دو نکتهٔ مفهومی از همین خروجی: عدد Z نزدیک ۹٫۸۱ است چون شتابسنج ساکن، واکنش به جاذبهٔ زمین را میسنجد و شتاب گرانش حدود ۹٫۸۱ متر بر مجذور ثانیه است. واحد g یعنی همین شتاب گرانش (۱g = ۹٫۸۱ m/s²)؛ اگر ماژول را بردارید و در هوا تکان دهید، Z عوض میشود ولی با سقوط آزاد، همهٔ محورها به صفر میگرایند. اعداد ژیروسکوپ ساکن هم باید نزدیک صفر باشند؛ انحراف کوچک و دائمی از صفر را «بایاس» (Offset) میگویند و در کارهای دقیق با کالیبراسیون حذف میشود.
و محاسبهٔ زاویه؟ شتابسنج از جاذبه زاویه میدهد (پایدار اما پرنویز) و ژیروسکوپ سرعت چرخش را جمع میزند (کمنویز اما لغزنده). روش رایج ترکیب این دو با فیلتر مکمل (Complementary Filter) است — یک میانگینگیری هوشمند که نقاط قوت هر دو را نگه میدارد؛ فرمولش یک خط است و بهعنوان گام بعدی شما تمرین خوبی است.
اشتباهات رایج و عیبیابی
| نشانه | علت رایج | راهحل |
|---|---|---|
| پیام MPU6050 connection failed | جابهجایی SDA/SCL، تغذیهٔ قطع یا آدرس متفاوت | A4→SDA و A5→SCL را چک کنید؛ با اسکنر I2C ببینید دستگاه روی 0x68 یا 0x69 است |
| مقادیر ثابت و بدون تغییر با حرکت | سیم SDA یا SCL شل است یا ماژول معیوب | اتصال بردبورد را سفت کنید و با اسکنر پاسخ بودن ماژول را تأیید کنید |
| اعداد پرشدار و پرنویز | ماژول روی سطح لرزان یا سیمهای شل | ماژول را محکم ببندید؛ در پروژهٔ جدی، میانگینگیری یا فیلتر اضافه کنید |
| Z به جای ۹٫۸۱ مقدار دیگر میدهد | ماژول کج گذاشته شده | ماژول را کاملاً افقی بگذارید؛ Z فقط در حالت صاف بهاندازهٔ گرانش است |
تمرینها
تمرین
تمرین ۱ — هشدار تکان شدید
اسکچ درس را طوری تغییر دهید که وقتی بزرگی شتاب روی هر محور از ۱۵ m/s² بیشتر شد (یعنی ضربه یا تکان شدید)، پیام Hard shake چاپ شود؛ در حالت عادی پیام Still چاپ شود.
نمایش راهحل
تابع abs قدر مطلق میگیرد تا جهت محورها مهم نباشد. کافی است پس از getEvent شرط بگذارید:
if (abs(a.acceleration.x) > 15 || abs(a.acceleration.y) > 15 || abs(a.acceleration.z) > 15) {
Serial.println("Hard shake");
} else {
Serial.println("Still");
}با تکاندادن محکم ماژول، خروجی سریال مانیتور چنین است:
MPU6050 ready Still Hard shake Still
::: :::
خلاصه
- MPU-6050 یک IMU با شتابسنج و ژیروسکوپ سهمحور است و داده را روی گذرگاه I2C میدهد؛ پیشزمینهٔ درس I2C برای فهم بهتر لازم است.
- آدرس I2C ماژول
0x68است و با بالا بردن AD0 به0x69تغییر میکند — راه استاندارد استفاده از دو ماژول روی یک گذرگاه. - کتابخانهٔ Adafruit MPU6050 همراه با Adafruit Unified Sensor از Library Manager نصب میشود.
- شتاب ساکن روی Z نزدیک ۹٫۸۱ m/s² است؛ این همان گرانش زمین است و واحد g یعنی ضرب آن (۱g = ۹٫۸۱ m/s²).
- زاویهٔ واقعی با ترکیب خروجی شتابسنج و ژیروسکوپ (فیلتر مکمل) بهدست میآید؛ بایاس ژیروسکوپ با کالیبراسیون حذف میشود.
حالا میتوانید حرکت را ببینید؛ در درس بعدی سراغ درایور موتور L298N میرویم تا از سنسور به کنش برسیم و اولین چرخها را بچرخانیم.