chain_manager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014-2016 Fetch Robotics Inc.
3  * Copyright (C) 2013-2014 Unbounded Robotics Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 // Author: Michael Ferguson
19 
21 
22 namespace robot_calibration
23 {
24 
26  state_is_valid_(false)
27 {
28  // We cannot do much without some kinematic chains
29  if (!nh.hasParam("chains"))
30  {
31  // TODO raise error
32  }
33 
34  // Get chains
35  XmlRpc::XmlRpcValue chains;
36  nh.getParam("chains", chains);
38 
39  // Construct each chain to manage
40  for (int i = 0; i < chains.size(); ++i)
41  {
42  std::string name, topic, group;
43  name = static_cast<std::string>(chains[i]["name"]);
44  group = static_cast<std::string>(chains[i]["planning_group"]);
45 
46  if (chains[i].hasMember("topic"))
47  {
48  topic = static_cast<std::string>(chains[i]["topic"]);
49 
50  boost::shared_ptr<ChainController> controller(new ChainController(name, topic, group));
51 
52  for (int j = 0; j < chains[i]["joints"].size(); ++j)
53  {
54  controller->joint_names.push_back(static_cast<std::string>(chains[i]["joints"][j]));
55  }
56 
57  ROS_INFO("Waiting for %s...", topic.c_str());
58  if (!controller->client.waitForServer(ros::Duration(wait_time)))
59  {
60  ROS_WARN("Failed to connect to %s", topic.c_str());
61  }
62 
63  if (controller->shouldPlan() && (!move_group_))
64  {
65  move_group_.reset(new MoveGroupClient("move_group", true));
66  if (!move_group_->waitForServer(ros::Duration(wait_time)))
67  {
68  ROS_WARN("Failed to connect to move_group");
69  }
70  }
71 
72  controllers_.push_back(controller);
73  }
74  }
75 
76  // Parameter to set movement time
77  nh.param<double>("duration", duration_, 5.0);
78 
79  // Parameter to set velocity scaling factor for move_group
80  nh.param<double>("velocity_factor", velocity_factor_, 1.0);
81 
82  subscriber_ = nh.subscribe("/joint_states", 10, &ChainManager::stateCallback, this);
83 }
84 
85 void ChainManager::stateCallback(const sensor_msgs::JointStateConstPtr& msg)
86 {
87  if (msg->name.size() != msg->position.size())
88  {
89  ROS_ERROR("JointState Error: name array is not same size as position array.");
90  return;
91  }
92 
93  if (msg->position.size() != msg->velocity.size())
94  {
95  ROS_ERROR("JointState Error: position array is not same size as velocity array.");
96  return;
97  }
98 
99  boost::mutex::scoped_lock lock(state_mutex_);
100  // Update each joint based on message
101  for (size_t msg_j = 0; msg_j < msg->name.size(); msg_j++)
102  {
103  size_t state_j;
104  for (state_j = 0; state_j < state_.name.size(); state_j++)
105  {
106  if (state_.name[state_j] == msg->name[msg_j])
107  {
108  state_.position[state_j] = msg->position[msg_j];
109  state_.velocity[state_j] = msg->velocity[msg_j];
110  break;
111  }
112  }
113  if (state_j == state_.name.size())
114  {
115  // New joint
116  state_.name.push_back(msg->name[msg_j]);
117  state_.position.push_back(msg->position[msg_j]);
118  state_.velocity.push_back(msg->velocity[msg_j]);
119  }
120  }
121  state_is_valid_ = true;
122 }
123 
124 bool ChainManager::getState(sensor_msgs::JointState* state)
125 {
126  boost::mutex::scoped_lock lock(state_mutex_);
127  *state = state_;
128  return state_is_valid_;
129 }
130 
131 trajectory_msgs::JointTrajectoryPoint
132 ChainManager::makePoint(const sensor_msgs::JointState& state, const std::vector<std::string>& joints)
133 {
134  trajectory_msgs::JointTrajectoryPoint p;
135  for (size_t i = 0; i < joints.size(); ++i)
136  {
137  for (size_t j = 0; j < state.name.size(); ++j)
138  {
139  if (joints[i] == state.name[j])
140  {
141  p.positions.push_back(state.position[j]);
142  break;
143  }
144  }
145  p.velocities.push_back(0.0);
146  p.accelerations.push_back(0.0);
147  if (p.velocities.size() != p.positions.size())
148  {
149  ROS_ERROR_STREAM("Bad move to state, missing " << joints[i]);
150  exit(-1);
151  }
152  }
153  return p;
154 }
155 
156 bool ChainManager::moveToState(const sensor_msgs::JointState& state)
157 {
158  double max_duration = duration_;
159 
160  // Split into different controllers
161  for (size_t i = 0; i < controllers_.size(); ++i)
162  {
163  control_msgs::FollowJointTrajectoryGoal goal;
164  goal.trajectory.joint_names = controllers_[i]->joint_names;
165 
166  trajectory_msgs::JointTrajectoryPoint p = makePoint(state, controllers_[i]->joint_names);
167  if (controllers_[i]->shouldPlan())
168  {
169  // Call MoveIt
170  moveit_msgs::MoveGroupGoal moveit_goal;
171  moveit_goal.request.group_name = controllers_[i]->chain_planning_group;
172  moveit_goal.request.num_planning_attempts = 1;
173  moveit_goal.request.allowed_planning_time = 5.0;
174 
175  moveit_msgs::Constraints c1;
176  c1.joint_constraints.resize(controllers_[i]->joint_names.size());
177  for (size_t c = 0; c < controllers_[i]->joint_names.size(); c++)
178  {
179  c1.joint_constraints[c].joint_name = controllers_[i]->joint_names[c];
180  c1.joint_constraints[c].position = p.positions[c];
181  c1.joint_constraints[c].tolerance_above = 0.01;
182  c1.joint_constraints[c].tolerance_below = 0.01;
183  c1.joint_constraints[c].weight = 1.0;
184  }
185  moveit_goal.request.goal_constraints.push_back(c1);
186 
187  // Reduce speed
188  moveit_goal.request.max_velocity_scaling_factor = velocity_factor_;
189 
190  // All diffs
191  moveit_goal.request.start_state.is_diff = true;
192  moveit_goal.planning_options.planning_scene_diff.is_diff = true;
193  moveit_goal.planning_options.planning_scene_diff.robot_state.is_diff = true;
194 
195  // Just make the plan, we will execute it
196  moveit_goal.planning_options.plan_only = true;
197 
198  move_group_->sendGoal(moveit_goal);
199  move_group_->waitForResult();
200  MoveGroupResultPtr result = move_group_->getResult();
201  if (result->error_code.val != moveit_msgs::MoveItErrorCodes::SUCCESS)
202  {
203  // Unable to plan, return error
204  return false;
205  }
206 
207  goal.trajectory = result->planned_trajectory.joint_trajectory;
208  max_duration = std::max(max_duration, goal.trajectory.points[goal.trajectory.points.size()-1].time_from_start.toSec());
209  }
210  else
211  {
212  // Go directly to point
213  p.time_from_start = ros::Duration(duration_);
214  goal.trajectory.points.push_back(p);
215  }
216 
217  goal.goal_time_tolerance = ros::Duration(1.0);
218 
219  // Call actions
220  controllers_[i]->client.sendGoal(goal);
221  }
222 
223  // Wait for results
224  for (size_t i = 0; i < controllers_.size(); ++i)
225  {
226  controllers_[i]->client.waitForResult(ros::Duration(max_duration*1.5));
227  // TODO: catch errors with clients
228  }
229 
230  return true;
231 }
232 
234 {
235  sensor_msgs::JointState state;
236 
237  // Reset to invalid so we know state is not stale
238  {
239  boost::mutex::scoped_lock lock(state_mutex_);
240  state_is_valid_ = false;
241  }
242 
243  // TODO: timeout?
244  while (true)
245  {
246  bool settled = true;
247 
248  if (getState(&state))
249  {
250 
251  // For each joint in state message
252  for (size_t j = 0; j < state.name.size(); ++j)
253  {
254  // Is this joint even a concern?
255  if (fabs(state.velocity[j]) < 0.001)
256  continue;
257 
258  for (size_t i = 0; i < controllers_.size(); ++i)
259  {
260  for (size_t k = 0; k < controllers_[i]->joint_names.size(); ++k)
261  {
262  if (controllers_[i]->joint_names[k] == state.name[j])
263  {
264  settled = false;
265  break;
266  }
267  }
268  }
269 
270  // If at least one joint is not settled, break out of this for loop
271  if (!settled)
272  break;
273  }
274  }
275  else
276  {
277  // State is not yet valid, can't determine if settled
278  settled = false;
279  }
280 
281  // If all joints are settled, break out of while loop
282  if (settled)
283  break;
284 
285  ros::spinOnce();
286  }
287 
288  return true;
289 }
290 
291 std::vector<std::string> ChainManager::getChains()
292 {
293  std::vector<std::string> chains;
294  for (size_t i = 0; i < controllers_.size(); ++i)
295  {
296  chains.push_back(controllers_[i]->chain_name);
297  }
298  return chains;
299 }
300 
301 std::vector<std::string> ChainManager::getChainJointNames(
302  const std::string& chain_name)
303 {
304  for (size_t i = 0; i < controllers_.size(); ++i)
305  {
306  if (controllers_[i]->chain_name == chain_name)
307  return controllers_[i]->joint_names;
308  }
309  std::vector<std::string> empty;
310  return empty;
311 }
312 
314  const std::string& chain_name)
315 {
316  for (size_t i = 0; i < controllers_.size(); ++i)
317  {
318  if (controllers_[i]->chain_name == chain_name)
319  return controllers_[i]->chain_planning_group;
320  }
321  std::vector<std::string> empty;
322  return std::string("");
323 }
324 
325 } // namespace robot_calibration
std::string getPlanningGroupName(const std::string &chain_name)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
actionlib::SimpleActionClient< moveit_msgs::MoveGroupAction > MoveGroupClient
Definition: chain_manager.h:40
int size() const
Type const & getType() const
#define ROS_WARN(...)
void stateCallback(const sensor_msgs::JointStateConstPtr &msg)
std::vector< std::string > getChainJointNames(const std::string &chain_name)
Get the joint names associated with a chain. Mainly for testing.
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
sensor_msgs::JointState state_
bool waitToSettle()
Wait for joints to settle.
trajectory_msgs::JointTrajectoryPoint makePoint(const sensor_msgs::JointState &state, const std::vector< std::string > &joints)
Calibration code lives under this namespace.
bool moveToState(const sensor_msgs::JointState &state)
Send commands to all managed joints. The ChainManager automatically figures out which controller to s...
bool getParam(const std::string &key, std::string &s) const
bool getState(sensor_msgs::JointState *state)
Get the current JointState message.
MoveGroupClientPtr move_group_
bool hasParam(const std::string &key) const
#define ROS_ERROR_STREAM(args)
#define ROS_ASSERT(cond)
std::vector< boost::shared_ptr< ChainController > > controllers_
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
std::vector< std::string > getChains()
Get the names of chains. Mainly for testing.
ChainManager(ros::NodeHandle &nh, double wait_time=15.0)
Constructor, sets up chains from ros parameters.


robot_calibration
Author(s): Michael Ferguson
autogenerated on Tue Nov 3 2020 17:30:30