विषयसूची:

रोबोटिक मनका छँटाई: 3 चरण (चित्रों के साथ)
रोबोटिक मनका छँटाई: 3 चरण (चित्रों के साथ)

वीडियो: रोबोटिक मनका छँटाई: 3 चरण (चित्रों के साथ)

वीडियो: रोबोटिक मनका छँटाई: 3 चरण (चित्रों के साथ)
वीडियो: चिन्टू की कार और डायनासोर 3 | pagal beta | desi comedy video | cs bisht vines | joke of 2024, जुलाई
Anonim
Image
Image
रोबोट मनका छँटाई
रोबोट मनका छँटाई
रोबोटिक मनका छँटाई
रोबोटिक मनका छँटाई
रोबोटिक मनका छँटाई
रोबोटिक मनका छँटाई

इस परियोजना में, हम पेरलर मोतियों को रंग के आधार पर छाँटने के लिए एक रोबोट का निर्माण करेंगे।

मैं हमेशा से एक कलर सॉर्टिंग रोबोट बनाना चाहता था, इसलिए जब मेरी बेटी को पेरलर बीड क्राफ्टिंग में दिलचस्पी हुई, तो मैंने इसे एक सही अवसर के रूप में देखा।

पेर्लर मोतियों का उपयोग कई मोतियों को एक पेगबोर्ड पर रखकर, और फिर उन्हें एक लोहे के साथ पिघलाकर फ़्यूज्ड आर्ट प्रोजेक्ट बनाने के लिए किया जाता है। आप आम तौर पर इन मोतियों को विशाल २२,००० मनके मिश्रित रंग के पैक में खरीदते हैं, और अपने मनचाहे रंग की खोज में बहुत समय बिताते हैं, इसलिए मैंने सोचा कि उन्हें छांटने से कला दक्षता में वृद्धि होगी।

मैं फ़िदगेट्स इंक के लिए काम करता हूँ इसलिए मैंने इस परियोजना के लिए ज्यादातर फ़िदगेट्स का उपयोग किया - लेकिन यह किसी भी उपयुक्त हार्डवेयर का उपयोग करके किया जा सकता है।

चरण 1: हार्डवेयर

यहाँ मैं इसे बनाने के लिए उपयोग करता हूँ। मैंने इसे phidgets.com के कुछ हिस्सों और घर के आस-पास पड़ी चीजों के साथ 100% बनाया है।

फ़िडगेट्स बोर्ड, मोटर्स, हार्डवेयर

  • HUB0000 - विंट हब फ़िदगेट
  • 1108 - चुंबकीय सेंसर
  • 2x STC1001 - 2.5A स्टेपर फ़िडगेट
  • 2x 3324 - 42STH38 NEMA-17 बाइपोलर गियरलेस स्टेपर
  • 3x 3002 - फिजेट केबल 60 सेमी
  • ३४०३ - यूएसबी २.० 4-पोर्ट हब
  • 3031 - महिला बेनी 5.5x2.1 मिमी
  • ३०२९ - २ तार १००' मुड़ केबल
  • 3604 - 10 मिमी सफेद एलईडी (10 का बैग)
  • 3402 - यूएसबी वेब कैमरा

अन्य भाग

  • 24VDC 2.0A बिजली की आपूर्ति
  • गैरेज से लकड़ी और धातु को स्क्रैप करें
  • ज़िप बंध
  • नीचे के कट ऑफ के साथ प्लास्टिक कंटेनर

चरण 2: रोबोट डिज़ाइन करें

रोबोट डिजाइन करें
रोबोट डिजाइन करें
रोबोट डिजाइन करें
रोबोट डिजाइन करें
रोबोट डिजाइन करें
रोबोट डिजाइन करें

हमें कुछ ऐसा डिज़ाइन करने की ज़रूरत है जो इनपुट हॉपर से एक बीड ले सके, उसे वेबकैम के नीचे रख सके, और फिर उसे उपयुक्त बिन में ले जा सके।

मनका पिकअप

मैंने पहले भाग को गोल प्लाईवुड के 2 टुकड़ों के साथ करने का फैसला किया, प्रत्येक में एक ही स्थान पर एक छेद ड्रिल किया गया। नीचे का टुकड़ा तय हो गया है, और शीर्ष टुकड़ा एक स्टेपर मोटर से जुड़ा हुआ है, जो इसे मोतियों से भरे हॉपर के नीचे घुमा सकता है। जब छेद हॉपर के नीचे जाता है, तो वह एक मनका उठाता है। फिर मैं इसे वेबकैम के नीचे घुमा सकता हूं, और तब तक और घुमा सकता हूं जब तक कि यह नीचे के टुकड़े में छेद के साथ मेल नहीं खाता, जिस बिंदु पर यह गिरता है।

इस तस्वीर में, मैं परीक्षण कर रहा हूं कि सिस्टम काम कर सकता है। प्लाईवुड के शीर्ष गोल टुकड़े को छोड़कर सब कुछ तय हो गया है, जो एक स्टेपर मोटर से नीचे की ओर से जुड़ा हुआ है। वेबकैम अभी तक माउंट नहीं किया गया है। मैं इस बिंदु पर मोटर की ओर मुड़ने के लिए सिर्फ फिजेट कंट्रोल पैनल का उपयोग कर रहा हूं।

मनका भंडारण

अगला भाग प्रत्येक रंग को धारण करने के लिए बिन प्रणाली को डिजाइन करना है। मैंने नीचे एक दूसरे स्टेपर मोटर का उपयोग करने और समान दूरी वाले डिब्बों के साथ एक गोल कंटेनर को घुमाने के लिए उपयोग करने का निर्णय लिया। इसका उपयोग उस छेद के नीचे सही डिब्बे को घुमाने के लिए किया जा सकता है जिससे मनका निकल जाएगा।

मैंने इसे कार्डबोर्ड और डक्ट टेप का उपयोग करके बनाया है। यहां सबसे महत्वपूर्ण बात एकरूपता है - प्रत्येक डिब्बे का आकार समान होना चाहिए, और पूरी चीज को समान रूप से भारित किया जाना चाहिए ताकि वह बिना लंघन के घूम जाए।

मनका हटाने को एक तंग फिटिंग ढक्कन के माध्यम से पूरा किया जाता है जो एक समय में एक ही डिब्बे को उजागर करता है, ताकि मोतियों को बाहर निकाला जा सके।

कैमरा

वेब कैमरा हॉपर और निचले प्लेट होल स्थान के बीच शीर्ष प्लेट पर लगा होता है। यह सिस्टम को बीड को गिराने से पहले उसे देखने की अनुमति देता है। कैमरे के नीचे मोतियों को रोशन करने के लिए एक एलईडी का उपयोग किया जाता है, और एक सुसंगत प्रकाश वातावरण प्रदान करने के लिए परिवेश प्रकाश को अवरुद्ध कर दिया जाता है। सटीक रंग पहचान के लिए यह बहुत महत्वपूर्ण है, क्योंकि परिवेश प्रकाश वास्तव में कथित रंग को फेंक सकता है।

स्थान का पता लगाना

सिस्टम के लिए बीड सेपरेटर के रोटेशन का पता लगाने में सक्षम होना महत्वपूर्ण है। इसका उपयोग शुरू करते समय प्रारंभिक स्थिति को स्थापित करने के लिए किया जाता है, लेकिन यह भी पता लगाने के लिए कि स्टेपर मोटर सिंक से बाहर हो गया है या नहीं। मेरे सिस्टम में, उठाते समय कभी-कभी एक मनका जाम हो जाता है, और सिस्टम को इस स्थिति का पता लगाने और उसे संभालने में सक्षम होने की आवश्यकता होती है - थोड़ा बैक अप करके और एजियन की कोशिश करके।

इसे संभालने के बहुत सारे तरीके हैं। मैंने एक 1108 चुंबकीय सेंसर का उपयोग करने का निर्णय लिया, जिसमें शीर्ष प्लेट के किनारे में एक चुंबक लगा हुआ था। यह मुझे हर घुमाव पर स्थिति को सत्यापित करने की अनुमति देता है। एक बेहतर समाधान शायद स्टेपर मोटर पर एक एनकोडर होगा, लेकिन मेरे पास 1108 पड़ा हुआ था इसलिए मैंने इसका इस्तेमाल किया।

रोबोट खत्म करो

इस बिंदु पर, सब कुछ काम किया गया है, और परीक्षण किया गया है। यह सब कुछ अच्छी तरह से माउंट करने और सॉफ्टवेयर लिखने पर आगे बढ़ने का समय है।

2 स्टेपर मोटर्स को STC1001 स्टेपर कंट्रोलर द्वारा संचालित किया जा रहा है। एक HUB000 - USB VINT हब का उपयोग स्टेपर नियंत्रकों को चलाने के साथ-साथ चुंबकीय सेंसर को पढ़ने और एलईडी चलाने के लिए किया जाता है। वेबकैम और HUB0000 दोनों एक छोटे USB हब से जुड़े हैं। मोटर्स को बिजली देने के लिए 24V बिजली की आपूर्ति के साथ एक 3031 बेनी और कुछ तार का उपयोग किया जाता है।

चरण 3: कोड लिखें

Image
Image

इस प्रोजेक्ट के लिए C# और Visual Studio 2015 का उपयोग किया जाता है। इस पृष्ठ के शीर्ष पर स्रोत डाउनलोड करें और आगे बढ़ें - मुख्य अनुभाग नीचे दिए गए हैं

प्रारंभ

सबसे पहले, हमें फिजेट ऑब्जेक्ट्स बनाना, खोलना और प्रारंभ करना होगा। यह फॉर्म लोड इवेंट में किया जाता है, और फिजेट हैंडलर संलग्न करता है।

निजी शून्य फॉर्म1_लोड (ऑब्जेक्ट प्रेषक, EventArgs e) {

/* फिजेट्स को इनिशियलाइज़ करें और खोलें */

शीर्ष। हबपोर्ट = 0; शीर्ष। संलग्न करें + = शीर्ष_संलग्न करें; शीर्ष। अलग करें + = Top_Detach; top. PositionChange += Top_PositionChange; शीर्ष। ओपन ();

नीचे। हबपोर्ट = 1;

बॉटम.अटैच += बॉटम_अटैच; नीचे। अलग करें + = नीचे_ अलग करें; बॉटम। पोजीशन चेंज + = बॉटम_पोजिशन चेंज; नीचे। ओपन ();

magSensor. HubPort = 2;

magSensor. IsHubPortDevice = सच; magSensor.अटैच += MagSensor_Attach; magSensor. Detach += MagSensor_Detach; magSensor. SensorChange += MagSensor_SensorChange; मैगसेंसर। ओपन ();

नेतृत्व किया। हबपोर्ट = 5;

एलईडी. IsHubPortDevice = सच; नेतृत्व किया। चैनल = 0; एलईडी। संलग्न करें + = लेड_अटैच; एलईडी। डिटैच + = लेड_डिटैच; नेतृत्व किया। ओपन (); }

निजी शून्य Led_Attach (ऑब्जेक्ट प्रेषक, Phidget22. Events. AttachEventArgs e) {

एलईडीअटैचडच.चेक किया गया = सच; नेतृत्व। राज्य = सच; LEDChk.चेक किया गया = सच; }

निजी शून्य MagSensor_Attach (ऑब्जेक्ट प्रेषक, Phidget22. Events. AttachEventArgs e) {

magSensorAttachedChk.checked = true; magSensor. SensorType = VoltageRatioSensorType. PN_1108; magSensor. DataInterval = 16; }

निजी शून्य बॉटम_अटैच (ऑब्जेक्ट प्रेषक, Phidget22. Events. AttachEventArgs e) {

बॉटमअटैच्डChk.चेक किया गया = सच; बॉटम। करंट लिमिट = बॉटम करंट लिमिट; नीचे। लगे हुए = सच; नीचे। वेग सीमा = निचला वेग सीमा; नीचे। त्वरण = नीचे एक्सेल; नीचे। डेटा अंतराल = १००; }

निजी शून्य Top_Attach (वस्तु प्रेषक, Phidget22. Events. AttachEventArgs e) {

topAttachedChk.checked = true; top. CurrentLimit = topCurrentLimit; शीर्ष। व्यस्त = सत्य; शीर्ष। रेस्केलफैक्टर = -1; top. VelocityLimit = -topVelocityLimit; शीर्ष। त्वरण = -टॉपएक्सेल; शीर्ष। डेटा अंतराल = १००; }

हम आरंभीकरण के दौरान किसी भी सहेजी गई रंग जानकारी में भी पढ़ते हैं, इसलिए पिछले रन को जारी रखा जा सकता है।

मोटर पोजिशनिंग

मोटर हैंडलिंग कोड में मोटर्स को स्थानांतरित करने के लिए सुविधा कार्य होते हैं। मैंने जिन मोटरों का उपयोग किया है, वे प्रति क्रांति ३, २०० १/१६वें चरण हैं, इसलिए मैंने इसके लिए एक स्थिरांक बनाया।

शीर्ष मोटर के लिए, 3 स्थितियां हैं जिन्हें हम मोटर को भेजने में सक्षम होना चाहते हैं: वेब कैमरा, छेद और स्थिति चुंबक। इनमें से प्रत्येक पद पर यात्रा करने के लिए एक कार्य है:

निजी शून्य अगला चुंबक (बूलियन प्रतीक्षा = झूठा) {

डबल स्थिति = शीर्ष। स्थिति% कदमPerRev;

top. TargetPosition += (stepsPerRev - posn);

अगर (प्रतीक्षा करें)

जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (५०); }

निजी शून्य अगला कैमरा (बूलियन प्रतीक्षा = झूठा) {

डबल स्थिति = शीर्ष। स्थिति% कदमPerRev; if (posn < Properties. Settings. Default.cameraOffset) top. TargetPosition += (Properties. Settings. Default.cameraOffset - posn); अन्य शीर्ष। लक्ष्य स्थिति + = ((गुण। सेटिंग्स। डिफॉल्ट.कैमराऑफसेट - पॉसन) + चरणपेररेव);

अगर (प्रतीक्षा करें)

जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (५०); }

निजी शून्य अगला होल (बूलियन प्रतीक्षा = झूठा) {

डबल स्थिति = शीर्ष। स्थिति% चरण PerRev; if (posn < Properties. Settings. Default.holeOffset) top. TargetPosition += (Properties. Settings. Default.holeOffset - posn); अन्य शीर्ष। लक्ष्य स्थिति + = ((गुण। सेटिंग्स। डिफॉल्ट.होलऑफसेट - पॉसन) + चरणपेररेव);

अगर (प्रतीक्षा करें)

जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (५०); }

एक रन शुरू करने से पहले, शीर्ष प्लेट को चुंबकीय सेंसर का उपयोग करके संरेखित किया जाता है। शीर्ष प्लेट को संरेखित करने के लिए किसी भी समय alignMotor फ़ंक्शन को कॉल किया जा सकता है। यह फ़ंक्शन सबसे पहले प्लेट को 1 पूर्ण क्रांति तक जल्दी से बदल देता है जब तक कि वह थ्रेशोल्ड के ऊपर चुंबक डेटा नहीं देखता। यह फिर थोड़ा सा बैक अप लेता है और धीरे-धीरे आगे बढ़ता है, सेंसर डेटा को कैप्चर करता है। अंत में, यह स्थिति को अधिकतम चुंबक डेटा स्थान पर सेट करता है, और स्थिति ऑफ़सेट को 0 पर रीसेट करता है। इस प्रकार, अधिकतम चुंबक स्थिति हमेशा (शीर्ष। स्थिति% stepsPerRev) पर होनी चाहिए।

थ्रेड संरेखणमोटरथ्रेड;बूलियन सॉ मैग्नेट; डबल मैगसेंसरमैक्स = 0; निजी शून्य संरेखण मोटर () {

// चुंबक का पता लगाएं

top. DataInterval = top. MinDataInterval;

आरीमैग्नेट = झूठा;

magSensor. SensorChange += magSensorStopMotor; शीर्ष। वेग सीमा = -1000;

इंट ट्राईकाउंट = 0;

पुनः प्रयास करें:

top. TargetPosition += stepsPerRev;

जबकि (top. IsMoving && !sawMagnet) थ्रेड.स्लीप(25);

अगर (!sawMagnet) {

अगर (tryCount> 3) {कंसोल। राइटलाइन ("संरेखण विफल"); शीर्ष। व्यस्त = झूठा; नीचे। व्यस्त = झूठा; रनटेस्ट = झूठा; वापसी; }

ट्राईकाउंट++;

Console. WriteLine ("क्या हम फंस गए हैं? बैकअप की कोशिश कर रहे हैं …"); शीर्ष। लक्ष्य स्थिति - = ६००; जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (१००);

गोटो कोशिश फिर से;

}

शीर्ष। वेग सीमा = -100;

मैगडाटा = नई सूची> (); magSensor. SensorChange += magSensorCollectPositionData; top. TargetPosition += ३००; जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (१००);

magSensor. SensorChange -= magSensorCollectPositionData;

top. VelocityLimit = -topVelocityLimit;

KeyValuePair अधिकतम = magData [0];

foreach (MagData में KeyValuePair जोड़ी) अगर (जोड़ी। मान> अधिकतम। मान) अधिकतम = जोड़ी;

top. AddPositionOffset(-max. Key);

magSensorMax = max. Value;

शीर्ष। लक्ष्य स्थिति = 0;

जबकि (शीर्ष। चल रहा है) धागा। सो जाओ (१००);

कंसोल। राइटलाइन ("सफलतापूर्वक संरेखित करें");

}

