moveit_state_adapter.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Apache License)
00003  *
00004  * Copyright (c) 2014, Dan Solomon
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  * http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 #include <console_bridge/console.h>
00020 #include "descartes_moveit/moveit_state_adapter.h"
00021 #include "eigen_conversions/eigen_msg.h"
00022 #include "random_numbers/random_numbers.h"
00023 #include "descartes_core/pretty_print.hpp"
00024 #include "descartes_moveit/seed_search.h"
00025 #include <sstream>
00026 
00027 const static int SAMPLE_ITERATIONS = 10;
00028 
00029 namespace
00030 {
00031 
00032 bool getJointVelocityLimits(const moveit::core::RobotState& state,
00033                             const std::string& group_name,
00034                             std::vector<double>& output)
00035 {
00036   std::vector<double> result;
00037 
00038   auto models = state.getJointModelGroup(group_name)->getActiveJointModels();
00039   for (const moveit::core::JointModel* model : models)
00040   {
00041     const auto& bounds = model->getVariableBounds();
00042     // Check to see if there is a single bounds constraint (more might indicate
00043     // not revolute joint)
00044     if (model->getType() != moveit::core::JointModel::REVOLUTE &&
00045         model->getType() != moveit::core::JointModel::PRISMATIC)
00046     {
00047       ROS_ERROR_STREAM(__FUNCTION__ << " Unexpected joint type. Currently works only with single axis prismatic or revolute joints.");
00048       return false;
00049     }
00050     else
00051     {
00052       result.push_back(bounds[0].max_velocity_);
00053     }
00054   }
00055 
00056   output = result;
00057   return true;
00058 }
00059 
00060 } // end anon namespace
00061 
00062 namespace descartes_moveit
00063 {
00064 
00065 MoveitStateAdapter::MoveitStateAdapter()
00066 {}
00067 
00068 MoveitStateAdapter::MoveitStateAdapter(const moveit::core::RobotState & robot_state, const std::string & group_name,
00069                                        const std::string & tool_frame, const std::string & world_frame) :
00070   robot_state_(new moveit::core::RobotState(robot_state)),
00071   group_name_(group_name),
00072   tool_frame_(tool_frame),
00073   world_frame_(world_frame),
00074   world_to_root_(Eigen::Affine3d::Identity())
00075 {
00076 
00077   ROS_INFO_STREAM("Generated random seeds");
00078   seed_states_ = seed::findRandomSeeds(*robot_state_, group_name_, SAMPLE_ITERATIONS);
00079 
00080   const moveit::core::JointModelGroup* joint_model_group_ptr = robot_state_->getJointModelGroup(group_name);
00081   if (joint_model_group_ptr)
00082   {
00083     // Find the velocity limits
00084     if (!getJointVelocityLimits(*robot_state_, group_name, velocity_limits_))
00085     {
00086       logWarn("Could not determine velocity limits of RobotModel from MoveIt");
00087     }
00088 
00089     joint_model_group_ptr->printGroupInfo();
00090 
00091     const std::vector<std::string>& link_names = joint_model_group_ptr->getLinkModelNames();
00092     if (tool_frame_ != link_names.back())
00093     {
00094       logWarn("Tool frame '%s' does not match group tool frame '%s', functionality will be implemented in the future",
00095                tool_frame_.c_str(), link_names.back().c_str());
00096     }
00097 
00098     if (world_frame_ != robot_state_->getRobotModel()->getModelFrame())
00099     {
00100       logWarn("World frame '%s' does not match model root frame '%s', all poses will be transformed to world frame '%s'",
00101                world_frame_.c_str(), link_names.front().c_str(),world_frame_.c_str());
00102 
00103       Eigen::Affine3d root_to_world = robot_state_->getFrameTransform(world_frame_);
00104       world_to_root_ = descartes_core::Frame(root_to_world.inverse());
00105     }
00106 
00107   }
00108   else
00109   {
00110     logError("Joint group: %s does not exist in robot model", group_name_.c_str());
00111     std::stringstream msg;
00112     msg << "Possible group names: " << robot_state_->getRobotModel()->getJointModelGroupNames();
00113     logError(msg.str().c_str());
00114   }
00115   return;
00116 }
00117 
00118 bool MoveitStateAdapter::initialize(const std::string& robot_description, const std::string& group_name,
00119                                     const std::string& world_frame,const std::string& tcp_frame)
00120 {
00121 
00122   robot_model_loader_.reset(new robot_model_loader::RobotModelLoader(robot_description));
00123   robot_model_ptr_ = robot_model_loader_->getModel();
00124   robot_state_.reset(new moveit::core::RobotState(robot_model_ptr_));
00125   planning_scene_.reset(new planning_scene::PlanningScene(robot_model_loader_->getModel()));
00126   group_name_ = group_name;
00127   tool_frame_ = tcp_frame;
00128   world_frame_ = world_frame;
00129 
00130   if (seed_states_.empty())
00131   {
00132     seed_states_ = seed::findRandomSeeds(*robot_state_, group_name_, SAMPLE_ITERATIONS);
00133     ROS_INFO_STREAM("Generated "<<seed_states_.size()<< " random seeds");
00134   }
00135 
00136   // Find the velocity limits
00137   if (!getJointVelocityLimits(*robot_state_, group_name, velocity_limits_))
00138   {
00139     logWarn("Could not determine velocity limits of RobotModel from MoveIt");
00140   }
00141 
00142   const moveit::core::JointModelGroup* joint_model_group_ptr = robot_state_->getJointModelGroup(group_name);
00143   if (joint_model_group_ptr)
00144   {
00145     joint_model_group_ptr->printGroupInfo();
00146 
00147     const std::vector<std::string>& link_names = joint_model_group_ptr->getLinkModelNames();
00148     if (tool_frame_ != link_names.back())
00149     {
00150       logWarn("Tool frame '%s' does not match group tool frame '%s', functionality will be implemented in the future",
00151                tool_frame_.c_str(), link_names.back().c_str());
00152     }
00153 
00154     if (world_frame_ != robot_state_->getRobotModel()->getModelFrame())
00155     {
00156       logWarn("World frame '%s' does not match model root frame '%s', all poses will be transformed to world frame '%s'",
00157                world_frame_.c_str(), robot_state_->getRobotModel()->getModelFrame().c_str(),world_frame_.c_str());
00158 
00159       Eigen::Affine3d root_to_world = robot_state_->getFrameTransform(world_frame_);
00160       world_to_root_ = descartes_core::Frame(root_to_world.inverse());
00161     }
00162 
00163   }
00164   else
00165   {
00166     logError("Joint group: %s does not exist in robot model", group_name_.c_str());
00167     std::stringstream msg;
00168     msg << "Possible group names: " << robot_state_->getRobotModel()->getJointModelGroupNames();
00169     logError(msg.str().c_str());
00170   }
00171   return true;
00172 }
00173 
00174 bool MoveitStateAdapter::getIK(const Eigen::Affine3d &pose, const std::vector<double> &seed_state,
00175                               std::vector<double> &joint_pose) const
00176 {
00177   robot_state_->setJointGroupPositions(group_name_, seed_state);
00178   return getIK(pose, joint_pose);
00179 }
00180 
00181 bool MoveitStateAdapter::getIK(const Eigen::Affine3d &pose, std::vector<double> &joint_pose) const
00182 {
00183   bool rtn = false;
00184 
00185   // transform to group base
00186   Eigen::Affine3d tool_pose = world_to_root_.frame* pose;
00187 
00188 
00189   if (robot_state_->setFromIK(robot_state_->getJointModelGroup(group_name_), tool_pose,
00190                               tool_frame_))
00191   {
00192     robot_state_->copyJointGroupPositions(group_name_, joint_pose);
00193     if(!isValid(joint_pose))
00194     {
00195       ROS_DEBUG_STREAM("Robot joint pose is invalid");
00196     }
00197     else
00198     {
00199       rtn = true;
00200     }
00201   }
00202   else
00203   {
00204     rtn = false;
00205   }
00206 
00207   return rtn;
00208 }
00209 
00210 bool MoveitStateAdapter::getAllIK(const Eigen::Affine3d &pose, std::vector<std::vector<double> > &joint_poses) const
00211 {
00212   //The minimum difference between solutions should be greater than the search discretization
00213   //used by the IK solver.  This value is multiplied by 4 to remove any chance that a solution
00214   //in the middle of a discretization step could be double counted.  In reality, we'd like solutions
00215   //to be further apart than this.
00216   double epsilon = 4 * robot_state_->getRobotModel()->getJointModelGroup(group_name_)->getSolverInstance()->
00217       getSearchDiscretization();
00218   logDebug("Utilizing an min. difference of %f between IK solutions", epsilon);
00219   joint_poses.clear();
00220   for (size_t sample_iter = 0; sample_iter < seed_states_.size(); ++sample_iter)
00221   {
00222     robot_state_->setJointGroupPositions(group_name_, seed_states_[sample_iter]);
00223     std::vector<double> joint_pose;
00224     if (getIK(pose, joint_pose))
00225     {
00226       if( joint_poses.empty())
00227       {
00228         std::stringstream msg;
00229         msg << "Found *first* solution on " << sample_iter << " iteration, joint: " << joint_pose;
00230         logDebug(msg.str().c_str());
00231         joint_poses.push_back(joint_pose);
00232       }
00233       else
00234       {
00235         std::stringstream msg;
00236         msg << "Found *potential* solution on " << sample_iter << " iteration, joint: " << joint_pose;
00237         logDebug(msg.str().c_str());
00238 
00239         std::vector<std::vector<double> >::iterator joint_pose_it;
00240         bool match_found = false;
00241         for(joint_pose_it = joint_poses.begin(); joint_pose_it != joint_poses.end(); ++joint_pose_it)
00242         {
00243           if( descartes_core::utils::equal(joint_pose, (*joint_pose_it), epsilon) )
00244           {
00245             logDebug("Found matching, potential solution is not new");
00246             match_found = true;
00247             break;
00248           }
00249         }
00250         if (!match_found)
00251         {
00252           std::stringstream msg;
00253           msg << "Found *new* solution on " << sample_iter << " iteration, joint: " << joint_pose;
00254           logDebug(msg.str().c_str());
00255           joint_poses.push_back(joint_pose);
00256         }
00257       }
00258     }
00259   }
00260   logDebug("Found %d joint solutions out of %d iterations", joint_poses.size(), seed_states_.size());
00261   if (joint_poses.empty())
00262   {
00263     logError("Found 0 joint solutions out of %d iterations", seed_states_.size());
00264     return false;
00265   }
00266   else
00267   {
00268     logInform("Found %d joint solutions out of %d iterations", joint_poses.size(), seed_states_.size());
00269     return true;
00270   }
00271 }
00272 
00273 bool MoveitStateAdapter::isInCollision(const std::vector<double>& joint_pose) const
00274 {
00275   bool in_collision = false;
00276   if(check_collisions_)
00277   {
00278     robot_state_->setJointGroupPositions(group_name_, joint_pose);
00279     in_collision = planning_scene_->isStateColliding(*robot_state_,group_name_);
00280   }
00281   return in_collision;
00282 }
00283 
00284 bool MoveitStateAdapter::getFK(const std::vector<double> &joint_pose, Eigen::Affine3d &pose) const
00285 {
00286   bool rtn = false;
00287   robot_state_->setJointGroupPositions(group_name_, joint_pose);
00288   if ( isValid(joint_pose) )
00289   {
00290     if (robot_state_->knowsFrameTransform(tool_frame_))
00291     {
00292 
00293       pose = world_to_root_.frame*robot_state_->getFrameTransform(tool_frame_);
00294       rtn = true;
00295     }
00296     else
00297     {
00298       logError("Robot state does not recognize tool frame: %s", tool_frame_.c_str());
00299       rtn = false;
00300     }
00301   }
00302   else
00303   {
00304     logError("Invalid joint pose passed to get forward kinematics");
00305     rtn = false;
00306   }
00307   std::stringstream msg;
00308   msg << "Returning the pose " << std::endl << pose.matrix() << std::endl
00309       << "For joint pose: " << joint_pose;
00310   logDebug(msg.str().c_str());
00311   return rtn;
00312 }
00313 
00314 bool MoveitStateAdapter::isValid(const std::vector<double> &joint_pose) const
00315 {
00316   bool rtn = false;
00317 
00318   if (robot_state_->getJointModelGroup(group_name_)->getActiveJointModels().size() ==
00319       joint_pose.size())
00320   {
00321     robot_state_->setJointGroupPositions(group_name_, joint_pose);
00322     //TODO: At some point velocities and accelerations should be set for the group as
00323     //well.
00324     robot_state_->setVariableVelocities(std::vector<double>(joint_pose.size(), 0.));
00325     robot_state_->setVariableAccelerations(std::vector<double>(joint_pose.size(), 0.));
00326     if (robot_state_->satisfiesBounds())
00327     {
00328       rtn = true;
00329     }
00330     else
00331     {
00332       std::stringstream msg;
00333       msg << "Joint pose: " << joint_pose << ", outside joint boundaries";
00334       logDebug(msg.str().c_str());
00335     }
00336 
00337     if(isInCollision(joint_pose))
00338     {
00339       ROS_DEBUG_STREAM("Robot is in collision at this joint pose");
00340       rtn = false;
00341     }
00342 
00343   }
00344   else
00345   {
00346     logError("Size of joint pose: %d doesn't match robot state variable size: %d",
00347              joint_pose.size(),
00348              robot_state_->getJointModelGroup(group_name_)->getActiveJointModels().size());
00349     rtn = false;
00350   }
00351   return rtn;
00352 }
00353 
00354 bool MoveitStateAdapter::isValid(const Eigen::Affine3d &pose) const
00355 {
00356   //TODO: Could check robot extents first as a quick check
00357   std::vector<double> dummy;
00358   return getIK(pose, dummy);
00359 }
00360 
00361 int MoveitStateAdapter::getDOF() const
00362 {
00363   const moveit::core::JointModelGroup* group;
00364   group = robot_state_->getJointModelGroup(group_name_);
00365   return group->getVariableCount();
00366 }
00367 
00368 bool MoveitStateAdapter::isValidMove(const std::vector<double>& from_joint_pose, 
00369                                      const std::vector<double>& to_joint_pose,
00370                                      double dt) const
00371 {
00372   std::vector<double> max_joint_deltas;
00373   max_joint_deltas.reserve(velocity_limits_.size());
00374 
00375   // Check for equal sized arrays
00376   if (from_joint_pose.size() != to_joint_pose.size())
00377   {
00378     ROS_ERROR_STREAM("To and From joint poses are of different sizes.");
00379     return false;
00380   }
00381 
00382   // Build a vector of the maximum angle delta per joint 
00383   for (std::vector<double>::const_iterator it = velocity_limits_.begin(); it != velocity_limits_.end(); ++it)
00384   {
00385     max_joint_deltas.push_back((*it) * dt);
00386   }
00387 
00388   for (std::vector<double>::size_type i = 0; i < from_joint_pose.size(); ++i)
00389   {
00390     if ( std::abs(from_joint_pose[i] - to_joint_pose[i]) > max_joint_deltas[i] )
00391     {
00392       return false;
00393     }
00394   }
00395 
00396   return true;
00397 }
00398 
00399 } //descartes_moveit
00400 


descartes_moveit
Author(s): Shaun Edwards
autogenerated on Wed Aug 26 2015 11:21:41