فهرست مطالب:

Robo-Technician: 8 مرحله
Robo-Technician: 8 مرحله

تصویری: Robo-Technician: 8 مرحله

تصویری: Robo-Technician: 8 مرحله
تصویری: Robbery Bob: CHAPTER 8 - BONUS Level 1 , 100% iOS/Android Walkthrough 2024, جولای
Anonim
Robo-Technician
Robo-Technician

برای یک لحظه تصور کنید که شما یکی از فضانوردان فرود آمده بر مریخ هستید. شما باید یک میلیون کار انجام دهید ، نمونه هایی را باید بگیرید ، آزمایش هایی را باید اجرا کنید ، داده هایی را جمع آوری کنید ، اما یک یا دو بار در روز باید در اطراف محل سکونت و/یا ماژول های تحقیقاتی که در آن زندگی و کار می کنید ، تحقیق کنید. ضروری است ، کسی باید اطمینان حاصل کند که چیز خوب است ، همه هزاران قطعه و قطعه کار می کنند و در جای خود هستند. اما اگر یک دستیار خودکار وجود داشته باشد که شما را از انجام برخی وظایف خلاص کند ، چه می شود؟ اگر یک ربات کوچک وجود داشته باشد که بتواند در داخل ماژول ها حرکت کند تا مطمئن شود که همه چیز سر جایش است ، کار می کند و ایمن است.

Robo-Technician برای نجات

در اصل ، این کد Robo-Technician را کنترل می کند زیرا از مسیر رنگ روشن روی زمین پیروی می کند. این مسیر را دنبال می کند تا جایی که در محل اتصال یا پیچشی پیدا می کند ، که باعث می شود عکسی برای پردازش تصویر گرفته شود تا تکنسین روبو بتواند در مورد مکان بعدی تصمیم گیری کند. سنسورهای ضربه و ضربه نور برای محافظت از تکنسین Robo در برابر آسیب کار می کنند و سنسورهای برجستگی زمان عکسبرداری تشخیصی را کنترل می کنند. روی هم رفته ، Robo-Technician به گونه ای طراحی شده است که بر روی ماژول های Mar بزرگنمایی می کند و زمان فضانوردان را در حالی که وظیفه اصلی بازرسی را انجام می دهند آزاد می کند ، و تنها در صورت پیدا کردن مشکلی از انسان برای ورود درخواست می کند.

دوباره به عنوان یک هشدار ، این کار در حال پیشرفت است. کد ، به عنوان موجود ، کار می کند اما دچار سکسکه می شود ، به ویژه از آنجا که چندین برنامه همپوشانی در آن دخیل هستند. همچنین ، برای کار این پروژه در مأموریت واقعی مریخ ، باید یک ربات برای این منظور خاص ساخته شود ، بنابراین دوباره حدس می زنم که این یک "اثبات مفهوم" است.

برای راه اندازی و راه اندازی چند مورد نیاز است. شما به یک برنامه گران قیمت ، بسته های پشتیبانی برای آن برنامه و کمی سابقه در برنامه نویسی نیاز دارید. از آنجا که من دانشجو هستم و برخی از کد طبقه همکف ارائه شده است (برای تمشک pi) ، من به طور خاص در مورد تنظیمات صحبت نخواهم کرد. در زیر می توانید تمام پیوندهای مربوط به آن کد پایه را بیابید. بیایید به لیست مواد برسیم.

سخت افزار

  • رزبری پای (ما از نسخه 3 استفاده کردیم)
  • iRobot
  • نوعی وسیله نگهدارنده برای اتصال رزبری پای به Robo-Technician
  • دوربین رزبری پای (مهم نیست چه نوع باشد ، مادامی که دارای فوکوس خودکار خوب و وضوح تصویر باشد)
  • نوعی استند یا روکش برای نگه داشتن دوربین رو به جلو روی Robo-Technician
  • ماده ای برای استفاده به عنوان نوار ، سفید (یا رنگ بسیار روشن) ، که محکم روی زمین نگه داشته می شود. باید کمی بیشتر از فضای بین دو سنسور صخره ای جلوتر باشد.
  • 4 علامت با متن بسیار بزرگ (با کلمات IMAGE ، RIGHT ، BACK و LEFT روی آنها چاپ شده است)
  • ورق کاغذ رنگی (حداقل سه و ترجیحا قرمز ، سبز و آبی)

نرم افزار

  • Matlab (2018a و 2017b هر دو مورد استفاده قرار گرفتند و به نظر می رسد تفاوت چندانی ندارند)
  • بسته پشتیبانی Raspberry Pi برای Matlab
  • کد Raspberry Pi برای اتصال به Matlab (پیوند به کد منبع ارائه شده در زیر)
  • جعبه ابزار پردازش تصویر برای Matlab (تقریباً نمی توانید این پروژه را بدون جعبه ابزار انجام دهید)
  • اختیاری: Matlab Mobile روی تلفن شما نصب شده است ، که بعداً توضیح خواهم داد

مرحله 1: راه اندازی سخت افزار

ef.engr.utk.edu/ef230-2018-08/projects/roo…

این پیوند کد اصلی است تا اطمینان حاصل شود که iRobot® می تواند به همراه آموزش اولیه با Matlab ارتباط برقرار کند. همانطور که قبلاً گفتم ، من این بخش خاص را پوشش نمی دهم ، زیرا آموزش قبلاً بسیار خوب ارائه شده است. ذکر می کنم که پس از طی مراحل پیوند ، می توانید از دستور "doc" Matlab برای مشاهده اطلاعات موجود استفاده کنید. به طور مشخص:

داک اتاقبا

و یک نکته بسیار مهم دیگر.

هنگامی که فایلها را از پیوند بالا بارگیری می کنید ، آنها را در پوشه ای که در بالا توضیح دادم قرار دهید ، زیرا Matlab نیاز دارد که فایلهای ایجاد شده توسط کاربر در پوشه فعلی کار باشد.

با دور از دسترس بودن ، اجازه دهید به سراغ کد برویم.

مرحله 2: پیدا کردن همه آن سنسورها

پیدا کردن همه آن سنسورها
پیدا کردن همه آن سنسورها
پیدا کردن همه آن سنسورها
پیدا کردن همه آن سنسورها

یک ثانیه وقت بگذارید و iRobot® را بازرسی کنید. خوب است بدانید اینها کجا هستند بنابراین شما ایده ای درباره ورودی هایی که تکنسین روبو دریافت می کند دارید و می توانید بفهمید که چرا این چیز به جای دنبال کردن مسیری که شما تنظیم کرده اید در حال چرخش است (این ممکن است یا ممکن است اتفاق نیفتاده باشد). بدیهی است که سنسور ضربه بزرگ فیزیکی را در جلو مشاهده خواهید کرد. دیدن سنسورهای صخره کمی سخت تر است ، باید آن را بچرخانید و به دنبال چهار پنجره پلاستیکی شفاف و نزدیک لبه جلویی باشید. سنسورهای ضربات نور حتی بیشتر پنهان شده اند ، اما فعلاً کافی است که زنده در نوار مشکی براق در اطراف جلوی iRobot® ، که در جلوی نوار سنسور ضربه فیزیکی قرار دارد ، حرکت کند.

سنسورهای سقوط چرخ وجود دارد ، اما در این پروژه از آنها استفاده نمی شود ، بنابراین ما به آزمایش سنسورها می پردازیم.

مرحله 3: آزمایش تنظیم پارامترها

آزمایش تنظیم پارامترها
آزمایش تنظیم پارامترها

قبل از اینکه بتوانیم Robo-Technician را برای انجام وظیفه خود بفرستیم ، باید ویژگی ها و محدوده های حسگر آن را مشخص کنیم. از آنجایی که هر iRobot® کمی متفاوت است و در طول عمر ربات تغییر می کند ، ما باید بفهمیم که چگونه سنسورها در قسمت هایی که در آن کار می کند چگونه می خوانند. من از نوارهای کاغذ چاپگر سفید استفاده کردم اما هر چیزی که رنگ روشن داشته باشد) روی سطحی که Robo-Technician عمل می کند استفاده کردم.

Matlab را راه اندازی کرده و یک اسکریپت جدید باز کنید. اسکریپت را در همان پوشه ای که من زودتر توصیف کردم ذخیره کنید و نام آن را هرطور که می خواهید بگذارید (هر چند سعی کنید آن را کوتاه نگه دارید ، زیرا نام این فایل نام تابع خواهد بود). ربات را روشن کرده و از تنظیمات متغیرهای roomba در آموزش استفاده کنید و دستورات را در پنجره فرمان تایپ کنید.

اطمینان حاصل کنید که رزبری پای به iRobot® وصل است و کامپیوتر شما به همان اتصال اینترنت متصل است. زمان کمتری را صرف کشیدن موهای خود می کنید تا بفهمید چرا متلب متصل نمی شود

r = roomba (شماره ای که تنظیم کرده اید)

متغیر "r" در این شرایط ضروری نیست ، شما می توانید آن را هرطور که می خواهید بنامید ، اما استفاده از یک متغیر تک حرفی را برای زندگی آسان می کند.

هنگامی که مسیر راه اندازی شد و اتاق با موفقیت متصل شد ، Robo-Technician آینده را در جایی قرار دهید که یک یا دو سنسور صخره در بالای مسیر قرار دارند. بدیهی است که این بدان معناست که دو یا سه مورد دیگر بالای سطح انتخابی شما قرار دارند.

حالا سنسورهای تست را با دستور زیر راه اندازی کنید:

r.test سنسورها

به خاطر داشته باشید که "r" متغیری است که قبلاً تعریف کرده اید ، بنابراین اگر "r" نیست ، "r" را تغییر دهید. به هر تصمیمی که گرفتی این صفحه نمایش سنسور تست را با اطلاعات زیادی نشان می دهد.

برای این پروژه بر روی چراغ های ضربه گیر ، سپرها و قسمت های صخره ای تمرکز کنید. Robo-Technician را به اطراف منتقل کنید تا مطمئن شوید که چگونه سنسورها روی سطوح مختلف تغییر می کنند یا اینکه چقدر باید یک شی برای تغییر مقادیر ligthBumper و غیره نزدیک باشد. این اعداد را در نظر داشته باشید (یا آنها را یادداشت کنید) زیرا به آنها نیاز دارید تا پارامترهای شما را در یک ثانیه تنظیم کنند.

مرحله 4: شروع کد

ابتدا یک تابع ایجاد می کنید. من آن را "راه" نامیدم اما دوباره ، نام لازم نیست ، اما از این به بعد به عنوان "راه" از آن یاد خواهم کرد.

قسمت بالای کد تنظیم برخی از گزینه های ورودی کاربر است. این برنامه لیستی ایجاد می کند که در listdlg مورد استفاده قرار می گیرد و سپس یک کادر محاوره ای لیست نشان می دهد. این به کاربر اجازه می دهد رنگ مسیری را که می خواهد دنبال کند انتخاب کند ، که بعداً مشخص می شود.

list = {'قرمز' ، 'آبی' ، 'سبز'}

problist = {'Casualty، Save Image'، 'Component Out of Place، Save Image'، 'Expected، Continue'} pathcolor = listdlg ('PromptString'، 'Select a Path Color'،… 'SelectionMode'، 'single'، 'ListString' ، list) prob = 0؛ driv = ؛

متغیرهای "prob" و "driv" باید در اینجا اعلام شوند زیرا در داخل حلقه main تابع مورد استفاده قرار می گیرند ، اما دوباره ، اگر می خواهید هر یک از این متغیرها را تغییر نام دهید یا انتخاب لیست را تغییر دهید ، تا زمانی که شما در بقیه کد سازگار هستید.

مرحله 5: بالای حلقه while: سنسورهای ضربه فیزیکی

بالای حلقه while شامل منطق حسگر ضربه فیزیکی است. اساساً ، وقتی Robo-Technician به چیزی برخورد می کند که متوقف می کند (یا برای سنسور ضربه جلو 0.1 متر ارتفاع می یابد) ، سپس خود را برای گرفتن عکس قرار می دهد. اجازه دهید ابتدا قسمت کنترل سرعت و موقعیت را پوشش دهیم.

اگر در مراحل قبل تمام سنسورها را بر روی Robo-Technician آزمایش کرده اید ، می دانید که سنسورهای bump دارای ارزش منطقی (0 یا 1) هستند و صفر نشان دهنده موقعیت طبیعی و فشرده نشده سنسور است. برای کد آن را در نظر داشته باشید.

while true٪ main while loop٪ اطلاعات سپر را دریافت می کند S = r.getBumpers if S.left ~ = 0 r.stop elseif S.right ~ = 0 r.stop elseif S.front ~ = 0 r.stop end

این قسمت اصلی "اگر به چیزی برخورد کرد ، متوقف شوید" است. اگر سنسورها برخورد را تشخیص دهند ، آن را به قسمت بعدی کد منتقل می کند ، که موقعیت تکنسین روبو را برای گرفتن عکس تنظیم می کند.

if S.left ~ = 0٪ if loop اطلاعات سپر را می گیرد و دوربین را برای عکس r تراز می کند r.turnAngle (5) pause (0.5) img = r.getImage٪ عکس می گیرد و تصویر (img)٪ dialog box prob = listdlg (' PromptString '،' یک مانع غیرمنتظره یافت ، لطفاً شناسایی کنید '… ،' SelectionMode '،' single '،' ListString '، problist) elseif S.right ~ = 0 r.turnAngle (-5) مکث (0.5) img = r. getImage image (img) prob = listdlg ('PromptString' ، 'یک موانع غیر منتظره پیدا شد ، لطفاً شناسایی کنید'… ، 'SelectionMode' ، 'single' ، 'ListString' ، problist) elseif S.front ~ = 0 r.moveDistance (- 0.1) مکث (0.5) img = r.get تصویر تصویر (img) prob = listdlg ('PromptString' ، 'یک موانع غیر منتظره پیدا شد ، لطفاً شناسایی کنید'… ، 'SelectionMode' ، 'single' ، 'ListString' ، listlist) پایان

اساساً ، هنگامی که تصویر گرفته می شود ، کادر گفتگوی دیگری با سه گزینه ظاهر می شود. دو گزینه اول عکس را در یک پوشه مشخص ذخیره می کند ، که بعداً به آن می پردازم ، در حالی که گزینه سوم به سادگی جعبه گفتگو را می بندد و در حلقه ادامه می دهد. اگر گزینه ها را به خاطر نمی آورید ، به مرحله قبل نگاه کنید.

حالا من یک قسمت کد را بین قسمت bump sensor و بخش ذخیره عکس قرار دادم. این مقدار lightBumper را می گیرد و سرعت درایو را روی 0.025 متر بر ثانیه تنظیم می کند (بسیار آهسته) ، که در واقع ضروری نیست ، اما باعث می شود که تکنسین روبو به چیزها ضربه بزند و در نهایت سنسورهای ضربه فیزیکی را از بین ببرد.

L = r.getLightBumpers if L.left> 100 || L.leftFront> 100 || L.rightFront> 100 || L.right> 100 driv = 0.025 r.setDrive سرعت (0.025) else driv = 0.1 پایان

این قسمتی خواهد بود که ارزشهایی که قبلاً مشاهده کرده اید (و امیدوارم آنها را یادداشت کرده باشید) به کار می روند

"L. (سمت و جهت سنسور)> 100" بر اساس مقادیری است که من مشاهده کردم ، بنابراین اگر مشاهدات شما متفاوت است ، این اعداد را تغییر دهید. ایده این است که اگر Robo-Technician چیزی را در چند سانتیمتر جلوتر حس کند ، سرعت آن کاهش می یابد ، بیش از این غیر ضروری است.

قسمت بعدی جایی است که عکس ها برای بعدا ذخیره می شوند.

٪ اگر گزینه اول یا دوم در گفتگوی prob انتخاب شده باشد ، اگر prob == 1٪ ذخیره شود اگر حلقه اطلاعات فایل را برای عکس ایجاد کند ، با timestamp t = clock می نویسد. basename = sprintf ('\ img_٪ d_٪ d_٪ d_٪ d_٪ d.png' ، t (1) ، t (2) ، t (3) ، t (4) ، t (5)) ؛ folder = 'E: / UTK / Classes / fall 18 / ef230 / irobot / images'؛ fullFileName = فایل کامل (پوشه ، نام اصلی) ؛ imwrite (img، fullFileName) close شکل 1 مکث (2) elseif prob == 2 t = ساعت؛ basename = sprintf ('\ img_٪ d_٪ d_٪ d_٪ d_٪ d.png' ، t (1) ، t (2) ، t (3) ، t (4) ، t (5)) ؛ folder = 'E: / UTK / Classes / fall 18 / ef230 / irobot / images'؛ fullFileName = فایل کامل (پوشه ، نام اصلی) ؛ imwrite (img، fullFileName) بستن شکل 1 مکث (2) پایان

