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

فصل دوازدهم: Behavior Tree و Lifecycle Nodes — هوش پشت Nav2

جایی که Nav2 دیگر یک برنامه خطی نیست، بلکه فکر می‌کند
پیش‌نیاز: فصل ۱۱ (Navigation2)
پروژه پیوسته: ربات ARCHO
مفاهیم: BT، Lifecycle، Recovery
زمان مطالعه: ۱۲۰ تا ۱۴۰ دقیقه
در این فصل چه می‌خوانیم ۱۲.۱مشکل برنامه‌های خطی ۱۲.۲Behavior Tree چیست ۱۲.۳سه نوع Node اصلی ۱۲.۴Status و Tick ۱۲.۵Behavior Tree واقعی Nav2 برای ARCHO ۱۲.۶Lifecycle Nodes: چرا ROS 2 با ROS 1 فرق دارد ۱۲.۷چهار حالت اصلی یک Lifecycle Node ۱۲.۸Lifecycle Manager: مدیر پروژه Nav2 ۱۲.۹جمع‌بندی، واژه‌نامه و تمرین‌ها

۱۲.۱مشکل برنامه‌های خطی

فرض کن به ARCHO مأموریت می‌دهی: «برو قفسه شماره ۱۲.» حالا وسط راه هرکدام از این‌ها ممکن است اتفاق بیفتد:

اگر منطق ARCHO فقط یک برنامه خطی ساده باشد:

flowchart LR A["Start"] --> B["Move"] --> C["Goal"] style B fill:#fdeeec,stroke:#d64a3c
⚠️ چرا این کافی نیست

در یک برنامه خطی، اولین اتفاق غیرمنتظره کل برنامه را متوقف می‌کند. اگر بنویسی Move → Pick → Return و مرحله اول شکست بخورد، کل زنجیره فرو می‌ریزد. اما در دنیای واقعی، یک ربات صنعتی باید بتواند تصمیم بگیرد — نه فقط اجرا کند.

راه‌حل ROS 2 برای این مشکل، ساختاری است به‌نام Behavior Tree.

۱۲.۲Behavior Tree چیست

📖 تعریف

Behavior Tree ساختاری درختی برای تصمیم‌گیری است که به ربات اجازه می‌دهد بر اساس شرایط لحظه‌ای محیط، بهترین رفتار را انتخاب کند — به‌جای اجرای کورکورانه یک زنجیره ثابت از دستورها.

🧠 یک تشبیه ساده

صبح که از خانه بیرون می‌روی، در ذهنت این اتفاق می‌افتد: «آیا باران می‌بارد؟ اگر بله، چتر بردار؛ اگر نه، بدون چتر برو.» این دقیقاً یک Behavior Tree است — یک شرط، و بسته به نتیجه‌اش، یک عمل متفاوت.

چون تصمیم‌ها شاخه‌دار هستند، ساختار درختی معنا پیدا می‌کند:

flowchart TB R["Mission"] --> A["Go To Goal"] R --> B["Recharge Battery"] R --> C["Wait"] R --> D["Recover"] style R fill:#eef0ff,stroke:#3d4bf5

۱۲.۳سه نوع Node اصلی

تقریباً هر Behavior Tree واقعی، از ترکیب همین سه نوع Node ساخته می‌شود:

نوع Nodeکارمثال
Conditionفقط یک سؤال می‌پرسد؛ خروجی فقط Success یا Failure استBattery OK؟ Goal Reached؟
Actionکاری واقعی انجام می‌دهدCompute Path، Follow Path، Rotate، Clear Costmap
Controlتصمیم می‌گیرد کدام شاخه اجرا شود — مهم‌ترین بخش BTSequence، Fallback، Parallel

Sequence Node (→)

همه مراحل باید یکی‌یکی موفق شوند؛ اگر یکی شکست بخورد، بقیه اصلاً اجرا نمی‌شوند.

flowchart LR S["Sequence →"] --> P1["Compute Path"] --> P2["Follow Path"] --> P3["Success"] style S fill:#eef0ff,stroke:#3d4bf5

Fallback Node — یا Selector (?)

اگر گزینه اول شکست خورد، گزینه بعدی امتحان می‌شود.

flowchart TB F["Navigate ?"] --> R1["Main Route"] F --> R2["Secondary Route"] F --> R3["Recovery"] style F fill:#f4effe,stroke:#8b5cf6

