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 "TransformPublisherDisplay.h"
00033 #include "TransformBroadcaster.h"
00034 #include "rotation_property.h"
00035
00036 #include <rviz/properties/string_property.h>
00037 #include <rviz/properties/bool_property.h>
00038 #include <rviz/properties/float_property.h>
00039 #include <rviz/properties/vector_property.h>
00040 #include <rviz/properties/tf_frame_property.h>
00041 #include <rviz/properties/enum_property.h>
00042
00043 #include <rviz/display_factory.h>
00044 #include <rviz/display_context.h>
00045 #include <rviz/frame_manager.h>
00046 #include <rviz/default_plugin/interactive_markers/interactive_marker.h>
00047 #include <interactive_markers/tools.h>
00048 #include <tf/transform_listener.h>
00049 #include <QDebug>
00050
00051 namespace vm = visualization_msgs;
00052 const std::string MARKER_NAME = "marker";
00053
00054 enum MARKER_TYPE { NONE, FRAME, IFRAME, DOF6 };
00055
00056 namespace agni_tf_tools
00057 {
00058
00059 void static updatePose(geometry_msgs::Pose &pose,
00060 const Eigen::Quaterniond &q,
00061 Ogre::Vector3 p = Ogre::Vector3::ZERO)
00062 {
00063 pose.orientation.w = q.w();
00064 pose.orientation.x = q.x();
00065 pose.orientation.y = q.y();
00066 pose.orientation.z = q.z();
00067
00068 pose.position.x = p.x;
00069 pose.position.y = p.y;
00070 pose.position.z = p.z;
00071 }
00072
00073
00074 TransformPublisherDisplay::TransformPublisherDisplay()
00075 : rviz::Display()
00076 , ignore_updates_(false)
00077 {
00078 translation_property_ = new rviz::VectorProperty("translation", Ogre::Vector3::ZERO, "", this);
00079 rotation_property_ = new RotationProperty(this, "rotation");
00080
00081 parent_frame_property_ = new rviz::TfFrameProperty(
00082 "parent frame", rviz::TfFrameProperty::FIXED_FRAME_STRING, "", this,
00083 0, true, SLOT(onRefFrameChanged()), this);
00084 adapt_transform_property_ = new rviz::BoolProperty(
00085 "adapt transformation", false,
00086 "Adapt transformation when changing the parent frame? "
00087 "If so, the marker will not move.", this,
00088 SLOT(onAdaptTransformChanged()), this);
00089 onAdaptTransformChanged();
00090
00091 broadcast_property_ = new rviz::BoolProperty("publish transform", true, "", this,
00092 SLOT(onBroadcastEnableChanged()), this);
00093 child_frame_property_ = new rviz::TfFrameProperty(
00094 "child frame", "", "", broadcast_property_,
00095 0, false, SLOT(onFramesChanged()), this);
00096
00097 connect(translation_property_, SIGNAL(changed()), this, SLOT(onTransformChanged()));
00098 connect(rotation_property_, SIGNAL(quaternionChanged(Eigen::Quaterniond)), this, SLOT(onTransformChanged()));
00099 connect(rotation_property_, SIGNAL(statusUpdate(int,QString,QString)),
00100 this, SLOT(setStatus(int,QString,QString)));
00101 tf_pub_ = new TransformBroadcaster("", "", this);
00102
00103 marker_property_ = new rviz::EnumProperty("marker type", "interactive frame", "Choose which type of interactive marker to show",
00104 this, SLOT(onMarkerTypeChanged()), this);
00105 marker_property_->addOption("none", NONE);
00106 marker_property_->addOption("static frame", FRAME);
00107 marker_property_->addOption("interactive frame", IFRAME);
00108 marker_property_->addOption("6 DoF handles", DOF6);
00109
00110 marker_scale_property_ = new rviz::FloatProperty("marker scale", 0.2, "", marker_property_,
00111 SLOT(onMarkerScaleChanged()), this);
00112 marker_property_->hide();
00113 }
00114
00115 TransformPublisherDisplay::~TransformPublisherDisplay()
00116 {
00117 }
00118
00119 void TransformPublisherDisplay::onInitialize()
00120 {
00121 Display::onInitialize();
00122 parent_frame_property_->setFrameManager(context_->getFrameManager());
00123 child_frame_property_->setFrameManager(context_->getFrameManager());
00124 marker_node_ = getSceneNode()->createChildSceneNode();
00125
00126
00127 this->expand();
00128 broadcast_property_->expand();
00129 }
00130
00131 void TransformPublisherDisplay::reset()
00132 {
00133 Display::reset();
00134 }
00135
00136 void TransformPublisherDisplay::onEnable()
00137 {
00138 Display::onEnable();
00139 tf_pub_->setEnabled(true);
00140 }
00141
00142 void TransformPublisherDisplay::onDisable()
00143 {
00144 Display::onDisable();
00145 tf_pub_->setEnabled(false);
00146 createInteractiveMarker(NONE);
00147 }
00148
00149 void TransformPublisherDisplay::update(float wall_dt, float ros_dt)
00150 {
00151 if (!this->isEnabled()) return;
00152
00153 Display::update(wall_dt, ros_dt);
00154
00155 if (!imarker_ && marker_property_->getOptionInt() != NONE &&
00156 !createInteractiveMarker(marker_property_->getOptionInt()))
00157 setStatusStd(StatusProperty::Warn, MARKER_NAME, "Waiting for tf");
00158 else if (imarker_)
00159 imarker_->update(wall_dt);
00160 }
00161
00162
00163 static vm::Marker createArrowMarker(double scale,
00164 const Eigen::Vector3d &dir,
00165 const QColor &color) {
00166 vm::Marker marker;
00167
00168 marker.type = vm::Marker::ARROW;
00169 marker.scale.x = scale;
00170 marker.scale.y = 0.1*scale;
00171 marker.scale.z = 0.1*scale;
00172
00173 updatePose(marker.pose,
00174 Eigen::Quaterniond::FromTwoVectors(Eigen::Vector3d::UnitX(), dir));
00175
00176 marker.color.r = color.redF();
00177 marker.color.g = color.greenF();
00178 marker.color.b = color.blueF();
00179 marker.color.a = color.alphaF();
00180
00181 return marker;
00182 }
00183
00184 inline void setOrientation(geometry_msgs::Quaternion &q, double w, double x, double y, double z) {
00185 q.w = w;
00186 q.x = x;
00187 q.y = y;
00188 q.z = z;
00189 }
00190
00191 void TransformPublisherDisplay::addFrameControls(vm::InteractiveMarker &im, double scale, bool interactive)
00192 {
00193 vm::InteractiveMarkerControl ctrl;
00194 setOrientation(ctrl.orientation, 1, 0,0,0);
00195 ctrl.always_visible = true;
00196 if (interactive) {
00197 ctrl.orientation_mode = vm::InteractiveMarkerControl::VIEW_FACING;
00198 ctrl.independent_marker_orientation = true;
00199 ctrl.interaction_mode = vm::InteractiveMarkerControl::MOVE_ROTATE_3D;
00200 }
00201 ctrl.name = "frame";
00202
00203 ctrl.markers.push_back(createArrowMarker(im.scale * scale, Eigen::Vector3d::UnitX(), QColor("red")));
00204 ctrl.markers.push_back(createArrowMarker(im.scale * scale, Eigen::Vector3d::UnitY(), QColor("green")));
00205 ctrl.markers.push_back(createArrowMarker(im.scale * scale, Eigen::Vector3d::UnitZ(), QColor("blue")));
00206
00207 im.controls.push_back(ctrl);
00208 }
00209
00210 void TransformPublisherDisplay::add6DOFControls(vm::InteractiveMarker &im) {
00211 vm::InteractiveMarkerControl ctrl;
00212 ctrl.always_visible = false;
00213
00214 setOrientation(ctrl.orientation, 1, 1,0,0);
00215 ctrl.interaction_mode = vm::InteractiveMarkerControl::MOVE_AXIS;
00216 ctrl.name = "x pos";
00217 im.controls.push_back(ctrl);
00218 ctrl.interaction_mode = vm::InteractiveMarkerControl::ROTATE_AXIS;
00219 ctrl.name = "x rot";
00220 im.controls.push_back(ctrl);
00221
00222 setOrientation(ctrl.orientation, 1, 0,1,0);
00223 ctrl.interaction_mode = vm::InteractiveMarkerControl::MOVE_AXIS;
00224 ctrl.name = "y pos";
00225 im.controls.push_back(ctrl);
00226 ctrl.interaction_mode = vm::InteractiveMarkerControl::ROTATE_AXIS;
00227 ctrl.name = "y rot";
00228 im.controls.push_back(ctrl);
00229
00230 setOrientation(ctrl.orientation, 1, 0,0,1);
00231 ctrl.interaction_mode = vm::InteractiveMarkerControl::MOVE_AXIS;
00232 ctrl.name = "z pos";
00233 im.controls.push_back(ctrl);
00234 ctrl.interaction_mode = vm::InteractiveMarkerControl::ROTATE_AXIS;
00235 ctrl.name = "z rot";
00236 im.controls.push_back(ctrl);
00237 }
00238
00239 bool TransformPublisherDisplay::createInteractiveMarker(int type)
00240 {
00241 if (type == NONE) {
00242 if (imarker_)
00243 imarker_.reset();
00244 return true;
00245 }
00246
00247 float scale = marker_scale_property_->getFloat();
00248
00249 vm::InteractiveMarker im;
00250 im.name = MARKER_NAME;
00251 im.scale = scale;
00252 if (!fillPoseStamped(im.header, im.pose)) return false;
00253
00254 if (type == FRAME || type == IFRAME)
00255 addFrameControls(im, 1.0, type == IFRAME);
00256 else if (type == DOF6) {
00257 addFrameControls(im, 0.5, type == IFRAME);
00258 add6DOFControls(im);
00259 }
00260
00261 imarker_.reset(new rviz::InteractiveMarker(marker_node_, context_));
00262 connect(imarker_.get(), SIGNAL(userFeedback(visualization_msgs::InteractiveMarkerFeedback&)),
00263 this, SLOT(onMarkerFeedback(visualization_msgs::InteractiveMarkerFeedback&)));
00264 connect(imarker_.get(), SIGNAL(statusUpdate(StatusProperty::Level,std::string,std::string)),
00265 this, SLOT(setStatusStd(StatusProperty::Level,std::string,std::string)));
00266
00267 setStatusStd(rviz::StatusProperty::Ok, MARKER_NAME, "Ok");
00268
00269
00270 interactive_markers::autoComplete(im, true);
00271
00272 imarker_->processMessage(im);
00273 imarker_->setShowVisualAids(false);
00274 imarker_->setShowAxes(false);
00275 imarker_->setShowDescription(false);
00276
00277 marker_property_->show();
00278 return true;
00279 }
00280
00281
00282 bool TransformPublisherDisplay::fillPoseStamped(std_msgs::Header &header,
00283 geometry_msgs::Pose &pose)
00284 {
00285 const std::string &parent_frame = parent_frame_property_->getFrameStd();
00286 std::string error;
00287 if (context_->getFrameManager()->transformHasProblems(parent_frame, ros::Time(), error))
00288 {
00289 setStatusStd(StatusProperty::Error, MARKER_NAME, error);
00290 return false;
00291 }
00292 setStatusStd(StatusProperty::Ok, MARKER_NAME, "");
00293
00294 const Eigen::Quaterniond &q = rotation_property_->getQuaternion();
00295 const Ogre::Vector3 &p = translation_property_->getVector();
00296 updatePose(pose, q, p);
00297 header.frame_id = parent_frame;
00298
00299 header.stamp = ros::Time();
00300 return true;
00301 }
00302
00303 void TransformPublisherDisplay::setStatus(int level, const QString &name, const QString &text)
00304 {
00305 if (level == rviz::StatusProperty::Ok && text.isEmpty()) {
00306 Display::setStatus(static_cast<rviz::StatusProperty::Level>(level), name, text);
00307 Display::deleteStatus(name);
00308 } else
00309 Display::setStatus(static_cast<rviz::StatusProperty::Level>(level), name, text);
00310 }
00311
00312 void TransformPublisherDisplay::setStatusStd(rviz::StatusProperty::Level level,
00313 const std::string &name, const std::string &text)
00314 {
00315 setStatus(level, QString::fromStdString(name), QString::fromStdString(text));
00316 }
00317
00318 static bool getTransform(rviz::FrameManager &fm, const std::string &frame, Eigen::Affine3d &tf)
00319 {
00320 Ogre::Vector3 p = Ogre::Vector3::ZERO;
00321 Ogre::Quaternion q = Ogre::Quaternion::IDENTITY;
00322
00323 bool success = fm.getTransform(frame, ros::Time(), p, q);
00324 tf = Eigen::Translation3d(p.x, p.y, p.z) * Eigen::Quaterniond(q.w, q.x, q.y, q.z);
00325 return success || frame == rviz::TfFrameProperty::FIXED_FRAME_STRING.toStdString();
00326 }
00327
00328 void TransformPublisherDisplay::onRefFrameChanged()
00329 {
00330
00331 Eigen::Affine3d prevRef, nextRef;
00332 rviz::FrameManager &fm = *context_->getFrameManager();
00333 if (getTransform(fm, prev_parent_frame_, prevRef) &&
00334 getTransform(fm, parent_frame_property_->getFrameStd(), nextRef)) {
00335 const Ogre::Vector3 &p = translation_property_->getVector();
00336 Eigen::Affine3d curPose = Eigen::Translation3d(p.x, p.y, p.z) * rotation_property_->getQuaternion();
00337 Eigen::Affine3d newPose = nextRef.inverse() * prevRef * curPose;
00338 Eigen::Vector3d t = newPose.translation();
00339 ignore_updates_ = true;
00340 translation_property_->setVector(Ogre::Vector3(t.x(), t.y(), t.z()));
00341 rotation_property_->setQuaternion(Eigen::Quaterniond(newPose.rotation()));
00342 ignore_updates_ = false;
00343 }
00344 onAdaptTransformChanged();
00345 onFramesChanged();
00346 }
00347
00348 void TransformPublisherDisplay::onAdaptTransformChanged()
00349 {
00350 if (adapt_transform_property_->getBool())
00351 prev_parent_frame_ = parent_frame_property_->getFrameStd();
00352 else
00353 prev_parent_frame_ = "";
00354 }
00355
00356 void TransformPublisherDisplay::onFramesChanged()
00357 {
00358
00359 vm::InteractiveMarkerPose marker_pose;
00360 fillPoseStamped(marker_pose.header, marker_pose.pose);
00361 if (imarker_) imarker_->processMessage(marker_pose);
00362
00363
00364 geometry_msgs::TransformStamped tf;
00365 tf.header.frame_id = parent_frame_property_->getFrameStd();
00366 tf.child_frame_id = child_frame_property_->getFrameStd();
00367 tf.transform.translation.x = marker_pose.pose.position.x;
00368 tf.transform.translation.y = marker_pose.pose.position.y;
00369 tf.transform.translation.z = marker_pose.pose.position.z;
00370 tf.transform.rotation = marker_pose.pose.orientation;
00371 tf_pub_->setValue(tf);
00372 }
00373
00374 void TransformPublisherDisplay::onTransformChanged()
00375 {
00376 if (ignore_updates_) return;
00377
00378 vm::InteractiveMarkerPose marker_pose;
00379 fillPoseStamped(marker_pose.header, marker_pose.pose);
00380
00381
00382 ignore_updates_ = true;
00383 if (imarker_) imarker_->processMessage(marker_pose);
00384 ignore_updates_ = false;
00385 tf_pub_->setPose(marker_pose.pose);
00386 }
00387
00388 void TransformPublisherDisplay::onMarkerFeedback(vm::InteractiveMarkerFeedback &feedback)
00389 {
00390 if (ignore_updates_) return;
00391 if (feedback.event_type != vm::InteractiveMarkerFeedback::POSE_UPDATE) return;
00392
00393
00394 const geometry_msgs::Point &p_in = feedback.pose.position;
00395 const geometry_msgs::Quaternion &q_in = feedback.pose.orientation;
00396
00397 tf::Stamped<tf::Pose> pose_in(tf::Transform(tf::Quaternion(q_in.x, q_in.y, q_in.z, q_in.w),
00398 tf::Vector3(p_in.x, p_in.y, p_in.z)),
00399 feedback.header.stamp, feedback.header.frame_id);
00400 tf::Stamped<tf::Pose> pose_out;
00401 try {
00402 context_->getTFClient()->transformPose(parent_frame_property_->getFrameStd(),
00403 pose_in, pose_out);
00404 } catch(const std::runtime_error &e) {
00405 ROS_DEBUG("Error transforming from frame '%s' to frame '%s': %s",
00406 feedback.header.frame_id.c_str(),
00407 parent_frame_property_->getFrameStd().c_str(),
00408 e.what());
00409 return;
00410 }
00411
00412 const tf::Vector3 &p = pose_out.getOrigin();
00413 const tf::Quaternion &q = pose_out.getRotation();
00414
00415 ignore_updates_ = true;
00416 translation_property_->setVector(Ogre::Vector3(p.x(), p.y(), p.z()));
00417 rotation_property_->setQuaternion(Eigen::Quaterniond(q.w(), q.x(), q.y(), q.z()));
00418 ignore_updates_ = false;
00419
00420 updatePose(feedback.pose, rotation_property_->getQuaternion(),
00421 translation_property_->getVector());
00422 tf_pub_->setPose(feedback.pose);
00423 }
00424
00425 void TransformPublisherDisplay::onBroadcastEnableChanged()
00426 {
00427 tf_pub_->setEnabled(broadcast_property_->getBool());
00428 }
00429
00430 void TransformPublisherDisplay::onMarkerTypeChanged()
00431 {
00432 createInteractiveMarker(marker_property_->getOptionInt());
00433 }
00434
00435 void TransformPublisherDisplay::onMarkerScaleChanged()
00436 {
00437 if (marker_scale_property_->getFloat() <= 0)
00438 marker_scale_property_->setFloat(0.2);
00439 createInteractiveMarker(marker_property_->getOptionInt());
00440 }
00441
00442 }