joint_with_effort_trajectory_controller_impl.h
Go to the documentation of this file.
00001 //
00002 // Created by tom on 18/09/16.
00003 //
00004 
00005 #ifndef ROBOTICAN_CONTROLLERS_JOINT_WITH_EFFORT_TRAJECTORY_CONTROLLER_IMPL_H
00006 #define ROBOTICAN_CONTROLLERS_JOINT_WITH_EFFORT_TRAJECTORY_CONTROLLER_IMPL_H
00007 
00008 namespace joint_with_effort_trajectory_controller
00009 {
00010 
00011     namespace internal
00012     {
00013 
00014         template <class Enclosure, class Member>
00015         inline boost::shared_ptr<Member> share_member(boost::shared_ptr<Enclosure> enclosure, Member &member)
00016         {
00017             actionlib::EnclosureDeleter<Enclosure> d(enclosure);
00018             boost::shared_ptr<Member> p(&member, d);
00019             return p;
00020         }
00021 
00022         std::vector<std::string> getStrings(const ros::NodeHandle& nh, const std::string& param_name)
00023         {
00024             using namespace XmlRpc;
00025             XmlRpcValue xml_array;
00026             if (!nh.getParam(param_name, xml_array))
00027             {
00028                 ROS_ERROR_STREAM("Could not find '" << param_name << "' parameter (namespace: " << nh.getNamespace() << ").");
00029                 return std::vector<std::string>();
00030             }
00031             if (xml_array.getType() != XmlRpcValue::TypeArray)
00032             {
00033                 ROS_ERROR_STREAM("The '" << param_name << "' parameter is not an array (namespace: " <<
00034                                          nh.getNamespace() << ").");
00035                 return std::vector<std::string>();
00036             }
00037 
00038             std::vector<std::string> out;
00039             for (int i = 0; i < xml_array.size(); ++i)
00040             {
00041                 if (xml_array[i].getType() != XmlRpcValue::TypeString)
00042                 {
00043                     ROS_ERROR_STREAM("The '" << param_name << "' parameter contains a non-string element (namespace: " <<
00044                                              nh.getNamespace() << ").");
00045                     return std::vector<std::string>();
00046                 }
00047                 out.push_back(static_cast<std::string>(xml_array[i]));
00048             }
00049             return out;
00050         }
00051 
00052         boost::shared_ptr<urdf::Model> getUrdf(const ros::NodeHandle& nh, const std::string& param_name)
00053         {
00054             boost::shared_ptr<urdf::Model> urdf(new urdf::Model);
00055 
00056             std::string urdf_str;
00057             // Check for robot_description in proper namespace
00058             if (nh.getParam(param_name, urdf_str))
00059             {
00060                 if (!urdf->initString(urdf_str))
00061                 {
00062                     ROS_ERROR_STREAM("Failed to parse URDF contained in '" << param_name << "' parameter (namespace: " <<
00063                                                                            nh.getNamespace() << ").");
00064                     return boost::shared_ptr<urdf::Model>();
00065                 }
00066             }
00067                 // Check for robot_description in root
00068             else if (!urdf->initParam("robot_description"))
00069             {
00070                 ROS_ERROR_STREAM("Failed to parse URDF contained in '" << param_name << "' parameter");
00071                 return boost::shared_ptr<urdf::Model>();
00072             }
00073             return urdf;
00074         }
00075 
00076         typedef boost::shared_ptr<const urdf::Joint> UrdfJointConstPtr;
00077         std::vector<UrdfJointConstPtr> getUrdfJoints(const urdf::Model& urdf, const std::vector<std::string>& joint_names)
00078         {
00079             std::vector<UrdfJointConstPtr> out;
00080             for (unsigned int i = 0; i < joint_names.size(); ++i)
00081             {
00082                 UrdfJointConstPtr urdf_joint = urdf.getJoint(joint_names[i]);
00083                 if (urdf_joint)
00084                 {
00085                     out.push_back(urdf_joint);
00086                 }
00087                 else
00088                 {
00089                     ROS_ERROR_STREAM("Could not find joint '" << joint_names[i] << "' in URDF model.");
00090                     return std::vector<UrdfJointConstPtr>();
00091                 }
00092             }
00093             return out;
00094         }
00095 
00096         std::string getLeafNamespace(const ros::NodeHandle& nh)
00097         {
00098             const std::string complete_ns = nh.getNamespace();
00099             std::size_t id   = complete_ns.find_last_of("/");
00100             return complete_ns.substr(id + 1);
00101         }
00102 
00103     } // namespace
00104 
00105     template <class SegmentImpl, class HardwareInterface>
00106     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00107     starting(const ros::Time& time)
00108     {
00109         // Update time data
00110         TimeData time_data;
00111         time_data.time   = time;
00112         time_data.uptime = ros::Time(0.0);
00113         time_data_.initRT(time_data);
00114 
00115         // Hold current position
00116         setHoldPosition(time_data.uptime);
00117 
00118         // Initialize last state update time
00119         last_state_publish_time_ = time_data.uptime;
00120 
00121         // Hardware interface adapter
00122         hw_iface_adapter_.starting(time_data.uptime);
00123     }
00124 
00125     template <class SegmentImpl, class HardwareInterface>
00126     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00127     stopping(const ros::Time& /*time*/)
00128     {
00129         preemptActiveGoal();
00130     }
00131 
00132     template <class SegmentImpl, class HardwareInterface>
00133     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00134     trajectoryCommandCB(const JointTrajectoryConstPtr& msg)
00135     {
00136         const bool update_ok = updateTrajectoryCommand(msg, RealtimeGoalHandlePtr());
00137         if (update_ok) {preemptActiveGoal();}
00138     }
00139 
00140     template <class SegmentImpl, class HardwareInterface>
00141     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00142     preemptActiveGoal()
00143     {
00144         RealtimeGoalHandlePtr current_active_goal(rt_active_goal_);
00145 
00146         // Cancels the currently active goal
00147         if (current_active_goal)
00148         {
00149             // Marks the current goal as canceled
00150             rt_active_goal_.reset();
00151             current_active_goal->gh_.setCanceled();
00152         }
00153     }
00154 
00155     template <class SegmentImpl, class HardwareInterface>
00156     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00157     checkPathTolerances(const typename Segment::State& state_error,
00158                         const Segment&                 segment)
00159     {
00160         const RealtimeGoalHandlePtr rt_segment_goal = segment.getGoalHandle();
00161         const SegmentTolerances<Scalar>& tolerances = segment.getTolerances();
00162         ROS_INFO("CUR: %f, Goal: %f", _currentEffort, _goalEffort);
00163         if(_goalEffort != 0 && _currentEffort > _goalEffort) {
00164             ROS_INFO("MAX effort");
00165             rt_segment_goal->preallocated_result_->error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
00166             rt_segment_goal->setSucceeded(rt_segment_goal->preallocated_result_);
00167             rt_active_goal_.reset();
00168         }
00169         else if (!checkStateTolerance(state_error, tolerances.state_tolerance))
00170         {
00171             rt_segment_goal->preallocated_result_->error_code =
00172                     control_msgs::FollowJointTrajectoryResult::PATH_TOLERANCE_VIOLATED;
00173             rt_segment_goal->setAborted(rt_segment_goal->preallocated_result_);
00174             rt_active_goal_.reset();
00175         }
00176     }
00177 
00178     template <class SegmentImpl, class HardwareInterface>
00179     inline void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00180     checkGoalTolerances(const typename Segment::State& state_error,
00181                         const Segment&                 segment)
00182     {
00183         // Controller uptime
00184         const ros::Time uptime = time_data_.readFromRT()->uptime;
00185 
00186         // Checks that we have ended inside the goal tolerances
00187         const RealtimeGoalHandlePtr rt_segment_goal = segment.getGoalHandle();
00188         const SegmentTolerances<Scalar>& tolerances = segment.getTolerances();
00189         const bool inside_goal_tolerances = checkStateTolerance(state_error, tolerances.goal_state_tolerance);
00190 
00191         if (inside_goal_tolerances || (_goalEffort != 0 && _currentEffort >= _goalEffort))
00192         {
00193             rt_segment_goal->preallocated_result_->error_code = control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
00194             rt_segment_goal->setSucceeded(rt_segment_goal->preallocated_result_);
00195             rt_active_goal_.reset();
00196             if(_goalEffort != 0 && _currentEffort >= _goalEffort) {
00197                 ROS_INFO("MAX effort");
00198             }
00199         }
00200         else if (uptime.toSec() < segment.endTime() + tolerances.goal_time_tolerance)
00201         {
00202             // Still have some time left to meet the goal state tolerances
00203         }
00204         else
00205         {
00206             if (verbose_)
00207             {
00208                 ROS_ERROR_STREAM_NAMED(name_,"Goal tolerances failed");
00209                 // Check the tolerances one more time to output the errors that occures
00210                 checkStateTolerance(state_error, tolerances.goal_state_tolerance, true);
00211             }
00212 
00213             rt_segment_goal->preallocated_result_->error_code = control_msgs::FollowJointTrajectoryResult::GOAL_TOLERANCE_VIOLATED;
00214             rt_segment_goal->setAborted(rt_segment_goal->preallocated_result_);
00215             rt_active_goal_.reset();
00216         }
00217     }
00218 
00219     template <class SegmentImpl, class HardwareInterface>
00220     JointTrajectoryController<SegmentImpl, HardwareInterface>::
00221     JointTrajectoryController()
00222             : verbose_(false), // Set to true during debugging
00223               hold_trajectory_ptr_(new Trajectory)
00224     {}
00225 
00226     template <class SegmentImpl, class HardwareInterface>
00227     bool JointTrajectoryController<SegmentImpl, HardwareInterface>::init(HardwareInterface* hw,
00228                                                                          ros::NodeHandle&   root_nh,
00229                                                                          ros::NodeHandle&   controller_nh)
00230     {
00231         using namespace internal;
00232         // Cache controller node handle
00233         controller_nh_ = controller_nh;
00234 
00235         // Controller name
00236         name_ = getLeafNamespace(controller_nh_);
00237 
00238         // State publish rate
00239         double state_publish_rate = 50.0;
00240         controller_nh_.getParam("state_publish_rate", state_publish_rate);
00241         ROS_DEBUG_STREAM_NAMED(name_, "Controller state will be published at " << state_publish_rate << "Hz.");
00242         state_publisher_period_ = ros::Duration(1.0 / state_publish_rate);
00243 
00244         // Action status checking update rate
00245         double action_monitor_rate = 20.0;
00246         controller_nh_.getParam("action_monitor_rate", action_monitor_rate);
00247         action_monitor_period_ = ros::Duration(1.0 / action_monitor_rate);
00248         ROS_DEBUG_STREAM_NAMED(name_, "Action status changes will be monitored at " << action_monitor_rate << "Hz.");
00249 
00250         // Stop trajectory duration
00251         stop_trajectory_duration_ = 0.0;
00252         _currentEffort = 0;
00253         if (!controller_nh_.getParam("stop_trajectory_duration", stop_trajectory_duration_))
00254         {
00255             // TODO: Remove this check/warning in Indigo
00256             if (controller_nh_.getParam("hold_trajectory_duration", stop_trajectory_duration_))
00257             {
00258                 ROS_WARN("The 'hold_trajectory_duration' has been deprecated in favor of the 'stop_trajectory_duration' parameter. Please update your controller configuration.");
00259             }
00260         }
00261         ROS_DEBUG_STREAM_NAMED(name_, "Stop trajectory has a duration of " << stop_trajectory_duration_ << "s.");
00262 
00263         // List of controlled joints
00264         joint_names_ = getStrings(controller_nh_, "joints");
00265         if (joint_names_.empty()) {return false;}
00266         const unsigned int n_joints = joint_names_.size();
00267 
00268         // URDF joints
00269         boost::shared_ptr<urdf::Model> urdf = getUrdf(root_nh, "robot_description");
00270         if (!urdf) {return false;}
00271 
00272         std::vector<UrdfJointConstPtr> urdf_joints = getUrdfJoints(*urdf, joint_names_);
00273         if (urdf_joints.empty()) {return false;}
00274         assert(n_joints == urdf_joints.size());
00275 
00276         // Initialize members
00277         joints_.resize(n_joints);
00278         angle_wraparound_.resize(n_joints);
00279         for (unsigned int i = 0; i < n_joints; ++i)
00280         {
00281             // Joint handle
00282             try {joints_[i] = hw->getHandle(joint_names_[i]);}
00283             catch (...)
00284             {
00285                 ROS_ERROR_STREAM_NAMED(name_, "Could not find joint '" << joint_names_[i] << "' in '" <<
00286                                                                        this->getHardwareInterfaceType() << "'.");
00287                 return false;
00288             }
00289 
00290             // Whether a joint is continuous (ie. has angle wraparound)
00291             angle_wraparound_[i] = urdf_joints[i]->type == urdf::Joint::CONTINUOUS;
00292             const std::string not_if = angle_wraparound_[i] ? "" : "non-";
00293 
00294             ROS_DEBUG_STREAM_NAMED(name_, "Found " << not_if << "continuous joint '" << joint_names_[i] << "' in '" <<
00295                                                    this->getHardwareInterfaceType() << "'.");
00296         }
00297 
00298         assert(joints_.size() == angle_wraparound_.size());
00299         ROS_DEBUG_STREAM_NAMED(name_, "Initialized controller '" << name_ << "' with:" <<
00300                                                                  "\n- Number of joints: " << joints_.size() <<
00301                                                                  "\n- Hardware interface type: '" << this->getHardwareInterfaceType() << "'" <<
00302                                                                  "\n- Trajectory segment type: '" << hardware_interface::internal::demangledTypeName<SegmentImpl>() << "'");
00303 
00304         // Default tolerances
00305         ros::NodeHandle tol_nh(controller_nh_, "constraints");
00306         default_tolerances_ = getSegmentTolerances<Scalar>(tol_nh, joint_names_);
00307 
00308         // Hardware interface adapter
00309         hw_iface_adapter_.init(joints_, controller_nh_);
00310 
00311         // ROS API: Subscribed topics
00312         trajectory_command_sub_ = controller_nh_.subscribe("command", 1, &JointTrajectoryController::trajectoryCommandCB, this);
00313 
00314         // ROS API: Published topics
00315         state_publisher_.reset(new StatePublisher(controller_nh_, "state", 1));
00316 
00317         // ROS API: Action interface
00318         action_server_.reset(new ActionServer(controller_nh_, "follow_joint_trajectory",
00319                                               boost::bind(&JointTrajectoryController::goalCB,   this, _1),
00320                                               boost::bind(&JointTrajectoryController::cancelCB, this, _1),
00321                                               false));
00322         action_server_->start();
00323 
00324         // ROS API: Provided services
00325         query_state_service_ = controller_nh_.advertiseService("query_state",
00326                                                                &JointTrajectoryController::queryStateService,
00327                                                                this);
00328 
00329         // Preeallocate resources
00330         current_state_    = typename Segment::State(n_joints);
00331         desired_state_    = typename Segment::State(n_joints);
00332         state_error_      = typename Segment::State(n_joints);
00333         hold_start_state_ = typename Segment::State(n_joints);
00334         hold_end_state_   = typename Segment::State(n_joints);
00335 
00336         Segment hold_segment(0.0, current_state_, 0.0, current_state_);
00337         hold_trajectory_ptr_->resize(1, hold_segment);
00338 
00339         {
00340             state_publisher_->lock();
00341             state_publisher_->msg_.joint_names = joint_names_;
00342             state_publisher_->msg_.desired.positions.resize(n_joints);
00343             state_publisher_->msg_.desired.velocities.resize(n_joints);
00344             state_publisher_->msg_.desired.accelerations.resize(n_joints);
00345             state_publisher_->msg_.actual.positions.resize(n_joints);
00346             state_publisher_->msg_.actual.velocities.resize(n_joints);
00347             state_publisher_->msg_.error.positions.resize(n_joints);
00348             state_publisher_->msg_.error.velocities.resize(n_joints);
00349             state_publisher_->unlock();
00350         }
00351 
00352         return true;
00353     }
00354 
00355     template <class SegmentImpl, class HardwareInterface>
00356     void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00357     update(const ros::Time& time, const ros::Duration& period)
00358     {
00359         // Get currently followed trajectory
00360         TrajectoryPtr curr_traj_ptr;
00361         curr_trajectory_box_.get(curr_traj_ptr);
00362         Trajectory& curr_traj = *curr_traj_ptr;
00363 
00364         // Update time data
00365         TimeData time_data;
00366         time_data.time   = time;                                     // Cache current time
00367         time_data.period = period;                                   // Cache current control period
00368         time_data.uptime = time_data_.readFromRT()->uptime + period; // Update controller uptime
00369         time_data_.writeFromNonRT(time_data); // TODO: Grrr, we need a lock-free data structure here!
00370 
00371         // NOTE: It is very important to execute the two above code blocks in the specified sequence: first get current
00372         // trajectory, then update time data. Hopefully the following paragraph sheds a bit of light on the rationale.
00373         // The non-rt thread responsible for processing new commands enqueues trajectories that can start at the _next_
00374         // control cycle (eg. zero start time) or later (eg. when we explicitly request a start time in the future).
00375         // If we reverse the order of the two blocks above, and update the time data first; it's possible that by the time we
00376         // fetch the currently followed trajectory, it has been updated by the non-rt thread with something that starts in the
00377         // next control cycle, leaving the current cycle without a valid trajectory.
00378 
00379         // Update desired state: sample trajectory at current time
00380         typename Trajectory::const_iterator segment_it = sample(curr_traj, time_data.uptime.toSec(), desired_state_);
00381         if (curr_traj.end() == segment_it)
00382         {
00383             // Non-realtime safe, but should never happen under normal operation
00384             ROS_ERROR_NAMED(name_,
00385                             "Unexpected error: No trajectory defined at current time. Please contact the package maintainer.");
00386             return;
00387         }
00388 
00389         // Update current state and state error
00390         double maxCurrentEffort = -100.0;
00391         for (unsigned int i = 0; i < joints_.size(); ++i)
00392         {
00393             current_state_.position[i] = joints_[i].getPosition();
00394             current_state_.velocity[i] = joints_[i].getVelocity();
00395             maxCurrentEffort = (maxCurrentEffort <= joints_[i].getEffort()) ? joints_[i].getEffort() : maxCurrentEffort;
00396             // There's no acceleration data available in a joint handle
00397 
00398             state_error_.position[i] = desired_state_.position[i] - current_state_.position[i];
00399             state_error_.velocity[i] = desired_state_.velocity[i] - current_state_.velocity[i];
00400             state_error_.acceleration[i] = 0.0;
00401         }
00402         _currentEffort = maxCurrentEffort;
00403         // Check tolerances if segment corresponds to currently active action goal
00404         const RealtimeGoalHandlePtr rt_segment_goal = segment_it->getGoalHandle();
00405         if (rt_segment_goal && rt_segment_goal == rt_active_goal_)
00406         {
00407             // Check tolerances
00408             if (time_data.uptime.toSec() < segment_it->endTime())
00409             {
00410                 // Currently executing a segment: check path tolerances
00411                 checkPathTolerances(state_error_,
00412                                     *segment_it);
00413             }
00414             else if (segment_it == --curr_traj.end())
00415             {
00416                 if (verbose_)
00417                     ROS_DEBUG_STREAM_THROTTLE_NAMED(1,name_,"Finished executing last segement, checking goal tolerances");
00418 
00419                 // Finished executing the LAST segment: check goal tolerances
00420                 checkGoalTolerances(state_error_,
00421                                     *segment_it);
00422             }
00423         }
00424 
00425         // Hardware interface adapter: Generate and send commands
00426         hw_iface_adapter_.updateCommand(time_data.uptime, time_data.period,
00427                                         desired_state_, state_error_);
00428 
00429         // Publish state
00430         publishState(time_data.uptime);
00431     }
00432 
00433     template <class SegmentImpl, class HardwareInterface>
00434     bool JointTrajectoryController<SegmentImpl, HardwareInterface>::
00435     updateTrajectoryCommand(const JointTrajectoryConstPtr& msg, RealtimeGoalHandlePtr gh)
00436     {
00437         typedef InitJointTrajectoryOptions<Trajectory> Options;
00438 
00439         // Preconditions
00440         if (!this->isRunning())
00441         {
00442             ROS_ERROR_NAMED(name_, "Can't accept new commands. Controller is not running.");
00443             return false;
00444         }
00445 
00446         if (!msg)
00447         {
00448             ROS_WARN_NAMED(name_, "Received null-pointer trajectory message, skipping.");
00449             return false;
00450         }
00451 
00452         // Time data
00453         TimeData* time_data = time_data_.readFromRT(); // TODO: Grrr, we need a lock-free data structure here!
00454 
00455         // Time of the next update
00456         const ros::Time next_update_time = time_data->time + time_data->period;
00457 
00458         // Uptime of the next update
00459         ros::Time next_update_uptime = time_data->uptime + time_data->period;
00460 
00461         // Hold current position if trajectory is empty
00462         if (msg->points.empty())
00463         {
00464             setHoldPosition(time_data->uptime);
00465             ROS_DEBUG_NAMED(name_, "Empty trajectory command, stopping.");
00466             return true;
00467         }
00468 
00469         // Trajectory initialization options
00470         TrajectoryPtr curr_traj_ptr;
00471         curr_trajectory_box_.get(curr_traj_ptr);
00472 
00473         Options options;
00474         options.other_time_base    = &next_update_uptime;
00475         options.current_trajectory = curr_traj_ptr.get();
00476         options.joint_names        = &joint_names_;
00477         options.angle_wraparound   = &angle_wraparound_;
00478         options.rt_goal_handle     = gh;
00479         options.default_tolerances = &default_tolerances_;
00480 
00481         // Update currently executing trajectory
00482         try
00483         {
00484             TrajectoryPtr traj_ptr(new Trajectory);
00485             *traj_ptr = initJointTrajectory<Trajectory>(*msg, next_update_time, options);
00486             if (!traj_ptr->empty())
00487             {
00488                 curr_trajectory_box_.set(traj_ptr);
00489             }
00490             else
00491             {
00492                 // All trajectory points are in the past, nothing new to execute. Keep on executing current trajectory
00493                 return false;
00494             }
00495         }
00496         catch(const std::invalid_argument& ex)
00497         {
00498             ROS_ERROR_STREAM_NAMED(name_, ex.what());
00499             return false;
00500         }
00501         catch(...)
00502         {
00503             ROS_ERROR_NAMED(name_, "Unexpected exception caught when initializing trajectory from ROS message data.");
00504             return false;
00505         }
00506 
00507         return true;
00508     }
00509 
00510     template <class SegmentImpl, class HardwareInterface>
00511     void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00512     goalCB(GoalHandle gh)
00513     {
00514         ROS_DEBUG_STREAM_NAMED(name_,"Recieved new action goal");
00515 
00516         // Precondition: Running controller
00517         if (!this->isRunning())
00518         {
00519             ROS_ERROR_NAMED(name_, "Can't accept new action goals. Controller is not running.");
00520             control_msgs::FollowJointTrajectoryResult result;
00521             result.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL; // TODO: Add better error status to msg?
00522             gh.setRejected(result);
00523             return;
00524         }
00525 
00526         // Goal should specify all controller joints (they can be ordered differently). Reject if this is not the case
00527         using joint_trajectory_controller::internal::permutation;
00528         std::vector<unsigned int> permutation_vector = permutation(joint_names_, gh.getGoal()->trajectory.joint_names);
00529 
00530         if (permutation_vector.empty())
00531         {
00532             ROS_ERROR_NAMED(name_, "Joints on incoming goal don't match the controller joints.");
00533             control_msgs::FollowJointTrajectoryResult result;
00534             result.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_JOINTS;
00535             gh.setRejected(result);
00536             return;
00537         }
00538 
00539         // Try to update new trajectory
00540         RealtimeGoalHandlePtr rt_goal(new RealtimeGoalHandle(gh));
00541         const bool update_ok = updateTrajectoryCommand(internal::share_member(gh.getGoal(), gh.getGoal()->trajectory),
00542                                                        rt_goal);
00543 
00544         if (update_ok)
00545         {
00546             // Accept new goal
00547             preemptActiveGoal();
00548             gh.setAccepted();
00549             rt_active_goal_ = rt_goal;
00550             size_t  size = rt_goal->gh_.getGoal()->trajectory.points.size();
00551             if(!rt_goal->gh_.getGoal()->trajectory.points.empty() && !rt_goal->gh_.getGoal()->trajectory.points[size - 1].effort.empty()) {
00552 
00553                 _goalEffort = rt_goal->gh_.getGoal()->trajectory.points[size - 1].effort[0];
00554                 ROS_INFO("goal effort is: %f", _goalEffort);
00555             } else {
00556                 _goalEffort = 0.0;
00557             }
00558             // Setup goal status checking timer
00559             goal_handle_timer_ = controller_nh_.createTimer(action_monitor_period_,
00560                                                             &RealtimeGoalHandle::runNonRealtime,
00561                                                             rt_goal);
00562             goal_handle_timer_.start();
00563         }
00564         else
00565         {
00566             // Reject invalid goal
00567             control_msgs::FollowJointTrajectoryResult result;
00568             result.error_code = control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
00569             gh.setRejected(result);
00570         }
00571     }
00572 
00573     template <class SegmentImpl, class HardwareInterface>
00574     void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00575     cancelCB(GoalHandle gh)
00576     {
00577         RealtimeGoalHandlePtr current_active_goal(rt_active_goal_);
00578 
00579         // Check that cancel request refers to currently active goal (if any)
00580         if (current_active_goal && current_active_goal->gh_ == gh)
00581         {
00582             // Reset current goal
00583             rt_active_goal_.reset();
00584 
00585             // Controller uptime
00586             const ros::Time uptime = time_data_.readFromRT()->uptime;
00587 
00588             // Enter hold current position mode
00589             setHoldPosition(uptime);
00590             ROS_DEBUG_NAMED(name_, "Canceling active action goal because cancel callback recieved from actionlib.");
00591 
00592             // Mark the current goal as canceled
00593             current_active_goal->gh_.setCanceled();
00594         }
00595     }
00596 
00597     template <class SegmentImpl, class HardwareInterface>
00598     bool JointTrajectoryController<SegmentImpl, HardwareInterface>::
00599     queryStateService(control_msgs::QueryTrajectoryState::Request&  req,
00600                       control_msgs::QueryTrajectoryState::Response& resp)
00601     {
00602         // Preconditions
00603         if (!this->isRunning())
00604         {
00605             ROS_ERROR_NAMED(name_, "Can't sample trajectory. Controller is not running.");
00606             return false;
00607         }
00608 
00609         // Convert request time to internal monotonic representation
00610         TimeData* time_data = time_data_.readFromRT();
00611         const ros::Duration time_offset = req.time - time_data->time;
00612         const ros::Time sample_time = time_data->uptime + time_offset;
00613 
00614         // Sample trajectory at requested time
00615         TrajectoryPtr curr_traj_ptr;
00616         curr_trajectory_box_.get(curr_traj_ptr);
00617         Trajectory& curr_traj = *curr_traj_ptr;
00618 
00619         typename Segment::State state;
00620         typename Trajectory::const_iterator segment_it = sample(curr_traj, sample_time.toSec(), state);
00621         if (curr_traj.end() == segment_it)
00622         {
00623             ROS_ERROR_STREAM_NAMED(name_, "Requested sample time preceeds trajectory start time.");
00624             return false;
00625         }
00626 
00627         // Populate response
00628         resp.name         = joint_names_;
00629         resp.position     = state.position;
00630         resp.velocity     = state.velocity;
00631         resp.acceleration = state.acceleration;
00632 
00633         return true;
00634     }
00635 
00636     template <class SegmentImpl, class HardwareInterface>
00637     void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00638     publishState(const ros::Time& time)
00639     {
00640         // Check if it's time to publish
00641         if (!state_publisher_period_.isZero() && last_state_publish_time_ + state_publisher_period_ < time)
00642         {
00643             if (state_publisher_ && state_publisher_->trylock())
00644             {
00645                 last_state_publish_time_ += state_publisher_period_;
00646 
00647                 state_publisher_->msg_.header.stamp          = time_data_.readFromRT()->time;
00648                 state_publisher_->msg_.desired.positions     = desired_state_.position;
00649                 state_publisher_->msg_.desired.velocities    = desired_state_.velocity;
00650                 state_publisher_->msg_.desired.accelerations = desired_state_.acceleration;
00651                 state_publisher_->msg_.actual.positions      = current_state_.position;
00652                 state_publisher_->msg_.actual.velocities     = current_state_.velocity;
00653                 state_publisher_->msg_.error.positions       = state_error_.position;
00654                 state_publisher_->msg_.error.velocities      = state_error_.velocity;
00655 
00656                 state_publisher_->unlockAndPublish();
00657             }
00658         }
00659     }
00660 
00661     template <class SegmentImpl, class HardwareInterface>
00662     void JointTrajectoryController<SegmentImpl, HardwareInterface>::
00663     setHoldPosition(const ros::Time& time)
00664     {
00665         // Settle position in a fixed time. We do the following:
00666         // - Create segment that goes from current (pos,vel) to (pos,-vel) in 2x the desired stop time
00667         // - Assuming segment symmetry, sample segment at its midpoint (desired stop time). It should have zero velocity
00668         // - Create segment that goes from current state to above zero velocity state, in the desired time
00669         // NOTE: The symmetry assumption from the second point above might not hold for all possible segment types
00670 
00671         assert(1 == hold_trajectory_ptr_->size());
00672 
00673         const typename Segment::Time start_time  = time.toSec();
00674         const typename Segment::Time end_time    = time.toSec() + stop_trajectory_duration_;
00675         const typename Segment::Time end_time_2x = time.toSec() + 2.0 * stop_trajectory_duration_;
00676 
00677         // Create segment that goes from current (pos,vel) to (pos,-vel)
00678         const unsigned int n_joints = joints_.size();
00679         for (unsigned int i = 0; i < n_joints; ++i)
00680         {
00681             hold_start_state_.position[i]     =  joints_[i].getPosition();
00682             hold_start_state_.velocity[i]     =  joints_[i].getVelocity();
00683             hold_start_state_.acceleration[i] =  0.0;
00684 
00685             hold_end_state_.position[i]       =  joints_[i].getPosition();
00686             hold_end_state_.velocity[i]       = -joints_[i].getVelocity();
00687             hold_end_state_.acceleration[i]   =  0.0;
00688         }
00689         hold_trajectory_ptr_->front().init(start_time,  hold_start_state_,
00690                                            end_time_2x, hold_end_state_);
00691 
00692         // Sample segment at its midpoint, that should have zero velocity
00693         hold_trajectory_ptr_->front().sample(end_time, hold_end_state_);
00694 
00695         // Now create segment that goes from current state to one with zero end velocity
00696         hold_trajectory_ptr_->front().init(start_time, hold_start_state_,
00697                                            end_time,   hold_end_state_);
00698 
00699         curr_trajectory_box_.set(hold_trajectory_ptr_);
00700     }
00701 
00702 } // namespace
00703 
00704 #endif //ROBOTICAN_CONTROLLERS_JOINT_WITH_EFFORT_TRAJECTORY_CONTROLLER_IMPL_H


robotican_controllers
Author(s):
autogenerated on Fri Oct 27 2017 03:02:40