temporary storage 7/9/2026 20:41
This commit is contained in:
34
PLAN.md
34
PLAN.md
@@ -28,7 +28,7 @@ plugin recovery có thể trả trạng thái, velocity command hoặc path.
|
|||||||
- Cung cấp ngữ cảnh + mục tiêu runtime:
|
- Cung cấp ngữ cảnh + mục tiêu runtime:
|
||||||
- `RecoveryContext` (tf/costmap/global_path)
|
- `RecoveryContext` (tf/costmap/global_path)
|
||||||
- `RecoveryGoal` (angle/distance/target_pose/params)
|
- `RecoveryGoal` (angle/distance/target_pose/params)
|
||||||
- Param chung `timeout` do base đọc trong `configure()` (param riêng plugin đọc `onConfigure()`).
|
- Param riêng plugin đọc trong `onConfigure()`; core base không giữ timeout chung.
|
||||||
- Cung cấp docs/test stub để plugin sau này implement đúng contract.
|
- Cung cấp docs/test stub để plugin sau này implement đúng contract.
|
||||||
|
|
||||||
### 2.2. `recovery_core` không chịu trách nhiệm
|
### 2.2. `recovery_core` không chịu trách nhiệm
|
||||||
@@ -120,7 +120,7 @@ public:
|
|||||||
robot_costmap_2d::Costmap2DROBOT* local_costmap) = 0;
|
robot_costmap_2d::Costmap2DROBOT* local_costmap) = 0;
|
||||||
|
|
||||||
virtual RecoveryResult runBehavior() = 0;
|
virtual RecoveryResult runBehavior() = 0;
|
||||||
virtual RecoveryResult computeCommand(double dt);
|
virtual RecoveryResult update();
|
||||||
virtual RecoveryStatus status() const = 0;
|
virtual RecoveryStatus status() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -131,7 +131,7 @@ protected:
|
|||||||
Điểm khác `robot_nav_core::RecoveryBehavior`:
|
Điểm khác `robot_nav_core::RecoveryBehavior`:
|
||||||
- Có thêm `global_path` để behavior họ path có ngữ cảnh plan hiện tại.
|
- Có thêm `global_path` để behavior họ path có ngữ cảnh plan hiện tại.
|
||||||
- `runBehavior()` trả `RecoveryResult` thay vì `void`.
|
- `runBehavior()` trả `RecoveryResult` thay vì `void`.
|
||||||
- Có `computeCommand(dt)` cho behavior per-cycle.
|
- Có `update()` cho behavior per-cycle.
|
||||||
|
|
||||||
## 4. Ba Nhóm Recovery
|
## 4. Ba Nhóm Recovery
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ protected:
|
|||||||
|------|-------|--------------|--------|
|
|------|-------|--------------|--------|
|
||||||
| A. Path output | regen path, detour path | `runBehavior()` | `RecoveryOutputType::kPath` |
|
| A. Path output | regen path, detour path | `runBehavior()` | `RecoveryOutputType::kPath` |
|
||||||
| B. No output | clear costmap, reset state | `runBehavior()` | `RecoveryOutputType::kNone` |
|
| B. No output | clear costmap, reset state | `runBehavior()` | `RecoveryOutputType::kNone` |
|
||||||
| C. Velocity output | rotate, backup | `computeCommand(dt)` | `RecoveryOutputType::kVelocity` |
|
| C. Velocity output | rotate, backup | `update()` | `RecoveryOutputType::kVelocity` |
|
||||||
|
|
||||||
Caller/adapter chịu trách nhiệm tiêu thụ output:
|
Caller/adapter chịu trách nhiệm tiêu thụ output:
|
||||||
- path output: thay local path hoặc request global/local replan;
|
- path output: thay local path hoặc request global/local replan;
|
||||||
@@ -228,10 +228,10 @@ Work items:
|
|||||||
1. [x] Implement `RecoveryResult` factories.
|
1. [x] Implement `RecoveryResult` factories.
|
||||||
2. [x] Implement `RecoveryConfig::validate`.
|
2. [x] Implement `RecoveryConfig::validate`.
|
||||||
3. [x] Implement `RecoveryConfig::fromNodeHandle`.
|
3. [x] Implement `RecoveryConfig::fromNodeHandle`.
|
||||||
4. [x] Giữ default `RecoveryBehavior::computeCommand(dt)` trả `Failed()`.
|
4. [x] Giữ guard `RecoveryBehavior::update()` fail an toàn khi chưa start.
|
||||||
5. Deferred: helper chạy loop cho behavior velocity chỉ thêm khi Phase 4 integration cần:
|
5. Deferred: helper chạy loop cho behavior velocity chỉ thêm khi Phase 4 integration cần:
|
||||||
- dùng `control_frequency`;
|
- dùng nhịp gọi từ adapter;
|
||||||
- tôn trọng `timeout`;
|
- giám sát ngoài core nếu cần giới hạn thời gian;
|
||||||
- không cấp phát/log trong loop.
|
- không cấp phát/log trong loop.
|
||||||
6. [x] Hoàn thiện `MockBehavior`.
|
6. [x] Hoàn thiện `MockBehavior`.
|
||||||
7. [x] Nâng `interface_contract_test.cpp` từ smoke test thành assertion test.
|
7. [x] Nâng `interface_contract_test.cpp` từ smoke test thành assertion test.
|
||||||
@@ -243,8 +243,8 @@ Acceptance:
|
|||||||
- `RecoveryResult::Failed()` trả `status = kFailed`, `output_type = kNone`.
|
- `RecoveryResult::Failed()` trả `status = kFailed`, `output_type = kNone`.
|
||||||
- `Velocity(command, status)` giữ `command`, set `output_type = kVelocity`.
|
- `Velocity(command, status)` giữ `command`, set `output_type = kVelocity`.
|
||||||
- `PathOut(path, status)` giữ `path`, set `output_type = kPath`.
|
- `PathOut(path, status)` giữ `path`, set `output_type = kPath`.
|
||||||
- Config reject `NaN`, `inf`, `control_frequency <= 0`, `timeout < 0`.
|
- Config/plugin reject input không hợp lệ.
|
||||||
- Default `computeCommand(dt)` không sinh velocity mù.
|
- Default `update()` không sinh velocity mù khi lifecycle sai.
|
||||||
- Test cover factory, config validation, default per-cycle behavior, mock lifecycle.
|
- Test cover factory, config validation, default per-cycle behavior, mock lifecycle.
|
||||||
|
|
||||||
Verify commands:
|
Verify commands:
|
||||||
@@ -275,12 +275,12 @@ Plugin đề xuất:
|
|||||||
- [x] trả `RecoveryResult::Succeeded()` hoặc `Failed()`.
|
- [x] trả `RecoveryResult::Succeeded()` hoặc `Failed()`.
|
||||||
2. `RotateRecovery`
|
2. `RotateRecovery`
|
||||||
- [x] nhóm C, per-cycle velocity;
|
- [x] nhóm C, per-cycle velocity;
|
||||||
- [x] đọc `target_angle`, `angular_speed`, `timeout`;
|
- [x] đọc `target_angle`, `angular_speed`, `control_period`;
|
||||||
- [x] dùng tích phân theo `dt` trong plugin mẫu; adapter production có thể thay bằng pose/tf;
|
- [x] dùng tích phân theo `control_period` trong plugin mẫu; adapter production có thể thay bằng pose/tf;
|
||||||
- [x] trả zero command khi kết thúc hoặc fail.
|
- [x] trả zero command khi kết thúc hoặc fail.
|
||||||
3. `BackUpRecovery`
|
3. `BackUpRecovery`
|
||||||
- [x] nhóm C, per-cycle velocity;
|
- [x] nhóm C, per-cycle velocity;
|
||||||
- [x] đọc `backup_distance`, `linear_speed`, `timeout`;
|
- [x] đọc `backup_distance`, `linear_speed`, `control_period`;
|
||||||
- [x] có `require_costmap` để fail nếu thiếu local costmap trước khi trả backward velocity.
|
- [x] có `require_costmap` để fail nếu thiếu local costmap trước khi trả backward velocity.
|
||||||
4. `RegenPathRecovery` hoặc `DetourPathRecovery`
|
4. `RegenPathRecovery` hoặc `DetourPathRecovery`
|
||||||
- [x] nhóm A, path output;
|
- [x] nhóm A, path output;
|
||||||
@@ -344,22 +344,22 @@ Phương án:
|
|||||||
- Adapter chịu trách nhiệm:
|
- Adapter chịu trách nhiệm:
|
||||||
- load plugin;
|
- load plugin;
|
||||||
- gọi `initialize`;
|
- gọi `initialize`;
|
||||||
- gọi `runBehavior` hoặc loop `computeCommand`;
|
- gọi `runBehavior` hoặc loop `update`;
|
||||||
- publish velocity nếu output là `kVelocity`;
|
- publish velocity nếu output là `kVelocity`;
|
||||||
- thay path hoặc request replan nếu output là `kPath`;
|
- thay path hoặc request replan nếu output là `kPath`;
|
||||||
- áp safety stop nếu output failed/timeout.
|
- áp safety stop nếu output failed hoặc giám sát ngoài core báo lỗi.
|
||||||
|
|
||||||
Acceptance:
|
Acceptance:
|
||||||
- Core vẫn không publish.
|
- Core vẫn không publish.
|
||||||
- Plugin vẫn chỉ trả `RecoveryResult`.
|
- Plugin vẫn chỉ trả `RecoveryResult`.
|
||||||
- Adapter có safety gate trước velocity command.
|
- Adapter có safety gate trước velocity command.
|
||||||
- Timeout và failure path luôn trả stop command hoặc abort rõ ràng.
|
- Failure path luôn trả stop command hoặc abort rõ ràng.
|
||||||
|
|
||||||
## 8. Safety Requirements
|
## 8. Safety Requirements
|
||||||
|
|
||||||
- Behavior velocity phải trả stop command khi không chắc an toàn.
|
- Behavior velocity phải trả stop command khi không chắc an toàn.
|
||||||
- Không publish command từ core/plugin nếu chưa qua adapter safety gate.
|
- Không publish command từ core/plugin nếu chưa qua adapter safety gate.
|
||||||
- `dt <= 0`, `NaN`, `inf`, missing tf/costmap/plan phải fail rõ ràng.
|
- Input `NaN`, `inf`, missing tf/costmap/plan phải fail rõ ràng.
|
||||||
- Không log spam trong control loop.
|
- Không log spam trong control loop.
|
||||||
- Không parse YAML hoặc cấp phát lớn trong mỗi cycle.
|
- Không parse YAML hoặc cấp phát lớn trong mỗi cycle.
|
||||||
- Đơn vị phải rõ:
|
- Đơn vị phải rõ:
|
||||||
@@ -399,7 +399,7 @@ Acceptance:
|
|||||||
### Integration DoD
|
### Integration DoD
|
||||||
|
|
||||||
- Adapter là nơi duy nhất có side effect publish/service/path replacement.
|
- Adapter là nơi duy nhất có side effect publish/service/path replacement.
|
||||||
- Safety stop rõ ràng khi failed/timeout.
|
- Safety stop rõ ràng khi failed hoặc adapter hủy recovery.
|
||||||
- Có log đủ ngữ cảnh, không spam loop.
|
- Có log đủ ngữ cảnh, không spam loop.
|
||||||
|
|
||||||
## 10. Verification Baseline
|
## 10. Verification Baseline
|
||||||
|
|||||||
@@ -20,11 +20,11 @@ behavior->configure(name, ctx); // 1 lần: ctx = {tf, global_path, glo
|
|||||||
RecoveryGoal goal; goal.angle = 1.57; // mục tiêu RUNTIME: "quay 90 độ ngay lượt này"
|
RecoveryGoal goal; goal.angle = 1.57; // mục tiêu RUNTIME: "quay 90 độ ngay lượt này"
|
||||||
RecoveryResult r = behavior->start(goal);
|
RecoveryResult r = behavior->start(goal);
|
||||||
while (r.status == RecoveryStatus::kRunning)
|
while (r.status == RecoveryStatus::kRunning)
|
||||||
r = behavior->update(dt); // publish r.command; đọc r.progress / r.remaining / r.message
|
r = behavior->update(); // publish r.command; đọc r.progress / r.remaining / r.message
|
||||||
```
|
```
|
||||||
|
|
||||||
API công khai `configure/start/update/cancel` là non-virtual (base lo guard/timeout/elapsed/cancel);
|
API công khai `configure/start/update/cancel` là non-virtual (base lo guard vòng đời/cancel);
|
||||||
plugin chỉ override hook `onConfigure()/onStart(goal)/onUpdate(dt)`.
|
plugin chỉ override hook `onConfigure()/onStart(goal)/onUpdate()`.
|
||||||
|
|
||||||
## Ba họ recovery
|
## Ba họ recovery
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ plugin chỉ override hook `onConfigure()/onStart(goal)/onUpdate(dt)`.
|
|||||||
|----|-------|--------|-----------|
|
|----|-------|--------|-----------|
|
||||||
| A | regen path (đường thoát) | `robot_nav_msgs::Path` | `onUpdate()` one-shot |
|
| A | regen path (đường thoát) | `robot_nav_msgs::Path` | `onUpdate()` one-shot |
|
||||||
| B | clear costmap | không có (chỉ status) | `onUpdate()` one-shot |
|
| B | clear costmap | không có (chỉ status) | `onUpdate()` one-shot |
|
||||||
| C | rotation / backup | `robot_geometry_msgs::Twist` mỗi cycle | `onStart(goal)` + `onUpdate(dt)` |
|
| C | rotation / backup | `robot_geometry_msgs::Twist` mỗi cycle | `onStart(goal)` + `onUpdate()` |
|
||||||
|
|
||||||
Cả 3 chia sẻ một `RecoveryResult` hợp nhất mang cờ `output_type` + rich feedback
|
Cả 3 chia sẻ một `RecoveryResult` hợp nhất mang cờ `output_type` + rich feedback
|
||||||
(`progress`/`remaining`/`elapsed`/`message`).
|
(`progress`/`remaining`/`elapsed`/`message`).
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ về output** (path/vận tốc), đồng thời vẫn dùng global path/costmap
|
|||||||
## Các thành phần
|
## Các thành phần
|
||||||
|
|
||||||
- `RecoveryBehavior` (interface, template-method): API non-virtual `configure`/`start`/`update`/
|
- `RecoveryBehavior` (interface, template-method): API non-virtual `configure`/`start`/`update`/
|
||||||
`cancel`; plugin chỉ triển khai hook `onConfigure`/`onStart(goal)`/`onUpdate(dt)`.
|
`cancel`; plugin chỉ triển khai hook `onConfigure`/`onStart(goal)`/`onUpdate()`.
|
||||||
- `RecoveryContext`: gói con trỏ ngữ cảnh (tf/costmap/global_path) truyền một lần qua `configure`.
|
- `RecoveryContext`: gói con trỏ ngữ cảnh (tf/costmap/global_path) truyền một lần qua `configure`.
|
||||||
- `RecoveryGoal`: mục tiêu RUNTIME mỗi lượt (angle/distance/target_pose/params).
|
- `RecoveryGoal`: mục tiêu RUNTIME mỗi lượt (angle/distance/target_pose/params).
|
||||||
- `RecoveryResult` / `RecoveryStatus` / `RecoveryOutputType`: hợp đồng output hợp nhất 3 họ +
|
- `RecoveryResult` / `RecoveryStatus` / `RecoveryOutputType`: hợp đồng output hợp nhất 3 họ +
|
||||||
@@ -27,22 +27,20 @@ configure(name, ctx) // 1 lần: cache ctx, đọc config chung, onConf
|
|||||||
│
|
│
|
||||||
start(goal) // mỗi lượt: chốt mục tiêu runtime, onStart()
|
start(goal) // mỗi lượt: chốt mục tiêu runtime, onStart()
|
||||||
│
|
│
|
||||||
├── one-shot (họ A/B): update(dt) 1 lần ─────────► RecoveryResult{status, path|none, msg}
|
├── one-shot (họ A/B): update() 1 lần ───────────► RecoveryResult{status, path|none, msg}
|
||||||
│
|
│
|
||||||
└── per-cycle (họ C): loop { update(dt) } ──────► RecoveryResult{status, velocity,
|
└── per-cycle (họ C): loop { update() } ────────► RecoveryResult{status, velocity,
|
||||||
(tới khi status != kRunning) progress, remaining}
|
(tới khi status != kRunning) progress, remaining}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ghi chú thiết kế
|
## Ghi chú thiết kế
|
||||||
|
|
||||||
- Template-method: base xử lý guard vòng đời (configure→start→update), `dt<=0`, `timeout`, đo
|
- Template-method: base xử lý guard vòng đời (configure→start→update) và `cancel` một chỗ;
|
||||||
`elapsed`, và `cancel` một chỗ; plugin không lặp lại các guard này.
|
plugin không lặp lại các guard này.
|
||||||
- Mục tiêu là RUNTIME qua `RecoveryGoal` (không cố định trong config): cùng plugin phục vụ nhiều
|
- Mục tiêu là RUNTIME qua `RecoveryGoal` (không cố định trong config): cùng plugin phục vụ nhiều
|
||||||
yêu cầu góc/khoảng khác nhau. Field = 0 → dùng default plugin đọc ở `onConfigure()`.
|
yêu cầu góc/khoảng khác nhau. Field = 0 → dùng default plugin đọc ở `onConfigure()`.
|
||||||
- `onUpdate(dt)` lấy pose robot từ costmap/tf bên trong; không truyền pose qua tham số.
|
- `onUpdate()` lấy pose robot từ costmap/tf bên trong; không truyền pose qua tham số.
|
||||||
- Sau `cancel()`, base tự trả stop output (Twist 0) + `kCancelled`.
|
- Sau `cancel()`, base tự trả stop output (Twist 0) + `kCancelled`.
|
||||||
- Param chung duy nhất còn lại là `timeout` (s, 0 = không giới hạn), base đọc trong `configure()`
|
- Param RIÊNG của plugin đọc trong `onConfigure()`.
|
||||||
từ `~/<name>/timeout`; giá trị `NaN/Inf/<0` bị thay bằng 0. Param RIÊNG của plugin đọc trong
|
|
||||||
`onConfigure()`.
|
|
||||||
- Interface KHÔNG include Boost.DLL; export/import là việc của plugin/loader.
|
- Interface KHÔNG include Boost.DLL; export/import là việc của plugin/loader.
|
||||||
- Plugin mẫu có dùng Boost.DLL alias, nhưng core contract vẫn không biết loader/adaptor.
|
- Plugin mẫu có dùng Boost.DLL alias, nhưng core contract vẫn không biết loader/adaptor.
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ Package hiện có 4 plugin mẫu dưới `plugins/`:
|
|||||||
1. Kế thừa `recovery_core::RecoveryBehavior`.
|
1. Kế thừa `recovery_core::RecoveryBehavior`.
|
||||||
2. Override hook `onConfigure()` (tuỳ chọn) — đọc param riêng qua `robot::NodeHandle("~/" + name)`;
|
2. Override hook `onConfigure()` (tuỳ chọn) — đọc param riêng qua `robot::NodeHandle("~/" + name)`;
|
||||||
ngữ cảnh tf/global_path/costmap lấy qua `ctx()`.
|
ngữ cảnh tf/global_path/costmap lấy qua `ctx()`.
|
||||||
3. Override `onStart(goal)` + `onUpdate(dt)` theo họ (xem dưới). KHÔNG override
|
3. Override `onStart(goal)` + `onUpdate()` theo họ (xem dưới). KHÔNG override
|
||||||
`configure/start/update/cancel` — base đã lo guard vòng đời/timeout/cancel/elapsed.
|
`configure/start/update/cancel` — base đã lo guard vòng đời/cancel.
|
||||||
4. Thêm factory `static RecoveryBehaviorPtr create()` **không tham số** + `BOOST_DLL_ALIAS(...)`.
|
4. Thêm factory `static RecoveryBehaviorPtr create()` **không tham số** + `BOOST_DLL_ALIAS(...)`.
|
||||||
|
|
||||||
## Vòng đời (goal-driven)
|
## Vòng đời (goal-driven)
|
||||||
@@ -22,7 +22,7 @@ configure(name, ctx) // 1 lần: cache ctx, đọc config chung, gọi onCo
|
|||||||
│
|
│
|
||||||
start(goal) // mỗi lượt: chốt mục tiêu RUNTIME (angle/distance/pose), gọi onStart()
|
start(goal) // mỗi lượt: chốt mục tiêu RUNTIME (angle/distance/pose), gọi onStart()
|
||||||
│
|
│
|
||||||
loop update(dt) // mỗi cycle tới khi status != kRunning; base tick elapsed + guard
|
loop update() // mỗi cycle tới khi status != kRunning; base guard vòng đời/cancel
|
||||||
│
|
│
|
||||||
[cancel()] // update() kế tiếp -> stop output + kCancelled
|
[cancel()] // update() kế tiếp -> stop output + kCancelled
|
||||||
```
|
```
|
||||||
@@ -37,7 +37,7 @@ qua `goal.params` (vd `goal.params["angular_speed"] = 0.8`).
|
|||||||
|----|----------|--------|
|
|----|----------|--------|
|
||||||
| A. path | `onUpdate()` (one-shot) | `RecoveryResult::PathOut(path, kSucceeded)` |
|
| A. path | `onUpdate()` (one-shot) | `RecoveryResult::PathOut(path, kSucceeded)` |
|
||||||
| B. none | `onUpdate()` (one-shot) | `RecoveryResult::Succeeded()` / `Failed()` |
|
| B. none | `onUpdate()` (one-shot) | `RecoveryResult::Succeeded()` / `Failed()` |
|
||||||
| C. velocity | `onStart()` chốt goal + `onUpdate(dt)` mỗi cycle | `RecoveryResult::Velocity(twist, kRunning\|kSucceeded)` |
|
| C. velocity | `onStart()` chốt goal + `onUpdate()` mỗi cycle | `RecoveryResult::Velocity(twist, kRunning\|kSucceeded)` |
|
||||||
|
|
||||||
Mọi kết quả nên gắn feedback qua `.withProgress(progress, remaining)` và `.withMessage(...)` để
|
Mọi kết quả nên gắn feedback qua `.withProgress(progress, remaining)` và `.withMessage(...)` để
|
||||||
caller giám sát tiến độ (progress ∈ [0,1], remaining theo rad/m).
|
caller giám sát tiến độ (progress ∈ [0,1], remaining theo rad/m).
|
||||||
@@ -55,7 +55,7 @@ class SpinRecovery : public recovery_core::RecoveryBehavior {
|
|||||||
return std::make_shared<SpinRecovery>();
|
return std::make_shared<SpinRecovery>();
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
// override onConfigure()/onStart(goal)/onUpdate(dt)...
|
// override onConfigure()/onStart(goal)/onUpdate()...
|
||||||
};
|
};
|
||||||
} // namespace recovery_plugins
|
} // namespace recovery_plugins
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ recovery_core::RecoveryGoal goal;
|
|||||||
goal.angle = 1.57; // "quay 90 độ ngay lượt này"
|
goal.angle = 1.57; // "quay 90 độ ngay lượt này"
|
||||||
recovery_core::RecoveryResult r = behavior->start(goal);
|
recovery_core::RecoveryResult r = behavior->start(goal);
|
||||||
while (r.status == recovery_core::RecoveryStatus::kRunning) {
|
while (r.status == recovery_core::RecoveryStatus::kRunning) {
|
||||||
r = behavior->update(dt); // publish r.command; đọc r.progress/r.remaining/r.message
|
r = behavior->update(); // publish r.command; đọc r.progress/r.remaining/r.message
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -7,18 +7,17 @@
|
|||||||
- **Không collision-check tự động.** Interface không kiểm tra va chạm khi sinh vận tốc
|
- **Không collision-check tự động.** Interface không kiểm tra va chạm khi sinh vận tốc
|
||||||
(backup/spin) hay khi tạo path. Việc tránh va chạm là trách nhiệm của **plugin** (dùng
|
(backup/spin) hay khi tạo path. Việc tránh va chạm là trách nhiệm của **plugin** (dùng
|
||||||
costmap được cấp qua `initialize`) hoặc của **caller**.
|
costmap được cấp qua `initialize`) hoặc của **caller**.
|
||||||
- **Không quản lý vòng lặp thời gian thực.** Caller chịu trách nhiệm gọi `computeCommand(dt)`
|
- **Không quản lý vòng lặp thời gian thực.** Caller chịu trách nhiệm gọi `update()` đúng nhịp
|
||||||
đúng nhịp và publish command.
|
và publish command.
|
||||||
- **Không đảm bảo frame/đơn vị.** Pose lấy từ costmap/tf phải đúng frame; đơn vị phải nhất quán
|
- **Không đảm bảo frame/đơn vị.** Pose lấy từ costmap/tf phải đúng frame; đơn vị phải nhất quán
|
||||||
(m, rad, s, m/s, rad/s).
|
(m, rad, s, m/s, rad/s).
|
||||||
- **Guard vòng đời ở base.** `start()` trước `configure()`, hay `update()` trước `start()`, đều trả
|
- **Guard vòng đời ở base.** `start()` trước `configure()`, hay `update()` trước `start()`, đều trả
|
||||||
`RecoveryResult::Failed()`. `dt <= 0`, `NaN`, `Inf`, và `timeout` do base chặn trước khi gọi
|
`RecoveryResult::Failed()`. Sau `cancel()`, base trả stop output (Twist 0) + `kCancelled`.
|
||||||
`onUpdate()`. Sau `cancel()`, base trả stop output (Twist 0) + `kCancelled`.
|
|
||||||
|
|
||||||
## Nguyên tắc cho plugin
|
## Nguyên tắc cho plugin
|
||||||
|
|
||||||
- Guard costmap/tf null (lấy qua `ctx()`) trước khi thao tác; fail an toàn -> `RecoveryResult::Failed()`.
|
- Guard costmap/tf null (lấy qua `ctx()`) trước khi thao tác; fail an toàn -> `RecoveryResult::Failed()`.
|
||||||
- Không cần tự guard `dt <= 0`/`NaN`/`Inf`/`timeout` — base đã lo; chỉ tập trung logic recovery.
|
- Không cần tự guard vòng đời/cancel — base đã lo; plugin tập trung logic recovery.
|
||||||
- Với họ vận tốc: khi không chắc an toàn, trả **stop command** (Twist 0), không trả vận tốc mù.
|
- Với họ vận tốc: khi không chắc an toàn, trả **stop command** (Twist 0), không trả vận tốc mù.
|
||||||
- Kiểm tra NaN/Inf của pose/vận tốc trước khi xuất command.
|
- Kiểm tra NaN/Inf của pose/vận tốc trước khi xuất command.
|
||||||
- Tôn trọng giới hạn vận tốc/gia tốc của robot (đọc qua param).
|
- Tôn trọng giới hạn vận tốc/gia tốc của robot (đọc qua param).
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
* recovery_core — interface (base class) cho recovery behaviors.
|
* recovery_core — interface (base class) cho recovery behaviors.
|
||||||
*
|
*
|
||||||
* Vòng đời hợp nhất, hướng-goal cho cả 3 họ recovery (path / none / velocity):
|
* Vòng đời hợp nhất, hướng-goal cho cả 3 họ recovery (path / none / velocity):
|
||||||
* configure(name, ctx) -> start(goal) -> lặp update(dt) -> [cancel()]
|
* configure(name, ctx) -> start(goal) -> lặp update() -> [cancel()]
|
||||||
* Base lo phần chung (guard init/dt/timeout/cancel, đo elapsed, đẩy feedback); plugin chỉ
|
* Base lo phần chung (guard init/cancel, đẩy feedback); plugin chỉ
|
||||||
* override các hook nhỏ onConfigure()/onStart()/onUpdate().
|
* override các hook nhỏ onConfigure()/onStart()/onUpdate().
|
||||||
*
|
*
|
||||||
* Author: DuongTD
|
* Author: DuongTD
|
||||||
@@ -35,7 +35,7 @@ namespace recovery_core
|
|||||||
* và do base xử lý phần lặp lại; plugin chỉ triển khai các hook protected:
|
* và do base xử lý phần lặp lại; plugin chỉ triển khai các hook protected:
|
||||||
* - onConfigure() : đọc param riêng từ ctx()/NodeHandle (tuỳ chọn).
|
* - onConfigure() : đọc param riêng từ ctx()/NodeHandle (tuỳ chọn).
|
||||||
* - onStart(goal) : chốt mục tiêu lượt này (rad/m/pose), reset trạng thái tiến độ.
|
* - onStart(goal) : chốt mục tiêu lượt này (rad/m/pose), reset trạng thái tiến độ.
|
||||||
* - onUpdate(dt) : một "tick"; họ one-shot (path/clear) hoàn tất ngay lần đầu.
|
* - onUpdate() : một "tick"; họ one-shot (path/clear) hoàn tất ngay lần đầu.
|
||||||
*
|
*
|
||||||
* Ba họ hành vi:
|
* Ba họ hành vi:
|
||||||
* - Họ A (trả path) : onUpdate() trả RecoveryResult::PathOut(...), kSucceeded ngay.
|
* - Họ A (trả path) : onUpdate() trả RecoveryResult::PathOut(...), kSucceeded ngay.
|
||||||
@@ -73,10 +73,9 @@ public:
|
|||||||
RecoveryResult start(const RecoveryGoal& goal);
|
RecoveryResult start(const RecoveryGoal& goal);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Một control cycle. Guard chưa start/dt<=0/timeout/cancel trước khi gọi onUpdate().
|
* @brief Một control cycle. Guard chưa start/cancel trước khi gọi onUpdate().
|
||||||
* @param dt Khoảng thời gian control cycle (s), > 0.
|
|
||||||
*/
|
*/
|
||||||
RecoveryResult update(double dt);
|
RecoveryResult update();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Yêu cầu huỷ: update() kế tiếp trả stop output + kCancelled.
|
* @brief Yêu cầu huỷ: update() kế tiếp trả stop output + kCancelled.
|
||||||
@@ -89,12 +88,6 @@ public:
|
|||||||
return status_;
|
return status_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Thời gian đã trôi từ start() (s).
|
|
||||||
double elapsed() const
|
|
||||||
{
|
|
||||||
return elapsed_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string& name() const
|
const std::string& name() const
|
||||||
{
|
{
|
||||||
return name_;
|
return name_;
|
||||||
@@ -120,7 +113,7 @@ protected:
|
|||||||
virtual RecoveryResult onStart(const RecoveryGoal& goal) = 0;
|
virtual RecoveryResult onStart(const RecoveryGoal& goal) = 0;
|
||||||
|
|
||||||
/// @brief Một tick. Họ one-shot trả kSucceeded/kFailed ngay; họ velocity trả kRunning tới goal.
|
/// @brief Một tick. Họ one-shot trả kSucceeded/kFailed ngay; họ velocity trả kRunning tới goal.
|
||||||
virtual RecoveryResult onUpdate(double dt) = 0;
|
virtual RecoveryResult onUpdate() = 0;
|
||||||
|
|
||||||
// Truy cập cho plugin (chỉ đọc ngữ cảnh/goal).
|
// Truy cập cho plugin (chỉ đọc ngữ cảnh/goal).
|
||||||
const RecoveryContext& ctx() const { return ctx_; }
|
const RecoveryContext& ctx() const { return ctx_; }
|
||||||
@@ -130,8 +123,6 @@ protected:
|
|||||||
RecoveryContext ctx_;
|
RecoveryContext ctx_;
|
||||||
RecoveryGoal goal_;
|
RecoveryGoal goal_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
double timeout_ = 0.0; ///< s — 0 nghĩa là không timeout; đọc param "~/<name>/timeout".
|
|
||||||
double elapsed_ = 0.0;
|
|
||||||
bool configured_ = false;
|
bool configured_ = false;
|
||||||
bool started_ = false;
|
bool started_ = false;
|
||||||
bool cancel_requested_ = false;
|
bool cancel_requested_ = false;
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace
|
|||||||
{
|
{
|
||||||
constexpr double kDefaultBackupDistance = 0.5; // m.
|
constexpr double kDefaultBackupDistance = 0.5; // m.
|
||||||
constexpr double kDefaultLinearSpeed = 0.1; // m/s.
|
constexpr double kDefaultLinearSpeed = 0.1; // m/s.
|
||||||
|
constexpr double kDefaultControlPeriod = 0.1; // s per update tick.
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +49,7 @@ protected:
|
|||||||
robot::NodeHandle private_nh("~/" + name_);
|
robot::NodeHandle private_nh("~/" + name_);
|
||||||
private_nh.param("backup_distance", default_backup_distance_, kDefaultBackupDistance);
|
private_nh.param("backup_distance", default_backup_distance_, kDefaultBackupDistance);
|
||||||
private_nh.param("linear_speed", default_linear_speed_, kDefaultLinearSpeed);
|
private_nh.param("linear_speed", default_linear_speed_, kDefaultLinearSpeed);
|
||||||
|
private_nh.param("control_period", control_period_, kDefaultControlPeriod);
|
||||||
private_nh.param("require_costmap", require_costmap_, false);
|
private_nh.param("require_costmap", require_costmap_, false);
|
||||||
|
|
||||||
if (!std::isfinite(default_backup_distance_) || default_backup_distance_ <= 0.0)
|
if (!std::isfinite(default_backup_distance_) || default_backup_distance_ <= 0.0)
|
||||||
@@ -62,6 +64,12 @@ protected:
|
|||||||
name_.c_str());
|
name_.c_str());
|
||||||
default_linear_speed_ = kDefaultLinearSpeed;
|
default_linear_speed_ = kDefaultLinearSpeed;
|
||||||
}
|
}
|
||||||
|
if (!std::isfinite(control_period_) || control_period_ <= 0.0)
|
||||||
|
{
|
||||||
|
robot::log_warning("[recovery_core] Invalid control_period for '%s'; using 0.1 s.",
|
||||||
|
name_.c_str());
|
||||||
|
control_period_ = kDefaultControlPeriod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onStart(const recovery_core::RecoveryGoal& goal) override
|
recovery_core::RecoveryResult onStart(const recovery_core::RecoveryGoal& goal) override
|
||||||
@@ -89,7 +97,7 @@ protected:
|
|||||||
.withMessage("backup start");
|
.withMessage("backup start");
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onUpdate(double dt) override
|
recovery_core::RecoveryResult onUpdate() override
|
||||||
{
|
{
|
||||||
if (traveled_distance_ >= backup_distance_)
|
if (traveled_distance_ >= backup_distance_)
|
||||||
{
|
{
|
||||||
@@ -98,8 +106,8 @@ protected:
|
|||||||
|
|
||||||
robot_geometry_msgs::Twist command;
|
robot_geometry_msgs::Twist command;
|
||||||
command.linear.x = -std::abs(linear_speed_);
|
command.linear.x = -std::abs(linear_speed_);
|
||||||
traveled_distance_ =
|
traveled_distance_ = std::min(
|
||||||
std::min(backup_distance_, traveled_distance_ + std::abs(command.linear.x) * dt);
|
backup_distance_, traveled_distance_ + std::abs(command.linear.x) * control_period_);
|
||||||
|
|
||||||
if (traveled_distance_ >= backup_distance_)
|
if (traveled_distance_ >= backup_distance_)
|
||||||
{
|
{
|
||||||
@@ -124,6 +132,7 @@ private:
|
|||||||
|
|
||||||
double default_backup_distance_ = kDefaultBackupDistance;
|
double default_backup_distance_ = kDefaultBackupDistance;
|
||||||
double default_linear_speed_ = kDefaultLinearSpeed;
|
double default_linear_speed_ = kDefaultLinearSpeed;
|
||||||
|
double control_period_ = kDefaultControlPeriod;
|
||||||
bool require_costmap_ = false;
|
bool require_costmap_ = false;
|
||||||
|
|
||||||
double backup_distance_ = kDefaultBackupDistance;
|
double backup_distance_ = kDefaultBackupDistance;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ protected:
|
|||||||
return recovery_core::RecoveryResult::Running().withMessage("clear costmap start");
|
return recovery_core::RecoveryResult::Running().withMessage("clear costmap start");
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onUpdate(double /*dt*/) override
|
recovery_core::RecoveryResult onUpdate() override
|
||||||
{
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (affected_maps_ == "global" || affected_maps_ == "both")
|
if (affected_maps_ == "global" || affected_maps_ == "both")
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ protected:
|
|||||||
.withMessage("regen path start");
|
.withMessage("regen path start");
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onUpdate(double /*dt*/) override
|
recovery_core::RecoveryResult onUpdate() override
|
||||||
{
|
{
|
||||||
const auto* global_path = ctx().global_path;
|
const auto* global_path = ctx().global_path;
|
||||||
if (global_path == nullptr || global_path->empty())
|
if (global_path == nullptr || global_path->empty())
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ namespace
|
|||||||
{
|
{
|
||||||
constexpr double kDefaultTargetAngle = 1.57079632679; // pi/2 rad.
|
constexpr double kDefaultTargetAngle = 1.57079632679; // pi/2 rad.
|
||||||
constexpr double kDefaultAngularSpeed = 0.4; // rad/s.
|
constexpr double kDefaultAngularSpeed = 0.4; // rad/s.
|
||||||
|
constexpr double kDefaultControlPeriod = 0.1; // s per update tick.
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,6 +49,7 @@ protected:
|
|||||||
robot::NodeHandle private_nh("~/" + name_);
|
robot::NodeHandle private_nh("~/" + name_);
|
||||||
private_nh.param("target_angle", default_target_angle_, kDefaultTargetAngle);
|
private_nh.param("target_angle", default_target_angle_, kDefaultTargetAngle);
|
||||||
private_nh.param("angular_speed", default_angular_speed_, kDefaultAngularSpeed);
|
private_nh.param("angular_speed", default_angular_speed_, kDefaultAngularSpeed);
|
||||||
|
private_nh.param("control_period", control_period_, kDefaultControlPeriod);
|
||||||
|
|
||||||
if (!std::isfinite(default_target_angle_) || std::abs(default_target_angle_) <= 0.0)
|
if (!std::isfinite(default_target_angle_) || std::abs(default_target_angle_) <= 0.0)
|
||||||
{
|
{
|
||||||
@@ -61,6 +63,12 @@ protected:
|
|||||||
name_.c_str());
|
name_.c_str());
|
||||||
default_angular_speed_ = kDefaultAngularSpeed;
|
default_angular_speed_ = kDefaultAngularSpeed;
|
||||||
}
|
}
|
||||||
|
if (!std::isfinite(control_period_) || control_period_ <= 0.0)
|
||||||
|
{
|
||||||
|
robot::log_warning("[recovery_core] Invalid control_period for '%s'; using 0.1 s.",
|
||||||
|
name_.c_str());
|
||||||
|
control_period_ = kDefaultControlPeriod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onStart(const recovery_core::RecoveryGoal& goal) override
|
recovery_core::RecoveryResult onStart(const recovery_core::RecoveryGoal& goal) override
|
||||||
@@ -83,7 +91,7 @@ protected:
|
|||||||
.withMessage("rotate start");
|
.withMessage("rotate start");
|
||||||
}
|
}
|
||||||
|
|
||||||
recovery_core::RecoveryResult onUpdate(double dt) override
|
recovery_core::RecoveryResult onUpdate() override
|
||||||
{
|
{
|
||||||
const double target = std::abs(target_angle_);
|
const double target = std::abs(target_angle_);
|
||||||
|
|
||||||
@@ -94,7 +102,8 @@ protected:
|
|||||||
|
|
||||||
robot_geometry_msgs::Twist command;
|
robot_geometry_msgs::Twist command;
|
||||||
command.angular.z = std::copysign(angular_speed_, target_angle_);
|
command.angular.z = std::copysign(angular_speed_, target_angle_);
|
||||||
rotated_angle_ = std::min(target, rotated_angle_ + std::abs(command.angular.z) * dt);
|
rotated_angle_ =
|
||||||
|
std::min(target, rotated_angle_ + std::abs(command.angular.z) * control_period_);
|
||||||
|
|
||||||
if (rotated_angle_ >= target)
|
if (rotated_angle_ >= target)
|
||||||
{
|
{
|
||||||
@@ -118,6 +127,7 @@ private:
|
|||||||
|
|
||||||
double default_target_angle_ = kDefaultTargetAngle;
|
double default_target_angle_ = kDefaultTargetAngle;
|
||||||
double default_angular_speed_ = kDefaultAngularSpeed;
|
double default_angular_speed_ = kDefaultAngularSpeed;
|
||||||
|
double control_period_ = kDefaultControlPeriod;
|
||||||
|
|
||||||
double target_angle_ = kDefaultTargetAngle;
|
double target_angle_ = kDefaultTargetAngle;
|
||||||
double angular_speed_ = kDefaultAngularSpeed;
|
double angular_speed_ = kDefaultAngularSpeed;
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* recovery_core — phần chung (template-method) của RecoveryBehavior.
|
* recovery_core — phần chung (template-method) của RecoveryBehavior.
|
||||||
*
|
*
|
||||||
* configure()/start()/update()/cancel() là NON-VIRTUAL: base lo guard vòng đời, timeout, đo
|
* configure()/start()/update()/cancel() là NON-VIRTUAL: base lo guard vòng đời và xử lý
|
||||||
* elapsed, và xử lý cancel; plugin chỉ triển khai onConfigure()/onStart()/onUpdate().
|
* cancel; plugin chỉ triển khai onConfigure()/onStart()/onUpdate().
|
||||||
*
|
*
|
||||||
* Author: DuongTD
|
* Author: DuongTD
|
||||||
*********************************************************************/
|
*********************************************************************/
|
||||||
#include <recovery_core/recovery_behavior.h>
|
#include <recovery_core/recovery_behavior.h>
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
|
|
||||||
#include <robot/robot.h>
|
|
||||||
|
|
||||||
namespace recovery_core
|
namespace recovery_core
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
@@ -20,11 +16,6 @@ robot_geometry_msgs::Twist zeroTwist()
|
|||||||
{
|
{
|
||||||
return robot_geometry_msgs::Twist();
|
return robot_geometry_msgs::Twist();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool validCycle(double dt)
|
|
||||||
{
|
|
||||||
return std::isfinite(dt) && dt > 0.0;
|
|
||||||
}
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void RecoveryBehavior::configure(const std::string& name, const RecoveryContext& ctx)
|
void RecoveryBehavior::configure(const std::string& name, const RecoveryContext& ctx)
|
||||||
@@ -38,16 +29,6 @@ void RecoveryBehavior::configure(const std::string& name, const RecoveryContext&
|
|||||||
ctx_ = ctx;
|
ctx_ = ctx;
|
||||||
status_ = RecoveryStatus::kIdle;
|
status_ = RecoveryStatus::kIdle;
|
||||||
|
|
||||||
// Param chung duy nhất còn lại: timeout (s, 0 = không giới hạn).
|
|
||||||
robot::NodeHandle private_nh("~/" + name_);
|
|
||||||
private_nh.param("timeout", timeout_, 0.0);
|
|
||||||
if (!std::isfinite(timeout_) || timeout_ < 0.0)
|
|
||||||
{
|
|
||||||
robot::log_warning("[recovery_core] Invalid timeout for '%s'; using 0 (no timeout).",
|
|
||||||
name_.c_str());
|
|
||||||
timeout_ = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
onConfigure();
|
onConfigure();
|
||||||
|
|
||||||
configured_ = true;
|
configured_ = true;
|
||||||
@@ -62,15 +43,16 @@ RecoveryResult RecoveryBehavior::start(const RecoveryGoal& goal)
|
|||||||
}
|
}
|
||||||
|
|
||||||
goal_ = goal;
|
goal_ = goal;
|
||||||
elapsed_ = 0.0;
|
|
||||||
cancel_requested_ = false;
|
cancel_requested_ = false;
|
||||||
started_ = true;
|
started_ = true;
|
||||||
status_ = RecoveryStatus::kRunning;
|
status_ = RecoveryStatus::kRunning;
|
||||||
|
|
||||||
return onStart(goal_);
|
RecoveryResult result = onStart(goal_);
|
||||||
|
status_ = result.status;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecoveryResult RecoveryBehavior::update(double dt)
|
RecoveryResult RecoveryBehavior::update()
|
||||||
{
|
{
|
||||||
if (!configured_ || !started_)
|
if (!configured_ || !started_)
|
||||||
{
|
{
|
||||||
@@ -91,21 +73,7 @@ RecoveryResult RecoveryBehavior::update(double dt)
|
|||||||
.withMessage("cancelled by caller");
|
.withMessage("cancelled by caller");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validCycle(dt))
|
RecoveryResult result = onUpdate();
|
||||||
{
|
|
||||||
status_ = RecoveryStatus::kFailed;
|
|
||||||
return RecoveryResult::Velocity(zeroTwist(), status_).withMessage("invalid dt");
|
|
||||||
}
|
|
||||||
|
|
||||||
elapsed_ += dt;
|
|
||||||
if (config_.timeout > 0.0 && elapsed_ > config_.timeout)
|
|
||||||
{
|
|
||||||
status_ = RecoveryStatus::kFailed;
|
|
||||||
return RecoveryResult::Velocity(zeroTwist(), status_).withMessage("timeout");
|
|
||||||
}
|
|
||||||
|
|
||||||
RecoveryResult result = onUpdate(dt);
|
|
||||||
result.elapsed = elapsed_;
|
|
||||||
status_ = result.status;
|
status_ = result.status;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ for(const auto& behavior : creators_)
|
|||||||
expect(started.status == recovery_core::RecoveryStatus::kRunning,
|
expect(started.status == recovery_core::RecoveryStatus::kRunning,
|
||||||
"rotate must be running right after start");
|
"rotate must be running right after start");
|
||||||
|
|
||||||
const recovery_core::RecoveryResult first = behavior->update(0.1);
|
const recovery_core::RecoveryResult first = behavior->update();
|
||||||
expect(first.status == recovery_core::RecoveryStatus::kRunning,
|
expect(first.status == recovery_core::RecoveryStatus::kRunning,
|
||||||
"rotate first cycle must be running");
|
"rotate first cycle must be running");
|
||||||
expect(first.output_type == recovery_core::RecoveryOutputType::kVelocity,
|
expect(first.output_type == recovery_core::RecoveryOutputType::kVelocity,
|
||||||
@@ -193,7 +193,7 @@ for(const auto& behavior : creators_)
|
|||||||
recovery_core::RecoveryResult last = first;
|
recovery_core::RecoveryResult last = first;
|
||||||
for (int i = 0; i < 100 && last.status == recovery_core::RecoveryStatus::kRunning; ++i)
|
for (int i = 0; i < 100 && last.status == recovery_core::RecoveryStatus::kRunning; ++i)
|
||||||
{
|
{
|
||||||
last = behavior->update(0.1);
|
last = behavior->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(last.status == recovery_core::RecoveryStatus::kSucceeded,
|
expect(last.status == recovery_core::RecoveryStatus::kSucceeded,
|
||||||
@@ -219,7 +219,7 @@ for(const auto& behavior : creators_)
|
|||||||
goal.distance = 0.3;
|
goal.distance = 0.3;
|
||||||
|
|
||||||
behavior->start(goal);
|
behavior->start(goal);
|
||||||
const recovery_core::RecoveryResult first = behavior->update(0.1);
|
const recovery_core::RecoveryResult first = behavior->update();
|
||||||
expect(first.status == recovery_core::RecoveryStatus::kRunning,
|
expect(first.status == recovery_core::RecoveryStatus::kRunning,
|
||||||
"backup first cycle must be running");
|
"backup first cycle must be running");
|
||||||
expect(first.command.linear.x < 0.0, "backup must command negative linear.x");
|
expect(first.command.linear.x < 0.0, "backup must command negative linear.x");
|
||||||
@@ -227,7 +227,7 @@ for(const auto& behavior : creators_)
|
|||||||
recovery_core::RecoveryResult last = first;
|
recovery_core::RecoveryResult last = first;
|
||||||
for (int i = 0; i < 1000 && last.status == recovery_core::RecoveryStatus::kRunning; ++i)
|
for (int i = 0; i < 1000 && last.status == recovery_core::RecoveryStatus::kRunning; ++i)
|
||||||
{
|
{
|
||||||
last = behavior->update(0.1);
|
last = behavior->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(last.status == recovery_core::RecoveryStatus::kSucceeded,
|
expect(last.status == recovery_core::RecoveryStatus::kSucceeded,
|
||||||
@@ -254,7 +254,7 @@ global_path_.push_back(pose2);
|
|||||||
if(behavior->getNameRecoveryBehavior() == "regen_path_rc")
|
if(behavior->getNameRecoveryBehavior() == "regen_path_rc")
|
||||||
{
|
{
|
||||||
behavior->start(recovery_core::RecoveryGoal());
|
behavior->start(recovery_core::RecoveryGoal());
|
||||||
const recovery_core::RecoveryResult result = behavior->update(0.1);
|
const recovery_core::RecoveryResult result = behavior->update();
|
||||||
|
|
||||||
expect(result.status == recovery_core::RecoveryStatus::kSucceeded,
|
expect(result.status == recovery_core::RecoveryStatus::kSucceeded,
|
||||||
"regen path must succeed with a non-empty global path");
|
"regen path must succeed with a non-empty global path");
|
||||||
|
|||||||
Reference in New Issue
Block a user