विज़ुअल सर्वोइंग के साथ निशाना लगाना
- आप केवल एक limelight और अपने drivetrain का उपयोग करके अपने रोबोट को सटीक और तेज़ी से निशाना लगा सकते हैं।
- यह सब 1 घंटे से भी कम समय में पूरा किया जा सकता है।
हाई-फ्रेमरेट विज़न ट्रैकिंग का उपयोग करके, अब विज़न पाइपलाइन को सीधे PID कंट्रोल लूप में "सेंसर" के रूप में उपयोग करना संभव है ताकि आपके रोबोट या टरेट को गाइड किया जा सके। इस विचार का परीक्षण करने के लिए हमने अपने 2017 FRC रोबोट में एक limelight जोड़ा और इसे केवल drivetrain और limelight द्वारा रिपोर्ट किए जा रहे networks table डेटा का उपयोग करके विज़न टारगेट पर निशाना लगाया।
इस उदाहरण में, हमारा टेस्ट कैंडिडेट एक 2017 FRC रोबोट था जो colson व्हील्स के साथ 6-व्हील drivetrain का उपयोग करता है। यहाँ एक तस्वीर है जिसमें हम इस टेस्ट को करने के लिए रोबोट पर limelight जोड़ रहे हैं।
इसके बाद हमने रोबोट में कुछ कोड जोड़ा जो तब चलता है जब ड्राइवर जॉयस्टिक पर एक बटन दबाए रखता है। इस रोबोट ने "tank" स्टाइल ड्राइविंग का उपयोग किया इसलिए OperatorControl फंक्शन drivetrain के बाएं और दाएं पक्षों को नियंत्रित करने के लिए 'left_command' वैल्यू और 'right_command' वैल्यू जेनरेट कर रहा था। सामान्य कंट्रोल कोड के बाद, हमने इस तरह का एक कोड ब्लॉक जोड़ा:
float Kp = -0.1f; // Proportional control constant
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) यह पर्याप्त नहीं होगा।
हमने अब तक जो ल ागू किया है वह एक सरल proportional control loop है। हमने heading में error की गणना की और उसे एक constant से गुणा किया, इस प्रकार एक motor command बनाया जो error के proportional है। जैसे-जैसे error शून्य की ओर जाता है, हमारा command शून्य की ओर जाएगा। समस्या यह है कि जब रोबोट मुड़ने की कोशिश करता है तो बहुत friction होता है। बहुत छोटे commands रोबोट को बिल्कुल नहीं घुमाएंगे। छोटे angles पर, command इतना छोटा हो सकता है कि वास्तव में रोबोट को हिला न सके। आप पा सकते हैं कि जब आप बड़ी targeting error के साथ शुरू करते हैं तो आपका रोबोट अपने टारगेट तक अच्छी तरह पहुंचता है लेकिन अगर आप वास्तव में करीब से शुरू करते हैं तो यह बिल्कुल निशाना नहीं लगा सकता।
इस समस्या को हल करने के कई तरीके हैं लेकिन यहाँ एक वास्तव में सरल समाधान है। हमने "minimum command" की अवधारणा का उपयोग किया। यदि error किसी threshold से बड़ा है, तो बस अपने motor command में एक constant जोड़ें जो लगभग उस न्यूनतम power का प्रतिनिधित्व करता है जो रोबोट को वास्तव में चलने के लिए आवश्यक है (आप वास्तव में इससे थोड़ा कम उपयोग करना चाहते हैं)। नया कोड इस तरह दिखता है:
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 बहुत अधिक सेट करते हैं, तो आपका रोबोट अस्थिर हो सकता है और टारगेट को overshoot करते हुए आगे-पीछे oscillate कर सकता है:

Kp और min_command पर कुछ tuning के बाद आपका रोबोट बहुत सटीक और तेज़ी से सीधे टारगेट पर निशाना लगाने लगेगा।
