Агуулгын хүснэгт:

Робот ирмэгийг эрэмбэлэх: 3 алхам (зурагтай)
Робот ирмэгийг эрэмбэлэх: 3 алхам (зурагтай)

Видео: Робот ирмэгийг эрэмбэлэх: 3 алхам (зурагтай)

Видео: Робот ирмэгийг эрэмбэлэх: 3 алхам (зурагтай)
Видео: МАЯТНИК ПОДАЧА ЧЕМПИОНОВ!КАК ОБУЧИТЬСЯ ПОДАЧЕ В НАСТОЛЬНОМ ТЕННИСЕ?#serve #подача #настольныйтеннис 2024, Арваннэгдүгээр
Anonim
Image
Image
Робот ирмэгийг ангилах
Робот ирмэгийг ангилах
Робот ирмэгийг ангилах
Робот ирмэгийг ангилах
Робот ирмэгийг ангилах
Робот ирмэгийг ангилах

Энэхүү төсөлд бид Перлерийн бөмбөлгүүдийг өнгөөр нь ялгах робот бүтээх болно.

Би өнгө ялгах робот бүтээхийг үргэлж хүсдэг байсан болохоор охин маань Перлерийн ирмэгийн урлалыг сонирхож эхлэхэд үүнийг төгс боломж гэж харсан.

Перлер бөмбөлгүүдийг нь олон тооны бөмбөлгүүдийг бэхэлгээний тавцан дээр байрлуулж, төмрөөр хайлуулж хайлуулах урлагийн төслүүдийг бий болгоход ашигладаг. Та эдгээр бөмбөлгүүдийг ерөнхийдөө 22000 ширхэг бөмбөлгүүдийг хольсон өнгөт багцаар худалдаж авдаг бөгөөд хүссэн өнгөө хайж олоход маш их цаг зарцуулдаг тул тэдгээрийг эрэмбэлэх нь урлагийн үр ашгийг дээшлүүлэх болно гэж бодлоо.

Би Phidgets Inc -д ажилладаг тул энэ төсөлд ихэвчлэн Phidgets ашигладаг байсан боловч үүнийг ямар ч тохиромжтой тоног төхөөрөмж ашиглан хийж болно.

Алхам 1: Техник хангамж

Үүнийг миний барьж байсан зүйл энд байна. Би үүнийг 100% phidgets.com -ийн хэсгүүд болон байшингийн эргэн тойронд хэвтэж байсан зүйлсээр бүтээсэн.

Phidgets самбар, мотор, техник хангамж

  • HUB0000 - VINT Hub Phidget
  • 1108 - Соронзон мэдрэгч
  • 2x STC1001 - 2.5A Stepper Phidget
  • 2x 3324 - 42STH38 NEMA -17 хоёр туйлт араагүй алхам
  • 3x 3002 - Phidget кабель 60см
  • 3403 - USB2.0 4 порт порт
  • 3031 - Эмэгтэй гахайн сүүл 5.5х2.1 мм
  • 3029 - 2 утас 100 'Эрчилсэн кабель
  • 3604 - 10мм цагаан LED (10 уут)
  • 3402 - USB вэб камер

Бусад хэсгүүд

  • 24VDC 2.0A цахилгаан хангамж
  • Гаражаас мод, төмөр хог хаягдал
  • Зип зангиа
  • Доод талыг нь хуваасан хуванцар сав

Алхам 2: Роботыг зохион бүтээх

Роботыг зохион бүтээх
Роботыг зохион бүтээх
Роботыг зохион бүтээх
Роботыг зохион бүтээх
Роботыг зохион бүтээх
Роботыг зохион бүтээх

Бид оролтын бункерээс ганц ирмэг авч болох зүйлийг зохион бүтээж, вэбкамерын доор байрлуулж, дараа нь зохих хогийн сав руу зөөх хэрэгтэй.

Бөмбөлөг авах

Би 1 -р хэсгийг 2 ширхэг дугуй фанераар хийхээр шийдсэн бөгөөд тус бүр нь нэг газар нүх гаргажээ. Доод хэсэг нь бэхлэгдсэн бөгөөд дээд хэсэг нь stepper моторт бэхлэгдсэн бөгөөд үүнийг бөмбөлгүүдийгээр дүүргэсэн бункер дор эргүүлэх боломжтой. Нүх нь бункерийн дор явж байхдаа ганц ирмэгийг авдаг. Дараа нь би үүнийг вэбкамерын доор эргүүлж, дараа нь доод хэсгийн нүхтэй таарах хүртэл эргүүлж, тэр үед унах болно.

Энэ зураг дээр би систем ажиллах боломжтой эсэхийг шалгаж байна. Доод талын фанерын дээд хэсгээс бусад бүх зүйлийг зассан бөгөөд энэ нь доогуураа шаталсан мотор дээр бэхлэгдсэн байна. Вэбкамыг хараахан суулгаагүй байна. Би яг энэ үед хөдөлгүүрийг асаахын тулд Phidget Control Panel -ийг ашиглаж байна.

Бөмбөлгүүдийг хадгалах

Дараагийн хэсэг нь өнгө бүрийг хадгалах зориулалттай хогийн савны загварыг гаргах явдал юм. Тэгш зайтай тасалгаатай дугуй савыг дэмжих, эргүүлэхийн тулд доорх хоёр дахь шаталсан моторыг ашиглахаар шийдлээ. Энэ нь ирмэгийн унах нүхний доорх зөв тасалгааг эргүүлэхэд ашиглаж болно.

Би үүнийг картон, наалдамхай тууз ашиглан барьсан. Энд хамгийн чухал зүйл бол тууштай байдал юм - тасалгаа бүр ижил хэмжээтэй байх ёстой бөгөөд бүх зүйл жигд жигнэсэн байх ёстой бөгөөд ингэснээр алгасахгүйгээр эргэдэг.

Бөмбөлгүүдийг тайлах ажлыг нягт тагны тусламжтайгаар гүйцэтгэдэг бөгөөд энэ нь нэг тасалгааг ил гаргадаг тул бөмбөлгүүдийг асгаж болно.

Камер

Вэбкамер нь дээд хавтан дээр бункер болон доод хавтангийн нүхний хооронд байрладаг. Энэ нь системийг ирмэгийг хаяхаасаа өмнө харах боломжийг олгодог. LED нь камерын доор байрлах бөмбөлгүүдийг гэрэлтүүлэхэд ашигладаг бөгөөд гэрэлтүүлгийн тогтвортой орчинг бүрдүүлэхийн тулд орчны гэрлийг хаадаг. Энэ нь өнгийг үнэн зөв тодорхойлоход маш чухал юм, учир нь орчны гэрэлтүүлэг нь хүлээн зөвшөөрөгдсөн өнгийг хаяж чаддаг.

Байршлыг илрүүлэх

Систем нь ирмэгийн тусгаарлагчийн эргэлтийг илрүүлэх чадвартай байх нь чухал юм. Энэ нь асаах үед анхны байрлалыг тохируулахын зэрэгцээ stepper мотор синхрончлогдсон эсэхийг илрүүлэхэд ашиглагддаг. Миний системд бөмбөлгүүдийг авах үед гацах тохиолдол гардаг бөгөөд систем нь энэ байдлыг бага зэрэг нөөцөлж, оролдож байж илрүүлж, зохицуулж чаддаг байх шаардлагатай байв.

Үүнийг зохицуулах олон арга бий. Би 1108 соронзон мэдрэгчийг ашиглахаар шийдсэн бөгөөд соронзыг дээд хавтангийн ирмэг дээр суулгасан байв. Энэ нь эргэлт бүрийн байрлалыг шалгах боломжийг надад олгодог. Илүү сайн шийдэл бол stepper мотор дээр кодлогч байх болно, гэхдээ би 1108 -тэй байсан тул үүнийг ашигласан.

Роботыг дуусгах

Энэ үед бүх зүйлийг боловсруулж, туршиж үзсэн болно. Бүгдийг сайхан холбож, бичих програм хангамж руу шилжих цаг болжээ.

2 шатлалт моторыг STC1001 алхам хянагч удирддаг. HUB000 - USB VINT зангилаа нь stepper хянагчийг ажиллуулах, соронзон мэдрэгчийг унших, LED жолоодоход ашиглагддаг. Вэбкам болон HUB0000 хоёулаа жижиг USB төвд холбогдсон байна. Хөдөлгүүрийг тэжээхийн тулд 3031 гахайн сүүл ба зарим утсыг 24В тэжээлийн хангамжийн хамт ашигладаг.

Алхам 3: Код бичих

Image
Image

Энэ төсөлд C# болон Visual Studio 2015 програмуудыг ашигладаг. Энэ хуудасны дээд хэсэгт байгаа эх сурвалжийг татаж аваад дагаж мөрдөөрэй - үндсэн хэсгүүдийг доор харуулав

Эхлүүлэх

Нэгдүгээрт, бид Phidget объектуудыг үүсгэх, нээх, эхлүүлэх ёстой. Энэ нь маягтыг ачаалах тохиолдолд хийгддэг бөгөөд Phidget -ийг боловсруулагчдыг хавсаргадаг.

хувийн хоосон Form1_Load (объект илгээгч, EventArgs e) {

/ * Phidgets -ийг эхлүүлэх, нээх */

top. HubPort = 0; top. Attach += Top_Attach; top. Detach += Top_Detach; top. PositionChange += Top_PositionChange; дээд Нээлттэй ();

доод. HubPort = 1;

доод. Attach += Bottom_Attach; доод. Detach += Bottom_Detach; доод. PositionChange += Bottom_PositionChange; доод Нээлттэй ();

magSensor. HubPort = 2;

magSensor. IsHubPortDevice = үнэн; magSensor. Attach += MagSensor_Attach; magSensor. Detach += MagSensor_Detach; magSensor. SensorChange += MagSensor_SensorChange; magSensor. Open ();

HubPort = 5;

led. IsHubPortDevice = үнэн; суваг = 0; led. Attach += Led_Attach; led. Detach += Led_Detach; удирдсан Нээлттэй (); }

хувийн хоосон орон зай 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. VelocityLimit = bottomVelocityLimit; доод Хурдасгах = доодАссель; доод. DataInterval = 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; }

Бид мөн эхлүүлэх явцад хадгалсан өнгөт мэдээллийг уншдаг тул өмнөх гүйлгээг үргэлжлүүлж болно.

Мотор байршил

Мотортой ажиллах код нь моторыг хөдөлгөхөд тохиромжтой функцуудаас бүрдэнэ. Миний ашигласан моторууд нь нэг хувьсгалд 1, 16 -р алхам болох 3, 200 байдаг тул би үүнийг тогтмол болгодог.

Дээд хөдөлгүүрийн хувьд бид мотор руу илгээхийг хүсч буй 3 байрлал байдаг: вэбкамер, нүх, байрлуулах соронз. Эдгээр албан тушаал бүрт очих функц байдаг:

private void nextMagnet (Boolean wait = false) {

double posn = top. Position % stepsPerRev;

top. TargetPosition += (stepsPerRev - posn);

хэрэв (хүлээх)

while (top. IsMoving) Thread. Sleep (50); }

private void nextCamera (Boolean wait = false) {

double posn = top. Position % stepsPerRev; if (posn <Properties. Settings. Default.cameraOffset) top. TargetPosition += (Properties. Settings. Default.cameraOffset - posn); else top. TargetPosition + = ((Properties. Settings. Default.cameraOffset - posn) + stepsPerRev);

хэрэв (хүлээх)

while (top. IsMoving) Thread. Sleep (50); }

private void nextHole (Boolean wait = false) {

double posn = top. Position % stepsPerRev; if (posn <Properties. Settings. Default.holeOffset) top. TargetPosition += (Properties. Settings. Default.holeOffset - posn); else top. TargetPosition + = ((Properties. Settings. Default.holeOffset - posn) + stepsPerRev);

хэрэв (хүлээх)

while (top. IsMoving) Thread. Sleep (50); }

Гүйлт эхлэхийн өмнө соронзон мэдрэгч ашиглан дээд хавтанг тэгшлэв. AlignMotor функцийг хүссэн үедээ дуудаж дээд хавтанг тэгшлэх боломжтой. Энэ функц нь эхлээд соронзон өгөгдлийг босгоноос дээш харах хүртэл хавтанг 1 бүтэн эргэлт хүртэл хурдан эргүүлнэ. Дараа нь энэ нь бага зэрэг ухарч, аажмаар аажмаар урагшилж, мэдрэгчийн өгөгдлийг хадгалж байдаг. Эцэст нь, энэ нь соронзон өгөгдлийн хамгийн дээд байрлалд байрлалыг тохируулж, офсетыг 0 болгож дахин тохируулна. Тиймээс соронзны хамгийн их байрлал үргэлж дээд талд байх ёстой.

Thread alignMotorThread; Boolean sawMagnet; давхар magSensorMax = 0; private void alignMotor () {

// Соронзыг олоорой

top. DataInterval = top. MinDataInterval;

sawMagnet = худал;

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

int tryCount = 0;

дахин оролд:

top. TargetPosition += stepsPerRev;

while (top. IsMoving &&! sawMagnet) Thread. Sleep (25);

хэрэв (! sawMagnet) {

if (tryCount> 3) {Console. WriteLine ("Align амжилтгүй болсон"); Top. Engaged = худал; ёроол. Оруулсан = худал; runtest = худал; буцах; }

tryCount ++;

Console. WriteLine ("Бид гацсан уу? Нөөцлөхийг оролдож байна …"); top. TargetPosition -= 600; while (top. IsMoving) Thread. Sleep (100);

дахин оролдох хэрэгтэй;

}

top. VelocityLimit = -100;

magData = шинэ жагсаалт> (); magSensor. SensorChange += magSensorCollectPositionData; top. TargetPosition += 300; while (top. IsMoving) Thread. Sleep (100);

magSensor. SensorChange -= magSensorCollectPositionData;

top. VelocityLimit = -topVelocityLimit;

KeyValuePair max = magData [0];

foreach (MagData дахь KeyValuePair хос) if (pair. Value> max. Value) max = pair;

top. AddPositionOffset (-max Key);

magSensorMax = хамгийн их утга;

top. TargetPosition = 0;

while (top. IsMoving) Thread. Sleep (100);

Console. WriteLine ("Align амжилттай боллоо");

}

Жагсаалт> magData;

private void magSensorCollectPositionData (объект илгээгч, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {magData. Add (шинэ KeyValuePair (top. Position, e. SensorValue))); }

хувийн хоосон magSensorStopMotor (объект илгээгч, Phidget22. Үйл явдал. Хүчдэлийн харьцааInputSensorChangeEventArgs e) {

if (top. IsMoving &&. SensorValue> 5) {top. TargetPosition = top. Position - 300; magSensor. SensorChange -= magSensorStopMotor; sawMagnet = үнэн; }}

Эцэст нь доод хөдөлгүүрийг ирмэгийн савны аль нэг байрлал руу илгээх замаар хянадаг. Энэ төслийн хувьд бид 19 албан тушаалтай. Алгоритм нь хамгийн богино замыг сонгож, цагийн зүүний дагуу эсвэл цагийн зүүний эсрэг эргүүлнэ.

