Turinys:

Robotų karoliukų rūšiavimas: 3 žingsniai (su nuotraukomis)
Robotų karoliukų rūšiavimas: 3 žingsniai (su nuotraukomis)

Video: Robotų karoliukų rūšiavimas: 3 žingsniai (su nuotraukomis)

Video: Robotų karoliukų rūšiavimas: 3 žingsniai (su nuotraukomis)
Video: Я работаю в Страшном музее для Богатых и Знаменитых. Страшные истории. Ужасы. 2024, Liepa
Anonim
Image
Image
Robotų karoliukų rūšiavimas
Robotų karoliukų rūšiavimas
Robotų karoliukų rūšiavimas
Robotų karoliukų rūšiavimas
Robotų karoliukų rūšiavimas
Robotų karoliukų rūšiavimas

Šiame projekte mes kursime robotą, kuris surūšiuotų „Perler“karoliukus pagal spalvą.

Aš visada norėjau sukurti spalvų rūšiavimo robotą, todėl kai mano dukra susidomėjo „Perler“karoliukų kūrimu, tai supratau kaip puikią galimybę.

„Perler“karoliukai naudojami lydytiems meno projektams kurti, dedant daug karoliukų ant lentos ir tada lydant juos lygintuvu. Paprastai perkate šiuos karoliukus milžiniškose 22 000 karoliukų mišrios spalvos pakuotėse ir praleidžiate daug laiko ieškodami norimos spalvos, todėl maniau, kad jų rūšiavimas padidins meno efektyvumą.

Aš dirbu „Phidgets Inc.“, todėl šiam projektui daugiausia naudojau „Phidgets“, tačiau tai buvo galima padaryti naudojant bet kokią tinkamą aparatūrą.

1 žingsnis: Aparatūra

Štai ką aš naudojau tai kurdamas. Aš jį sukūriau 100% su dalimis iš phidgets.com ir daiktų, kuriuos turėjau aplink namą.

„Phidgets“plokštės, varikliai, techninė įranga

  • HUB0000 - „VINT Hub“„Phidget“
  • 1108 - magnetinis jutiklis
  • 2x STC1001 - 2.5A Stepper Phidget
  • 2x 3324 - 42STH38 NEMA -17 bipolinis pavarų perjungiklis
  • 3x 3002 - „Phidget“kabelis 60 cm
  • 3403 - USB2.0 4 prievadų koncentratorius
  • 3031 - patelė moteriai 5,5x2,1 mm
  • 3029 - 2 laidų 100 colių susuktas kabelis
  • 3604 - 10 mm baltas LED (maišelis po 10)
  • 3402 - USB kamera

Kitos dalys

  • 24VDC 2.0A maitinimo šaltinis
  • Medžio ir metalo laužas iš garažo
  • Užsegami užtrauktukais
  • Plastikinis indas su nupjautu dugnu

2 žingsnis: suprojektuokite robotą

Suprojektuokite robotą
Suprojektuokite robotą
Suprojektuokite robotą
Suprojektuokite robotą
Suprojektuokite robotą
Suprojektuokite robotą

Turime suprojektuoti tai, kas iš įvesties bunkerio galėtų paimti vieną karoliuką, įdėti jį po kamera ir perkelti į atitinkamą šiukšliadėžę.

Karoliukų paėmimas

Aš nusprendžiau padaryti pirmąją dalį su 2 gabalėliais apvalios faneros, kiekvienoje - toje pačioje vietoje išgręžta skylė. Apatinė dalis yra fiksuota, o viršutinė dalis pritvirtinta prie žingsninio variklio, kuris gali jį pasukti po bunkeriu, užpildytu karoliukais. Kai skylė keliauja po bunkeriu, ji surenka vieną karoliuką. Tada galiu jį pasukti po internetine kamera, o paskui dar pasukti, kol jis sutaps su skylute apatinėje dalyje, ir tada ji iškris.

Šiame paveikslėlyje aš išbandau, ar sistema gali veikti. Viskas pritvirtinta, išskyrus viršutinį apvalų faneros gabalą, kuris apačioje yra pritvirtintas prie žingsninio variklio. Interneto kamera dar nebuvo sumontuota. Aš tik naudoju „Phidget“valdymo skydelį, kad šiuo metu pasukčiau į variklį.

Karoliukų laikymas

Kita dalis - suprojektuoti šiukšliadėžės sistemą kiekvienai spalvai laikyti. Aš nusprendžiau naudoti antrą žingsninį variklį apačioje, norėdamas palaikyti ir pasukti apvalų indą su tolygiai išdėstytais skyriais. Tai galima panaudoti norint pasukti tinkamą skyrių po anga, iš kurios karoliukas iškris.

Aš tai sukūriau naudodami kartoną ir lipnią juostą. Svarbiausia čia yra nuoseklumas - kiekvienas skyrius turi būti vienodo dydžio, o visas daiktas turi būti tolygiai pasvertas, kad jis suktųsi nepraleisdamas.

Karoliukas pašalinamas sandariai uždengtu dangteliu, kuris vienu metu atskleidžia vieną skyrių, todėl karoliukus galima išpilti.

Fotoaparatas

Interneto kamera yra sumontuota virš viršutinės plokštės tarp bunkerio ir apatinės plokštės skylės vietos. Tai leidžia sistemai pažvelgti į karoliuką prieš jį numetant. Šviesos diodas naudojamas apšviesti rutuliukus po fotoaparatu, o aplinkos šviesa užblokuojama, kad būtų užtikrinta pastovi apšvietimo aplinka. Tai labai svarbu tiksliam spalvų aptikimui, nes aplinkos apšvietimas tikrai gali išmesti suvoktas spalvas.

Vietos aptikimas

Svarbu, kad sistema galėtų aptikti granulių separatoriaus sukimąsi. Tai naudojama norint nustatyti pradinę padėtį paleidžiant, taip pat nustatyti, ar žingsninis variklis nesinchronizuotas. Mano sistemoje karoliukas kartais užstringa, kai jis yra paimamas, ir sistema turėjo sugebėti aptikti ir išspręsti šią situaciją - šiek tiek padarydama atsargines kopijas ir bandydama.

Yra daug būdų tai išspręsti. Aš nusprendžiau naudoti 1108 magnetinį jutiklį su magnetu, įterptu į viršutinės plokštės kraštą. Tai leidžia man patikrinti kiekvieno posūkio padėtį. Geresnis sprendimas tikriausiai būtų žingsninio variklio kodavimo įrenginys, bet aš gulėjau 1108, todėl aš jį naudojau.

Užbaikite robotą

Šiuo metu viskas buvo išsiaiškinta ir išbandyta. Atėjo laikas viską gražiai sumontuoti ir pereiti prie rašymo programinės įrangos.

2 žingsninius variklius varo STC1001 žingsniniai valdikliai. HUB000 - USB VINT koncentratorius naudojamas žingsniniams valdikliams paleisti, magnetiniam jutikliui skaityti ir šviesos diodui valdyti. Interneto kamera ir HUB0000 yra prijungti prie mažo USB šakotuvo. Varikliams maitinti naudojamas 3031 pataisa ir tam tikra viela kartu su 24 V maitinimo šaltiniu.

3 žingsnis: parašykite kodą

Image
Image

Šiam projektui naudojami „C#“ir „Visual Studio 2015“. Atsisiųskite šaltinį šio puslapio viršuje ir sekite toliau - pagrindiniai skyriai yra išdėstyti žemiau

Inicijavimas

Pirmiausia turime sukurti, atidaryti ir inicijuoti „Phidget“objektus. Tai atliekama formos įkėlimo atveju ir „Phidget“priedų tvarkytojai.

private void Form1_Load (objekto siuntėjas, „EventArgs e“) {

/ * Inicijuokite ir atidarykite „Phidgets“*/

viršuje. HubPort = 0; top. Attach += Top_Attach; top. Detach += Top_Detach; top. PositionChange += Top_PositionChange; viršuje. Atidaryti ();

apačioje. HubPort = 1;

bottom. Attach += Bottom_Attach; bottom. Detach += Bottom_Detach; bottom. PositionChange += Bottom_PositionChange; apačioje. Atidaryti ();

magSensor. HubPort = 2;

magSensor. IsHubPortDevice = tiesa; magSensor. Attach += MagSensor_Attach; magSensor. Detach += MagSensor_Detach; magSensor. SensorChange += MagSensor_SensorChange; magSensor. Open ();

led. HubPort = 5;

led. IsHubPortDevice = tiesa; led. Kanalas = 0; led. Attach += Led_Attach; led. Detach += Led_Detach; led. Open (); }

private void Led_Attach (objekto siuntėjas, Phidget22. Events. AttachEventArgs e) {

ledAttachedChk. Checked = tiesa; led. State = tiesa; ledChk. Checked = tiesa; }

private void MagSensor_Attach (objekto siuntėjas, Phidget22. Events. AttachEventArgs e) {

magSensorAttachedChk. Checked = tiesa; magSensor. SensorType = VoltageRatioSensorType. PN_1108; magSensor. DataInterval = 16; }

private void Bottom_Attach (objekto siuntėjas, Phidget22. Events. AttachEventArgs e) {

bottomAttachedChk. Checked = tiesa; bottom. CurrentLimit = bottomCurrentLimit; apačioje. Įsitraukęs = tiesa; bottom. VelocityLimit = bottomVelocityLimit; apačia. Spartinimas = apačiaAccel; apačioje. DataInterval = 100; }

private void Top_Attach (objekto siuntėjas, Phidget22. Events. AttachEventArgs e) {

topAttachedChk. Checked = tiesa; top. CurrentLimit = topCurrentLimit; viršuje. Įsitraukęs = tiesa; viršuje. RescaleFactor = -1; viršuje. VelocityLimit = -topVelocityLimit; viršuje. Spartėjimas = -topAccel; viršuje. DataInterval = 100; }

Inicializuojant taip pat skaitome išsaugotą spalvų informaciją, todėl galima tęsti ankstesnį paleidimą.

Variklio padėties nustatymas

Variklio valdymo kodą sudaro patogios variklių perkėlimo funkcijos. Mano naudojami varikliai yra 3 200 1/16 žingsnių per apsisukimą, todėl sukūriau tam konstantą.

Viršutiniam varikliui yra 3 pozicijos, kurias norime perduoti varikliui: internetinė kamera, skylė ir padėties nustatymo magnetas. Yra funkcija, skirta keliauti į kiekvieną iš šių pozicijų:

private void nextMagnet (Boolean wait = false) {

dvigubas posn = viršuje. Pozicija % žingsniųPerRev;

top. TargetPosition += (stepsPerRev - posn);

jei (palauk)

while (viršuje. IsMoving) Thread. Sleep (50); }

private void nextCamera (Boolean wait = false) {

dvigubas posn = viršuje. Pozicija % žingsniųPerRev; if (posn <Properties. Settings. Default.cameraOffset) top. TargetPosition += (Properties. Settings. Default.cameraOffset - posn); else top. TargetPosition + = ((Properties. Settings. Default.cameraOffset - posn) + stepsPerRev);

jei (palauk)

while (viršuje. IsMoving) Thread. Sleep (50); }

private void nextHole (Boolean wait = false) {

dvigubas posn = viršuje. Pozicija % žingsniųPerRev; if (posn <Properties. Settings. Default.holeOffset) top. TargetPosition += (Properties. Settings. Default.holeOffset - posn); else top. TargetPosition + = ((Properties. Settings. Default.holeOffset - posn) + stepsPerRev);

jei (palauk)

while (viršuje. IsMoving) Thread. Sleep (50); }

Prieš pradedant važiavimą, viršutinė plokštė sulygiuojama naudojant magnetinį jutiklį. Funkciją alignMotor galima iškviesti bet kuriuo metu, kad sulygiuotumėte viršutinę plokštę. Ši funkcija pirmiausia greitai pasuka plokštę iki 1 visiško apsisukimo, kol pamatys magneto duomenis virš slenksčio. Tada jis šiek tiek sukuria atsarginę kopiją ir vėl lėtai juda į priekį, fiksuodamas jutiklio duomenis. Galiausiai, ji nustato poziciją į didžiausią magneto duomenų vietą ir atstato padėties poslinkį į 0. Taigi maksimali magneto padėtis visada turi būti (viršuje. Pozicija % žingsniaiPerRev)

Temos suderinimasMotorThread; Būliniai pjūklaiMagnetas; dvigubas magSensorMax = 0; private void alignMotor () {

// Rask magnetą

top. DataInterval = viršuje. MinDataInterval;

sawMagnet = klaidinga;

magSensor. SensorChange += magSensorStopMotor; viršuje. VelocityLimit = -1000;

int tryCount = 0;

Bandyk iš naujo:

top. TargetPosition += stepsPerRev;

while (viršuje. IsMoving &&! sawMagnet) Thread. Sleep (25);

jei (! sawMagnet) {

if (tryCount> 3) {Console. WriteLine ("Nepavyko suderinti"); viršuje. Įsitraukęs = klaidingas; apačioje. Įsitraukęs = klaidingas; runtest = klaidinga; grįžti; }

tryCount ++;

Console. WriteLine ("Ar mes įstrigę? Bandome sukurti atsarginę kopiją …"); top. TargetPosition -= 600; tuo tarpu (viršuje. IsMoving) Thread. Sleep (100);

vėl pabandyti;

}

viršuje. VelocityLimit = -100;

magData = naujas sąrašas> (); magSensor. SensorChange += magSensorCollectPositionData; top. TargetPosition += 300; while (top. IsMoving) Thread. Sleep (100);

magSensor. SensorChange -= magSensorCollectPositionData;

viršuje. VelocityLimit = -topVelocityLimit;

KeyValuePair max = magData [0];

foreach (KeyValuePair pora magData) if (pair. Value> max. Value) max = pora;

top. AddPositionOffset (-max. Key);

magSensorMax = max. Value;

top. TargetPosition = 0;

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

Console. WriteLine ("Išlygiuoti pavyko");

}

Sąrašas> magData;

private void magSensorCollectPositionData (objekto siuntėjas, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {magData. Add (naujas KeyValuePair (top. Position, e. SensorValue)); }

private void magSensorStopMotor (objekto siuntėjas, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {

if (top. IsMoving && e. SensorValue> 5) {top. TargetPosition = viršuje. Pozicija - 300; magSensor. SensorChange -= magSensorStopMotor; sawMagnet = tiesa; }}

Galiausiai, apatinis variklis yra valdomas siunčiant jį į vieną iš granulių konteinerio pozicijų. Šiam projektui turime 19 pozicijų. Algoritmas pasirenka trumpiausią kelią ir sukasi pagal laikrodžio rodyklę arba prieš laikrodžio rodyklę.

private int BottomPosition {get {int posn = (int) bottom. Position % stepsPerRev; if (posn <0) posn += žingsniaiPerRev;

return (int) Math. Rund ((((posn * beadCompartments) / (dvigubi) žingsniaiPerRev));

} }

private void SetBottomPosition (int posn, bool wait = false) {

posn = posn % beadCompartments; double targetPosn = (posn * stepsPerRev) / beadCompartments;

dviguba srovėPosn = apačia. Pozicija % žingsniųPerRev;

dvigubas posnDiff = targetPosn - currentPosn;

// Laikykite tai kaip visus veiksmus

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

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

jei (palauk)

tuo tarpu (apačioje. IsMoving) Thread. Sleep (50); }

Fotoaparatas

„OpenCV“naudojama vaizdams skaityti iš internetinės kameros. Fotoaparato siūlai pradedami prieš pradedant pagrindinį rūšiavimo siūlą. Ši gija nuolat skaitoma vaizduose, apskaičiuoja vidutinę konkretaus regiono spalvą naudojant vidurkį ir atnaujina visuotinį spalvų kintamąjį. Siūlas taip pat naudoja „HoughCircles“, kad bandytų aptikti karoliuką arba skylę viršutinėje plokštėje, kad patikslintų sritį, į kurią ji žiūri, kad aptiktų spalvas. Slenksčio ir „HoughCircles“skaičiai buvo nustatyti bandymų ir klaidų būdu ir labai priklauso nuo internetinės kameros, apšvietimo ir tarpų.

bool runVideo = tiesa; bool videoRunning = false; „VideoCapture“fiksavimas; Siūlai cvThread; Aptikta spalvaSpalva; Būlo aptikimas = klaidinga; int aptiktiCnt = 0;

private void cvThreadFunction () {

videoRunning = false;

užfiksuoti = naujas „VideoCapture“(pasirinkta kamera);

naudojant (lango langas = naujas langas („užfiksuoti“)) {

Mat vaizdas = naujas Mat (); Mat vaizdas2 = naujas kilimėlis (); while (runVideo) {capture. Read (vaizdas); jei (vaizdas. Tuščia ()) pertrauka;

jei (aptinkama)

detectCnt ++; else detectCnt = 0;

if (aptinkama || circleDetectChecked || showDetectionImgChecked) {

Cv2. CvtColor (vaizdas, vaizdas2, „ColorConversionCodes. BGR2GRAY“); Mat thres = image2. Threshold ((dvigubas) Properties. Settings. Default.videoThresh, 255, ThresholdTypes. Binary); thres = thres. GaussianBlur (naujas „OpenCvSharp. Size“(9, 9), 10);

if (showDetectionImgChecked)

vaizdas = thres;

if (aptinkama || circleDetectChecked) {

CircleSegment karoliukas = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 20, 200, 100, 20, 65); if (bead. Length> = 1) {image. Circle (karoliukas [0]. Center, 3, new Scalar (0, 100, 0), -1); vaizdas. Apskritimas (karoliukas [0]. Centras, (int) karoliukas [0]. Spindulys, naujas skaliaras (0, 0, 255), 3); if (karoliukas [0]. Radius> = 55) {Properties. Settings. Default.x = (dešimtainis) karoliukas [0]. Center. X + (dešimtainis) (karoliukas [0]. Radius / 2); Properties. Settings. Default.y = (dešimtainis) karoliukas [0]. Centras. Y - (dešimtainis) (karoliukas [0]. Radius / 2); } else {Properties. Settings. Default.x = (dešimtainis) karoliukas [0]. Center. X + (dešimtainis) (karoliukas [0]. Radius); Properties. Settings. Default.y = (dešimtainis) karoliukas [0]. Center. Y - (dešimtainis) (karoliukas [0]. Radiusas); } Properties. Settings. Default.size = 15; Properties. Settings. Default.height = 15; } Kitas {

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

jei (apskritimai. Length> 1) {Sąrašas xs = apskritimai. Pasirinkite (c => c. Center. X). ToList (); xs. Rūšiuoti (); Sąrašas ys = apskritimai. Pasirinkite (c => c. Center. Y). ToList (); ys. Rūšiuoti ();

int medianX = (int) xs [xs. Skaičius / 2];

int medianY = (int) ys [ys. Skaičius / 2];

if (medianX> vaizdas. Plotis - 15)

medianX = vaizdas. Plotis - 15; if (medianY> vaizdas. Aukštis - 15) medianY = vaizdas. Aukštis - 15;

vaizdas. Apskritimas (medianX, medianY, 100, new Scalar (0, 0, 150), 3);

jei (aptinkama) {

Properties. Settings. Default.x = medianaX - 7; Properties. Settings. Default.y = medianaY - 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 = naujas Mat (vaizdas, r);

Scalar avgColor = Cv2. Mean (beadSample); detectColor = Color. FromArgb ((int) avgColor [2], (int) avgColor [1], (int) avgColor [0]);

vaizdas. Stačiakampis (r, naujas skaliaras (0, 150, 0));

window. ShowImage (vaizdas);

Cv2. WaitKey (1); videoRunning = tiesa; }

videoRunning = false;

} }

private void cameraStartBtn_Click (objekto siuntėjas, „EventArgs e“) {

if (cameraStartBtn. Text == "start") {

cvThread = new Thread (new ThreadStart (cvThreadFunction)); runVideo = tiesa; cvThread. Start (); cameraStartBtn. Text = "sustabdyti"; while (! videoRunning) Thread. Sleep (100);

updateColorTimer. Start ();

} Kitas {

runVideo = klaidinga; cvThread. Join (); cameraStartBtn. Text = "pradžia"; }}

Spalva

Dabar mes galime nustatyti karoliuko spalvą ir pagal tą spalvą nuspręsti, į kurią talpyklą įdėti.

Šis žingsnis grindžiamas spalvų palyginimu. Mes norime atskirti spalvas, kad apribotume klaidingai teigiamus, bet taip pat leistume pakankamai slenksčio, kad apribotume klaidingus neigiamus dalykus. Spalvų palyginimas iš tikrųjų yra stebėtinai sudėtingas, nes tai, kaip kompiuteriai spalvas saugo kaip RGB, ir tai, kaip žmonės suvokia spalvas, nėra tiesiškai koreliuojamos. Dar blogiau, taip pat reikia atsižvelgti į šviesos spalvą, pagal kurią žiūrima spalva.

Yra sudėtingas spalvų skirtumo apskaičiavimo algoritmas. Mes naudojame CIE2000, kuris išleidžia skaičių, esantį netoli 1, jei 2 spalvos žmogui nesiskiria. Šiems sudėtingiems skaičiavimams atlikti naudojame „ColorMine C#“biblioteką. Nustatyta, kad „DeltaE“vertė 5 yra geras kompromisas tarp klaidingai teigiamų ir klaidingai neigiamų.

Kadangi dažnai yra daugiau spalvų nei konteinerių, paskutinė vieta rezervuojama kaip gaudyklė. Aš paprastai juos atidedu, kad mašina veiktų antrą kartą.

Sąrašas

spalvos = naujas sąrašas (); sąrašas colorPanels = naujas sąrašas (); Sąrašo spalvosTxts = naujas Sąrašas (); Sąrašas colorCnts = naujas Sąrašas ();

const int numColorSpots = 18;

const int nežinomasColorIndex = 18; int findColorPosition (spalva c) {

Console. WriteLine ("Rasti spalvą …");

var cRGB = naujas Rgb ();

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

int bestMatch = -1;

dvigubos rungtynėsDelta = 100;

už (int i = 0; i <spalvos. skaičius; i ++) {

var RGB = naujas Rgb ();

RGB. R = spalvos . R; RGB. G = spalvos . G; RGB. B = spalvos . B;

dvigubas delta = cRGB. Compare (RGB, naujas CieDe2000Comparison ());

// dviguba delta = deltaE (c, spalvos ); Console. WriteLine ("DeltaE (" + i. ToString () + "):" + delta. ToString ()); if (delta <matchDelta) {matchDelta = delta; bestMatch = i; }}

if (matchDelta <5) {Console. WriteLine ("Rasta! (Posn:" + bestMatch + "Delta:" + matchDelta + ")"); return bestMatch; }

if (color. Count <numColorSpots) {Console. WriteLine ("Nauja spalva!"); spalvos. Pridėti (c); this. BeginInvoke (naujas veiksmas (setBackColor), naujas objektas {colors. Count - 1}); writeOutColors (); grįžti (spalvos. Skaičius - 1); } else {Console. WriteLine ("Nežinoma spalva!"); return unknownColorIndex; }}

Rūšiavimo logika

Rūšiavimo funkcija sujungia visus gabalus, kad iš tikrųjų rūšiuotų karoliukus. Ši funkcija veikia specialioje temoje; perkelkite viršutinę plokštę, nustatykite karoliukų spalvą, įdėkite ją į šiukšliadėžę, įsitikinkite, kad viršutinė plokštė lieka sulygiuota, skaičiuojant karoliukus ir pan. Jis taip pat nustoja veikti, kai pripildoma šiukšliadėžė. Priešingu atveju mes tiesiog baigiame perpildytus karoliukus.

Siūlo spalva colorTestThread; Boolean runtest = false; void colourTest () {

jei (! viršuje. Įsitraukęs)

viršuje. Įsitraukęs = tiesa;

jei (! apačioje. Įsitraukęs)

apačioje. Įsitraukęs = tiesa;

while (runtest) {

nextMagnet (tiesa);

Siūlas. Miegas (100); pabandykite {if (magSensor. SensorValue <(magSensorMax - 4)) alignMotor (); } pagauti {alignMotor (); }

nextCamera (tiesa);

aptikimas = tiesa;

while (aptiktiCnt <5) Thread. Sleep (25); Console. WriteLine ("Detect Count:" + detectCnt); aptikimas = klaidingas;

Spalva c = aptikta spalva;

this. BeginInvoke (naujas veiksmas (setColorDet), naujas objektas {c}); int i = rastiSpalvaPozicija (c);

SetBottomPosition (i, tiesa);

nextHole (tiesa); colorCnts ++; this. BeginInvoke (naujas veiksmas (setColorTxt), naujas objektas {i}); Siūlai. Miegas (250);

if (colorCnts [unknownColorIndex]> 500) {

viršuje. Įsitraukęs = klaidingas; apačioje. Įsitraukęs = klaidingas; runtest = klaidinga; this. BeginInvoke (naujas veiksmas (setGoGreen), null); grįžti; }}}

private void colourTestBtn_Click (objekto siuntėjas, „EventArgs e“) {

if (colourTestThread == null ||! colourTestThread. IsAlive) {colourTestThread = new Thread (new ThreadStart (colourTest)); runtest = tiesa; colourTestThread. Start (); colourTestBtn. Text = "STOP"; colourTestBtn. BackColor = Spalva. Ruda; } else {runtest = false; colourTestBtn. Text = "EITI"; colourTestBtn. BackColor = Spalva. Žalia; }}

Šiuo metu mes turime darbo programą. Kai kurie kodo bitai nebuvo įtraukti į straipsnį, todėl pažiūrėkite į šaltinį, kad jį iš tikrųjų paleistumėte.

Optikos konkursas
Optikos konkursas

Antrasis prizas optikos konkurse

Rekomenduojamas: