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
00031
00032
00033
00034
00035
00036
00037 #include "tablet_controller_panel.h"
00038 #include <Eigen/Core>
00039 #include <Eigen/Geometry>
00040 namespace jsk_rviz_plugins
00041 {
00042 TabletCmdVelArea::TabletCmdVelArea(QWidget* parent, ros::Publisher& pub_cmd_vel):
00043 QWidget(parent), mouse_x_(-1), mouse_y_(-1), pub_cmd_vel_(pub_cmd_vel)
00044 {
00045 setBackgroundRole(QPalette::Base);
00046 setAutoFillBackground(true);
00047 }
00048
00049 QSize TabletCmdVelArea::minimumSizeHint() const
00050 {
00051 return QSize(300, 300);
00052 }
00053
00054 QSize TabletCmdVelArea::sizeHint() const
00055 {
00056 return QSize(300, 300);
00057 }
00058
00059 void TabletCmdVelArea::mouseMoveEvent(QMouseEvent* event){
00060 mouse_x_ = event->x();
00061 mouse_y_ = event->y();
00062 repaint();
00063 }
00064 void TabletCmdVelArea::mousePressEvent(QMouseEvent* event){
00065 mouse_x_ = event->x();
00066 mouse_y_ = event->y();
00067 repaint();
00068 }
00069 void TabletCmdVelArea::mouseReleaseEvent(QMouseEvent* event){
00070 mouse_x_ = -1;
00071 mouse_y_ = -1;
00072 repaint();
00073 publishCmdVel(0, 0, 0);
00074 }
00075
00076 void TabletCmdVelArea::paintEvent(QPaintEvent* event)
00077 {
00078 QSize widget_size = size();
00079 int line_width = 20;
00080 int width = widget_size.width() - line_width * 2;
00081 int height = widget_size.height() - line_width * 2;
00082
00083 int radius = std::min(width, height) / 2;
00084 int center_x = width / 2 + line_width;
00085 int center_y = height / 2 + line_width;
00086 QPainter painter(this);
00087 painter.setRenderHint(QPainter::Antialiasing);
00088 QPen pen;
00089 pen.setColor(QColor(130, 177, 255));
00090 pen.setWidth(10);
00091 painter.setPen(pen);
00092 painter.drawArc(center_x - radius, center_y - radius,
00093 radius * 2, radius * 2, 0, (360 + 1) * 16);
00094
00095 QPen inner_pen;
00096 inner_pen.setColor(QColor(33, 150, 243));
00097 int inner_size = 40;
00098 inner_pen.setWidth(inner_size);
00099 painter.setPen(inner_pen);
00100 if (mouse_x_ == -1 && mouse_y_ == -1) {
00101 mouse_x_ = center_x;
00102 mouse_y_ = center_y;
00103 }
00104 else {
00105 publishVelocity(mouse_x_, mouse_y_, center_x, center_y);
00106 }
00107 painter.drawArc(mouse_x_ - inner_size / 2,
00108 mouse_y_ - inner_size / 2,
00109 inner_size, inner_size, 0, (360 + 1) * 16);
00110 }
00111
00112 void TabletCmdVelArea::publishVelocity(
00113 int mouse_x, int mouse_y, int cx, int cy)
00114 {
00115 double diff_x = mouse_x - cx;
00116 double diff_y = mouse_y - cy;
00117 Eigen::Vector3d ex(0, -1, 0);
00118 Eigen::Vector3d vel(diff_x / cx, diff_y / cy, 0);
00119
00120 int sign = 1;
00121 if (ex.cross(vel).dot(Eigen::Vector3d(0, 0, -1)) < 0) {
00122 sign = -1;
00123 }
00124 double dot = ex.dot(vel) / ex.norm() / vel.norm();
00125 if (dot < -1) {
00126 dot = -1.0;
00127 }
00128 else if (dot > 1) {
00129 dot = 1.0;
00130 }
00131 double theta = sign * acos(dot);
00132 if (!isnan(theta)) {
00133 Eigen::Vector3d vel_refined(-vel[1], -vel[0], 0);
00134
00135 publishCmdVel(vel_refined[0] * 0.2 , vel_refined[1] * 0.2, theta * 0.2);
00136 }
00137 }
00138
00139 void TabletCmdVelArea::publishCmdVel(double x, double y, double theta)
00140 {
00141 ROS_INFO("(%f, %f)", x, y);
00142 ROS_INFO("theta: %f", theta);
00143 geometry_msgs::Twist twist;
00144 twist.linear.x = x;
00145 twist.linear.y = y;
00146 twist.angular.z = theta;
00147 pub_cmd_vel_.publish(twist);
00148 }
00149
00150 QString TabletControllerPanel::defaultButtonStyleSheet()
00151 {
00152 return "QPushButton {background-color: #FF5252; color: white; font-size: 30pt;}";
00153 }
00154
00155 QString TabletControllerPanel::executeButtonStyleSheet()
00156 {
00157 return "QPushButton {background-color: white; color: #424242; font-size: 30pt;}";
00158 }
00159
00160 QString TabletControllerPanel::radioButtonStyleSheet()
00161 {
00162 return "QRadioButton {font-size: 20pt; color: #424242;}";
00163 }
00164
00165 QString TabletControllerPanel::listStyleSheet()
00166 {
00167 return "QListWidget {font-size: 20pt; color: #424242;}";
00168 }
00169
00170 TabletControllerPanel::TabletControllerPanel(QWidget* parent): rviz::Panel(parent)
00171 {
00172 ros::NodeHandle nh;
00173 pub_start_demo_ = nh.advertise<roseus::StringStamped>(
00174 "/Tablet/StartDemo", 1);
00175 pub_spot_ = nh.advertise<roseus::StringStamped>(
00176 "/Tablet/MoveToSpot", 1);
00177 sub_spots_ = nh.subscribe("/spots_marker_array",
00178 1, &TabletControllerPanel::spotCallback, this);
00179 pub_cmd_vel_ = nh.advertise<geometry_msgs::Twist>(
00180 "/navigation/unsafe_vel", 1);
00181 layout_ = new QVBoxLayout();
00182 layout_->addStretch();
00183 task_button_ = new QPushButton("Task", this);
00184 task_button_->setMinimumHeight(100);
00185 task_button_->setStyleSheet(defaultButtonStyleSheet());
00186
00187 connect(task_button_, SIGNAL(released()), this, SLOT(taskButtonClicked()));
00188 layout_->addWidget(task_button_);
00189 layout_->addSpacing(10);
00190 spot_button_ = new QPushButton("Move to spot", this);
00191 spot_button_->setMinimumHeight(100);
00192 spot_button_->setStyleSheet(defaultButtonStyleSheet());
00193 connect(spot_button_, SIGNAL(released()), this, SLOT(spotButtonClicked()));
00194 layout_->addWidget(spot_button_);
00195 layout_->addSpacing(10);
00196 cmd_vel_area_ = new TabletCmdVelArea(this, pub_cmd_vel_);
00197 layout_->addWidget(cmd_vel_area_);
00198
00199
00200 setLayout(layout_);
00201 setBackgroundRole(QPalette::Base);
00202 setAutoFillBackground(true);
00203 }
00204
00205 TabletControllerPanel::~TabletControllerPanel()
00206 {
00207
00208 }
00209
00210 void TabletControllerPanel::load(const rviz::Config& config)
00211 {
00212 rviz::Panel::load(config);
00213 }
00214
00215 void TabletControllerPanel::save(rviz::Config config) const
00216 {
00217 rviz::Panel::save(config);
00218 }
00219
00221
00223 void TabletControllerPanel::spotCallback(
00224 const visualization_msgs::MarkerArray::ConstPtr& marker)
00225 {
00226 boost::mutex::scoped_lock lock(mutex_);
00227 spots_.clear();
00228 for (size_t i = 0; i < marker->markers.size(); i++) {
00229 std::string text = marker->markers[i].text;
00230 if (!text.empty()) {
00231 spots_.push_back(text);
00232 }
00233 }
00234 }
00235
00236
00237
00238 void TabletControllerPanel::taskButtonClicked()
00239 {
00240 task_dialog_ = new QDialog();
00241 task_dialog_->setBackgroundRole(QPalette::Base);
00242 task_dialog_->setAutoFillBackground(true);
00243 task_dialog_layout_ = new QVBoxLayout();
00244 task_radio_buttons_.clear();
00245 std::vector<std::string> tasks;
00246 tasks.push_back("/Tablet/other/GetGeorgia");
00247 tasks.push_back("/Tablet/chen/GoToElevator");
00248 tasks.push_back("/Tablet/chen/Greeting1");
00249 tasks.push_back("/Tablet/chen/Greeting2");
00250 tasks.push_back("/Tablet/chen/Greeting3");
00251 tasks.push_back("/Tablet/chen/Greeting4");
00252 tasks.push_back("/Tablet/chen/Greeting5");
00253 tasks.push_back("/Tablet/chen/HandOver");
00254 for (size_t i = 0; i < tasks.size(); i++) {
00255 QRadioButton* task = new QRadioButton(QString::fromStdString(tasks[i]), this);
00256 task->setMinimumHeight(50);
00257 if (i == 0) {
00258 task->setChecked(true);
00259 }
00260 task->setStyleSheet(radioButtonStyleSheet());
00261 task_radio_buttons_.push_back(task);
00262 }
00263
00264 for (size_t i = 0; i < task_radio_buttons_.size(); i++) {
00265 task_dialog_layout_->addWidget(task_radio_buttons_[i]);
00266 }
00267 task_dialog_button_layout_ = new QHBoxLayout();
00268 task_execute_button_ = new QPushButton("Execute", this);
00269 task_execute_button_->setStyleSheet(executeButtonStyleSheet());
00270 task_execute_button_->setMinimumHeight(100);
00271 task_execute_button_->setMinimumWidth(300);
00272 task_dialog_button_layout_->addWidget(task_execute_button_);
00273 connect(task_execute_button_, SIGNAL(released()), this, SLOT(taskExecuteClicked()));
00274 task_cancel_button_ = new QPushButton("Cancel", this);
00275 task_cancel_button_->setStyleSheet(defaultButtonStyleSheet());
00276 task_cancel_button_->setMinimumHeight(100);
00277 task_cancel_button_->setMinimumWidth(300);
00278 connect(task_cancel_button_, SIGNAL(released()), this, SLOT(taskCancelClicked()));
00279 task_dialog_button_layout_->addWidget(task_cancel_button_);
00280 task_dialog_layout_->addLayout(task_dialog_button_layout_);
00281 task_dialog_->setLayout(task_dialog_layout_);
00282 task_dialog_->show();
00283
00284 }
00285
00286 void TabletControllerPanel::taskCancelClicked()
00287 {
00288 task_dialog_->reject();
00289 }
00290
00291 void TabletControllerPanel::taskExecuteClicked()
00292 {
00293 for (size_t i = 0; i < task_radio_buttons_.size(); i++) {
00294 QRadioButton* radio = task_radio_buttons_[i];
00295 if (radio->isChecked()) {
00296 std::string task = radio->text().toStdString();
00297 ROS_INFO("task: %s", task.c_str());
00298 task_dialog_->reject();
00299 roseus::StringStamped command;
00300 command.data = task;
00301 command.header.stamp = ros::Time::now();
00302 pub_start_demo_.publish(command);
00303 return;
00304 }
00305 }
00306 }
00307
00308 void TabletControllerPanel::spotButtonClicked()
00309 {
00310 boost::mutex::scoped_lock lock(mutex_);
00311 spot_dialog_ = new QDialog();
00312 spot_dialog_->setBackgroundRole(QPalette::Base);
00313 spot_dialog_->setAutoFillBackground(true);
00314 spot_dialog_layout_ = new QVBoxLayout();
00315
00316 spot_list_ = new QListWidget();
00317 spot_list_->setSortingEnabled(true);
00318 spot_list_->setStyleSheet(listStyleSheet());
00319 for (size_t i = 0; i < spots_.size(); i++) {
00320 QListWidgetItem* item = new QListWidgetItem(
00321 QString::fromStdString(spots_[i]));
00322 item->setSizeHint(QSize(item->sizeHint().width(), 30));
00323 spot_list_->addItem(item);
00324 }
00325 spot_dialog_layout_->addWidget(spot_list_);
00326 spot_dialog_button_layout_ = new QHBoxLayout();
00327 spot_go_button_ = new QPushButton("Go", this);
00328 spot_go_button_->setStyleSheet(executeButtonStyleSheet());
00329 spot_go_button_->setMinimumHeight(50);
00330 spot_go_button_->setMinimumWidth(300);
00331 connect(spot_go_button_, SIGNAL(released()),
00332 this, SLOT(spotGoClicked()));
00333 spot_dialog_button_layout_->addWidget(spot_go_button_);
00334
00335 spot_cancel_button_ = new QPushButton("Cancel", this);
00336 spot_cancel_button_->setMinimumHeight(50);
00337 spot_cancel_button_->setMinimumWidth(300);
00338 spot_cancel_button_->setStyleSheet(defaultButtonStyleSheet());
00339 connect(spot_cancel_button_, SIGNAL(released()),
00340 this, SLOT(spotCancelClicked()));
00341 spot_dialog_button_layout_->addWidget(spot_cancel_button_);
00342 spot_dialog_layout_->addLayout(spot_dialog_button_layout_);
00343 spot_dialog_->setLayout(spot_dialog_layout_);
00344 spot_dialog_->show();
00345 }
00346
00347 void TabletControllerPanel::spotCancelClicked()
00348 {
00349 spot_dialog_->reject();
00350 }
00351
00352 void TabletControllerPanel::spotGoClicked()
00353 {
00354 QListWidgetItem* item = spot_list_->currentItem();
00355 if (item) {
00356 std::string spot = item->text().toStdString();
00357 roseus::StringStamped spot_command;
00358 spot_command.data = spot;
00359 spot_command.header.stamp = ros::Time::now();
00360 pub_spot_.publish(spot_command);
00361 }
00362 spot_dialog_->reject();
00363 }
00364
00365 }
00366
00367 #include <pluginlib/class_list_macros.h>
00368 PLUGINLIB_EXPORT_CLASS (jsk_rviz_plugins::TabletControllerPanel, rviz::Panel);