484 lines
9.8 KiB
Markdown
484 lines
9.8 KiB
Markdown
# robot::ok() - Hướng dẫn sử dụng
|
|
|
|
## Tổng quan
|
|
|
|
`robot::ok()` và các hàm liên quan cung cấp cơ chế quản lý vòng đời của robot system, tương tự như `ros::ok()` trong ROS. Chúng cho phép bạn kiểm tra trạng thái system và xử lý shutdown một cách graceful.
|
|
|
|
## API Reference
|
|
|
|
### `bool robot::ok()`
|
|
|
|
Kiểm tra xem robot system có đang chạy không.
|
|
|
|
- **Trả về `true`**: System đang chạy bình thường
|
|
- **Trả về `false`**: System đã shutdown hoàn toàn
|
|
|
|
### `bool robot::isShuttingDown()`
|
|
|
|
Kiểm tra xem shutdown đã được yêu cầu chưa.
|
|
|
|
- **Trả về `true`**: Shutdown đã được yêu cầu (ngay lập tức)
|
|
- **Trả về `false`**: System vẫn đang chạy
|
|
|
|
### `void robot::shutdown()`
|
|
|
|
Bắt đầu quá trình shutdown system.
|
|
|
|
### `void robot::init(int& argc, char** argv, const std::string& node_name = "", bool install_sigint_handler = true)`
|
|
|
|
Khởi tạo robot system.
|
|
|
|
- `argc`, `argv`: Command line arguments (có thể được modify)
|
|
- `node_name`: Tên node (optional, dùng cho logging)
|
|
- `install_sigint_handler`: Nếu `true`, tự động xử lý Ctrl-C (default: `true`)
|
|
|
|
### `void robot::init(const std::string& node_name = "", bool install_sigint_handler = true)`
|
|
|
|
Khởi tạo robot system không cần command line arguments.
|
|
|
|
## Cách sử dụng cơ bản
|
|
|
|
### 1. Main Loop với Rate
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <robot/time.h>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
// Initialize robot system
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
robot::Rate rate(10); // 10 Hz
|
|
|
|
// Main loop
|
|
while (robot::ok())
|
|
{
|
|
// Do work here
|
|
std::cout << "Running..." << std::endl;
|
|
|
|
rate.sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 2. Main Loop không dùng Rate
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <robot/time.h>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
while (robot::ok())
|
|
{
|
|
// Do work
|
|
robot::Duration(0.1).sleep(); // Sleep 100ms
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 3. Thread Loop
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <thread>
|
|
#include <atomic>
|
|
|
|
std::atomic<bool> stop_flag_(false);
|
|
|
|
void myThread()
|
|
{
|
|
while (robot::ok() && !stop_flag_)
|
|
{
|
|
// Do work in thread
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
std::thread t(myThread);
|
|
|
|
// Main loop
|
|
while (robot::ok())
|
|
{
|
|
// Do main work
|
|
robot::Duration(1.0).sleep();
|
|
}
|
|
|
|
stop_flag_ = true;
|
|
t.join();
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 4. Long-running Callback với Early Exit
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
|
|
void processLargeData(const std::vector<int>& data)
|
|
{
|
|
for (size_t i = 0; i < data.size(); i++)
|
|
{
|
|
// Check if shutdown requested
|
|
if (robot::isShuttingDown())
|
|
{
|
|
std::cout << "Shutdown requested, exiting early" << std::endl;
|
|
return; // Exit early
|
|
}
|
|
|
|
// Process data[i]...
|
|
processItem(data[i]);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
std::vector<int> large_data(1000000);
|
|
// ... fill data ...
|
|
|
|
while (robot::ok())
|
|
{
|
|
processLargeData(large_data);
|
|
robot::Duration(1.0).sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 5. Custom SIGINT Handler
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <signal.h>
|
|
#include <robot/time.h>
|
|
|
|
void mySigintHandler(int sig)
|
|
{
|
|
(void)sig;
|
|
|
|
// Do custom cleanup
|
|
std::cout << "Custom cleanup before shutdown..." << std::endl;
|
|
|
|
// Publish stop message, save state, etc.
|
|
|
|
// Call shutdown
|
|
robot::shutdown();
|
|
}
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
// Initialize without SIGINT handler
|
|
robot::init(argc, argv, "my_node", false);
|
|
|
|
// Install custom handler
|
|
signal(SIGINT, mySigintHandler);
|
|
|
|
while (robot::ok())
|
|
{
|
|
// Do work
|
|
robot::Duration(0.1).sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 6. Nested Loops
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <robot/time.h>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
while (robot::ok()) // Outer loop
|
|
{
|
|
// Setup connection
|
|
bool connected = connectToDevice();
|
|
|
|
while (robot::ok() && connected) // Inner loop
|
|
{
|
|
// Do work with device
|
|
if (!deviceIsAlive())
|
|
{
|
|
connected = false;
|
|
break;
|
|
}
|
|
|
|
robot::Duration(0.1).sleep();
|
|
}
|
|
|
|
// Reconnect after delay
|
|
robot::Duration(1.0).sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### 7. Multiple Conditions
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <robot/time.h>
|
|
#include <atomic>
|
|
|
|
std::atomic<bool> cancel_(false);
|
|
std::atomic<bool> connected_(false);
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
|
|
while (robot::ok() && !cancel_ && connected_)
|
|
{
|
|
// Do work only if all conditions are met
|
|
processData();
|
|
|
|
robot::Duration(0.1).sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
## So sánh với ROS
|
|
|
|
### Tương đương với ROS:
|
|
|
|
| ROS | robot:: | Mô tả |
|
|
|-----|---------|-------|
|
|
| `ros::ok()` | `robot::ok()` | Kiểm tra system đang chạy |
|
|
| `ros::isShuttingDown()` | `robot::isShuttingDown()` | Kiểm tra shutdown được yêu cầu |
|
|
| `ros::shutdown()` | `robot::shutdown()` | Bắt đầu shutdown |
|
|
| `ros::init(argc, argv, "node")` | `robot::init(argc, argv, "node")` | Khởi tạo system |
|
|
|
|
### Ví dụ chuyển đổi từ ROS:
|
|
|
|
**ROS Code:**
|
|
```cpp
|
|
#include <ros/ros.h>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
ros::init(argc, argv, "my_node");
|
|
ros::NodeHandle nh;
|
|
ros::Rate rate(10);
|
|
|
|
while (ros::ok())
|
|
{
|
|
ros::spinOnce();
|
|
rate.sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
**robot:: Code:**
|
|
```cpp
|
|
#include <robot/init.h>
|
|
#include <robot/time.h>
|
|
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
robot::Rate rate(10);
|
|
|
|
while (robot::ok())
|
|
{
|
|
// Do work (no ros::spinOnce() equivalent needed)
|
|
rate.sleep();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
## Best Practices
|
|
|
|
### ✅ Nên làm:
|
|
|
|
1. **Luôn gọi `robot::init()` trước khi dùng các hàm khác**
|
|
```cpp
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node");
|
|
// ... rest of code
|
|
}
|
|
```
|
|
|
|
2. **Luôn kiểm tra `robot::ok()` trong vòng lặp chính**
|
|
```cpp
|
|
while (robot::ok())
|
|
{
|
|
// Do work
|
|
}
|
|
```
|
|
|
|
3. **Kiểm tra trong thread loops**
|
|
```cpp
|
|
while (robot::ok() && !stop_flag_)
|
|
{
|
|
// Thread work
|
|
}
|
|
```
|
|
|
|
4. **Dùng `robot::isShuttingDown()` trong callback dài**
|
|
```cpp
|
|
if (robot::isShuttingDown()) return;
|
|
```
|
|
|
|
5. **Kết hợp với các điều kiện khác**
|
|
```cpp
|
|
while (robot::ok() && connected && !cancel_)
|
|
{
|
|
// Work
|
|
}
|
|
```
|
|
|
|
### ❌ Không nên:
|
|
|
|
1. **Không bỏ qua kiểm tra trong thread**
|
|
- Thread có thể chạy mãi nếu không kiểm tra
|
|
|
|
2. **Không dùng `robot::ok()` trong callback ngắn**
|
|
- Callback ngắn sẽ chạy xong trước khi shutdown
|
|
- Dùng `robot::isShuttingDown()` thay vì
|
|
|
|
3. **Không gọi `robot::shutdown()` trong callback**
|
|
- Có thể gây deadlock
|
|
- Để shutdown tự nhiên hoặc dùng flag
|
|
|
|
## Shutdown Process
|
|
|
|
### Quy trình shutdown:
|
|
|
|
1. **SIGINT (Ctrl-C) được gửi** hoặc `robot::shutdown()` được gọi
|
|
2. **`robot::isShuttingDown()`** → `true` (ngay lập tức)
|
|
3. **`robot::ok()`** → vẫn `true` (chưa shutdown hoàn toàn)
|
|
4. **Resources được cleanup** (nếu có)
|
|
5. **`robot::ok()`** → `false` (shutdown hoàn tất)
|
|
|
|
### Timeline:
|
|
|
|
```
|
|
Time | Event | ok() | isShuttingDown()
|
|
--------|--------------------------|------|------------------
|
|
T0 | System running | true | false
|
|
T1 | Ctrl-C pressed | true | false
|
|
T2 | shutdown() called | true | true ← isShuttingDown() = true
|
|
T3 | Cleanup in progress | true | true
|
|
T4 | Cleanup complete | false| true ← ok() = false
|
|
```
|
|
|
|
## Ví dụ thực tế trong move_base
|
|
|
|
Bạn có thể sử dụng trong `planThread()`:
|
|
|
|
```cpp
|
|
#include <robot/init.h>
|
|
|
|
void move_base::MoveBase::planThread()
|
|
{
|
|
robot::Timer timer;
|
|
bool wait_for_wake = false;
|
|
boost::unique_lock<boost::recursive_mutex> lock(planner_mutex_);
|
|
|
|
while (robot::ok()) // ← Thêm kiểm tra này
|
|
{
|
|
// ... existing code ...
|
|
|
|
while (wait_for_wake || !runPlanner_)
|
|
{
|
|
if (!robot::ok()) // ← Kiểm tra trước khi wait
|
|
break;
|
|
|
|
planner_cond_.wait(lock);
|
|
wait_for_wake = false;
|
|
}
|
|
|
|
// ... rest of code ...
|
|
}
|
|
}
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
### Vấn đề: Thread không dừng khi shutdown
|
|
|
|
**Nguyên nhân**: Không kiểm tra `robot::ok()` trong thread loop
|
|
|
|
**Giải pháp**:
|
|
```cpp
|
|
void myThread()
|
|
{
|
|
while (robot::ok() && !stop_flag_) // ← Thêm robot::ok()
|
|
{
|
|
// Work
|
|
}
|
|
}
|
|
```
|
|
|
|
### Vấn đề: Callback dài không exit khi shutdown
|
|
|
|
**Nguyên nhân**: Không kiểm tra `robot::isShuttingDown()`
|
|
|
|
**Giải pháp**:
|
|
```cpp
|
|
void longCallback()
|
|
{
|
|
for (int i = 0; i < 1000000; i++)
|
|
{
|
|
if (robot::isShuttingDown()) // ← Thêm kiểm tra
|
|
return;
|
|
// Work
|
|
}
|
|
}
|
|
```
|
|
|
|
### Vấn đề: Shutdown không hoạt động
|
|
|
|
**Nguyên nhân**: Chưa gọi `robot::init()`
|
|
|
|
**Giải pháp**:
|
|
```cpp
|
|
int main(int argc, char** argv)
|
|
{
|
|
robot::init(argc, argv, "my_node"); // ← Phải gọi init() trước
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## Tóm tắt
|
|
|
|
- **`robot::ok()`**: Kiểm tra system đã shutdown hoàn toàn chưa → dùng trong loops
|
|
- **`robot::isShuttingDown()`**: Kiểm tra shutdown đã được yêu cầu chưa → dùng trong callback dài
|
|
- **`robot::shutdown()`**: Bắt đầu shutdown process
|
|
- **`robot::init()`**: Khởi tạo system (phải gọi trước khi dùng các hàm khác)
|
|
- **Luôn kiểm tra** trong vòng lặp chính và thread loops
|
|
- **Mặc định** tự động xử lý SIGINT (Ctrl-C)
|
|
|
|
## Tài liệu tham khảo
|
|
|
|
- [ROS Wiki - Initialization and Shutdown](https://wiki.ros.org/roscpp/Overview/Initialization%20and%20Shutdown)
|
|
- `robot_time/ROS_OK_EXPLANATION.md` - Giải thích chi tiết về `ros::ok()`
|
|
|