תוכן עניינים:

רובוט איזון עצמי ממג'יקביט: 6 שלבים
רובוט איזון עצמי ממג'יקביט: 6 שלבים

וִידֵאוֹ: רובוט איזון עצמי ממג'יקביט: 6 שלבים

וִידֵאוֹ: רובוט איזון עצמי ממג'יקביט: 6 שלבים
וִידֵאוֹ: מניפולטור תוצרת אינדבה איטליה מניפולטור עם איזון עצמי 2024, יולי
Anonim

הדרכה זו מציגה כיצד להכין רובוט לאיזון עצמי באמצעות לוח devbit של Magicbit. אנו משתמשים ב- magicbit כלוח הפיתוח בפרויקט זה המבוסס על ESP32. לכן ניתן להשתמש בכל לוח פיתוח ESP32 בפרויקט זה.

אספקה:

  • קסם
  • נהג מנוע כפול H-bridge L298
  • וסת לינארי (7805)
  • סוללת ליפו 7.4V 700mah
  • יחידת מדידת אינרציה (IMU) (6 מעלות חופש)
  • מנועי הילוכים 3V-6V DC

שלב 1: סיפור

כַּתָבָה
כַּתָבָה
כַּתָבָה
כַּתָבָה

היי חבר'ה, היום במדריך זה נלמד על דבר קצת מורכב. זהו רובוט לאיזון עצמי באמצעות Magicbit עם Arduino IDE. אז בואו נתחיל.

קודם כל, בואו נסתכל על מהו רובוט איזון עצמי. רובוט איזון עצמי הוא רובוט דו גלגלי. התכונה המיוחדת היא שהרובוט יכול לאזן את עצמו ללא כל תמיכה חיצונית. כאשר הכוח מופעל הרובוט יקום ואז הוא יתאזן באופן רציף באמצעות תנועות תנודה. אז עכשיו כל מה שיש לך מושג גס לגבי רובוט איזון עצמי.

שלב 2: תיאוריה ומתודולוגיה

תיאוריה ומתודולוגיה
תיאוריה ומתודולוגיה

כדי לאזן את הרובוט, ראשית אנו מקבלים נתונים מחיישן כלשהו למדידת זווית הרובוט למישור אנכי. לשם כך השתמשנו ב- MPU6050. לאחר קבלת הנתונים מהחיישן אנו מחשבים את ההטיה למישור האנכי. אם רובוט במיקום ישר ומאוזן, זווית ההטיה היא אפס. אם לא, אז זווית ההטיה היא ערך חיובי או שלילי. אם הרובוט נוטה לצד הקדמי, אז הרובוט צריך לעבור לכיוון הקדמי. כמו כן אם הרובוט נוטה לצד ההפוך הרובוט צריך לעבור לכיוון ההפוך. אם זווית הטיה זו גבוהה אז מהירות התגובה צריכה להיות גבוהה. להיפך זווית ההטיה נמוכה ואז מהירות התגובה צריכה להיות נמוכה. כדי לשלוט בתהליך זה השתמשנו במשפט ספציפי הנקרא PID. PID היא מערכת בקרה אשר נהגה לשלוט בתהליכים רבים. PID מייצג 3 תהליכים.

  • P- פרופורציונלי
  • אני- אינטגרלי
  • נגזרת D

לכל מערכת יש קלט ופלט. באותו אופן למערכת בקרה זו יש גם קלט כלשהו. במערכת בקרה זו המהווה סטייה ממצב יציב. קראנו לזה טעות. ברובוט שלנו, השגיאה היא זווית ההטיה מהמישור האנכי. אם הרובוט מאוזן אז זווית ההטיה היא אפס. אז ערך השגיאה יהיה אפס. לכן הפלט של מערכת PID הוא אפס. מערכת זו כוללת שלושה תהליכים מתמטיים נפרדים.

הראשונה היא הכפלת השגיאה מהרווח המספרי. רווח זה מכונה בדרך כלל Kp

P = שגיאה*Kp

השני הוא ליצור את אינטגרל השגיאה בתחום הזמן ולהכפיל אותה מכמה רווח. הרווח הזה נקרא Ki

I = אינטגרל (שגיאה)*Ki

השלישית היא נגזרת של השגיאה בתחום הזמן וכפל אותה בכמה רווח. רווח זה נקרא Kd

D = (d (שגיאה)/dt)*kd

לאחר הוספת פעולות למעלה אנו מקבלים את התפוקה הסופית שלנו

פלט = P+I+D

בגלל חלק ה- P רובוט יכול לקבל מיקום יציב אשר פרופורציונאלי לסטייה. אני חלק מחשב את שטח השגיאה לעומת גרף הזמן. אז הוא מנסה להביא את הרובוט למיקום יציב תמיד במדויק. חלק D מודד את השיפוע בזמן לעומת גרף השגיאות. אם השגיאה עולה ערך זה חיובי. אם השגיאה יורדת ערך זה הוא שלילי. בגלל זה, כשהרובוט ינוע למיקום יציב, מהירות התגובה תפחת וזה יעזור להסיר מעיפות מיותרות. אתה יכול ללמוד עוד על תורת PID מהקישור המוצג להלן.

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

הפלט של פונקציית ה- PID מוגבל לטווח 0-255 (רזולוציית PWM של 8 סיביות) וזה יוזן למנועים כאות PWM.

שלב 3: התקנת חומרה

התקנת חומרה
התקנת חומרה

עכשיו זהו חלק להתקנת חומרה. עיצוב הרובוט תלוי בך. כשעיצבת את גוף הרובוט אתה צריך לשקול אותו סימטרי סביב הציר האנכי שנמצא בציר המנוע. מארז הסוללות הממוקם למטה. לכן הרובוט קל לאזן. בעיצוב שלנו אנו מקבעים לוח מג'ביט אנכית לגוף. השתמשנו בשני מנועי 12V הילוכים. אבל אתה יכול להשתמש בכל סוג של מנועי הילוכים. זה תלוי במידות הרובוט שלך.

כאשר אנו דנים על מעגל הוא מופעל על ידי סוללת ליפו 7.4V. Magicbit השתמשה ב -5 וולט להפעלה. לכן השתמשנו בווסת 7805 לווסת מתח הסוללה ל -5 וולט. בגרסאות מאוחרות יותר של Magicbit אין צורך בווסת. מכיוון שהוא מפעיל עד 12V. אנו מספקים ישירות 7.4V לנהג מנוע.

חבר את כל הרכיבים לפי התרשים שלהלן.

שלב 4: התקנת תוכנה

בקוד השתמשנו בספריית PID לחישוב פלט PID.

עבור לקישור הבא כדי להוריד אותו.

www.arduinolibraries.info/libraries/pid

הורד את הגרסה האחרונה שלו.

כדי לקבל קריאות חיישן טובות יותר השתמשנו בספריית DMP. DMP מייצג תהליך תנועה דיגיטלית. זוהי תכונה מובנית של MPU6050. שבב זה כולל יחידת תהליך תנועה משולבת. אז זה דורש קריאה וניתוח. לאחר שהוא יוצר יציאות מדויקות ללא רעש למיקרו -בקר (במקרה זה Magicbit (ESP32)). אבל יש הרבה עבודות בצד המיקרו -בקר כדי לבצע את הקריאות ולחשב את הזווית. אז פשוט שהשתמשנו בספריית MPU6050 DMP. הורד אותו על ידי goint לקישור הבא.

github.com/ElectronicCats/mpu6050

כדי להתקין את הספריות, בתפריט Arduino עבור אל כלים-> כלול ספרייה-> add.zip ספריית ובחר את קובץ הספרייה שהורדת.

בקוד עליך לשנות את זווית נקודת ההגדרה כראוי. ערכי קבוע ה- PID שונים מרובוט לרובוט. אז בכוונון זה, הגדר תחילה את ערכי Ki ו- Kd אפס ולאחר מכן הגדל את Kp עד שתקבל מהירות תגובה טובה יותר. גורמי Kp נוספים לירידות נוספות. לאחר מכן הגדל את ערך Kd. הגדל אותו תמיד בכמות קטנה מאוד. ערך זה בדרך כלל נמוך משאר הערכים. כעת הגדל את ה- Ki עד שיהיה לך יציבות טובה מאוד.

