joint_movement_adapter.cpp
Go to the documentation of this file.
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 }


katana_joint_movement_adapter
Author(s): Martin Günther
autogenerated on Mon Oct 6 2014 10:47:13