selection_widget.cpp
Go to the documentation of this file.
1 //
2 // Created by yijiangh on 6/27/17.
3 //
4 
5 #include <algorithm>
6 
7 #include <ros/console.h>
8 
9 #include <QListWidgetItem>
10 #include <QCheckBox>
11 
12 #include <ui_selection_widget.h>
14 
15 // service
16 #include <choreo_msgs/ElementNumberRequest.h>
17 #include <choreo_msgs/VisualizeSelectedPath.h>
18 #include <choreo_msgs/QueryComputationRecord.h>
19 
20 const static std::string ELEMENT_NUMBER_REQUEST_SERVICE = "element_member_request";
21 const static std::string VISUALIZE_SELECTED_PATH = "visualize_select_path";
22 const static std::string QUERY_COMPUTATION_RESULT = "query_computation_result";
23 
24 namespace {
25 
26 // TODO: whenever a new assembly type is added, this part should be extended accordingly.
27 void convertParsedAssemblyTypeString(const std::string& p_at, choreo_gui::SelectionWidget::ASSEMBLY_TYPE& at)
28 {
29  if("spatial_extrusion" == p_at)
30  {
31  at = choreo_gui::SelectionWidget::ASSEMBLY_TYPE::SPATIAL_EXTRUSION;
32  return;
33  }
34 
35  if("picknplace" == p_at)
36  {
37  at = choreo_gui::SelectionWidget::ASSEMBLY_TYPE::PICKNPLACE;
38  return;
39  }
40 
41  // only supports these two for now
42  // TODO: default value here for now
43  if(p_at.empty())
44  {
45  at = choreo_gui::SelectionWidget::ASSEMBLY_TYPE::SPATIAL_EXTRUSION;
46  }
47  else
48  {
49  assert(false);
50  }
51 // assert(p_at == "picknplace" || p_at == "spatial_extrusion");
52 }
53 
54 } // anon util namespace
55 
56 choreo_gui::SelectionWidget::SelectionWidget(QWidget* parent) : QWidget(parent),
57  mode_(PATH_SELECTION),
58  sim_type_(SIMULATE_TYPE::SINGLE),
59  selected_value_(0),
60  selected_grasp_id_(0),
61  visualize_ee_(false),
62  use_saved_result_(false)
63 {
64  // UI setup
65  ui_ = new Ui::SelectionWidgetWindow;
66  ui_->setupUi(this);
67 
68  this->setWindowFlags(Qt::WindowStaysOnTopHint);
69 
72 
73  this->select_for_plan_pop_up_->setWindowFlags(Qt::WindowStaysOnTopHint);
74  this->task_seq_recompute_pop_up_->setWindowFlags(Qt::WindowStaysOnTopHint);
75 
76  // wire in pop up widget signals
77  connect(select_for_plan_pop_up_, SIGNAL(buttonRecompute()), this, SLOT(recomputeChosen()));
78  connect(select_for_plan_pop_up_, SIGNAL(buttonKeepRecord()), this, SLOT(useSavedResultChosen()));
79 
80  // wire in pop up widget signals
81  connect(task_seq_recompute_pop_up_, SIGNAL(buttonRecompute()), this, SIGNAL(recomputeTaskSequenceChosen()));
82  connect(task_seq_recompute_pop_up_, SIGNAL(buttonKeepRecord()), this, SLOT(useSavedTaskSequenceResultChosen()));
83 // connect(task_seq_recompute_pop_up_, SIGNAL(exitSelectForPlanPopUpWidget()), this, SLOT(popUpWindowClosed()));
84 
85  // Wire in buttons
86  connect(ui_->pushbutton_select_backward, SIGNAL(clicked()), this, SLOT(buttonBackwardUpdateOrderValue()));
87  connect(ui_->pushbutton_select_forward, SIGNAL(clicked()), this, SLOT(buttonForwardUpdateOrderValue()));
88  connect(ui_->pushbutton_select_for_plan, SIGNAL(clicked()), this, SLOT(buttonSelectForPlan()));
89 
90  connect(ui_->pushbutton_select_all, SIGNAL(clicked()), this, SLOT(buttonSelectAll()));
91 
92  connect(ui_->pushbutton_simulate_single, SIGNAL(clicked()), this, SLOT(buttonSimulateSingle()));
93  connect(ui_->pushbutton_simulate_until, SIGNAL(clicked()), this, SLOT(buttonSimulateUntil()));
94  connect(ui_->pushbutton_simulate_chosen, SIGNAL(clicked()), this, SLOT(buttonSimulateChosen()));
95  connect(this, SIGNAL(simulateOn(SIMULATE_TYPE)), this, SLOT(buttonSimulate(SIMULATE_TYPE)));
96 
97  connect(ui_->pushbutton_clear_chosen, SIGNAL(clicked()), this, SLOT(buttonClearSelection()));
98  connect(ui_->pushbutton_set_output_save_dir, SIGNAL(clicked()), this, SIGNAL(setOutputSaveDirOn()));
99  connect(ui_->pushbutton_output_generate_chosen, SIGNAL(clicked()), this, SLOT(buttonOutputChosen()));
100 
101  connect(ui_->pushbutton_close_widget, SIGNAL(clicked()), this, SLOT(buttonCloseWidget()));
102 
103  // Wire in slider
104  connect(ui_->slider_select_number, SIGNAL(valueChanged(int)), this, SLOT(sliderUpdateOrderValue(int)));
105  connect(ui_->slider_select_grasp, SIGNAL(valueChanged(int)), this, SLOT(sliderUpdateSelectedGraspValue(int)));
106  connect(ui_->slider_sim_speed, SIGNAL(valueChanged(int)), this, SLOT(sliderUpdateSimSpeed(int)));
107 
108  // Wire in lineedit
109  connect(ui_->lineedit_select_number, SIGNAL(returnPressed()), this, SLOT(lineeditUpdateOrderValue()));
110  connect(ui_->lineedit_select_grasp, SIGNAL(returnPressed()), this, SLOT(lineeditUpdateSelectedGraspValue()));
111 
112  // Wire in checkbox
113  connect(ui_->checkbox_visualize_ee, SIGNAL(stateChanged(int)), this, SLOT(checkboxEEVisualUpdateValue()));
114 
115  // Start Service Client
116  // call core node for visualization request
118  nh_.serviceClient<choreo_msgs::VisualizeSelectedPath>(VISUALIZE_SELECTED_PATH);
119 
120  // call core node to fetch element number in (1) parsed assembly seq or (2) computed plans
122  nh_.serviceClient<choreo_msgs::QueryComputationRecord>(QUERY_COMPUTATION_RESULT);
123 }
124 
126 {
127  choreo_msgs::ElementNumberRequest srv;
128 
129  switch (mode_)
130  {
131  case PATH_SELECTION:
132  {
133  srv.request.action = choreo_msgs::ElementNumberRequest::Request::REQUEST_ELEMENT_NUMBER;
134  break;
135  }
136  case PLAN_SELECTION:
137  {
138  srv.request.action = choreo_msgs::ElementNumberRequest::Request::REQUEST_SELECTED_TASK_NUMBER;
139  break;
140  }
141  default:
142  {
143  ROS_ERROR_STREAM("Unknown element_number parameter loading request in selection widget");
144  break;
145  }
146  }
147 
148  ros::ServiceClient element_number_param_client =
149  nh_.serviceClient<choreo_msgs::ElementNumberRequest>(ELEMENT_NUMBER_REQUEST_SERVICE);
150 
151  setInputEnabled(false);
152 
153  element_number_param_client.waitForExistence();
154 
155  if (element_number_param_client.call(srv))
156  {
157  this->setMaxValue(srv.response.element_number);
158 
159  // fetch back grasp number for each assembly
160  grasp_nums_ = srv.response.grasp_nums;
161 
162 // ROS_INFO_STREAM("[Selection Widget] select path panel fetch model info successfully.");
163  }
164  else
165  {
166  ROS_ERROR_STREAM("[Selection Widget] Unable to fetch model's element number!");
167  }
168 
169  // reset display value
170  selected_value_ = 0;
171  ui_->slider_select_number->setValue(0);
172 
173  ui_->slider_sim_speed->setValue(1);
174 
175  ui_->lineedit_select_number->setText(QString::number(0));
176 
177  setInputEnabled(true);
178 
179  // trigger update visualization
181 }
182 
184 {
185  max_value_ = m - 1;
186 
187  ui_->slider_select_number->setMaximum(max_value_);
188  ui_->lineedit_select_number->setValidator(new QIntValidator(0, max_value_, this));
189  ui_->lineedit_max->setText(QString::number(max_value_));
190 }
191 
193 {
194  assert(m > 0);
195  max_grasp_num_ = m - 1;
196 
197  ui_->slider_select_grasp->setMaximum(max_grasp_num_);
198  ui_->lineedit_select_grasp->setValidator(new QIntValidator(0, max_grasp_num_, this));
199  ui_->lineedit_max_grasp_num->setText(QString::number(max_grasp_num_));
200 }
201 
203 {
204  // synchronize assembly seq slider and lineedit
205  ui_->slider_select_number->setValue(selected_value_);
206  ui_->lineedit_select_number->setText(QString::number(selected_value_));
207 
208  // synchronize grasp id slider and lineedit
210  {
211  assert(grasp_nums_.size() > selected_value_);
213  }
214 
215  //sync checkbox
216  ui_->checkbox_visualize_ee->setChecked(visualize_ee_);
217 
219  {
220  selected_grasp_id_ = 0;
221  }
222 
223  // synchronize grasp selection slider and lineedit
224  ui_->slider_select_grasp->setValue(selected_grasp_id_);
225  ui_->lineedit_select_grasp->setText(QString::number(selected_grasp_id_));
226 
227  // call visualization srv
228  choreo_msgs::VisualizeSelectedPath srv;
229 
230  // TODO: MAGIC SWITCH!!
231  // TODO: the assembly task type should be a part of model param
232  // TODO: hardcoded to picknplace for now
233  srv.request.assembly_type = srv.request.SPATIAL_EXTRUSION;
234 // srv.request.assembly_type = srv.request.PICKNPLACE;
235 
236  srv.request.index = selected_value_;
237  srv.request.visualize_ee = visualize_ee_;
238  srv.request.grasp_id = selected_grasp_id_;
239 
240 // if(PATH_SELECTION == mode_)
241 // {
242 //
243 // }
244 
245  if(PLAN_SELECTION == mode_)
246  {
247  ui_->plan_list_widget->clearSelection();
248 
249  std::vector<int> not_found_index;
250  std::vector<int>::iterator it;
251 
252  // update list widget selection, all until selected_value_
253  for(std::size_t i=0; i <= selected_value_; i++)
254  {
255  std::vector<int>::iterator it =
256  std::find(fetched_plan_ids_.begin(), fetched_plan_ids_.end(), i);
257 
258  if(it != fetched_plan_ids_.end())
259  {
260  ui_->plan_list_widget->item(it - fetched_plan_ids_.begin())->setSelected(true);
261  }
262  else
263  {
264  not_found_index.push_back(i);
265  }
266  }
267 
268  if(0 != not_found_index.size())
269  {
270  std::string error_msg = std::to_string(not_found_index.size()) + " plans not found";
271  ui_->status_bar->setStyleSheet("QLabel { color : red; }");
272  ui_->status_bar->setText(QString::fromStdString(error_msg));
273  }
274  }
275 
276  setInputEnabled(false);
277 
279  if (!visualize_client_.call(srv))
280  {
281  ROS_ERROR_STREAM("UI: Unable to visualize selected path!!");
282  }
283 
284  setInputEnabled(true);
285 }
286 
288 {
289  ui_->lineedit_sim_speed->setText(QString::number(sim_speed_));
290 }
291 
292 static int getIntFromString(const std::string &str)
293 {
294  std::string::size_type sz; // alias of size_t
295 
296  int i_dec = std::stoi(str, &sz);
297 
298  return i_dec;
299 }
300 
301 void choreo_gui::SelectionWidget::addFetchedPlans(const std::vector<std::string> &plan_names)
302 {
303  ui_->plan_list_widget->clear();
304  fetched_plan_ids_.clear();
305 
306  for (const auto& plan : plan_names)
307  {
308  // add it in fetched_plans for available plan database
309  fetched_plan_ids_.push_back(getIntFromString(plan));
310  }
311 
312  // sort fetched plans in an increasing order
313  std::sort(fetched_plan_ids_.begin(), fetched_plan_ids_.end());
314 
315  for (const auto& id : fetched_plan_ids_)
316  {
317  QListWidgetItem *item = new QListWidgetItem();
318  item->setText(QString::number(id));
319  ui_->plan_list_widget->addItem(item);
320  }
321 }
322 
324 {
325  chosen_ids_for_sim_.clear();
326 
327  QList<QListWidgetItem*> qt_chosen_items = ui_->plan_list_widget->selectedItems();
328 
329  for(auto q_item : qt_chosen_items)
330  {
331 // ROS_INFO_STREAM("chosen: " << q_item->text().toStdString());
332  chosen_ids_for_sim_.push_back(getIntFromString(q_item->text().toStdString()));
333  }
334 
335  // sort in increasing index order
336  std::sort(chosen_ids_for_sim_.begin(), chosen_ids_for_sim_.end());
337 }
338 
339 void choreo_gui::SelectionWidget::setStatusBar(std::string string, bool state)
340 {
341  if(state)
342  {
343  ui_->status_bar->setStyleSheet("QLabel { color : green; }");
344  }
345  else
346  {
347  ui_->status_bar->setStyleSheet("QLabel { color : red; }");
348  }
349 
350  ui_->status_bar->setText(QString::fromStdString(string));
351  setInputEnabled(true);
352 }
353 
355 {
356  // call visualization srv
357  choreo_msgs::VisualizeSelectedPath srv;
358  srv.request.index = -1;
359 
361  if (!visualize_client_.call(srv))
362  {
363  ROS_ERROR_STREAM("Unable to clean up selected path!!");
364  }
365 }
366 
368 {
369  convertParsedAssemblyTypeString(at, assembly_type_);
370 }
371 
373 {
375  {
376  if (found_task_plan)
377  {
378  std::string msg = "Saved task sequence plan record found.";
380  }
381  else
382  {
383  ROS_WARN_STREAM("[UI] No saved task sequence plan found.");
384 
385  std::string msg = "No saved task sequence plan record found.";
387  }
388 
389  task_seq_recompute_pop_up_->enableButtons(found_task_plan);
390  }
391 
392  // TODO: currently we don't support task sequence planning for picknplace with arbitrary geometry
393  // This should be removed later
395  {
396  std::string msg = "Currently we don't support sequence planning for general picknplace.";
398 
399  task_seq_recompute_pop_up_->enableButtons(found_task_plan, false);
400  }
401 
403 }
404 
406 {
407  Q_EMIT enterSelectionWidget();
408 }
409 
411 {
412  Q_EMIT exitSelectionWidget();
413 }
414 
416 {
417  if(mode_ == PATH_SELECTION)
418  {
419  ui_->pushbutton_select_backward->setEnabled(enabled);
420  ui_->pushbutton_select_forward->setEnabled(enabled);
421  ui_->slider_select_number->setEnabled(enabled);
422  ui_->lineedit_select_number->setEnabled(enabled);
423 
424  ui_->pushbutton_select_for_plan->setEnabled(enabled);
425  ui_->pushbutton_select_all->setEnabled(enabled);
426  ui_->pushbutton_simulate_single->setEnabled(false);
427  ui_->pushbutton_simulate_until->setEnabled(false);
428 
430  setInputGraspEnabled(enabled);
431 
432  // TODO: to be implemented
434 
435  ui_->pushbutton_close_widget->setEnabled(false);
436 
437  // set tab_widget to <grasp visualizer> and disable <traj lib> tab
438  ui_->tab_widget->setEnabled(enabled);
439  ui_->tab_widget->setTabEnabled(0, enabled);
440  ui_->tab_widget->setTabEnabled(1, false);
441  ui_->tab_widget->setCurrentIndex(0);
442  }
443 
444  if(mode_ == ZOOM_IN_SELECTION)
445  {
446  enabled = false;
447 
448  ui_->pushbutton_select_backward->setEnabled(enabled);
449  ui_->pushbutton_select_forward->setEnabled(enabled);
450  ui_->slider_select_number->setEnabled(enabled);
451  ui_->lineedit_select_number->setEnabled(enabled);
452 
453  ui_->pushbutton_select_for_plan->setEnabled(false);
454  ui_->pushbutton_select_all->setEnabled(false);
455  ui_->pushbutton_simulate_single->setEnabled(false);
456  ui_->pushbutton_simulate_until->setEnabled(false);
457 
459  setInputGraspEnabled(enabled);
460  setInputIKSolutionEnabled(enabled);
461 
462  ui_->pushbutton_close_widget->setEnabled(false);
463 
464  ui_->tab_widget->setEnabled(enabled);
465  ui_->tab_widget->setTabEnabled(0, enabled);
466  ui_->tab_widget->setTabEnabled(1, false);
467  ui_->tab_widget->setCurrentIndex(0);
468  }
469 
470  if(mode_ == PLAN_SELECTION)
471  {
472  ui_->pushbutton_select_backward->setEnabled(enabled);
473  ui_->pushbutton_select_forward->setEnabled(enabled);
474  ui_->slider_select_number->setEnabled(enabled);
475  ui_->lineedit_select_number->setEnabled(enabled);
476 
477  ui_->pushbutton_select_for_plan->setEnabled(false);
478  ui_->pushbutton_select_all->setEnabled(enabled);
479  ui_->pushbutton_simulate_single->setEnabled(enabled);
480  ui_->pushbutton_simulate_until->setEnabled(enabled);
481 
482  setInputGraspEnabled(false);
484 
485  ui_->pushbutton_close_widget->setEnabled(true);
486 
487  ui_->tab_widget->setEnabled(enabled);
488  ui_->tab_widget->setTabEnabled(0, false);
489  ui_->tab_widget->setTabEnabled(1, true);
490  ui_->tab_widget->setCurrentIndex(1);
491  }
492 }
493 
495 {
496  ui_->checkbox_visualize_ee->setEnabled(enabled);
497 }
498 
500 {
501  ui_->slider_select_grasp->setEnabled(enabled);
502  ui_->lineedit_select_grasp->setEnabled(enabled);
503 }
504 
506 {
507  ui_->slider_select_ik_solution->setEnabled(enabled);
508  ui_->lineedit_select_ik_solution->setEnabled(enabled);
509 }
510 
512 {
513  if((selected_value_+1) <= max_value_)
514  {
515  selected_value_++;
517  }
518 }
519 
521 {
522  if((selected_value_-1) >= 0)
523  {
524  selected_value_--;
526  }
527 }
528 
530 {
533 
534 // Q_EMIT acceptSelection();
535 }
536 
538 {
539  // update internal simulate type
540  sim_type_ = sim_type;
541  selected_ids_for_sim_.clear();
542 
543  // update selected_ids for simulation
544  switch (sim_type_)
545  {
546  case SIMULATE_TYPE::SINGLE:
547  {
549 
550 
551  break;
552  }
553  case SIMULATE_TYPE::ALL_UNTIL:
554  {
555  for(int i = 0; i <= selected_value_; i++)
556  {
557  selected_ids_for_sim_.push_back(i);
558  }
559 
560  break;
561  }
562  case SIMULATE_TYPE::CHOSEN:
563  {
564  getChosenPlans();
566 
567  if(0 == selected_ids_for_sim_.size())
568  {
569  ROS_WARN("No ids is chosen!");
570  return;
571  }
572 
574 
575  break;
576  }
577  }
578 
579  // wait for simulation to be completed
580  setInputEnabled(false);
581  Q_EMIT flushSimulation();
582 }
583 
585 {
586  getChosenPlans();
587  Q_EMIT flushOutputProcess();
588 }
589 
591 {
592  ui_->plan_list_widget->clearSelection();
593 }
594 
596 {
597  Q_EMIT simulateOn(SIMULATE_TYPE::SINGLE);
598 }
599 
601 {
602  Q_EMIT simulateOn(SIMULATE_TYPE::ALL_UNTIL);
603 }
604 
606 {
607  Q_EMIT simulateOn(SIMULATE_TYPE::CHOSEN);
608 }
609 
611 {
612  this->close();
613 }
614 
616 {
617  setInputEnabled(false);
618 
619  choreo_msgs::QueryComputationRecord srv;
620  bool saved_record_found = false;
621 
622  srv.request.action = choreo_msgs::QueryComputationRecordRequest::SAVED_LADDER_GRAPH;
623  srv.request.file_name = model_file_name_;
624 
626 
628  {
629 // ROS_INFO_STREAM("[Selection Widget] select path panel fetch saved ladder graph info successfully.");
630 
631  saved_record_found = srv.response.record_found;
632  const int found_record_size = srv.response.found_record_size;
633 
634  // set pop up widget text
635  if(saved_record_found && found_record_size > 0)
636  {
637  std::string msg = "Previous ladder graph record found: 0 - " + std::to_string(found_record_size-1);
639  }
640  else
641  {
642  ROS_WARN_STREAM("[UI] No previous ladder graph record found.");
643 
644  std::string msg = "No previous ladder graph record found.";
646  }
647  }
648  else
649  {
650  std::string msg = "Unable to fetch model's element number.";
652  saved_record_found = false;
653  }
654 
655  select_for_plan_pop_up_->enableButtons(saved_record_found);
656  select_for_plan_pop_up_->show();
657 
659  setInputEnabled(true);
660 }
661 
663 {
664  selected_value_ = value;
666 }
667 
669 {
670  selected_value_ = ui_->lineedit_select_number->text().toInt();
672 }
673 
675 {
676  visualize_ee_ = ui_->checkbox_visualize_ee->isChecked();
678 }
679 
681 {
682  selected_grasp_id_ = value;
684 }
685 
687 {
688  selected_value_ = ui_->lineedit_select_grasp->text().toInt();
690 }
691 
693 {
694  // TODO: finish this
695  // discretization of slider is set in qt ui file
696  sim_speed_ = (double) value / 100;
697  simSpeedChanged();
698 }
699 
701 {
702  use_saved_result_ = false;
703  this->close();
704 
705  Q_EMIT closeWidgetAndContinue();
706 }
707 
709 {
710  use_saved_result_ = true;
711  this->close();
712 
713  Q_EMIT closeWidgetAndContinue();
714 }
715 
717 {
718  Q_EMIT closeWidgetAndContinue();
719 }
720 
722 {
723  Q_EMIT enableChoreoWidgetButtons();
724 }
void setMode(const MODE &_mode)
ServiceClient serviceClient(const std::string &service_name, bool persistent=false, const M_string &header_values=M_string())
ros::ServiceClient visualize_client_
Ui::SelectionWidgetWindow * ui_
void addFetchedPlans(const std::vector< std::string > &plan_names)
std::vector< int > grasp_nums_
SelectionWidget(QWidget *parent=0)
static const std::string ELEMENT_NUMBER_REQUEST_SERVICE
virtual void closeEvent(QCloseEvent *ev)
void sliderUpdateOrderValue(int value)
bool call(MReq &req, MRes &res)
#define ROS_WARN(...)
void showTaskSequenceRecomputePopUp(bool found_task_plan)
void enableButtons(bool record_found, bool enable_recompute=true)
void buttonSimulate(SIMULATE_TYPE sim_type)
bool waitForExistence(ros::Duration timeout=ros::Duration(-1))
void sliderUpdateSelectedGraspValue(int value)
virtual void showEvent(QShowEvent *ev)
#define ROS_WARN_STREAM(args)
void setAssemblyType(const std::string &at)
std::vector< int > fetched_plan_ids_
void setInputEnabled(bool enabled)
void simulateOn(SIMULATE_TYPE sim_type)
static const std::string QUERY_COMPUTATION_RESULT
void setStatusBar(std::string string, bool state)
#define ROS_ERROR_STREAM(args)
SelectForPlanPopUpWidget * task_seq_recompute_pop_up_
std::vector< int > chosen_ids_for_sim_
static const std::string VISUALIZE_SELECTED_PATH
SelectForPlanPopUpWidget * select_for_plan_pop_up_
static int getIntFromString(const std::string &str)
std::vector< int > selected_ids_for_sim_
ros::ServiceClient query_computation_record_client_


choreo_gui
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:58:56