2 #include <boost/algorithm/clamp.hpp> 4 #include <std_msgs/Time.h> 6 #include <teleoperation/keyboard_controllerConfig.h> 8 double map(
double value,
double in_lower,
double in_upper,
double out_lower,
double out_upper)
10 return out_lower + (out_upper - out_lower) * (value - in_lower) / (in_upper - in_lower);
19 ROS_ASSERT_MSG(m_key_codes.size() == KEY_COUNT,
"KEY_CODES needs to have KEY_COUNT many elements.");
20 ROS_ASSERT_MSG(this->m_key_pressed_state.size() == KEY_COUNT,
21 "m_key_pressed_state needs to have KEY_COUNT many elements.");
23 this->m_drive_parameters_publisher =
25 this->m_enable_manual_publisher = this->m_node_handle.advertise<std_msgs::Time>(
TOPIC_HEARTBEAT_MANUAL, 1);
27 this->m_drive_mode_subscriber =
28 this->m_node_handle.subscribe<std_msgs::Int32>(
TOPIC_DRIVE_MODE, 1, &KeyboardController::driveModeCallback,
35 this->m_timer = this->m_node_handle.createTimer(tick_duration, &KeyboardController::timerCallback,
this);
37 this->updateDynamicConfig();
38 m_dyn_cfg_server.setCallback([&](teleoperation::keyboard_controllerConfig& cfg, uint32_t) {
39 m_steering_speed = cfg.steering_speed;
40 m_acceleration = cfg.acceleration;
41 m_braking = cfg.braking;
43 m_fast_steer_limit = cfg.fast_steer_limit;
44 m_steering_gravity = cfg.steering_gravity;
45 m_throttle_gravity = cfg.throttle_gravity;
47 m_max_throttle = cfg.max_throttle;
53 SDL_DestroyWindow(this->m_window);
54 SDL_FreeSurface(this->m_image_locked);
55 SDL_FreeSurface(this->m_image_manual);
56 SDL_FreeSurface(this->m_image_autonomous);
60 void KeyboardController::createWindow()
62 std::string icon_filename = ros::package::getPath(
"teleoperation") + std::string(
"/img/wasd.bmp");
64 if (SDL_Init(SDL_INIT_VIDEO) < 0)
66 throw std::runtime_error(
"Could not initialize SDL: " + std::string(SDL_GetError()));
68 this->m_window = SDL_CreateWindow(
"Keyboard teleoperation", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 580,
69 128, SDL_WINDOW_RESIZABLE);
71 auto window_surface = SDL_GetWindowSurface(this->m_window);
72 SDL_DisplayMode display_mode;
73 SDL_GetCurrentDisplayMode(0, &display_mode);
75 SDL_SetWindowPosition(this->m_window,
80 SDL_Surface* icon = SDL_LoadBMP(icon_filename.c_str());
83 SDL_SetWindowIcon(this->m_window, icon);
84 SDL_FreeSurface(icon);
88 void KeyboardController::pollWindowEvents()
91 while (SDL_PollEvent(&event))
93 if (event.type == SDL_KEYUP || event.type == SDL_KEYDOWN)
95 for (
size_t i = 0; i < KEY_COUNT; i++)
97 if ((
int)event.key.keysym.sym == (
int)m_key_codes[i])
99 this->m_key_pressed_state[i] =
event.type == SDL_KEYDOWN;
103 else if (event.type == SDL_QUIT)
107 else if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_EXPOSED)
109 this->updateWindow();
114 void KeyboardController::updateWindow()
116 SDL_Surface* surface = SDL_GetWindowSurface(this->m_window);
117 SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 0, 0, 0));
118 switch (this->m_drive_mode)
121 SDL_BlitSurface(this->m_image_locked, NULL, surface, NULL);
124 SDL_BlitSurface(this->m_image_manual, NULL, surface, NULL);
127 SDL_BlitSurface(this->m_image_autonomous, NULL, surface, NULL);
130 SDL_UpdateWindowSurface(this->m_window);
133 void KeyboardController::loadImages()
135 std::string locked_filename = ros::package::getPath(
"teleoperation") + std::string(
"/img/locked.bmp");
136 this->m_image_locked = SDL_LoadBMP(locked_filename.c_str());
137 std::string manual_filename = ros::package::getPath(
"teleoperation") + std::string(
"/img/manual.bmp");
138 this->m_image_manual = SDL_LoadBMP(manual_filename.c_str());
139 std::string autonomous_filename = ros::package::getPath(
"teleoperation") + std::string(
"/img/autonomous.bmp");
140 this->m_image_autonomous = SDL_LoadBMP(autonomous_filename.c_str());
147 void KeyboardController::timerCallback(
const ros::TimerEvent& event)
149 double delta_time = (
event.current_real -
event.last_real).toSec();
151 this->pollWindowEvents();
152 this->updateDriveParameters(delta_time);
153 this->publishDriveParameters();
154 this->updateDeadMansSwitch();
160 message.data = ros::Time::now();
167 void KeyboardController::updateDeadMansSwitch()
184 void KeyboardController::updateDriveParameters(
double delta_time)
188 #pragma GCC diagnostic push 189 #pragma GCC diagnostic ignored "-Wfloat-equal" 197 double steer_limit =
map(std::abs(this->m_velocity), 0, m_max_throttle, 1, m_fast_steer_limit);
198 double angle_update = steer * delta_time * m_steering_speed;
199 this->m_angle = boost::algorithm::clamp(this->m_angle + angle_update, -steer_limit, +steer_limit);
200 double velocity_update = throttle * delta_time * (this->m_velocity * throttle > 0 ? m_acceleration : m_braking);
201 this->m_velocity = boost::algorithm::clamp(this->m_velocity + velocity_update, -m_max_throttle, +m_max_throttle);
203 if (steer == 0 && this->m_angle != 0)
205 double sign = std::copysign(1.0, this->m_angle);
206 this->m_angle -= m_steering_gravity * delta_time * sign;
207 if (std::abs(this->m_angle) < m_steering_gravity * delta_time)
213 if (throttle == 0 && this->m_velocity != 0)
215 double sign = std::copysign(1.0, this->m_velocity);
216 this->m_velocity -= m_throttle_gravity * delta_time * sign;
217 if (std::abs(this->m_velocity) < m_throttle_gravity * delta_time)
219 this->m_velocity = 0;
222 #pragma GCC diagnostic pop 225 void KeyboardController::publishDriveParameters()
227 drive_msgs::drive_param drive_parameters;
228 drive_parameters.velocity = this->m_velocity;
229 drive_parameters.angle = this->m_angle;
230 this->m_drive_parameters_publisher.publish(drive_parameters);
233 void KeyboardController::driveModeCallback(
const std_msgs::Int32::ConstPtr& drive_mode_message)
235 auto mode = (
DriveMode)drive_mode_message->data;
237 "Unknown drive mode.");
238 if (this->m_drive_mode != mode)
240 this->m_drive_mode = mode;
241 this->updateWindow();
245 void KeyboardController::updateDynamicConfig()
247 teleoperation::keyboard_controllerConfig cfg;
249 cfg.steering_speed = m_steering_speed;
250 cfg.acceleration = m_acceleration;
251 cfg.braking = m_braking;
253 cfg.fast_steer_limit = m_fast_steer_limit;
254 cfg.steering_gravity = m_steering_gravity;
255 cfg.throttle_gravity = m_throttle_gravity;
257 cfg.max_throttle = m_max_throttle;
259 m_dyn_cfg_server.updateConfig(cfg);
262 int main(
int argc,
char** argv)
264 ros::init(argc, argv,
"keyboard_controller");
constexpr const char * TOPIC_DRIVE_MODE
constexpr const char * TOPIC_HEARTBEAT_MANUAL
std_msgs::Time createHearbeatMessage()
constexpr const char * TOPIC_HEARTBEAT_AUTONOMOUS
constexpr double PARAMETER_UPDATE_FREQUENCY
constexpr int SCREEN_EDGE_MARGIN
string TOPIC_DRIVE_PARAMETERS
int main(int argc, char **argv)
double map(double value, double in_lower, double in_upper, double out_lower, double out_upper)