tf_static_publisher.cpp
Go to the documentation of this file.
1 #include <cmath>
3 #include <std_srvs/Trigger.h>
4 #include <thread>
5 #include <mutex>
6 #include <XmlRpcException.h>
7 
9 typedef XmlRpcValue::ValueStruct::value_type KeyValue;
10 using geometry_msgs::TransformStamped;
11 
12 TransformStamped value_to_transform(XmlRpcValue& value)
13 {
14  ROS_ASSERT_MSG(value.getType() == XmlRpcValue::TypeArray
15  && (value.size() == 8 || value.size() == 9),
16  "Transform must be an array of 8 or 9 elements.");
17 
18  TransformStamped msg;
19  // Header
20  msg.header.frame_id = static_cast<std::string>(value[value.size() - 2]);
21  msg.header.stamp = ros::Time::now();
22  msg.child_frame_id = static_cast<std::string>(value[value.size() - 1]);
23  // Translation
24  msg.transform.translation.x = static_cast<double>(value[0]);
25  msg.transform.translation.y = static_cast<double>(value[1]);
26  msg.transform.translation.z = static_cast<double>(value[2]);
27  // Rotation
28  if (value.size() == 8)
29  {
30  // [x y z yaw pitch roll 'parent' 'child']
31  double halfYaw = static_cast<double>(value[3]) / 2;
32  double halfPitch = static_cast<double>(value[4]) / 2;
33  double halfRoll = static_cast<double>(value[5]) / 2;
34  double cy = std::cos(halfYaw);
35  double sy = std::sin(halfYaw);
36  double cp = std::cos(halfPitch);
37  double sp = std::sin(halfPitch);
38  double cr = std::cos(halfRoll);
39  double sr = std::sin(halfRoll);
40 
41  msg.transform.rotation.x = sr * cp * cy - cr * sp * sy;
42  msg.transform.rotation.y = cr * sp * cy + sr * cp * sy;
43  msg.transform.rotation.z = cr * cp * sy - sr * sp * cy;
44  msg.transform.rotation.w = cr * cp * cy + sr * sp * sy;
45  }
46  else if (value.size() == 9)
47  {
48  // [x y z qx qy qz qw 'parent' 'child']
49  msg.transform.rotation.x = static_cast<double>(value[3]);
50  msg.transform.rotation.y = static_cast<double>(value[4]);
51  msg.transform.rotation.z = static_cast<double>(value[5]);
52  msg.transform.rotation.w = static_cast<double>(value[6]);
53  }
54  return msg;
55 }
56 
57 namespace geometry_msgs
58 {
59 bool operator==(const TransformStamped &lhs, const TransformStamped &rhs)
60 {
61  return lhs.header.frame_id == rhs.header.frame_id &&
62  lhs.child_frame_id == rhs.child_frame_id &&
63  lhs.transform.translation.x == rhs.transform.translation.x &&
64  lhs.transform.translation.y == rhs.transform.translation.y &&
65  lhs.transform.translation.z == rhs.transform.translation.z &&
66  lhs.transform.rotation.x == rhs.transform.rotation.x &&
67  lhs.transform.rotation.y == rhs.transform.rotation.y &&
68  lhs.transform.rotation.z == rhs.transform.rotation.z &&
69  lhs.transform.rotation.w == rhs.transform.rotation.w;
70 }
71 }
72 
73 
75 {
76  public: void loadAndPublish()
77  {
78  if (!ros::ok()) return;
79 
80  ROS_DEBUG("Reloading static transforms");
81 
82  XmlRpcValue transforms;
83  {
84  std::lock_guard<std::mutex> lock(this->paramMutex);
85  if (!this->nh.hasParam("transforms"))
86  {
87  ROS_WARN_ONCE("Parameter 'transforms' was not found. Will not publish any transforms until it appears.");
88  return;
89  }
90 
91  try
92  {
93  this->nh.param("transforms", transforms, transforms);
94  }
95  catch (XmlRpc::XmlRpcException& e)
96  {
97  ROS_ERROR("Error reading transforms from parameter %s: %s, error code %i",
98  this->nh.resolveName("transforms").c_str(),
99  e.getMessage().c_str(), e.getCode());
100  return;
101  }
102  }
103 
104  if (transforms.getType() != XmlRpcValue::TypeArray
105  && transforms.getType() != XmlRpcValue::TypeStruct)
106  {
107  ROS_ERROR("Parameter %s must be array or struct of arrays, got type %i.",
108  this->nh.resolveName("transforms").c_str(), transforms.getType());
109  return;
110  }
111 
112  std::vector<TransformStamped> msgs;
113  msgs.reserve(static_cast<size_t>(transforms.size()));
114 
115  if (transforms.getType() == XmlRpcValue::TypeArray)
116  {
117  // Do not use range-based for-loop! It's used for structs, not arrays!
118  for (size_t i = 0; i < transforms.size(); ++i)
119  {
120  auto& transform = transforms[i];
121  try
122  {
123  msgs.push_back(value_to_transform(transform));
124  }
125  catch (XmlRpc::XmlRpcException& e)
126  {
127  ROS_ERROR("Error reading static transform nr. %lu: %s, error code %i",
128  i, e.getMessage().c_str(), e.getCode());
129  }
130  }
131  }
132  else
133  {
134  for (KeyValue &v : transforms)
135  {
136  try
137  {
138  msgs.push_back(value_to_transform(v.second));
139  }
140  catch (XmlRpc::XmlRpcException& e)
141  {
142  ROS_ERROR("Error reading static transform %s: %s, error code %i",
143  v.first.c_str(), e.getMessage().c_str(), e.getCode());
144  }
145  }
146  }
147 
148  if (msgs != this->lastTransforms)
149  {
151 
152  for (const auto &msg : msgs)
153  {
154  ROS_DEBUG("Publishing static transform from %s to %s.",
155  msg.header.frame_id.c_str(),
156  msg.child_frame_id.c_str());
157  }
158  this->lastTransforms.clear();
159  this->lastTransforms = msgs;
160  }
161  }
162 
163  protected: bool onReloadTrigger(std_srvs::Trigger::Request&, std_srvs::Trigger::Response& resp)
164  {
165  this->loadAndPublish();
166  resp.success = true;
167  return true;
168  }
169 
170  public: explicit TfStaticPublisher(ros::NodeHandle nh) : nh(nh)
171  {
173  }
174 
175  private: ros::NodeHandle nh;
177  private: std::mutex paramMutex;
179  private: std::vector<geometry_msgs::TransformStamped> lastTransforms;
180 };
181 
182 
183 int main(int argc, char **argv)
184 {
185  ros::init(argc, argv, "tf_static_publisher",
187  ros::NodeHandle pnh("~");
188 
189  TfStaticPublisher node(pnh);
190 
191  const auto reload_frequency = pnh.param("reload_frequency", 0.0);
192 
193  node.loadAndPublish();
194 
195  if (reload_frequency == 0.0)
196  {
197  ros::spin();
198  }
199  else
200  {
201  ros::Rate rate(reload_frequency);
202  std::thread reload_thread([&rate, &node]()
203  {
204  while (ros::ok())
205  {
206  rate.sleep();
207  node.loadAndPublish();
208  }
209  });
210 
211  ros::spin();
212  reload_thread.join();
213  }
214 
215  return 0;
216 }
ros::init_options::AnonymousName
AnonymousName
XmlRpc::XmlRpcValue::size
int size() const
tf2_ros::StaticTransformBroadcaster::sendTransform
void sendTransform(const geometry_msgs::TransformStamped &transform)
TfStaticPublisher::triggerServer
ros::ServiceServer triggerServer
Definition: tf_static_publisher.cpp:176
ros::init
ROSCPP_DECL void init(const M_string &remappings, const std::string &name, uint32_t options=0)
XmlRpc::XmlRpcException::getMessage
const std::string & getMessage() const
TfStaticPublisher::onReloadTrigger
bool onReloadTrigger(std_srvs::Trigger::Request &, std_srvs::Trigger::Response &resp)
Definition: tf_static_publisher.cpp:163
geometry_msgs
ros::NodeHandle::advertiseService
ServiceServer advertiseService(AdvertiseServiceOptions &ops)
KeyValue
XmlRpcValue::ValueStruct::value_type KeyValue
Definition: tf_static_publisher.cpp:9
value_to_transform
TransformStamped value_to_transform(XmlRpcValue &value)
Definition: tf_static_publisher.cpp:12
ROS_WARN_ONCE
#define ROS_WARN_ONCE(...)
main
int main(int argc, char **argv)
Definition: tf_static_publisher.cpp:183
ros::ok
ROSCPP_DECL bool ok()
ros::ServiceServer
tf2_ros::StaticTransformBroadcaster
ros::NodeHandle::resolveName
std::string resolveName(const std::string &name, bool remap=true) const
ROS_DEBUG
#define ROS_DEBUG(...)
geometry_msgs::operator==
bool operator==(const TransformStamped &lhs, const TransformStamped &rhs)
Definition: tf_static_publisher.cpp:59
ROS_ASSERT_MSG
#define ROS_ASSERT_MSG(cond,...)
XmlRpc::XmlRpcException::getCode
int getCode() const
ros::NodeHandle::hasParam
bool hasParam(const std::string &key) const
TfStaticPublisher::broadcaster
tf2_ros::StaticTransformBroadcaster broadcaster
Definition: tf_static_publisher.cpp:178
ros::Rate::sleep
bool sleep()
XmlRpc::XmlRpcValue::getType
const Type & getType() const
TfStaticPublisher
Definition: tf_static_publisher.cpp:74
XmlRpc::XmlRpcException
TfStaticPublisher::nh
ros::NodeHandle nh
Definition: tf_static_publisher.cpp:175
TfStaticPublisher::paramMutex
std::mutex paramMutex
Definition: tf_static_publisher.cpp:177
TfStaticPublisher::lastTransforms
std::vector< geometry_msgs::TransformStamped > lastTransforms
Definition: tf_static_publisher.cpp:179
ROS_ERROR
#define ROS_ERROR(...)
TfStaticPublisher::loadAndPublish
void loadAndPublish()
Definition: tf_static_publisher.cpp:76
static_transform_broadcaster.h
ros::NodeHandle::param
T param(const std::string &param_name, const T &default_val) const
ros::Rate
ros::spin
ROSCPP_DECL void spin()
XmlRpcException.h
XmlRpc::XmlRpcValue
ros::NodeHandle
ros::Time::now
static Time now()
TfStaticPublisher::TfStaticPublisher
TfStaticPublisher(ros::NodeHandle nh)
Definition: tf_static_publisher.cpp:170


tf_static_publisher
Author(s): Tomas Petricek
autogenerated on Wed Apr 23 2025 02:49:05