218 lines
5.2 KiB
Markdown
218 lines
5.2 KiB
Markdown
# robot::Timer Usage Guide
|
|
|
|
## Overview
|
|
|
|
`robot::Timer` is a class similar to `ros::Timer` that allows you to call a callback function at a specified rate. It creates a separate thread that periodically invokes your callback function.
|
|
|
|
## Basic Usage
|
|
|
|
### Simple Timer Example
|
|
|
|
```cpp
|
|
#include <robot/timer.h>
|
|
#include <iostream>
|
|
|
|
void myCallback(const robot::TimerEvent& event)
|
|
{
|
|
std::cout << "Timer fired! Current time: "
|
|
<< event.current_real.toSec() << std::endl;
|
|
std::cout << "Time since last callback: "
|
|
<< event.last_duration.toSec() << " seconds" << std::endl;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
// Create a timer that fires every 1 second
|
|
robot::Timer timer(
|
|
robot::Duration(1.0), // Period: 1 second
|
|
myCallback, // Callback function
|
|
false, // Not one-shot (repeats)
|
|
true // Auto-start
|
|
);
|
|
|
|
// Timer is now running...
|
|
// Do other work here
|
|
|
|
// Sleep for 5 seconds to see timer fire multiple times
|
|
robot::Duration(5.0).sleep();
|
|
|
|
// Stop the timer
|
|
timer.stop();
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### Using with Class Methods
|
|
|
|
```cpp
|
|
#include <robot/timer.h>
|
|
|
|
class MyClass
|
|
{
|
|
public:
|
|
void startTimer()
|
|
{
|
|
// Create timer with member function callback
|
|
timer_ = std::make_unique<robot::Timer>(
|
|
robot::Duration(0.5), // 2 Hz
|
|
[this](const robot::TimerEvent& event) {
|
|
this->timerCallback(event);
|
|
},
|
|
false, // Repeating
|
|
true // Auto-start
|
|
);
|
|
}
|
|
|
|
void timerCallback(const robot::TimerEvent& event)
|
|
{
|
|
// Do periodic work here
|
|
std::cout << "Periodic task executed" << std::endl;
|
|
}
|
|
|
|
void stopTimer()
|
|
{
|
|
if (timer_)
|
|
{
|
|
timer_->stop();
|
|
}
|
|
}
|
|
|
|
private:
|
|
std::unique_ptr<robot::Timer> timer_;
|
|
};
|
|
```
|
|
|
|
### One-Shot Timer
|
|
|
|
```cpp
|
|
#include <robot/timer.h>
|
|
|
|
void delayedAction(const robot::TimerEvent& event)
|
|
{
|
|
std::cout << "Delayed action executed after 5 seconds" << std::endl;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
// Create a one-shot timer that fires once after 5 seconds
|
|
robot::Timer timer(
|
|
robot::Duration(5.0), // Wait 5 seconds
|
|
delayedAction, // Callback
|
|
true, // One-shot
|
|
true // Auto-start
|
|
);
|
|
|
|
// Wait for timer to fire
|
|
robot::Duration(6.0).sleep();
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
## TimerEvent Structure
|
|
|
|
The `TimerEvent` structure passed to your callback contains:
|
|
|
|
- `current_real`: The actual time when the callback was called
|
|
- `current_expected`: The expected time when the callback should have been called
|
|
- `last_real`: The actual time of the previous callback
|
|
- `last_expected`: The expected time of the previous callback
|
|
- `last_duration`: The duration between the last two callbacks
|
|
|
|
## API Reference
|
|
|
|
### Constructor
|
|
|
|
```cpp
|
|
Timer(const Duration& period,
|
|
const Callback& callback,
|
|
bool oneshot = false,
|
|
bool autostart = true);
|
|
```
|
|
|
|
- `period`: Time between callbacks
|
|
- `callback`: Function to call (signature: `void(const TimerEvent&)`)
|
|
- `oneshot`: If true, timer fires only once
|
|
- `autostart`: If true, timer starts automatically
|
|
|
|
### Methods
|
|
|
|
- `void start()`: Start the timer
|
|
- `void stop()`: Stop the timer
|
|
- `bool hasStarted()`: Check if timer is running
|
|
- `bool isOneShot()`: Check if timer is one-shot
|
|
- `void setOneShot(bool oneshot)`: Set one-shot mode
|
|
- `Duration getPeriod()`: Get the timer period
|
|
- `void setPeriod(const Duration& period)`: Set the timer period
|
|
|
|
## Example: Using in move_base
|
|
|
|
Here's how you could use `robot::Timer` in the `planThread` function:
|
|
|
|
```cpp
|
|
#include <robot/timer.h>
|
|
|
|
void move_base::MoveBase::planThread()
|
|
{
|
|
boost::unique_lock<boost::recursive_mutex> lock(planner_mutex_);
|
|
|
|
while (true)
|
|
{
|
|
// Wait until we should run the planner
|
|
while (!runPlanner_)
|
|
{
|
|
planner_cond_.wait(lock);
|
|
}
|
|
|
|
lock.unlock();
|
|
|
|
// Do planning work
|
|
robot_geometry_msgs::PoseStamped temp_goal = planner_goal_;
|
|
planner_plan_->clear();
|
|
bool gotPlan = makePlan(temp_goal, *planner_plan_);
|
|
|
|
// ... handle plan result ...
|
|
|
|
// If planner_frequency > 0, use timer to wake up later
|
|
if (planner_frequency_ > 0)
|
|
{
|
|
robot::Duration sleep_time = robot::Duration(1.0 / planner_frequency_);
|
|
|
|
// Create one-shot timer to wake up planner
|
|
robot::Timer wake_timer(
|
|
sleep_time,
|
|
[this](const robot::TimerEvent&) {
|
|
boost::unique_lock<boost::recursive_mutex> lock(planner_mutex_);
|
|
planner_cond_.notify_one();
|
|
},
|
|
true, // One-shot
|
|
true // Auto-start
|
|
);
|
|
|
|
// Wait for timer or condition variable
|
|
lock.lock();
|
|
planner_cond_.wait(lock);
|
|
}
|
|
else
|
|
{
|
|
lock.lock();
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Thread Safety
|
|
|
|
- `Timer` is thread-safe and can be started/stopped from any thread
|
|
- The callback function is executed in a separate thread
|
|
- Be careful when accessing shared data from the callback - use proper synchronization
|
|
|
|
## Notes
|
|
|
|
- The timer uses `robot::Time` which respects simulation time if enabled
|
|
- Timer accuracy depends on system scheduling and may drift slightly
|
|
- For very high frequency timers (>100 Hz), consider using `robot::Rate` in a loop instead
|
|
- The timer thread will automatically clean up when the `Timer` object is destroyed
|
|
|