

Các command đơn lẻ có thể thực hiện rất nhiều nhiệm vụ khác nhau của robot. Tuy nhiên, mô hình ba trạng thái đơn giản (initialize – execute – end) sẽ nhanh chóng trở nên cồng kềnh và khó quản lý khi cần những chức năng nâng cao hơn, chẳng hạn như:
Chuỗi hành động robot kéo dài
Sự phối hợp giữa nhiều subsystem của robot
Để giải quyết vấn đề này, người dùng được khuyến khích sử dụng chức năng command group mạnh mẽ được tích hợp trong thư viện command-based.
Khái niệm Command Group
Đúng như tên gọi, command group là sự kết hợp của nhiều command.
Việc kết hợp nhiều đối tượng (ví dụ: các command) thành một đối tượng lớn hơn được gọi là composition (tổ hợp).
Command group tổ hợp nhiều command thành một command tổng hợp (composite command). Điều này giúp:
Code gọn gàng hơn
Các command thành phần có thể được viết độc lập với logic kết hợp
Giảm đáng kể độ phức tạp ở mỗi bước xử lý
Quan trọng nhất:
👉 Bản thân command group cũng là một command – chúng implement interface Command.
Điều này cho phép tổ hợp đệ quy (recursive composition), nghĩa là:
Một command group có thể chứa các command group khác làm thành phần
Types of Command Groups (Các loại Command Group)
Thư viện command-based hỗ trợ 4 loại command group cơ bản:
SequentialCommandGroupParallelCommandGroupParallelRaceGroupParallelDeadlineGroup
Mỗi loại đều kết hợp nhiều command thành một command tổng hợp, nhưng cách hoạt động khác nhau.
SequentialCommandGroup
SequentialCommandGroup chạy một danh sách các command theo thứ tự:
Command thứ nhất chạy
Sau khi xong → command thứ hai
Rồi command thứ ba
… cho đến khi hết danh sách
Group này kết thúc khi command cuối cùng kết thúc.
⚠️ Vì vậy, rất quan trọng là mỗi command trong chuỗi phải có khả năng kết thúc.
Nếu một command không bao giờ kết thúc, các command phía sau sẽ không bao giờ được chạy.
ParallelCommandGroup
ParallelCommandGroup chạy một tập các command song song:
Tất cả command bắt đầu cùng lúc
Group kết thúc khi tất cả command đều đã kết thúc
ParallelRaceGroup
ParallelRaceGroup tương tự như ParallelCommandGroup ở chỗ:
Các command chạy đồng thời
Tuy nhiên:
Group kết thúc ngay khi bất kỳ command nào kết thúc
Tất cả các command còn lại bị ngắt (interrupted) tại thời điểm đó
ParallelDeadlineGroup
ParallelDeadlineGroup cũng chạy các command đồng thời.
Điểm khác biệt:
Group kết thúc khi một command cụ thể (gọi là “deadline”) kết thúc
Tất cả các command khác đang chạy sẽ bị ngắt
Creating Command Groups (Tạo Command Group)
Người dùng có nhiều cách để tạo command group.
Một cách (tương tự cách cũ của thư viện command-based) là kế thừa (subclass) từ một trong các lớp command group.
Ví dụ sau minh họa một command group:
Phương thức addCommands():
Dùng để thêm các command vào group
Có mặt trong cả 4 loại command group
Inline Command Groups (Command Group nội tuyến)
Command group không nhất thiết phải tạo bằng cách subclass.
Người dùng có thể truyền trực tiếp các command vào constructor:
new SequentialCommandGroup(new FooCommand(), new BarCommand());
Cách này được gọi là inline command definition.
Nó đặc biệt hữu ích khi:
Command group không có khả năng tái sử dụng
Việc viết cả một class riêng là lãng phí
Recursive Composition of Command Groups
(Tổ hợp đệ quy Command Group)
Như đã đề cập, command group có thể tổ hợp đệ quy.
Vì command group cũng là command, nên:
Chúng có thể được đưa vào command group khác như một thành phần
Đây là một tính năng cực kỳ mạnh, cho phép xây dựng các hành vi robot rất phức tạp từ các khối đơn giản.
Ví dụ:
Lưu ý:
Cấu trúc song song được lồng bên trong cấu trúc tuần tự
Toàn bộ cấu trúc phức tạp này có thể tiếp tục được lồng vào một cấu trúc khác
👉 Composition (tổ hợp) là một công cụ cực kỳ mạnh mẽ và người dùng nên tận dụng triệt để.
Command Group and Requirements
(Command Group và Requirements)
Vì command group cũng là command, nên chúng cũng phải khai báo requirements.
Tuy nhiên:
Người dùng không cần khai báo thủ công
Requirements được tự động suy ra từ các command thành phần
Quy tắc chung:
Command group yêu cầu hợp (union) của tất cả subsystem mà các command con yêu cầu
Ví dụ:
ReleaseAndBackở trên sẽ yêu cầu:Drive subsystem
Gripper subsystem
Ngoài ra:
Requirements được cưỡng chế trong tất cả các loại parallel group
Một parallel group không được chứa hai command cùng yêu cầu một subsystem
Một số người dùng nâng cao có thể thấy điều này quá hạn chế.
Với những trường hợp đó, thư viện cung cấp lớp ScheduleCommand, cho phép:
“Tách nhánh” độc lập khỏi command group
Quản lý requirement với độ chi tiết cao hơn
Restrictions on Command Group Components
(Các hạn chế đối với thành phần của Command Group)
Vì các command trong command group được chạy thông qua group bao bọc chúng, nên sẽ xảy ra lỗi nếu:
Cùng một instance command
Bị lập lịch độc lập
Đồng thời với command group chứa nó
Khi đó:
Command bị chạy từ nhiều nơi cùng lúc
Trạng thái nội bộ có thể không nhất quán
Dẫn đến hành vi khó đoán và rất khó debug
Vì lý do này:
Một command đã được thêm vào command group:
Không thể được lập lịch độc lập
Không thể thêm vào command group thứ hai
Nếu cố tình làm vậy:
Chương trình sẽ ném exception
Và crash chương trình người dùng
Những người dùng nâng cao, nếu chắc chắn an toàn, có thể:
Bỏ qua hạn chế này bằng phương thức
clearGroupedCommand()
Phương thức này nằm trong lớp CommandGroupBase