private int BottomPosition {get {int posn = (int) bottom. Position % stepsPerRev; хэрэв (posn <0) posn += stepsPerRev;

буцах (int) Math. Round ((((posn * beadCompartments) / (давхар) алхамPerRev));

} }

хувийн хоосон SetBottomPosition (int posn, bool wait = false) {

posn = posn % beadCompartments; давхар targetPosn = (posn * stepsPerRev) / beadCompartments;

давхар currentPosn = доод. Байрлал % stepsPerRev;

давхар posnDiff = targetPosn - currentPosn;

// Үүнийг бүрэн алхам болгон хадгална уу

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

if (posnDiff <= 1600) доод. TargetPosition += posnDiff; else доод. TargetPosition - = (stepsPerRev - posnDiff);

хэрэв (хүлээх)

while (bottom. IsMoving) Thread. Sleep (50); }

Камер

OpenCV нь вэбкамераас зураг уншихад ашиглагддаг. Камерын утас нь үндсэн ялгах утас эхлэхээс өмнө эхэлдэг. Энэ утас нь зургуудыг тасралтгүй уншиж, дундаж ашиглан тодорхой бүс нутгийн дундаж өнгийг тооцоолж, дэлхийн өнгөний хувьсагчийг шинэчилдэг. Энэ утас нь өнгөний илрүүлэлтийг хайж буй хэсгийг нарийвчлахын тулд ирмэг эсвэл дээд хавтангийн нүхийг илрүүлэхийн тулд HoughCircles -ийг ашигладаг. Босго ба HoughCircles -ийн тоог туршилт, алдааны дагуу тодорхойлсон бөгөөд энэ нь вэбкамер, гэрэлтүүлэг, зайнаас ихээхэн хамаардаг.

bool runVideo = үнэн; bool videoRunning = худал; Видео бичлэг хийх; Урсгал cvThread; Өнгийг илрүүлсэн Өнгө; Boolean илрүүлэх = худал; int илрүүлэхCnt = 0;

хувийн хоосон cvThreadFunction () {

videoRunning = худал;

барих = шинэ VideoCapture (selectedCamera);

ашиглан (Цонхны цонх = шинэ цонх ("барих")) {

Mat зураг = шинэ Mat (); Mat image2 = шинэ Mat (); while (runVideo) {capture. Read (зураг); if (image. Empty ()) эвдэх;

хэрэв (илрүүлэх)

илрүүлэхCnt ++; өөр илрүүлэхCnt = 0;

if (илрүүлэх || тойрогDetectChecked || showDetectionImgChecked) {

Cv2. CvtColor (зураг, зураг2, ColorConversionCodes. BGR2GRAY); Mat thres = image2. Threshold ((double) Properties. Settings. Default.videoThresh, 255, ThresholdTypes. Binary); thres = thres. GaussianBlur (шинэ OpenCvSharp. Size (9, 9), 10);

хэрэв (showDetectionImgChecked)

зураг = босго;

if (илрүүлэх || тойрогDetectChecked) {

CircleSegment bead = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 20, 200, 100, 20, 65); if (bead. Length> = 1) {image. Circle (bead [0]. Center, 3, new Scalar (0, 100, 0), -1); дүрс. Circle (bead [0]. Center, (int) bead [0]. Radius, new Scalar (0, 0, 255), 3); if (bead [0]. Radius> = 55) {Properties. Settings. Default.x = (аравтын) ирмэг [0]. Center. X + (аравтын) (bead [0]. Radius / 2); Properties. Settings. Default.y = (аравтын) ирмэг [0]. Center. Y - (аравтын) (bead [0]. Radius / 2); } өөр {Properties. Settings. Default.x = (аравтын) ирмэг [0]. Center. X + (аравтын бутархай) (ирмэг [0]. Радиус); Properties. Settings. Default.y = (аравтын) ирмэг [0]. Center. Y - (аравтын) (bead [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);

if (тойрог. Урт> 1) {Жагсаалт xs = тойрог. (c => c. Төв. X) -ийг сонгоно уу. xs. Sort (); Ys = тойрог жагсаана уу (c => c. Center. Y). ToList (); ys. Sort ();

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

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

if (medianX> image. Өргөн - 15)

medianX = зураг Өргөн - 15; if (medianY> image. Hightight - 15) medYAN = image. Height - 15;

дүрс. Дугуйл (medianX, medYANY, 100, шинэ Scalar (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 = шинэ Rect ((int) Properties. Settings. Default.x, (int) Properties. Settings. Default.y, (int) Properties. Settings. Default.size, (int) Properties. Settings. Default.height);

Mat beadSample = шинэ дэвсгэр (зураг, r);

Scalar avgColor = Cv2. Mean (beadSample); aşkarColor = Өнгө. FromArgb ((int) avgColor [2], (int) avgColor [1], (int) avgColor [0]);

Тэгш өнцөгт (r, шинэ Scalar (0, 150, 0));

цонх. ShowImage (зураг);

Cv2. WaitKey (1); videoRunning = үнэн; }

videoRunning = худал;

} }

хувийн хоосон камерStartBtn_Click (объект илгээгч, EventArgs e) {

хэрэв (cameraStartBtn. Text == "эхлэх") {

cvThread = шинэ Thread (шинэ ThreadStart (cvThreadFunction)); runVideo = үнэн; cvThread. Start (); cameraStartBtn. Text = "зогсоох"; while (! videoRunning) Thread. Sleep (100);

updateColorTimer. Start ();

} өөр {

runVideo = худал; cvThread. Join (); cameraStartBtn. Text = "эхлэх"; }}

Өнгө

Одоо бид ирмэгийн өнгийг тодорхойлж, аль саванд хийхээ шийдэх боломжтой болсон.

Энэ алхам нь өнгөний харьцуулалт дээр тулгуурладаг. Бид хуурамч эерэгийг хязгаарлахын тулд өнгийг ялгаж салгахыг хүсч байгаа боловч хуурамч сөрөг байдлыг хязгаарлахад хангалттай босгыг зөвшөөрөхийг хүсч байна. Өнгийг харьцуулах нь үнэхээр гайхалтай төвөгтэй, учир нь компьютер өнгийг RGB хэлбэрээр хадгалдаг бөгөөд хүмүүсийн өнгийг хэрхэн хүлээн авах нь шугаман хамааралгүй байдаг. Нөхцөл байдлыг улам дордуулахын тулд доороос харж буй гэрлийн өнгийг бас анхаарч үзэх хэрэгтэй.

Өнгөний ялгааг тооцоолох нарийн төвөгтэй алгоритм байдаг. Бид CIE2000 -ийг ашигладаг бөгөөд хэрэв 2 өнгө нь хүний хувьд ялгаагүй бол 1 -ийн ойролцоо тоо гаргадаг. Бид эдгээр төвөгтэй тооцооллыг хийхийн тулд ColorMine C# номын санг ашиглаж байна. DeltaE -ийн 5 утга нь хуурамч эерэг ба хуурамч сөрөг хоёрын хооронд сайн буулт хийх боломжтой болох нь тогтоогджээ.

Контейнерээс илүү олон өнгө байдаг тул хамгийн сүүлийн байрыг хогийн сав болгон хадгалдаг. Би ерөнхийдөө машиныг хоёр дахь дамжуулалтаар ажиллуулахаар хойшлуулсан.

Жагсаалт

өнгө = шинэ жагсаалт (); жагсаалтын өнгөPanels = шинэ жагсаалт (); Жагсаалтын өнгөTxts = шинэ жагсаалт (); ColorCnts жагсаалт = шинэ жагсаалт ();

const int numColorSpots = 18;

const int unknownColorIndex = 18; int findColorPosition (Өнгө в) {

Console. WriteLine ("Өнгийг хайж байна …");

var cRGB = шинэ Rgb ();

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

int bestMatch = -1;

давхар тоглолтDelta = 100;

for (int i = 0; i <color. Count; i ++) {

var RGB = шинэ Rgb ();

RGB. R = өнгө . R; RGB. G = өнгө . G; RGB. B = өнгө . B;

давхар дельта = cRGB. Харьцуулах (RGB, шинэ CieDe2000Comparison ());

// давхар дельта = deltaE (c, өнгө ); Console. WriteLine ("DeltaE (" + i. ToString () + "):" + delta. ToString ()); хэрэв (дельта <matchDelta) {matchDelta = дельта; bestMatch = i; }}

if (matchDelta <5) {Console. WriteLine ("Олдлоо! (Posn:" + bestMatch + "Delta:" + matchDelta + ")"); bestMatch -ийг буцаах; }

if (colors. Count <numColorSpots) {Console. WriteLine ("Шинэ өнгө!"); өнгө нэмэх (c); this. BeginInvoke (шинэ Action (setBackColor), шинэ объект {colors. Count - 1}); writeOutColors (); буцах (өнгө. Тооллого - 1); } өөр {Console. WriteLine ("Үл мэдэгдэх өнгө!"); unknownColorIndex буцаах; }}

Логикийг ангилах

Эрэмбэлэх функц нь бүх хэсгүүдийг нэгтгэн бөмбөлгүүдийг ангилдаг. Энэ функц нь зориулагдсан утас дээр ажилладаг; дээд хавтанг зөөх, ирмэгийн өнгийг илрүүлэх, хогийн саванд хийх, дээд хавтанг тэгш байрлуулах, бөмбөлгүүдийг тоолох гэх мэт. Мөн хогийн сав дүүрэх үед энэ нь ажиллахаа болино - Үгүй бол бид бөмбөлгүүдийг дүүрч дуусдаг.

Thread colourTestThread; Boolean runtest = false; хүчингүй colourTest () {

хэрэв (! дээд. Ууртай)

Top. Engaged = үнэн;

хэрэв (! доод. Ууртай)

ёроол. Оруулсан = үнэн;

while (runtest) {

nextMagnet (үнэн);

Унтах (100); оролдох {if (magSensor. SensorValue <(magSensorMax - 4)) alignMotor (); } барих {alignMotor (); }

nextCamera (үнэн);

илрүүлэх = үнэн;

while (detectCnt <5) Thread. Sleep (25); Console. WriteLine ("Detect Count:" + detectCnt); илрүүлэх = худал;

Өнгө c = илрүүлсэн өнгө;

this. BeginInvoke (шинэ үйлдэл (setColorDet), шинэ объект {c}); int i = findColorPosition (c);

SetBottomPosition (i, үнэн);

nextHole (үнэн); colorCnts ++; this. BeginInvoke (шинэ үйлдэл (setColorTxt), шинэ объект {i}); Унтах (250);

хэрэв (colorCnts [unknownColorIndex]> 500) {

Top. Engaged = худал; ёроол. Оруулсан = худал; runtest = худал; this. BeginInvoke (шинэ Action (setGoGreen), null); буцах; }}}

private void colourTestBtn_Click (объект илгээгч, EventArgs e) {

if (colourTestThread == null ||! colourTestThread. IsAlive) {colourTestThread = шинэ урсгал (шинэ ThreadStart (colourTest)); runtest = үнэн; colourTestThread. Start (); colourTestBtn. Text = "ЗОГСООХ"; colourTestBtn. BackColor = Color. Red; } өөр {runtest = худал; colourTestBtn. Text = "GO"; colourTestBtn. BackColor = Өнгө. Ногоон; }}

Энэ үед бидэнд ажлын хөтөлбөр байна. Зарим бит кодуудыг нийтлэлээс хассан тул үүнийг ажиллуулахын тулд эх сурвалжтай нь танилцаарай.

Оптикийн тэмцээн
Оптикийн тэмцээн

Оптикийн тэмцээний хоёрдугаар шагнал

Зөвлөмж болгож буй: