ዝርዝር ሁኔታ:

ሮቦቲክ ዶቃ መደርደር 3 ደረጃዎች (ከስዕሎች ጋር)
ሮቦቲክ ዶቃ መደርደር 3 ደረጃዎች (ከስዕሎች ጋር)

ቪዲዮ: ሮቦቲክ ዶቃ መደርደር 3 ደረጃዎች (ከስዕሎች ጋር)

ቪዲዮ: ሮቦቲክ ዶቃ መደርደር 3 ደረጃዎች (ከስዕሎች ጋር)
ቪዲዮ: በድምጽ የሚሰራ ሮቦቲክ አርም 2024, ሀምሌ
Anonim
Image
Image
ሮቦቲክ ዶቃ መደርደር
ሮቦቲክ ዶቃ መደርደር
ሮቦቲክ ዶቃ መደርደር
ሮቦቲክ ዶቃ መደርደር
ሮቦቲክ ዶቃ መደርደር
ሮቦቲክ ዶቃ መደርደር

በዚህ ፕሮጀክት ውስጥ የፐርለር ዶቃዎችን በቀለም ለመደርደር ሮቦት እንሠራለን።

እኔ ሁል ጊዜ የቀለም መደርደር ሮቦት መገንባት እፈልግ ነበር ፣ ስለዚህ ልጄ በፔርለር ዶቃ የእጅ ሥራ ላይ ፍላጎት ባላት ጊዜ ፣ ይህንን እንደ ጥሩ አጋጣሚ አየሁት።

ፐርለር ዶቃዎች ብዙ ዶቃዎችን በእንጨት መሰንጠቂያ ላይ በማስቀመጥ የተዋሃዱ የጥበብ ፕሮጄክቶችን ለመፍጠር ያገለግላሉ ፣ ከዚያም በብረት ይቀልጣሉ። በአጠቃላይ እነዚህን ዶቃዎች በግዙፍ 22, 000 ዶቃ በተቀላቀለ የቀለም ጥቅሎች ውስጥ ይገዛሉ ፣ እና የሚፈልጉትን ቀለም በመፈለግ ብዙ ጊዜ ያሳልፋሉ ፣ ስለሆነም እነሱን መደርደር የጥበብ ቅልጥፍናን ይጨምራል ብዬ አሰብኩ።

እኔ ለ Phidgets Inc. እሰራለሁ ስለዚህ ለዚህ ፕሮጀክት አብዛኛውን ጊዜ ፒድጄቶችን እጠቀም ነበር - ግን ይህ ማንኛውንም ተስማሚ ሃርድዌር በመጠቀም ሊከናወን ይችላል።

ደረጃ 1 - ሃርድዌር

ይሄን የሠራሁት እዚህ ነው። ከ phidgets.com ክፍሎች እና በቤቱ ዙሪያ ተኝተው ከነበሩት ነገሮች ጋር 100% ገንብቼዋለሁ።

Phidgets Boards, Motors, Hardware

  • HUB0000 - VINT Hub Phidget
  • 1108 - መግነጢሳዊ ዳሳሽ
  • 2x STC1001 - 2.5A Stepper Phidget
  • 2x 3324 - 42STH38 NEMA -17 ባይፖላር Gearless Stepper
  • 3x 3002 - የፒዲጅ ኬብል 60 ሴ.ሜ
  • 3403 - USB2.0 4 -Port Hub
  • 3031 - ሴት አሳማ 5.5x2.1 ሚሜ
  • 3029 - 2 ሽቦ 100 'ጠማማ ገመድ
  • 3604 - 10 ሚሜ ነጭ LED (የ 10 ቦርሳ)
  • 3402 - የዩኤስቢ ድር ካሜራ

ሌሎች ክፍሎች

  • 24VDC 2.0A የኃይል አቅርቦት
  • ከእንጨት እና ከብረት ጋራዥ ይከርክሙ
  • የዚፕ ግንኙነቶች
  • ከታች የተቆረጠ የፕላስቲክ መያዣ

ደረጃ 2 - ሮቦቱን ዲዛይን ያድርጉ

ሮቦትን ዲዛይን ያድርጉ
ሮቦትን ዲዛይን ያድርጉ
ሮቦትን ዲዛይን ያድርጉ
ሮቦትን ዲዛይን ያድርጉ
ሮቦትን ዲዛይን ያድርጉ
ሮቦትን ዲዛይን ያድርጉ

ከግብዓት ማስቀመጫው ውስጥ አንድ ነጠላ ዶቃን ሊወስድ የሚችል አንድ ነገር ዲዛይን ማድረግ ፣ ከድር ካሜራ ስር ማስቀመጥ እና ከዚያ ወደ ተገቢው መያዣ ውስጥ ማንቀሳቀስ አለብን።

ዶቃ ማንሳት

እኔ 1 ኛ ክፍልን በ 2 ቁርጥራጮች በክብ ጣውላዎች ለመሥራት እወስናለሁ ፣ እያንዳንዳቸው በአንድ ቦታ ላይ ቀዳዳ ተቆፍረዋል። የታችኛው ቁራጭ ተስተካክሏል ፣ እና የላይኛው ቁራጭ በእቃ መጫኛ ሞተር ላይ ተጣብቋል ፣ ይህም በዶላዎች የተሞላ ሆፕ ስር ሊያሽከረክረው ይችላል። ቀዳዳው ከጉድጓዱ ስር ሲጓዝ አንድ ዶቃን ይወስዳል። ከዚያ ከድር ካሜራ በታች ማሽከርከር እችላለሁ ፣ እና ከዚያ በታችኛው ቁራጭ ውስጥ ካለው ቀዳዳ ጋር እስኪመሳሰል ድረስ ከዚያ በኋላ ማሽከርከር እችላለሁ ፣ በዚህ ጊዜ ወደሚወድቅበት።

በዚህ ሥዕል ውስጥ ስርዓቱ መሥራት እንደሚችል እየሞከርኩ ነው። ከታች ካለው የእግረኛ ሞተር ጋር ከተያያዘው የላይኛው ክብ የፓንች ቁራጭ በስተቀር ሁሉም ነገር ተስተካክሏል። የድር ካሜራ ገና አልተጫነም። እኔ በዚህ ጊዜ ወደ ሞተር ለመዞር የፒዲጅ መቆጣጠሪያ ፓነልን እየተጠቀምኩ ነው።

ዶቃ ማከማቻ

ቀጣዩ ክፍል እያንዳንዱን ቀለም ለመያዝ የቢን ስርዓቱን ዲዛይን ማድረግ ነው። እኔ በእኩል ርቀት ክፍሎች ጋር ክብ መያዣን ለመደገፍ እና ለማሽከርከር ከዚህ በታች ሁለተኛውን የእርከን ሞተር ለመጠቀም ወሰንኩ። ይህ ዶቃው በሚወድቅበት ቀዳዳ ስር ትክክለኛውን ክፍል ለማሽከርከር ሊያገለግል ይችላል።

ይህንን የሠራሁት ካርቶን እና ቱቦ ቴፕ በመጠቀም ነው። እዚህ በጣም አስፈላጊው ነገር ወጥነት ነው - እያንዳንዱ ክፍል ተመሳሳይ መጠን መሆን አለበት ፣ እና ሁሉም ነገር በእኩል ክብደት መሆን አለበት ስለሆነም ሳይዘል ይሽከረከራል።

ዶቃዎችን ማፍሰስ የሚቻለው በአንድ ጊዜ አንድ ክፍልን በሚያጋልጥ በጥብቅ በሚገጣጠም ክዳን አማካኝነት ነው።

ካሜራ

የድር ካሜራ በሆፕለር እና በታችኛው ጠፍጣፋ ቀዳዳ ቦታ መካከል ባለው የላይኛው ሳህን ላይ ተጭኗል። ይህ ስርዓቱ ከመውደቁ በፊት ዶቃውን እንዲመለከት ያስችለዋል። አንድ ወጥ የሆነ የመብራት አከባቢን ለማቅረብ በካሜራው ስር ያሉትን ዶቃዎች ለማብራት ኤልኢዲ ጥቅም ላይ ይውላል ፣ እና የአካባቢ ብርሃን ታግዷል። የአከባቢ መብራት በእውነቱ የተገነዘበውን ቀለም መጣል ስለሚችል ይህ ለትክክለኛ ቀለም መለየት በጣም አስፈላጊ ነው።

የቦታ መለየት

የስርዓቱ የዶላ መለያየትን አዙሪት መለየት መቻሉ አስፈላጊ ነው። ይህ በሚነሳበት ጊዜ የመጀመሪያውን ቦታ ለማቀናበር ፣ ግን የእርምጃ ሞተሩ ከማመሳሰል የወጣ መሆኑን ለመለየትም ያገለግላል። በእኔ ስርዓት ውስጥ አንድ ዶቃ በሚነሳበት ጊዜ አንዳንድ ጊዜ ይጨናነቃል ፣ እና ስርዓቱ ይህንን ሁኔታ ለመለየት እና ለማስተናገድ መቻል ነበረበት - ትንሽ በመጠባበቅ እና አጊያን በመሞከር።

ይህንን ለመቋቋም ብዙ መንገዶች አሉ። ከላይኛው ጠፍጣፋ ጠርዝ ላይ በማግኔት ውስጥ የተካተተ 1108 መግነጢሳዊ ዳሳሽ ለመጠቀም ወሰንኩ። ይህ በእያንዳንዱ ሽክርክሪት ላይ ያለውን አቀማመጥ ለማረጋገጥ ያስችለኛል። የተሻለ መፍትሔ ምናልባት በእግረኛው ሞተር ላይ ኢንኮደር ይሆናል ፣ ግን እኔ 1108 ዙሪያ ተኝቶ ነበር ስለዚህ ያንን ተጠቀምኩ።

ሮቦትን ጨርስ

በዚህ ጊዜ ሁሉም ነገር ተሠርቷል ፣ ተፈትኗል። ሁሉንም ነገር በጥሩ ሁኔታ ለመጫን እና ወደ ጽሑፍ ሶፍትዌር ለመግባት ጊዜው አሁን ነው።

የ 2 ስቴፐር ሞተሮች በ STC1001 stepper መቆጣጠሪያዎች እየተነዱ ናቸው። አንድ HUB000 - የዩኤስቢ VINT ማዕከል የእርከን መቆጣጠሪያዎችን ለማስኬድ ፣ እንዲሁም መግነጢሳዊ ዳሳሹን ለማንበብ እና ኤልኢዲውን ለመንዳት ያገለግላል። የድር ካሜራ እና HUB0000 ሁለቱም ከአነስተኛ የዩኤስቢ ማዕከል ጋር ተያይዘዋል። ሞተሮችን ለማንቀሳቀስ 3031 አሳማ እና አንዳንድ ሽቦ ከ 24 ቪ የኃይል አቅርቦት ጋር ያገለግላሉ።

ደረጃ 3 ኮድ ይጻፉ

Image
Image

C# እና Visual Studio 2015 ለዚህ ፕሮጀክት ስራ ላይ ይውላሉ። በዚህ ገጽ አናት ላይ ያለውን ምንጭ ያውርዱ እና ይከተሉ - ዋናዎቹ ክፍሎች ከዚህ በታች ተዘርዝረዋል

ተነሳሽነት

በመጀመሪያ ፣ የፒዲጅ ዕቃዎችን መፍጠር ፣ መክፈት እና ማስጀመር አለብን። ይህ የሚከናወነው በቅጹ ጭነት ክስተት ውስጥ ነው ፣ እና ፊድጌት ተቆጣጣሪዎችን ያያይዙታል።

የግል ባዶነት Form1_Load (የነገር ላኪ ፣ EventArgs e) {

/ * ፊደሎችን ያስጀምሩ እና ይክፈቱ */

top. HubPort = 0; top. Attach += Top_Attach; top. Detach += Top_Detach; top. PositionChange += Top_PositionChange; ከላይ ይክፈቱ ();

bottom. HubPort = 1;

bottom. Attach += የታችኛው_አባሪ; ታች። bottom. PositionChange += Bottom_PositionChange; ታች። ክፈት ();

magSensor. HubPort = 2;

magSensor. IsHubPortDevice = እውነት; magSensor. Attach += MagSensor_Attach; magSensor. Detach += MagSensor_Detach; magSensor. SensorChange += MagSensor_SensorChange; magSensor. Open ();

led. HubPort = 5;

led. IsHubPortDevice = እውነት; led. Channel = 0; led. Attach += Led_Attach; led. Detach += Led_Detach; led. Open (); }

የግል ባዶነት Led_Attach (የነገር ላኪ ፣ Phidget22. Events. AttachEventArgs e) {

ledAttachedChk. Checked = እውነት; led. State = እውነት; ledChk. Checked = እውነት; }

የግል ባዶነት MagSensor_Attach (የነገር ላኪ ፣ Phidget22. Events. AttachEventArgs e) {

magSensorAttachedChk. Checked = እውነት; magSensor. SensorType = VoltageRatioSensorType. PN_1108; magSensor. DataInterval = 16; }

የግል ባዶነት Bottom_Attach (የነገር ላኪ ፣ Phidget22. Events. AttachEventArgs e) {

bottomAttachedChk. Checked = እውነት; bottom. CurrentLimit = bottomCurrentLimit; bottom. Engaged = እውነት; bottom. VelocityLimit = bottomVelocityLimit; bottom. Acceleration = bottomAccel; ታች ዳታ ኢንተርቫል = 100; }

የግል ባዶነት Top_Attach (የነገር ላኪ ፣ Phidget22. Events. AttachEventArgs e) {

topAttachedChk. Checked = እውነት; top. CurrentLimit = topCurrentLimit; top. Engaged = እውነት; top. RescaleFactor = -1; top. VelocityLimit = -topVelocityLimit; top. Acceleration = -topAccel; top. DataInterval = 100; }

እኛ በማነሳሳት ጊዜ በማንኛውም የተቀመጠ የቀለም መረጃ ውስጥ እናነባለን ፣ ስለዚህ የቀደመው ሩጫ መቀጠል ይችላል።

የሞተር አቀማመጥ

የሞተር አያያዝ ኮድ ሞተሮችን ለማንቀሳቀስ ምቹ ተግባራትን ያጠቃልላል። እኔ የተጠቀምኩባቸው ሞተሮች በአንድ አብዮት 3 ፣ 200 1/16 ኛ ደረጃዎች ናቸው ፣ ስለዚህ ለዚህ ቋሚ ፈጠርኩ።

ለከፍተኛው ሞተር ወደ ሞተር ለመላክ የምንፈልጋቸው 3 ቦታዎች አሉ -የድር ካሜራ ፣ ቀዳዳ እና የአቀማመጥ ማግኔት። ወደ እያንዳንዱ ወደ እነዚህ ቦታዎች የመጓዝ ተግባር አለ-

የግል ባዶ ቀጥሎMagnet (ቡሊያን መጠበቅ = ሐሰት) {

ድርብ posn = top. አቀማመጥ % stepsPerRev;

top. TargetPosition += (stepsPerRev - posn);

ከሆነ (ይጠብቁ)

(ከላይ. IsMoving) ክር። እንቅልፍ (50); }

የግል ባዶነት ቀጥሎ ካሜራ (ቡሊያን መጠበቅ = ሐሰት) {

ድርብ posn = top. አቀማመጥ % stepsPerRev; ከሆነ (posn <Properties. Settings. Default.cameraOffset) top. TargetPosition += (Properties. Settings. Default.cameraOffset - posn); ሌላ top. TargetPosition + = ((Properties. Settings. Default.cameraOffset - posn) + stepsPerRev);

ከሆነ (ይጠብቁ)

(ከላይ. IsMoving) ክር። እንቅልፍ (50); }

የግል ባዶ ቀጥሎ ሆል (ቡሊያን መጠበቅ = ሐሰት) {

ድርብ posn = top. አቀማመጥ % stepsPerRev; ከሆነ (posn <Properties. Settings. Default.holeOffset) top. TargetPosition += (Properties. Settings. Default.holeOffset - posn); ሌላ top. TargetPosition + = ((Properties. Settings. Default.holeOffset - posn) + stepsPerRev);

ከሆነ (ይጠብቁ)

(ከላይ. IsMoving) ክር። እንቅልፍ (50); }

ሩጫ ከመጀመርዎ በፊት የላይኛው ንጣፍ መግነጢሳዊ ዳሳሹን በመጠቀም ይስተካከላል። የላይ ሰሌዳውን ለማስተካከል የ alignMotor ተግባር በማንኛውም ጊዜ ሊጠራ ይችላል። የመግነጢሳዊ መረጃን ከመነሻው በላይ እስኪያይ ድረስ ይህ ተግባር በመጀመሪያ ሳህኑን በፍጥነት ወደ 1 ሙሉ አብዮት ይለውጣል። ከዚያ ትንሽ ወደኋላ በመመለስ እንደገና ወደ ፊት ወደፊት ይራመዳል ፣ ሲሄድ የዳሳሽ ውሂብን ይይዛል። በመጨረሻም ፣ ቦታውን ወደ ከፍተኛው የማግኔት የውሂብ ሥፍራ ያዘጋጃል ፣ እና የቦታ ማካካሻውን ወደ 0. ዳግም ያስጀምራል ፣ ስለዚህ ፣ ከፍተኛው የማግኔት አቀማመጥ ሁል ጊዜ መሆን አለበት (ከላይ። ቦታ % ደረጃዎችPerRev)

