فهرست مطالب:

ربات خود متعادل از Magicbit: 6 مرحله
ربات خود متعادل از Magicbit: 6 مرحله

تصویری: ربات خود متعادل از Magicbit: 6 مرحله

تصویری: ربات خود متعادل از Magicbit: 6 مرحله
تصویری: 😉 وقتی شوهرش سرکاره، ربات مرد تمام خواسته های زن را برآورده می کند 2024, جولای
Anonim

این آموزش نحوه ساخت یک روبات متعادل کننده را با استفاده از برد Magicbit dev نشان می دهد. ما در این پروژه که بر اساس ESP32 طراحی شده است ، از magicbit به عنوان تابلوی توسعه استفاده می کنیم. بنابراین می توان از هر تخته توسعه ESP32 در این پروژه استفاده کرد.

تدارکات:

  • magicbit
  • دو درایور موتور H-Bridge L298
  • تنظیم کننده خطی (7805)
  • باتری Lipo 7.4V 700mah
  • واحد اندازه گیری اینرسی (IMU) (6 درجه آزادی)
  • موتورهای دنده ای 3V-6V DC

مرحله 1: داستان

داستان
داستان
داستان
داستان

سلام بچه ها ، امروز در این آموزش ما با چیزهای کمی پیچیده آشنا می شویم. این در مورد روبات خود متعادل با استفاده از Magicbit با Arduino IDE است. بنابراین اجازه دهید شروع کنیم.

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

مرحله 2: نظریه و روش شناسی

نظریه و روش شناسی
نظریه و روش شناسی

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

  • P- متناسب
  • I- انتگرال
  • د- مشتق

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

اولین مورد ضرب خطا از افزایش عددی است. این سود معمولاً Kp نامیده می شود

P = خطا*Kp

مورد دوم این است که انتگرال خطا را در حوزه زمان ایجاد کرده و آن را از برخی از سودها ضرب کنید. این سود به نام Ki نامیده می شود

I = انتگرال (خطا)*Ki

مورد سوم مشتق شده از خطا در حوزه زمانی و ضرب آن در مقدار سود است. این سود Kd نامیده می شود

D = (d (خطا)/dt)*kd

پس از افزودن عملیات بالا ، خروجی نهایی خود را دریافت می کنیم

خروجی = P+I+D

به دلیل قسمت P ، ربات می تواند موقعیت پایداری پیدا کند که متناسب با انحراف است. بخش I مساحت خطا را در برابر نمودار زمان محاسبه می کند. بنابراین سعی می شود ربات را همیشه با دقت به موقعیت پایدار برساند. قسمت D شیب را در نمودار زمان و خطا اندازه گیری می کند. در صورت افزایش خطا ، این مقدار مثبت است. اگر خطا در حال کاهش است ، این مقدار منفی است. به همین دلیل ، هنگامی که ربات به موقعیت پایدار حرکت می کند ، سرعت عکس العمل کاهش می یابد و این به حذف بیش از حد اضافی کمک می کند. از طریق این پیوند که در زیر نشان داده شده است ، می توانید در مورد نظریه PID بیشتر بیاموزید.

www.arrow.com/fa/research-and-events/articles/pid-controller-basics-and-tutorial-pid-implementation-in-arduino

خروجی عملکرد PID محدوده 0-255 (وضوح 8 بیتی PWM) است و به عنوان سیگنال PWM به موتورها تغذیه می شود.

مرحله 3: راه اندازی سخت افزار

راه اندازی سخت افزار
راه اندازی سخت افزار

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

وقتی در مورد مدار بحث می کنیم از باتری 7.4 ولت لیپو تغذیه می کند. Magicbit برای تغذیه از 5 ولت استفاده کرد. بنابراین ما از تنظیم کننده 7805 برای تنظیم ولتاژ باتری به 5V استفاده کردیم. در نسخه های بعدی Magicbit آن تنظیم کننده نیاز ندارد. زیرا تا 12 ولت قدرت دارد. ما مستقیماً 7.4 ولت را برای راننده موتور تأمین می کنیم.

مطابق نمودار زیر همه اجزا را وصل کنید.

مرحله 4: راه اندازی نرم افزار

در کد ما از کتابخانه PID برای محاسبه خروجی PID استفاده کردیم.

برای بارگیری به لینک زیر بروید.

www.arduinolibraries.info/libraries/pid

آخرین نسخه آن را بارگیری کنید.

برای به دست آوردن خواندن بهتر حسگرها از کتابخانه DMP استفاده کردیم. DMP مخفف فرآیند حرکت دیجیتال است. این ویژگی داخلی MPU6050 است. این تراشه دارای واحد فرآیند حرکت یکپارچه است. بنابراین به خواندن و تحلیل نیاز دارد. پس از تولید خروجی های دقیق بدون سر و صدا به میکروکنترلر (در این مورد Magicbit (ESP32)). اما کارهای زیادی در سمت میکروکنترلر وجود دارد که این اندازه گیری ها را انجام داده و زاویه را محاسبه می کند. بنابراین به سادگی ما از کتابخانه MPU6050 DMP استفاده کردیم. آن را از طریق goint به لینک زیر بارگیری کنید.

github.com/ElectronicCats/mpu6050

برای نصب کتابخانه ها ، در منوی آردوینو به منوی tools-> include library-> add.zip library رفته و فایل کتابخانه ای را که بارگیری کرده اید انتخاب کنید.

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

پورت COM و برد مناسب را انتخاب کنید. کد را بارگذاری کنید اکنون می توانید با ربات DIY خود بازی کنید.

مرحله 5: شماتیک

طرحواره ها
طرحواره ها

مرحله 6: کد

#عبارتند از

#شامل "I2Cdev.h" #شامل "MPU6050_6Axis_MotionApps20.h" #اگر I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #شامل "Wire.h" #endif MPU6050 mpu؛ bool dmpReady = false؛ // اگر DMP init موفق بود uint8_t mpuIntStatus موفقیت آمیز بود ؛ // دارای بایت وضعیت وقفه واقعی از MPU uint8_t devStatus است. // بازگشت وضعیت پس از هر عملیات دستگاه (0 = موفقیت ، 0 = خطا) uint16_t packetSize؛ // اندازه بسته DMP مورد انتظار (پیش فرض 42 بایت است) uint16_t fifoCount؛ // تعداد کل بایت های موجود در FIFO uint8_t fifoBuffer [64] ؛ // بافر ذخیره سازی FIFO Quaternion q؛ // [w، x، y، z] quaternion container VectorFlo gravity؛ // [x، y، z] بردار گرانش شناور ypr [3]؛ // [yaw، pitch، roll] yaw/pitch/roll ظرف و بردار گرانش دو اصل اصلیSetpoint = 172.5؛ double setpoint = originalSetpoint؛ double moveAngleOffset = 0.1؛ ورودی دوگانه ، خروجی ؛ int moveState = 0؛ double Kp = 23؛ // set P first double Kd = 0.8؛ // این مقدار به طور کلی کوچک دو برابر Ki = 300 ؛ // این مقدار برای ثبات بهتر PID pid (& ورودی ، & خروجی ، & setpoint ، Kp ، Ki ، Kd ، DIRECT) ؛ // pid initialize int motL1 = 26 ؛ // 4 پین برای درایو موتور int motL2 = 2 ؛ int motR1 = 27 ؛ int motR2 = 4 ؛ bool فرار mpuInterrupt = false؛ // نشان می دهد که آیا پین وقفه MPU بسیار void شده است dmpDataReady () {mpuInterrupt = true؛ } void setup () {ledcSetup (0، 20000، 8)؛ // راه اندازی pwm ledcSetup (1، 20000، 8)؛ ledcSetup (2 ، 20000 ، 8) ؛ ledcSetup (3 ، 20000 ، 8) ؛ ledcAttachPin (motL1 ، 0) ؛ // pinmode از موتورها ledcAttachPin (motL2 ، 1) ؛ ledcAttachPin (motR1 ، 2) ؛ ledcAttachPin (motR2 ، 3) ؛ // به گذرگاه I2C بپیوندید (کتابخانه I2Cdev این کار را به صورت خودکار انجام نمی دهد) #اگر I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin ()؛ Wire.setClock (400000) ؛ // ساعت 400kHz I2C. در صورت داشتن مشکلات کامپایل ، این خط را کامنت کنید #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400 ، true) ؛ #endif Serial.println (F ("راه اندازی دستگاههای I2C …")) ؛ pinMode (14 ، ورودی) ؛ // راه اندازی ارتباط سریال // (115200 انتخاب شده است زیرا برای خروجی نسخه نمایشی قوری مورد نیاز است ، اما // بسته به پروژه شما بستگی به شما دارد) Serial.begin (9600) ؛ در حالی که (! سریال) ؛ // منتظر شمارش لئوناردو باشید ، دیگران بلافاصله ادامه می دهند // مقداردهی اولیه دستگاه Serial.println (F ("راه اندازی دستگاه های I2C …")) ؛ mpu.initialize ()؛ // تأیید اتصال Serial.println (F ("آزمایش اتصالات دستگاه …")) ؛ Serial.println (mpu.testConnection ()؟ F ("اتصال MPU6050 موفق شد"): F ("اتصال MPU6050 ناموفق بود")) ؛ // بارگذاری و پیکربندی DMP Serial.println (F ("راه اندازی DMP …")) ؛ devStatus = mpu.dmpInitialize ()؛ // جفت های ژیروسکوپ خود را در اینجا تهیه کنید ، برای حداقل حساسیت mpu.setXGyroOffset (220) ؛ mpu.setYGyroOffset (76) ؛ mpu.setZGyroOffset (-85) ؛ mpu.setZAccelOffset (1788) ؛ // 1688 پیش فرض کارخانه برای تراشه آزمایشی من // مطمئن شوید که کار کرده است (در صورت وجود 0) اگر (devStatus == 0) {// DMP را روشن کنید ، اکنون که آماده است Serial.println (F ("فعال کردن DMP … "))؛ mpu.setDMP فعال (درست) ؛ // فعال کردن تشخیص وقفه Arduino Serial.println (F ("فعال کردن تشخیص وقفه (وقفه خارجی Arduino 0) …")) ؛ attachInterrupt (14 ، dmpDataReady ، RISING) ؛ mpuIntStatus = mpu.getIntStatus ()؛ // پرچم DMP Ready ما را تنظیم کنید تا تابع حلقه اصلی () بداند که استفاده از آن اشکالی ندارد Serial.println (F ("DMP آماده! منتظر اولین وقفه …")) ؛ dmpReady = true؛ // اندازه بسته مورد انتظار DMP را برای مقایسه packetSize = mpu.dmpGetFIFOPacketSize () دریافت کنید؛ // راه اندازی PID pid. SetMode (AUTOMATIC) ؛ pid. SetSampleTime (10) ؛ pid. SetOutputLimits (-255 ، 255) ؛ } else {// ERROR! // 1 = بارگذاری اولیه حافظه انجام نشد // 2 = به روز رسانی پیکربندی DMP ناموفق بود // (در صورت خرابی ، معمولاً کد 1 خواهد بود) Serial.print (F ("DMP Initialization failed (code")) ؛ Serial. print (devStatus) ؛ Serial.println (F (")")) ؛ }} void loop () {// اگر برنامه نویسی شکست خورد ، در صورت بازگشت (! dmpReady) سعی نکنید کاری انجام دهید. // منتظر وقفه MPU یا بسته های اضافی در حالی باشید که (! mpuInterrupt && fifoCount <packetSize) {pid. Compute ()؛ // این مدت زمان برای بارگیری داده ها استفاده می شود ، بنابراین می توانید از آن برای محاسبات دیگر استفاده کنید motorSpeed (خروجی) ؛ } // بازنشانی پرچم وقفه و دریافت INT_STATUS بایت mpuInterrupt = false؛ mpuIntStatus = mpu.getIntStatus ()؛ // دریافت تعداد فعلی FIFO fifoCount = mpu.getFIFOCount ()؛ // برای سرریز چک کنید (این هرگز اتفاق نمی افتد مگر اینکه کد ما بسیار ناکارآمد باشد) اگر ((mpuIntStatus & 0x10) || fifoCount == 1024) {// بازنشانی شود تا بتوانیم تمیز mpu.resetFIFO () را تمیز ادامه دهیم. Serial.println (F ("سرریز FIFO!")) ؛ // در غیر این صورت ، برای قطع اطلاعات آماده DMP (این باید مکرراً اتفاق بیفتد)} در غیر این صورت (mpuIntStatus & 0x02) {// منتظر طول داده صحیح در دسترس باشید ، باید منتظر بمانید (PFoCount 1 بسته در دسترس است //) به ما اجازه می دهد بلافاصله بیشتر بدون انتظار وقفه بخوانیم) fifoCount -= packetSize؛ چاپ ("ypr / t") ؛ Serial.print (ypr [0] * 180/M_PI) ؛ // زاویه euler Serial.print ("\ t") ؛ Serial.print (ypr [1] * 180/M_PI) ؛ Serial.print ("\ t")؛ Serial.println (ypr [2] * 180/M_PI)؛ #endif input = ypr [1] * 180/M_PI + 180؛}} void motorSpeed (int PWM) {float L1 ، L2 ، R1 ، R2 ؛ اگر (PWM> = 0) {// جهت جلو L2 = 0 ؛ L1 = abs (PWM) ؛ R2 = 0 ؛ R1 = abs (PWM) ؛ اگر (L1> = 255) { L1 = R1 = 255؛}} else {// جهت عقب L1 = 0 ؛ L2 = abs (PWM) ؛ R1 = 0 ؛ R2 = abs (PWM) ؛ اگر (L2> = 255) {L2 = R2 = 255 ؛ }} // درایو موتور ledcWrite (0 ، L1) ؛ ledcWrite (1 ، L2) ؛ ledcWrite (2 ، R1*0.97) ؛ // 0.97 واقعیت سرعت است یا چون موتور راست دارای سرعت بالاتری نسبت به موتور چپ است ، بنابراین آن را کاهش می دهیم تا سرعت موتور برابر شود ledcWrite (3 ، R2*0.97) ؛

}

توصیه شده: