Mundarija:
Video: Boncuklarni robotlashtirish: 3 qadam (rasmlar bilan)
2024 Muallif: John Day | [email protected]. Oxirgi o'zgartirilgan: 2024-01-30 13:26
Ushbu loyihada biz Perler boncuklarini rang bo'yicha saralash uchun robot quramiz.
Men har doim ranglarni ajratuvchi robot yaratmoqchi edim, shuning uchun qizim Perlerdan boncuk yasashga qiziqib qolganida, men buni ajoyib imkoniyat deb bildim.
Perler munchoqlari ko'plab munchoqlarni qoziq taxtasiga qo'yib, keyin ularni temir bilan eritib, birlashtirilgan san'at loyihalarini yaratish uchun ishlatiladi. Siz odatda bu boncuklarni 22 000 dona boncukli aralash paketlarda sotib olasiz va kerakli rangni qidirishga ko'p vaqt sarflaysiz, shuning uchun ularni saralash san'at samaradorligini oshiradi deb o'yladim.
Men Phidgets Inc.da ishlayman, shuning uchun men ushbu loyihada asosan Phidgets -dan foydalanardim, lekin buni har qanday mos keladigan uskuna yordamida amalga oshirish mumkin edi.
1 -qadam: Uskuna
Mana, men buni oldin qurganman. Men uni 100% phidgets.com saytining qismlari va uy atrofida yotgan narsalarim bilan qurdim.
Fidjetlar taxtasi, motorlar, apparat
- HUB0000 - VINT Hub vidjeti
- 1108 - magnit sensor
- 2x STC1001 - 2,5A qadamli vidjet
- 2x 3324 - 42STH38 NEMA -17 bipolyar tishli holda
- 3x 3002 - Phidget kabeli 60 sm
- 3403 - USB2.0 4 -portli uyadan
- 3031 - urg'ochi cho'chqa go'shti 5,5x2,1 mm
- 3029 - 2 simli 100 'o'ralgan kabel
- 3604 - 10 mm oq LED (10 ta sumka)
- 3402 - USB veb -kamerasi
Boshqa qismlar
- 24VDC 2.0A quvvat manbai
- Garajdan yog'och va metallni olib tashlang
- Fermuar bog'lamlari
- Pastki qismi kesilgan plastik idish
2 -qadam: Robotni loyihalash
Biz kirish shkafidan bitta boncuk oladigan, uni veb -kameraning ostiga qo'yadigan va keyin uni tegishli qutiga ko'chiradigan narsalarni loyihalashimiz kerak.
Boncuk olish
Men 1 -qismni 2 dona dumaloq kontrplak bilan bajarishga qaror qildim, ularning har biri bir joyda teshilgan. Pastki qismi mahkamlangan, ustki qismi esa zanjirli dvigatelga ulangan, uni boncuklar bilan to'ldirilgan huni tagida aylantirish mumkin. Teshik huni tagida harakat qilganda, u bitta boncuk oladi. Keyin men uni veb -kamera ostida aylantira olaman, so'ngra pastki qismidagi teshikka to'g'ri kelgunga qadar aylantira olaman, shu vaqtda u tushadi.
Bu rasmda men tizim ishlay olishini sinovdan o'tkazyapman. Hamma narsa pog'onali dvigatelning ostidan ko'rinmas holda biriktirilgan kontrplakning yuqori dumaloq bo'lagidan boshqa hamma narsa tuzatilgan. Veb -kamera hali o'rnatilmagan. Men hozirda dvigatelga o'tish uchun Phidget boshqaruv panelidan foydalanayapman.
Boncuklarni saqlash
Keyingi qism - har bir rangni saqlash uchun axlat qutisi tizimini loyihalash. Tegishli bo'linmali dumaloq idishni qo'llab -quvvatlash va aylantirish uchun men quyida ikkinchi qadamli dvigatelni ishlatishga qaror qildim. Bu boncuk tushadigan teshik ostidagi to'g'ri bo'linmani aylantirish uchun ishlatilishi mumkin.
Men buni karton va yopishqoq lenta yordamida qurdim. Bu erda eng muhim narsa - bu mustahkamlik - har bir bo'linma bir xil o'lchamda bo'lishi kerak va hamma narsa bir xil og'irlikda bo'lishi kerak, shunda u o'tkazib yubormasdan aylanadi.
Boncuklarni olib tashlash mahkam yopilgan qopqoq yordamida amalga oshiriladi, u bir vaqtning o'zida bitta bo'lakni ochadi, shuning uchun boncuklarni to'kish mumkin.
Kamera
Veb -kamera ustki plastinka ustki ustuni bilan pastki plastinka teshigining orasiga o'rnatiladi. Bu tizimga boncukni tushirishdan oldin qarashga imkon beradi. Kamera ostidagi munchoqlarni yoritish uchun LED ishlatiladi va doimiy yorug'lik muhitini ta'minlash uchun atrofdagi yorug'lik bloklanadi. Bu rangni aniq aniqlash uchun juda muhim, chunki atrofdagi yorug'lik haqiqatan ham qabul qilingan rangni yo'qotishi mumkin.
Joyni aniqlash
Tizim uchun boncuk ajratgichning aylanishini aniqlay olish juda muhimdir. Bu ishga tushirish paytida boshlang'ich pozitsiyasini o'rnatish uchun, shuningdek, step motorining sinxronlashdan chiqqanligini aniqlash uchun ishlatiladi. Mening tizimimda, munchoq olganda, ba'zida tiqilib qoladi va tizim bu holatni aniqlay olishi va hal qila olishi kerak edi - biroz zaxiralash va agianni sinab ko'rish.
Buni hal qilishning ko'plab usullari mavjud. Men yuqori plastinkaning chetiga o'rnatilgan magnitli 1108 magnitli sensorni ishlatishga qaror qildim. Bu menga har bir aylanishdagi pozitsiyani tekshirishga imkon beradi. Yaxshi echim, ehtimol, step motoridagi kodlovchi bo'lardi, lekin menda 1108 yotardi, shuning uchun men uni ishlatardim.
Robotni tugating
Bu vaqtda hamma narsa ishlab chiqilgan va sinovdan o'tgan. Hamma narsani yaxshi o'rnatish va dasturiy ta'minotga o'tish vaqti keldi.
2 bosqichli dvigatellar STC1001 pog'onali boshqaruvchilari tomonidan boshqariladi. HUB000 - USB VINT uyasi qadamni boshqarish moslamalarini ishga tushirish, shuningdek magnitli sensorni o'qish va LEDni boshqarish uchun ishlatiladi. Veb -kamera va HUB0000 ikkalasi ham kichik USB uyasiga ulangan. Dvigatellarni quvvatlantirish uchun 24 V kuchlanishli quvvat manbai bilan bir qatorda 3031 cho'chqa va ba'zi simlar ishlatiladi.
3 -qadam: Kod yozing
Ushbu loyiha uchun C# va Visual Studio 2015 ishlatiladi. Sahifaning yuqori qismidagi manbani yuklab oling va davom eting - asosiy bo'limlar quyida keltirilgan
Boshlash
Birinchidan, biz Phidget ob'ektlarini yaratishimiz, ochishimiz va ishga tushirishimiz kerak. Bu formani yuklash hodisasida amalga oshiriladi va Phidget biriktiruvchi ishlovchilar.
shaxsiy bo'shliq Form1_Load (ob'ekt yuboruvchi, EventArgs e) {
/ * Fidjetlarni ishga tushiring va oching */
top. HubPort = 0; top. Attach += Top_Attach; top. Detach += Top_Detach; top. PositionChange += Top_PositionChange; top. Open ();
pastki. HubPort = 1;
pastki. Attach += Bottom_Attach; pastki. Detach += Bottom_Detach; pastki. PositionChange += Bottom_PositionChange; pastki Ochiq ();
magSensor. HubPort = 2;
magSensor. IsHubPortDevice = rost; magSensor. Attach += MagSensor_Attach; magSensor. Detach += MagSensor_Detach; magSensor. SensorChange += MagSensor_SensorChange; magSensor. Open ();
led. HubPort = 5;
led. IsHubPortDevice = rost; LED kanal = 0; led. Attach += Led_Attach; led. Detach += Led_Detach; led. Open (); }
shaxsiy bo'shliq Led_Attach (ob'ekt yuboruvchi, Phidget22. Events. AttachEventArgs e) {
ledAttachedChk. Checked = rost; led. State = rost; ledChk. Checked = rost; }
shaxsiy bo'shliq MagSensor_Attach (ob'ekt yuboruvchi, Phidget22. Events. AttachEventArgs e) {
magSensorAttachedChk. Checked = rost; magSensor. SensorType = VoltageRatioSensorType. PN_1108; magSensor. DataInterval = 16; }
shaxsiy bo'shliq Bottom_Attach (ob'ekt yuboruvchi, Phidget22. Events. AttachEventArgs e) {
bottomAttachedChk. Checked = rost; pastki. CurrentLimit = bottomCurrentLimit; pastki. Engaged = rost; pastki. VelocityLimit = bottomVelocityLimit; pastki Tezlik = bottomAccel; pastki. DataInterval = 100; }
shaxsiy bo'shliq Top_Attach (ob'ekt yuboruvchi, Phidget22. Events. AttachEventArgs e) {
topAttachedChk. Checked = rost; top. CurrentLimit = topCurrentLimit; top. Engaged = rost; top. RescaleFactor = -1; top. VelocityLimit = -topVelocityLimit; top. Akseleratsiya = -topAccel; top. DataInterval = 100; }
Biz, shuningdek, ishga tushirish paytida saqlangan rangli ma'lumotlarni o'qiymiz, shuning uchun oldingi ishga tushirishni davom ettirish mumkin.
Dvigatel joylashuvi
Dvigatelni boshqarish kodi dvigatellarni harakatlantirish uchun qulaylik funktsiyalaridan iborat. Men ishlatgan dvigatellar har bir inqilobda 3 200 ta 1/16 qadamdir, shuning uchun men doimiyni yaratdim.
Yuqori dvigatel uchun biz motorga yuborishimiz kerak bo'lgan 3 pozitsiya mavjud: veb -kamera, teshik va joylashishni aniqlash magnitlari. Ushbu pozitsiyalarning har biriga sayohat qilish funktsiyasi mavjud:
nextMagnet shaxsiy bo'shligi (mantiqiy kutish = noto'g'ri) {
double posn = top. Position % stepsPerRev;
top. TargetPosition += (stepsPerRev - posn);
agar (kuting)
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);
agar (kuting)
while (top. IsMoving) Thread. Sleep (50); }
nextHole shaxsiy bo'sh joy (mantiqiy kutish = noto'g'ri) {
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);
agar (kuting)
while (top. IsMoving) Thread. Sleep (50); }
Yugurishni boshlashdan oldin, yuqori plastinka magnit sensor yordamida tekislanadi. AlignMotor funktsiyasini istalgan vaqtda yuqori plastinkani tekislash uchun chaqirish mumkin. Bu funktsiya, birinchi navbatda, plastinkani magnit ma'lumotlarini pol ostidan ko'rmaguncha, 1 to'liq aylanishga aylantiradi. Keyin u bir oz orqaga qaytadi va asta -sekin oldinga siljiydi va sensorlar ma'lumotlarini ushlab turadi. Nihoyat, u pozitsiyani magnitlangan ma'lumotlarning maksimal joylashuviga o'rnatadi va o'rnini 0 ga qaytaradi. Shunday qilib, magnitning maksimal joylashuvi har doim bo'lishi kerak (tepada. % QadamPerRev pozitsiyasi).
Mavzuni tekislashMotorThread; Boolean sawMagnet; er -xotin magSensorMax = 0; shaxsiy bo'shliq alignMotor () {
// Magnitni toping
top. DataInterval = top. MinDataInterval;
sawMagnet = noto'g'ri;
magSensor. SensorChange += magSensorStopMotor; top. VelocityLimit = -1000;
int tryCount = 0;
qayta urinib ko'ring:
top. TargetPosition += stepsPerRev;
while (top. IsMoving &&! sawMagnet) Thread. Sleep (25);
agar (! sawMagnet) {
if (tryCount> 3) {Console. WriteLine ("Hizalanmadi"); top. Engaged = false; pastki. Engaged = false; runtest = noto'g'ri; qaytish; }
tryCount ++;
Console. WriteLine ("Biz qolib ketdikmi? Zaxira nusxasini qidirmoqdamiz …"); top. TargetPosition -= 600; while (top. IsMoving) Thread. Sleep (100);
qayta urinish kerak;
}
top. VelocityLimit = -100;
magData = yangi ro'yxat> (); magSensor. SensorChange += magSensorCollectPositionData; top. TargetPosition += 300; while (top. IsMoving) Thread. Sleep (100);
magSensor. SensorChange -= magSensorCollectPositionData;
top. VelocityLimit = -topVelocityLimit;
KeyValuePair max = magData [0];
foreach (magData -dagi KeyValuePair juftligi) if (pair. Value> max. Value) max = pair;
top. AddPositionOffset (-max kalit);
magSensorMax = maksimal qiymat;
top. TargetPosition = 0;
while (top. IsMoving) Thread. Sleep (100);
Console. WriteLine ("Align muvaffaq bo'ldi");
}
Ro'yxat> magData;
maxfiy bo'sh magSensorCollectPositionData (ob'ekt yuboruvchi, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {magData. Add (yangi KeyValuePair (top. Position, e. SensorValue))); }
magSensorStopMotor xususiy bo'sh joy (ob'ektni jo'natuvchi, Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {
if (top. IsMoving &&. SensorValue> 5) {top. TargetPosition = top. Position - 300; magSensor. SensorChange -= magSensorStopMotor; sawMagnet = haqiqiy; }}
Nihoyat, pastki dvigatel, uni boncuk konteyner pozitsiyalaridan biriga yuborish orqali boshqariladi. Ushbu loyiha uchun bizda 19 ta pozitsiya mavjud. Algoritm eng qisqa yo'lni tanlaydi va soat yo'nalishi bo'yicha yoki teskari yo'nalishda aylanadi.
private int BottomPosition {get {int posn = (int) bottom. Position % stepsPerRev; agar (posn <0) posn += stepsPerRev;
return (int) Math. Round (((posn * beadCompartments) / (double) stepsPerRev));
} }
Maxsus bo'sh joy SetBottomPosition (int posn, bool wait = false) {
posn = posn % beadCompartments; double targetPosn = (posn * stepsPerRev) / beadCompartments;
ikki tomonlama
er -xotin posnDiff = targetPosn - currentPosn;
// Buni to'liq qadamlar sifatida saqlang
posnDiff = ((int) (posnDiff / 16)) * 16;
if (posnDiff <= 1600) pastki. TargetPosition += posnDiff; else bottom. TargetPosition - = (stepsPerRev - posnDiff);
agar (kuting)
while (bottom. IsMoving) Thread. Sleep (50); }
Kamera
OpenCV veb -kameradan rasmlarni o'qish uchun ishlatiladi. Kamera chizig'i asosiy saralash ipini ishga tushirishdan oldin boshlanadi. Bu mavzu doimiy ravishda rasmlarda o'qiladi, o'rtacha yordamida ma'lum bir mintaqaning o'rtacha rangini hisoblab chiqadi va global rang o'zgaruvchisini yangilaydi. Ip, shuningdek, boncukni yoki yuqori plastinkadagi teshikni aniqlashga harakat qilib, rangni aniqlaydigan maydonni aniqlab beradi. Eshik va HoughCircles raqamlari sinov va xato orqali aniqlandi va ko'p jihatdan veb -kameraga, yorug'lik va intervalga bog'liq.
bool runVideo = rost; bool videoRunning = noto'g'ri; Video ta'qib qilish; Mavzu cvThread; Rang aniqlandi; Mantiqiy aniqlash = noto'g'ri; int detectCnt = 0;
maxfiy vv cvThreadFunction () {
videoRunning = noto'g'ri;
ta'qib qilish = yangi VideoCapture (selectedCamera);
yordamida (Oyna oynasi = yangi oyna ("yozib olish")) {
Mat tasviri = yangi Mat (); Mat image2 = yangi Mat (); while (runVideo) {capture. Read (rasm); if (image. Empty ()) buzilsa;
agar (aniqlansa)
aniqlashCnt ++; boshqa aniqlashCnt = 0;
if (aniqlash || CircleDetectChecked || showDetectionImgChecked) {
Cv2. CvtColor (rasm, image2, ColorConversionCodes. BGR2GRAY); Mat thres = image2. Threshold ((double) Properties. Settings. Default.videoThresh, 255, ThresholdTypes. Binary); thres = thres. GaussianBlur (yangi OpenCvSharp. Size (9, 9), 10);
agar (showDetectionImgChecked)
tasvir = thres;
agar (aniqlansa || CircleDetectChecked) {
CircleSegment bead = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 20, 200, 100, 20, 65); if (munchoq. Length> = 1) {image. Circle (boncuk [0]. Markaz, 3, yangi Skalyar (0, 100, 0), -1); tasvir. Circle (munchoq [0]. Markaz, (int) boncuk [0]. Radius, yangi Skalyar (0, 0, 255), 3); if (bead [0]. Radius> = 55) {Properties. Settings. Default.x = (o'nlik) munchoq [0]. Center. X + (o'nlik) (boncuk [0]. Radius / 2); Properties. Settings. Default.y = (o'nlik) boncuk [0]. Center. Y - (o'nlik) (boncuk [0]. Radius / 2); } else {Properties. Settings. Default.x = (o'nlik) boncuk [0]. Center. X + (o'nlik) (boncuk [0]. Radius); Properties. Settings. Default.y = (o'nlik) boncuk [0]. Center. Y - (o'nlik) (boncuk [0]. Radius); } Properties. Settings. Default.size = 15; Xususiyatlar. Sozlamalar. Default.height = 15; } boshqa {
CircleSegment doiralar = thres. HoughCircles (HoughMethods. Gradient, 2, /*thres. Rows/4*/ 5, 200, 100, 60, 180);
agar (doiralar. Uzunlik> 1) {Ro'yxat xs = doiralar. ni tanlang (c => c. Center. X). ToList (); xs. Sort (); Ro'yxat ys = doiralar. Ni tanlang (c => c. Center. Y). ToList (); ys. Sort ();
int medianX = (int) xs [xs. Count / 2];
int medianY = (int) ys [ys. Count / 2];
agar (medianX> tasvir. Kenglik - 15)
medianX = tasvir. Kenglik - 15; agar (medianY> tasvir. Balandlik - 15) medyanY = tasvir. Yuqori - 15;
tasvir. Doira (medianX, medyanY, 100, yangi Skalyar (0, 0, 150), 3);
agar (aniqlansa) {
Properties. Settings. Default.x = medianX - 7; Xususiyatlar. Sozlamalar. Default.y = medianY - 7; Properties. Settings. Default.size = 15; Xususiyatlar. Sozlamalar. 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 = yangi Mat (rasm, r);
Skalar avgColor = Cv2. Mean (beadSample); detectColor = Color. FromArgb ((int) avgColor [2], (int) avgColor [1], (int) avgColor [0]);
tasvir. To'g'ri to'rtburchak (r, yangi Skalyar (0, 150, 0));
window. ShowImage (rasm);
Cv2. WaitKey (1); videoRunning = to'g'ri; }
videoRunning = noto'g'ri;
} }
shaxsiy bo'sh kameraStartBtn_Click (ob'ekt yuboruvchi, EventArgs e) {
agar (cameraStartBtn. Text == "boshlash") {
cvThread = yangi mavzu (yangi ThreadStart (cvThreadFunction)); runVideo = to'g'ri; cvThread. Start (); cameraStartBtn. Text = "to'xtatish"; while (! videoRunning) Thread. Sleep (100);
updateColorTimer. Start ();
} boshqa {
runVideo = noto'g'ri; cvThread. Join (); cameraStartBtn. Text = "boshlash"; }}
Rang
Endi biz boncukning rangini aniqlay olamiz va qaysi rangga qarab uni qaysi idishga tashlashni hal qila olamiz.
Bu qadam ranglarni taqqoslashga asoslangan. Biz yolg'on musbatlikni cheklash uchun ranglarni ajrata olmoqchimiz, lekin soxta negativlarni chegaralash uchun etarli chegaraga ruxsat berishni xohlaymiz. Ranglarni solishtirish aslida hayratlanarli darajada murakkab, chunki kompyuterlarning ranglarni RGB sifatida saqlashi va odamlarning ranglarni idrok etishlari chiziqli bog'liq emas. Vaziyatni yomonlashtirish uchun, ko'rib turgan yorug'lik rangini ham hisobga olish kerak.
Rang farqini hisoblash uchun murakkab algoritm mavjud. Biz CIE2000 -dan foydalanamiz, bu raqam 1 ga yaqin bo'lsa, 2 ta rang odam uchun farq qilmaydi. Biz ColorMine C# kutubxonasidan ushbu murakkab hisob -kitoblarni bajarish uchun foydalanmoqdamiz. DeltaE -ning 5 -qiymati noto'g'ri ijobiy va noto'g'ri salbiy o'rtasida yaxshi murosaga kelishi aniqlandi.
Konteynerlardan ko'ra ko'proq ranglar ko'p bo'lganligi sababli, oxirgi joy yig'iladigan quti sifatida saqlanadi. Men, odatda, mashinani ikkinchi uzatishda ishlash uchun bir chetga suraman.
Ro'yxat
ranglar = yangi ro'yxat (); ro'yxat colorPanels = yangi ro'yxat (); Ranglar ro'yxatiTxts = new List (); ColorCnts ro'yxati = yangi ro'yxat ();
const int numColorSpots = 18;
const int unknownColorIndex = 18; int findColorPosition (rang c) {
Console. WriteLine ("Rang topilmoqda …");
var cRGB = yangi Rgb ();
cRGB. R = c. R; cRGB. G = c. G; cRGB. B = c. B;
int bestMatch = -1;
er -xotin matchDelta = 100;
uchun (int i = 0; i <ranglar. Count; i ++) {
var RGB = yangi Rgb ();
RGB. R = ranglar . R; RGB. G = ranglar . G; RGB. B = ranglar . B;
er -xotin delta = cRGB. Compare (RGB, yangi CieDe2000Comparison ());
// juft delta = deltaE (c, ranglar ); Console. WriteLine ("DeltaE (" + i. ToString () + "):" + delta. ToString ()); agar (delta <matchDelta) {matchDelta = delta; bestMatch = i; }}
if (matchDelta <5) {Console. WriteLine ("Topildi! (Posn:" + bestMatch + "Delta:" + matchDelta + ")"); bestMatch -ga qaytish; }
if (colors. Count <numColorSpots) {Console. WriteLine ("Yangi rang!"); ranglar Qo'shish (c); this. BeginInvoke (yangi Action (setBackColor), yangi ob'ekt {colors. Count - 1}); writeOutColors (); qaytish (ranglar soni - 1); } else {Console. WriteLine ("Noma'lum rang!"); unknownColorIndex -ni qaytarish; }}
Mantiqni saralash
Saralash funktsiyasi boncuklarni saralash uchun barcha qismlarni birlashtiradi. Bu funksiya ajratilgan mavzuda ishlaydi; yuqori plastinkani siljitish, boncuk rangini aniqlash, axlat qutisiga joylashtirish, ustki plastinkaning tekis holatda turishiga ishonch hosil qilish, boncuklarni sanash va h.k. Qopqoq qutisi to'lganida u ham ishlamay qoladi - Aks holda, biz to'lib toshgan munchoqlar bilan tugaymiz.
Boolean runtest = false; yaroqsiz rang testi () {
agar (! yuqori. g'azablangan)
top. Engaged = rost;
agar (! pastki. g'azablangan)
pastki. Engaged = rost;
while (runtest) {
nextMagnet (haqiqiy);
Uyqu (100); harakat qilib ko'ring {if (magSensor. SensorValue <(magSensorMax - 4)) alignMotor (); } ushlash {alignMotor (); }
nextCamera (haqiqiy);
aniqlash = rost;
while (detectCnt <5) Thread. Sleep (25); Console. WriteLine ("Detect Count:" + detectCnt); aniqlash = noto'g'ri;
Rang c = aniqlanganColor;
this. BeginInvoke (yangi Action (setColorDet), yangi ob'ekt {c}); int i = findColorPosition (c);
SetBottomPosition (i, rost);
nextHole (haqiqiy); colorCnts ++; this. BeginInvoke (yangi Action (setColorTxt), yangi ob'ekt {i}); Uyqu (250);
agar (colorCnts [unknownColorIndex]> 500) {
top. Engaged = false; pastki. Engaged = false; runtest = noto'g'ri; this. BeginInvoke (yangi Action (setGoGreen), null); qaytish; }}}
shaxsiy bo'sh rang colourTestBtn_Click (ob'ekt yuboruvchi, EventArgs e) {
if (colourTestThread == null ||! colourTestThread. IsAlive) {colourTestThread = yangi mavzu (yangi ThreadStart (colourTest))); runtest = rost; colourTestThread. Start (); colourTestBtn. Text = "To'xtatish"; colourTestBtn. BackColor = Color. Red; } boshqa {runtest = false; colourTestBtn. Text = "GO"; colourTestBtn. BackColor = Color. Green; }}
Bu vaqtda bizda ishchi dastur mavjud. Maqolada ba'zi kodlar qoldirilgan, shuning uchun uni ishga tushirish uchun manbaga qarang.
Optika tanlovining ikkinchi sovrini
Tavsiya:
Batareya bilan ishlaydigan ofis. Quyosh panellari va shamol turbinasi: Sharq/G'arbni avtomatik almashtirish bilan quyosh tizimi: 11 qadam (rasmlar bilan)
Batareya bilan ishlaydigan ofis. Quyosh tizimi Sharq/G'arbning avtomatik panellari va shamol turbinasi bilan almashinuvi bilan: Loyiha: 200 kvadrat metrli ofis batareyali bo'lishi kerak. Ofis, shuningdek, ushbu tizim uchun zarur bo'lgan barcha tekshirgichlar, batareyalar va komponentlarni o'z ichiga olishi kerak. Quyosh va shamol energiyasi batareyalarni zaryad qiladi. Faqat kichik muammo bor
NaTaLia ob -havo stantsiyasi: Arduino quyosh energiyasi bilan ishlaydigan ob -havo stantsiyasi to'g'ri yo'l bilan amalga oshirildi: 8 qadam (rasmlar bilan)
NaTaLia ob -havo stantsiyasi: Arduino quyosh energiyasi bilan ishlaydigan ob -havo stantsiyasi to'g'ri yo'lga qo'yildi: 1 yil davomida 2 xil joyda muvaffaqiyatli ishlaganimdan so'ng, men quyosh energiyasi bilan ishlaydigan ob -havo stantsiyasining loyiha rejalari bilan bo'lishaman va uning qanday qilib uzoq vaqt yashay oladigan tizimga aylanganini tushuntiraman. quyosh energiyasidan o'tgan davrlar. Agar ergashsangiz
Twinky bilan eng zo'r Arduino robot bilan tanishing: 7 qadam (rasmlar bilan)
Twinky bilan eng zo'r Arduino roboti bilan tanishing: Salom, men sizga "Jibo" ni o'zim qanday yaratganimni o'rgataman. lekin "Twinky" deb nomlangan, men buni ochib bermoqchiman … Bu nusxa emas! Men ikkiyuzlamachilik bilan qurardim va shundan keyingina shunga o'xshash narsaning mavjudligini tushundim: bu erda
OpenLH: Biologiya bilan ijodiy tajriba o'tkazish uchun ochiq suyuqlik bilan ishlash tizimi: 9 qadam (rasmlar bilan)
OpenLH: Biologiya bilan ijodiy eksperimentlar uchun ochiq suyuqlik bilan ishlash tizimi: Biz bu ishni moddiy, ko'milgan va mujassamlangan o'zaro ta'sir xalqaro konferentsiyasida (TEI 2019) taqdim etganimizdan faxrlanamiz. Tempe, Arizona, AQSh | 17-20 mart. Hamma yig'ish fayllari va qo'llanmalar bu erda mavjud. Oxirgi kod versiyasi
Vaqt o'tishi bilan rasmlar uchun kamera osonlashtirildi: 22 qadam (rasmlar bilan)
Vaqt o'tishi bilan suratga olish uchun kamera osonlashtirildi. Men boshqa ko'rsatmalarni vaqtni tez suratga olish filmlarini suratga olishni tekshirib ko'rdim. U kino qismini juda yaxshi yoritgan. U filmlar yaratish uchun yuklab olishingiz mumkin bo'lgan bepul dasturiy ta'minot haqida gapirib berdi. Men o'z -o'zimga aytdim, men o'ylaymanki, agar men qila olsam