robot_poses_widget.cpp
Go to the documentation of this file.
00001 /*********************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2012, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of the Willow Garage nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *********************************************************************/
00034 
00035 /* Author: Dave Coleman */
00036 
00037 // SA
00038 #include "robot_poses_widget.h"
00039 #include <moveit_msgs/JointLimits.h>
00040 // Qt
00041 #include <QFormLayout>
00042 #include <QMessageBox>
00043 #include <QDoubleValidator>
00044 #include <QApplication>
00045 
00046 #include <moveit/robot_state/conversions.h>
00047 #include <moveit_msgs/DisplayRobotState.h>
00048 
00049 namespace moveit_setup_assistant
00050 {
00051 
00052 // ******************************************************************************************
00053 // Outer User Interface for MoveIt Configuration Assistant
00054 // ******************************************************************************************
00055 RobotPosesWidget::RobotPosesWidget( QWidget *parent, moveit_setup_assistant::MoveItConfigDataPtr config_data )
00056   : SetupScreenWidget( parent ), config_data_(config_data)
00057 {
00058   // Set pointer to null so later we can tell if we need to delete it
00059   joint_list_layout_ = NULL;
00060 
00061   // Basic widget container
00062   QVBoxLayout *layout = new QVBoxLayout( );
00063 
00064   // Top Header Area ------------------------------------------------
00065 
00066   HeaderWidget *header = new HeaderWidget( "Robot Poses",
00067                                            "Create poses for the robot. Poses are defined as sets of joint values for particular planning groups. This is useful for things like <i>folded arms</i>.",
00068                                            this);
00069   layout->addWidget( header );
00070 
00071   // Create contents screens ---------------------------------------
00072   pose_list_widget_ = createContentsWidget();
00073   pose_edit_widget_ = createEditWidget();
00074 
00075   // Create stacked layout -----------------------------------------
00076   stacked_layout_ = new QStackedLayout( this );
00077   stacked_layout_->addWidget( pose_list_widget_ ); // screen index 0
00078   stacked_layout_->addWidget( pose_edit_widget_ ); // screen index 1
00079 
00080   // Create Widget wrapper for layout
00081   QWidget *stacked_layout_widget = new QWidget( this );
00082   stacked_layout_widget->setLayout( stacked_layout_ );
00083 
00084   layout->addWidget( stacked_layout_widget );
00085 
00086 
00087   // Finish Layout --------------------------------------------------
00088   this->setLayout(layout);
00089 
00090 
00091   // Create joint publisher -----------------------------------------
00092   ros::NodeHandle nh;
00093 
00094   // Create scene publisher for later use
00095   pub_robot_state_ = nh.advertise<moveit_msgs::DisplayRobotState>( MOVEIT_ROBOT_STATE, 1 );
00096 
00097   // Set the planning scene
00098   config_data_->getPlanningScene()->setName("MoveIt Planning Scene");
00099 
00100 
00101   // Collision Detection initializtion -------------------------------
00102 
00103   // Setup the request
00104   request.contacts = true;
00105   request.max_contacts = 1;
00106   request.max_contacts_per_pair = 1;
00107   request.verbose = false;
00108 
00109 }
00110 
00111 // ******************************************************************************************
00112 // Create the main content widget
00113 // ******************************************************************************************
00114 QWidget* RobotPosesWidget::createContentsWidget()
00115 {
00116   // Main widget
00117   QWidget *content_widget = new QWidget( this );
00118 
00119   // Basic widget container
00120   QVBoxLayout *layout = new QVBoxLayout( this );
00121 
00122   // Table ------------ ------------------------------------------------
00123 
00124   data_table_ = new QTableWidget( this );
00125   data_table_->setColumnCount(2);
00126   data_table_->setSortingEnabled(true);
00127   data_table_->setSelectionBehavior( QAbstractItemView::SelectRows );
00128   connect( data_table_, SIGNAL( cellDoubleClicked( int, int ) ), this, SLOT( editDoubleClicked( int, int ) ) );
00129   connect( data_table_, SIGNAL( cellClicked( int, int ) ), this, SLOT( previewClicked( int, int ) ) );
00130   layout->addWidget( data_table_ );
00131 
00132   // Set header labels
00133   QStringList header_list;
00134   header_list.append("Pose Name");
00135   header_list.append("Group Name");
00136   data_table_->setHorizontalHeaderLabels(header_list);
00137 
00138   // Bottom Buttons --------------------------------------------------
00139 
00140   QHBoxLayout *controls_layout = new QHBoxLayout();
00141 
00142   // Set Default Button
00143   QPushButton *btn_default = new QPushButton( "&Show Default Pose", this );
00144   btn_default->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00145   btn_default->setMaximumWidth(300);
00146   connect(btn_default, SIGNAL(clicked()), this, SLOT(showDefaultPose()));
00147   controls_layout->addWidget(btn_default);
00148   controls_layout->setAlignment( btn_default, Qt::AlignLeft );
00149 
00150   // Set play button
00151   QPushButton *btn_play = new QPushButton( "&MoveIt!", this );
00152   btn_play->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00153   btn_play->setMaximumWidth(300);
00154   connect(btn_play, SIGNAL(clicked()), this, SLOT(playPoses()));
00155   controls_layout->addWidget(btn_play);
00156   controls_layout->setAlignment( btn_play, Qt::AlignLeft );
00157 
00158   // Spacer
00159   QWidget *spacer = new QWidget( this );
00160   spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
00161   controls_layout->addWidget( spacer );
00162 
00163   // Edit Selected Button
00164   btn_edit_ = new QPushButton( "&Edit Selected", this );
00165   btn_edit_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00166   btn_edit_->setMaximumWidth(300);
00167   btn_edit_->hide(); // show once we know if there are existing poses
00168   connect(btn_edit_, SIGNAL(clicked()), this, SLOT(editSelected()));
00169   controls_layout->addWidget(btn_edit_);
00170   controls_layout->setAlignment( btn_edit_, Qt::AlignRight );
00171 
00172   // Delete
00173   btn_delete_ = new QPushButton( "&Delete Selected", this );
00174   connect( btn_delete_, SIGNAL(clicked()), this, SLOT( deleteSelected() ) );
00175   controls_layout->addWidget( btn_delete_ );
00176   controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
00177 
00178   // Add Group Button
00179   QPushButton *btn_add = new QPushButton( "&Add Pose", this );
00180   btn_add->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred );
00181   btn_add->setMaximumWidth(300);
00182   connect(btn_add, SIGNAL(clicked()), this, SLOT(showNewScreen()));
00183   controls_layout->addWidget(btn_add);
00184   controls_layout->setAlignment( btn_add, Qt::AlignRight );
00185 
00186   // Add layout
00187   layout->addLayout( controls_layout );
00188 
00189 
00190   // Set layout -----------------------------------------------------
00191   content_widget->setLayout(layout);
00192 
00193   return content_widget;
00194 }
00195 
00196 // ******************************************************************************************
00197 // Create the edit widget
00198 // ******************************************************************************************
00199 QWidget* RobotPosesWidget::createEditWidget()
00200 {
00201   // Main widget
00202   QWidget *edit_widget = new QWidget( this );
00203   // Layout
00204   QVBoxLayout *layout = new QVBoxLayout();
00205 
00206   // 2 columns -------------------------------------------------------
00207 
00208   QHBoxLayout *columns_layout = new QHBoxLayout();
00209   QVBoxLayout *column1 = new QVBoxLayout();
00210   column2_ = new QVBoxLayout();
00211 
00212   // Column 1 --------------------------------------------------------
00213 
00214   // Simple form -------------------------------------------
00215   QFormLayout *form_layout = new QFormLayout();
00216   //form_layout->setContentsMargins( 0, 15, 0, 15 );
00217   form_layout->setRowWrapPolicy( QFormLayout::WrapAllRows );
00218 
00219   // Name input
00220   pose_name_field_ = new QLineEdit( this );
00221   //pose_name_field_->setMaximumWidth( 300 );
00222   form_layout->addRow( "Pose Name:", pose_name_field_ );
00223 
00224   // Group name input
00225   group_name_field_ = new QComboBox( this );
00226   group_name_field_->setEditable( false );
00227   // Connect the signal for changes to the drop down box
00228   connect( group_name_field_, SIGNAL( currentIndexChanged( const QString & ) ),
00229            this, SLOT( loadJointSliders( const QString & ) ) );
00230   //group_name_field_->setMaximumWidth( 300 );
00231   form_layout->addRow( "Planning Group:", group_name_field_ );
00232 
00233   // Indicator that robot is in collision or not
00234   collision_warning_ = new QLabel( "<font color='red'><b>Robot in Collision State</b></font>", this );
00235   collision_warning_->setTextFormat( Qt::RichText );
00236   collision_warning_->hide(); // show later
00237   form_layout->addRow( " ", collision_warning_ );
00238 
00239   column1->addLayout( form_layout );
00240   columns_layout->addLayout( column1 );
00241 
00242   // Column 2 --------------------------------------------------------
00243 
00244   // Box to hold joint sliders
00245   joint_list_widget_ = new QWidget( this );
00246 
00247   // Create scroll area
00248   scroll_area_ = new QScrollArea( this );
00249   //scroll_area_->setBackgroundRole(QPalette::Dark);
00250   scroll_area_->setWidget( joint_list_widget_ );
00251 
00252   column2_->addWidget( scroll_area_ );
00253 
00254   columns_layout->addLayout( column2_ );
00255 
00256   // Set columns in main layout
00257   layout->addLayout( columns_layout );
00258 
00259   // Bottom Buttons --------------------------------------------------
00260 
00261   QHBoxLayout *controls_layout = new QHBoxLayout();
00262   controls_layout->setContentsMargins( 0, 25, 0, 15 );
00263 
00264   // Spacer
00265   QWidget *spacer = new QWidget( this );
00266   spacer->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
00267   controls_layout->addWidget( spacer );
00268 
00269   // Save
00270   QPushButton *btn_save_ = new QPushButton( "&Save", this );
00271   btn_save_->setMaximumWidth( 200 );
00272   connect( btn_save_, SIGNAL(clicked()), this, SLOT( doneEditing() ) );
00273   controls_layout->addWidget( btn_save_ );
00274   controls_layout->setAlignment(btn_save_, Qt::AlignRight);
00275 
00276   // Cancel
00277   QPushButton *btn_cancel_ = new QPushButton( "&Cancel", this );
00278   btn_cancel_->setMaximumWidth( 200 );
00279   connect( btn_cancel_, SIGNAL(clicked()), this, SLOT( cancelEditing() ) );
00280   controls_layout->addWidget( btn_cancel_ );
00281   controls_layout->setAlignment(btn_cancel_, Qt::AlignRight);
00282 
00283   // Add layout
00284   layout->addLayout( controls_layout );
00285 
00286 
00287   // Set layout -----------------------------------------------------
00288   edit_widget->setLayout(layout);
00289 
00290   return edit_widget;
00291 }
00292 
00293 // ******************************************************************************************
00294 // Show edit screen for creating a new pose
00295 // ******************************************************************************************
00296 void RobotPosesWidget::showNewScreen()
00297 {
00298   // Switch to screen - do this before clearEditText()
00299   stacked_layout_->setCurrentIndex( 1 );
00300 
00301   // Remember that this is a new pose
00302   current_edit_pose_.clear();
00303 
00304   // Manually send the load joint sliders signal
00305   if( !group_name_field_->currentText().isEmpty() )
00306     loadJointSliders( group_name_field_->currentText() );
00307 
00308   // Clear previous data
00309   pose_name_field_->setText("");
00310 
00311   // Announce that this widget is in modal mode
00312   Q_EMIT isModal( true );
00313 }
00314 
00315 // ******************************************************************************************
00316 // Edit whatever element is selected
00317 // ******************************************************************************************
00318 void RobotPosesWidget::editDoubleClicked( int row, int column )
00319 {
00320   // We'll just base the edit on the selection highlight
00321   editSelected();
00322 }
00323 
00324 // ******************************************************************************************
00325 // Preview whatever element is selected
00326 // ******************************************************************************************
00327 void RobotPosesWidget::previewClicked( int row, int column )
00328 {
00329   // Get list of all selected items
00330   QList<QTableWidgetItem*> selected = data_table_->selectedItems();
00331 
00332   // Check that an element was selected
00333   if( !selected.size() )
00334     return;
00335 
00336   // Find the selected in datastructure
00337   srdf::Model::GroupState *pose = findPoseByName( selected[0]->text().toStdString() );
00338 
00339   showPose( pose );
00340 }
00341 
00342 // ******************************************************************************************
00343 // Show the robot in the current pose
00344 // ******************************************************************************************
00345 void RobotPosesWidget::showPose( srdf::Model::GroupState *pose )
00346 {
00347   // Set pose joint values by adding them to the local joint state map
00348   for( std::map<std::string, std::vector<double> >::const_iterator value_it = pose->joint_values_.begin();
00349        value_it != pose->joint_values_.end(); ++value_it )
00350   {
00351     // Only copy the first joint value // TODO: add capability for multi-DOF joints?
00352     joint_state_map_[ value_it->first ] = value_it->second[0];
00353   }
00354 
00355   // Update the joints
00356   publishJoints();
00357 
00358 
00359   // Unhighlight all links
00360   Q_EMIT unhighlightAll();
00361 
00362   // Highlight group
00363   Q_EMIT highlightGroup( pose->group_ );
00364 }
00365 
00366 // ******************************************************************************************
00367 // Show the robot in its default joint positions
00368 // ******************************************************************************************
00369 void RobotPosesWidget::showDefaultPose()
00370 {
00371   // Get list of all joints for the robot
00372   std::vector<const robot_model::JointModel*> joint_models = config_data_->getRobotModel()->getJointModels();
00373 
00374   // Iterate through the joints
00375   for( std::vector<const robot_model::JointModel*>::const_iterator joint_it = joint_models.begin();
00376        joint_it < joint_models.end(); ++joint_it )
00377   {
00378 
00379     // Check that this joint only represents 1 variable.
00380     if( (*joint_it)->getVariableCount() == 1 )
00381     {
00382       double init_value;
00383 
00384       // get the first joint value in its vector
00385       std::vector<double> default_values;
00386       (*joint_it)->getVariableDefaultValues( default_values );
00387       init_value = default_values[0];
00388 
00389       // Change joint's value in joint_state_map to the default
00390       joint_state_map_[ (*joint_it)->getName() ] = init_value;
00391     }
00392   }
00393 
00394   // Update the joints
00395   publishJoints();
00396 
00397   // Unhighlight all links
00398   Q_EMIT unhighlightAll();
00399 }
00400 
00401 // ******************************************************************************************
00402 // Play through the poses
00403 // ******************************************************************************************
00404 void RobotPosesWidget::playPoses()
00405 {
00406   // Loop through each pose and play them
00407   for( std::vector<srdf::Model::GroupState>::iterator pose_it = config_data_->srdf_->group_states_.begin();
00408        pose_it != config_data_->srdf_->group_states_.end(); ++pose_it )
00409   {
00410     ROS_INFO_STREAM("Showing pose " << pose_it->name_ );
00411     showPose( &(*pose_it) );
00412     ros::Duration(0.05).sleep();
00413     QApplication::processEvents();
00414     ros::Duration(0.45).sleep();
00415   }
00416 }
00417 
00418 // ******************************************************************************************
00419 // Edit whatever element is selected
00420 // ******************************************************************************************
00421 void RobotPosesWidget::editSelected()
00422 {
00423   // Get list of all selected items
00424   QList<QTableWidgetItem*> selected = data_table_->selectedItems();
00425 
00426   // Check that an element was selected
00427   if( !selected.size() )
00428     return;
00429 
00430   // Get selected name and edit it
00431   edit( selected[0]->text().toStdString() );
00432 }
00433 
00434 // ******************************************************************************************
00435 // Edit pose
00436 // ******************************************************************************************
00437 void RobotPosesWidget::edit( const std::string &name )
00438 {
00439   // Remember what we are editing
00440   current_edit_pose_ = name;
00441 
00442   // Find the selected in datastruture
00443   srdf::Model::GroupState *pose = findPoseByName( name );
00444 
00445   // Set pose name
00446   pose_name_field_->setText( pose->name_.c_str() );
00447 
00448   // Set pose joint values by adding them to the local joint state map
00449   for( std::map<std::string, std::vector<double> >::const_iterator value_it = pose->joint_values_.begin();
00450        value_it != pose->joint_values_.end(); ++value_it )
00451   {
00452     // Only copy the first joint value // TODO: add capability for multi-DOF joints?
00453     joint_state_map_[ value_it->first ] = value_it->second[0];
00454   }
00455 
00456   // Update robot model in rviz
00457   publishJoints();
00458 
00459   // Set group:
00460   int index = group_name_field_->findText( pose->group_.c_str() );
00461   if( index == -1 )
00462   {
00463     QMessageBox::critical( this, "Error Loading", "Unable to find group name in drop down box" );
00464     return;
00465   }
00466 
00467   // Load joint sliders
00468   group_name_field_->setCurrentIndex( index );
00469 
00470   // Switch to screen - do this before setCurrentIndex
00471   stacked_layout_->setCurrentIndex( 1 );
00472 
00473   // Announce that this widget is in modal mode
00474   Q_EMIT isModal( true );
00475 
00476   // Manually send the load joint sliders signal
00477   loadJointSliders( QString( pose->group_.c_str() ) );
00478 
00479 }
00480 
00481 // ******************************************************************************************
00482 // Populate the combo dropdown box with avail group names
00483 // ******************************************************************************************
00484 void RobotPosesWidget::loadGroupsComboBox()
00485 {
00486   // Remove all old groups
00487   group_name_field_->clear();
00488 
00489   // Add all group names to combo box
00490   for( std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
00491        group_it != config_data_->srdf_->groups_.end(); ++group_it )
00492   {
00493     group_name_field_->addItem( group_it->name_.c_str() );
00494   }
00495 
00496 }
00497 
00498 // ******************************************************************************************
00499 // Load the joint sliders based on group selected from combo box
00500 // ******************************************************************************************
00501 void RobotPosesWidget::loadJointSliders( const QString &selected )
00502 {
00503   // Ignore this event if the combo box is empty. This occurs when clearing the combo box and reloading with the
00504   // newest groups. Also ignore if we are not on the edit screen
00505   if( !group_name_field_->count() || selected.isEmpty() || stacked_layout_->currentIndex() == 0)
00506     return;
00507 
00508   // Get group name from input
00509   const std::string group_name = selected.toStdString();
00510 
00511   // Check that joint model exist
00512   if( !config_data_->getRobotModel()->hasJointModelGroup( group_name ) )
00513   {
00514     QMessageBox::critical( this, "Error Loading",
00515                            QString("Unable to find joint model group for group: ").append( group_name.c_str()).append(" Are you sure this group has associated joints/links?" ));
00516     return;
00517   }
00518 
00519   // Delete old sliders from joint_list_layout_ if this has been loaded before
00520   if( joint_list_layout_ )
00521   {
00522     delete joint_list_layout_;
00523     qDeleteAll( joint_list_widget_->children() );
00524   }
00525 
00526   // Create layout again
00527   joint_list_layout_ = new QVBoxLayout();
00528   joint_list_widget_->setLayout( joint_list_layout_ );
00529   //  joint_list_widget_->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
00530   joint_list_widget_->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
00531   joint_list_widget_->setMinimumSize( 50, 50 ); // w, h
00532 
00533   // Get list of associated joints
00534   const robot_model::JointModelGroup *joint_model_group =
00535     config_data_->getRobotModel()->getJointModelGroup( group_name );
00536   joint_models_ = joint_model_group->getJointModels();
00537 
00538   // Iterate through the joints
00539   int num_joints = 0;
00540   for( std::vector<const robot_model::JointModel*>::const_iterator joint_it = joint_models_.begin();
00541        joint_it < joint_models_.end(); ++joint_it )
00542   {
00543 
00544     // Check that this joint only represents 1 variable.
00545     if( (*joint_it)->getVariableCount() == 1 )
00546     {
00547       double init_value;
00548 
00549       // Decide what this joint's initial value is
00550       if( joint_state_map_.find( (*joint_it)->getName() ) == joint_state_map_.end() )
00551       {
00552         // the joint state map does not yet have an entry for this joint
00553 
00554         // get the first joint value in its vector
00555         std::vector<double> default_values;
00556         (*joint_it)->getVariableDefaultValues( default_values );
00557         init_value = default_values[0];
00558 
00559       }
00560       else // there is already a value in the map
00561       {
00562         init_value = joint_state_map_[ (*joint_it)->getName() ];
00563       }
00564 
00565       // For each joint in group add slider
00566       SliderWidget *sw = new SliderWidget( this, *joint_it, init_value );
00567       joint_list_layout_->addWidget( sw );
00568 
00569       // Connect value change event
00570       connect( sw, SIGNAL( jointValueChanged( const std::string &, double ) ),
00571                this, SLOT( updateRobotModel( const std::string &, double ) ) );
00572 
00573       ++num_joints;
00574     }
00575   }
00576 
00577   // Copy the width of column 2 and manually calculate height from number of joints
00578   joint_list_widget_->resize( 300, num_joints * 70 ); //w, h
00579 
00580   // Update the robot model in Rviz with newly selected joint values
00581   publishJoints();
00582 
00583   // Highlight the planning group
00584   Q_EMIT unhighlightAll();
00585   Q_EMIT highlightGroup( group_name );
00586 }
00587 
00588 // ******************************************************************************************
00589 // Find the associated data by name
00590 // ******************************************************************************************
00591 srdf::Model::GroupState *RobotPosesWidget::findPoseByName( const std::string &name )
00592 {
00593   // Find the group state we are editing based on the pose name
00594   srdf::Model::GroupState *searched_group = NULL; // used for holding our search results
00595 
00596   for( std::vector<srdf::Model::GroupState>::iterator pose_it = config_data_->srdf_->group_states_.begin();
00597        pose_it != config_data_->srdf_->group_states_.end(); ++pose_it )
00598   {
00599     if( pose_it->name_ == name ) // string match
00600     {
00601       searched_group = &(*pose_it);  // convert to pointer from iterator
00602       break; // we are done searching
00603     }
00604   }
00605 
00606   // Check if pose was found
00607   if( searched_group == NULL ) // not found
00608   {
00609     QMessageBox::critical( this, "Error Saving", "An internal error has occured while saving. Quitting.");
00610     QApplication::quit();
00611   }
00612 
00613   return searched_group;
00614 }
00615 
00616 // ******************************************************************************************
00617 // Delete currently editing item
00618 // ******************************************************************************************
00619 void RobotPosesWidget::deleteSelected()
00620 {
00621   // Get list of all selected items
00622   QList<QTableWidgetItem*> selected = data_table_->selectedItems();
00623 
00624   // Check that an element was selected
00625   if( !selected.size() )
00626     return;
00627 
00628   // Get selected name and edit it
00629   current_edit_pose_ = selected[0]->text().toStdString();
00630 
00631   // Confirm user wants to delete group
00632   if( QMessageBox::question( this, "Confirm Pose Deletion",
00633                              QString("Are you sure you want to delete the pose '")
00634                              .append( current_edit_pose_.c_str() )
00635                              .append( "'?" ),
00636                              QMessageBox::Ok | QMessageBox::Cancel)
00637       == QMessageBox::Cancel )
00638   {
00639     return;
00640   }
00641 
00642   // Delete pose from vector
00643   for( std::vector<srdf::Model::GroupState>::iterator pose_it = config_data_->srdf_->group_states_.begin();
00644        pose_it != config_data_->srdf_->group_states_.end(); ++pose_it )
00645   {
00646     // check if this is the group we want to delete
00647     if( pose_it->name_ == current_edit_pose_ ) // string match
00648     {
00649       config_data_->srdf_->group_states_.erase( pose_it );
00650       break;
00651     }
00652   }
00653 
00654   // Reload main screen table
00655   loadDataTable();
00656 
00657 }
00658 
00659 // ******************************************************************************************
00660 // Save editing changes
00661 // ******************************************************************************************
00662 void RobotPosesWidget::doneEditing()
00663 {
00664   // Get a reference to the supplied strings
00665   const std::string pose_name = pose_name_field_->text().toStdString();
00666 
00667   // Used for editing existing groups
00668   srdf::Model::GroupState *searched_data = NULL;
00669 
00670   // Check that name field is not empty
00671   if( pose_name.empty() )
00672   {
00673     QMessageBox::warning( this, "Error Saving", "A name must be given for the pose!" );
00674     return;
00675   }
00676 
00677   // Check if this is an existing group
00678   if( !current_edit_pose_.empty() )
00679   {
00680     // Find the group we are editing based on the goup name string
00681     searched_data = findPoseByName( current_edit_pose_ );
00682   }
00683 
00684   // Check that the pose name is unique
00685   for( std::vector<srdf::Model::GroupState>::const_iterator data_it = config_data_->srdf_->group_states_.begin();
00686        data_it != config_data_->srdf_->group_states_.end();  ++data_it )
00687   {
00688     if( data_it->name_.compare( pose_name ) == 0 ) // the names are the same
00689     {
00690       // is this our existing pose? check if pose pointers are same
00691       if( &(*data_it) != searched_data )
00692       {
00693         QMessageBox::warning( this, "Error Saving", "A pose already exists with that name!" );
00694         return;
00695       }
00696     }
00697   }
00698 
00699   // Check that a group was selected
00700   if( group_name_field_->currentText().isEmpty() )
00701   {
00702     QMessageBox::warning( this, "Error Saving", "A planning group must be chosen!" );
00703     return;
00704   }
00705 
00706   // Save the new pose name or create the new pose ----------------------------
00707   bool isNew = false;
00708 
00709   if( searched_data == NULL ) // create new
00710   {
00711     isNew = true;
00712 
00713     searched_data = new srdf::Model::GroupState();
00714   }
00715 
00716   // Copy name data ----------------------------------------------------
00717   searched_data->name_ = pose_name;
00718   searched_data->group_ = group_name_field_->currentText().toStdString();
00719 
00720   // Copy joint positions ----------------------------------------
00721 
00722   // Clear the old values
00723   searched_data->joint_values_.clear();
00724 
00725   // Iterate through the current group's joints and add to SRDF
00726   for( std::vector<const robot_model::JointModel*>::const_iterator joint_it = joint_models_.begin();
00727        joint_it < joint_models_.end(); ++joint_it )
00728   {
00729     // Check that this joint only represents 1 variable.
00730     if( (*joint_it)->getVariableCount() == 1 )
00731     {
00732       // Create vector for new joint values
00733       std::vector<double> joint_value;
00734       joint_value.push_back( joint_state_map_[ (*joint_it)->getName() ] );
00735 
00736       // Add joint vector to SRDF
00737       searched_data->joint_values_[ (*joint_it)->getName() ] = joint_value;
00738     }
00739   }
00740 
00741   // Insert new poses into group state vector --------------------------
00742   if( isNew )
00743   {
00744     config_data_->srdf_->group_states_.push_back( *searched_data );
00745   }
00746 
00747   // Finish up ------------------------------------------------------
00748 
00749   // Reload main screen table
00750   loadDataTable();
00751 
00752   // Switch to screen
00753   stacked_layout_->setCurrentIndex( 0 );
00754 
00755   // Announce that this widget is done with modal mode
00756   Q_EMIT isModal( false );
00757 }
00758 
00759 // ******************************************************************************************
00760 // Cancel changes
00761 // ******************************************************************************************
00762 void RobotPosesWidget::cancelEditing()
00763 {
00764   // Switch to screen
00765   stacked_layout_->setCurrentIndex( 0 );
00766 
00767   // Announce that this widget is done with modal mode
00768   Q_EMIT isModal( false );
00769 }
00770 
00771 // ******************************************************************************************
00772 // Load the robot poses into the table
00773 // ******************************************************************************************
00774 void RobotPosesWidget::loadDataTable()
00775 {
00776   // Disable Table
00777   data_table_->setUpdatesEnabled(false); // prevent table from updating until we are completely done
00778   data_table_->setDisabled(true); // make sure we disable it so that the cellChanged event is not called
00779   data_table_->clearContents();
00780 
00781   // Set size of datatable
00782   data_table_->setRowCount( config_data_->srdf_->group_states_.size() );
00783 
00784   // Loop through every pose
00785   int row = 0;
00786   for( std::vector<srdf::Model::GroupState>::const_iterator data_it = config_data_->srdf_->group_states_.begin();
00787        data_it != config_data_->srdf_->group_states_.end(); ++data_it )
00788   {
00789     // Create row elements
00790     QTableWidgetItem* data_name = new QTableWidgetItem( data_it->name_.c_str() );
00791     data_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00792     QTableWidgetItem* group_name = new QTableWidgetItem( data_it->group_.c_str() );
00793     group_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
00794 
00795     // Add to table
00796     data_table_->setItem( row, 0, data_name );
00797     data_table_->setItem( row, 1, group_name );
00798 
00799     // Increment counter
00800     ++row;
00801   }
00802 
00803   // Reenable
00804   data_table_->setUpdatesEnabled(true); // prevent table from updating until we are completely done
00805   data_table_->setDisabled(false); // make sure we disable it so that the cellChanged event is not called
00806 
00807   // Resize header
00808   data_table_->resizeColumnToContents(0);
00809   data_table_->resizeColumnToContents(1);
00810 
00811   // Show edit button if applicable
00812   if( config_data_->srdf_->group_states_.size() )
00813     btn_edit_->show();
00814 }
00815 
00816 // ******************************************************************************************
00817 // Called when setup assistant navigation switches to this screen
00818 // ******************************************************************************************
00819 void RobotPosesWidget::focusGiven()
00820 {
00821   // Show the current poses screen
00822   stacked_layout_->setCurrentIndex( 0 );
00823 
00824   // Load the data to the tree
00825   loadDataTable();
00826 
00827   // Load the avail groups to the combo box
00828   loadGroupsComboBox();
00829 
00830 }
00831 
00832 // ******************************************************************************************
00833 // Call when one of the sliders has its value changed
00834 // ******************************************************************************************
00835 void RobotPosesWidget::updateRobotModel( const std::string &name, double value )
00836 {
00837   // Save the new value
00838   joint_state_map_[ name ] = value;
00839 
00840   // Update the robot model/rviz
00841   publishJoints();
00842 }
00843 
00844 // ******************************************************************************************
00845 // Publish the joint values in the joint_state_map_ to Rviz
00846 // ******************************************************************************************
00847 void RobotPosesWidget::publishJoints()
00848 {
00849   // Change the scene
00850   //scene.getCurrentState().setToDefaultValues();//set to default values of 0 OR half between low and high joint values
00851   //config_data_->getPlanningScene()->getCurrentState().setToRandomValues();
00852 
00853   // Set the joints based on the map
00854   config_data_->getPlanningScene()->getCurrentStateNonConst().setStateValues( joint_state_map_ );
00855 
00856   // Create a planning scene message
00857   moveit_msgs::DisplayRobotState msg;
00858   robot_state::robotStateToRobotStateMsg(config_data_->getPlanningScene()->getCurrentState(), msg.state);
00859 
00860   // Publish!
00861   pub_robot_state_.publish( msg );
00862 
00863   // Decide if current state is in collision
00864   collision_detection::CollisionResult result;
00865   config_data_->getPlanningScene()->checkSelfCollision( request, result,
00866                                                         config_data_->getPlanningScene()->getCurrentState(),
00867                                                         config_data_->allowed_collision_matrix_ );
00868   // Show result notification
00869   if( result.contacts.size() )
00870   {
00871     collision_warning_->show();
00872   }
00873   else
00874   {
00875     collision_warning_->hide();
00876   }
00877 }
00878 
00879 
00880 // ******************************************************************************************
00881 // ******************************************************************************************
00882 // Slider Widget
00883 // ******************************************************************************************
00884 // ******************************************************************************************
00885 
00886 // ******************************************************************************************
00887 // Simple widget for adjusting joints of a robot
00888 // ******************************************************************************************
00889 SliderWidget::SliderWidget( QWidget *parent, const robot_model::JointModel *joint_model,
00890                             double init_value )
00891   : QWidget( parent ), joint_model_( joint_model )
00892 {
00893   // Create layouts
00894   QVBoxLayout *layout = new QVBoxLayout();
00895   QHBoxLayout *row2 = new QHBoxLayout();
00896 
00897   // Row 1
00898   joint_label_ = new QLabel( joint_model_->getName().c_str() , this );
00899   joint_label_->setContentsMargins( 0, 0, 0, 0 );
00900   layout->addWidget( joint_label_ );
00901 
00902   // Row 2 -------------------------------------------------------------
00903   joint_slider_ = new QSlider( Qt::Horizontal, this );
00904   joint_slider_->setTickPosition(QSlider::TicksBelow);
00905   joint_slider_->setSingleStep( 10 );
00906   joint_slider_->setPageStep( 500 );
00907   joint_slider_->setTickInterval( 1000 );
00908   joint_slider_->setContentsMargins( 0, 0, 0, 0 );
00909   row2->addWidget( joint_slider_ );
00910 
00911   // Joint Value Box ------------------------------------------------
00912   joint_value_ = new QLineEdit( this );
00913   joint_value_->setMaximumWidth( 62 );
00914   joint_value_->setContentsMargins( 0, 0, 0, 0 );
00915   connect( joint_value_, SIGNAL( editingFinished() ), this, SLOT( changeJointSlider() ) );
00916   row2->addWidget( joint_value_ );
00917 
00918   // Joint Limits ----------------------------------------------------
00919   const std::vector<moveit_msgs::JointLimits> &limits = joint_model_->getVariableLimits();
00920   if( limits.empty() )
00921   {
00922     QMessageBox::critical( this, "Error Loading", "An internal error has occured while loading the joints" );
00923     return;
00924   }
00925 
00926   // Only use the first limit, because there is only 1 variable (as checked earlier)
00927   moveit_msgs::JointLimits joint_limit = limits[0];
00928   max_position_ = joint_limit.max_position;
00929   min_position_ = joint_limit.min_position;
00930 
00931   // Set the slider limits
00932   joint_slider_->setMaximum( max_position_*10000 );
00933   joint_slider_->setMinimum( min_position_*10000 );
00934 
00935   // Connect slider to joint value box
00936   connect( joint_slider_, SIGNAL(valueChanged(int)), this, SLOT(changeJointValue(int)) );
00937 
00938   // Initial joint values -------------------------------------------
00939   int value = init_value * 10000; // scale double to integer for slider use
00940   joint_slider_->setSliderPosition( value ); // set slider value
00941   changeJointValue( value ); // show in textbox
00942 
00943   // Finish GUI ----------------------------------------
00944   layout->addLayout( row2 );
00945 
00946   this->setContentsMargins( 0, 0, 0, 0 );
00947   //this->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Preferred );
00948   this->setGeometry(QRect(110, 80, 120, 80));
00949   this->setLayout( layout );
00950 
00951   // Declare std::string as metatype so we can use it in a signal
00952   qRegisterMetaType<std::string>("std::string");
00953 }
00954 
00955 // ******************************************************************************************
00956 // Deconstructor
00957 // ******************************************************************************************
00958 SliderWidget::~SliderWidget()
00959 {
00960 }
00961 
00962 // ******************************************************************************************
00963 // Called when the joint value slider is changed
00964 // ******************************************************************************************
00965 void SliderWidget::changeJointValue( int value )
00966 {
00967   // Get joint value
00968   const double double_value = double( value ) / 10000;
00969 
00970   // Set textbox
00971   joint_value_->setText( QString( "%1" ).arg( double_value, 0, 'f', 4 ) );
00972 
00973   // Send event to parent widget
00974   Q_EMIT jointValueChanged( joint_model_->getName(), double_value );
00975 }
00976 
00977 // ******************************************************************************************
00978 // Called when the joint value box is changed
00979 // ******************************************************************************************
00980 void SliderWidget::changeJointSlider()
00981 {
00982   // Get joint value
00983   double value = joint_value_->text().toDouble();
00984 
00985   if( min_position_ > value || value > max_position_ ) {
00986     value = (min_position_ > value) ? min_position_ : max_position_;
00987     joint_value_->setText( QString( "%1" ).arg( value, 0, 'f', 4 ) );
00988   }
00989 
00990   // We assume it converts to double because of the validator
00991   joint_slider_->setSliderPosition( value * 10000 );
00992 
00993   // Send event to parent widget
00994   Q_EMIT jointValueChanged( joint_model_->getName(), value );
00995 }
00996 
00997 
00998 
00999 
01000 
01001 
01002 } // namespace


moveit_setup_assistant
Author(s): Dave Coleman
autogenerated on Mon Oct 6 2014 02:32:27