00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include <mapviz_plugins/plan_route_plugin.h>
00031
00032
00033 #include <cstdio>
00034 #include <vector>
00035
00036
00037 #include <QDateTime>
00038 #include <QDialog>
00039 #include <QGLWidget>
00040 #include <QMouseEvent>
00041 #include <QPainter>
00042 #include <QPalette>
00043 #include <QStaticText>
00044
00045 #include <opencv2/core/core.hpp>
00046
00047
00048 #include <ros/master.h>
00049
00050 #include <swri_route_util/util.h>
00051 #include <swri_transform_util/frames.h>
00052
00053 #include <marti_nav_msgs/PlanRoute.h>
00054
00055
00056 #include <pluginlib/class_list_macros.h>
00057 PLUGINLIB_DECLARE_CLASS(mapviz_plugins, plan_route, mapviz_plugins::PlanRoutePlugin,
00058 mapviz::MapvizPlugin);
00059
00060 namespace mnm = marti_nav_msgs;
00061 namespace sru = swri_route_util;
00062 namespace stu = swri_transform_util;
00063
00064 namespace mapviz_plugins
00065 {
00066 PlanRoutePlugin::PlanRoutePlugin() :
00067 config_widget_(new QWidget()),
00068 map_canvas_(NULL),
00069 failed_service_(false),
00070 selected_point_(-1),
00071 is_mouse_down_(false),
00072 max_ms_(Q_INT64_C(500)),
00073 max_distance_(2.0)
00074 {
00075 ui_.setupUi(config_widget_);
00076
00077 ui_.color->setColor(Qt::green);
00078
00079 QPalette p(config_widget_->palette());
00080 p.setColor(QPalette::Background, Qt::white);
00081 config_widget_->setPalette(p);
00082
00083 QPalette p3(ui_.status->palette());
00084 p3.setColor(QPalette::Text, Qt::red);
00085 ui_.status->setPalette(p3);
00086 QObject::connect(ui_.service, SIGNAL(editingFinished()), this,
00087 SLOT(PlanRoute()));
00088 QObject::connect(ui_.publish, SIGNAL(clicked()), this,
00089 SLOT(PublishRoute()));
00090 QObject::connect(ui_.clear, SIGNAL(clicked()), this,
00091 SLOT(Clear()));
00092 }
00093
00094 PlanRoutePlugin::~PlanRoutePlugin()
00095 {
00096 if (map_canvas_)
00097 {
00098 map_canvas_->removeEventFilter(this);
00099 }
00100 }
00101
00102 void PlanRoutePlugin::PublishRoute()
00103 {
00104 if (route_preview_)
00105 {
00106 if (route_topic_ != ui_.topic->text().toStdString())
00107 {
00108 route_topic_ = ui_.topic->text().toStdString();
00109 route_pub_.shutdown();
00110 route_pub_ = node_.advertise<sru::Route>(route_topic_, 1, true);
00111 }
00112
00113 route_pub_.publish(route_preview_);
00114 }
00115 }
00116
00117 void PlanRoutePlugin::PlanRoute()
00118 {
00119 route_preview_ = sru::RoutePtr();
00120 bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
00121 if (waypoints_.size() + start_from_vehicle < 2)
00122 {
00123 return;
00124 }
00125
00126 std::string service = ui_.service->text().toStdString();
00127 ros::ServiceClient client = node_.serviceClient<mnm::PlanRoute>(service);
00128
00129 mnm::PlanRoute plan_route;
00130 plan_route.request.header.frame_id = stu::_wgs84_frame;
00131 plan_route.request.header.stamp = ros::Time::now();
00132 plan_route.request.plan_from_vehicle = static_cast<unsigned char>(start_from_vehicle);
00133 plan_route.request.waypoints = waypoints_;
00134
00135 if (client.call(plan_route))
00136 {
00137 if (plan_route.response.success)
00138 {
00139 route_preview_ = boost::make_shared<sru::Route>(plan_route.response.route);
00140 failed_service_ = false;
00141 }
00142 else
00143 {
00144 PrintError(plan_route.response.message);
00145 failed_service_ = true;
00146 }
00147 }
00148 else
00149 {
00150 PrintError("Failed to plan route.");
00151 failed_service_ = true;
00152 }
00153 }
00154
00155 void PlanRoutePlugin::Retry(const ros::TimerEvent& e)
00156 {
00157 PlanRoute();
00158 }
00159
00160 void PlanRoutePlugin::Clear()
00161 {
00162 waypoints_.clear();
00163 route_preview_ = sru::RoutePtr();
00164 }
00165
00166 void PlanRoutePlugin::PrintError(const std::string& message)
00167 {
00168 if (message == ui_.status->text().toStdString())
00169 {
00170 return;
00171 }
00172
00173 ROS_ERROR_THROTTLE(1.0, "Error: %s", message.c_str());
00174 QPalette p(ui_.status->palette());
00175 p.setColor(QPalette::Text, Qt::red);
00176 ui_.status->setPalette(p);
00177 ui_.status->setText(message.c_str());
00178 }
00179
00180 void PlanRoutePlugin::PrintInfo(const std::string& message)
00181 {
00182 if (message == ui_.status->text().toStdString())
00183 {
00184 return;
00185 }
00186
00187 ROS_INFO_THROTTLE(1.0, "%s", message.c_str());
00188 QPalette p(ui_.status->palette());
00189 p.setColor(QPalette::Text, Qt::green);
00190 ui_.status->setPalette(p);
00191 ui_.status->setText(message.c_str());
00192 }
00193
00194 void PlanRoutePlugin::PrintWarning(const std::string& message)
00195 {
00196 if (message == ui_.status->text().toStdString())
00197 {
00198 return;
00199 }
00200
00201 ROS_WARN_THROTTLE(1.0, "%s", message.c_str());
00202 QPalette p(ui_.status->palette());
00203 p.setColor(QPalette::Text, Qt::darkYellow);
00204 ui_.status->setPalette(p);
00205 ui_.status->setText(message.c_str());
00206 }
00207
00208 QWidget* PlanRoutePlugin::GetConfigWidget(QWidget* parent)
00209 {
00210 config_widget_->setParent(parent);
00211
00212 return config_widget_;
00213 }
00214
00215 bool PlanRoutePlugin::Initialize(QGLWidget* canvas)
00216 {
00217 map_canvas_ = static_cast<mapviz::MapCanvas*>(canvas);
00218 map_canvas_->installEventFilter(this);
00219
00220 retry_timer_ = node_.createTimer(ros::Duration(1), &PlanRoutePlugin::Retry, this);
00221
00222 initialized_ = true;
00223 return true;
00224 }
00225
00226 bool PlanRoutePlugin::eventFilter(QObject *object, QEvent* event)
00227 {
00228 switch (event->type())
00229 {
00230 case QEvent::MouseButtonPress:
00231 return handleMousePress(static_cast<QMouseEvent*>(event));
00232 case QEvent::MouseButtonRelease:
00233 return handleMouseRelease(static_cast<QMouseEvent*>(event));
00234 case QEvent::MouseMove:
00235 return handleMouseMove(static_cast<QMouseEvent*>(event));
00236 default:
00237 return false;
00238 }
00239 }
00240
00241 bool PlanRoutePlugin::handleMousePress(QMouseEvent* event)
00242 {
00243 selected_point_ = -1;
00244 int closest_point = 0;
00245 double closest_distance = std::numeric_limits<double>::max();
00246
00247 QPointF point = event->posF();
00248 stu::Transform transform;
00249 if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00250 {
00251 for (size_t i = 0; i < waypoints_.size(); i++)
00252 {
00253 tf::Vector3 waypoint(
00254 waypoints_[i].position.x,
00255 waypoints_[i].position.y,
00256 0.0);
00257 waypoint = transform * waypoint;
00258
00259 QPointF transformed = map_canvas_->FixedFrameToMapGlCoord(QPointF(waypoint.x(), waypoint.y()));
00260
00261 double distance = QLineF(transformed, point).length();
00262
00263 if (distance < closest_distance)
00264 {
00265 closest_distance = distance;
00266 closest_point = static_cast<int>(i);
00267 }
00268 }
00269 }
00270
00271 if (event->button() == Qt::LeftButton)
00272 {
00273 if (closest_distance < 15)
00274 {
00275 selected_point_ = closest_point;
00276 return true;
00277 }
00278 else
00279 {
00280 is_mouse_down_ = true;
00281 mouse_down_pos_ = event->posF();
00282 mouse_down_time_ = QDateTime::currentMSecsSinceEpoch();
00283 return false;
00284 }
00285 }
00286 else if (event->button() == Qt::RightButton)
00287 {
00288 if (closest_distance < 15)
00289 {
00290 waypoints_.erase(waypoints_.begin() + closest_point);
00291 PlanRoute();
00292 return true;
00293 }
00294 }
00295
00296 return false;
00297 }
00298
00299 bool PlanRoutePlugin::handleMouseRelease(QMouseEvent* event)
00300 {
00301 if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
00302 {
00303 QPointF point = event->posF();
00304 stu::Transform transform;
00305 if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00306 {
00307 QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00308 tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00309 position = transform * position;
00310 waypoints_[selected_point_].position.x = position.x();
00311 waypoints_[selected_point_].position.y = position.y();
00312 PlanRoute();
00313 }
00314
00315 selected_point_ = -1;
00316 return true;
00317 }
00318 else if (is_mouse_down_)
00319 {
00320 qreal distance = QLineF(mouse_down_pos_, event->posF()).length();
00321 qint64 msecsDiff = QDateTime::currentMSecsSinceEpoch() - mouse_down_time_;
00322
00323
00324
00325
00326
00327 if (msecsDiff < max_ms_ && distance <= max_distance_)
00328 {
00329 QPointF point = event->posF();
00330
00331
00332 QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00333
00334 stu::Transform transform;
00335 tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00336 if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00337 {
00338 position = transform * position;
00339
00340 geometry_msgs::Pose pose;
00341 pose.position.x = position.x();
00342 pose.position.y = position.y();
00343 waypoints_.push_back(pose);
00344 PlanRoute();
00345 }
00346 }
00347 }
00348 is_mouse_down_ = false;
00349
00350 return false;
00351 }
00352
00353 bool PlanRoutePlugin::handleMouseMove(QMouseEvent* event)
00354 {
00355 if (selected_point_ >= 0 && static_cast<size_t>(selected_point_) < waypoints_.size())
00356 {
00357 QPointF point = event->posF();
00358 stu::Transform transform;
00359 if (tf_manager_.GetTransform(stu::_wgs84_frame, target_frame_, transform))
00360 {
00361 QPointF transformed = map_canvas_->MapGlCoordToFixedFrame(point);
00362 tf::Vector3 position(transformed.x(), transformed.y(), 0.0);
00363 position = transform * position;
00364 waypoints_[selected_point_].position.y = position.y();
00365 waypoints_[selected_point_].position.x = position.x();
00366 PlanRoute();
00367 }
00368
00369 return true;
00370 }
00371 return false;
00372 }
00373
00374 void PlanRoutePlugin::Draw(double x, double y, double scale)
00375 {
00376 stu::Transform transform;
00377 if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00378 {
00379 if (!failed_service_)
00380 {
00381 if (route_preview_)
00382 {
00383 sru::Route route = *route_preview_;
00384 sru::transform(route, transform, target_frame_);
00385
00386 glLineWidth(2);
00387 const QColor color = ui_.color->color();
00388 glColor4d(color.redF(), color.greenF(), color.blueF(), 1.0);
00389 glBegin(GL_LINE_STRIP);
00390
00391 for (size_t i = 0; i < route.points.size(); i++)
00392 {
00393 glVertex2d(route.points[i].position().x(), route.points[i].position().y());
00394 }
00395
00396 glEnd();
00397 }
00398
00399 PrintInfo("OK");
00400 }
00401
00402
00403
00404 glPointSize(20);
00405 glColor4f(0.0, 1.0, 1.0, 1.0);
00406 glBegin(GL_POINTS);
00407
00408 for (size_t i = 0; i < waypoints_.size(); i++)
00409 {
00410 tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
00411 point = transform * point;
00412 glVertex2d(point.x(), point.y());
00413 }
00414 glEnd();
00415 }
00416 else
00417 {
00418 PrintError("Failed to transform.");
00419 }
00420 }
00421
00422 void PlanRoutePlugin::Paint(QPainter* painter, double x, double y, double scale)
00423 {
00424 painter->save();
00425 painter->resetTransform();
00426
00427 QPen pen(QBrush(QColor(Qt::darkCyan).darker()), 1);
00428 painter->setPen(pen);
00429 painter->setFont(QFont("DejaVu Sans Mono", 7));
00430
00431 stu::Transform transform;
00432 if (tf_manager_.GetTransform(target_frame_, stu::_wgs84_frame, transform))
00433 {
00434 for (size_t i = 0; i < waypoints_.size(); i++)
00435 {
00436 tf::Vector3 point(waypoints_[i].position.x, waypoints_[i].position.y, 0);
00437 point = transform * point;
00438 QPointF gl_point = map_canvas_->FixedFrameToMapGlCoord(QPointF(point.x(), point.y()));
00439 QPointF corner(gl_point.x() - 20, gl_point.y() - 20);
00440 QRectF rect(corner, QSizeF(40, 40));
00441 painter->drawText(rect, Qt::AlignHCenter | Qt::AlignVCenter, QString::fromStdString(boost::lexical_cast<std::string>(i + 1)));
00442 }
00443 }
00444
00445 painter->restore();
00446 }
00447
00448 void PlanRoutePlugin::LoadConfig(const YAML::Node& node, const std::string& path)
00449 {
00450 if (node["route_topic"])
00451 {
00452 std::string route_topic;
00453 node["route_topic"] >> route_topic;
00454 ui_.topic->setText(route_topic.c_str());
00455 }
00456 if (node["color"])
00457 {
00458 std::string color;
00459 node["color"] >> color;
00460 ui_.color->setColor(QColor(color.c_str()));
00461 }
00462 if (node["service"])
00463 {
00464 std::string service;
00465 node["service"] >> service;
00466 ui_.service->setText(service.c_str());
00467 }
00468 if (node["start_from_vehicle"])
00469 {
00470 bool start_from_vehicle;
00471 node["start_from_vehicle"] >> start_from_vehicle;
00472 ui_.start_from_vehicle->setChecked(start_from_vehicle);
00473 }
00474
00475 PlanRoute();
00476 }
00477
00478 void PlanRoutePlugin::SaveConfig(YAML::Emitter& emitter, const std::string& path)
00479 {
00480 std::string route_topic = ui_.topic->text().toStdString();
00481 emitter << YAML::Key << "route_topic" << YAML::Value << route_topic;
00482
00483 std::string color = ui_.color->color().name().toStdString();
00484 emitter << YAML::Key << "color" << YAML::Value << color;
00485
00486 std::string service = ui_.service->text().toStdString();
00487 emitter << YAML::Key << "service" << YAML::Value << service;
00488
00489 bool start_from_vehicle = ui_.start_from_vehicle->isChecked();
00490 emitter << YAML::Key << "start_from_vehicle" << YAML::Value << start_from_vehicle;
00491 }
00492 }