Parallel Node

چند کار را هم‌زمان اجرا می‌کند — ARCHO فقط حرکت نمی‌کند، بلکه هم‌زمان باتری، LiDAR و مقصد را هم زیر نظر دارد.

flowchart TB P["Parallel"] --> M1["Move"] P --> M2["Monitor Battery"] P --> M3["Watch Obstacles"] style P fill:#eafaf3,stroke:#0e9e6e

۱۲.۴Status و Tick

هر Node در یک لحظه یکی از این سه وضعیت را برمی‌گرداند:

وضعیتمعنی
Successکار با موفقیت انجام شد
Failureکار انجام نشد
Runningهنوز در حال انجام است — مثلاً ARCHO هنوز در حال حرکت است
📖 Tick چیست

Behavior Tree فقط یک‌بار اجرا نمی‌شود؛ دائماً و مکرراً (مثلاً ۲۰ بار در ثانیه) از ریشه بررسی می‌شود. هر بار بررسی را Tick می‌نامند. در هر Tick دوباره پرسیده می‌شود: مقصد عوض شده؟ مانع جدید آمده؟ باتری کم شده؟ مسیر هنوز معتبر است؟

🔧 چرا Behavior Tree بهتر از انبوه if-else است

اگر بخواهی همه این شرایط را با if battery، if obstacle، if planner، if recovery، if localization، if timeout و if sensor بنویسی، خیلی زود کد به یک آشفتگی غیرقابل نگهداری تبدیل می‌شود. Behavior Tree همین پیچیدگی را در قالب یک ساختار بصری و قابل توسعه سازمان‌دهی می‌کند.

۱۲.۵Behavior Tree واقعی Nav2 برای ARCHO

نسخه ساده‌شده:

flowchart LR A["Navigate"] --> B["Compute Path"] --> C["Follow Path"] --> D["Goal Reached?"]

اما نسخه واقعی که Nav2 اجرا می‌کند شکل کامل‌تری دارد:

flowchart TB N["Navigate"] --> C1["Compute Path"] N --> C2["Follow Path"] N --> C3["Check Goal"] N --> C4["Check Battery"] N --> C5["Replan"] N --> C6["Recovery"] style N fill:#eef0ff,stroke:#3d4bf5 style C6 fill:#fdeeec,stroke:#d64a3c

Recovery Behavior: وقتی Planner گیر می‌کند

اگر Global Planner نتواند مسیر پیدا کند، BT به‌جای فروپاشی، یک زنجیره بازیابی را امتحان می‌کند:

flowchart TB A["Rotate"] -->|شکست| B["Backup"] B -->|شکست| C["Try Again"] C -->|شکست| D["Mission Failed"] style D fill:#fdeeec,stroke:#d64a3c

Replanning: وقتی یک لیفتراک راهرو را می‌بندد

اگر Planner قبلاً مسیری از یک راهرو پیدا کرده بود اما حالا آن راهرو مسدود شده، Behavior Tree خودش تصمیم می‌گیرد Planner دوباره اجرا شود و مسیر تازه‌ای محاسبه کند — بدون این‌که خط جدیدی از کد نوشته شود.

مثال باتری کم

اگر باتری ARCHO به ۸٪ برسد، BT می‌تواند بدون این‌که برنامه‌نویس صدها شرط if بنویسد، تصمیم بگیرد: مأموریت را لغو کن، برو ایستگاه شارژ.

🌍 مأموریت کامل ARCHO با BT

مأموریت «برو قفسه ۱۲» در قالب BT چیزی شبیه این است: Battery OK؟ → Localization OK؟ → Compute Path → Follow Path → Goal Reached؟ → Recovery. اگر وسط راه یک کارگر عبور کند، Planner دوباره مسیر را محاسبه می‌کند و ARCHO ادامه می‌دهد؛ اگر این هم جواب نداد، Recovery فعال می‌شود — کمی عقب می‌رود، دوباره تلاش می‌کند، یا در نهایت مأموریت را لغو می‌کند.

معماری کامل Nav2 با Behavior Tree در مرکز Goal Behavior Tree Planner Controller Recovery cmd_vel
Behavior Tree در مرکز تصمیم‌گیری قرار دارد و به هر Tick تصمیم می‌گیرد Planner، Controller یا Recovery فعال باشند.

۱۲.۶Lifecycle Nodes: چرا ROS 2 با ROS 1 فرق دارد

فرض کن ARCHO را روشن می‌کنی. آیا منطقی است که بلافاصله LiDAR شروع به کار کند، Planner اجرا شود، Controller فرمان بدهد و موتورها حرکت کنند — بدون اطمینان از سالم‌بودن همه‌چیز؟ قطعاً نه.

🧠 مثل چک‌لیست پیش از پرواز یک هواپیما

خلبان فقط دکمه روشن را نمی‌زند و پرواز نمی‌کند. اول موتور، سوخت، سیستم هیدرولیک و ابزارها بررسی می‌شوند و بعد اجازه پرواز داده می‌شود. ROS 2 دقیقاً همین منطق را برای Nodeهای حیاتی پیاده کرده است.

در ROS 1، Nodeها معمولاً فقط دو حالت داشتند: Start و Running. اگر مشکلی پیش می‌آمد، مدیریت آن سخت بود چون هیچ حالت میانی کنترل‌شده‌ای وجود نداشت. ROS 2 این را با Lifecycle Node حل کرده است.

📖 تعریف

Lifecycle Node، Nodeای است که وضعیت‌های مشخصی دارد و فقط زمانی کاملاً فعال می‌شود که همه شرایط لازم برقرار باشند — نه به‌محض روشن‌شدن.

۱۲.۷چهار حالت اصلی یک Lifecycle Node

stateDiagram-v2 [*] --> Unconfigured: Create Unconfigured --> Inactive: Configure() Inactive --> Active: Activate() Active --> Inactive: Deactivate() Inactive --> Unconfigured: Cleanup() Unconfigured --> Finalized: Shutdown() Inactive --> Finalized: Shutdown() Active --> Finalized: Shutdown() Finalized --> [*]

توجه: علاوه بر این چهار حالت اصلی (Unconfigured, Inactive, Active, Finalized)، هر گذار بین آن‌ها (مثل Configure یا Activate) عملاً از یک حالت گذار موقت (Transition State) عبور می‌کند؛ این حالت‌های گذار در نمودار ساده‌شده بالا نشان داده نشده‌اند.

حالتمعنیمثال LiDAR Driver
UnconfiguredNode وجود دارد، اما هنوز آماده کار نیستپورت سریال هنوز باز نشده
InactiveNode آماده است اما هنوز کاری انجام نمی‌دهدLiDAR آماده است اما هنوز داده منتشر نمی‌کند
ActiveNode واقعاً در حال کار است — Topic منتشر، Service پاسخ می‌دهدLaserScan روی /scan منتشر می‌شود
FinalizedNode به‌طور کامل و برگشت‌ناپذیر بسته شده — از هر سه حالت دیگر قابل دسترسی استخاموشی کامل سیستم
🔧 چرا حالت Inactive این‌قدر مهم است

فرض کن Planner آماده است اما Localization هنوز آماده نشده. اگر Planner همین الان فعال شود، اطلاعات موقعیت اشتباه دریافت می‌کند و مسیرهای غلط تولید می‌کند. حالت Inactive به Planner اجازه می‌دهد «آماده اما ساکت» بماند تا وقتی که واقعاً وقتش برسد.

⚠️ چرا ترتیب فعال‌سازی مهم است

اگر Controller قبل از Localization فعال شود، ARCHO ممکن است بر اساس موقعیت اشتباه حرکت کند — که در یک انبار پر از قفسه و کارگر، خطرناک است. Lifecycle دقیقاً همین ترتیب را کنترل می‌کند: LiDAR → TF → Localization → Costmap → Planner → Controller.

۱۲.۸Lifecycle Manager: مدیر پروژه Nav2

در Navigation2 یک Node مرکزی به‌نام Lifecycle Manager وجود دارد که مثل یک مدیر پروژه عمل می‌کند: Configure → Activate → Monitor → Shutdown را برای تمام Nodeهای حیاتی هماهنگ می‌کند.

flowchart TB LM["Lifecycle Manager"] --> A["Map Server"] LM --> B["AMCL"] LM --> C["Planner Server"] LM --> D["Controller Server"] LM --> E["BT Navigator"] LM --> F["Behavior Server"] style LM fill:#3d4bf5,color:#fff
dev@archo:~$ ros2 lifecycle get /amcl active [3] dev@archo:~$ ros2 lifecycle get /planner_server active [3] dev@archo:~$ ros2 lifecycle set /planner_server deactivate Transitioning successful
🌍 یک سناریوی صنعتی واقعی

شیفت شب در یک کارخانه شروع می‌شود. ARCHO روشن می‌شود؛ Lifecycle Manager بررسی می‌کند LiDAR، IMU و Encoder سالم‌اند. AMCL فعال می‌شود و موقعیت را پیدا می‌کند. Planner و Controller فعال می‌شوند و ARCHO شروع به کار می‌کند. در میانه شیفت، LiDAR به‌طور موقت از دسترس خارج می‌شود — Lifecycle Manager فوراً Planner و Controller را به Inactive می‌برد تا ARCHO حرکت خطرناک نکند. وقتی LiDAR دوباره سالم شد، Nodeها به همان ترتیب منطقی دوباره فعال می‌شوند. این رفتار، سیستم را قابل پیش‌بینی و ایمن نگه می‌دارد.

🧠 Behavior Tree و Lifecycle مکمل هم‌اند، نه یکی

Behavior Tree تصمیم می‌گیرد چه کاری الان انجام شود. Lifecycle تصمیم می‌گیرد کدام Node اصلاً اجازه اجرا دارد. یکی مغز تصمیم‌گیری لحظه‌ای است، دیگری چارچوب ایمنی راه‌اندازی و توقف.

۱۲.۹جمع‌بندی فصل دوازدهم

حالا معماری کامل Navigation2 برایت روشن شد: Localization، Map، Costmap، Global Planner و Local Controller (فصل ۱۱)، به‌همراه Behavior Tree که همه این‌ها را هماهنگ می‌کند و Lifecycle Nodes که تضمین می‌کند هر بخش فقط وقتی فعال شود که واقعاً آماده است. این شش‌بخش با هم باعث می‌شوند ARCHO بتواند در یک محیط واقعی — با موانع متحرک، تغییر مسیر، خطای سنسور و شرایط غیرمنتظره — کنار بیاید.

✅ نقطه بازبینی یادگیری
  • می‌توانم فرق Sequence، Fallback و Parallel Node را با مثال توضیح دهم.
  • می‌دانم Tick چیست و چرا BT فقط یک‌بار اجرا نمی‌شود.
  • می‌توانم توضیح دهم Recovery Behavior چطور از شکست Planner جلوگیری می‌کند.
  • می‌توانم چهار حالت اصلی یک Lifecycle Node را به ترتیب نام ببرم.
  • می‌دانم چرا Lifecycle Manager برای راه‌اندازی امن Nav2 ضروری است.
🌍 ارتباط با پروژه اصلی

پروژه ARCHO اکنون یک معماری کامل Nav2 دارد: BT Navigator که تصمیم‌گیری لحظه‌ای را هماهنگ می‌کند، و Lifecycle Manager که ترتیب امن راه‌اندازی و بازیابی همه Nodeهای حیاتی را کنترل می‌کند.

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

در فصل سیزدهم به سراغ MoveIt 2 می‌رویم — اگر ARCHO یک بازوی رباتیک هم داشته باشد، اینجا یاد می‌گیریم چطور آن بازو مسیر حرکت خودش را برنامه‌ریزی می‌کند.

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

Behavior Tree (BT)
ساختاری درختی برای تصمیم‌گیری ربات بر اساس شرایط لحظه‌ای محیط.
Sequence Node
Control Node که همه فرزندانش باید به‌ترتیب موفق شوند تا خودش موفق شود.
Fallback (Selector) Node
Control Node که اولین فرزند موفق را انتخاب می‌کند.
Tick
هر بار بررسی مکرر و دوره‌ای درخت رفتار از ریشه.
Recovery Behavior
رفتار جایگزین (مثل چرخش یا عقب‌رفتن) وقتی مسیر اصلی شکست می‌خورد.
Lifecycle Node
Nodeای با حالت‌های مشخص که فقط با ترتیب کنترل‌شده فعال می‌شود.
Lifecycle Manager
Node مدیریتی که ترتیب Configure/Activate/Deactivate همه Lifecycle Nodeها را هماهنگ می‌کند.

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