בחר ביציאת COM הנכונה ולוח הקלד את. להעלות את הקוד. עכשיו אתה יכול לשחק עם רובוט ה- DIY שלך.

שלב 5: תרשימים

סכמטים
סכמטים

שלב 6: קוד

#לִכלוֹל

#include "I2Cdev.h" #include "MPU6050_6Axis_MotionApps20.h" #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE #include "Wire.h" #endif MPU6050 mpu; bool dmpReady = false; // set true אם 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] מיכל הרבעון VectorFloat gravity; // [x, y, z] צף וקטור הכבידה ypr [3]; // [yaw, pitch, roll] מיכל yaw/pitch/roll וגרמטר הכבידה originalSetpoint = 172.5; ערך כפול = originalSetpoint; double movingAngleOffset = 0.1; קלט כפול, פלט; int moveState = 0; כפול Kp = 23; // set P first כפול Kd = 0.8; // ערך זה בדרך כלל Ki כפול קטן = 300; // ערך זה צריך להיות גבוה ליציבות טובה יותר PID pid (& קלט, פלט, & נקודת ערך, Kp, Ki, Kd, DIRECT); // pid לאתחל int motL1 = 26; // 4 סיכות לכונן מנוע int motL2 = 2; int motR1 = 27; int motR2 = 4; בול נדיף mpuInterrupt = false; // מציין אם סיכת ההפרעה של MPU הפכה לחלל חלל dmpDataReady () {mpuInterrupt = true; } void setup () {ledcSetup (0, 20000, 8); // pwm setup 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 לא עושה זאת באופן אוטומטי) #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE Wire.begin (); Wire.setClock (400000); // שעון I2C של 400kHz. הגיבו על שורה זו אם יש לכם קשיי הידור #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE Fastwire:: setup (400, true); #endif Serial.println (F ("אתחול התקני I2C …")); pinMode (14, INPUT); // אתחול תקשורת טורית // (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.setDMPEnabled (true); // אפשר את זיהוי הפרעות Arduino Serial.println (F ("הפעלת זיהוי הפרעות (Arduino interrupt extern 0) …")); attachInterrupt (14, dmpDataReady, RISING); mpuIntStatus = mpu.getIntStatus (); // הגדר את הדגל Ready DMP שלנו כך שפונקציית הלולאה () הראשית תדע שזה בסדר להשתמש בו Serial.println (F ("DMP מוכן! מחכה להפסקה ראשונה …")); dmpReady = true; // קבל את גודל חבילת DMP הצפויה להשוואה מאוחר יותר packetSize = mpu.dmpGetFIFOPacketSize (); // הגדרת PID pid. SetMode (AUTOMATIC); pid. SetSampleTime (10); pid. SetOutputLimits (-255, 255); } אחר {// שגיאה! // 1 = טעינת הזיכרון הראשונית נכשלה // 2 = עדכוני תצורת DMP נכשלו // (אם הוא עומד להישבר, בדרך כלל הקוד יהיה 1) Serial.print (F ("אתחול DMP נכשל (קוד")); סידורי. print (devStatus); Serial.println (F (")")); }} לולאת void () {// אם התכנות נכשל, אל תנסה לעשות דבר אם (! 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) {// המתן לאורך הנתונים הזמין הנכון, אמור להיות המתנה קצרה ביותר בזמן (חבילת fifoCount 1 זמינה // (זו מאפשר לנו לקרוא מיד יותר מבלי לחכות להפסקה) fifoCount -= packetSize; mpu.dmpGetQuaternion (& q, fifoBuffer); mpu.dmpGetGravity (& gravity, & q); mpu.dmpGetYawPitchRoll (ypr, & q, & gravity); #if LOG_IN. print ("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;}} אחרת {// כיוון לאחור 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 הוא עובדת מהירות או, מכיוון שלמנוע הימני יש מהירות גבוהה יותר מאשר המנוע השמאלי, לכן אנו מפחיתים אותו עד שמהירות המנוע שוות לדcWrite (3, R2*0.97);

}

מוּמלָץ: