$search
00001 /* 00002 * UOS-ROS packages - Robot Operating System code by the University of Osnabrück 00003 * Copyright (C) 2011 University of Osnabrück 00004 * 00005 * This program is free software; you can redistribute it and/or 00006 * modify it under the terms of the GNU General Public License 00007 * as published by the Free Software Foundation; either version 2 00008 * of the License, or (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program; if not, write to the Free Software 00017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00018 * 00019 * joint_movement_adapter.cpp 00020 * 00021 * Created on: 30.08.2011 00022 * Author: Martin Günther <mguenthe@uos.de> 00023 * 00024 * based on joint_trajectory_generator by Eitan Marder-Eppstein 00025 */ 00026 00027 #include <katana_joint_movement_adapter/joint_movement_adapter.h> 00028 #include <fstream> 00029 #include <iostream> 00030 #include <cstdio> 00031 00032 namespace katana_joint_movement_adapter 00033 { 00034 00035 JointMovementAdapter::JointMovementAdapter(std::string name) : 00036 as_(ros::NodeHandle(), "joint_movement_action", boost::bind(&JointMovementAdapter::executeCB, this, _1), false), 00037 ac_("joint_trajectory_action"), got_state_(false) 00038 { 00039 ros::NodeHandle n; 00040 state_sub_ = n.subscribe("state", 1, &JointMovementAdapter::jointStateCb, this); 00041 00042 ros::NodeHandle pn("~"); 00043 pn.param("max_acc", max_acc_, 0.5); 00044 pn.param("max_vel", max_vel_, 5.0); 00045 00046 // Load Robot Model 00047 ROS_DEBUG("Loading robot model"); 00048 std::string xml_string; 00049 ros::NodeHandle nh_toplevel; 00050 if (!nh_toplevel.getParam(std::string("/robot_description"), xml_string)) 00051 throw ros::Exception("Could not find parameter robot_description on parameter server"); 00052 00053 if (!robot_model_.initString(xml_string)) 00054 throw ros::Exception("Could not parse robot model"); 00055 00056 ros::Rate r(10.0); 00057 while (!got_state_) 00058 { 00059 ros::spinOnce(); 00060 r.sleep(); 00061 } 00062 00063 // gripper_joints_.push_back("katana_r_finger_joint"); 00064 // gripper_joints_.push_back("katana_l_finger_joint"); 00065 00066 ac_.waitForServer(); 00067 as_.start(); 00068 ROS_INFO("%s: Initialized",name.c_str()); 00069 } 00070 00071 JointMovementAdapter::~JointMovementAdapter() 00072 { 00073 } 00074 00075 void JointMovementAdapter::jointStateCb(const pr2_controllers_msgs::JointTrajectoryControllerStateConstPtr& state) 00076 { 00077 boost::mutex::scoped_lock lock(mutex_); 00078 for (unsigned int i = 0; i < state->joint_names.size(); ++i) 00079 { 00080 current_state_[state->joint_names[i]] = state->actual.positions[i]; 00081 } 00082 got_state_ = true; 00083 } 00084 00085 void JointMovementAdapter::executeCB(const JMAS::GoalConstPtr &movement_goal) 00086 { 00087 ROS_DEBUG("Got a goal"); 00088 00089 // note: the SimpleActionServer guarantees that we enter this function only when 00090 // there is no other active goal. in other words, only one instance of executeCB() 00091 // is ever running at the same time. 00092 00093 // ---------- adjust all goal positions to match the given motor limits ---------- 00094 sensor_msgs::JointState limited_joint_states = limitJointStates(movement_goal->jointGoal); 00095 00096 // ---------- transform JointMovement goal to rough JointTrajectory goal ---------- 00097 pr2_controllers_msgs::JointTrajectoryGoal rough_trajectory_goal = makeRoughTrajectory(limited_joint_states); 00098 00099 // ---------- generate full trajectory ---------- 00100 pr2_controllers_msgs::JointTrajectoryGoal full_trajectory_goal; 00101 try 00102 { 00103 full_trajectory_goal = makeFullTrajectory(rough_trajectory_goal); 00104 } 00105 catch (ros::Exception ex) 00106 { 00107 ROS_ERROR_STREAM(ex.what()); 00108 as_.setAborted(); 00109 return; 00110 } 00111 00112 // ---------- send goal to action client ---------- 00113 ac_.sendGoal(full_trajectory_goal); 00114 00115 // ---------- wait for action client to finish---------- 00116 while (ros::ok() && !ac_.waitForResult(ros::Duration(0.05))) 00117 { 00118 if (as_.isPreemptRequested()) 00119 { 00120 ROS_DEBUG("Preempted"); 00121 ac_.cancelGoal(); 00122 } 00123 } 00124 00125 // ---------- check if node was killed ---------- 00126 if (!ros::ok()) 00127 { 00128 as_.setAborted(); 00129 return; 00130 } 00131 00132 // ---------- pass on terminal state from action client to action server ---------- 00133 actionlib::SimpleClientGoalState state = ac_.getState(); 00134 00135 if (state == actionlib::SimpleClientGoalState::PREEMPTED) 00136 { 00137 ROS_DEBUG("Preempted"); 00138 as_.setPreempted(); 00139 } 00140 else if (state == actionlib::SimpleClientGoalState::SUCCEEDED) 00141 { 00142 ROS_DEBUG("Succeeded"); 00143 as_.setSucceeded(); 00144 } 00145 else if (state == actionlib::SimpleClientGoalState::ABORTED) 00146 { 00147 ROS_DEBUG("Aborted"); 00148 as_.setAborted(); 00149 } 00150 else 00151 as_.setAborted(katana_msgs::JointMovementResult(), "Unknown result from joint_trajectory_action"); 00152 } 00153 00154 pr2_controllers_msgs::JointTrajectoryGoal JointMovementAdapter::makeRoughTrajectory( 00155 const sensor_msgs::JointState &jointGoal) 00156 { 00157 pr2_controllers_msgs::JointTrajectoryGoal result; 00158 00159 if (jointGoal.name.size() != jointGoal.position.size()) 00160 ROS_FATAL("joint goal: name and position array have different size!"); 00161 00162 // copy current state to make sure every joint has a target 00163 std::map<std::string, double> target_state = std::map<std::string, double>(current_state_); 00164 00165 // overwrite with positions from joint goal (can be only some of the joints) 00166 for (size_t i = 0; i < jointGoal.name.size(); ++i) 00167 { 00168 if (target_state.find(jointGoal.name[i]) == target_state.end()) 00169 ROS_WARN("joint name %s is not one of our controlled joints, ignoring", jointGoal.name[i].c_str()); 00170 else 00171 target_state[jointGoal.name[i]] = jointGoal.position[i]; 00172 } 00173 00174 // create a joint trajectory with only one trajectory point (the target); 00175 // the proper start point will be inserted by makeFullTrajectory() 00176 result.trajectory.header = jointGoal.header; 00177 result.trajectory.points.resize(1); 00178 00179 // set the time at which the target should be reached to 0.0 seconds after start; 00180 // this will be adjusted by makeFullTrajectory() 00181 result.trajectory.points[0].time_from_start = ros::Duration(0.0); 00182 00183 // copy positions to target 00184 for (std::map<std::string, double>::iterator it = target_state.begin(); it != target_state.end(); ++it) 00185 { 00186 result.trajectory.joint_names.push_back(it->first); 00187 result.trajectory.points[0].positions.push_back(it->second); 00188 00189 // we want the arm to stop at the target (ignore velocities and accelerations from joint goal); 00190 // this is a requirement for the applicability of makeFullTrajectory(). 00191 result.trajectory.points[0].velocities.push_back(0.0); 00192 result.trajectory.points[0].accelerations.push_back(0.0); 00193 } 00194 00195 return result; 00196 } 00197 00198 pr2_controllers_msgs::JointTrajectoryGoal JointMovementAdapter::makeFullTrajectory( 00199 const pr2_controllers_msgs::JointTrajectoryGoal& goal) 00200 { 00201 pr2_controllers_msgs::JointTrajectoryGoal new_goal; 00202 new_goal.trajectory.header = goal.trajectory.header; 00203 new_goal.trajectory.joint_names = goal.trajectory.joint_names; 00204 00205 size_t n_traj_points = goal.trajectory.points.size(), n_joint_names = goal.trajectory.joint_names.size(); 00206 00207 // Increase traj length to account for the initial pose 00208 ROS_DEBUG_STREAM("Initial trajectory has "<<n_traj_points<<" points."); 00209 new_goal.trajectory.points.resize(n_traj_points + 1); 00210 00211 // Set joint names 00212 for (size_t i = 0; i < n_traj_points + 1; i++) 00213 { 00214 new_goal.trajectory.points[i].positions.resize(n_joint_names); 00215 } 00216 00217 { 00218 boost::mutex::scoped_lock lock(mutex_); 00219 //add the current point as the start of the trajectory 00220 for (unsigned int i = 0; i < n_joint_names; ++i) 00221 { 00222 // Generate the first point 00223 if (current_state_.find(new_goal.trajectory.joint_names[i]) == current_state_.end()) 00224 { 00225 ROS_FATAL_STREAM("Joint names in goal and controller don't match. Something is very wrong. Goal joint name: "<<new_goal.trajectory.joint_names[i]); 00226 throw std::runtime_error("Joint names in goal and controller don't match. Something is very wrong."); 00227 } 00228 new_goal.trajectory.points[0].positions[i] = current_state_[new_goal.trajectory.joint_names[i]]; 00229 00230 // Get the joint and calculate the offset from the current state 00231 boost::shared_ptr<const urdf::Joint> joint = robot_model_.getJoint(new_goal.trajectory.joint_names[i]); 00232 double offset = 0; 00233 00234 double goal_position = goal.trajectory.points[0].positions[i], current_position = 00235 new_goal.trajectory.points[0].positions[i]; 00236 00237 if (joint->type == urdf::Joint::REVOLUTE) 00238 { 00239 offset = 0; 00240 } 00241 else if (joint->type == urdf::Joint::CONTINUOUS) 00242 { 00243 offset = current_position - goal_position - angles::shortest_angular_distance(goal_position, current_position); 00244 } 00245 else 00246 { 00247 ROS_WARN("Unknown joint type in joint trajectory. This joint might not be unwrapped properly. Supported joint types are urdf::Joint::REVOLUTE and urdf::Joint::CONTINUOUS"); 00248 offset = 0; 00249 } 00250 00251 // Apply offset to each point in the trajectory on this joint 00252 for (unsigned int j = 0; j < n_traj_points; j++) 00253 { 00254 new_goal.trajectory.points[j + 1].time_from_start = goal.trajectory.points[j].time_from_start; 00255 new_goal.trajectory.points[j + 1].positions[i] = goal.trajectory.points[j].positions[i] + offset; 00256 } 00257 } 00258 } 00259 00260 // pass into trajectory generator here 00261 trajectory::TrajectoryGenerator g(max_vel_, max_acc_, new_goal.trajectory.joint_names.size()); 00262 00263 // do the trajectory generation 00264 g.generate(new_goal.trajectory, new_goal.trajectory); 00265 00266 return new_goal; 00267 } 00268 00269 sensor_msgs::JointState JointMovementAdapter::limitJointStates(const sensor_msgs::JointState &jointGoal) 00270 { 00271 sensor_msgs::JointState adjustedJointGoal; 00272 00273 adjustedJointGoal.name = jointGoal.name; 00274 adjustedJointGoal.position = jointGoal.position; 00275 00276 // for (size_t i = 0; i < jointGoal.name.size(); i++) 00277 // { 00278 // ROS_DEBUG("%s - min: %f - max: %f - curr: % f - req: %f", jointGoal.name[i].c_str(), getMotorLimitMin(jointGoal.name[i]), getMotorLimitMax(jointGoal.name[i]), katana_->getMotorAngles()[katana_->getJointIndex(jointGoal.name[i])], jointGoal.position[i]); 00279 // } 00280 00281 for (size_t i = 0; i < jointGoal.name.size(); i++) 00282 { 00283 boost::shared_ptr<const urdf::Joint> joint = robot_model_.getJoint(jointGoal.name[i]); 00284 if (!joint) 00285 ROS_FATAL("Joint %s not found in URDF!", jointGoal.name[i].c_str()); 00286 00287 if (jointGoal.position[i] < joint->limits->lower) 00288 { 00289 adjustedJointGoal.position[i] = joint->limits->lower; 00290 } 00291 00292 if (jointGoal.position[i] > joint->limits->upper) 00293 { 00294 adjustedJointGoal.position[i] = joint->limits->upper; 00295 } 00296 } 00297 00298 return adjustedJointGoal; 00299 } 00300 } 00301 00302 int main(int argc, char** argv) 00303 { 00304 ros::init(argc, argv, "joint_movement_adapter"); 00305 katana_joint_movement_adapter::JointMovementAdapter jma(ros::this_node::getName()); 00306 00307 ros::spin(); 00308 00309 return 0; 00310 }