ክር alignMotorThread; ቡሊያን መጋዝ ማግኔት; ድርብ magSensorMax = 0; የግል ባዶነት alignMotor () {

// ማግኔትን ያግኙ

top. DataInterval = top. MinDataInterval;

sawMagnet = ሐሰት;

magSensor. SensorChange += magSensorStopMotor; top. VelocityLimit = -1000;

int tryCount = 0;

እንደገና ሞክር:

top. TargetPosition += stepsPerRev;

ሳለ (ከላይ ።IsMoving &&! sawMagnet) Thread. Sleep (25);

ከሆነ (! sawMagnet) {

ከሆነ (tryCount> 3) {Console. WriteLine («አሰላለፍ አልተሳካም»); top. Engaged = ሐሰት; bottom. Engaged = ሐሰት; runtest = ሐሰት; መመለስ; }

tryCount ++;

Console. WriteLine ("ተጣብቀናል? ምትኬን በመሞከር ላይ…"); top. TargetPosition -= 600; (ከላይ. IsMoving) ክር። እንቅልፍ (100);

goto tryagain;

}

top. VelocityLimit = -100;

magData = አዲስ ዝርዝር> (); magSensor. SensorChange += magSensorCollectPositionData; top. TargetPosition += 300; (ከላይ. IsMoving) ክር። እንቅልፍ (100);

magSensor. SensorChange -= magSensorCollectPositionData;

top. VelocityLimit = -topVelocityLimit;

KeyValuePair max = magData [0];

foreach (KeyValuePair ጥንድ በ magData ውስጥ) ከሆነ (pair. Value> max. Value) max = pair;

top. AddPositionOffset (-max. Key);

magSensorMax = max. Value;

top. TargetPosition = 0;

(ከላይ. IsMoving) ክር። እንቅልፍ (100);

Console. WriteLine ("አሰልፍ ተሳካ");

}

ዝርዝር> magData;

የግል ባዶ ባዶ magSensorCollectPositionData (የነገር ላኪ ፣ Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {magData. Add (አዲስ KeyValuePair (ከላይ። ቦታ ፣ e. SensorValue)); }

የግል ባዶ ባዶ magSensorStopMotor (የነገር ላኪ ፣ Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {

ከሆነ (top. IsMoving && e. SensorValue> 5) {top. TargetPosition = top. Position - 300; magSensor. SensorChange -= magSensorStopMotor; sawMagnet = እውነት; }}

በመጨረሻ ፣ የታችኛው ሞተር ወደ አንድ የቢድ ኮንቴይነር አቀማመጥ በመላክ ቁጥጥር ይደረግበታል። ለዚህ ፕሮጀክት 19 የሥራ ቦታዎች አሉን። አልጎሪዝም አጭሩ መንገድን እየመረጠ ነው ፣ እና በሰዓት አቅጣጫ ወይም በተቃራኒ ሰዓት አቅጣጫ ይቀይራል።

የግል int BottomPosition {get {int posn = (int) bottom. አቀማመጥ % stepsPerRev; ከሆነ (posn <0) posn += stepsPerRev;

መመለስ (int) ሂሳብ። ዙር (((posn * beadCompartments) / (double) stepsPerRev));

} }

የግል ባዶ SetBottomPosition (int posn ፣ bool wait = false) {

posn = posn % beadCompartments; ድርብ targetPosn = (posn * stepsPerRev) / beadCompartments;

ድርብ currentPosn = bottom. አቀማመጥ % ደረጃዎችPerRev;

ድርብ posnDiff = targetPosn - currentPosn;

// እንደ ሙሉ ደረጃዎች ያቆዩት

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

ከሆነ (posnDiff <= 1600) ታች ።TargetPosition += posnDiff; ሌላ ታች ።TargetPosition - = (stepsPerRev - posnDiff);

ከሆነ (ይጠብቁ)

ሳለ (ታች ።IsMoving) ክር። እንቅልፍ (50); }

ካሜራ

OpenCV ከድር ካሜራ ምስሎችን ለማንበብ ያገለግላል። ዋናው የመደርደር ክር ከመጀመሩ በፊት የካሜራ ክር ይጀምራል። ይህ ክር በምስሎች ውስጥ ያለማቋረጥ ያነባል ፣ አማካይን በመጠቀም ለአንድ የተወሰነ ክልል አማካይ ቀለም ያሰላል እና ዓለም አቀፍ የቀለም ተለዋዋጭን ያዘምናል። ክርው ቀለምን ለመለየት የሚመለከተውን ቦታ ለማጣራት ወይም ዶቃን ፣ ወይም የላይኛው ሳህን ውስጥ ያለውን ቀዳዳ ለመለየት ለመሞከር HoughCircles ን ይጠቀማል። ደፍ እና የ HoughCircles ቁጥሮች በሙከራ እና በስህተት ተወስነዋል ፣ እና በድር ካሜራ ፣ መብራት እና ክፍተት ላይ በእጅጉ ጥገኛ ናቸው።

bool runVideo = true; bool videoRunning = false; የቪዲዮ ቀረጻ መያዝ; ክር cvThread; ቀለም ተገኝቷል ቀለም; ቡሊያን መመርመር = ሐሰት; int deteCnt = 0;

የግል ባዶ cvThreadFunction () {

videoRunning = ሐሰት;

ቀረጻ = አዲስ VideoCapture (የተመረጠ ካሜራ);

በመጠቀም (የመስኮት መስኮት = አዲስ መስኮት (“መያዝ”)) {

የማት ምስል = አዲስ ማት (); ማት ምስል 2 = አዲስ ማት (); ሳለ (runVideo) {ቀረጻ። ያንብቡ (ምስል); (ምስል. ባዶ ()) ከተሰበረ;

ከሆነ (መለየት)

detectCnt ++; ሌላ detectCnt = 0;

ከሆነ (በመለየት || circleDetectChecked || showDetectionImgChecked) {

Cv2. CvtColor (ምስል ፣ ምስል 2 ፣ ColorConversionCodes. BGR2GRAY); Mat thres = image2. Threshold ((ድርብ) Properties. Settings. Default.videoThresh, 255, ThresholdTypes. Binary); thres = thres. GaussianBlur (አዲስ OpenCvSharp. Size (9, 9) ፣ 10);

ከሆነ (አሳይDetectionImgChecked)

ምስል = ትሬስ;

ከሆነ (በመለየት || circleDetectChecked) {

CircleSegment bead = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 20, 200, 100, 20, 65); ከሆነ (bead. Length> = 1) {image. Circle (bead [0]. Center, 3, new Scalar (0, 100, 0), -1); ምስል ክበብ (ዶቃ [0]. Center, (int) ዶቃ [0]. ከሆነ (ዶቃ [0]. Radius> = 55) {Properties. Settings. Default.x = (አስርዮሽ) ዶቃ [0]. Center. X + (አስርዮሽ) (ዶቃ [0]. Radius / 2); Properties. Settings. Default.y = (አስርዮሽ) ዶቃ [0]. Center. Y - (አስርዮሽ) (ዶቃ [0]. Radius / 2); } ሌላ {Properties. Settings. Default.x = (አስርዮሽ) ዶቃ [0]. Center. X + (አስርዮሽ) (ዶቃ [0]. Radius); Properties. Settings. Default.y = (አስርዮሽ) ዶቃ [0]. Center. Y - (አስርዮሽ) (ዶቃ [0]. Radius); } Properties. Settings. Default.size = 15; Properties. Settings. Default.height = 15; } ሌላ {

CircleSegment ክበቦች = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 5, 200, 100, 60, 180);

ከሆነ (ክበቦች። ርዝመት> 1) {ዝርዝር xs = ክበቦች። ይምረጡ (c => c. Center. X). ToList (); xs ደርድር (); Ys = ክበቦችን ይዘርዝሩ። (c => c. Center. Y). ToList (); ys ደርድር ();

int medianX = (int) xs [xs. Count / 2];

int medianY = (int) ys [ys. Count / 2];

ከሆነ (medianX> ምስል። ስፋት - 15)

medianX = ምስል። ስፋት - 15; ከሆነ (ሚዲያን> ምስል። ከፍታ - 15) መካከለኛ = ምስል። ቁመት - 15;

ምስል ክበብ (ሚዲያን ኤክስ ፣ መካከለኛ ፣ 100 ፣ አዲስ ስካላር (0 ፣ 0 ፣ 150) ፣ 3);

ከሆነ (መለየት) {

Properties. Settings. Default.x = medianX - 7; Properties. Settings. Default.y = medianY - 7; Properties. Settings. Default.size = 15; Properties. Settings. Default.height = 15; }}}}}

Rect r = new Rect ((int) Properties. Settings. Default.x, (int) Properties. Settings. Default.y, (int) Properties. Settings. Default.size, (int) Properties. Settings. Default.height);

Mat beadSample = new Mat (ምስል ፣ r);

ስካላር avgColor = Cv2. Mean (beadSample); detectedColor = Color. FromArgb ((int) avgColor [2] ፣ (int) avgColor [1] ፣ (int) avgColor [0]);

ምስል አራት ማዕዘን (አር ፣ አዲስ ስካላር (0 ፣ 150 ፣ 0));

መስኮት ማሳያ ምስል (ምስል);

Cv2. WaitKey (1); videoRunning = እውነት; }

videoRunning = ሐሰት;

} }

የግል ባዶ ካሜራStartBtn_Click (የነገር ላኪ ፣ EventArgs e) {

ከሆነ (cameraStartBtn. Text == "ጀምር") {

cvThread = አዲስ ክር (አዲስ ThreadStart (cvThreadFunction)); runVideo = እውነት; cvThread. Start (); cameraStartBtn. Text = "አቁም"; (! videoRunning) ክር። እንቅልፍ (100);

updateColorTimer. Start ();

} ሌላ {

runVideo = ሐሰት; cvThread. Join (); cameraStartBtn. Text = "ጀምር"; }}

ቀለም

አሁን ፣ የአንድን ዶቃ ቀለም መወሰን እንችላለን ፣ እና በየትኛው መያዣ ውስጥ እንደሚጣል በዚያ ቀለም ላይ በመመርኮዝ መወሰን እንችላለን።

ይህ እርምጃ በቀለም ንፅፅር ላይ የተመሠረተ ነው። የሐሰት አወንታዊን ለመገደብ ቀለሞችን ለይቶ መናገር መቻል እንፈልጋለን ፣ ግን ደግሞ የሐሰት አሉታዊዎችን ለመገደብ በቂ ደፍ እንዲኖር መፍቀድ እንፈልጋለን። ቀለሞችን ማወዳደር በእውነቱ በሚያስደንቅ ሁኔታ የተወሳሰበ ነው ፣ ምክንያቱም ኮምፒተሮች ቀለሞችን እንደ አርጂቢ (RGB) የሚያከማቹበት መንገድ ፣ እና ሰዎች ቀለሞችን የሚገነዘቡበት መንገድ ከመስመር ጋር አይዛመዱም። ይባስ ብሎ አንድ ቀለም እየታየ ያለው የብርሃን ቀለም እንዲሁ ከግምት ውስጥ መግባት አለበት።

የቀለም ልዩነት ለማስላት የተወሳሰበ ስልተ -ቀመር አለ። 2 ቀለሞች ለሰው የማይለዩ ቢሆኑ ከ 1 አጠገብ ያለውን ቁጥር የሚያወጣውን CIE2000 እንጠቀማለን። እነዚህን የተወሳሰቡ ስሌቶች ለማድረግ የ ColorMine C# ቤተ -መጽሐፍትን እየተጠቀምን ነው። በሐሰተኛ አዎንታዊ እና በሐሰት አሉታዊ መካከል ጥሩ ስምምነት የሚያቀርብ የ 5 ዴልታ እሴት ተገኝቷል።

ብዙ ተጨማሪ ቀለሞች ከዚያ ኮንቴይነሮች እንደመሆናቸው ፣ የመጨረሻው ቦታ እንደ ካታክ ማጠራቀሚያ ተይ isል። እኔ በአጠቃላይ ማሽኑን በሁለተኛው ማለፊያ ላይ ለማሄድ እነዚህን ወደ ጎን አስቀምጫለሁ።

ዝርዝር

ቀለሞች = አዲስ ዝርዝር () ፤ ዝርዝር colorPanels = አዲስ ዝርዝር (); የቀለም ዘሮችTxts = አዲስ ዝርዝር (); ዝርዝር colorCnts = አዲስ ዝርዝር ();

const int numColorSpots = 18;

const int ያልታወቀColorIndex = 18; int findColorPosition (ቀለም ሐ) {

Console. WriteLine ("ቀለም ማግኘት …");

var cRGB = አዲስ Rgb ();

cRGB. R = c. R; cRGB. G = c. G; cRGB. B = c. B;

int bestMatch = -1;

ድርብ ግጥሚያ ዴልታ = 100;

ለ (int i = 0; i <colors. Count; i ++) {

var RGB = አዲስ Rgb ();

RGB. R = ቀለሞች . R; RGB. G = ቀለሞች . G; RGB. B = ቀለሞች . B;

ድርብ ዴልታ = cRGB. Compare (RGB ፣ አዲስ CieDe2000Comparison ());

// ድርብ ዴልታ = ዴልታኢ (ሐ ፣ ቀለሞች ); Console. WriteLine ("DeltaE (" + i. ToString () + ")):" + delta. ToString ()); ከሆነ (ዴልታ <matchDelta) {matchDelta = delta; bestMatch = እኔ; }}

ከሆነ (matchDelta <5) {Console. WriteLine ("ተገኝቷል (Posn:" + bestMatch + "Delta:" + matchDelta + ")"); ተመለስ bestMatch; }

ከሆነ (ቀለሞች. ቁጥር <numColorSpots) {Console. WriteLine ("አዲስ ቀለም!"); ቀለሞች አክል (ሐ); this. BeginInvoke (አዲስ እርምጃ (setBackColor) ፣ አዲስ ነገር {colors. Count - 1}); WriteOutColors (); መመለስ (ቀለሞች ቁጥር - 1); } ሌላ {Console. WriteLine («ያልታወቀ ቀለም!»); መመለስ ያልታወቀColorIndex; }}

ሎጂክ መደርደር

የመደርደር ተግባሩ በእውነቱ ዶቃዎችን ለመደርደር ሁሉንም ቁርጥራጮች ያሰባስባል። ይህ ተግባር በተወሰነው ክር ውስጥ ይሠራል። የላይኛውን ሳህን ማንቀሳቀስ ፣ የዶላውን ቀለም መለየት ፣ በመያዣ ውስጥ ማስቀመጥ ፣ የላይኛው ሳህን ተስተካክሎ እንዲቆይ ማድረግ ፣ ዶቃዎችን መቁጠር ፣ ወዘተ.ካታቹል ቢን ሲሞላ መሮጥንም ያቆማል - ያለበለዚያ እኛ የተትረፈረፈ ዶቃዎች እንጨርሳለን።

የክር ቀለም ቀለም ሙከራ ሙከራ; ቡሊያን runtest = ሐሰት; ባዶ ቀለም ሙከራ () {

ከሆነ (! ከላይ። ገቢር)

top. Engaged = እውነት;

ከሆነ (! ታች። ገቢ የተደረገ)

bottom. Engaged = እውነት;

ሳለ (በጣም ሩጫ) {

ቀጣይ ማግኔት (እውነት);

ክር እንቅልፍ (100); ይሞክሩ {ከሆነ (magSensor. SensorValue <(magSensorMax - 4)) alignMotor (); } ይያዙ {alignMotor (); }

ቀጣዩ ካሜራ (እውነት);

መለየት = እውነት;

ሳለ (detectCnt <5) ክር። እንቅልፍ (25); Console. WriteLine ("የቁጥር ፈልግ" + deteCnt); መለየት = ሐሰት;

ቀለም ሐ = ተገኝቷል ቀለም;

ይህ. BeginInvoke (አዲስ እርምጃ (setColorDet) ፣ አዲስ ነገር {c}); int i = findColorPosition (ሐ);

SetBottomPosition (i ፣ እውነት);

nextHole (እውነት); colorCnts ++; ይህ. BeginInvoke (አዲስ እርምጃ (setColorTxt) ፣ አዲስ ነገር {i}); ክር እንቅልፍ (250);

ከሆነ (colorCnts [unknownColorIndex]> 500) {

top. Engaged = ሐሰት; bottom. Engaged = ሐሰት; runtest = ሐሰት; ይህ. BeginInvoke (አዲስ እርምጃ (setGoGreen) ፣ ባዶ); መመለስ; }}}

የግል ባዶነት ሙከራ TestBtn_Click (የነገር ላኪ ፣ EventArgs e) {

ከሆነ (colourTestThread == null ||! colourTestThread. IsAlive) {colourTestThread = አዲስ ክር (አዲስ ThreadStart (colourTest)); runtest = እውነት; colourTestThread. Sartart (); colourTestBtn. Text = "አቁም"; colourTestBtn. BackColor = Color. Red; } ሌላ {runtest = ሐሰት; colourTestBtn. Text = "ሂድ"; colourTestBtn. BackColor = Color. Green; }}

በዚህ ጊዜ የሥራ መርሃ ግብር አለን። አንዳንድ የኮድ ቁርጥራጮች ከጽሑፉ ውጭ ቀርተዋል ፣ ስለዚህ እሱን በትክክል ለማካሄድ ምንጩን ይመልከቱ።

የኦፕቲክስ ውድድር
የኦፕቲክስ ውድድር

በኦፕቲክስ ውድድር ሁለተኛ ሽልማት

የሚመከር: