imarker_robot_state.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2016, University of Colorado, Boulder
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 PickNik LLC nor the names of its
18  * 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: Dave Coleman
36  Desc: Class to encapsule a visualized robot state that can be controlled using an interactive marker
37 */
38 #ifdef _MSC_VER
39 #define _ENABLE_EXTENDED_ALIGNED_STORAGE // https://devblogs.microsoft.com/cppblog/stl-features-and-fixes-in-vs-2017-15-8/
40 #endif
41 
42 // MoveIt
45 
46 // this package
49 
50 // C++
51 #include <string>
52 #include <utility>
53 #include <vector>
54 
55 namespace moveit_visual_tools
56 {
57 IMarkerRobotState::IMarkerRobotState(planning_scene_monitor::PlanningSceneMonitorPtr psm,
58  const std::string& imarker_name, std::vector<ArmData> arm_datas,
59  rviz_visual_tools::colors color, const std::string& package_path)
60  : name_(imarker_name)
61  , nh_("~")
62  , arm_datas_(std::move(arm_datas))
63  , psm_(std::move(psm))
64  , color_(color)
65  , package_path_(package_path)
66 {
67  // Load Visual tools
68  visual_tools_ = std::make_shared<moveit_visual_tools::MoveItVisualTools>(
69  psm_->getRobotModel()->getModelFrame(), nh_.getNamespace() + "/" + imarker_name, psm_);
70 
71  // visual_tools_->setPlanningSceneMonitor(psm_);
72  visual_tools_->loadRobotStatePub(nh_.getNamespace() + "/imarker_" + imarker_name + "_state");
73 
74  // Load robot state
75  imarker_state_ = std::make_shared<moveit::core::RobotState>(psm_->getRobotModel());
76  imarker_state_->setToDefaultValues();
77 
78  // Create Marker Server
79  const std::string imarker_topic = nh_.getNamespace() + "/" + imarker_name + "_imarker";
80  imarker_server_ = std::make_shared<interactive_markers::InteractiveMarkerServer>(imarker_topic, "", false);
81 
82  // Get file name
83  if (!getFilePath(file_path_, "imarker_" + name_ + ".csv", "config/imarkers"))
84  exit(-1);
85 
86  // Load previous pose from file
88  ROS_INFO_STREAM_NAMED(name_, "Unable to find state from file, setting to default");
89 
90  // Show initial robot state loaded from file
92 
93  // Create each end effector
94  end_effectors_.resize(arm_datas_.size());
95  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
96  {
97  std::string eef_name;
98  if (i == 0)
99  eef_name = imarker_name + "_right";
100  else
101  eef_name = imarker_name + "_left";
102 
103  end_effectors_[i] = std::make_shared<IMarkerEndEffector>(this, eef_name, arm_datas_[i], color);
104 
105  // Create map from eef name to object
106  name_to_eef_[eef_name] = end_effectors_[i];
107  }
108 
109  // After both end effectors have been added, apply on server
110  imarker_server_->applyChanges();
111 
112  ROS_DEBUG_STREAM_NAMED(name_, "IMarkerRobotState '" << name_ << "' Ready.");
113 }
114 
115 bool IMarkerRobotState::loadFromFile(const std::string& file_name)
116 {
117  if (!boost::filesystem::exists(file_name))
118  {
119  ROS_WARN_STREAM_NAMED(name_, "File not found: " << file_name);
120  return false;
121  }
122  std::ifstream input_file(file_name);
123 
124  std::string line;
125 
126  if (!std::getline(input_file, line))
127  {
128  ROS_ERROR_STREAM_NAMED(name_, "Unable to read line");
129  return false;
130  }
131 
132  // Get robot state from file
134 
135  return true;
136 }
137 
139 {
140  output_file_.open(file_path_);
142  output_file_.close();
143 
144  return true;
145 }
146 
148 {
149  for (const IMarkerEndEffectorPtr& ee : end_effectors_)
150  ee->setIMarkerCallback(callback);
151 }
152 
153 void IMarkerRobotState::setRobotState(const moveit::core::RobotStatePtr& state)
154 {
155  // Do a copy
156  *imarker_state_ = *state;
157 
158  // Update the imarkers
159  for (const IMarkerEndEffectorPtr& ee : end_effectors_)
160  ee->setPoseFromRobotState();
161 }
162 
164 {
165  // Get the real current state
166  planning_scene_monitor::LockedPlanningSceneRO scene(psm_); // Lock planning scene
167  (*imarker_state_) = scene->getCurrentState();
168 
169  // Set updated pose from robot state
170  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
171  end_effectors_[i]->setPoseFromRobotState();
172 
173  // Show new state
174  visual_tools_->publishRobotState(imarker_state_, color_);
175 }
176 
178 {
179  static const std::size_t MAX_ATTEMPTS = 1000;
180  for (std::size_t attempt = 0; attempt < MAX_ATTEMPTS; ++attempt)
181  {
182  // Set each planning group to random
183  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
184  {
185  imarker_state_->setToRandomPositions(arm_datas_[i].jmg_);
186  }
187 
188  // Update transforms
189  imarker_state_->update();
191 
192  // Collision check
193  // which planning group to collision check, "" is everything
194  static const bool verbose = false;
195  if (planning_scene->isStateValid(*imarker_state_, "", verbose))
196  {
197  // Check clearance
198  if (clearance > 0)
199  {
200  // which planning group to collision check, "" is everything
201  if (planning_scene->distanceToCollision(*imarker_state_) < clearance)
202  {
203  continue; // clearance is not enough
204  }
205  }
206 
207  ROS_INFO_STREAM_NAMED(name_, "Found valid random robot state after " << attempt << " attempts");
208 
209  // Set updated pose from robot state
210  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
211  end_effectors_[i]->setPoseFromRobotState();
212 
213  // Send to imarker
214  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
215  end_effectors_[i]->sendUpdatedIMarkerPose();
216 
217  return true;
218  }
219 
220  if (attempt == 100)
221  ROS_WARN_STREAM_NAMED(name_, "Taking long time to find valid random state");
222  }
223 
224  ROS_ERROR_STREAM_NAMED(name_, "Unable to find valid random robot state for imarker after " << MAX_ATTEMPTS << " attem"
225  "pts");
226 
227  return false;
228 }
229 
231 {
232  // Update transforms
233  imarker_state_->update();
234 
236 
237  // which planning group to collision check, "" is everything
238  return planning_scene->isStateValid(*imarker_state_, "", verbose);
239 }
240 
242 {
243  visual_tools_->publishRobotState(imarker_state_, color_);
244 }
245 
247 {
248  return visual_tools_;
249 }
250 
251 bool IMarkerRobotState::getFilePath(std::string& file_path, const std::string& file_name,
252  const std::string& subdirectory) const
253 
254 {
255  namespace fs = boost::filesystem;
256 
257  // Check that the directory exists, if not, create it
258  fs::path rootPath = fs::path(package_path_);
259  rootPath = rootPath / fs::path(subdirectory);
260 
261  boost::system::error_code returnedError;
262  fs::create_directories(rootPath, returnedError);
263 
264  if (returnedError)
265  {
266  // did not successfully create directories
267  ROS_ERROR("Unable to create directory %s", subdirectory.c_str());
268  return false;
269  }
270 
271  // directories successfully created, append the group name as the file name
272  rootPath = rootPath / fs::path(file_name);
273  file_path = rootPath.string();
274  // ROS_DEBUG_STREAM_NAMED(name_, "Config file: " << file_path);
275 
276  return true;
277 }
278 
280  const moveit::core::JointModelGroup* group)
281 {
282  std::vector<std::string> tips;
283  for (std::size_t i = 0; i < arm_datas_.size(); ++i)
284  tips.push_back(arm_datas_[i].ee_link_->getName());
285 
286  // ROS_DEBUG_STREAM_NAMED(name_, "First pose should be for joint model group: " << arm_datas_[0].ee_link_->getName());
287 
288  const double timeout = 1.0 / 30.0; // 30 fps
289 
290  // Optionally collision check
292 #if 1
293  bool collision_checking_verbose_ = false;
294  bool only_check_self_collision_ = false;
295 
296  // TODO(davetcoleman): this is currently not working, the locking seems to cause segfaults
297  // TODO(davetcoleman): change to std shared_ptr
298  boost::scoped_ptr<planning_scene_monitor::LockedPlanningSceneRO> ls;
300  constraint_fn = boost::bind(&isIKStateValid, static_cast<const planning_scene::PlanningSceneConstPtr&>(*ls).get(),
301  collision_checking_verbose_, only_check_self_collision_, visual_tools_, _1, _2, _3);
302 #endif
303 
304  // Solve
305  std::size_t outer_attempts = 20;
306  for (std::size_t i = 0; i < outer_attempts; ++i)
307  {
308  if (!imarker_state_->setFromIK(group, poses, tips, timeout, constraint_fn))
309  {
310  ROS_DEBUG_STREAM_NAMED(name_, "Failed to find dual arm pose, trying again");
311 
312  // Re-seed
313  imarker_state_->setToRandomPositions(group);
314  }
315  else
316  {
317  ROS_DEBUG_STREAM_NAMED(name_, "Found IK solution");
318 
319  // Visualize robot
321 
322  // Update the imarkers
323  for (const IMarkerEndEffectorPtr& ee : end_effectors_)
324  ee->setPoseFromRobotState();
325 
326  return true;
327  }
328  }
329 
330  ROS_ERROR_STREAM_NAMED(name_, "Failed to find dual arm pose");
331  return false;
332 }
333 
334 } // namespace moveit_visual_tools
335 
336 namespace
337 {
338 bool isIKStateValid(const planning_scene::PlanningScene* planning_scene, bool verbose, bool only_check_self_collision,
339  const moveit_visual_tools::MoveItVisualToolsPtr& visual_tools,
340  moveit::core::RobotState* robot_state, const moveit::core::JointModelGroup* group,
341  const double* ik_solution)
342 {
343  // Apply IK solution to robot state
344  robot_state->setJointGroupPositions(group, ik_solution);
345  robot_state->update();
346 
347 #if 0 // Ensure there are objects in the planning scene
348  const std::size_t num_collision_objects = planning_scene->getCollisionWorld()->getWorld()->size();
349  if (num_collision_objects == 0)
350  {
351  ROS_ERROR_STREAM_NAMED("imarker_robot_state", "No collision objects exist in world, you need at least a table "
352  "modeled for the controller to work");
353  ROS_ERROR_STREAM_NAMED("imarker_robot_state", "To fix this, relaunch the teleop/head tracking/whatever MoveIt "
354  "node to publish the collision objects");
355  return false;
356  }
357 #endif
358 
359  if (!planning_scene)
360  {
361  ROS_ERROR_STREAM_NAMED("imarker_robot_state", "No planning scene provided");
362  return false;
363  }
364  if (only_check_self_collision)
365  {
366  // No easy API exists for only checking self-collision, so we do it here.
367  // TODO(davetcoleman): move this into planning_scene.cpp
369  req.verbose = verbose;
370  req.group_name = group->getName();
372  planning_scene->checkSelfCollision(req, res, *robot_state);
373  if (!res.collision)
374  return true; // not in collision
375  }
376  else if (!planning_scene->isStateColliding(*robot_state, group->getName()))
377  return true; // not in collision
378 
379  // Display more info about the collision
380  if (verbose)
381  {
382  visual_tools->publishRobotState(*robot_state, rviz_visual_tools::RED);
383  planning_scene->isStateColliding(*robot_state, group->getName(), true);
384  visual_tools->publishContactPoints(*robot_state, planning_scene);
385  ROS_WARN_STREAM_THROTTLE_NAMED(2.0, "imarker_robot_state", "Collision in IK CC callback");
386  }
387 
388  return false;
389 }
390 
391 } // namespace
void setRobotState(const moveit::core::RobotStatePtr &state)
Set the robot state.
IMarkerRobotState(planning_scene_monitor::PlanningSceneMonitorPtr psm, const std::string &imarker_name, std::vector< ArmData > arm_datas, rviz_visual_tools::colors color, const std::string &package_path)
Constructor.
void setToCurrentState()
Set the robot state to current in planning scene monitor.
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::shared_ptr< MoveItVisualTools > MoveItVisualToolsPtr
#define ROS_ERROR_STREAM_NAMED(name, args)
void robotStateToStream(const RobotState &state, std::ostream &out, bool include_header=true, const std::string &separator=",")
void checkSelfCollision(const collision_detection::CollisionRequest &req, collision_detection::CollisionResult &res)
std::vector< IMarkerEndEffectorPtr > end_effectors_
bool isStateValid(bool verbose=false)
Return true if the currently solved IK solution is valid.
void publishRobotState()
Show current state in Rviz.
#define ROS_ERROR(...)
#define ROS_INFO_STREAM_NAMED(name, args)
bool setToRandomState(double clearance=0)
Set the robot to a random position.
std::shared_ptr< IMarkerEndEffector > IMarkerEndEffectorPtr
bool loadFromFile(const std::string &file_name)
InteractiveMarkerServerPtr imarker_server_
bool verbose
void update(bool force=false)
#define ROS_WARN_STREAM_THROTTLE_NAMED(period, name, args)
std::function< void(const visualization_msgs::InteractiveMarkerFeedbackConstPtr &, const Eigen::Isometry3d &)> IMarkerCallback
bool setFromPoses(const EigenSTL::vector_Isometry3d &poses, const moveit::core::JointModelGroup *group)
const std::string & getName() const
std::map< std::string, IMarkerEndEffectorPtr > name_to_eef_
bool getFilePath(std::string &file_path, const std::string &file_name, const std::string &subdirectory) const
planning_scene_monitor::PlanningSceneMonitorPtr psm_
moveit::core::RobotStatePtr imarker_state_
const std::string & getNamespace() const
void setJointGroupPositions(const std::string &joint_group_name, const double *gstate)
moveit_visual_tools::MoveItVisualToolsPtr visual_tools_
std::vector< Eigen::Isometry3d, Eigen::aligned_allocator< Eigen::Isometry3d > > vector_Isometry3d
void setIMarkerCallback(const IMarkerCallback &callback)
Set where in the parent class the feedback should be sent.
void streamToRobotState(RobotState &state, const std::string &line, const std::string &separator=",")
boost::function< bool(RobotState *robot_state, const JointModelGroup *joint_group, const double *joint_group_variable_values)> GroupStateValidityCallbackFn
moveit_visual_tools::MoveItVisualToolsPtr getVisualTools()
const collision_detection::CollisionWorldConstPtr & getCollisionWorld() const
bool isStateColliding(const std::string &group="", bool verbose=false)
#define ROS_WARN_STREAM_NAMED(name, args)


moveit_visual_tools
Author(s): Dave Coleman
autogenerated on Mon Feb 28 2022 22:51:25