40 #include "ui_motion_planning_rviz_plugin_frame_joints.h" 
   44 #include <QMouseEvent> 
   48 static const rclcpp::Logger 
LOGGER = rclcpp::get_logger(
"moveit_ros_visualization.motion_planning_frame_joints_widget");
 
   51   : QAbstractTableModel(parent), robot_state_(robot_state), jmg_(nullptr)
 
   53   if (robot_state_.
getRobotModel()->hasJointModelGroup(group_name))
 
   54     jmg_ = robot_state_.
getRobotModel()->getJointModelGroup(group_name);
 
   73     return Qt::ItemFlags();
 
   75   Qt::ItemFlags 
f = QAbstractTableModel::flags(index);
 
   79   f.setFlag(Qt::ItemIsEnabled, is_editable);
 
   80   if (index.column() == 1)
 
   81     f.setFlag(Qt::ItemIsEditable, is_editable);
 
   91   switch (index.column())
 
   98         case Qt::TextAlignmentRole:
 
  108         case Qt::DisplayRole:
 
  120             return QPointF(bounds->min_position_, bounds->max_position_);
 
  122         case Qt::TextAlignmentRole:
 
  123           return Qt::AlignLeft;
 
  132   if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
 
  133     return section == 0 ? 
"Joint Name" : 
"Value";
 
  134   return QAbstractTableModel::headerData(section, orientation, role);
 
  139   if (index.column() != 1 || role != Qt::EditRole)
 
  144   if (!value.canConvert<
double>())
 
  148   double v = value.toDouble(&ok);
 
  158   dataChanged(index, index);
 
  164   if (!index.isValid())
 
  167   return robot_state_.
getRobotModel()->getJointOfVariable(var_idx);
 
  171                                                                     const QModelIndex& index)
 const 
  187   dataChanged(index(0, 1), index(
rowCount() - 1, 1));
 
  191   : QWidget(parent), ui_(new 
Ui::MotionPlanningFrameJointsUI()), planning_display_(display)
 
  197   svd_.setThreshold(0.001);
 
  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();
 
  215     const std::string& group_name, 
const robot_interaction::InteractionHandlerPtr& start_state_handler,
 
  216     const robot_interaction::InteractionHandlerPtr& goal_state_handler)
 
  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);
 
  227   connect(start_state_model_.get(), &JMGItemModel::dataChanged, 
this, [
this]() {
 
  228     if (!ignore_state_changes_)
 
  229       planning_display_->setQueryStartState(start_state_model_->getRobotState());
 
  231   connect(goal_state_model_.get(), &JMGItemModel::dataChanged, 
this, [
this]() {
 
  232     if (!ignore_state_changes_)
 
  233       planning_display_->setQueryGoalState(goal_state_model_->getRobotState());
 
  243   if (!start_state_model_ || !start_state_handler_)
 
  245   ignore_state_changes_ = 
true;
 
  246   start_state_model_->updateRobotState(*start_state_handler_->getState());
 
  247   ignore_state_changes_ = 
false;
 
  254   if (!goal_state_model_ || !goal_state_handler_)
 
  256   ignore_state_changes_ = 
true;
 
  257   goal_state_model_->updateRobotState(*goal_state_handler_->getState());
 
  258   ignore_state_changes_ = 
false;
 
  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"));
 
  272   if (model == start_state_model_.get())
 
  281 static Eigen::Index findMatching(
const Eigen::VectorXd& key, 
const Eigen::MatrixXd& haystack,
 
  282                                  const Eigen::VectorXi& available, 
double& sign)
 
  284   Eigen::Index result = available.array().maxCoeff();
 
  285   double best_match = 0.0;
 
  286   for (
unsigned int i = 0; i < available.rows(); ++i)
 
  288     int index = available[i];
 
  291     if (index >= haystack.cols())
 
  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)
 
  297       best_match = abs_match;
 
  299       sign = match > 0 ? 1.0 : -1.0;
 
  312     Eigen::MatrixXd jacobian;
 
  315                                             Eigen::Vector3d::Zero(), jacobian, 
false))
 
  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)
 
  326     ns_sliders_.reserve(ns_dim);
 
  328     for (; i < ns_dim; ++i)
 
  330       if (i >= ns_sliders_.size())
 
  332       ns_sliders_[i]->show();
 
  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;  
 
  346     nullspace_.resize(0, 0);
 
  349   ui_->dummy_ns_slider_->setVisible(i == 0);
 
  352   for (; i < ns_sliders_.size(); ++i)
 
  353     ns_sliders_[i]->hide();
 
  359   slider->setOrientation(Qt::Horizontal);
 
  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)));
 
  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())
 
  380   Eigen::VectorXd values;
 
  382   values += value * nullspace_.col(index);
 
  391   QStyle* style = option.widget ? option.widget->style() : QApplication::style();
 
  392   QStyleOptionViewItem style_option = option;
 
  393   initStyleOption(&style_option, index);
 
  395   if (index.column() == 1)
 
  398     double value = index.data().toDouble();
 
  399     if (joint_type.isValid())
 
  401       switch (joint_type.toInt())
 
  404           style_option.text = option.locale.toString(value * 180 / M_PI, 
'f', 0).append(
"°");
 
  407           style_option.text = option.locale.toString(value, 
'f', 3).append(
"m");
 
  415     if (vbounds.isValid())
 
  417       QPointF bounds = vbounds.toPointF();
 
  418       const float min = bounds.x();
 
  419       const float max = bounds.y();
 
  421       QStyleOptionProgressBar 
opt;
 
  422       opt.rect = option.rect;
 
  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);
 
  434   style->drawControl(QStyle::CE_ItemViewItem, &style_option, painter, option.widget);
 
  438                                            const QModelIndex& index)
 const 
  441   if (index.column() == 1)
 
  444     if (vbounds.isValid())
 
  446       QPointF bounds = vbounds.toPointF();
 
  447       float min = bounds.x();
 
  448       float max = bounds.y();
 
  458         const_cast<QAbstractItemModel*
>(index.model())->setData(index, value, Qt::EditRole);
 
  463   return QStyledItemDelegate::createEditor(parent, option, index);
 
  466 void ProgressBarDelegate::commitAndCloseEditor()
 
  479   if (event->type() == QEvent::MouseButtonPress)
 
  481     QAbstractItemView* 
view = qobject_cast<QAbstractItemView*>(parent());
 
  482     QModelIndex index = 
view->indexAt(
static_cast<QMouseEvent*
>(event)->pos());
 
  483     if (index.flags() & Qt::ItemIsEditable)  
 
  485       view->setCurrentIndex(index);
 
  494   : QWidget(parent), min_(min), max_(max), digits_(digits)
 
  497   if (QApplication::mouseButtons() & Qt::LeftButton)
 
  503   QPainter painter(
this);
 
  505   QStyleOptionProgressBar 
opt;
 
  507   opt.palette = this->palette();
 
  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);
 
  519   if (event->button() == Qt::LeftButton)
 
  525   float v = std::min(max_, std::max(min_, min_ + event->x() * (max_ - min_) / width()));
 
  537   if (event->button() == Qt::LeftButton)
 
  553   timer_interval_ = ms;
 
  558   QSlider::setRange(-resolution, +resolution);
 
  568   QSlider::timerEvent(event);
 
  569   if (event->timerId() == timer_id_)
 
  575   QSlider::mousePressEvent(event);
 
  576   timer_id_ = startTimer(timer_interval_);
 
  581   killTimer(timer_id_);
 
  582   QSlider::mouseReleaseEvent(event);
 
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....
 
size_t getFirstVariableIndex() const
Get the index of this joint's first variable within the full robot state.
 
bool isPassive() const
Check if this joint is passive.
 
bool enforcePositionBounds(double *values) const
Force the specified values to be inside bounds and normalized. Quaternions are normalized,...
 
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.
 
const JointModel * getMimic() const
Get the joint this one is mimicking.
 
Representation of a robot's state. This includes position, velocity, acceleration and effort.
 
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.
 
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...
 
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...
 
const RobotModelConstPtr & getRobotModel() const
Get the robot model this state is constructed for.
 
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....
 
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.
 
std::size_t getVariableCount() const
Get the number of variables that make up this state.
 
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.
 
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
 
moveit::core::RobotState & getRobotState()
 
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
 
Slider that jumps back to zero.
 
void setResolution(unsigned int resolution)
 
void setTimerInterval(int ms)
 
void triggered(double value)
 
JogSlider(QWidget *parent=nullptr)
 
void mousePressEvent(QMouseEvent *event) override
 
void mouseReleaseEvent(QMouseEvent *event) override
 
void setMaximum(double value)
 
void timerEvent(QTimerEvent *event) override
 
void setQueryGoalState(const moveit::core::RobotState &goal)
 
void setQueryStartState(const moveit::core::RobotState &start)
 
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.
 
void mouseMoveEvent(QMouseEvent *event) override
 
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.
 
void valueChanged(float value)
 
void mouseReleaseEvent(QMouseEvent *event) override
 
void paintEvent(QPaintEvent *event) override
 
void mousePressEvent(QMouseEvent *event) override
 
const rclcpp::Logger LOGGER