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