ros_tagdetect_client.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019 Roboception GmbH
3  *
4  * Author: Monika Florek-Jasinska
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice,
10  * this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  *
16  * 3. Neither the name of the copyright holder nor the names of its contributors
17  * may be used to endorse or promote products derived from this software without
18  * specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "ros_tagdetect_client.h"
34 #include "json_conversions.h"
35 
36 using std::string;
37 
38 namespace rc_tagdetect_client
39 {
41  const std::string& detection_type)
42  : nh_(nh)
43 
44 {
45  if (detection_type == "rc_april_tag_detect" || detection_type == "rc_qr_code_detect")
46  {
47  rest_helper_.reset(new rc_rest_api::RestHelper(host, detection_type, 10000));
48  }
49  else
50  {
51  throw std::runtime_error("Acceptable detection types are \"rc_april_tag_detect\" and \"rc_qr_code_detect\"");
52  }
53  image_version_ = rest_helper_->getImageVersion();
57 }
58 
60 {
61  try
62  {
63  if (continuous_mode_thread_.joinable())
64  {
67  }
68 
69  stopTagDetect();
70  }
71  catch (const std::exception& ex)
72  {
73  ROS_FATAL("Exception during destruction of RosTagdetectClient: %s", ex.what());
74  }
75  catch (...)
76  {
77  ROS_FATAL("Exception during destruction of RosTagdetectClient");
78  }
79 }
80 
82 {
83  rest_helper_->servicePutRequest("start");
84 }
85 
87 {
88  rest_helper_->servicePutRequest("stop");
89 }
90 
91 template <typename Request, typename Response>
92 bool RosTagdetectClient::callService(const std::string& name, const Request& req, Response& res)
93 {
94  try
95  {
96  json j_req = req;
97  const auto j_res = rest_helper_->servicePutRequest(name, j_req);
98  res = j_res;
99  return true;
100  }
102  {
103  ROS_ERROR("This rc_visard firmware does not support \"%s\"", ex.what());
104  res.return_code.value = -8; // NOT_APPLICABLE
105  res.return_code.message = "Not available in this firmware version";
106  return false;
107  }
108  catch (const std::exception& ex)
109  {
110  ROS_ERROR("%s", ex.what());
111  res.return_code.value = -2; // INTERNAL_ERROR
112  res.return_code.message = ex.what();
113  return false;
114  }
115 }
116 
117 bool RosTagdetectClient::detect(DetectTagsRequest& req, DetectTagsResponse& res)
118 {
119  bool success = callService("detect", req, res);
120  if (success && res.return_code.value >= 0 && visualizer_)
121  {
122  visualizer_->publishTags(res.tags);
123  }
125  return success;
126 }
127 
128 bool RosTagdetectClient::detectService(DetectTagsRequest& req, DetectTagsResponse& res)
129 {
130  if (continuous_mode_thread_.joinable())
131  {
132  ROS_ERROR("Cannot execute detect when continuous mode is enabled.");
133  res.return_code.value = -8; // NOT_APPLICABLE
134  res.return_code.message = "Cannot execute detect when continuous mode is enabled.";
135  return true;
136  }
137 
138  detect(req, res);
139  return true;
140 }
141 
142 bool RosTagdetectClient::stopContinousDetection(std_srvs::TriggerRequest& request, std_srvs::TriggerResponse& response)
143 {
144  if (continuous_mode_thread_.joinable())
145  {
148  }
149  response.success = true;
150  return true;
151 }
152 
153 bool RosTagdetectClient::startContinousDetection(StartContinuousDetectionRequest& request,
154  StartContinuousDetectionResponse& response)
155 {
156  {
157  std_srvs::TriggerRequest request;
158  std_srvs::TriggerResponse response;
159  stopContinousDetection(request, response);
160  }
161 
162  if (!continuous_mode_thread_.joinable())
163  {
165  continuous_mode_thread_ = std::thread([request, this]() {
166  ROS_INFO("Entering continuous mode...");
167 
168  const double rate = 1.0;
169 
171  {
172  const auto start_time = std::chrono::steady_clock::now();
173 
174  DetectTagsRequest req;
175  req.tags = request.tags;
176  req.pose_frame = request.pose_frame;
177  req.robot_pose = request.robot_pose;
178  DetectTagsResponse res;
179  if (!detect(req, res))
180  {
181  break;
182  }
183 
185  std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::steady_clock::now() - start_time)
186  .count() < rate)
187  {
188  std::this_thread::sleep_for(std::chrono::milliseconds(10));
189  }
190  }
191 
192  ROS_INFO("Stopping continuous mode...");
193  });
194  }
195 
196  response.success = true;
197  return true;
198 }
199 
201 {
202  detections_pub_ = nh_.advertise<rc_tagdetect_client::DetectedTags>("detected_tags", 100);
203 
206  nh_.advertiseService("start_continuous_detection", &RosTagdetectClient::startContinousDetection, this);
208  nh_.advertiseService("stop_continuous_detection", &RosTagdetectClient::stopContinousDetection, this);
209 }
210 
211 void paramsToCfg(const json& params, TagDetectConfig& cfg)
212 {
213  for (const auto& param : params)
214  {
215  const auto& name = param["name"];
216  if (name == "quality")
217  {
218  cfg.quality = param["value"];
219  }
220  else if (name == "detect_inverted_tags")
221  {
222  // TODO is it working with all versions?
223  cfg.detect_inverted_tags = param["value"];
224  }
225  else if (name == "forget_after_n_detections")
226  {
227  cfg.forget_after_n_detections = param["value"];
228  }
229  else if (name == "max_corner_distance")
230  {
231  cfg.max_corner_distance = param["value"];
232  }
233  else if (name == "use_cached_images")
234  {
235  cfg.use_cached_images = param["value"];
236  }
237  }
238 }
239 
241 {
242  rc_tagdetect_client::TagDetectConfig cfg;
243 
244  // first get the current values from sensor
245  const auto j_params = rest_helper_->getParameters();
246 
247  paramsToCfg(j_params, cfg);
248 
249  // second, try to get ROS parameters:
250  // if parameter is not set in parameter server, we default to current sensor configuration
251  nh_.param("quality", cfg.quality, cfg.quality);
252  nh_.param("detect_inverted_tags", cfg.detect_inverted_tags, cfg.detect_inverted_tags);
253  nh_.param("forget_after_n_detections", cfg.forget_after_n_detections, cfg.forget_after_n_detections);
254  nh_.param("max_corner_distance", cfg.max_corner_distance, cfg.max_corner_distance);
255  nh_.param("use_cached_images", cfg.use_cached_images, cfg.use_cached_images);
256 
257  // set parameters on parameter server so that dynamic reconfigure picks them up
258  nh_.setParam("quality", cfg.quality);
259  nh_.setParam("detect_inverted_tags", cfg.detect_inverted_tags);
260  nh_.setParam("forget_after_n_detections", cfg.forget_after_n_detections);
261  nh_.setParam("max_corner_distance", cfg.max_corner_distance);
262  nh_.setParam("use_cached_images", cfg.use_cached_images);
263 
264  // instantiate dynamic reconfigure server that will initially read those values
265  using ReconfServer = dynamic_reconfigure::Server<rc_tagdetect_client::TagDetectConfig>;
266  server_ = std::unique_ptr<ReconfServer>(new ReconfServer(nh_));
268 }
269 
270 void RosTagdetectClient::dynamicReconfigureCallback(rc_tagdetect_client::TagDetectConfig& config, uint32_t)
271 {
272  // fill json request from dynamic reconfigure request
273  json js_params, js_param;
274  js_param["name"] = "quality";
275  js_param["value"] = config.quality;
276  js_params.push_back(js_param);
277  if (image_version_ >= std::make_tuple(1ul, 2ul, 1ul))
278  {
279  js_param["name"] = "detect_inverted_tags";
280  js_param["value"] = config.detect_inverted_tags;
281  js_params.push_back(js_param);
282  }
283  else
284  {
285  ROS_WARN("\"detect_inverted_tags\" only available in newer software versions.");
286  config.detect_inverted_tags = false;
287  }
288  js_param["name"] = "forget_after_n_detections";
289  js_param["value"] = config.forget_after_n_detections;
290  js_params.push_back(js_param);
291  js_param["name"] = "max_corner_distance";
292  js_param["value"] = config.max_corner_distance;
293  js_params.push_back(js_param);
294  js_param["name"] = "use_cached_images";
295  js_param["value"] = config.use_cached_images;
296  js_params.push_back(js_param);
297 
298  if (config.publish_visualization)
299  {
300  if (!visualizer_)
301  {
302  visualizer_.reset(new Visualization(nh_));
303  }
304  }
305  else
306  {
307  visualizer_.reset();
308  }
309 
310  json j_params_new = rest_helper_->setParameters(js_params);
311  // set config with new params so they are updated if needed
312  paramsToCfg(j_params_new, config);
313 }
314 
315 } // namespace rc_tagdetect_client
std::unique_ptr< dynamic_reconfigure::Server< rc_tagdetect_client::TagDetectConfig > > server_
bool param(const std::string &param_name, T &param_val, const T &default_val)
bool detect(rc_tagdetect_client::DetectTagsRequest &req, rc_tagdetect_client::DetectTagsResponse &response)
#define ROS_FATAL(...)
#define bind
Definition: setup-os400.h:211
Definition: ws_ssl.c:25
void publish(const boost::shared_ptr< M > &message) const
bool startContinousDetection(rc_tagdetect_client::StartContinuousDetectionRequest &request, rc_tagdetect_client::StartContinuousDetectionResponse &response)
::std::string string
Definition: gtest-port.h:1129
struct curltime now
Definition: unit1399.c:83
RosTagdetectClient(const std::string &host, const ros::NodeHandle &nh, const std::string &detection_type)
static int res
std::tuple< size_t, size_t, size_t > image_version_
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_WARN(...)
tuple make_tuple()
Definition: gtest-tuple.h:675
nlohmann::json json
Definition: rest_helper.h:41
void dynamicReconfigureCallback(rc_tagdetect_client::TagDetectConfig &config, uint32_t)
std::unique_ptr< rc_rest_api::RestHelper > rest_helper_
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::unique_ptr< rc_tagdetect_client::Visualization > visualizer_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
bool stopContinousDetection(std_srvs::TriggerRequest &request, std_srvs::TriggerResponse &response)
void paramsToCfg(const json &params, TagDetectConfig &cfg)
bool detectService(rc_tagdetect_client::DetectTagsRequest &request, rc_tagdetect_client::DetectTagsResponse &response)
const char * name
Definition: curl_sasl.c:54
#define ROS_ERROR(...)
void setParam(const std::string &key, const XmlRpc::XmlRpcValue &v) const
bool callService(const std::string &name, const Request &req, Response &res)


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:16