$npx -y skills add arpitg1304/robotics-agent-skills --skill robotics-design-patternsArchitecture patterns, design principles, and proven recipes for building robust robotics software. Use this skill when designing robot software architectures, choosing between behavioral frameworks, structuring perception-planning-control pipelines, implementing state machines,
| 1 | # Robotics Design Patterns |
| 2 | |
| 3 | ## When to Use This Skill |
| 4 | - Designing robot software architecture from scratch |
| 5 | - Choosing between behavior trees, FSMs, or hybrid approaches |
| 6 | - Structuring perception → planning → control pipelines |
| 7 | - Implementing safety systems and watchdogs |
| 8 | - Building hardware abstraction layers (HAL) |
| 9 | - Designing for sim-to-real transfer |
| 10 | - Architecting multi-robot / fleet systems |
| 11 | - Making real-time vs. non-real-time tradeoffs |
| 12 | |
| 13 | ## Pattern 1: The Robot Software Stack |
| 14 | |
| 15 | Every robot system follows this layered architecture, regardless of complexity: |
| 16 | |
| 17 | ``` |
| 18 | ┌─────────────────────────────────────────────┐ |
| 19 | │ APPLICATION LAYER │ |
| 20 | │ Mission planning, task allocation, UI │ |
| 21 | ├─────────────────────────────────────────────┤ |
| 22 | │ BEHAVIORAL LAYER │ |
| 23 | │ Behavior trees, FSMs, decision-making │ |
| 24 | ├─────────────────────────────────────────────┤ |
| 25 | │ FUNCTIONAL LAYER │ |
| 26 | │ Perception, Planning, Control, Estimation │ |
| 27 | ├─────────────────────────────────────────────┤ |
| 28 | │ COMMUNICATION LAYER │ |
| 29 | │ ROS2, DDS, shared memory, IPC │ |
| 30 | ├─────────────────────────────────────────────┤ |
| 31 | │ HARDWARE ABSTRACTION LAYER │ |
| 32 | │ Drivers, sensor interfaces, actuators │ |
| 33 | ├─────────────────────────────────────────────┤ |
| 34 | │ HARDWARE LAYER │ |
| 35 | │ Cameras, LiDARs, motors, grippers, IMUs │ |
| 36 | └─────────────────────────────────────────────┘ |
| 37 | ``` |
| 38 | |
| 39 | **Design Rule**: Information flows UP through perception, decisions flow DOWN through control. Never let the application layer directly command hardware. |
| 40 | |
| 41 | ## Pattern 2: Behavior Trees (BT) |
| 42 | |
| 43 | Behavior trees are the **recommended default** for robot decision-making. They're modular, reusable, and easier to debug than FSMs for complex behaviors. |
| 44 | |
| 45 | ### Core Node Types |
| 46 | |
| 47 | ``` |
| 48 | Sequence (→) : Execute children left-to-right, FAIL on first failure |
| 49 | Fallback (?) : Execute children left-to-right, SUCCEED on first success |
| 50 | Parallel (⇉) : Execute all children simultaneously |
| 51 | Decorator : Modify a single child's behavior |
| 52 | Action (leaf) : Execute a robot action |
| 53 | Condition (leaf) : Check a condition (no side effects) |
| 54 | ``` |
| 55 | |
| 56 | ### Example: Pick-and-Place BT |
| 57 | |
| 58 | ``` |
| 59 | → Sequence |
| 60 | / | \ |
| 61 | → Check → Pick → Place |
| 62 | / \ / | \ / | \ |
| 63 | Battery Obj Open Move Close Move Open Release |
| 64 | OK? Found? Grip To Grip To Grip |
| 65 | per Obj per Goal per |
| 66 | ``` |
| 67 | |
| 68 | ### Implementation Pattern |
| 69 | |
| 70 | ```python |
| 71 | import py_trees |
| 72 | |
| 73 | class MoveToTarget(py_trees.behaviour.Behaviour): |
| 74 | """Action node: Move robot to a target pose""" |
| 75 | |
| 76 | def __init__(self, name, target_key="target_pose"): |
| 77 | super().__init__(name) |
| 78 | self.target_key = target_key |
| 79 | self.action_client = None |
| 80 | |
| 81 | def setup(self, **kwargs): |
| 82 | """Called once when tree is set up — initialize resources""" |
| 83 | self.node = kwargs.get('node') # ROS2 node |
| 84 | self.action_client = ActionClient( |
| 85 | self.node, MoveBase, 'move_base') |
| 86 | |
| 87 | def initialise(self): |
| 88 | """Called when this node first ticks — send the goal""" |
| 89 | bb = self.blackboard |
| 90 | target = bb.get(self.target_key) |
| 91 | self.goal_handle = self.action_client.send_goal(target) |
| 92 | self.logger.info(f"Moving to {target}") |
| 93 | |
| 94 | def update(self): |
| 95 | """Called every tick — check progress""" |
| 96 | if self.goal_handle is None: |
| 97 | return py_trees.common.Status.FAILURE |
| 98 | |
| 99 | status = self.goal_handle.status |
| 100 | if status == GoalStatus.STATUS_SUCCEEDED: |
| 101 | return py_trees.common.Status.SUCCESS |
| 102 | elif status == GoalStatus.STATUS_ABORTED: |
| 103 | return py_trees.common.Status.FAILURE |
| 104 | else: |
| 105 | return py_trees.common.Status.RUNNING |
| 106 | |
| 107 | def terminate(self, new_status): |
| 108 | """Called when node exits — cancel if preempted""" |
| 109 | if new_status == py_trees.common.Status.INVALID: |
| 110 | if self.goal_handle: |
| 111 | self.goal_handle.cancel_goal() |
| 112 | self.logger.info("Movement cancelled") |
| 113 | |
| 114 | # Build the tree |
| 115 | def create_pick_place_tree(): |
| 116 | root = py_trees.composites.Sequence("P |