moveit2
The MoveIt Motion Planning Framework for ROS 2.
motion_planning_frame_joints_widget.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, CITEC, Bielefeld University
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of CITEC / Bielefeld University nor the names of
18  * its contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Robert Haschke */
36 
39 
40 #include "ui_motion_planning_rviz_plugin_frame_joints.h"
41 #include <QPainter>
42 #include <QSlider>
43 #include <QEvent>
44 #include <QMouseEvent>
45 
46 namespace moveit_rviz_plugin
47 {
48 static const rclcpp::Logger LOGGER = rclcpp::get_logger("moveit_ros_visualization.motion_planning_frame_joints_widget");
49 
50 JMGItemModel::JMGItemModel(const moveit::core::RobotState& robot_state, const std::string& group_name, QObject* parent)
51  : QAbstractTableModel(parent), robot_state_(robot_state), jmg_(nullptr)
52 {
53  if (robot_state_.getRobotModel()->hasJointModelGroup(group_name))
54  jmg_ = robot_state_.getRobotModel()->getJointModelGroup(group_name);
55 }
56 
57 int JMGItemModel::rowCount(const QModelIndex& /*parent*/) const
58 {
59  if (!jmg_)
60  return robot_state_.getVariableCount();
61  else
62  return jmg_->getVariableCount();
63 }
64 
65 int JMGItemModel::columnCount(const QModelIndex& /*parent*/) const
66 {
67  return 2;
68 }
69 
70 Qt::ItemFlags JMGItemModel::flags(const QModelIndex& index) const
71 {
72  if (!index.isValid())
73  return Qt::ItemFlags();
74 
75  Qt::ItemFlags f = QAbstractTableModel::flags(index);
76 
77  const moveit::core::JointModel* jm = getJointModel(index);
78  bool is_editable = !jm->isPassive() && !jm->getMimic();
79  f.setFlag(Qt::ItemIsEnabled, is_editable);
80  if (index.column() == 1)
81  f.setFlag(Qt::ItemIsEditable, is_editable);
82  return f;
83 }
84 
85 QVariant JMGItemModel::data(const QModelIndex& index, int role) const
86 {
87  if (!index.isValid())
88  return QVariant();
89 
90  int idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
91  switch (index.column())
92  {
93  case 0: // joint name column
94  switch (role)
95  {
96  case Qt::DisplayRole:
97  return QString::fromStdString(robot_state_.getVariableNames()[idx]);
98  case Qt::TextAlignmentRole:
99  return Qt::AlignLeft;
100  }
101  break;
102  case 1: // joint value column
103  {
104  double value = robot_state_.getVariablePosition(idx);
105  const moveit::core::JointModel* jm = robot_state_.getRobotModel()->getJointOfVariable(idx);
106  switch (role)
107  {
108  case Qt::DisplayRole:
109  return value;
110  case Qt::EditRole:
111  if (jm)
112  return jm->getType() == moveit::core::JointModel::REVOLUTE ? value * 180 / M_PI : value;
113  break;
115  if (jm)
116  return jm->getType();
117  break;
119  if (const moveit::core::VariableBounds* bounds = getVariableBounds(jm, index))
120  return QPointF(bounds->min_position_, bounds->max_position_);
121  break;
122  case Qt::TextAlignmentRole:
123  return Qt::AlignLeft;
124  }
125  }
126  }
127  return QVariant();
128 }
129 
130 QVariant JMGItemModel::headerData(int section, Qt::Orientation orientation, int role) const
131 {
132  if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
133  return section == 0 ? "Joint Name" : "Value";
134  return QAbstractTableModel::headerData(section, orientation, role);
135 }
136 
137 bool JMGItemModel::setData(const QModelIndex& index, const QVariant& value, int role)
138 {
139  if (index.column() != 1 || role != Qt::EditRole)
140  return false;
141 
142  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
143  const moveit::core::JointModel* jm = robot_state_.getRobotModel()->getJointOfVariable(var_idx);
144  if (!value.canConvert<double>())
145  return false;
146 
147  bool ok;
148  double v = value.toDouble(&ok);
149  if (!ok)
150  return false;
151 
152  // for revolute joints, we convert degrees to radians
153  if (jm && jm->getType() == moveit::core::JointModel::REVOLUTE)
154  v *= M_PI / 180;
155 
156  robot_state_.setVariablePosition(var_idx, v);
158  dataChanged(index, index);
159  return true;
160 }
161 
162 const moveit::core::JointModel* JMGItemModel::getJointModel(const QModelIndex& index) const
163 {
164  if (!index.isValid())
165  return nullptr;
166  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
167  return robot_state_.getRobotModel()->getJointOfVariable(var_idx);
168 }
169 
170 const moveit::core::VariableBounds* JMGItemModel::getVariableBounds(const moveit::core::JointModel* jm,
171  const QModelIndex& index) const
172 {
173  if (!jm)
174  return nullptr;
175  int var_idx = jmg_ ? jmg_->getVariableIndexList()[index.row()] : index.row();
176  const moveit::core::VariableBounds* bounds = &jm->getVariableBounds()[var_idx - jm->getFirstVariableIndex()];
177  return bounds->position_bounded_ ? bounds : nullptr;
178 }
179 
180 // copy positions from new_state and notify about these changes
182 {
183  if (robot_state_.getRobotModel() != state.getRobotModel())
184  return;
185  robot_state_.setVariablePositions(state.getVariablePositions());
186 
187  dataChanged(index(0, 1), index(rowCount() - 1, 1));
188 }
189 
191  : QWidget(parent), ui_(new Ui::MotionPlanningFrameJointsUI()), planning_display_(display)
192 {
193  ui_->setupUi(this);
194  // intercept mouse events delivered to joints_view_ to open editor on first mouse press
195  ui_->joints_view_->viewport()->installEventFilter(new JointsWidgetEventFilter(ui_->joints_view_));
196  ui_->joints_view_->setItemDelegateForColumn(1, new ProgressBarDelegate(this));
197  svd_.setThreshold(0.001);
198 }
199 
201 {
202  delete ui_;
203 }
204 
206 {
207  ui_->joints_view_->setModel(nullptr);
208  start_state_handler_.reset();
209  goal_state_handler_.reset();
210  start_state_model_.reset();
211  goal_state_model_.reset();
212 }
213 
215  const std::string& group_name, const robot_interaction::InteractionHandlerPtr& start_state_handler,
216  const robot_interaction::InteractionHandlerPtr& goal_state_handler)
217 {
218  // release previous models (if any)
219  clearRobotModel();
220  // create new models
221  start_state_handler_ = start_state_handler;
222  goal_state_handler_ = goal_state_handler;
223  start_state_model_ = std::make_unique<JMGItemModel>(*start_state_handler_->getState(), group_name, this);
224  goal_state_model_ = std::make_unique<JMGItemModel>(*goal_state_handler_->getState(), group_name, this);
225 
226  // forward model updates to the PlanningDisplay
227  connect(start_state_model_.get(), &JMGItemModel::dataChanged, this, [this]() {
228  if (!ignore_state_changes_)
229  planning_display_->setQueryStartState(start_state_model_->getRobotState());
230  });
231  connect(goal_state_model_.get(), &JMGItemModel::dataChanged, this, [this]() {
232  if (!ignore_state_changes_)
233  planning_display_->setQueryGoalState(goal_state_model_->getRobotState());
234  });
235 
236  // show the goal state by default
237  setActiveModel(goal_state_model_.get());
239 }
240 
242 {
243  if (!start_state_model_ || !start_state_handler_)
244  return;
245  ignore_state_changes_ = true;
246  start_state_model_->updateRobotState(*start_state_handler_->getState());
247  ignore_state_changes_ = false;
248  setActiveModel(start_state_model_.get());
250 }
251 
253 {
254  if (!goal_state_model_ || !goal_state_handler_)
255  return;
256  ignore_state_changes_ = true;
257  goal_state_model_->updateRobotState(*goal_state_handler_->getState());
258  ignore_state_changes_ = false;
259  setActiveModel(goal_state_model_.get());
261 }
262 
264 {
265  ui_->joints_view_->setModel(model);
266  ui_->joints_view_label_->setText(
267  QString("Group joints of %1 state").arg(model == start_state_model_.get() ? "start" : "goal"));
268 }
269 
271 {
272  if (model == start_state_model_.get())
273  planning_display_->setQueryStartState(model->getRobotState());
274  else
275  planning_display_->setQueryGoalState(model->getRobotState());
276 }
277 
278 // Find matching key vector in columns of haystack and return the best-aligned column index.
279 // Only consider available indexes (> 0). If no match is found, return largest available index.
280 // sign becomes -1 if key has changed sign compared to the matching haystack column.
281 static Eigen::Index findMatching(const Eigen::VectorXd& key, const Eigen::MatrixXd& haystack,
282  const Eigen::VectorXi& available, double& sign)
283 {
284  Eigen::Index result = available.array().maxCoeff();
285  double best_match = 0.0;
286  for (unsigned int i = 0; i < available.rows(); ++i)
287  {
288  int index = available[i];
289  if (index < 0) // index already taken
290  continue;
291  if (index >= haystack.cols())
292  return result;
293  double match = haystack.col(available[i]).transpose() * key;
294  double abs_match = std::abs(match);
295  if (abs_match > 0.5 && abs_match > best_match)
296  {
297  best_match = abs_match;
298  result = index;
299  sign = match > 0 ? 1.0 : -1.0;
300  }
301  }
302  return result;
303 }
304 
306 {
307  JMGItemModel* model = dynamic_cast<JMGItemModel*>(ui_->joints_view_->model());
308  std::size_t i = 0;
309  if (model && model->getJointModelGroup() && model->getJointModelGroup()->isChain())
310  {
312  Eigen::MatrixXd jacobian;
313  if (!model->getRobotState().getJacobian(model->getJointModelGroup(),
314  model->getJointModelGroup()->getLinkModels().back(),
315  Eigen::Vector3d::Zero(), jacobian, false))
316  goto cleanup;
317 
318  svd_.compute(jacobian, Eigen::ComputeFullV);
319  Eigen::Index rank = svd_.rank();
320  std::size_t ns_dim = svd_.cols() - rank;
321  Eigen::MatrixXd ns(svd_.cols(), ns_dim);
322  Eigen::VectorXi available(ns_dim);
323  for (std::size_t j = 0; j < ns_dim; ++j)
324  available[j] = j;
325 
326  ns_sliders_.reserve(ns_dim);
327  // create/unhide sliders
328  for (; i < ns_dim; ++i)
329  {
330  if (i >= ns_sliders_.size())
331  ns_sliders_.push_back(createNSSlider(i + 1));
332  ns_sliders_[i]->show();
333 
334  // Find matching null-space basis vector in previous nullspace_
335  double sign = 1.0;
336  const Eigen::VectorXd& current = svd_.matrixV().col(rank + i);
337  Eigen::Index index = findMatching(current, nullspace_, available, sign);
338  ns.col(index).noalias() = sign * current;
339  available[index] = -1; // mark index as taken
340  }
341  nullspace_ = ns;
342  }
343 
344 cleanup:
345  if (i == 0)
346  nullspace_.resize(0, 0);
347 
348  // show/hide dummy slider
349  ui_->dummy_ns_slider_->setVisible(i == 0);
350 
351  // hide remaining sliders
352  for (; i < ns_sliders_.size(); ++i)
353  ns_sliders_[i]->hide();
354 }
355 
357 {
358  JogSlider* slider = new JogSlider(this);
359  slider->setOrientation(Qt::Horizontal);
360  slider->setMaximum(0.1);
361  slider->setToolTip(QString("Nullspace dim #%1").arg(i));
362  ui_->nullspace_layout_->addWidget(slider);
363  connect(slider, SIGNAL(triggered(double)), this, SLOT(jogNullspace(double)));
364  return slider;
365 }
366 
368 {
369  if (value == 0)
370  return;
371 
372  std::size_t index = std::find(ns_sliders_.begin(), ns_sliders_.end(), sender()) - ns_sliders_.begin();
373  if (static_cast<int>(index) >= nullspace_.cols())
374  return;
375 
376  JMGItemModel* model = dynamic_cast<JMGItemModel*>(ui_->joints_view_->model());
377  if (!model)
378  return;
379 
380  Eigen::VectorXd values;
381  model->getRobotState().copyJointGroupPositions(model->getJointModelGroup(), values);
382  values += value * nullspace_.col(index);
383  model->getRobotState().setJointGroupPositions(model->getJointModelGroup(), values);
385  triggerUpdate(model);
386 }
387 
388 void ProgressBarDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
389 {
390  // copied from QStyledItemDelegate::paint
391  QStyle* style = option.widget ? option.widget->style() : QApplication::style();
392  QStyleOptionViewItem style_option = option;
393  initStyleOption(&style_option, index);
394 
395  if (index.column() == 1)
396  {
397  QVariant joint_type = index.data(JointTypeRole);
398  double value = index.data().toDouble();
399  if (joint_type.isValid())
400  {
401  switch (joint_type.toInt())
402  {
404  style_option.text = option.locale.toString(value * 180 / M_PI, 'f', 0).append("°");
405  break;
407  style_option.text = option.locale.toString(value, 'f', 3).append("m");
408  break;
409  default:
410  break;
411  }
412  }
413 
414  QVariant vbounds = index.data(VariableBoundsRole);
415  if (vbounds.isValid())
416  {
417  QPointF bounds = vbounds.toPointF();
418  const float min = bounds.x();
419  const float max = bounds.y();
420 
421  QStyleOptionProgressBar opt;
422  opt.rect = option.rect;
423  opt.minimum = 0;
424  opt.maximum = 1000;
425  opt.progress = 1000. * (value - min) / (max - min);
426  opt.text = style_option.text;
427  opt.textAlignment = style_option.displayAlignment;
428  opt.textVisible = true;
429  style->drawControl(QStyle::CE_ProgressBar, &opt, painter);
430  return;
431  }
432  }
433 
434  style->drawControl(QStyle::CE_ItemViewItem, &style_option, painter, option.widget);
435 }
436 
437 QWidget* ProgressBarDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option,
438  const QModelIndex& index) const
439 
440 {
441  if (index.column() == 1)
442  {
443  QVariant vbounds = index.data(VariableBoundsRole);
444  if (vbounds.isValid())
445  {
446  QPointF bounds = vbounds.toPointF();
447  float min = bounds.x();
448  float max = bounds.y();
449  bool is_revolute = (index.data(JointTypeRole).toInt() == moveit::core::JointModel::REVOLUTE);
450  if (is_revolute)
451  {
452  min *= 180. / M_PI;
453  max *= 180. / M_PI;
454  }
455  auto* editor = new ProgressBarEditor(parent, min, max, is_revolute ? 0 : 3);
456  connect(editor, &ProgressBarEditor::editingFinished, this, &ProgressBarDelegate::commitAndCloseEditor);
457  connect(editor, &ProgressBarEditor::valueChanged, this, [=](float value) {
458  const_cast<QAbstractItemModel*>(index.model())->setData(index, value, Qt::EditRole);
459  });
460  return editor;
461  }
462  }
463  return QStyledItemDelegate::createEditor(parent, option, index);
464 }
465 
466 void ProgressBarDelegate::commitAndCloseEditor()
467 {
468  ProgressBarEditor* editor = qobject_cast<ProgressBarEditor*>(sender());
469  commitData(editor);
470  closeEditor(editor);
471 }
472 
474 {
475 }
476 
477 bool JointsWidgetEventFilter::eventFilter(QObject* /*target*/, QEvent* event)
478 {
479  if (event->type() == QEvent::MouseButtonPress)
480  {
481  QAbstractItemView* view = qobject_cast<QAbstractItemView*>(parent());
482  QModelIndex index = view->indexAt(static_cast<QMouseEvent*>(event)->pos());
483  if (index.flags() & Qt::ItemIsEditable) // mouse event on any editable slider?
484  {
485  view->setCurrentIndex(index);
486  view->edit(index);
487  return true; // event handled
488  }
489  }
490  return false;
491 }
492 
493 ProgressBarEditor::ProgressBarEditor(QWidget* parent, float min, float max, int digits)
494  : QWidget(parent), min_(min), max_(max), digits_(digits)
495 {
496  // if left mouse button is pressed, grab all future mouse events until button(s) released
497  if (QApplication::mouseButtons() & Qt::LeftButton)
498  this->grabMouse();
499 }
500 
501 void ProgressBarEditor::paintEvent(QPaintEvent* /*event*/)
502 {
503  QPainter painter(this);
504 
505  QStyleOptionProgressBar opt;
506  opt.rect = rect();
507  opt.palette = this->palette();
508  opt.minimum = 0;
509  opt.maximum = 1000;
510  opt.progress = 1000. * (value_ - min_) / (max_ - min_);
511  opt.text = QLocale().toString(value_, 'f', digits_);
512  opt.textAlignment = Qt::AlignRight;
513  opt.textVisible = true;
514  style()->drawControl(QStyle::CE_ProgressBar, &opt, &painter);
515 }
516 
517 void ProgressBarEditor::mousePressEvent(QMouseEvent* event)
518 {
519  if (event->button() == Qt::LeftButton)
520  mouseMoveEvent(event);
521 }
522 
523 void ProgressBarEditor::mouseMoveEvent(QMouseEvent* event)
524 {
525  float v = std::min(max_, std::max(min_, min_ + event->x() * (max_ - min_) / width()));
526  if (value_ != v)
527  {
528  value_ = v;
529  valueChanged(v);
530  update();
531  }
532  event->accept();
533 }
534 
535 void ProgressBarEditor::mouseReleaseEvent(QMouseEvent* event)
536 {
537  if (event->button() == Qt::LeftButton)
538  {
539  event->accept();
540  editingFinished();
541  }
542 }
543 
544 JogSlider::JogSlider(QWidget* parent) : QSlider(parent)
545 {
546  setTimerInterval(50);
547  setResolution(1000);
548  setMaximum(1.0);
549 }
550 
552 {
553  timer_interval_ = ms;
554 }
555 
556 void JogSlider::setResolution(unsigned int resolution)
557 {
558  QSlider::setRange(-resolution, +resolution);
559 }
560 
561 void JogSlider::setMaximum(double value)
562 {
563  maximum_ = value;
564 }
565 
566 void JogSlider::timerEvent(QTimerEvent* event)
567 {
568  QSlider::timerEvent(event);
569  if (event->timerId() == timer_id_)
570  triggered(value());
571 }
572 
573 void JogSlider::mousePressEvent(QMouseEvent* event)
574 {
575  QSlider::mousePressEvent(event);
576  timer_id_ = startTimer(timer_interval_);
577 }
578 
579 void JogSlider::mouseReleaseEvent(QMouseEvent* event)
580 {
581  killTimer(timer_id_);
582  QSlider::mouseReleaseEvent(event);
583  setValue(0);
584 }
585 
586 } // namespace moveit_rviz_plugin
bool isChain() const
Check if this group is a linear chain.
const std::vector< const LinkModel * > & getLinkModels() const
Get the links that are part of this joint group.
unsigned int getVariableCount() const
Get the number of variables that describe this joint group. This includes variables necessary for mim...
const std::vector< int > & getVariableIndexList() const
Get the index locations in the complete robot state for all the variables in this group.
A joint from the robot. Models the transform that this joint applies in the kinematic chain....
Definition: joint_model.h:117
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
Definition: joint_model.h:216
bool isPassive() const
Check if this joint is passive.
Definition: joint_model.h:422
bool enforcePositionBounds(double *values) const
Force the specified values to be inside bounds and normalized. Quaternions are normalized,...
Definition: joint_model.h:292
const VariableBounds & getVariableBounds(const std::string &variable) const
Get the bounds for a variable. Throw an exception if the variable was not found.
JointType getType() const
Get the type of joint.
Definition: joint_model.h:151
const JointModel * getMimic() const
Get the joint this one is mimicking.
Definition: joint_model.h:372
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void setVariablePositions(const double *position)
It is assumed positions is an array containing the new positions for all variables in this state....
bool getJacobian(const JointModelGroup *group, const LinkModel *link, const Eigen::Vector3d &reference_point_position, Eigen::MatrixXd &jacobian, bool use_quaternion_representation=false) const
Compute the Jacobian with reference to a particular point on a given link, for a specified group.
void setVariablePosition(const std::string &variable, double value)
Set the position of a single variable. An exception is thrown if the variable name is not known.
Definition: robot_state.h:188
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
Given positions for the variables that make up a group, in the order found in the group (including va...
Definition: robot_state.h:605
void copyJointGroupPositions(const std::string &joint_group_name, std::vector< double > &gstate) const
For a given group, copy the position values of the variables that make up the group into another loca...
Definition: robot_state.h:691
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
Definition: robot_state.h:104
void harmonizePositions()
Call harmonizePosition() for all joints / all joints in group / given joint.
double * getVariablePositions()
Get a raw pointer to the positions of the variables stored in this state. Use carefully....
Definition: robot_state.h:147
void updateLinkTransforms()
Update the reference frame transforms for links. This call is needed before using the transforms of l...
double getVariablePosition(const std::string &variable) const
Get the position of a particular variable. An exception is thrown if the variable is not known.
Definition: robot_state.h:207
std::size_t getVariableCount() const
Get the number of variables that make up this state.
Definition: robot_state.h:110
const std::vector< std::string > & getVariableNames() const
Get the names of the variables that make up this state, in the order they are stored in memory.
Definition: robot_state.h:116
int columnCount(const QModelIndex &parent=QModelIndex()) const override
JMGItemModel(const moveit::core::RobotState &robot_state, const std::string &group_name, QObject *parent=nullptr)
Qt::ItemFlags flags(const QModelIndex &index) const override
QVariant data(const QModelIndex &index, int role) const override
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
const moveit::core::JointModelGroup * getJointModelGroup() const
void updateRobotState(const moveit::core::RobotState &state)
call this on any external change of the RobotState
int rowCount(const QModelIndex &parent=QModelIndex()) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
void triggered(double value)
void mousePressEvent(QMouseEvent *event) override
void mouseReleaseEvent(QMouseEvent *event) override
void timerEvent(QTimerEvent *event) override
bool eventFilter(QObject *target, QEvent *event) override
void setQueryGoalState(const moveit::core::RobotState &goal)
void setQueryStartState(const moveit::core::RobotState &start)
void changePlanningGroup(const std::string &group_name, const robot_interaction::InteractionHandlerPtr &start_state_handler, const robot_interaction::InteractionHandlerPtr &goal_state_handler)
MotionPlanningFrameJointsWidget(const MotionPlanningFrameJointsWidget &)=delete
Delegate to show the joint value as with a progress bar indicator between min and max.
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Number editor via progress bar dragging.
ProgressBarEditor(QWidget *parent=nullptr, float min=-1.0, float max=0.0, int digits=0)
Create a progressbar-like slider for editing values in range mix..max.
const rclcpp::Logger LOGGER
Definition: async_test.h:31