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 <QHBoxLayout>
00038 #include <QMessageBox>
00039 #include <QProgressDialog>
00040 #include <QString>
00041 #include <QFont>
00042 #include <QApplication>
00043 #include "default_collisions_widget.h"
00044 #include <boost/unordered_map.hpp>
00045 #include <boost/assign.hpp>
00046 #include <ros/console.h>
00047
00048 namespace moveit_setup_assistant
00049 {
00051 const boost::unordered_map<moveit_setup_assistant::DisabledReason, const char*> longReasonsToString =
00052 boost::assign::map_list_of(moveit_setup_assistant::NEVER, "Never in Collision")(moveit_setup_assistant::DEFAULT,
00053 "Collision by Default")(
00054 moveit_setup_assistant::ADJACENT, "Adjacent Links")(moveit_setup_assistant::ALWAYS, "Always in Collision")(
00055 moveit_setup_assistant::USER, "User Disabled")(moveit_setup_assistant::NOT_DISABLED, "");
00056
00060 class CheckboxSortWidgetItem : public QTableWidgetItem
00061 {
00062 public:
00066 bool operator<(const QTableWidgetItem& other) const
00067 {
00068 return checkState() < other.checkState();
00069 }
00070 };
00071
00072
00073
00074
00075 DefaultCollisionsWidget::DefaultCollisionsWidget(QWidget* parent, MoveItConfigDataPtr config_data)
00076 : SetupScreenWidget(parent), config_data_(config_data)
00077 {
00078
00079 layout_ = new QVBoxLayout(this);
00080
00081
00082 HeaderWidget* header = new HeaderWidget(
00083 "Optimize Self-Collision Checking",
00084 "The Default Self-Collision Matrix Generator will search for pairs of links on the robot that can safely be "
00085 "disabled from collision checking, decreasing motion planning processing time. These pairs of links are disabled "
00086 "when they are always in collision, never in collision, in collision in the robot's default position or when the "
00087 "links are adjacent to each other on the kinematic chain. Sampling density specifies how many random robot "
00088 "positions to check for self collision. Higher densities require more computation time.",
00089 this);
00090 layout_->addWidget(header);
00091
00092
00093 controls_box_ = new QGroupBox(this);
00094 layout_->addWidget(controls_box_);
00095 QHBoxLayout* controls_box_layout = new QHBoxLayout(controls_box_);
00096 controls_box_layout->setAlignment(Qt::AlignTop | Qt::AlignLeft);
00097
00098
00099 QLabel* density_left_label = new QLabel(this);
00100 density_left_label->setText("Sampling Density: Low");
00101 controls_box_layout->addWidget(density_left_label);
00102
00103
00104 density_slider_ = new QSlider(this);
00105 density_slider_->setTickPosition(QSlider::TicksBelow);
00106 density_slider_->setMinimum(0);
00107 density_slider_->setMaximum(99);
00108 density_slider_->setSingleStep(10);
00109 density_slider_->setPageStep(50);
00110 density_slider_->setSliderPosition(9);
00111 density_slider_->setTickInterval(10);
00112 density_slider_->setOrientation(Qt::Horizontal);
00113 controls_box_layout->addWidget(density_slider_);
00114 connect(density_slider_, SIGNAL(valueChanged(int)), this, SLOT(changeDensityLabel(int)));
00115
00116
00117 QLabel* density_right_label = new QLabel(this);
00118 density_right_label->setText("High ");
00119 controls_box_layout->addWidget(density_right_label);
00120
00121
00122 density_value_label_ = new QLabel(this);
00123 density_value_label_->setMinimumWidth(50);
00124 controls_box_layout->addWidget(density_value_label_);
00125 changeDensityLabel(density_slider_->value());
00126
00127
00128 btn_generate_ = new QPushButton(this);
00129 btn_generate_->setText("&Generate Collision Matrix");
00130 btn_generate_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
00131 connect(btn_generate_, SIGNAL(clicked()), this, SLOT(generateCollisionTable()));
00132 layout_->addWidget(btn_generate_);
00133 layout_->setAlignment(btn_generate_, Qt::AlignRight);
00134
00135
00136
00137
00138 progress_label_ = new QLabel(this);
00139 progress_label_->setText("Generating Default Collision Matrix");
00140 progress_label_->hide();
00141 layout_->addWidget(progress_label_);
00142
00143
00144 progress_bar_ = new QProgressBar(this);
00145 progress_bar_->setMaximum(100);
00146 progress_bar_->setMinimum(0);
00147 progress_bar_->hide();
00148 layout_->addWidget(progress_bar_);
00149
00150
00151
00152
00153 collision_table_ = new QTableWidget(this);
00154 collision_table_->setColumnCount(4);
00155 collision_table_->setSortingEnabled(true);
00156 collision_table_->setSelectionMode(QAbstractItemView::SingleSelection);
00157 collision_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
00158 connect(collision_table_, SIGNAL(currentCellChanged(int, int, int, int)), this, SLOT(previewSelected(int)));
00159 connect(collision_table_, SIGNAL(cellChanged(int, int)), this, SLOT(toggleCheckBox(int, int)));
00160 layout_->addWidget(collision_table_);
00161
00162 QStringList header_list;
00163 header_list.append("Link A");
00164 header_list.append("Link B");
00165 header_list.append("Disabled");
00166 header_list.append("Reason To Disable");
00167 collision_table_->setHorizontalHeaderLabels(header_list);
00168
00169
00170 collision_table_->resizeColumnToContents(0);
00171 collision_table_->resizeColumnToContents(1);
00172 collision_table_->resizeColumnToContents(2);
00173 collision_table_->resizeColumnToContents(3);
00174
00175
00176 controls_box_bottom_ = new QGroupBox(this);
00177 layout_->addWidget(controls_box_bottom_);
00178 QHBoxLayout* controls_box_bottom_layout = new QHBoxLayout(controls_box_bottom_);
00179
00180
00181 collision_checkbox_ = new QCheckBox(this);
00182 collision_checkbox_->setText("Show Non-Disabled Link Pairs");
00183 connect(collision_checkbox_, SIGNAL(toggled(bool)), this, SLOT(collisionCheckboxToggle()));
00184 controls_box_bottom_layout->addWidget(collision_checkbox_);
00185
00186 fraction_label_ = new QLabel(this);
00187 fraction_label_->setText("Min. collisions for \"always\"-colliding pairs:");
00188
00189 controls_box_bottom_layout->addWidget(fraction_label_);
00190
00191 fraction_spinbox_ = new QSpinBox(this);
00192 fraction_spinbox_->setRange(1, 100);
00193 fraction_spinbox_->setValue(95);
00194 fraction_spinbox_->setSuffix("%");
00195 controls_box_bottom_layout->addWidget(fraction_spinbox_);
00196
00197 controls_box_bottom_layout->setAlignment(collision_checkbox_, Qt::AlignLeft);
00198
00199 setLayout(layout_);
00200
00201 setWindowTitle("Default Collision Matrix");
00202 }
00203
00204
00205
00206
00207 void DefaultCollisionsWidget::generateCollisionTable()
00208 {
00209
00210 if (!config_data_->srdf_->disabled_collisions_.empty())
00211 {
00212 if (QMessageBox::question(this, "Confirm Disabled Collision Overwrite", "Are you sure you want to overwrite the "
00213 "current default collisions matrix with a "
00214 "newly generated one?",
00215 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
00216 {
00217 return;
00218 }
00219 }
00220 QApplication::processEvents();
00221 progress_label_->setText("Computing default collision matrix for robot model...");
00222
00223
00224 disableControls(true);
00225
00226
00227
00228
00229
00230 unsigned int collision_progress = 0;
00231 progress_bar_->setValue(collision_progress);
00232
00233 QApplication::processEvents();
00234
00235
00236 boost::thread workerThread(
00237 boost::bind(&DefaultCollisionsWidget::generateCollisionTableThread, this, &collision_progress));
00238
00239 boost::posix_time::seconds check_interval(1);
00240
00241
00242 while (collision_progress < 100)
00243 {
00244
00245 progress_bar_->setValue(collision_progress);
00246
00247
00248 QApplication::processEvents();
00249
00250
00251 boost::this_thread::sleep(check_interval);
00252
00253 }
00254
00255
00256 workerThread.join();
00257
00258
00259 loadCollisionTable();
00260
00261
00262 disableControls(false);
00263
00264 config_data_->changes |= MoveItConfigData::COLLISIONS;
00265 }
00266
00267
00268
00269
00270 void DefaultCollisionsWidget::generateCollisionTableThread(unsigned int* collision_progress)
00271 {
00272 unsigned int num_trials = density_slider_->value() * 1000 + 1000;
00273 double min_frac = (double)fraction_spinbox_->value() / 100.0;
00274
00275 const bool verbose = true;
00276 const bool include_never_colliding = true;
00277
00278
00279 config_data_->getPlanningScene()->getAllowedCollisionMatrixNonConst().clear();
00280
00281
00282 link_pairs_ = moveit_setup_assistant::computeDefaultCollisions(
00283 config_data_->getPlanningScene(), collision_progress, include_never_colliding, num_trials, min_frac, verbose);
00284
00285
00286 linkPairsToSRDF();
00287
00288
00289 *collision_progress = 100;
00290
00291 ROS_INFO_STREAM("Thread complete " << link_pairs_.size());
00292 }
00293
00294
00295
00296
00297 void DefaultCollisionsWidget::loadCollisionTable()
00298 {
00299 int row = 0;
00300 int progress_counter = 0;
00301
00302
00303 progress_bar_->setValue(0);
00304
00305 QApplication::processEvents();
00306 progress_label_->setText("Loading table...");
00307
00308
00309 collision_table_->setUpdatesEnabled(false);
00310 collision_table_->setDisabled(true);
00311 collision_table_->clearContents();
00312
00313
00314 if (link_pairs_.empty())
00315 {
00316 collision_table_->setRowCount(1);
00317 QTableWidgetItem* no_collide = new QTableWidgetItem("No Link Pairs Of This Kind");
00318 collision_table_->setItem(0, 0, no_collide);
00319 }
00320 else
00321 {
00322
00323 btn_generate_->setText("Regenerate Default Collision Matrix");
00324 }
00325
00326
00327 collision_table_->setRowCount(link_pairs_.size());
00328
00329 for (moveit_setup_assistant::LinkPairMap::const_iterator pair_it = link_pairs_.begin(); pair_it != link_pairs_.end();
00330 ++pair_it)
00331 {
00332
00333 if (pair_it->second.disable_check || collision_checkbox_->isChecked())
00334 {
00335
00336 QTableWidgetItem* linkA = new QTableWidgetItem(pair_it->first.first.c_str());
00337 linkA->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00338
00339 QTableWidgetItem* linkB = new QTableWidgetItem(pair_it->first.second.c_str());
00340 linkB->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00341
00342 CheckboxSortWidgetItem* disable_check = new CheckboxSortWidgetItem();
00343 disable_check->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable);
00344 if (pair_it->second.disable_check)
00345 disable_check->setCheckState(Qt::Checked);
00346 else
00347 disable_check->setCheckState(Qt::Unchecked);
00348
00349 QTableWidgetItem* reason = new QTableWidgetItem(longReasonsToString.at(pair_it->second.reason));
00350 reason->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00351
00352
00353 collision_table_->setItem(row, 0, linkA);
00354 collision_table_->setItem(row, 1, linkB);
00355 collision_table_->setItem(row, 2, disable_check);
00356 collision_table_->setItem(row, 3, reason);
00357
00358
00359 ++row;
00360 }
00361
00362 ++progress_counter;
00363
00364 if (progress_counter % 200 == 0)
00365 {
00366
00367 progress_bar_->setValue(progress_counter * 100 / link_pairs_.size());
00368 QApplication::processEvents();
00369 }
00370 }
00371
00372
00373 collision_table_->setRowCount(row);
00374
00375
00376 collision_table_->setVisible(false);
00377 collision_table_->resizeColumnToContents(0);
00378 collision_table_->resizeColumnToContents(1);
00379 collision_table_->resizeColumnToContents(2);
00380 collision_table_->resizeColumnToContents(3);
00381 collision_table_->setVisible(true);
00382
00383 collision_table_->setUpdatesEnabled(true);
00384 }
00385
00386
00387
00388
00389 void DefaultCollisionsWidget::changeDensityLabel(int value)
00390 {
00391 density_value_label_->setText(QString::number(value * 1000 + 1000));
00392 }
00393
00394
00395
00396
00397 void DefaultCollisionsWidget::disableControls(bool disable)
00398 {
00399 controls_box_->setDisabled(disable);
00400 collision_table_->setDisabled(disable);
00401 collision_checkbox_->setDisabled(disable);
00402
00403 if (disable)
00404 {
00405 progress_bar_->show();
00406 progress_label_->show();
00407 }
00408 else
00409 {
00410 progress_label_->hide();
00411 progress_bar_->hide();
00412 }
00413
00414 QApplication::processEvents();
00415 }
00416
00417
00418
00419
00420 void DefaultCollisionsWidget::collisionCheckboxToggle()
00421 {
00422
00423 disableControls(true);
00424
00425
00426 loadCollisionTable();
00427
00428
00429 disableControls(false);
00430 }
00431
00432
00433
00434
00435 void DefaultCollisionsWidget::toggleCheckBox(int row, int column)
00436 {
00437
00438
00439 if (!collision_table_->isEnabled() || column != 2)
00440 return;
00441
00442
00443 std::pair<std::string, std::string> link_pair;
00444 link_pair.first = collision_table_->item(row, 0)->text().toStdString();
00445 link_pair.second = collision_table_->item(row, 1)->text().toStdString();
00446
00447
00448 bool check_state = collision_table_->item(row, 2)->checkState();
00449
00450
00451 if (link_pairs_[link_pair].disable_check != check_state)
00452 {
00453
00454 link_pairs_[link_pair].disable_check = check_state;
00455
00456
00457 if (link_pairs_[link_pair].disable_check == true &&
00458 link_pairs_[link_pair].reason == moveit_setup_assistant::NOT_DISABLED)
00459 {
00460 link_pairs_[link_pair].reason = moveit_setup_assistant::USER;
00461
00462
00463 collision_table_->item(row, 3)->setText(longReasonsToString.at(link_pairs_[link_pair].reason));
00464 }
00465
00466 else if (link_pairs_[link_pair].disable_check == false &&
00467 link_pairs_[link_pair].reason == moveit_setup_assistant::USER)
00468 {
00469 link_pairs_[link_pair].reason = moveit_setup_assistant::NOT_DISABLED;
00470
00471
00472 collision_table_->item(row, 3)->setText("");
00473 }
00474
00475 config_data_->changes |= MoveItConfigData::COLLISIONS;
00476 }
00477
00478
00479 linkPairsToSRDF();
00480
00481 previewSelected(row);
00482 }
00483
00484
00485
00486
00487 void DefaultCollisionsWidget::linkPairsToSRDF()
00488 {
00489
00490 config_data_->srdf_->disabled_collisions_.clear();
00491
00492
00493 srdf::Model::DisabledCollision dc;
00494
00495
00496 for (moveit_setup_assistant::LinkPairMap::const_iterator pair_it = link_pairs_.begin(); pair_it != link_pairs_.end();
00497 ++pair_it)
00498 {
00499
00500 if (pair_it->second.disable_check)
00501 {
00502 dc.link1_ = pair_it->first.first;
00503 dc.link2_ = pair_it->first.second;
00504 dc.reason_ = moveit_setup_assistant::disabledReasonToString(pair_it->second.reason);
00505 config_data_->srdf_->disabled_collisions_.push_back(dc);
00506 }
00507 }
00508
00509
00510 config_data_->loadAllowedCollisionMatrix();
00511 }
00512
00513
00514
00515
00516 void DefaultCollisionsWidget::linkPairsFromSRDF()
00517 {
00518
00519 link_pairs_.clear();
00520
00521
00522 planning_scene::PlanningScenePtr scene = config_data_->getPlanningScene()->diff();
00523
00524
00525 moveit_setup_assistant::computeLinkPairs(*scene, link_pairs_);
00526
00527
00528 moveit_setup_assistant::LinkPairData link_pair_data;
00529 std::pair<std::string, std::string> link_pair;
00530
00531
00532 for (std::vector<srdf::Model::DisabledCollision>::const_iterator collision_it =
00533 config_data_->srdf_->disabled_collisions_.begin();
00534 collision_it != config_data_->srdf_->disabled_collisions_.end(); ++collision_it)
00535 {
00536
00537 link_pair.first = collision_it->link1_;
00538 link_pair.second = collision_it->link2_;
00539
00540
00541 link_pair_data.reason = moveit_setup_assistant::disabledReasonFromString(collision_it->reason_);
00542 link_pair_data.disable_check = true;
00543
00544
00545 link_pairs_[link_pair] = link_pair_data;
00546 }
00547 }
00548
00549
00550
00551
00552 void DefaultCollisionsWidget::previewSelected(int row)
00553 {
00554
00555 Q_EMIT unhighlightAll();
00556
00557
00558 QTableWidgetItem* first_link_item = collision_table_->item(row, 0);
00559 if (!first_link_item)
00560 return;
00561
00562 const QString& first_link = first_link_item->text();
00563 const QString& second_link = collision_table_->item(row, 1)->text();
00564 Qt::CheckState check_state = collision_table_->item(row, 2)->checkState();
00565
00566 QColor color = (check_state == Qt::Checked) ? QColor(0, 255, 0) : QColor(255, 0, 0);
00567 Q_EMIT highlightLink(first_link.toStdString(), color);
00568 Q_EMIT highlightLink(second_link.toStdString(), color);
00569 }
00570
00571
00572
00573
00574 void DefaultCollisionsWidget::focusGiven()
00575 {
00576
00577 linkPairsFromSRDF();
00578
00579
00580 loadCollisionTable();
00581
00582
00583 disableControls(false);
00584 }
00585
00586 }