כיוון עם שירות חזותי
- אתה יכול לכוון את ה רובוט שלך במדויק ובמהירות באמצעות רק limelight ומערכת ההנעה שלך.
- ניתן להשיג את כל זה בפחות משעה אחת.
באמצעות מעקב חזותי בקצב פריימים גבוה, כעת אפשר להשתמש בצינור הראייה ישירות כ"חיישן" בלולאת בקרת PID כדי להנחות את הרובוט או המגדל שלך. כדי לבדוק את הרעיון הזה, הוספנו limelight לרובוט ה-FRC 2017 שלנו וגרמנו לו לכוון למטרות חזותיות באמצעות רק מערכת ההנעה ונתוני טבלת הרשתות שדווחו על ידי ה-limelight.
בדוגמה זו, מועמד הבדיקה שלנו היה רובוט FRC 2017 המשתמש במערכת הנעה בעלת 6 גלגלים עם גלגלי colson. הנה תמונה של הוספת limelight לרובוט כדי לבצע את הבדיקה הזו.
לאחר מכן הוספנו קוד לרובוט שיפעל בכל פעם שהנהג מחזיק לחצן בג'ויסטיק. רובוט זה השתמש בנהיגה בסגנון "טנק" כך שפונקציית OperatorControl יצרה ערך 'left_command' וערך 'right_command' כדי לשלוט בצדדים השמאלי והימני של מערכת ההנעה. לאחר קוד הבקרה הרגיל, הוספנו בלוק קוד כזה:
float Kp = -0.1f; // קבוע בקרה פרופורציונלי
std::shared_ptr<NetworkTable> table = NetworkTable::GetTable("limelight");
float tx = table->GetNumber("tx");
if (joystick->GetRawButton(9))
{
float heading_error = tx;
steering_adjust = Kp * tx;
left_command+=steering_adjust;
right_command-=steering_adjust;
}
מיד בהתחלה, זה עבד ברובו. הרובוט מסתובב לכיוון המטרה באופן אוטומטי בכל פעם שאתה מחזיק את הלחצן. אם אתה מזיז את המטרה, הרובוט מסתובב כדי לעקוב אחר המטרה. עם זאת, באמצעות הזנת הווידאו החי בלוח המחוונים, יכולנו לראות שהייתה בעיה גדולה אחת: הרובוט לא תמיד הגיע עד הסוף כדי להתיישר באופן מושלם עם המטרה. בכמה משחקים עם מטרות קטנות (כמו 2016 ו-2017) זה לא היה מספיק טוב.
מה שיישמנו עד כה הוא לולאת בקרה פרופורציונלית פשוטה. חישבנו את השגיאה בכיוון והכפלנו אותה בקבוע, ובכך יצרנו פקודת מנוע שהיא פרופורציונלית לשגיאה. כאשר השגיאה מתקרבת לאפס, הפקודה שלנו תתקרב לאפס. הבעיה היא שיש הרבה חיכוך כאשר הרובוט מנסה להסתובב. פקודות קטנות מאוד לא יסובבו את הרובוט בכלל. בזוויות קטנות, הפקודה יכולה להיות קטנה מדי כדי להזיז את הרובוט בפועל. ייתכן שתגלה שהרובוט שלך מגיע למטרה היטב כאשר אתה מתחיל עם שגיאת כיוון גדולה, אבל הוא פשוט לא יכול לכוון בכלל אם אתה מתחיל ממש קרוב.
ישנן מספר דרכים לפתור את הבעיה הזו, אבל הנה פתרון פשוט מאוד. השתמשנו במושג "פקודה מינימלית". אם השגיאה גדולה מסף מסוים, פשוט הוסף קבוע לפקודת המנוע שלך שמייצג בערך את כמות הכוח המינימלית הנדרש ת כדי שהרובוט יזוז בפועל (למעשה אתה רוצה להשתמש בקצת פחות מזה). הקוד החדש נראה כך:
float Kp = -0.1f;
float min_command = 0.05f;
std::shared_ptr<NetworkTable> table = NetworkTable::GetTable("limelight");
float tx = table->GetNumber("tx");
if (joystick->GetRawButton(9))
{
float heading_error = -tx;
float steering_adjust = 0.0f;
if (Math.abs(heading_error) > 1.0)
{
if (heading_error < 0)
{
steering_adjust = Kp*heading_error + min_command;
}
else
{
steering_adjust = Kp*heading_error - min_command;
}
}
left_command += steering_adjust;
right_command -= steering_adjust;
}
היזהר, אם תגדיר את Kp או min_command גבוה מדי, הרובוט שלך עלול להיות לא יציב ולהתנדנד הלוך ושוב כשהוא חורג מהמטרה:
לאחר כוונון מסוים של Kp ו-min_command, הרובוט שלך אמור לכוון ישירות למטרה במדויק ובמהירות.