فهرست مطالب:
تصویری: مرتب سازی مهره های روباتیک: 3 مرحله (همراه با تصاویر)
2024 نویسنده: John Day | [email protected]. آخرین اصلاح شده: 2024-01-30 08:56
در این پروژه ، ما یک ربات برای مرتب سازی مهره های پرلر بر اساس رنگ خواهیم ساخت.
من همیشه می خواستم یک ربات مرتب سازی رنگ بسازم ، بنابراین وقتی دخترم به کار با مهره Perler علاقه مند شد ، من این را به عنوان یک فرصت عالی دیدم.
از مهره های پرلر برای ایجاد پروژه های هنری ذوب شده با قرار دادن مهره های زیاد بر روی تخته سنگ و سپس ذوب آنها با یک آهن استفاده می شود. شما معمولاً این مهره ها را در بسته های غول پیکر 22 ، 000 رنگی مخلوط خریداری می کنید و زمان زیادی را صرف جستجوی رنگ مورد نظر خود می کنید ، بنابراین فکر کردم مرتب سازی آنها کارایی هنر را افزایش می دهد.
من برای Phidgets Inc کار می کنم ، بنابراین بیشتر از Phidgets برای این پروژه استفاده کردم - اما این را می توان با استفاده از هر سخت افزار مناسب انجام داد.
مرحله 1: سخت افزار
در اینجا چیزی است که من برای ساختن آن استفاده کردم. من آن را 100 with با قطعاتی از phidgets.com و چیزهایی که در خانه داشتم ساختم.
تابلوهای فیجت ، موتور ، سخت افزار
- HUB0000 - VINT Hub Phidget
- 1108 - سنسور مغناطیسی
- 2x STC1001 - 2.5A Stepper Phidget
- 2x 3324 - 42STH38 NEMA -17 دوقطبی بدون دنده استپر
- 3x 3002 - کابل فیجت 60 سانتی متر
- 3403 - هاب USB2.0 4 پورت
- 3031 - خوک ماده 5.5x2.1 میلی متر
- 3029 - 2 سیم 100 "پیچ خورده کابل
- 3604 - LED سفید 10 میلی متری (کیسه 10)
- 3402 - وب کم USB
قسمت های دیگر
- منبع تغذیه 24VDC 2.0A
- چوب و فلز را از گاراژ خارج کنید
- کراوات زیپی
- ظرف پلاستیکی که قسمت پایین آن قطع شده است
مرحله 2: طراحی ربات
ما باید چیزی را طراحی کنیم که بتواند یک مهره را از قیف ورودی بگیرد ، آن را زیر وب کم قرار دهد و سپس آن را به سطل مناسب منتقل کند.
وانت مهره
من تصمیم گرفتم قسمت اول را با 2 قطعه تخته سه لا گرد ، هر کدام با یک سوراخ در همان مکان انجام دهم. قطعه پایینی ثابت است ، و قطعه بالا به یک موتور پله ای متصل است ، که می تواند آن را زیر یک قیف پر از مهره بچرخاند. هنگامی که سوراخ در زیر قیف حرکت می کند ، یک مهره را جمع می کند. سپس می توانم آن را زیر وب کم بچرخانم ، و سپس بیشتر بچرخانم تا با سوراخ قطعه پایینی مطابقت داشته باشد ، در این مرحله از آن عبور می کند.
در این تصویر ، من آزمایش می کنم که سیستم می تواند کار کند. همه چیز ثابت است به جز تخته سه لا دور بالا ، که خارج از دید به یک موتور پله ای وصل شده است. هنوز وب کم نصب نشده است. من فقط از کنترل پنل Phidget برای چرخاندن به موتور در این مرحله استفاده می کنم.
ذخیره سازی مهره
قسمت بعدی طراحی سیستم سطل زباله برای نگهداری هر رنگ است. تصمیم گرفتم از دومین موتور پله ای زیر برای پشتیبانی و چرخاندن یک ظرف گرد با محفظه های مساوی استفاده کنم. این می تواند برای چرخاندن محفظه صحیح زیر سوراخی که مهره از آن خارج می شود ، استفاده شود.
من این را با استفاده از مقوا و نوار چسب ساخته ام. مهمترین چیز در اینجا قوام است - هر محفظه باید یک اندازه باشد و کل آن باید به طور مساوی وزن داشته باشد تا بدون رد شدن بچرخد.
حذف مهره با استفاده از یک درپوش محکم انجام می شود که در آن واحد یک محفظه را نمایان می کند ، بنابراین می توان مهره ها را بیرون ریخت.
دوربین
وب کم روی صفحه بالایی بین قیف و محل سوراخ صفحه پایین نصب شده است. این به سیستم اجازه می دهد قبل از انداختن مهره به آن نگاه کند. از یک LED برای روشن کردن مهره های زیر دوربین استفاده می شود و نور محیط مسدود می شود تا محیطی روشنایی یکنواخت ایجاد شود. این برای تشخیص دقیق رنگ بسیار مهم است ، زیرا روشنایی محیط واقعاً می تواند رنگ درک شده را از بین ببرد.
تشخیص مکان
برای سیستم مهم است که بتواند چرخش مهره را تشخیص دهد. این مورد برای تنظیم موقعیت اولیه هنگام راه اندازی ، و همچنین برای تشخیص اینکه موتور پله ای از همگام شده است استفاده می شود. در سیستم من ، گاهی اوقات یک مهره هنگام برداشتن گیر می کند و سیستم باید بتواند این وضعیت را تشخیص داده و مدیریت کند - با کمی پشتیبان گیری و تلاش برای جلوگیری از فشار.
راههای زیادی برای رسیدگی به این امر وجود دارد. تصمیم گرفتم از یک سنسور مغناطیسی 1108 استفاده کنم که آهن ربا در لبه بالای صفحه تعبیه شده بود. این به من امکان می دهد موقعیت را در هر چرخش تأیید کنم. راه حل بهتر احتمالاً رمزگذار روی موتور پله ای است ، اما من یک 1108 در اطراف داشتم ، بنابراین از آن استفاده کردم.
ربات را تمام کنید
در این مرحله ، همه چیز کار شده و آزمایش شده است. وقت آن است که همه چیز را به خوبی نصب کرده و به سراغ نرم افزار نوشتن بروید.
دو موتور پله ای توسط کنترل کننده های پله ای STC1001 هدایت می شوند. یک هاب HUB000 - USB VINT برای اجرای کنترل کننده های پله ای ، همچنین خواندن سنسور مغناطیسی و هدایت LED استفاده می شود. وب کم و HUB0000 هر دو به یک هاب USB کوچک متصل شده اند. یک پیگتایل 3031 و مقداری سیم به همراه منبع تغذیه 24 ولت برای تغذیه موتورها استفاده می شود.
مرحله 3: کد بنویسید
C# و Visual Studio 2015 برای این پروژه استفاده می شود. منبع را در بالای این صفحه بارگیری کرده و دنبال کنید - بخشهای اصلی در زیر شرح داده شده است
مقداردهی اولیه
اول ، ما باید اشیاء Phidget را ایجاد ، باز و اولیه کنیم. این امر در رویداد load form انجام می شود و Phidget handler ها را ضمیمه می کند.
خلأ خصوصی Form1_Load (فرستنده شیء ، EventArgs e) {
/ * شروع و باز کردن Phidgets */
top. HubPort = 0؛ top. Attach += Top_Attach؛ top. Detach += Top_Detach؛ top. PositionChange += Top_PositionChange؛ بالا. باز کردن () ؛
bottom. HubPort = 1؛
bottom. Attach += Bottom_Attach ؛ bottom. Detach += Bottom_Detach ؛ bottom. PositionChange += Bottom_PositionChange؛ پایین باز ()؛
magSensor. HubPort = 2؛
magSensor. IsHubPortDevice = true؛ magSensor. Attach += MagSensor_Attach؛ magSensor. Detach += MagSensor_Detach؛ magSensor. SensorChange += MagSensor_SensorChange؛ magSensor. Open ()؛
led. HubPort = 5؛
led. IsHubPortDevice = true؛ led. Channel = 0؛ led. Attach += Led_Attach ؛ led. Detach += Led_Detach؛ led. Open ()؛ }
خلأ خصوصی Led_Attach (فرستنده شیء ، Phidget22. Events. AttachEventArgs e) {
ledAttachedChk. Checked = true؛ led. State = true؛ ledChk. Checked = true؛ }
خلاء خصوصی MagSensor_Attach (فرستنده شیء ، Phidget22. Events. AttachEventArgs e) {
magSensorAttachedChk. Checked = true؛ magSensor. SensorType = VoltageRatioSensorType. PN_1108؛ magSensor. DataInterval = 16؛ }
خلأ خصوصی Bottom_Attach (فرستنده شیء ، Phidget22. Events. AttachEventArgs e) {
bottomAttachedChk. Checked = true؛ bottom. CurrentLimit = bottomCurrentLimit؛ bottom. Angaged = true؛ bottom. VelocityLimit = bottomVelocityLimit؛ bottom. Acceleration = bottomAccel؛ bottom. DataInterval = 100 ؛ }
خلأ خصوصی Top_Attach (فرستنده شیء ، Phidget22. Events. AttachEventArgs e) {
topAttachedChk. Checked = true؛ top. CurrentLimit = topCurrentLimit؛ بالا. درگیر = درست؛ top. RescaleFactor = -1؛ top. VelocityLimit = -topVelocityLimit؛ بالا شتاب = -topAccel؛ top. DataInterval = 100؛ }
ما همچنین در هنگام راه اندازی اولیه اطلاعات رنگ ذخیره شده را می خوانیم ، بنابراین می توان اجرای قبلی را ادامه داد.
موقعیت یابی موتور
کد جابجایی موتور شامل توابع راحتی برای حرکت موتورها است. موتورهایی که استفاده کردم 3 ، 200 1/16 پله در هر دور هستند ، بنابراین من برای این ثابت ایجاد کردم.
برای موتور بالا ، 3 موقعیت وجود دارد که می خواهیم بتوانیم آنها را به موتور ارسال کنیم: وب کم ، سوراخ و آهنربای موقعیت یابی. برای سفر به هر یک از این موقعیت ها یک تابع وجود دارد:
private void nextMagnet (انتظار بولی = false) {
double posn = top. Position٪ stepsPerRev؛
top. TargetPosition += (stepsPerRev - posn) ؛
اگر (صبر کنید)
while (top. IsMoving) Thread. Sleep (50) ؛ }
private void nextCamera (انتظار بولی = 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 (انتظار بولی = 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 تغییر می دهد. بنابراین ، موقعیت حداکثر آهنربا همیشه باید در (بالا. موقعیت٪ stepPerRev)
موضوع alignMotorThread ؛ اره بولیو مگنت ؛ double magSensorMax = 0؛ void private alignMotor () {
// آهن ربا را پیدا کنید
top. DataInterval = top. MinDataInterval؛
sawMagnet = false؛
magSensor. SensorChange += magSensorStopMotor؛ top. VelocityLimit = -1000 ؛
int tryCount = 0؛
دوباره امتحان کنید:
top. TargetPosition += stepsPerRev؛
while (بالا. IsMoving &&! sawMagnet) Thread. Sleep (25) ؛
اگر (! sawMagnet) {
if (tryCount> 3) {Console. WriteLine ("تراز انجام نشد")؛ بالا. Engaged = false؛ bottom. Angaged = false؛ runtest = false؛ برگشت؛ }
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 (جفت KeyValuePair در magData) if (pair. Value> max. Value) max = جفت؛
بالا. AddPositionOffset (-max. Key) ؛
magSensorMax = max. Value؛
top. TargetPosition = 0؛
while (top. IsMoving) Thread. Sleep (100) ؛
Console. WriteLine ("تراز با موفقیت انجام شد") ؛
}
لیست> magData؛
private void magSensorCollectPositionData (فرستنده شیء ، Phidget22. Events. VoltageRatioInputSensorChangeEventArgs ه) {magData. Add (جدید KeyValuePair (بالا. موقعیت ، e. SensorValue)) ؛ }
private void magSensorStopMotor (فرستنده شیء ، Phidget22. Events. VoltageRatioInputSensorChangeEventArgs e) {
if (top. IsMoving && e. SensorValue> 5) {top. TargetPosition = top. Position - 300 ؛ magSensor. SensorChange -= magSensorStopMotor؛ sawMagnet = true؛ }}
در نهایت ، موتور پایین با ارسال آن به یکی از موقعیت های ظروف مهره کنترل می شود. برای این پروژه ، ما 19 موقعیت داریم. الگوریتم کوتاهترین مسیر را انتخاب می کند و در جهت عقربه های ساعت یا خلاف جهت عقربه های ساعت می چرخد.
private int BottomPosition {get {int posn = (int) bottom. Position٪ stepsPerRev؛ if (posn <0) posn += stepsPerRev؛
return (int) Math. Round (((posn * beadCompartments) / (double) stepsPerRev)) ؛
} }
void خصوصی SetBottomPosition (int posn، bool wait = false) {
posn = posn٪ beadCompartments؛ double targetPosn = (posn * stepsPerRev) / beadCompartments؛
double currentPosn = bottom. Position٪ stepsPerRev؛
double posnDiff = targetPosn - currentPosn؛
// آن را به صورت مراحل کامل نگه دارید
posnDiff = ((int) (posnDiff / 16)) * 16؛
if (posnDiff <= 1600) bottom. TargetPosition += posnDiff؛ else bottom. TargetPosition - = (stepsPerRev - posnDiff) ؛
اگر (صبر کنید)
while (bottom. IsMoving) Thread. Sleep (50) ؛ }
دوربین
OpenCV برای خواندن تصاویر از وب کم استفاده می شود. نخ دوربین قبل از شروع موضوع مرتب سازی اصلی شروع می شود. این موضوع به طور مداوم در تصاویر می خواند ، یک رنگ متوسط را برای یک منطقه خاص با استفاده از Mean محاسبه می کند و یک متغیر رنگ جهانی را به روز می کند. این نخ همچنین از HoughCircles استفاده می کند تا یک مهره یا سوراخ در صفحه بالا را تشخیص دهد تا ناحیه ای را که برای تشخیص رنگ به دنبال آن است ، تصفیه کند. اعداد آستانه و HoughCircles از طریق آزمایش و خطا تعیین می شوند و بستگی زیادی به وب کم ، روشنایی و فاصله دارند.
bool runVideo = true ؛ bool videoRunning = false ؛ ضبط ویدئو؛ موضوع cvThread؛ رنگ تشخیص داده شده تشخیص بولی = false؛ int deteCnt = 0؛
خصوصی void cvThreadFunction () {
videoRunning = false؛
ضبط = VideoCapture جدید (دوربین انتخابی) ؛
با استفاده از (Window window = new Window ("capture")) {
تصویر مات = جدید Mat ()؛ تصویر مات 2 = حصیر جدید ()؛ while (runVideo) {capture. Read (تصویر) ؛ if (image. Empty ()) break؛
اگر (تشخیص)
deteCnt ++؛ else deteCnt = 0؛
if (تشخیص ||| circleDetectChecked || 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) ؛
if (showDetectionImgChecked)
تصویر = thres؛
if (تشخیص || circleDetectChecked) {
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)؛ تصویر دایره (مهره [0]. مرکز ، (int) مهره [0]. Radius ، Scalar جدید (0 ، 0 ، 255) ، 3) ؛ if (مهره [0]. Radius> = 55) {Properties. Settings. Default.x = (اعشاری) مهره [0]. Center. X + (اعشاری) (مهره [0]. Radius / 2) ؛ Properties. Settings. Default.y = (اعشاری) مهره [0]. Center. Y - (اعشاری) (مهره [0]. Radius / 2) ؛ } else {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 rings = thres. HoughCircles (HoughMethods. Gradient، 2، /*thres. Rows/4*/ 5، 200، 100، 60، 180)؛
if (rings. Length> 1) {List xs = rings. Select (c => c. Center. X). ToList ()؛ 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> تصویر. عرض - 15)
medianX = تصویر. عرض - 15؛ if (medianY> image. Hight - 15) medianY = image. Hightight - 15؛
تصویر دایره (medianX ، medianY ، 100 ، Scalar جدید (0 ، 0 ، 150) ، 3) ؛
اگر (تشخیص) {
Properties. Settings. Default.x = medianX - 7؛ Properties. Settings. Default.y = متوسط Y - 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 = حصیر جدید (تصویر ، r) ؛
scalar avgColor = Cv2. Mean (beadSample) ؛ deteColor = Color. FromArgb ((int) avgColor [2] ، (int) avgColor [1] ، (int) avgColor [0]) ؛
تصویر مستطیل (r ، Scalar جدید (0 ، 150 ، 0)) ؛
window. ShowImage (تصویر) ؛
Cv2. WaitKey (1) ؛ videoRunning = true؛ }
videoRunning = false؛
} }
private void cameraStartBtn_Click (فرستنده شیء ، EventArgs e) {
if (cameraStartBtn. Text == "شروع") {
cvThread = موضوع جدید (جدید ThreadStart (cvThreadFunction)) ؛ runVideo = true؛ cvThread. Start ()؛ cameraStartBtn. Text = "توقف"؛ while (! videoRunning) Thread. Sleep (100) ؛
updateColorTimer. Start ()؛
} دیگری {
runVideo = false؛ cvThread. Join ()؛ cameraStartBtn. Text = "شروع"؛ }}
رنگ
اکنون ، ما می توانیم رنگ یک مهره را تعیین کرده و بر اساس آن رنگ تصمیم بگیریم که آن را در کدام ظرف قرار دهیم.
این مرحله به مقایسه رنگ متکی است. ما می خواهیم بتوانیم رنگ ها را از یکدیگر متمایز کنیم تا مثبت کاذب را محدود کند ، اما آستانه کافی را نیز برای محدود کردن منفی های کاذب بگذاریم. مقایسه رنگها در واقع به طرز شگفت انگیزی پیچیده است ، زیرا نحوه ذخیره رنگها به عنوان RGB و نحوه درک انسان از رنگها به طور خطی با هم ارتباط ندارند. برای بدتر شدن اوضاع ، باید به رنگ نوری که یک رنگ در آن مشاهده می شود نیز توجه شود.
الگوریتم پیچیده ای برای محاسبه تفاوت رنگ وجود دارد. ما از CIE2000 استفاده می کنیم ، که اگر 2 رنگ برای انسان غیرقابل تشخیص باشد عددی نزدیک به 1 را نشان می دهد. ما از کتابخانه ColorMine C# برای انجام این محاسبات پیچیده استفاده می کنیم. مقدار DeltaE 5 نشان داده شده است که سازگاری خوبی بین مثبت کاذب و منفی کاذب ارائه می دهد.
از آنجا که اغلب رنگها بیشتر از ظروف است ، آخرین موقعیت به عنوان سطل کچال محفوظ است. من به طور کلی اینها را کنار می گذارم تا بتوانم دستگاه را در پاس دوم اجرا کنم.
لیست
colors = new list ()؛ list colorPanels = new list ()؛ list colorsTxts = لیست جدید ()؛ لیست colorCnts = لیست جدید ()؛
const int numColorSpots = 18؛
const int unknownColorIndex = 18؛ int findColorPosition (رنگ c) {
Console. WriteLine ("پیدا کردن رنگ …") ؛
var cRGB = new 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 = new Rgb ()؛
RGB. R = رنگ . R؛ RGB. G = رنگ . G؛ RGB. B = رنگ . B؛
Double delta = cRGB. مقایسه (RGB ، CieDe2000Comparison جدید ()) ؛
// دو دلتا = deltaE (c ، رنگ ) ؛ Console. WriteLine ("DeltaE (" + i. ToString () + "):" + delta. ToString ()) ؛ if (delta <matchDelta) {matchDelta = delta؛ bestMatch = i؛ }}
if (matchDelta <5) {Console. WriteLine ("پیدا شد! (Posn:" + bestMatch + "Delta:" + matchDelta + ")")؛ بازگشت bestMatch؛ }
if (colors. Count <numColorSpots) {Console. WriteLine ("رنگ جدید!") ؛ رنگها (c) را اضافه کنید ؛ this. BeginInvoke (اقدام جدید (setBackColor) ، شی جدید {colors. Count - 1}) ؛ writeOutColors ()؛ بازگشت (رنگ. تعداد - 1) ؛ } else {Console. WriteLine ("رنگ ناشناخته!")؛ بازگشت ناشناسColorIndex؛ }}
مرتب سازی منطق
عملکرد مرتب سازی همه قطعات را گرد می آورد تا در واقع مهره ها را مرتب کند. این عملکرد در یک موضوع اختصاصی اجرا می شود. حرکت دادن صفحه بالایی ، تشخیص رنگ مهره ، قرار دادن آن در سطل زباله ، اطمینان از تراز بودن صفحه بالا ، شمارش مهره ها و غیره.همچنین با پر شدن سطل آشپزخانه متوقف می شود - در غیر این صورت ما فقط با دانه های سرریز می کنیم.
موضوع colourTestThread ؛ boolean runtest = false؛ void colourTest () {
اگر (! بالا. درگیر)
بالا. درگیر = درست؛
اگر (! پایین. درگیر)
bottom. Angaged = true؛
در حالی که (بدترین) {
nextMagnet (درست) ؛
موضوع خواب (100) ؛ سعی کنید {if (magSensor. SensorValue <(magSensorMax - 4)) alignMotor ()؛ } catch {alignMotor ()؛ }
nextCamera (درست) ؛
تشخیص = درست؛
while (deteCnt <5) Thread. Sleep (25) ؛ Console. WriteLine ("Detect Count:" + detectCnt) ؛ تشخیص = false؛
رنگ c = deteColor؛
this. BeginInvoke (اقدام جدید (setColorDet) ، شی جدید {c}) ؛ int i = findColorPosition (c) ؛
SetBottomPosition (i ، true) ؛
nextHole (درست) ؛ colorCnts ++؛ this. BeginInvoke (اقدام جدید (setColorTxt) ، شی جدید {i}) ؛ موضوع خواب (250) ؛
if (colorCnts [unknownColorIndex]> 500) {
بالا. Engaged = false؛ bottom. Angaged = false؛ runtest = false؛ this. BeginInvoke (اقدام جدید (setGoGreen) ، null) ؛ برگشت؛ }}}
private void colourTestBtn_Click (فرستنده شیء ، EventArgs e) {
if (colourTestThread == null ||! colourTestThread. IsAlive) {colourTestThread = موضوع جدید (جدید ThreadStart (colourTest))؛ runtest = true؛ colourTestThread. Start ()؛ colourTestBtn. Text = "STOP"؛ colourTestBtn. BackColor = Color. Red؛ } else {runtest = false؛ colourTestBtn. Text = "GO"؛ colourTestBtn. BackColor = Color. Green؛ }}
در این مرحله ، ما یک برنامه کاری داریم. برخی از کد ها از مقاله خارج شده اند ، بنابراین برای اجرای آن به منبع نگاه کنید.
جایزه دوم در مسابقه اپتیک
توصیه شده:
مرتب سازی الکترونیکی سکه: 7 مرحله (همراه با تصاویر)
مرتب سازی الکترونیکی سکه: مدت ها پیش ، زمانی که هنوز امکان رفتن به مدرسه وجود داشت ، به ایده جالبی رسیدیم تا دستگاهی بسازیم که به روشی نسبتاً ساده کار می کند - پس از انداختن مقدار مناسب پول ، ما محصول خاصی را صادر خواهد کرد نمیتونم برعکس کنم
ربات مرتب سازی بازیافت: 15 مرحله (همراه با تصاویر)
ربات مرتب سازی بازیافت: آیا می دانستید که میانگین میزان آلودگی در جوامع و مشاغل تا 25 درصد متغیر است؟ این بدان معناست که از هر چهار قطعه بازیافتی که دور می ریزید ، یک مورد بازیافت نمی شود. این به دلیل خطای انسانی در مراکز بازیافت ایجاد می شود. سنتی
کلاه مرتب سازی بابانوئل: 10 مرحله (همراه با تصاویر)
کلاه مرتب سازی بابانوئل: ما همکاری نزدیکی با کارگاه بابانوئل داشته ایم تا این نوآوری را در ارتباطات شیطان یا خوب با شما به ارمغان بیاوریم. اکنون ، می توانید در زمان واقعی بررسی کنید که آیا اعمال خوب و بد شما بر جایگاه شما در لیست شیطان یا نیس سانتا تأثیر گذاشته است! یک پروژه سرگرم کننده
دستگاه مرتب سازی LittleBits Magical Marble: 11 مرحله (همراه با تصاویر)
ماشین مرتب سازی LittleBits Magical Marble: آیا تا به حال خواسته اید تیله ها را مرتب کنید؟ سپس می توانید این دستگاه را بسازید. شما دیگر نیازی نخواهید داشت که یک کیسه مرمر را به هم بزنید! این یک ماشین مرتب سازی جادویی با استفاده از حسگر رنگ Adafruit ، نوع TCS34725 و لئوناردو آردوینو از
دستگاه مرتب سازی پیچ: 7 مرحله (همراه با تصاویر)
دستگاه مرتب سازی پیچ: یک روز در آزمایشگاه (FabLab Moscow) ، همکارم را دیدم که مشغول مرتب سازی یک جعبه کامل پیچ ، مهره ، حلقه و سایر سخت افزارها بود. کنار او ایستادم ، یک ثانیه تماشا کردم و گفتم: & quot؛ این یک کار عالی برای یک ماشین خواهد بود. & quot؛ بعد از یک نگاه سریع