multi_trigger_controller.cpp
Go to the documentation of this file.
1 
2 /*********************************************************************
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2009, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of the Willow Garage nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *********************************************************************/
35 
36 #include <boost/format.hpp>
37 #include <boost/shared_ptr.hpp>
38 #include <boost/thread/mutex.hpp>
39 
41 #include "ros/console.h"
43 
45 
46 using std::string;
47 using namespace controller;
48 
50 {
51  ROS_DEBUG("creating controller...");
52 }
53 
55 {
56 }
57 
59 {
60  int maxloops = 10; // @todo Workaround to avoid breaking realtime in response to #3274. Need to revamp things to fix this better.
61 
62  if (!config_.transitions.empty() && config_mutex_.try_lock())
63  { // If we missed the lock, then hold current value for now.
64  ros::Time cur_time = robot_->getTime();
65 
66  while (cur_time.toSec() >= transition_time_) // Usually only happens at most once per update.
67  {
68  if (!maxloops--)
69  {
70  //ROS_ERROR("MultiTriggerController exceeded iteration limit. Please report this to Blaise."); // @todo remove this
71  break;
72  }
73 
74  //ROS_INFO("hit %f %f %i", cur_time.toSec(), transition_time_, config_.transitions[transition_index_].value);
75  // Do the transition
77  if (pubs_[transition_index_] && pubs_[transition_index_]->trylock())
78  {
79  pubs_[transition_index_]->msg_.stamp = cur_time;
80  pubs_[transition_index_]->unlockAndPublish();
81  }
82 
83  // Prepare for next transition
84  if (++transition_index_ == config_.transitions.size())
85  {
88  }
89  transition_time_ = config_.transitions[transition_index_].time + config_.period * transition_period_ + config_.zero_offset;
90  }
91  config_mutex_.unlock();
92  }
93 }
94 
95 template <class T>
96 static bool parseParamList(ros::NodeHandle nh, std::string param, std::vector<T> &rslt)
97 {
98  std::string param_value;
99  nh.getParam(param, param_value);
100  std::stringstream parser(param_value);
101  T value;
102  while (parser >> value)
103  rslt.push_back(value);
104 
105  bool eof = parser.eof();
106 
107  if (!eof)
108  ROS_ERROR("Error parsing '%s/%s' argument to MultiTriggerController.", nh.getNamespace().c_str(), param.c_str());
109 
110  return eof; // Returns true on success
111 }
112 
114 {
115  node_handle_ = n;
116 
117  ROS_DEBUG("LOADING TRIGGER CONTROLLER NODE");
118  //string prefix = config->Attribute("name");
119  //ROS_DEBUG_STREAM("the prefix is "<<prefix);
120 
121  assert(robot);
122  robot_=robot;
123 
124  ROS_DEBUG("MultiTriggerController::init starting");
125 
126  // Get the digital out name.
127 
128  if (!n.getParam("digital_output", digital_output_name_)){
129  ROS_ERROR("MultiTriggerController was not given a digital_output parameter.");
130  return false;
131  }
132 
134  if (!digital_out)
135  {
136  ROS_ERROR("MultiTriggerController could not find digital output named \"%s\".",
137  digital_output_name_.c_str());
138  return false;
139  }
140 
141  digital_out_command_ = &digital_out->command_;
142 
143  n.param("period", config_.period, 1.);
144  n.param("zero_offset", config_.zero_offset, 0.);
145 
146  std::vector<string> topics;
147  std::vector<double> times;
148  std::vector<uint32_t> values;
149 
150  waveform_ = node_handle_.advertise<ethercat_trigger_controllers::MultiWaveform>("waveform", 1, true);
151 
152  if (parseParamList(n, "times", times) && parseParamList(n, "topics", topics) && parseParamList(n, "values", values))
153  {
154  if (times.size() != topics.size() || times.size() != values.size())
155  ROS_ERROR("'topics', 'times' and 'values' parameters must have same length in %s. Ignoring initial settings.",
156  n.getNamespace().c_str());
157  else
158  {
159  for (unsigned int i = 0; i < times.size(); i++)
160  {
161  ethercat_trigger_controllers::MultiWaveformTransition t;
162  t.time = times[i];
163  t.value = values[i];
164  t.topic = topics[i];
165  config_.transitions.push_back(t);
166  }
167 
168  ethercat_trigger_controllers::SetMultiWaveform::Request req;
169  req.waveform = config_;
170  ethercat_trigger_controllers::SetMultiWaveform::Response dummy;
171  setMultiWaveformSrv(req, dummy);
172  }
173  }
174 
176 
177  ROS_DEBUG("MultiTriggerController::init completed successfully.");
178 
179  return true;
180 }
181 
183  ethercat_trigger_controllers::SetMultiWaveform::Request &req,
184  ethercat_trigger_controllers::SetMultiWaveform::Response &resp)
185 {
186  std::vector<boost::shared_ptr<realtime_tools::RealtimePublisher<std_msgs::Header> > > new_pubs;
187  new_pubs.reserve(config_.transitions.size());
188  ethercat_trigger_controllers::MultiWaveform &new_config = req.waveform;
189 
190  double prev_time = -1; // There is a check for negative values below.
191  double now = ros::Time::now().toSec();
192  double new_transition_period = round((now - new_config.zero_offset) / new_config.period);
193  double current_period_start = new_config.zero_offset + new_transition_period * new_config.period;
194  double now_offset = now - current_period_start;
195  unsigned int new_transition_index = 0;
196  resp.success = true;
197 
198  if (new_transition_period <= 0)
199  {
200  resp.status_message = "MultiTrigger period must be >0.";
201  resp.success = false;
202  }
203 
204  for (std::vector<ethercat_trigger_controllers::MultiWaveformTransition>::iterator trans = new_config.transitions.begin();
205  trans != new_config.transitions.end() && resp.success; trans++)
206  {
207  if (trans->time < now_offset)
208  new_transition_index++;
209 
210  if (trans->time < 0 || trans->time >= new_config.period)
211  {
212  resp.status_message = (boost::format("MultiTriggerController::setMultiWaveformSrv transition time (%f) must be >= 0 and < period (%f).")%
213  trans->time%new_config.period).str();
214  resp.success = false;
215  }
216 
217  if (prev_time >= trans->time)
218  {
219  resp.status_message = (boost::format("MultiTriggerController::setMultiWaveformSrv transition times must be in increasing order. %f >= %f")%
220  prev_time%trans->time).str();
221  resp.success = false;
222  }
223  }
224 
225  if (new_transition_index == new_config.transitions.size())
226  {
227  new_transition_index = 0;
228  new_transition_period++;
229  }
230 
231  double new_transition_time = current_period_start + new_config.transitions[new_transition_index].time;
232 
233 // ROS_DEBUG("MultiTriggerController::setMultiWaveformSrv completed successfully"
234 // " rr=%f ph=%f al=%i r=%i p=%i dc=%f.", config_.rep_rate, config_.phase,
235 // config_.active_low, config_.running, config_.pulsed, config_.duty_cycle);
236 
237  if (resp.success)
238  {
239  for (std::vector<ethercat_trigger_controllers::MultiWaveformTransition>::iterator trans = new_config.transitions.begin();
240  trans != new_config.transitions.end() && resp.success; trans++)
241  {
243 
244  if (trans->topic.compare("-"))
245  new_pub.reset(new realtime_tools::RealtimePublisher<std_msgs::Header>(node_handle_, trans->topic, 10));
246 
247  new_pubs.push_back(new_pub);
248  }
249 
250  boost::mutex::scoped_lock lock(config_mutex_);
251  config_ = new_config;
252  pubs_ = new_pubs;
253  transition_period_ = new_transition_period;
254  transition_index_ = new_transition_index;
255  transition_time_ = new_transition_time;
256  waveform_.publish(req.waveform);
257  }
258  else
259  ROS_ERROR("%s", resp.status_message.c_str());
260 
261  return true;
262 }
pr2_mechanism_model::RobotState * robot_
std::vector< boost::shared_ptr< realtime_tools::RealtimePublisher< std_msgs::Header > > > pubs_
pr2_hardware_interface::HardwareInterface * hw_
#define ROS_ERROR(...)
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
#define ROS_DEBUG(...)
DigitalOut * getDigitalOut(const std::string &name) const
bool init(pr2_mechanism_model::RobotState *robot, ros::NodeHandle &n)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void publish(const boost::shared_ptr< M > &message) const
PLUGINLIB_EXPORT_CLASS(pr2_mechanism_model::PR2BeltCompensatorTransmission, pr2_mechanism_model::Transmission) namespace pr2_mechanism_model
bool getParam(const std::string &key, std::string &s) const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
const std::string & getNamespace() const
pr2_hardware_interface::DigitalOutCommand * digital_out_command_
parser
static Time now()
double & value
static bool parseParamList(ros::NodeHandle nh, std::string param, std::vector< T > &rslt)
bool setMultiWaveformSrv(ethercat_trigger_controllers::SetMultiWaveform::Request &req, ethercat_trigger_controllers::SetMultiWaveform::Response &resp)


ethercat_trigger_controllers
Author(s): Blaise Gassend
autogenerated on Sat Nov 12 2022 03:16:21