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