5.9 KiB
5.9 KiB
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
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
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ế:
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:
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:
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:
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 để:
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
// 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:
- Monitor timer performance
- Phát hiện timing issues
- Điều chỉnh hành vi dựa trên timing
- Debug timing problems
- 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!