مسیر یادگیری ROS 2  ·  کتاب آموزشی تصویری

فصل اول: معماری ROS 2

ستون فقرات هر ربات — از Node تا Launch File
مخاطب: مبتدی تا مهندس رباتیک
پیش‌نیاز: هیچ تجربه قبلی با ROS لازم نیست
پروژه پیوسته: ربات ARCHO
زمان مطالعه: ۹۰ تا ۱۲۰ دقیقه
در این فصل چه می‌خوانیم ۱.۱تصویر بزرگ — چرا معماری قبل از کد؟ ۱.۲Node — واحد زنده سیستم ۱.۳Topic و Message — جریان پیوسته داده ۱.۴Service — درخواست و پاسخ ۱.۵Action — عملیات طولانی و قابل لغو ۱.۶مقایسه سه روش ارتباط ۱.۷Parameter — تنظیم رفتار بدون تغییر کد ۱.۸Launch File — راه‌انداز کل سیستم ۱.۹نقشه کامل معماری ۱.۱۰جمع‌بندی، واژه‌نامه و تمرین‌ها

۱.۱تصویر بزرگ: چرا معماری قبل از کد؟

تصور کن قرار است یک ربات بسازی به اسم ARCHO (آرکو)؛ ربات کوچکی که باید بین قفسه‌های بلند یک انبار حرکت کند، مسیرش را با یک حسگر لیزری پیدا کند، و اگر انسانی جلویش سبز شد، بایستد. اولین وسوسه این است که یک فایل کد باز کنی و شروع کنی به نوشتن: بخوان از دوربین، پردازش کن، بفرست به موتور. بعد از چند ساعت متوجه می‌شوی همه‌چیز در یک فایل هزار خطی گیر کرده، هیچ بخشی را نمی‌توانی جدا تست کنی، و اگر یک خط کد خراب شود، کل ربات یخ می‌زند. این دقیقاً همان مسیری است که بیشتر آموزش‌های ROS 2 طی می‌کنند: مستقیم می‌روند سراغ دستورهای ترمینال — این را نصب کن، آن را اجرا کن — و یاد می‌گیری دستور بزنی، بدون اینکه بدانی چرا.

این کتاب، و این فصل به‌طور خاص، مسیر دیگری را انتخاب می‌کند. قبل از اینکه حتی یک خط کد برای ARCHO بنویسیم، می‌نشینیم و نقشه‌اش را می‌کشیم: چه تکه‌هایی لازم داریم، هرکدام چه کاری انجام می‌دهند، و چطور با هم حرف می‌زنند. این دقیقاً همان کاری است که یک مهندس رباتیک واقعی قبل از نوشتن اولین خط کد انجام می‌دهد. خبر خوب این است که کسانی که ROS 2 را ساخته‌اند، سال‌ها پیش همین مسئله را حل کرده‌اند و تقریباً تمام سیستم — از یک ربات ساده جاروبرقی تا بازوی رباتیک صنعتی — را روی همین چند مفهوم بنا کرده‌اند:

💡 ایده ساده

اگر پنج مفهوم Node، Topic، Message، Service و Action را خوب یاد بگیری، حدود ۷۰٪ از ROS 2 را فهمیده‌ای. بقیه فصل‌های کتاب فقط جزئیات و ابزارهای اطراف همین هسته هستند.

در پایان این فصل، این هفت مفهوم پایه را می‌شناسی و می‌توانی برای هر Node در هر پروژه‌ای این چهار سؤال را جواب بدهی:

نقشه یادگیری این فصل به این شکل است — هر جعبه روی جعبه قبلی خودش ساخته می‌شود:

flowchart RL A["Node
واحد اجرایی مستقل"] --> B["Topic + Message
جریان پیوسته داده"] A --> C["Service
درخواست / پاسخ"] A --> D["Action
عملیات طولانی"] A --> E["Parameter
تنظیم رفتار"] B --> F["Launch File
راه‌انداز کل سیستم"] C --> F D --> F E --> F F --> G["فصل ۲: محیط توسعه
Workspace و Package"] style A fill:#2f7de8,stroke:#ffffff,color:#0b1220,font-weight:bold style F fill:#d98c19,stroke:#ffffff,color:#0b1220,font-weight:bold style G fill:#0f9d78,stroke:#ffffff,color:#0b1220,font-weight:bold
🌍 مثال واقعی: داستان ربات ARCHO

در طول این کتاب، تمام مفاهیم را روی یک پروژه ثابت پیاده می‌کنیم: ARCHO، یک ربات متحرک ساده که قرار است در یک انبار بزرگ حرکت کند، محیط را با LiDAR ببیند و مسیر خودش را پیدا کند. هر فصل یک تکه از این ربات را کامل‌تر می‌کند. در همین فصل، فقط اسکلت ارتباطی ARCHO را طراحی می‌کنیم؛ هنوز کدی نمی‌نویسیم.

۱.۲Node — واحد زنده سیستم

قبل از ROS، این مشکل چگونه حل می‌شد؟

برگردیم به ARCHO و همان فایل هزار خطی. فرض کن سه هفته روی آن کار کرده‌ای: خواندن دوربین، پردازش تصویر، محاسبه مسیر، کنترل موتور، همه در یک برنامه، در یک پردازش (process). تا وقتی پروژه کوچک است همه‌چیز خوب پیش می‌رود. اما یک روز صبح، بخش پردازش تصویر کرش می‌کند و کل ربات یخ می‌زند — حتی موتورها هم دیگر جواب نمی‌دهند، چون همه در یک برنامه گیر افتاده‌اند. بدتر از آن، وقتی می‌خواهی فقط الگوریتم مسیریابی را تست کنی، مجبوری کل برنامه غول‌پیکر را کامپایل و اجرا کنی، فقط برای دیدن اینکه یک خط محاسبه درست کار می‌کند یا نه. این همان دیواری است که تقریباً هر کسی که بدون ROS شروع می‌کند، دیر یا زود به آن می‌خورد.

راه‌حل ROS: تقسیم به واحدهای مستقل

ROS این مسئله را با مفهومی به نام Node حل می‌کند. هر Node یک برنامه کوچک و مستقل است که فقط یک مسئولیت مشخص دارد. یکی فقط از دوربین می‌خواند، یکی فقط مسیر را محاسبه می‌کند، یکی فقط به موتورها فرمان می‌دهد.

📖 تعریف Node

Node یک پردازش (process) مستقل در ROS 2 است که یک وظیفه مشخص انجام می‌دهد و برای انجام آن با سایر Nodeها از طریق Topic، Service، Action یا Parameter ارتباط برقرار می‌کند.

🧠 تشبیه ساده

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

در یک ربات متحرک واقعی، معمولاً ده‌ها Node به‌صورت هم‌زمان در حال اجرا هستند:

Nodeمسئولیت
camera_nodeخواندن تصویر از دوربین و انتشار آن
lidar_nodeخواندن داده فاصله‌سنج لیزری
slam_nodeساخت نقشه محیط از روی داده حسگرها
navigation_nodeمحاسبه مسیر حرکت به هدف
motor_controller_nodeتبدیل فرمان سرعت به سیگنال موتور
⚠️ اشتباه رایج مبتدی‌ها

خیلی از تازه‌کارها فکر می‌کنند باید همه منطق ربات را در یک Node بزرگ بنویسند تا «ساده‌تر» باشد. نتیجه برعکس است: دیباگ کردن سخت می‌شود، تست کردن جداگانه هر بخش غیرممکن می‌شود، و اگر یک بخش کرش کند کل ربات از کار می‌افتد. قانون طلایی: هر Node، یک مسئولیت.

🔧 دید مهندسی

از دید معماری نرم‌افزار، Node در ROS 2 دقیقاً همان نقشی را دارد که یک microservice در معماری سرویس‌های وب دارد: واحد کوچک، مستقل، قابل جایگزینی، با یک قرارداد ارتباطی مشخص با بقیه سیستم. این شباهت تصادفی نیست — هر دو برای حل یک مسئله مشترک طراحی شده‌اند: کاهش وابستگی بین بخش‌های یک سیستم بزرگ.

تمرین آسان

اگر بخواهی یک ربات ساده جاروبرقی طراحی کنی، چه Nodeهایی احتمالاً لازم داری؟ حداقل چهار مورد نام ببر و مسئولیت هرکدام را در یک جمله بنویس.

۱.۳Topic و Message — جریان پیوسته داده

مشکل: Nodeها چگونه با هم حرف بزنند؟

خب، حالا ARCHO را به چند Node مستقل تقسیم کردیم — یکی برای دوربین، یکی برای پردازش تصویر، یکی برای موتور. اما یک مشکل تازه پیدا شده: این Nodeها در دنیای خودشان تنها هستند. Node دوربین هر لحظه یک تصویر تازه می‌گیرد، اما اگر هیچ راهی برای رساندن آن به Node پردازش تصویر نداشته باشد، این تصویر همان‌جا در حافظه دوربین می‌ماند و به دردی نمی‌خورد. باید راهی پیدا کنیم که این جزیره‌های مستقل بتوانند با هم حرف بزنند. اولین و رایج‌ترین راه ارتباط در ROS 2، Topic است.

📖 تعریف Topic و Message

Topic یک کانال نام‌گذاری‌شده برای انتقال داده است. یک Node می‌تواند روی یک Topic اطلاعات منتشر (Publish) کند و هر Node دیگری می‌تواند به همان Topic مشترک (Subscribe) شود و اطلاعات را دریافت کند. هر بسته داده‌ای که روی یک Topic فرستاده می‌شود را Message می‌گویند.

🧠 تشبیه ساده: مانیتور آشپزخانه

در یک رستوران، آشپز هر غذایی که آماده می‌شود را روی یک مانیتور نمایش می‌دهد. آشپز نمی‌داند چه کسی دارد نگاه می‌کند — شاید گارسون، شاید مدیر، شاید هیچ‌کس. او فقط دائماً وضعیت را منتشر می‌کند. این دقیقاً رفتار یک Publisher روی یک Topic است.

Camera Node Publisher Topic: /image sensor_msgs/Image Vision Node Subscriber ۳۰ بار در ثانیه، بدون توقف، بدون درخواست قبلی هر پیام روی این کانال یک Message از نوع sensor_msgs/Image است
شکل ۱.۱ — یک Publisher (دوربین) پیوسته Message منتشر می‌کند و یک یا چند Subscriber (پردازش تصویر) آن‌ها را دریافت می‌کنند.

چند نکته مهم درباره Topic که باید از همین ابتدا در ذهن بماند:

🌍 مثال واقعی از ARCHO

در ربات ARCHO، Node مربوط به LiDAR روی Topic به نام /scan اطلاعات فاصله را با نوع پیام sensor_msgs/LaserScan منتشر می‌کند. همزمان، هم Node نقشه‌سازی (SLAM) و هم Node تشخیص مانع به همین یک Topic مشترک می‌شوند — بدون اینکه LiDAR اصلاً بداند چند نفر دارند به آن گوش می‌دهند.

⚠️ اشتباه رایج

بسیاری از تازه‌واردها فکر می‌کنند همه نوع ارتباط بین Nodeها باید از طریق Topic انجام شود. Topic فقط برای جریان پیوسته داده مناسب است. اگر بخواهی از یک Node چیزی بپرسی و منتظر یک پاسخ مشخص باشی، Topic ابزار درستی نیست — همان‌طور که در بخش بعد می‌بینیم.

تمرین متوسط

فرض کن یک IMU (حسگر شتاب و جهت) روی ربات نصب کرده‌ای که هر ۱۰۰ میلی‌ثانیه یک بار داده جدید تولید می‌کند. آیا این یک Topic خوب است یا نه؟ دلیل خودت را در دو خط بنویس.

۱.۴Service — درخواست و پاسخ

مشکل: گاهی فقط یک جواب مشخص می‌خواهیم

حالا که ARCHO دارد با Topic اطلاعات دوربینش را پخش می‌کند، یک اتفاق جالب می‌افتد: تیم توسعه، هیجان‌زده از این ابزار تازه، شروع می‌کند همه‌چیز را با Topic حل کردن. حتی برای ذخیره نقشه، حتی برای خواندن باتری. نتیجه؟ کانال‌های بی‌شماری که هر لحظه پیام‌های بی‌فایده می‌فرستند. برای فهمیدن اینکه چرا این اشتباه است، بیا وارد یک رستوران شویم. اگر بخواهی وضعیت آشپزخانه را به‌صورت زنده ببینی، دقیقاً مثل یک Topic است — اطلاعات دائماً در حال پخش شدن است. اما اگر بخواهی بگویی «یک پیتزا لطفاً»، اتفاق دیگری می‌افتد: تو یک درخواست مشخص می‌فرستی و منتظر یک پاسخ مشخص می‌مانی. این دیگر Topic نیست؛ این یک درخواست و پاسخ (Request / Response) است. ROS برای دقیقاً همین کار، Service را ساخته است.

📖 تعریف Service

Service یک ارتباط دوطرفه است که در آن یک Node (Client) یک درخواست (Request) ارسال می‌کند و Node دیگری (Server) آن را پردازش کرده و یک پاسخ مشخص (Response) برمی‌گرداند.

Client Navigation Node Server Map Server Request: filename = warehouse_map Response: success = true Client منتظر می‌ماند تا Response برسد؛ سپس ارتباط تمام می‌شود
شکل ۱.۲ — الگوی Service: یک درخواست، یک پاسخ، تمام.

چه زمانی Topic، چه زمانی Service؟

معیارTopic مناسب است اگر...Service مناسب است اگر...
نوع دادهدائماً در حال تغییر است (دوربین، LiDAR، IMU)فقط هنگام نیاز خوانده یا اجرا می‌شود
الگوی زمانیجریان پیوسته و تکرارشوندهیک‌بار، بر اساس درخواست
مثالسرعت لحظه‌ای، تصویر دوربین، Odometryذخیره نقشه، Reset کردن Encoder، خواندن درصد باتری
انتظار پاسخPublisher منتظر پاسخ نمی‌ماندClient منتظر Response مشخص می‌ماند
🌍 مثال واقعی: باتری ربات

آیا لازم است ربات هر ثانیه درصد باتری خودش را برای همه منتشر کند؟ نه — این کار بیهوده است و پهنای باند شبکه را اشغال می‌کند. به‌جایش، وقتی لازم شد (مثلاً وقتی رابط کاربری باز می‌شود)، یک درخواست Get Battery Status فرستاده می‌شود و Server یک بار پاسخ 78% را برمی‌گرداند.

در پروژه ARCHO، نمونه‌هایی از Serviceهای واقعی این‌ها خواهند بود:

دیدن Service از خط فرمان

وقتی وارد فصل‌های عملی شویم، این دستورها روزمره‌ترین ابزار تو خواهند بود:

ros2 service list
ros2 service type /clear
ros2 interface show std_srvs/srv/Empty
ros2 service call /clear std_srvs/srv/Empty "{}"

خروجی std_srvs/srv/Empty فقط یک خط --- است، چون این نوع Service هیچ داده‌ای در Request یا Response ندارد؛ فراخوانی آن فقط باعث اجرای یک عمل می‌شود، دقیقاً مثل فشردن یک دکمه. در مقابل، example_interfaces/srv/AddTwoInts دو عدد صحیح می‌گیرد (a و b) و مجموع آن‌ها (sum) را برمی‌گرداند.

تمرین متوسط

فرض کن به ربات می‌گویی «برو به اتاق شماره ۵». آیا این یک Topic است؟ آیا یک Service است؟ اگر جواب هر دو منفی است، فکر کن چرا — این سؤال دقیقاً ما را به بخش بعدی می‌برد.

۱.۵Action — عملیات طولانی و قابل لغو

یک روز، یکی از اعضای تیم ARCHO یک سؤال ساده می‌پرسد که همه را برای چند دقیقه ساکت می‌کند: «اگر بخواهیم به ربات بگوییم برو به قفسه شماره ۵، از کدام ابزار استفاده کنیم؟» همه فکر می‌کنند جواب Service است — یک درخواست، یک پاسخ. اما وقتی دقیق‌تر نگاه می‌کنند، متوجه می‌شوند فرمان «برو به قفسه ۵» نه Topic است و نه Service. چرا؟ چون این کار ممکن است چند دقیقه طول بکشد: حرکت باید شروع شود، پیشرفت باید گزارش شود، احتمالاً در مسیر مانعی پیدا می‌شود، شاید لازم باشد عملیات لغو شود، و در پایان باید بدانیم موفق بوده یا نه. Service فقط یک پاسخ کوتاه می‌دهد و منتظر پایان یک کار طولانی نمی‌ماند. برای این دسته از کارها، ROS 2 مفهوم سومی به نام Action را معرفی کرده است.

🧠 تشبیه ساده: سفارش تاکسی آنلاین

وقتی از یک اپلیکیشن تاکسی درخواست سفر می‌دهی، فقط یک پاسخ نمی‌گیری. اول می‌گویند راننده قبول کرد، بعد می‌گویند راننده ۳ کیلومتر با تو فاصله دارد، بعد می‌گویند راننده رسید، بعد سفر شروع می‌شود، و در پایان سفر تمام می‌شود. این دقیقاً همان چیزی است که Action در ROS 2 فراهم می‌کند: یک هدف، چند به‌روزرسانی پیشرفت، و یک نتیجه نهایی.

📖 تعریف Action

Action یک عملیات طولانی‌مدت است که می‌توان پیشرفت آن را در حین اجرا مشاهده کرد، در صورت نیاز آن را لغو کرد، و در پایان نتیجه نهایی را دریافت کرد. هر Action از سه بخش تشکیل شده است: Goal (هدف)، Feedback (گزارش پیشرفت) و Result (نتیجه نهایی).

sequenceDiagram participant C as Client (Navigation) participant S as Action Server (Motion Controller) C->>S: Goal: Move To Kitchen S-->>C: Feedback: 20% S-->>C: Feedback: 50% S-->>C: Feedback: 80% Note over C,S: در هر لحظه Client می‌تواند Cancel Goal بفرستد S-->>C: Result: Succeeded

شکل ۱.۳ — چرخه کامل یک Action: از Goal تا Result، با چند Feedback در میانه راه.

بخش Actionنقشمثال
Goalهدفی که باید انجام شودtarget_x: 5.2, target_y: 8.1
Feedbackگزارش وضعیت در حین اجراdistance_remaining: 2.3
Resultنتیجه نهایی پس از پایانsuccess: true
🌍 مثال واقعی: بازوی رباتیک

فرض کن بازوی ربات باید یک پیچ را ببندد؛ این کار ممکن است ۲۰ ثانیه طول بکشد. اگر از Service استفاده می‌کردیم، فقط یک درخواست و یک پاسخ داشتیم و هیچ اطلاعاتی از وسط کار نمی‌دیدیم. با Action، مراحل را به‌صورت زنده دنبال می‌کنیم: Approaching → Aligning → Tightening → Finished. اگر شیء در میانه راه بیفتد، Result برابر Failed برمی‌گردد — نه یک سکوت مبهم.

یکی از معروف‌ترین Actionهای دنیای واقعی ROS 2، NavigateToPose در بسته Nav2 است. تقریباً تمام ربات‌های متحرک مبتنی بر Nav2 از همین Action برای رفتن به یک نقطه هدف استفاده می‌کنند: Client می‌گوید «برو اینجا»، Server مراحل Planning… → Moving… → Avoiding Obstacle… → Arrived را گزارش می‌دهد.

⚠️ اشتباه رایج

قابلیت مهمی که Action دارد و Topic و Service ندارند، امکان لغو (Cancel) است. اگر ربات در حال حرکت باشد و ناگهان انسانی جلوی آن قرار بگیرد، می‌توان همان لحظه Cancel Goal فرستاد و ربات متوقف می‌شود. خیلی از طراحی‌های ابتدایی این قابلیت را فراموش می‌کنند و بعداً برای اضافه‌کردن «دکمه توقف اضطراری» به مشکل می‌خورند.

تمرین سخت‌تر

یک قهوه‌ساز هوشمند را تصور کن. توضیح بده رفتار آن اگر با Topic ساخته شود چگونه است، اگر با Service ساخته شود چگونه است، و چرا Action بهترین انتخاب است. حداقل یک محدودیت هرکدام را بنویس.

۱.۶مقایسه سه روش ارتباط

یک تصویر ذهنی که باید همیشه یادت بماند: Topic مثل رادیو است، Service مثل تماس تلفنی با بانک، و Action مثل سفارش تاکسی آنلاین.

Topic مثل رادیو 📻 Publish Publish Publish Publish... جریان پیوسته، بدون پاسخ Service مثل تماس با بانک ☎️ Request → ← Response یک سؤال، یک جواب، تمام Action مثل سفارش تاکسی 🚕 Goal → Feedback 20% Feedback 60% ← Result: Done هدف، پیشرفت، نتیجه، قابل لغو
شکل ۱.۴ — سه الگوی ارتباطی ROS 2 در کنار هم.
معیارTopicServiceAction
الگوPublish / SubscribeRequest / ResponseGoal / Feedback / Result
مدت زمانپیوستهلحظه‌ای و کوتاهطولانی
گزارش پیشرفتندارد (خودش نوعی جریان است)ندارددارد
قابل لغوخیرخیربله
مثالدوربین، LiDAR، IMUReset، Save، CalibrateNavigate، Pick Object
مناسب برایحسگرها و جریان‌های دادهعملیات آنی و تنظیماتوظایف رباتیک بلندمدت
🔧 دید مهندسی: تصمیم طراحی

وقتی داری معماری یک Node جدید طراحی می‌کنی، این سؤال را از خودت بپرس: «آیا این داده دائماً در حال تغییر است، یا فقط بر اساس یک محرک مشخص اتفاق می‌افتد؟» اگر پیوسته است → Topic. اگر لحظه‌ای و کوتاه است → Service. اگر طولانی و نیازمند گزارش میانی است → Action. انتخاب اشتباه، معمولاً یا شبکه را با پیام‌های بی‌فایده پر می‌کند (Topic به‌جای Service) یا رابط کاربری را در حالت «قفل‌شده و بدون بازخورد» نگه می‌دارد (Service به‌جای Action).

۱.۷Parameter — تنظیم رفتار بدون تغییر کد

🧠 تشبیه ساده: تنظیمات دوربین DSLR

روی یک دوربین حرفه‌ای، تنظیماتی مثل ISO، سرعت شاتر و دیافراگم وجود دارد. برای تغییر ISO لازم نیست فریمور دوربین را دوباره برنامه‌ریزی کنی؛ فقط یک تنظیم را عوض می‌کنی. Parameter در ROS 2 دقیقاً همین نقش را دارد.

مشکل بدون Parameter

تیم ARCHO حالا می‌داند کِی از Topic استفاده کند و کِی از Service و Action. اما یک مشکل کوچک‌تر و آزاردهنده‌تر هنوز باقی مانده. یکی از مهندس‌ها سرعت پیش‌فرض ربات را مستقیم در کد نوشته: robot_speed = 0.5;. یک ماه بعد، وقتی ربات را در یک راهروی باریک‌تر آزمایش می‌کنند، می‌خواهند این مقدار را به ۰.۷ تغییر بدهند. بدون Parameter باید فایل را باز کنی، کد را ویرایش کنی، دوباره Build کنی و دوباره اجرا کنی — برای یک تغییر کوچک، کل چرخه توسعه تکرار می‌شود. با Parameter، کد ثابت می‌ماند و فقط مقدار تنظیمات عوض می‌شود.

📖 تعریف Parameter

Parameter یک مقدار قابل تنظیم است که رفتار یک Node را بدون تغییر کد کنترل می‌کند. Parameterها معمولاً در فایل‌های YAML نگهداری می‌شوند تا بتوان یک نرم‌افزار را روی چند ربات مختلف، بدون بازنویسی کد، به کار برد.

# camera_params.yaml
camera_node:
  ros__parameters:
    fps: 30
    width: 1280
    height: 720
🌍 مثال واقعی: سه اندازه از یک ربات

فرض کن همین نرم‌افزار حرکتی را روی سه ربات نصب می‌کنی: ربات کوچک با max_speed = 0.4، ربات متوسط با max_speed = 0.8، ربات بزرگ با max_speed = 1.5. کد یکی است؛ فقط Parameter فرق می‌کند. در پروژه ARCHO، Node به نام motor_controller_node پارامترهایی مثل wheel_radius، wheel_base و max_velocity دارد. اگر قطر چرخ عوض شود، فقط مقدار wheel_radius را تغییر می‌دهیم؛ الگوریتم کنترل دست‌نخورده می‌ماند.

Parameter در برابر Topic — تفاوت اصلی

یک تشبیه ساده: سرعت لحظه‌ای ماشین (۸۰ کیلومتر بر ساعت) دائماً تغییر می‌کند — این مثل Topic است. اما تنظیم Cruise Control روی ۱۰۰ کیلومتر بر ساعت، شاید تا چند ساعت ثابت بماند — این مثل Parameter است. Topic داده جاری را منتقل می‌کند؛ Parameter تنظیمات نسبتاً ثابت را نگه می‌دارد.

ros2 param list
ros2 param get /camera_node fps
ros2 param set /camera_node fps 60
تمرین آسان

برای Node مربوط به LiDAR در ربات ARCHO، سه Parameter پیشنهاد بده که منطقی باشد (مثلاً محدوده تشخیص، نرخ اسکن). برای هرکدام بگو چرا این مقدار باید Parameter باشد، نه بخشی ثابت از کد.

۱.۸Launch File — راه‌انداز کل سیستم

🧠 تشبیه ساده: اسکریپت شروع کار

هر روز صبح که سر کار می‌روی، چند برنامه را باز می‌کنی: مرورگر، ایمیل، ابزار پیام‌رسانی، ویرایشگر کد. اگر هر روز یکی‌یکی بازشان کنی، بعد از یک هفته خسته می‌شوی. به‌جایش یک اسکریپت (start_work.sh) می‌سازی که همه را با هم اجرا کند. Launch File دقیقاً همین کار را برای ROS 2 انجام می‌دهد.

مشکل بدون Launch

حالا ARCHO هفت، هشت Node مستقل دارد که هرکدام با Topic، Service، Action و Parameter خودشان کار می‌کنند. روز آزمایش که می‌رسد، یکی از مهندس‌ها باید هرکدام را در یک پنجره ترمینال جدا، دستی، اجرا کند: اول دوربین، بعد LiDAR، بعد IMU، بعد SLAM، بعد ناوبری، بعد کنترلر موتور، بعد RViz. اگر ترتیب اجرا اشتباه شود یا یکی را فراموش کند، ربات درست کار نمی‌کند. حالا تصور کن این عدد به‌جای هفت، صد و پنجاه Node باشد — دقیقاً همین اتفاق در یک ربات صنعتی واقعی می‌افتد. یک ربات واقعی معمولاً این Nodeها را هم‌زمان لازم دارد: camera_node، lidar_node، imu_node، slam_node، navigation_node، motor_controller و rviz. اجرای دستی هرکدام با ros2 run برای یک ربات صنعتی با صدها Node عملاً غیرممکن است.

📖 تعریف Launch File

Launch File یک فایل پایتون است که مشخص می‌کند چه Nodeهایی، با چه Parameterهایی، در چه ترتیبی و تحت چه شرایطی اجرا شوند. Launch فقط یک اسکریپت اجرای پشت‌سرهم نیست؛ یک موتور (Engine) با منطق شرطی است.

یک فایل Launch می‌تواند موارد زیر را انجام دهد:

🌍 مثال واقعی: شبیه‌سازی در برابر ربات واقعی

فرض کن پروژه هم حالت Simulation دارد و هم حالت اجرا روی ربات واقعی. با یک شرط ساده در Launch File، اگر simulation = true باشد، Gazebo و RViz و یک کنترلر شبیه‌سازی‌شده اجرا می‌شوند؛ اگر simulation = false باشد، دوربین واقعی، LiDAR واقعی و درایور موتور واقعی اجرا می‌شوند — همان پروژه، بدون تغییر کد.

# robot.launch.py (فقط برای آشنایی، جزئیات کامل در فصل‌های عملی)
from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(package="camera_driver", executable="camera_node"),
        Node(package="lidar_driver",  executable="lidar_node"),
        Node(package="rviz2",         executable="rviz2"),
    ])

و اجرای همه این‌ها با یک دستور:

ros2 launch my_robot robot.launch.py

ساختار پوشه‌بندی یک پروژه واقعی ROS 2

وقتی داخل تقریباً هر پروژه حرفه‌ای ROS 2 را باز کنی، همین الگو تکرار می‌شود:

my_robot/
├── launch/
│   ├── robot.launch.py
│   ├── simulation.launch.py
│   └── navigation.launch.py
├── config/
│   ├── controller.yaml
│   ├── nav2.yaml
│   └── camera.yaml
├── urdf/
├── rviz/
├── worlds/
├── src/
└── package.xml
🔧 دید مهندسی

این نکته را از همین فصل با خودت ببر: ROS فقط برنامه‌نویسی نیست. ROS ترکیبی است از معماری نرم‌افزار (Node، Topic، Service، Action)، ارتباطات (پیام‌رسانی بین فرایندها)، استقرار (Deployment) (Launch File) و پیکربندی (Configuration) (Parameter و YAML). کسی که فقط کد می‌نویسد ولی این چهار لایه را نمی‌شناسد، هیچ‌وقت یک سیستم رباتیک واقعی را کامل نمی‌فهمد.

تمرین سخت‌تر

برای ربات ARCHO یک فهرست از Nodeهایی که باید در یک Launch File واحد اجرا شوند بنویس (حداقل پنج Node)، و مشخص کن کدام‌یک فقط در حالت Simulation و کدام‌یک فقط روی سخت‌افزار واقعی باید اجرا شوند.

