first commit
This commit is contained in:
483
INIT_USAGE.md
Normal file
483
INIT_USAGE.md
Normal file
@@ -0,0 +1,483 @@
|
||||
# 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()`
|
||||
|
||||
Reference in New Issue
Block a user