robot_cpp/INIT_USAGE.md
2026-01-31 17:20:07 +07:00

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()`