optimal & fix file cmake
This commit is contained in:
176
docs/PLUGIN_GUIDE.md
Normal file
176
docs/PLUGIN_GUIDE.md
Normal file
@@ -0,0 +1,176 @@
|
||||
# Viết một nguồn mission mới
|
||||
|
||||
Nguồn mission là plugin duy nhất của gói này. Thêm một loại nguồn (REST, fleet manager riêng,
|
||||
teach-pendant, file kịch bản...) không cần sửa dòng nào trong `src/`.
|
||||
|
||||
Việc **thực thi action** không thuộc đây: adapter chỉ chuyển dữ liệu, navigation runtime mới là nơi
|
||||
chạy action.
|
||||
|
||||
## 1. Chọn tên schema
|
||||
|
||||
Schema là chuỗi định danh loại payload, và là thứ core dùng để định tuyến. Đặt tên theo miền dữ
|
||||
liệu, không theo tên hãng hay giao thức truyền tải:
|
||||
|
||||
```
|
||||
vda5050.order # đã có
|
||||
geometry.pose_stamped # đã có
|
||||
json.pick_and_place # ví dụ nguồn mới
|
||||
```
|
||||
|
||||
Hai adapter khai cùng một schema sẽ bị registry từ chối — định tuyến khi đó phụ thuộc thứ tự nạp,
|
||||
tức phụ thuộc vào thứ tự dòng trong file YAML.
|
||||
|
||||
## 2. Hiện thực `MissionSourceAdapter`
|
||||
|
||||
```cpp
|
||||
#include <boost/dll/alias.hpp>
|
||||
#include <mission_adapters/adapter.h>
|
||||
|
||||
namespace mission_plugins
|
||||
{
|
||||
|
||||
class PickAndPlaceAdapter : public mission_adapters::MissionSourceAdapter
|
||||
{
|
||||
public:
|
||||
static mission_adapters::MissionSourceAdapter::Ptr create()
|
||||
{
|
||||
return std::make_shared<PickAndPlaceAdapter>();
|
||||
}
|
||||
|
||||
bool configure(const std::string& name, robot::NodeHandle& nh) override
|
||||
{
|
||||
// Param riêng nằm trong namespace tên instance.
|
||||
nh.getParam(name + "/global_frame", global_frame_, std::string("map"));
|
||||
return !global_frame_.empty();
|
||||
}
|
||||
|
||||
std::string schema() const override { return "json.pick_and_place"; }
|
||||
|
||||
bool validate(const mission_adapters::MissionRequest& request,
|
||||
std::string& reason) const override
|
||||
{
|
||||
if (request.raw_payload.empty())
|
||||
{
|
||||
reason = "payload rỗng";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
mission_adapters::ConversionResult
|
||||
convert(const mission_adapters::MissionRequest& request) override
|
||||
{
|
||||
mission_adapters::ConversionResult result;
|
||||
// ... parse request.raw_payload, dựng mission ...
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string global_frame_ = "map";
|
||||
};
|
||||
|
||||
} // namespace mission_plugins
|
||||
|
||||
BOOST_DLL_ALIAS(mission_plugins::PickAndPlaceAdapter::create, PickAndPlaceAdapter)
|
||||
```
|
||||
|
||||
Bốn quy tắc bắt buộc:
|
||||
|
||||
- **State là member, không phải `static` local.** Một tiến trình có thể chạy nhiều instance; state
|
||||
static sẽ nối chúng lại và order của robot này ảnh hưởng robot kia.
|
||||
- **`validate()` chặn dữ liệu hỏng trước khi nó tới navigation**: NaN/Inf, quaternion không chuẩn
|
||||
hoá được, payload thiếu trường. Trả `false` kèm `reason` cụ thể — chuỗi đó đi thẳng vào log.
|
||||
- **`convert()` trả rỗng nghĩa là "không có việc", KHÔNG phải lỗi và KHÔNG phải lệnh huỷ.** Core sẽ
|
||||
bỏ qua và giữ nguyên hàng đợi đang chạy. Đây là bất biến A1: một order lỗi từ fleet manager không
|
||||
được âm thầm xoá order đang chạy.
|
||||
- **Mission `has_goal == false` phải có ít nhất một action.** Mission không goal và cũng không
|
||||
action là chặng không có việc gì để làm, và nó sẽ không bao giờ báo kết quả về — mission layer kẹt
|
||||
`RUNNING` vĩnh viễn. Core kiểm lại điều này và bỏ cả lô nếu phát hiện.
|
||||
|
||||
### `SubmitMode` — thay hay nối tiếp
|
||||
|
||||
`ConversionResult::mode` quyết định mission mới quan hệ thế nào với hàng đợi đang có:
|
||||
|
||||
| mode | Ý nghĩa | Dùng khi |
|
||||
|---|---|---|
|
||||
| `kReplace` (mặc định) | Thay toàn bộ hàng đợi, chặng đang chạy bị preempt và được bảo dừng | Yêu cầu mới, độc lập với việc đang làm |
|
||||
| `kAppend` | Chỉ thêm vào cuối hàng đợi, không đụng chặng đang chạy | Phần nối tiếp của chính yêu cầu đang chạy |
|
||||
|
||||
`kAppend` là hình dạng của VDA5050 order update. Trả `kReplace` cho một bản cập nhật nghĩa là mỗi
|
||||
lần fleet manager release thêm horizon, robot lại huỷ và chạy lại chặng đang đi.
|
||||
|
||||
## 3. Build thành `.so` riêng
|
||||
|
||||
```cmake
|
||||
add_library(mission_adapters_pick_and_place SHARED plugins/pick_and_place_adapter.cpp)
|
||||
|
||||
target_compile_options(mission_adapters_pick_and_place PRIVATE -Wall -Wextra)
|
||||
set_target_properties(mission_adapters_pick_and_place PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
target_link_libraries(mission_adapters_pick_and_place
|
||||
PUBLIC mission_adapters
|
||||
PRIVATE Boost::boost Threads::Threads
|
||||
)
|
||||
|
||||
install(TARGETS mission_adapters_pick_and_place
|
||||
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
|
||||
)
|
||||
```
|
||||
|
||||
Thêm dependency cho plugin thì phải cập nhật **đủ bốn chỗ**: `CMakeLists.txt`, `package.xml`,
|
||||
install rule, và file YAML.
|
||||
|
||||
## 4. Khai báo trong YAML — **đừng quên `library_path`**
|
||||
|
||||
Trong `pnkx_nav_core/config/mission_adapters_params.yaml`:
|
||||
|
||||
```yaml
|
||||
mission_adapters:
|
||||
mission_sources:
|
||||
- {name: pick_src, type: PickAndPlaceAdapter} # type = tên symbol trong BOOST_DLL_ALIAS
|
||||
|
||||
pick_src:
|
||||
global_frame: map # param riêng của instance, đọc trong configure()
|
||||
|
||||
PickAndPlaceAdapter:
|
||||
library_path: libmission_adapters_pick_and_place # BẮT BUỘC
|
||||
```
|
||||
|
||||
Ba tên phải khớp nhau:
|
||||
|
||||
| Nơi | Giá trị |
|
||||
|---|---|
|
||||
| `BOOST_DLL_ALIAS(..., PickAndPlaceAdapter)` | tên symbol |
|
||||
| `mission_sources[].type` | **cùng** tên symbol |
|
||||
| `<type>/library_path` | tên file `.so` (không cần đuôi) |
|
||||
|
||||
**Thiếu `library_path` là lỗi phổ biến nhất**: plugin build sạch, `.so` nằm đúng chỗ, nhưng runtime
|
||||
báo "không tìm thấy". Registry sẽ nêu đích danh khoá bị thiếu trong log.
|
||||
|
||||
Tên không có đuôi `.so` được resolve qua `PNKX_NAV_CORE_LIBRARY_PATH`, `devel/lib`, rồi
|
||||
`LD_LIBRARY_PATH` — nên **phải `source devel/setup.bash`** trước khi chạy, nếu không plugin sẽ không
|
||||
được tìm thấy dù file có thật.
|
||||
|
||||
## 5. Kiểm chứng
|
||||
|
||||
```bash
|
||||
catkin_make --pkg mission_adapters
|
||||
source devel/setup.bash
|
||||
|
||||
PNKX_NAV_CORE_CONFIG_DIR=src/AMR_T800/Test/mission_adapters/test/config \
|
||||
./devel/lib/mission_adapters/plugin_registry_test
|
||||
```
|
||||
|
||||
Nên có test cho: payload hợp lệ, payload thiếu trường, payload chứa NaN/Inf, payload không sinh
|
||||
mission nào, và (nếu nguồn có state) hai yêu cầu liên tiếp.
|
||||
|
||||
## 6. Nguồn không cần `.so`
|
||||
|
||||
Nguồn biên dịch thẳng vào host thì bỏ qua bước 3 và 4, đăng ký trực tiếp:
|
||||
|
||||
```cpp
|
||||
registry.registerAdapter(std::make_shared<PickAndPlaceAdapter>());
|
||||
```
|
||||
|
||||
Đường này dùng trong test và cho host muốn kiểm soát vòng đời adapter; phần còn lại của luồng
|
||||
(validate, convert, định tuyến theo schema) giống hệt.
|
||||
Reference in New Issue
Block a user