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

فصل چهاردهم: Multi-Robot — ناوگانی از ARCHOها

وقتی یک ARCHO دیگر کافی نیست
پیش‌نیاز: فصل ۵ (TF2)، فصل ۱۱ (Nav2)
پروژه پیوسته: ناوگان ARCHO
مفاهیم: Namespace، TF Prefix، Fleet Manager
زمان مطالعه: ۹۰ تا ۱۱۰ دقیقه
در این فصل چه می‌خوانیم ۱۴.۱مشکل: وقتی سه ARCHO با هم صحبت می‌کنند ۱۴.۲راه‌حل اول: Namespace ۱۴.۳راه‌حل دوم: TF Prefix ۱۴.۴Fleet Manager: مغز بالای همه ARCHOها ۱۴.۵نقشه مشترک یا نقشه مستقل ۱۴.۶مشکل ازدحام: وقتی دو ربات روبه‌روی هم می‌رسند ۱۴.۷جمع‌بندی، واژه‌نامه و تمرین‌ها

۱۴.۱مشکل: وقتی سه ARCHO با هم صحبت می‌کنند

فرض کن انبار به‌قدری بزرگ شده که یک ARCHO کافی نیست و سه‌تا از آن‌ها هم‌زمان کار می‌کنند: robot_1، robot_2 و robot_3.

⚠️ اگر هر سه یک Topic یکسان منتشر کنند

اگر هر سه ARCHO هم‌زمان روی /scan، /odom و /cmd_vel منتشر و مشترک شوند، کل سیستم دیگر نمی‌داند کدام پیام متعلق به کدام ربات است. Nav2 هرکدام سعی می‌کند فرمان حرکت را برای همه سه ربات هم‌زمان بفرستد — نتیجه فقط هرج‌ومرج است.

۱۴.۲راه‌حل اول: Namespace

راه‌حل ساده و رایج، پیشوند گذاشتن روی همه Topicهای هر ربات با نام خودش است — دقیقاً همان مفهوم Namespace که در فصل ۲ دیدیم، فقط این‌بار در مقیاس یک ناوگان کامل:

/robot_1/scan
/robot_1/odom
/robot_1/cmd_vel

/robot_2/scan
/robot_2/odom
/robot_2/cmd_vel

حالا هر ARCHO فقط به Topicهای خودش گوش می‌دهد و فقط روی Topicهای خودش منتشر می‌کند. Nav2، SLAM Toolbox و ros2_control هرکدام داخل همان Namespace اجرا می‌شوند و اصلاً نمی‌دانند ARCHOهای دیگری هم وجود دارند.

۱۴.۳راه‌حل دوم: TF Prefix

Namespace به‌تنهایی کافی نیست. یادت هست در فصل ۵ دیدیم TF Tree یک ساختار سراسری است — اگر هر سه ARCHO فریمی به‌نام base_link داشته باشند، TF نمی‌داند کدام base_link متعلق به کدام ربات است. راه‌حل: هر ربات فریم‌های خودش را با پیشوند خودش نام‌گذاری می‌کند.

robot_1/base_link
robot_1/laser_link
robot_1/odom

robot_2/base_link
robot_2/laser_link
robot_2/odom
flowchart TB M["map"] --> O1["robot_1/odom"] --> B1["robot_1/base_link"] --> L1["robot_1/laser_link"] M --> O2["robot_2/odom"] --> B2["robot_2/base_link"] --> L2["robot_2/laser_link"] style M fill:#eef0ff,stroke:#3d4bf5
🧠 چرا map مشترک ولی odom مجزاست

فریم map معمولاً یکی برای همه ربات‌های ناوگان است — چون همه در همان انبار حرکت می‌کنند. اما هر ربات، Odometry، درایفت و خطای تجمعی خودش را دارد؛ پس هرکدام باید فریم odom مستقل خودش را داشته باشد، دقیقاً مثل فصل ۵ و ۹ برای یک ربات تنها.

۱۴.۴Fleet Manager: مغز بالای همه ARCHOها

Namespace و TF Prefix فقط تضمین می‌کنند ربات‌ها با هم قاطی نمی‌شوند. اما یک سؤال بزرگ‌تر هنوز باز است: وقتی یک مأموریت جدید می‌آید (مثلاً «قفسه ۴۰ را خالی کن»)، کدام ARCHO باید آن را انجام دهد؟

flowchart TB FM["Fleet Manager"] --> R1["Robot 1
Nav2"] FM --> R2["Robot 2
Nav2"] FM --> R3["Robot 3
Nav2"] style FM fill:#3d4bf5,color:#fff
📖 Fleet Manager چه تصمیم‌هایی می‌گیرد
  • کدام ربات این مأموریت را بگیرد؟
  • کدام ربات از نظر فاصله به مقصد نزدیک‌تر است؟
  • کدام ربات باتری بیشتری دارد؟
  • آیا راهرو مقصد در حال حاضر توسط ربات دیگری رزرو شده؟
  • آیا دو ربات مسیرهایشان با هم تداخل (Conflict) دارند؟
📖 جمله طلایی این فصل

Multi-Robot فقط اجرای چند نسخه موازی از Nav2 نیست؛ نیازمند یک لایه مدیریت ناوگان (Fleet Manager) برای تخصیص مأموریت و حل تعارض میان ربات‌هاست.

۱۴.۵نقشه مشترک یا نقشه مستقل

حالتسناریومثال
نقشه مشترکیک ساختمان، چند ربات، همه روی یک map حرکت می‌کنندچند ARCHO در یک طبقه از انبار
نقشه مستقلربات‌ها در طبقات یا محیط‌های کاملاً جدا کار می‌کنندیک ARCHO در طبقه همکف، یکی در طبقه بالا

۱۴.۶مشکل ازدحام: وقتی دو ربات روبه‌روی هم می‌رسند

حتی اگر هر ARCHO به‌تنهایی از موانع ثابت دوری کند، ممکن است دو ربات دقیقاً در یک راهروی باریک روبه‌روی هم قرار بگیرند — چیزی که Local Costmap یک ربات به‌تنهایی نمی‌تواند پیش‌بینی کند، چون هر ربات فقط محیط اطراف خودش را می‌بیند.

Robot A →      ← Robot B

راه‌حل‌های رایج در سطح Fleet (نه در سطح یک ربات تنها):

راه‌حلایده
رزرو راهروقبل از ورود به یک راهروی باریک، ربات آن را برای خودش رزرو می‌کند
اولویت عبوریک ربات (مثلاً با مأموریت مهم‌تر یا باتری کمتر) اولویت عبور دارد
Traffic Graphنقشه انبار به یک گراف ترافیکی با جهت مجاز حرکت تبدیل می‌شود
Zone Lockیک ناحیه کامل برای مدت کوتاهی قفل می‌شود تا فقط یک ربات در آن باشد
زمان‌بندی مأموریتمأموریت‌های نزدیک به‌هم زمان‌بندی می‌شوند تا هم‌زمان به یک نقطه نرسند
نقطه انتظاریک ربات در یک نقطه امن صبر می‌کند تا مسیر باز شود
راهروی باریک — نیاز به رزرو Fleet-level A B تصادم احتمالی بدون رزرو راهرو
دو ARCHO در یک راهروی باریک بدون هماهنگی سطح ناوگان به سمت هم حرکت می‌کنند.

۱۴.۷جمع‌بندی فصل چهاردهم

ناوگان ARCHO حالا می‌تواند بدون تداخل در ارتباطات کار کند (به‌لطف Namespace و TF Prefix)، و مأموریت‌ها به‌صورت هوشمند بین ربات‌ها تقسیم می‌شود (به‌لطف Fleet Manager) — بدون این‌که دو ARCHO در یک راهروی باریک با هم برخورد کنند.

✅ نقطه بازبینی یادگیری
  • می‌توانم توضیح دهم چرا بدون Namespace، چند ربات نمی‌توانند هم‌زمان کار کنند.
  • می‌دانم چرا TF Prefix جدا از Namespace هم لازم است.
  • می‌توانم بگویم چرا معمولاً map مشترک است اما odom مستقل.
  • می‌توانم حداقل سه راه‌حل سطح Fleet برای جلوگیری از ازدحام را نام ببرم.
🌍 ارتباط با پروژه اصلی

پروژه ARCHO اکنون به‌عنوان یک ناوگان سه‌رباتی با Namespace و TF Prefix مستقل، و یک Fleet Manager ساده برای تخصیص مأموریت و رزرو راهرو، در انبار کار می‌کند.

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

در فصل پانزدهم یاد می‌گیریم چطور کل این سیستم را با Docker بسته‌بندی و با CI/CD به‌صورت خودکار تست و تحویل کنیم — مسیری که یک پروژه ROS 2 را از «روی لپ‌تاپ من کار می‌کند» به یک محصول قابل استقرار تبدیل می‌کند.

واژه‌نامه فصل چهاردهم

Namespace
پیشوندی که Topic و Serviceهای یک ربات را از بقیه ربات‌ها در همان شبکه جدا می‌کند.
TF Prefix
پیشوندی که فریم‌های TF یک ربات را در یک TF Tree مشترک از ربات‌های دیگر متمایز می‌کند.
Fleet Manager
لایه بالادستی که مأموریت را بین چند ربات تخصیص می‌دهد و تعارض بین آن‌ها را حل می‌کند.
Traffic Graph
نمایش گراف‌مانند نقشه محیط برای مدیریت جهت و اولویت عبور چند ربات.
Zone Lock
قفل موقت یک ناحیه از نقشه برای اجازه حضور فقط یک ربات در آن.

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