۱.۹نقشه کامل معماری

حالا که هر تکه را جداگانه دیدیم، بیایید همه را کنار هم بگذاریم. این نموداری است که باید تا آخر کتاب در ذهنت بماند — ستون فقرات ROS 2:

flowchart TB N["Node"] N --> T["Topic
Streaming"] N --> S["Service
Request / Reply"] N --> A["Action
Long Tasks"] T --> M["Message"] S --> RQ["Request"] S --> RS["Response"] A --> G["Goal"] A --> F["Feedback"] A --> R["Result"] P["Parameter
تنظیم رفتار Node"] -.-> N L["Launch File
راه‌انداز کل سیستم"] --> N L --> P style N fill:#2f7de8,stroke:#ffffff,color:#0b1220,font-weight:bold style P fill:#d98c19,stroke:#ffffff,color:#0b1220,font-weight:bold style L fill:#7c5cff,stroke:#ffffff,color:#0b1220,font-weight:bold

برای هر Node تازه که در پروژه ARCHO یا هر پروژه دیگری می‌سازی، این چهار سؤال را از خودت بپرس؛ اگر بتوانی جواب بدهی، معماری آن Node را واقعاً فهمیده‌ای:

  1. چه Topicهایی را Publish می‌کند؟
  2. چه Topicهایی را Subscribe می‌کند؟
  3. چه Serviceها یا Actionهایی ارائه می‌دهد یا فراخوانی می‌کند؟
  4. چه Parameterهایی رفتار آن را کنترل می‌کنند؟

۱.۱۰جمع‌بندی فصل اول

چه یاد گرفتیم

تبریک — تو الان با هفت ستون اصلی معماری ROS 2 آشنا شده‌ای: Node به‌عنوان واحد اجرایی مستقل، Topic و Message برای جریان پیوسته داده، Service برای درخواست/پاسخ لحظه‌ای، Action برای عملیات طولانی و قابل لغو، Parameter برای تنظیم رفتار بدون تغییر کد، و Launch File برای راه‌اندازی کل سیستم با یک دستور. تا اینجا فقط نقشه شهر را یاد گرفتیم؛ هنوز وارد شهر نشده‌ایم.

✅ نقطه بازبینی یادگیری
  • می‌توانم در یک جمله بگویم Node چیست و چرا سیستم را به چند Node تقسیم می‌کنیم.
  • می‌توانم تفاوت Topic و Service را با یک مثال واقعی توضیح دهم.
  • می‌دانم چرا Action برای عملیات طولانی لازم است و Service کافی نیست.
  • می‌توانم بگویم Parameter چه فرقی با Topic دارد.
  • می‌دانم Launch File چه کاری انجام می‌دهد و چرا فقط یک اسکریپت ساده نیست.
  • برای یک Node فرضی می‌توانم بگویم چه Topic، Service، Action و Parameteری ممکن است داشته باشد.

ارتباط با پروژه اصلی

پروژه ARCHO در این فصل فقط اسکلت ارتباطی ربات را روی کاغذ طراحی کردیم: کدام Node با کدام Node از طریق Topic حرف می‌زند، کدام کارها باید Service باشند، و کدام‌ها Action. هنوز هیچ کدی ننوشته‌ایم و هیچ Nodeی روی سیستم اجرا نشده است.

فصل بعد چه چیزی اضافه می‌کند

از فصل ۲ به بعد وارد دنیای عملی می‌شویم: ساخت Workspace از صفر، بررسی ساختار آن، ساخت اولین Package، نوشتن اولین Node واقعی با Python، اجرای آن، و ساخت اولین Publisher و Subscriber با چشم خودمان. از آنجا به بعد، هر مفهومی که یاد می‌گیری بلافاصله روی سیستم خودت اجرا خواهی کرد — همان‌جاست که ROS 2 از یک مجموعه مفاهیم به یک ابزار واقعی برای ساختن ربات تبدیل می‌شود.

واژه‌نامه فصل اول

Node
یک پردازش مستقل در ROS 2 که یک مسئولیت مشخص دارد.
Topic
کانال نام‌گذاری‌شده برای انتشار پیوسته داده بین Nodeها.
Message
قالب داده‌ای که روی یک Topic منتقل می‌شود.
Publisher
Nodeی که روی یک Topic داده منتشر می‌کند.
Subscriber
Nodeی که به یک Topic گوش می‌دهد و داده دریافت می‌کند.
Service
ارتباط دوطرفه درخواست/پاسخ بین یک Client و یک Server.
Action
عملیات طولانی با گزارش پیشرفت (Feedback) و قابلیت لغو.
Parameter
مقدار قابل‌تنظیمی که رفتار یک Node را بدون تغییر کد کنترل می‌کند.
Launch File
فایل پایتونی که اجرای هم‌زمان چند Node و بارگذاری تنظیمات را مدیریت می‌کند.

خطاهای رایج فصل اول — جمع‌بندی