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 #include <main_window.h>
00033 #include <job_processing.h>
00034
00035 #include <moveit/kinematic_constraints/utils.h>
00036 #include <moveit/robot_state/conversions.h>
00037 #include <moveit/warehouse/constraints_storage.h>
00038 #include <moveit/warehouse/state_storage.h>
00039
00040 #include <rviz/display_context.h>
00041 #include <rviz/window_manager_interface.h>
00042
00043 #include <eigen_conversions/eigen_msg.h>
00044
00045 #include <QMessageBox>
00046 #include <QInputDialog>
00047 #include <QFileDialog>
00048
00049
00050 #include <boost/math/constants/constants.hpp>
00051
00052 namespace benchmark_tool
00053 {
00054
00055 void MainWindow::createGoalPoseButtonClicked(void)
00056 {
00057 std::stringstream ss;
00058
00059 {
00060 const planning_scene_monitor::LockedPlanningSceneRO &ps = scene_display_->getPlanningSceneRO();
00061 if ( ! ps || robot_interaction_->getActiveEndEffectors().empty() )
00062 {
00063 if ( ! ps ) ROS_ERROR("Not planning scene");
00064 if ( robot_interaction_->getActiveEndEffectors().empty() ) ROS_ERROR("No end effector");
00065 return;
00066 }
00067 else
00068 ss << ps->getName().c_str() << "_pose_" << std::setfill('0') << std::setw(4) << goal_poses_.size();
00069 }
00070
00071 bool ok = false;
00072 QString text = QInputDialog::getText(this, tr("Choose a name"),
00073 tr("Goal pose name:"), QLineEdit::Normal,
00074 QString(ss.str().c_str()), &ok);
00075
00076 std::string name;
00077 if (ok)
00078 {
00079 if ( ! text.isEmpty() )
00080 {
00081 name = text.toStdString();
00082 if (goal_poses_.find(name) != goal_poses_.end())
00083 QMessageBox::warning(this, "Name already exists", QString("The name '").append(name.c_str()).
00084 append("' already exists. Not creating goal."));
00085 else
00086 {
00087
00088 Eigen::Affine3d tip_pose = scene_display_->getPlanningSceneRO()->getCurrentState().getLinkState(robot_interaction_->getActiveEndEffectors()[0].parent_link)->getGlobalLinkTransform();
00089 goals_initial_pose_.insert(std::pair<std::string, Eigen::Affine3d>(name, tip_pose));
00090
00091 geometry_msgs::Pose marker_pose;
00092 tf::poseEigenToMsg(tip_pose * goal_offset_, marker_pose);
00093 static const float marker_scale = 0.15;
00094
00095 GripperMarkerPtr goal_pose(new GripperMarker(scene_display_->getPlanningSceneRO()->getCurrentState(), scene_display_->getSceneNode(), visualization_manager_, name, scene_display_->getRobotModel()->getModelFrame(),
00096 robot_interaction_->getActiveEndEffectors()[0], marker_pose, marker_scale, GripperMarker::NOT_TESTED));
00097 goal_poses_.insert(GoalPosePair(name, goal_pose));
00098
00099
00100 goal_pose->connect(this, SLOT( goalPoseFeedback(visualization_msgs::InteractiveMarkerFeedback &) ));
00101
00102
00103 if (constraints_storage_)
00104 {
00105 moveit_msgs::Constraints c;
00106 c.name = name;
00107
00108 shape_msgs::SolidPrimitive sp;
00109 sp.type = sp.BOX;
00110 sp.dimensions.resize(3, std::numeric_limits<float>::epsilon() * 10.0);
00111
00112 moveit_msgs::PositionConstraint pc;
00113 pc.constraint_region.primitives.push_back(sp);
00114 geometry_msgs::Pose posemsg;
00115 posemsg.position.x = goal_pose->imarker->getPosition().x;
00116 posemsg.position.y = goal_pose->imarker->getPosition().y;
00117 posemsg.position.z = goal_pose->imarker->getPosition().z;
00118 posemsg.orientation.x = 0.0;
00119 posemsg.orientation.y = 0.0;
00120 posemsg.orientation.z = 0.0;
00121 posemsg.orientation.w = 1.0;
00122 pc.constraint_region.primitive_poses.push_back(posemsg);
00123 pc.weight = 1.0;
00124 c.position_constraints.push_back(pc);
00125
00126 moveit_msgs::OrientationConstraint oc;
00127 oc.orientation.x = goal_pose->imarker->getOrientation().x;
00128 oc.orientation.y = goal_pose->imarker->getOrientation().y;
00129 oc.orientation.z = goal_pose->imarker->getOrientation().z;
00130 oc.orientation.w = goal_pose->imarker->getOrientation().w;
00131 oc.absolute_x_axis_tolerance = oc.absolute_y_axis_tolerance =
00132 oc.absolute_z_axis_tolerance = std::numeric_limits<float>::epsilon() * 10.0;
00133 oc.weight = 1.0;
00134 c.orientation_constraints.push_back(oc);
00135
00136 try
00137 {
00138 constraints_storage_->addConstraints(c);
00139 }
00140 catch (std::runtime_error &ex)
00141 {
00142 ROS_ERROR("Cannot save constraint on database: %s", ex.what());
00143 }
00144 }
00145 }
00146 }
00147 else
00148 QMessageBox::warning(this, "Goal not created", "Cannot use an empty name for a new goal pose.");
00149 }
00150
00151 populateGoalPosesList();
00152 }
00153
00154 void MainWindow::removeSelectedGoalsButtonClicked(void)
00155 {
00156 QList<QListWidgetItem*> found_items = ui_.goal_poses_list->selectedItems();
00157 for ( unsigned int i = 0 ; i < found_items.size() ; i++ )
00158 {
00159 goal_poses_.erase(found_items[i]->text().toStdString());
00160 }
00161 populateGoalPosesList();
00162 }
00163
00164 void MainWindow::removeAllGoalsButtonClicked(void)
00165 {
00166 goal_poses_.clear();
00167 goals_initial_pose_.clear();
00168 populateGoalPosesList();
00169 }
00170
00171 void MainWindow::loadGoalsFromDBButtonClicked(void)
00172 {
00173
00174 if (constraints_storage_ && !robot_interaction_->getActiveEndEffectors().empty())
00175 {
00176
00177 removeAllGoalsButtonClicked();
00178
00179 std::vector<std::string> names;
00180 try
00181 {
00182 constraints_storage_->getKnownConstraints(ui_.load_poses_filter_text->text().toStdString(), names);
00183 }
00184 catch (std::runtime_error &ex)
00185 {
00186 QMessageBox::warning(this, "Cannot query the database", QString("Wrongly formatted regular expression for goal poses: ").append(ex.what()));
00187 return;
00188 }
00189
00190 for (unsigned int i = 0 ; i < names.size() ; i++)
00191 {
00192
00193 moveit_warehouse::ConstraintsWithMetadata c;
00194 bool got_constraint = false;
00195 try
00196 {
00197 got_constraint = constraints_storage_->getConstraints(c, names[i]);
00198 }
00199 catch (std::runtime_error &ex)
00200 {
00201 ROS_ERROR("%s", ex.what());
00202 }
00203 if (!got_constraint)
00204 continue;
00205
00206 if ( c->position_constraints.size() > 0 && c->position_constraints[0].constraint_region.primitive_poses.size() > 0 && c->orientation_constraints.size() > 0 )
00207 {
00208
00209 if ( goal_poses_.find(c->name) != goal_poses_.end() )
00210 {
00211 goal_poses_.erase(c->name);
00212 }
00213 geometry_msgs::Pose shape_pose;
00214 shape_pose.position = c->position_constraints[0].constraint_region.primitive_poses[0].position;
00215 shape_pose.orientation = c->orientation_constraints[0].orientation;
00216
00217 Eigen::Affine3d shape_pose_eigen;
00218 tf::poseMsgToEigen(shape_pose, shape_pose_eigen);
00219 goals_initial_pose_.insert(std::pair<std::string, Eigen::Affine3d>(c->name, shape_pose_eigen));
00220
00221 tf::poseEigenToMsg(shape_pose_eigen * goal_offset_, shape_pose);
00222
00223 static const float marker_scale = 0.15;
00224 GripperMarkerPtr goal_pose(new GripperMarker(scene_display_->getPlanningSceneRO()->getCurrentState(), scene_display_->getSceneNode(), visualization_manager_, c->name, scene_display_->getRobotModel()->getModelFrame(),
00225 robot_interaction_->getActiveEndEffectors()[0], shape_pose, marker_scale, GripperMarker::NOT_TESTED, false,
00226 ui_.show_x_checkbox->isChecked(), ui_.show_y_checkbox->isChecked(), ui_.show_z_checkbox->isChecked()));
00227
00228 goal_pose->connect(this, SLOT( goalPoseFeedback(visualization_msgs::InteractiveMarkerFeedback &) ));
00229
00230 goal_poses_.insert(GoalPosePair(c->name, goal_pose));
00231 }
00232 }
00233 populateGoalPosesList();
00234 }
00235 else
00236 {
00237 if (!constraints_storage_)
00238 QMessageBox::warning(this, "Warning", "Not connected to a database.");
00239 }
00240 }
00241
00242 void MainWindow::saveGoalsOnDBButtonClicked(void)
00243 {
00244 if (constraints_storage_)
00245 {
00246
00247 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00248 {
00249 moveit_msgs::Constraints c;
00250 c.name = it->first;
00251
00252 shape_msgs::SolidPrimitive sp;
00253 sp.type = sp.BOX;
00254 sp.dimensions.resize(3, std::numeric_limits<float>::epsilon() * 10.0);
00255
00256 moveit_msgs::PositionConstraint pc;
00257 pc.constraint_region.primitives.push_back(sp);
00258 geometry_msgs::Pose posemsg;
00259 it->second->getPosition(posemsg.position);
00260 posemsg.orientation.x = 0.0;
00261 posemsg.orientation.y = 0.0;
00262 posemsg.orientation.z = 0.0;
00263 posemsg.orientation.w = 1.0;
00264 pc.constraint_region.primitive_poses.push_back(posemsg);
00265 pc.weight = 1.0;
00266 c.position_constraints.push_back(pc);
00267
00268 moveit_msgs::OrientationConstraint oc;
00269 it->second->getOrientation(oc.orientation);
00270 oc.absolute_x_axis_tolerance = oc.absolute_y_axis_tolerance =
00271 oc.absolute_z_axis_tolerance = std::numeric_limits<float>::epsilon() * 10.0;
00272 oc.weight = 1.0;
00273 c.orientation_constraints.push_back(oc);
00274
00275 try
00276 {
00277 constraints_storage_->addConstraints(c);
00278 }
00279 catch (std::runtime_error &ex)
00280 {
00281 ROS_ERROR("Cannot save constraint: %s", ex.what());
00282 }
00283 }
00284 }
00285 else
00286 {
00287 QMessageBox::warning(this, "Warning", "Not connected to a database.");
00288 }
00289 }
00290
00291 void MainWindow::deleteGoalsOnDBButtonClicked(void)
00292 {
00293 if (constraints_storage_)
00294 {
00295
00296 QMessageBox msgBox;
00297 msgBox.setText("All the selected items will be removed from the database");
00298 msgBox.setInformativeText("Do you want to continue?");
00299 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
00300 msgBox.setDefaultButton(QMessageBox::No);
00301 int ret = msgBox.exec();
00302
00303 switch (ret)
00304 {
00305 case QMessageBox::Yes:
00306 {
00307
00308 QList<QListWidgetItem*> found_items = ui_.goal_poses_list->selectedItems();
00309 for ( std::size_t i = 0 ; i < found_items.size() ; i++ )
00310 {
00311 try
00312 {
00313 constraints_storage_->removeConstraints(found_items[i]->text().toStdString());
00314 }
00315 catch (std::runtime_error &ex)
00316 {
00317 ROS_ERROR("%s", ex.what());
00318 }
00319 }
00320 break;
00321 }
00322 }
00323 }
00324 removeSelectedGoalsButtonClicked();
00325 }
00326
00327
00328 void MainWindow::loadStatesFromDBButtonClicked(void)
00329 {
00330
00331 if (robot_state_storage_)
00332 {
00333
00334 removeAllStatesButtonClicked();
00335
00336 std::vector<std::string> names;
00337 try
00338 {
00339 robot_state_storage_->getKnownRobotStates(ui_.load_states_filter_text->text().toStdString(), names);
00340 }
00341 catch (std::runtime_error &ex)
00342 {
00343 QMessageBox::warning(this, "Cannot query the database", QString("Wrongly formatted regular expression for goal poses: ").append(ex.what()));
00344 return;
00345 }
00346
00347 for ( unsigned int i = 0 ; i < names.size() ; i++ )
00348 {
00349 moveit_warehouse::RobotStateWithMetadata rs;
00350 bool got_state = false;
00351 try
00352 {
00353 got_state = robot_state_storage_->getRobotState(rs, names[i]);
00354 }
00355 catch(std::runtime_error &ex)
00356 {
00357 ROS_ERROR("%s", ex.what());
00358 }
00359 if (!got_state)
00360 continue;
00361
00362
00363 if (start_states_.find(names[i]) != start_states_.end())
00364 {
00365 start_states_.erase(names[i]);
00366 }
00367
00368
00369 start_states_.insert(StartStatePair(names[i], StartStatePtr(new StartState(*rs))));
00370 }
00371 populateStartStatesList();
00372 }
00373 else
00374 {
00375 QMessageBox::warning(this, "Warning", "Not connected to a database.");
00376 }
00377 }
00378
00379 void MainWindow::saveStatesOnDBButtonClicked(void)
00380 {
00381 if (robot_state_storage_)
00382 {
00383
00384 for (StartStateMap::iterator it = start_states_.begin(); it != start_states_.end(); ++it)
00385 try
00386 {
00387 robot_state_storage_->addRobotState(it->second->state_msg, it->first);
00388 }
00389 catch (std::runtime_error &ex)
00390 {
00391 ROS_ERROR("Cannot save robot state: %s", ex.what());
00392 }
00393 }
00394 else
00395 {
00396 QMessageBox::warning(this, "Warning", "Not connected to a database.");
00397 }
00398 }
00399
00400 void MainWindow::deleteStatesOnDBButtonClicked(void)
00401 {
00402 if (robot_state_storage_)
00403 {
00404
00405 QMessageBox msgBox;
00406 msgBox.setText("All the selected items will be removed from the database");
00407 msgBox.setInformativeText("Do you want to continue?");
00408 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
00409 msgBox.setDefaultButton(QMessageBox::No);
00410 int ret = msgBox.exec();
00411
00412 switch (ret)
00413 {
00414 case QMessageBox::Yes:
00415 {
00416 QList<QListWidgetItem*> found_items = ui_.start_states_list->selectedItems();
00417 for (unsigned int i = 0; i < found_items.size() ; ++i)
00418 {
00419 try
00420 {
00421 robot_state_storage_->removeRobotState(found_items[i]->text().toStdString());
00422 }
00423 catch (std::runtime_error &ex)
00424 {
00425 ROS_ERROR("%s", ex.what());
00426 }
00427 }
00428 break;
00429 }
00430 }
00431 }
00432 removeSelectedStatesButtonClicked();
00433 }
00434
00435 void MainWindow::visibleAxisChanged(int state)
00436 {
00437 if ( ! robot_interaction_->getActiveEndEffectors().empty() )
00438 {
00439 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00440 {
00441 if (it->second->isVisible())
00442 {
00443 it->second->setAxisVisibility(ui_.show_x_checkbox->isChecked(), ui_.show_y_checkbox->isChecked(), ui_.show_z_checkbox->isChecked());
00444 }
00445 }
00446 }
00447 }
00448
00449 void MainWindow::populateGoalPosesList(void)
00450 {
00451 ui_.goal_poses_list->clear();
00452 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00453 {
00454 QListWidgetItem *item = new QListWidgetItem(QString(it->first.c_str()));
00455 ui_.goal_poses_list->addItem(item);
00456 if (! it->second->isVisible())
00457 {
00458 item->setBackground(QBrush(Qt::Dense4Pattern));
00459 }
00460 else if (it->second->isSelected())
00461 {
00462
00463 item->setSelected(true);
00464 }
00465 }
00466 }
00467
00468 void MainWindow::switchGoalVisibilityButtonClicked(void)
00469 {
00470 QList<QListWidgetItem*> selection = ui_.goal_poses_list->selectedItems();
00471 for (std::size_t i = 0; i < selection.size() ; ++i)
00472 {
00473 std::string name = selection[i]->text().toStdString();
00474 if (goal_poses_[name]->isVisible())
00475 {
00476
00477 goal_poses_[name]->hide();
00478 selection[i]->setBackground(QBrush(Qt::Dense4Pattern));
00479 }
00480 else
00481 {
00482
00483 goal_poses_[name]->show(scene_display_->getSceneNode(), visualization_manager_);
00484 selection[i]->setBackground(QBrush(Qt::NoBrush));
00485 }
00486 }
00487 }
00488
00489 void MainWindow::goalPoseSelectionChanged(void)
00490 {
00491 for (unsigned int i = 0; i < ui_.goal_poses_list->count() ; ++i)
00492 {
00493 QListWidgetItem *item = ui_.goal_poses_list->item(i);
00494 std::string name = item->text().toStdString();
00495 if ( goal_poses_.find(name) != goal_poses_.end() &&
00496 ( (item->isSelected() && ! goal_poses_[name]->isSelected() )
00497 || ( ! item->isSelected() && goal_poses_[name]->isSelected() )))
00498 switchGoalPoseMarkerSelection(name);
00499 }
00500 }
00501
00502 void MainWindow::goalPoseDoubleClicked(QListWidgetItem * item)
00503 {
00504 JobProcessing::addBackgroundJob(boost::bind(&MainWindow::computeGoalPoseDoubleClicked, this, item));
00505 }
00506
00507 void MainWindow::computeGoalPoseDoubleClicked(QListWidgetItem * item)
00508 {
00509 if ( ! robot_interaction_ || robot_interaction_->getActiveEndEffectors().empty() )
00510 return;
00511
00512 std::string item_text = item->text().toStdString();
00513
00514
00515 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, item_text, GripperMarker::PROCESSING));
00516
00517 checkIfGoalReachable(item_text, true);
00518 }
00519
00520
00521 void MainWindow::goalPoseFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
00522 {
00523 static Eigen::Affine3d initial_pose_eigen;
00524
00525 if (feedback.event_type == feedback.BUTTON_CLICK)
00526 {
00527
00528 QListWidgetItem *item = 0;
00529 for (unsigned int i = 0; i < ui_.goal_poses_list->count(); ++i)
00530 {
00531 item = ui_.goal_poses_list->item(i);
00532 if ( item->text().toStdString() != feedback.marker_name)
00533 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::selectItemJob, this, item, false));
00534 }
00535
00536 for (unsigned int i = 0; i < ui_.goal_poses_list->count(); ++i)
00537 {
00538 item = ui_.goal_poses_list->item(i);
00539 if (item->text().toStdString() == feedback.marker_name)
00540 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::selectItemJob, this, item, true));
00541 }
00542 }
00543 else if (feedback.event_type == feedback.MOUSE_DOWN)
00544 {
00545
00546 goals_dragging_initial_pose_.clear();
00547 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00548 {
00549 if (it->second->isSelected() && it->second->isVisible())
00550 {
00551 Eigen::Affine3d pose(Eigen::Quaterniond(it->second->imarker->getOrientation().w, it->second->imarker->getOrientation().x,
00552 it->second->imarker->getOrientation().y, it->second->imarker->getOrientation().z));
00553 pose(0,3) = it->second->imarker->getPosition().x;
00554 pose(1,3) = it->second->imarker->getPosition().y;
00555 pose(2,3) = it->second->imarker->getPosition().z;
00556 goals_dragging_initial_pose_.insert(std::pair<std::string, Eigen::Affine3d>(it->second->imarker->getName(), pose));
00557
00558 if (it->second->imarker->getName() == feedback.marker_name)
00559 initial_pose_eigen = pose;
00560 }
00561 }
00562 goal_pose_dragging_=true;
00563 }
00564 else if (feedback.event_type == feedback.POSE_UPDATE && goal_pose_dragging_)
00565 {
00566
00567 Eigen::Affine3d current_pose_eigen;
00568 tf::poseMsgToEigen(feedback.pose, current_pose_eigen);
00569
00570 Eigen::Affine3d current_wrt_initial = initial_pose_eigen.inverse() * current_pose_eigen;
00571
00572
00573 Eigen::Vector3d v = current_pose_eigen.linear().eulerAngles(0,1,2);
00574 setStatusFromBackground(STATUS_INFO, QString().sprintf(
00575 "%.2f %.2f %.2f %.2f %.2f %.2f",
00576 current_pose_eigen(0,3),
00577 current_pose_eigen(1,3),
00578 current_pose_eigen(2,3),
00579 v(0) * 180.0 / boost::math::constants::pi<double>(),
00580 v(1) * 180.0 / boost::math::constants::pi<double>(),
00581 v(2) * 180.0 / boost::math::constants::pi<double>()));
00582
00583
00584 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end() ; ++it)
00585 {
00586 if (it->second->isVisible() && it->second->imarker->getName() != feedback.marker_name && it->second->isSelected())
00587 {
00588 visualization_msgs::InteractiveMarkerPose impose;
00589
00590 Eigen::Affine3d newpose = initial_pose_eigen * current_wrt_initial * initial_pose_eigen.inverse() * goals_dragging_initial_pose_[it->second->imarker->getName()];
00591 tf::poseEigenToMsg(newpose, impose.pose);
00592
00593 it->second->imarker->setPose(Ogre::Vector3(impose.pose.position.x, impose.pose.position.y, impose.pose.position.z),
00594 Ogre::Quaternion(impose.pose.orientation.w, impose.pose.orientation.x, impose.pose.orientation.y, impose.pose.orientation.z), "");
00595 }
00596 }
00597 } else if (feedback.event_type == feedback.MOUSE_UP)
00598 {
00599 goal_pose_dragging_ = false;
00600 JobProcessing::addBackgroundJob(boost::bind(&MainWindow::checkIfGoalInCollision, this, feedback.marker_name));
00601 }
00602 }
00603
00604 void MainWindow::checkGoalsReachable(void)
00605 {
00606 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00607 JobProcessing::addBackgroundJob(boost::bind(&MainWindow::checkIfGoalReachable, this, it->first, false));
00608 }
00609
00610 void MainWindow::checkGoalsInCollision(void)
00611 {
00612 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
00613 JobProcessing::addBackgroundJob(boost::bind(&MainWindow::checkIfGoalInCollision, this, it->first));
00614 }
00615
00616 void MainWindow::checkIfGoalReachable(const std::string &goal_name, bool update_if_reachable)
00617 {
00618 if ( goal_poses_.find(goal_name) == goal_poses_.end())
00619 return;
00620
00621 if ( ! goal_poses_[goal_name]->isVisible())
00622 return;
00623
00624 const boost::shared_ptr<rviz::InteractiveMarker> &imarker = goal_poses_[goal_name]->imarker;
00625
00626 geometry_msgs::Pose current_pose_msg;
00627 current_pose_msg.position.x = imarker->getPosition().x;
00628 current_pose_msg.position.y = imarker->getPosition().y;
00629 current_pose_msg.position.z = imarker->getPosition().z;
00630 current_pose_msg.orientation.x = imarker->getOrientation().x;
00631 current_pose_msg.orientation.y = imarker->getOrientation().y;
00632 current_pose_msg.orientation.z = imarker->getOrientation().z;
00633 current_pose_msg.orientation.w = imarker->getOrientation().w;
00634
00635
00636 setStatusFromBackground(STATUS_INFO, "Computing inverse kinematics...");
00637 robot_state::RobotState ks(scene_display_->getPlanningSceneRO()->getCurrentState());
00638 static const int ik_attempts = 5;
00639 static const float ik_timeout = 0.2;
00640 bool feasible = robot_interaction_->updateState(ks,
00641 robot_interaction_->getActiveEndEffectors()[0],
00642 current_pose_msg, ik_attempts, ik_timeout);
00643 if (feasible)
00644 {
00645 setStatusFromBackground(STATUS_INFO, "Updating state...");
00646 if (update_if_reachable)
00647 {
00648 scene_display_->getPlanningSceneRW()->setCurrentState(ks);
00649 scene_display_->queueRenderSceneGeometry();
00650 }
00651
00652 setStatusFromBackground(STATUS_INFO, "Updating marker...");
00653
00654 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
00655 GripperMarker::REACHABLE));
00656 }
00657 else
00658 {
00659
00660 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
00661 GripperMarker::NOT_REACHABLE));
00662 }
00663 setStatusFromBackground(STATUS_INFO, "");
00664 }
00665
00666 void MainWindow::checkIfGoalInCollision(const std::string & goal_name)
00667 {
00668 if ( goal_poses_.find(goal_name) == goal_poses_.end())
00669 return;
00670
00671
00672 if ( ! goal_poses_[goal_name]->isVisible())
00673 return;
00674
00675 const robot_interaction::RobotInteraction::EndEffector &eef = robot_interaction_->getActiveEndEffectors()[0];
00676
00677 const boost::shared_ptr<rviz::InteractiveMarker> &im = goal_poses_[goal_name]->imarker;
00678 Eigen::Affine3d marker_pose_eigen;
00679 goal_poses_[goal_name]->getPose(marker_pose_eigen);
00680
00681 robot_state::RobotState ks(scene_display_->getPlanningSceneRO()->getCurrentState());
00682 ks.updateStateWithLinkAt(eef.parent_link, marker_pose_eigen);
00683 bool in_collision = scene_display_->getPlanningSceneRO()->isStateColliding(ks, eef.eef_group);
00684
00685 if ( in_collision )
00686 {
00687 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
00688 GripperMarker::IN_COLLISION));
00689 }
00690 else
00691 {
00692 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
00693 GripperMarker::NOT_TESTED));
00694 }
00695 }
00696
00697 void MainWindow::switchGoalPoseMarkerSelection(const std::string &marker_name)
00698 {
00699 if (robot_interaction_->getActiveEndEffectors().empty() || ! goal_poses_[marker_name]->isVisible())
00700 return;
00701
00702 if (goal_poses_[marker_name]->isSelected())
00703 {
00704
00705 goal_poses_[marker_name]->unselect();
00706 setItemSelectionInList(marker_name, false, ui_.goal_poses_list);
00707 }
00708 else
00709 {
00710
00711 if (ui_.goal_poses_list->selectedItems().size() == 1)
00712 goal_poses_[marker_name]->select(true);
00713 else
00714 goal_poses_[marker_name]->select(false);
00715 setItemSelectionInList(marker_name, true, ui_.goal_poses_list);
00716 }
00717 }
00718
00719 void MainWindow::copySelectedGoalPoses(void)
00720 {
00721 QList<QListWidgetItem *> sel = ui_.goal_poses_list->selectedItems();
00722 if (sel.empty() || robot_interaction_->getActiveEndEffectors().empty())
00723 return;
00724
00725 std::string scene_name;
00726 {
00727 const planning_scene_monitor::LockedPlanningSceneRO &ps = scene_display_->getPlanningSceneRO();
00728 if (!ps)
00729 return;
00730 else
00731 scene_name = ps->getName();
00732 }
00733
00734 for (int i = 0 ; i < sel.size() ; ++i)
00735 {
00736 std::string name = sel[i]->text().toStdString();
00737 if (! goal_poses_[name]->isVisible())
00738 continue;
00739
00740 std::stringstream ss;
00741 ss << scene_name.c_str() << "_pose_" << std::setfill('0') << std::setw(4) << goal_poses_.size();
00742
00743 Eigen::Affine3d tip_pose = scene_display_->getPlanningSceneRO()->getCurrentState().getLinkState(robot_interaction_->getActiveEndEffectors()[0].parent_link)->getGlobalLinkTransform();
00744 geometry_msgs::Pose marker_pose;
00745 marker_pose.position.x = goal_poses_[name]->imarker->getPosition().x;
00746 marker_pose.position.y = goal_poses_[name]->imarker->getPosition().y;
00747 marker_pose.position.z = goal_poses_[name]->imarker->getPosition().z;
00748 marker_pose.orientation.x = goal_poses_[name]->imarker->getOrientation().x;
00749 marker_pose.orientation.y = goal_poses_[name]->imarker->getOrientation().y;
00750 marker_pose.orientation.z = goal_poses_[name]->imarker->getOrientation().z;
00751 marker_pose.orientation.w = goal_poses_[name]->imarker->getOrientation().w;
00752
00753 static const float marker_scale = 0.15;
00754 GripperMarkerPtr goal_pose(new GripperMarker(scene_display_->getPlanningSceneRO()->getCurrentState(), scene_display_->getSceneNode(), visualization_manager_, ss.str(), scene_display_->getRobotModel()->getModelFrame(),
00755 robot_interaction_->getActiveEndEffectors()[0], marker_pose, marker_scale, GripperMarker::NOT_TESTED, true));
00756
00757 goal_poses_.insert(GoalPosePair(ss.str(), goal_pose));
00758
00759
00760 goal_pose->connect(this, SLOT( goalPoseFeedback(visualization_msgs::InteractiveMarkerFeedback &)));
00761
00762
00763 switchGoalPoseMarkerSelection(name);
00764 }
00765
00766 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::populateGoalPosesList, this));
00767 }
00768
00769 void MainWindow::saveStartStateButtonClicked(void)
00770 {
00771 bool ok = false;
00772
00773 std::stringstream ss;
00774 ss << scene_display_->getRobotModel()->getName().c_str() << "_state_" << std::setfill('0') << std::setw(4) << start_states_.size();
00775
00776 QString text = QInputDialog::getText(this, tr("Choose a name"),
00777 tr("Start state name:"), QLineEdit::Normal,
00778 QString(ss.str().c_str()), &ok);
00779
00780 std::string name;
00781 if (ok)
00782 {
00783 if (!text.isEmpty())
00784 {
00785 name = text.toStdString();
00786 if (start_states_.find(name) != start_states_.end())
00787 QMessageBox::warning(this, "Name already exists", QString("The name '").append(name.c_str()).
00788 append("' already exists. Not creating state."));
00789 else
00790 {
00791
00792 moveit_msgs::RobotState msg;
00793 robot_state::robotStateToRobotStateMsg(scene_display_->getPlanningSceneRO()->getCurrentState(), msg);
00794 start_states_.insert(StartStatePair(name, StartStatePtr(new StartState(msg))));
00795
00796
00797 if (robot_state_storage_)
00798 {
00799 try
00800 {
00801 robot_state_storage_->addRobotState(msg, name);
00802 }
00803 catch (std::runtime_error &ex)
00804 {
00805 ROS_ERROR("Cannot save robot state on the database: %s", ex.what());
00806 }
00807 }
00808 }
00809 }
00810 else
00811 QMessageBox::warning(this, "Start state not saved", "Cannot use an empty name for a new start state.");
00812 }
00813 populateStartStatesList();
00814 }
00815
00816 void MainWindow::removeSelectedStatesButtonClicked(void)
00817 {
00818 QList<QListWidgetItem*> found_items = ui_.start_states_list->selectedItems();
00819 for (unsigned int i = 0; i < found_items.size(); i++)
00820 {
00821 start_states_.erase(found_items[i]->text().toStdString());
00822 }
00823 populateStartStatesList();
00824 }
00825
00826 void MainWindow::removeAllStatesButtonClicked(void)
00827 {
00828 start_states_.clear();
00829 populateStartStatesList();
00830 }
00831
00832 void MainWindow::populateStartStatesList(void)
00833 {
00834 ui_.start_states_list->clear();
00835 for (StartStateMap::iterator it = start_states_.begin(); it != start_states_.end(); ++it)
00836 {
00837 QListWidgetItem *item = new QListWidgetItem(QString(it->first.c_str()));
00838 ui_.start_states_list->addItem(item);
00839 if (it->second->selected)
00840 {
00841
00842 item->setSelected(true);
00843 }
00844 }
00845 }
00846
00847 void MainWindow::startStateItemDoubleClicked(QListWidgetItem * item)
00848 {
00849 scene_display_->getPlanningSceneRW()->setCurrentState(start_states_[item->text().toStdString()]->state_msg);
00850 scene_display_->queueRenderSceneGeometry();
00851 }
00852
00853 void MainWindow::runBenchmark(void)
00854 {
00855 QDialog *dialog = new QDialog(0,0);
00856
00857 run_benchmark_ui_.setupUi(dialog);
00858 run_benchmark_ui_.benchmark_select_folder_button->setIcon(QIcon::fromTheme("document-open", QApplication::style()->standardIcon(QStyle::SP_DirOpenIcon)));
00859 connect( run_benchmark_ui_.benchmark_button_box, SIGNAL( accepted( ) ), this, SLOT( runBenchmarkOKButtonClicked( ) ));
00860 connect( run_benchmark_ui_.benchmark_select_folder_button, SIGNAL( clicked( ) ), this, SLOT( benchmarkFolderButtonClicked( ) ));
00861
00862 for (StartStateMap::iterator it = start_states_.begin(); it != start_states_.end(); ++it)
00863 {
00864 run_benchmark_ui_.benchmark_start_state_combo->addItem(it->first.c_str());
00865 }
00866
00867 dialog->show();
00868 }
00869
00870 void MainWindow::benchmarkFolderButtonClicked(void)
00871 {
00872 QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
00873 "/home", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
00874 run_benchmark_ui_.benchmark_output_folder_text->setText(dir);
00875 }
00876
00877 void MainWindow::runBenchmarkOKButtonClicked(void)
00878 {
00879 if (run_benchmark_ui_.benchmark_output_folder_text->text().isEmpty())
00880 {
00881 QMessageBox::warning(this, "Missing data", "Must specify an output folder");
00882 return;
00883 }
00884
00885 QString outfilename = run_benchmark_ui_.benchmark_output_folder_text->text().append("/config.cfg");
00886 std::ofstream outfile(outfilename.toUtf8());
00887 if (outfile)
00888 {
00889 outfile << "[scene]" << std::endl;
00890 outfile << "group=" << ui_.planning_group_combo->currentText().toStdString() << std::endl;
00891 outfile << "default_constrained_link=" << robot_interaction_->getActiveEndEffectors()[0].parent_link << std::endl;
00892 outfile << "planning_frame=" << scene_display_->getPlanningSceneMonitor()->getRobotModel()->getModelFrame() << std::endl;
00893 outfile << "name=" << scene_display_->getPlanningSceneRO()->getName() << std::endl;
00894
00895
00896 outfile << "timeout=1" << std::endl;
00897 outfile << "runs=1" << std::endl;
00898 outfile << "output=" << scene_display_->getPlanningSceneMonitor()->getRobotModel()->getName() << "_" <<
00899 scene_display_->getPlanningSceneRO()->getName() << "_" <<
00900 ros::Time::now() << std::endl;
00901 outfile << "start=" << run_benchmark_ui_.benchmark_output_folder_text->text().toStdString() << std::endl;
00902 outfile << "query=" << std::endl;
00903 outfile << "goal=" << ui_.load_poses_filter_text->text().toStdString() << std::endl;
00904 outfile << "goal_offset_roll=" << ui_.goal_offset_roll->value() << std::endl;
00905 outfile << "goal_offset_pitch=" << ui_.goal_offset_pitch->value() << std::endl;
00906 outfile << "goal_offset_yaw=" << ui_.goal_offset_yaw->value() << std::endl << std::endl;
00907
00908
00909 outfile << "[plugin]" << std::endl;
00910 outfile << "name=ompl_interface_ros/OMPLPlanner" << std::endl;
00911 outfile << "planners=RRTConnectkConfigDefault" << std::endl;
00912
00913 outfile.close();
00914 }
00915 else
00916 {
00917 QMessageBox::warning(this, "Error", QString("Cannot open file ").append(outfilename).append(" for writing"));
00918 }
00919 }
00920
00921 void MainWindow::loadBenchmarkResults(void)
00922 {
00923
00924 QString path = QFileDialog::getOpenFileName(this, tr("Select a log file in the set"), tr(""), tr("Log files (*.log)"));
00925 if (!path.isEmpty())
00926 {
00927 JobProcessing::addBackgroundJob(boost::bind(&MainWindow::computeLoadBenchmarkResults, this, path.toStdString()));
00928 }
00929 }
00930
00931 void MainWindow::computeLoadBenchmarkResults(const std::string &file)
00932 {
00933 std::string logid, basename, logid_text;
00934 try
00935 {
00936 logid = file.substr( file.find_last_of(".", file.length()-5) + 1, file.find_last_of(".") - file.find_last_of(".", file.length()-5) - 1 );
00937 basename = file.substr(0, file.find_last_of(".", file.length()-5));
00938 logid_text = logid.substr(logid.find_first_of("_"), logid.length() - logid.find_first_of("_"));
00939 }
00940 catch (...)
00941 {
00942 ROS_ERROR("Invalid benchmark log file. Cannot load results.");
00943 return;
00944 }
00945
00946 int count = 1;
00947 bool more_files = true;
00948
00949 while (more_files)
00950 {
00951 std::ifstream ifile;
00952 std::stringstream file_to_load;
00953 file_to_load << basename << "." << count << logid_text << ".log";
00954
00955 ifile.open(file_to_load.str().c_str());
00956 if (ifile.good())
00957 {
00958
00959 char text_line[512];
00960 static std::streamsize text_line_length = 512;
00961 bool valid_file = false;
00962 ifile.getline(text_line, text_line_length);
00963
00964
00965 if (ifile.good() && strstr(text_line, "Experiment") != NULL && strlen(text_line) > 11
00966 && strncmp(&text_line[11], scene_display_->getPlanningSceneRO()->getName().c_str(), scene_display_->getPlanningSceneRO()->getName().length()) == 0)
00967 {
00968 while (ifile.good())
00969 {
00970 if ( strstr(text_line, "total_time REAL") != NULL)
00971 {
00972 valid_file = true;
00973 break;
00974 }
00975
00976 ifile.getline(text_line, text_line_length);
00977 }
00978 }
00979 else
00980 {
00981 ROS_ERROR("Not a valid log file, or a different planning scene loaded");
00982 }
00983
00984 if (valid_file)
00985 {
00986 if (basename.find(".trajectory") != std::string::npos)
00987 {
00988
00989 int nwaypoint = 0;
00990 while (ifile.getline(text_line, text_line_length) && ifile.good() && strlen(text_line) > 6)
00991 {
00992
00993 try
00994 {
00995 bool reachable = boost::lexical_cast<bool>(text_line[0]);
00996 bool collision_free = boost::lexical_cast<bool>(text_line[3]);
00997
00998
00999
01000 if (count <= trajectories_.size())
01001 {
01002 std::string trajectory_name = ui_.trajectory_list->item(count-1)->text().toStdString();
01003 if ( nwaypoint < trajectories_[trajectory_name]->waypoint_markers.size() )
01004 {
01005 if (reachable)
01006 {
01007 if (collision_free)
01008 {
01009
01010 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateMarkerState, this, trajectories_[trajectory_name]->waypoint_markers[nwaypoint],
01011 GripperMarker::REACHABLE));
01012 }
01013 else
01014 {
01015
01016 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateMarkerState, this, trajectories_[trajectory_name]->waypoint_markers[nwaypoint],
01017 GripperMarker::IN_COLLISION));
01018 }
01019 }
01020 else
01021 {
01022
01023 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateMarkerState, this, trajectories_[trajectory_name]->waypoint_markers[nwaypoint],
01024 GripperMarker::NOT_REACHABLE));
01025 }
01026 }
01027 }
01028 nwaypoint++;
01029 }
01030 catch (...)
01031 {
01032 ROS_ERROR("Error parsing the log file");
01033 }
01034 }
01035 }
01036 else
01037 {
01038 ifile.getline(text_line, text_line_length);
01039 if (ifile.good() && strlen(text_line) > 6)
01040 {
01041
01042 try
01043 {
01044 bool reachable = boost::lexical_cast<bool>(text_line[0]);
01045 bool collision_free = boost::lexical_cast<bool>(text_line[3]);
01046
01047
01048 if (count <= goal_poses_.size())
01049 {
01050 std::string goal_name = ui_.goal_poses_list->item(count-1)->text().toStdString();
01051 if (reachable)
01052 {
01053 if (collision_free)
01054 {
01055
01056 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
01057 GripperMarker::REACHABLE));
01058 }
01059 else
01060 {
01061
01062 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
01063 GripperMarker::IN_COLLISION));
01064 }
01065 }
01066 else
01067 {
01068
01069 JobProcessing::addMainLoopJob(boost::bind(&MainWindow::updateGoalMarkerStateFromName, this, goal_name,
01070 GripperMarker::NOT_REACHABLE));
01071 }
01072 }
01073 }
01074 catch (...)
01075 {
01076 ROS_ERROR("Error parsing the log file");
01077 }
01078 }
01079 }
01080 }
01081 else
01082 {
01083 ROS_ERROR("Invalid benchmark log file. Cannot load results.");
01084 }
01085
01086 ifile.close();
01087 }
01088 else
01089 {
01090 more_files = false;
01091 }
01092 count++;
01093 }
01094 }
01095
01096 void MainWindow::updateGoalMarkerStateFromName(const std::string &name, const GripperMarker::GripperMarkerState &state)
01097 {
01098 if ( goal_poses_.find(name) != goal_poses_.end())
01099 goal_poses_[name]->setState(state);
01100 }
01101
01102 void MainWindow::updateMarkerState(GripperMarkerPtr marker, const GripperMarker::GripperMarkerState &state)
01103 {
01104 marker->setState(state);
01105 }
01106
01107 void MainWindow::goalOffsetChanged()
01108 {
01109 goal_offset_.setIdentity();
01110 goal_offset_ = Eigen::AngleAxisd(ui_.goal_offset_roll->value() * boost::math::constants::pi<double>() / 180.0, Eigen::Vector3d::UnitX()) *
01111 Eigen::AngleAxisd(ui_.goal_offset_pitch->value() * boost::math::constants::pi<double>() / 180.0, Eigen::Vector3d::UnitY()) *
01112 Eigen::AngleAxisd(ui_.goal_offset_yaw->value() * boost::math::constants::pi<double>() / 180.0, Eigen::Vector3d::UnitZ());
01113
01114 if ( ! robot_interaction_->getActiveEndEffectors().empty() )
01115 {
01116 Eigen::Affine3d current_pose;
01117 for (GoalPoseMap::iterator it = goal_poses_.begin(); it != goal_poses_.end(); ++it)
01118 {
01119 current_pose = goals_initial_pose_[it->first] * goal_offset_;
01120 it->second->setPose(current_pose);
01121 }
01122 }
01123 }
01124
01125 }