joint_state_listener.cpp
Go to the documentation of this file.
1 /*********************************************************************
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2008, Willow Garage, Inc.
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 the Willow Garage 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: Wim Meeussen */
36 
37 #include <ros/ros.h>
38 #include <urdf/model.h>
39 #include <kdl/tree.hpp>
40 
43 
44 using namespace std;
45 using namespace ros;
46 using namespace KDL;
47 using namespace robot_state_publisher;
48 
49 JointStateListener::JointStateListener(const KDL::Tree& tree, const MimicMap& m, const urdf::Model& model)
50  : state_publisher_(tree, model), mimic_(m)
51 {
52  ros::NodeHandle n_tilde("~");
54 
55  // set publish frequency
56  double publish_freq;
57  n_tilde.param("publish_frequency", publish_freq, 50.0);
58  // set whether to use the /tf_static latched static transform broadcaster
59  n_tilde.param("use_tf_static", use_tf_static_, true);
60  // ignore_timestamp_ == true, joins_states messages are accepted, no matter their timestamp
61  n_tilde.param("ignore_timestamp", ignore_timestamp_, false);
62  // get the tf_prefix parameter from the closest namespace
63  std::string tf_prefix_key;
64  n_tilde.searchParam("tf_prefix", tf_prefix_key);
65  n_tilde.param(tf_prefix_key, tf_prefix_, std::string(""));
66  publish_interval_ = ros::Duration(1.0/max(publish_freq, 1.0));
67 
68  // Setting tcpNoNelay tells the subscriber to ask publishers that connect
69  // to set TCP_NODELAY on their side. This prevents some joint_state messages
70  // from being bundled together, increasing the latency of one of the messages.
71  ros::TransportHints transport_hints;
72  transport_hints.tcpNoDelay(true);
73  // subscribe to joint state
74  joint_state_sub_ = n.subscribe("joint_states", 1, &JointStateListener::callbackJointState, this, transport_hints);
75 
76  // trigger to publish fixed joints
77  // if using static transform broadcaster, this will be a oneshot trigger and only run once
79 }
80 
81 
83 {}
84 
85 
87 {
88  (void)e;
90 }
91 
93 {
94  if (state->name.size() != state->position.size()){
95  if (state->position.empty()){
96  const int throttleSeconds = 300;
97  ROS_WARN_THROTTLE(throttleSeconds,
98  "Robot state publisher ignored a JointState message about joint(s) "
99  "\"%s\"(,...) whose position member was empty. This message will "
100  "not reappear for %d seconds.", state->name[0].c_str(),
101  throttleSeconds);
102  } else {
103  ROS_ERROR("Robot state publisher ignored an invalid JointState message");
104  }
105  return;
106  }
107 
108  // check if we moved backwards in time (e.g. when playing a bag file)
109  ros::Time now = ros::Time::now();
110  if (last_callback_time_ > now) {
111  // force re-publish of joint transforms
112  ROS_WARN("Moved backwards in time (probably because ROS clock was reset), re-publishing joint transforms!");
113  last_publish_time_.clear();
114  }
115  ros::Duration warning_threshold(30.0);
116  if ((state->header.stamp + warning_threshold) < now) {
117  ROS_WARN_THROTTLE(10, "Received JointState is %f seconds old.", (now - state->header.stamp).toSec());
118  }
119  last_callback_time_ = now;
120 
121  // determine least recently published joint
122  ros::Time last_published = now;
123  for (unsigned int i=0; i<state->name.size(); i++) {
124  ros::Time t = last_publish_time_[state->name[i]];
125  last_published = (t < last_published) ? t : last_published;
126  }
127  // note: if a joint was seen for the first time,
128  // then last_published is zero.
129 
130  // check if we need to publish
131  if (ignore_timestamp_ || state->header.stamp >= last_published + publish_interval_) {
132  // get joint positions from state message
133  map<string, double> joint_positions;
134  for (unsigned int i=0; i<state->name.size(); i++) {
135  joint_positions.insert(make_pair(state->name[i], state->position[i]));
136  }
137 
138  for (MimicMap::iterator i = mimic_.begin(); i != mimic_.end(); i++) {
139  if(joint_positions.find(i->second->joint_name) != joint_positions.end()) {
140  double pos = joint_positions[i->second->joint_name] * i->second->multiplier + i->second->offset;
141  joint_positions.insert(make_pair(i->first, pos));
142  }
143  }
144 
145  state_publisher_.publishTransforms(joint_positions, state->header.stamp, tf_prefix_);
146 
147  // store publish time in joint map
148  for (unsigned int i = 0; i<state->name.size(); i++) {
149  last_publish_time_[state->name[i]] = state->header.stamp;
150  }
151  }
152 }
153 
Timer createTimer(Rate r, Handler h, Obj o, bool oneshot=false, bool autostart=true) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
#define ROS_ERROR(...)
#define ROS_WARN(...)
virtual void publishFixedTransforms(const std::string &tf_prefix, bool use_tf_static=false)
virtual void callbackFixedJoint(const ros::TimerEvent &e)
std::map< std::string, ros::Time > last_publish_time_
TransportHints & tcpNoDelay(bool nodelay=true)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
virtual void publishTransforms(const std::map< std::string, double > &joint_positions, const ros::Time &time, const std::string &tf_prefix)
#define ROS_WARN_THROTTLE(period,...)
robot_state_publisher::RobotStatePublisher state_publisher_
bool searchParam(const std::string &key, std::string &result) const
static Time now()
std::map< std::string, urdf::JointMimicSharedPtr > MimicMap
virtual void callbackJointState(const JointStateConstPtr &state)
double max(double a, double b)


robot_state_publisher
Author(s): Ioan Sucan , Jackie Kay , Wim Meeussen
autogenerated on Mon Feb 28 2022 23:26:24