सूची> मैगडाटा;

निजी शून्य magSensorCollectPositionData (ऑब्जेक्ट प्रेषक, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) { magData. Add(new KeyValuePair(top. Position, e. SensorValue)); }

निजी शून्य magSensorStopMotor (वस्तु प्रेषक, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {

if (top. IsMoving && e. SensorValue> 5) {top. TargetPosition = top. Position - 300; magSensor. SensorChange -= magSensorStopMotor; आरीमैग्नेट = सच; } }

अंत में, नीचे की मोटर को बीड कंटेनर पोजीशन में से एक में भेजकर नियंत्रित किया जाता है। इस प्रोजेक्ट के लिए हमारे पास 19 पद हैं। एल्गोरिथ्म सबसे छोटा रास्ता चुन रहा है, और या तो दक्षिणावर्त या वामावर्त मुड़ता है।

निजी इंट बॉटमपोजिशन {प्राप्त करें {इंट पॉसन = (इंट) बॉटम। पोजीशन% स्टेप्सपेररेव; अगर (posn < 0) posn += stepsPerRev;

वापसी (int)Math. Round(((posn *beadCompartments) / (डबल)स्टेप्सपेररेव));

} }

निजी शून्य SetBottomPosition (int posn, bool wait = false) {

posn = posn% मनका डिब्बों; डबल टारगेटपॉसन = (पोज़न * स्टेप्सपेररेव) / बीड कम्पार्टमेंट;

डबल करंटपोस = बॉटम। पोजीशन% स्टेप्सपेररेव;

डबल posnDiff = targetPosn - currentPosn;

// इसे पूर्ण चरणों के रूप में रखें

posnDiff = ((int)(posnDiff / 16)) * 16;

अगर (posnDiff <= १६००) नीचे। लक्ष्य स्थिति + = posnDiff; और नीचे। लक्ष्य स्थिति - = (कदम PerRev - posnDiff);

अगर (प्रतीक्षा करें)

जबकि (नीचे। चल रहा है) धागा। सो जाओ (५०); }

कैमरा

OpenCV का उपयोग वेबकैम से छवियों को पढ़ने के लिए किया जाता है। मुख्य सॉर्टिंग थ्रेड प्रारंभ करने से पहले कैमरा थ्रेड प्रारंभ हो जाता है। यह थ्रेड लगातार छवियों में पढ़ता है, माध्य का उपयोग करके एक विशिष्ट क्षेत्र के लिए औसत रंग की गणना करता है और एक वैश्विक रंग चर को अद्यतन करता है। थ्रेड रंग का पता लगाने के लिए जिस क्षेत्र को देख रहा है उसे परिष्कृत करने के लिए, या तो एक मनका, या शीर्ष प्लेट में छेद का पता लगाने की कोशिश करने के लिए HoughCircles को नियोजित करता है। दहलीज और HoughCircles संख्या परीक्षण और त्रुटि के माध्यम से निर्धारित की गई थी, और वेबकैम, प्रकाश व्यवस्था और रिक्ति पर बहुत अधिक निर्भर करती है।

बूल रनविडियो = सच; बूल वीडियोरनिंग = झूठा; वीडियो कैप्चर कैप्चर; धागा cvThread; रंग का पता चलारंग; बूलियन का पता लगाना = झूठा; इंट डिटेक्ट सीएनटी = 0;

निजी शून्य cvThreadFunction () {

वीडियोरनिंग = झूठा;

कैप्चर = नया वीडियो कैप्चर (चयनित कैमरा);

का उपयोग (विंडो विंडो = नई विंडो ("कैप्चर")) {

चटाई छवि = नई चटाई (); मैट इमेज 2 = नया मैट (); जबकि (रनवीडियो) {कैप्चर। पढ़ें (छवि); अगर (छवि। खाली ()) तोड़;

अगर (पता लगाना)

डिटेक्ट सीएनटी ++; अन्य का पता लगाएं = 0;

अगर (पता लगाना || सर्कलडिटेक्टचेक किया गया || शो डिटेक्शनआईएमजी चेक किया गया) {

Cv2. CvtColor (छवि, छवि 2, ColorConversionCodes. BGR2GRAY); मैट थ्रेस = इमेज 2. थ्रेशोल्ड ((डबल) गुण। सेटिंग्स। डिफॉल्ट.वीडियो थ्रेश, 255, थ्रेसहोल्ड टाइप्स। बाइनरी); thres = thres. GaussianBlur (नया OpenCvSharp. Size (9, 9), 10);

अगर (शो डिटेक्शनआईएमजी चेक किया गया)

छवि = थ्रेस;

अगर (पता लगाना || सर्कलडिटेक्टचेक किया गया) {

सर्कल सेगमेंट बीड = थ्रेस। होफसर्कल (हफमेथोड्स। ग्रेडिएंट, 2, / * थ्रेस। रो / 4 * / 20, 200, 100, 20, 65); अगर (मनका। लंबाई> = 1) {छवि। सर्कल (बीड [0]। केंद्र, 3, नया स्केलर (0, 100, 0)), -1); छवि। सर्कल (बीड [0]। केंद्र, (इंट) मनका [0]। त्रिज्या, नया स्केलर (0, 0, 255), 3); अगर (मनका [0]। त्रिज्या> = 55) { गुण। सेटिंग्स। डिफ़ॉल्ट। x = (दशमलव) मनका [0]। केंद्र। एक्स + (दशमलव) (मनका [0]। त्रिज्या / 2); गुण। सेटिंग्स। डिफ़ॉल्ट। वाई = (दशमलव) मनका [0]। केंद्र। वाई - (दशमलव) (मनका [0]। त्रिज्या / 2); } और { गुण। सेटिंग्स। डिफ़ॉल्ट। x = (दशमलव) मनका [0]। केंद्र। एक्स + (दशमलव) (मनका [0]। त्रिज्या); गुण। सेटिंग्स। डिफ़ॉल्ट। वाई = (दशमलव) मनका [0]। केंद्र। वाई - (दशमलव) (मनका [0]। त्रिज्या); } गुण.सेटिंग्स. Default.size = 15; गुण। सेटिंग्स। डिफ़ॉल्ट। ऊंचाई = 15; } अन्यथा {

सर्कल सेगमेंट सर्कल = थ्रेस। होफसर्कल (हफमेथोड्स। ग्रेडिएंट, 2, / * थ्रेस। पंक्तियाँ / 4 * / 5, 200, 100, 60, 180);

अगर (मंडलियां। लंबाई> 1) {सूची xs = मंडलियां। चुनें (सी => सी। केंद्र। एक्स)। सूची (); xs.सॉर्ट (); सूची ys = वृत्त। चयन करें (c => c. Center. Y)। ToList (); वाईएस.सॉर्ट ();

इंट मेडियनएक्स = (इंट) एक्सएस [एक्सएस। काउंट / 2];

int माध्यिका = (int)ys[ys. Count / 2];

अगर (माध्यम> छवि। चौड़ाई - 15)

माध्यिका = छवि। चौड़ाई - 15; अगर (माध्य> छवि। ऊँचाई - 15) माध्यिका = छवि। ऊँचाई - 15;

image. Circle (माध्यम X, माध्यिका, 100, नया अदिश (0, 0, 150), 3);

अगर (पता लगाना) {

गुण.सेटिंग्स.डिफॉल्ट.एक्स = मेडियनएक्स - 7; Properties. Settings. Default.y = medianY - 7; गुण। सेटिंग्स। डिफ़ॉल्ट। आकार = 15; गुण। सेटिंग्स। डिफ़ॉल्ट। ऊंचाई = 15; } } } } }

रेक्ट आर = नया रेक्ट ((इंट) गुण। सेटिंग्स। डिफॉल्ट.एक्स, (int)Properties. Settings. Default.y, (int)Properties. Settings. Default.size, (int)Properties. Settings. Default.height);

चटाई मनका नमूना = नया चटाई (छवि, आर);

अदिश औसत रंग = Cv2.मीन (मनका नमूना); पता लगाया रंग = रंग। FromArgb ((int) avgColor [2], (int) avgColor [1], (int) avgColor [0]);

छवि। आयत (आर, नया स्केलर (0, 150, 0));

window. ShowImage (छवि);

Cv2. WaitKey(1); वीडियोरनिंग = सच; }

वीडियोरनिंग = झूठा;

} }

निजी शून्य कैमराStartBtn_Click(ऑब्जेक्ट प्रेषक, EventArgs e) {

अगर (कैमरास्टार्टबीटीएन.टेक्स्ट == "स्टार्ट") {

cvThread = नया थ्रेड (नया थ्रेडस्टार्ट (cvThreadFunction)); रनवीडियो = सच; सीवी थ्रेड। प्रारंभ (); CameraStartBtn. Text = "रोकें"; जबकि (! videoRunning) थ्रेड। सो (100);

UpdateColorTimer. Start ();

} अन्यथा {

रनविडियो = झूठा; सीवी थ्रेड। शामिल हों (); CameraStartBtn. Text = "शुरू"; } }

रंग

अब, हम एक मनका का रंग निर्धारित करने में सक्षम हैं, और उस रंग के आधार पर निर्णय लेते हैं कि इसे किस कंटेनर में गिराना है।

यह चरण रंग तुलना पर निर्भर करता है। हम झूठे सकारात्मक को सीमित करने के अलावा रंगों को बताने में सक्षम होना चाहते हैं, लेकिन साथ ही झूठी नकारात्मक को सीमित करने के लिए पर्याप्त सीमा की अनुमति देना चाहते हैं। रंगों की तुलना करना वास्तव में आश्चर्यजनक रूप से जटिल है, क्योंकि जिस तरह से कंप्यूटर रंगों को आरजीबी के रूप में संग्रहीत करते हैं, और जिस तरह से मनुष्य रंगों को समझते हैं, वे रैखिक रूप से सहसंबंधित नहीं होते हैं। मामले को बदतर बनाने के लिए, जिस रंग के तहत प्रकाश का रंग देखा जा रहा है, उसे भी ध्यान में रखा जाना चाहिए।

रंग अंतर की गणना के लिए जटिल एल्गोरिदम हैं। हम CIE2000 का उपयोग करते हैं, जो 1 के पास एक संख्या को आउटपुट करता है यदि 2 रंग मानव के लिए अप्रभेद्य होंगे। हम इन जटिल गणनाओं को करने के लिए ColorMine C# लाइब्रेरी का उपयोग कर रहे हैं। 5 का डेल्टाई मान गलत सकारात्मक और गलत नकारात्मक के बीच एक अच्छा समझौता करने के लिए पाया गया है।

चूंकि कंटेनरों के बाद अक्सर अधिक रंग होते हैं, अंतिम स्थिति कैचल बिन के रूप में आरक्षित होती है। मैं आम तौर पर मशीन को दूसरे पास पर चलाने के लिए अलग रखता हूं।

सूची

रंग = नई सूची (); सूची रंगपैनल्स = नई सूची (); सूची रंगटेक्स = नई सूची (); सूची colorCnts = नई सूची ();

const int numColorSpots = १८;

कॉन्स्ट इंट अज्ञातColorIndex = 18; int findColorPosition (रंग c) {

कंसोल। राइटलाइन ("रंग ढूँढना …");

वर cRGB = नया आरजीबी ();

सीआरजीबी.आर = सीआर; सीआरजीबी.जी = सीजी; सीआरजीबी.बी = सीबी;

इंट बेस्टमैच = -1;

डबल मैचडेल्टा = १००;

के लिए (int i = 0; i <रंग। गणना; i++) {

वर आरजीबी = नया आरजीबी ();

आरजीबी.आर = रंग । आर; आरजीबी.जी = रंग । जी; आरजीबी.बी = रंग । बी;

डबल डेल्टा = cRGB. Compare (RGB, नया CieDe2000Comparison ());

// डबल डेल्टा = डेल्टाई (सी, रंग ); Console. WriteLine("DeltaE (" + i. ToString () + "):" + delta. ToString ()); अगर (डेल्टा <मैचडेल्टा) {मैचडेल्टा = डेल्टा; बेस्टमैच = मैं; } }

अगर (मैचडेल्टा <5) {कंसोल। राइटलाइन ("मिला! (पॉसन:" + बेस्टमैच + "डेल्टा:" + मैचडेल्टा + ")"); बेस्टमैच लौटाएं; }

अगर (रंग। गणना < numColorSpots) {कंसोल। राइटलाइन ("नया रंग!"); रंग। जोड़ें (सी); this. BeginInvoke (नई क्रिया (सेटबैककलर), नई वस्तु {रंग। गणना - 1}); राइटऑट कलर्स (); वापसी (रंग। गणना - 1); } और { कंसोल.राइटलाइन ("अज्ञात रंग!"); अज्ञात रंग इंडेक्स लौटाएं; } }

तर्क छँटाई

सॉर्टिंग फ़ंक्शन वास्तव में मोतियों को सॉर्ट करने के लिए सभी टुकड़ों को एक साथ लाता है। यह फ़ंक्शन एक समर्पित थ्रेड में चलता है; शीर्ष प्लेट को हिलाना, मनके के रंग का पता लगाना, उसे एक बिन में रखना, सुनिश्चित करना कि शीर्ष प्लेट संरेखित रहती है, मोतियों की गिनती करना आदि।जब कैटचेल बिन भर जाता है तो यह चलना भी बंद कर देता है - अन्यथा हम बस अतिप्रवाह मोतियों के साथ समाप्त हो जाते हैं।

थ्रेड कलरटेस्ट थ्रेड; बूलियन रनटेस्ट = झूठा; शून्य रंग परीक्षण () {

अगर (! शीर्ष। व्यस्त)

शीर्ष। व्यस्त = सत्य;

अगर (! नीचे। व्यस्त)

नीचे। लगे हुए = सच;

जबकि (रनटेस्ट) {

नेक्स्टमैग्नेट (सच);

धागा। नींद (100); कोशिश करें { अगर (magSensor. SensorValue < (magSensorMax - 4)) alignMotor (); } पकड़ें { alignMotor (); }

अगला कैमरा (सच);

पता लगाना = सच;

जबकि (डिटेक्टेंट <5) थ्रेड। स्लीप (25); Console. WriteLine ("गणना का पता लगाएं:" + पता लगाएँ); पता लगाना = झूठा;

रंग सी = पता लगायारंग;

this. BeginInvoke (नई क्रिया (सेटकोलरडेट), नई वस्तु {सी}); int i = findColorPosition (c);

सेटबॉटमपोजिशन (i, सच);

नेक्स्टहोल (सच); colorCnts ++; this. BeginInvoke (नई क्रिया (setColorTxt), नई वस्तु {i}); धागा। सो (250);

अगर (colorCnts [अज्ञातColorIndex]> 500) {

शीर्ष। व्यस्त = झूठा; नीचे। व्यस्त = झूठा; रनटेस्ट = झूठा; this. BeginInvoke (नई क्रिया (सेटगोग्रीन), शून्य); वापसी; } } }

निजी शून्य colorTestBtn_Click (ऑब्जेक्ट प्रेषक, EventArgs e) {

अगर (colourTestThread == null || !colorTestThread. IsAlive) {colorTestThread = नया थ्रेड (नया थ्रेडस्टार्ट (कलरटेस्ट)); रनटेस्ट = सच; colorTestThread. Start (); colorTestBtn. Text = "STOP"; colorTestBtn. BackColor = Color. Red; } और {रनटेस्ट = झूठा; colorTestBtn. Text = "जाओ"; colorTestBtn. BackColor = Color. Green; } }

इस बिंदु पर, हमारे पास एक कार्य कार्यक्रम है। कोड के कुछ अंश लेख से बाहर रह गए थे, इसलिए वास्तव में इसे चलाने के लिए स्रोत पर एक नज़र डालें।

प्रकाशिकी प्रतियोगिता
प्रकाशिकी प्रतियोगिता

प्रकाशिकी प्रतियोगिता में द्वितीय पुरस्कार

सिफारिश की: