213 lines
5.9 KiB
Markdown
213 lines
5.9 KiB
Markdown
# TimerEvent - Giải thích và Cách sử dụng
|
|
|
|
## TimerEvent là gì?
|
|
|
|
`TimerEvent` là một structure chứa thông tin về timing của timer callback. Nó được truyền vào mỗi lần callback được gọi, giúp bạn biết:
|
|
- Timer có chạy đúng thời gian không?
|
|
- Timer có bị delay không?
|
|
- Khoảng thời gian thực tế giữa các lần callback
|
|
|
|
## Các thành phần của TimerEvent
|
|
|
|
```cpp
|
|
struct TimerEvent
|
|
{
|
|
Time current_real; // Thời gian thực tế khi callback được gọi
|
|
Time current_expected; // Thời gian dự kiến khi callback nên được gọi
|
|
Time last_real; // Thời gian thực tế của lần callback trước
|
|
Time last_expected; // Thời gian dự kiến của lần callback trước
|
|
Duration last_duration; // Khoảng thời gian thực tế giữa 2 lần callback
|
|
};
|
|
```
|
|
|
|
## Tại sao cần TimerEvent?
|
|
|
|
### 1. **Phát hiện Timer Drift (Lệch thời gian)**
|
|
|
|
Timer có thể bị lệch do:
|
|
- Hệ thống bận
|
|
- Thread scheduling
|
|
- Callback mất nhiều thời gian
|
|
|
|
```cpp
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
// Tính độ lệch thời gian
|
|
robot::Duration drift = event.current_real - event.current_expected;
|
|
|
|
if (drift.toSec() > 0.1) // Lệch hơn 100ms
|
|
{
|
|
std::cout << "Warning: Timer is " << drift.toSec() << " seconds late!" << std::endl;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 2. **Đo thời gian thực tế giữa các callback**
|
|
|
|
Không phải lúc nào timer cũng chạy đúng period. Bạn có thể đo thời gian thực tế:
|
|
|
|
```cpp
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
// Thời gian thực tế giữa 2 lần callback
|
|
double actual_period = event.last_duration.toSec();
|
|
double expected_period = 1.0; // Period bạn set
|
|
|
|
if (actual_period > expected_period * 1.1) // Lệch hơn 10%
|
|
{
|
|
std::cout << "Timer is running slow! Expected: " << expected_period
|
|
<< ", Actual: " << actual_period << std::endl;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 3. **Tính toán thời gian xử lý**
|
|
|
|
Bạn có thể biết callback mất bao lâu:
|
|
|
|
```cpp
|
|
robot::Time callback_start;
|
|
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
callback_start = robot::Time::now();
|
|
|
|
// Do some work...
|
|
doSomeWork();
|
|
|
|
robot::Duration processing_time = robot::Time::now() - callback_start;
|
|
robot::Duration time_until_next = event.current_expected + period - robot::Time::now();
|
|
|
|
if (processing_time > time_until_next)
|
|
{
|
|
std::cout << "Warning: Callback takes longer than period!" << std::endl;
|
|
}
|
|
}
|
|
```
|
|
|
|
### 4. **Điều chỉnh hành vi dựa trên timing**
|
|
|
|
Ví dụ: Nếu timer bị delay, có thể bỏ qua một số công việc:
|
|
|
|
```cpp
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
robot::Duration drift = event.current_real - event.current_expected;
|
|
|
|
if (drift.toSec() > 0.5) // Delay quá nhiều
|
|
{
|
|
// Bỏ qua công việc không quan trọng
|
|
return;
|
|
}
|
|
|
|
// Thực hiện công việc bình thường
|
|
doImportantWork();
|
|
}
|
|
```
|
|
|
|
### 5. **Logging và Debugging**
|
|
|
|
TimerEvent rất hữu ích để debug:
|
|
|
|
```cpp
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
static int count = 0;
|
|
count++;
|
|
|
|
if (count % 100 == 0) // Log mỗi 100 lần
|
|
{
|
|
robot::Duration drift = event.current_real - event.current_expected;
|
|
double avg_period = event.last_duration.toSec();
|
|
|
|
std::cout << "Timer Stats:" << std::endl;
|
|
std::cout << " Callback #" << count << std::endl;
|
|
std::cout << " Current drift: " << drift.toSec() << " seconds" << std::endl;
|
|
std::cout << " Average period: " << avg_period << " seconds" << std::endl;
|
|
std::cout << " Expected period: " << period.toSec() << " seconds" << std::endl;
|
|
}
|
|
}
|
|
```
|
|
|
|
## Ví dụ thực tế trong move_base
|
|
|
|
Trong code của bạn, `wakePlanner` có thể sử dụng TimerEvent để:
|
|
|
|
```cpp
|
|
void move_base::MoveBase::wakePlanner(const robot::TimerEvent& event)
|
|
{
|
|
// Kiểm tra xem timer có chạy đúng không
|
|
robot::Duration drift = event.current_real - event.current_expected;
|
|
|
|
if (drift.toSec() > 0.05) // Lệch hơn 50ms
|
|
{
|
|
robot::log_warning("Planner timer is running late by %.3f seconds", drift.toSec());
|
|
}
|
|
|
|
// Thời gian thực tế giữa 2 lần wake
|
|
double actual_period = event.last_duration.toSec();
|
|
double expected_period = 1.0 / planner_frequency_;
|
|
|
|
if (actual_period > expected_period * 1.2) // Lệch hơn 20%
|
|
{
|
|
robot::log_warning("Planner frequency is lower than expected. "
|
|
"Expected: %.2f Hz, Actual: %.2f Hz",
|
|
planner_frequency_, 1.0 / actual_period);
|
|
}
|
|
|
|
// Wake up planner thread
|
|
planner_cond_.notify_one();
|
|
}
|
|
```
|
|
|
|
## Khi nào nên sử dụng TimerEvent?
|
|
|
|
### Nên dùng khi:
|
|
- ✅ Cần monitor timer performance
|
|
- ✅ Cần phát hiện timer drift
|
|
- ✅ Cần điều chỉnh hành vi dựa trên timing
|
|
- ✅ Debug timing issues
|
|
- ✅ Tính toán thời gian xử lý
|
|
|
|
### Không cần dùng khi:
|
|
- ❌ Callback đơn giản, không quan tâm timing
|
|
- ❌ Chỉ cần biết timer đã fire
|
|
- ❌ Không cần thông tin về drift
|
|
|
|
## Ví dụ đơn giản
|
|
|
|
```cpp
|
|
// Callback đơn giản - không dùng TimerEvent
|
|
void simpleCallback(const robot::TimerEvent& event)
|
|
{
|
|
// Không cần dùng event, chỉ cần biết timer đã fire
|
|
doSomething();
|
|
}
|
|
|
|
// Callback phức tạp - sử dụng TimerEvent
|
|
void advancedCallback(const robot::TimerEvent& event)
|
|
{
|
|
// Sử dụng event để monitor
|
|
double drift = (event.current_real - event.current_expected).toSec();
|
|
|
|
if (std::abs(drift) > 0.01) // Lệch hơn 10ms
|
|
{
|
|
adjustBehavior(drift);
|
|
}
|
|
|
|
doSomething();
|
|
}
|
|
```
|
|
|
|
## Tóm tắt
|
|
|
|
`TimerEvent` cung cấp thông tin timing chi tiết giúp bạn:
|
|
1. **Monitor** timer performance
|
|
2. **Phát hiện** timing issues
|
|
3. **Điều chỉnh** hành vi dựa trên timing
|
|
4. **Debug** timing problems
|
|
5. **Tối ưu** performance
|
|
|
|
Trong hầu hết trường hợp đơn giản, bạn có thể bỏ qua TimerEvent. Nhưng khi cần monitor hoặc debug timing, nó rất hữu ích!
|
|
|