همه نام فایل ها و مکان هایی که عکس ها در آن ذخیره می شوند اختیاری هستند. من پوشه ای را انتخاب کردم که درون پوشه roomba که در مرحله معرفی ایجاد کردم تو در تو قرار داشته باشد ، اما می تواند هر جایی که شما انتخاب می کنید باشد. همچنین ، عکسها با برچسب زمان ذخیره می شوند ، اما این به ویژه ضروری نیست (اگرچه برای یک ماموریت مریخ به طور فرضی مفید خواهد بود).

با پوشاندن سنسورهای برخورد فیزیکی ، می توانیم روی سنسورهای صخره ای حرکت کرده و مسیر زیر را طی کنیم.

مرحله ششم: دنبال کردن مسیر

کد سنسورهای صخره ای برای مقایسه مقادیر دو مقدار سنسور جلو و دو طرف تنظیم شده است. شما باید این مقادیر را (احتمالاً) بر اساس مقادیر مشاهده شده خود تغییر دهید. شما همچنین احتمالاً باید این مقادیر را بعد از چند بار آزمایش ویرایش کنید و آنها را بر اساس نور محیط ، زمان روز (بسته به میزان روشنایی منطقه آزمایش) یا زمانی که پنجره های سنسور کثیف هستند تغییر دهید.

با این حال ، قبل از رسیدن به کد سنسور صخره ، یک بخش کد کوتاه وجود دارد که من آن را برای پاک کردن برخی از داده های غیر ضروری از Matlab وارد کرده ام. این قسمت مورد نیاز نیست ، اما من از آن برای کاهش حافظه مورد نیاز برای اجرای برنامه استفاده کردم.

clear img clear t clear basename clear fullFileName clear folder

بخش کد بعدی گوشت پروژه است. این به Robo-Technician اجازه می دهد تا مسیر رنگ روشن را که روی زمین قرار گرفته است ، دنبال کند. به طور خلاصه ، سعی می کند خود را هدایت کند تا دو سنسور جلویی صخره بر اساس مقادیر مشاهده شده شما بالاتر از آستانه باشند و به برنامه اجازه می دهد مراحل پردازش تصویر را کمی دیرتر آغاز کند.

C = r.getCliff سنسور٪ if حلقه از یک باند رنگی (سفید) پیروی می کند اگر C.leftFront> 2000 && C.rightFront> 2000٪ راهنمای مسیر مستقیم r.setDriveVelocity (driv) elseif C.leftFront 2000٪ اگر روبات بیش از حد پیش برود سمت چپ r.turnAngle (-2.5) elseif C.leftFront> 2000 && C.rightFront <2000٪ اگر روبات بیش از حد به راست برود r.turnAngle (2.5) elseif C.leftFront <2000 && C. راست جلو 100 || L.leftFront> 100 || L.rightFront> 100 || L.right> 100 img = r.get تصویر پایانی٪ بررسی می کند که آیا خم در مسیر وجود دارد اگر C.left> 2800 && C. <2800 r.turnAngle (2.5) elseif C.left 2800 r.turnAngle (- 2.5) end٪ place holder برای مسیر تشخیص تصویر ('GETTING IMAGE') end end end end

به خاطر داشته باشید که نام متغیرهایی که انتخاب کردم اختیاری است ، اما باز هم فکر می کنم استفاده از متغیرهای تک حرفی در صورت امکان زندگی را آسان می کند

برای توضیح بخش میانی کد ، هنگامی که دو سنسور جلو از لبه مسیر خارج می شوند (وقتی به یک تقاطع می رسد یا هنگامی که به انتهای مسیر می رسد) به نظر می رسد که چیزی در جلوی آن وجود دارد یا خیر. به شما باید یک شیء را در انتهای مسیر یا در هر تقاطعی روی زمین قرار دهید تا این کار را انجام دهد.

پس از گرفتن عکس ، از تشخیص تصویر استفاده می کند تا بفهمد چه باید بکند. در این قسمت کد نیز دارنده مکان وجود دارد:

٪ دارنده مکان برای تشخیص مسیر مسیر disp ('GETTING IMAGE')

من در حال حاضر از این استفاده کردم زیرا می خواستم به طور خاص در مورد پردازش متن و رنگ که در مرحله بعدی است صحبت کنم.

مرحله 7: پردازش تصویر

پردازش تصویر دو بخش دارد. اول تشخیص رنگ است که شدت رنگ را در تصویر محاسبه می کند تا در مورد ادامه یا عدم تشخیص متن تصمیم گیری کند. محاسبات رنگ بر اساس انتخابی است که در همان جعبه گفتگو در ابتدا انجام شد (من از قرمز ، آبی ، سبز استفاده کردم اما شما می توانید هر رنگی را که می خواهید انتخاب کنید ، تا زمانی که مقادیر میانگین شدت رنگ را بتوان با دوربین رزبری پای).

img = r.getImage img = imcrop (img، [0 30 512 354]) imgb = imcrop (img، [0 30 512 354]) imgt = imcrop (img، [0 30 512 354] 0) قرمز = میانگین (میانگین (imgb (:،: ، 1))) ؛ g = میانگین (میانگین (imgb (:،: ، 2))) ؛ b = میانگین (میانگین (imgb (:،: ، 3))) ؛

این بررسی شدت است. این مورد در بخش بعدی مورد استفاده قرار می گیرد تا تصمیم بگیرد که می خواهد چه کاری انجام دهد.

if red> g && red> b if pathcolor == 1 imgc = imcrop (img، [0 30 512 354]) R = ocr (img) if R. کلمات {1} == تصویر || R. Words {2} == IMAGE || R. Words {3} == IMAGE t = ساعت ؛ basename = sprintf ('\ img_٪ d_٪ d_٪ d_٪ d_٪ d.png' ، t (1) ، t (2) ، t (3) ، t (4) ، t (5)) ؛ folder = 'E: / UTK / Classes / fall 18 / ef230 / irobot / images'؛ fullFileName = فایل کامل (پوشه ، نام اصلی) ؛ imwrite (img، fullFileName) مکث (2) elseif R. Words {1} == RIGHT || R. Words {2} == RIGHT || R. Words {3} == RIGHT r.turnAngle (-75) elseif R. Words {1} == چپ || R. Words {2} == چپ || R. Words {3} == LEFT r.turnAngle (75) elseif R. Words {1} == BACK || R. Words {2} == BACK || R. Words {3} == BACK r.turnAngle (110) end else r.turnAngle (110) انتهای پایان

این بخش تصمیم می گیرد که آیا رنگی که در اولین کادر محاوره ای انتخاب شده است با رنگی که دوربین می بیند مطابقت دارد یا خیر. اگر این کار را انجام دهد ، تشخیص متن را اجرا می کند. به نظر می رسد که کدام کلمه (IMAGE ، BACK ، RIGHT یا LEFT) ظاهر می شود و سپس یا می چرخد (برای راست و چپ) ، به دور خود می چرخد (برای عقب) یا عکس می گیرد و آن را به همان شیوه قبلی ذخیره می کند.

من فقط یک قسمت از کد را برای رنگ های مختلف ارائه کرده ام

برای اینکه کد بتواند آبی و سبز را تشخیص دهد ، کافی است کد را کپی کرده و بررسی منطقی را در بالای بخش تغییر دهید و "pathcolor == (number)" را مطابق با انتخاب رنگ از کادر گفتگوی بالا (برای همانطور که نمایش داده می شود ، آبی 2 و سبز 3 خواهد بود).

مرحله 8: محصول نهایی

محصول نهایی
محصول نهایی

اکنون تکنسین روبو باید بر روی ماژول های مأموریت مریخ زوم کرده و هنگامی که هر چیزی در جای خود نیست به فضانوردان گزارش دهد.

به یاد داشته باشید ، همه سنسورهای صخره ای و مقادیر lightBumper باید به مقادیر مشاهده شده شما تغییر کند. همچنین ، از تجربیات من بهتر است این پروژه را روی یک کف رنگ تیره آزمایش کنم و اگر آن کف بازتابنده نباشد ، حتی بهتر است. این امر باعث افزایش تضاد بین مسیر و کف می شود که احتمال اینکه Robo-Technician آن را به درستی دنبال کند افزایش می دهد.

امیدوارم از راه اندازی یک یاور کوچک برای ماموریت مریخ لذت برده باشید و از ساختن آن لذت ببرید.

توصیه شده: