ros2_canopen  master
C++ ROS CANopen Library
node_canopen_base_driver_impl.hpp
Go to the documentation of this file.
1 #ifndef NODE_CANOPEN_BASE_DRIVER_IMPL
2 #define NODE_CANOPEN_BASE_DRIVER_IMPL
5 
6 using namespace ros2_canopen::node_interfaces;
7 
8 template <class NODETYPE>
10 : ros2_canopen::node_interfaces::NodeCanopenDriver<NODETYPE>(node)
11 {
12 }
13 
14 template <class NODETYPE>
15 void NodeCanopenBaseDriver<NODETYPE>::init(bool called_from_base)
16 {
17 }
18 
19 template <>
21 {
22  try
23  {
24  polling_ = this->config_["polling"].as<bool>();
25  }
26  catch (...)
27  {
28  RCLCPP_ERROR(this->node_->get_logger(), "Could not polling from config, setting to true.");
29  polling_ = true;
30  }
31  if (polling_)
32  {
33  try
34  {
35  period_ms_ = this->config_["period"].as<std::uint32_t>();
36  }
37  catch (...)
38  {
39  RCLCPP_ERROR(this->node_->get_logger(), "Could not read period from config, setting to 10ms");
40  period_ms_ = 10;
41  }
42  }
43 }
44 template <>
45 void NodeCanopenBaseDriver<rclcpp::Node>::configure(bool called_from_base)
46 {
47  try
48  {
49  polling_ = this->config_["polling"].as<bool>();
50  }
51  catch (...)
52  {
53  RCLCPP_ERROR(this->node_->get_logger(), "Could not polling from config, setting to true.");
54  polling_ = true;
55  }
56  if (polling_)
57  {
58  try
59  {
60  period_ms_ = this->config_["period"].as<std::uint32_t>();
61  }
62  catch (...)
63  {
64  RCLCPP_ERROR(this->node_->get_logger(), "Could not read period from config, setting to 10ms");
65  period_ms_ = 10;
66  }
67  }
68 }
69 
70 template <class NODETYPE>
71 void NodeCanopenBaseDriver<NODETYPE>::activate(bool called_from_base)
72 {
73  nmt_state_publisher_thread_ =
74  std::thread(std::bind(&NodeCanopenBaseDriver<NODETYPE>::nmt_listener, this));
75  emcy_queue_ = this->lely_driver_->get_emcy_queue();
76  rpdo_queue_ = this->lely_driver_->get_rpdo_queue();
77  if (polling_)
78  {
79  RCLCPP_INFO(this->node_->get_logger(), "Starting with polling mode.");
80  poll_timer_ = this->node_->create_wall_timer(
81  std::chrono::milliseconds(period_ms_),
82  std::bind(&NodeCanopenBaseDriver<NODETYPE>::poll_timer_callback, this), this->timer_cbg_);
83  }
84  else
85  {
86  RCLCPP_INFO(this->node_->get_logger(), "Starting with event mode.");
87  this->lely_driver_->set_sync_function(
89  }
90 }
91 
92 template <class NODETYPE>
94 {
95  nmt_state_publisher_thread_.join();
96  poll_timer_->cancel();
97  this->lely_driver_->unset_sync_function();
98 }
99 
100 template <class NODETYPE>
101 void NodeCanopenBaseDriver<NODETYPE>::cleanup(bool called_from_base)
102 {
103 }
104 
105 template <class NODETYPE>
106 void NodeCanopenBaseDriver<NODETYPE>::shutdown(bool called_from_base)
107 {
108 }
109 
110 template <class NODETYPE>
112 {
113  RCLCPP_INFO(this->node_->get_logger(), "eds file %s", this->eds_.c_str());
114  RCLCPP_INFO(this->node_->get_logger(), "bin file %s", this->bin_.c_str());
115  std::shared_ptr<std::promise<std::shared_ptr<ros2_canopen::LelyDriverBridge>>> prom;
116  prom = std::make_shared<std::promise<std::shared_ptr<ros2_canopen::LelyDriverBridge>>>();
117  std::future<std::shared_ptr<ros2_canopen::LelyDriverBridge>> f = prom->get_future();
118  this->exec_->post(
119  [this, prom]()
120  {
121  std::scoped_lock<std::mutex> lock(this->driver_mutex_);
122  this->lely_driver_ = std::make_shared<ros2_canopen::LelyDriverBridge>(
123  *(this->exec_), *(this->master_), this->node_id_, this->node_->get_name(), this->eds_,
124  this->bin_);
125  this->driver_ = std::static_pointer_cast<lely::canopen::BasicDriver>(this->lely_driver_);
126  prom->set_value(lely_driver_);
127  });
128 
129  auto future_status = f.wait_for(this->non_transmit_timeout_);
130  if (future_status != std::future_status::ready)
131  {
132  RCLCPP_ERROR(this->node_->get_logger(), "Adding timed out.");
133  throw DriverException("add_to_master: adding timed out");
134  }
135  this->lely_driver_ = f.get();
136  this->driver_ = std::static_pointer_cast<lely::canopen::BasicDriver>(this->lely_driver_);
137  if (!this->lely_driver_->IsReady())
138  {
139  RCLCPP_WARN(this->node_->get_logger(), "Wait for device to boot.");
140  try
141  {
142  this->lely_driver_->wait_for_boot();
143  }
144  catch (const std::exception & e)
145  {
146  RCLCPP_ERROR(this->node_->get_logger(), e.what());
147  }
148  }
149  RCLCPP_INFO(this->node_->get_logger(), "Driver booted and ready.");
150 }
151 
152 template <class NODETYPE>
154 {
155  std::shared_ptr<std::promise<void>> prom = std::make_shared<std::promise<void>>();
156  auto f = prom->get_future();
157  this->exec_->post(
158  [this, prom]()
159  {
160  this->driver_.reset();
161  this->lely_driver_.reset();
162  prom->set_value();
163  });
164 
165  auto future_status = f.wait_for(this->non_transmit_timeout_);
166  if (future_status != std::future_status::ready)
167  {
168  throw DriverException("remove_from_master: removing timed out");
169  }
170 }
171 template <class NODETYPE>
173 {
174  while (rclcpp::ok())
175  {
176  std::future<lely::canopen::NmtState> f;
177  {
178  std::scoped_lock<std::mutex> lock(this->driver_mutex_);
179  f = this->lely_driver_->async_request_nmt();
180  }
181  while (f.wait_for(this->non_transmit_timeout_) != std::future_status::ready)
182  {
183  if (!this->activated_.load()) return;
184  }
185  try
186  {
187  auto state = f.get();
188  if (nmt_state_cb_)
189  {
190  nmt_state_cb_(state, this->lely_driver_->get_id());
191  }
192  on_nmt(state);
193  }
194  catch (const std::future_error & e)
195  {
196  break;
197  }
198  }
199 }
200 template <class NODETYPE>
201 void NodeCanopenBaseDriver<NODETYPE>::on_nmt(canopen::NmtState nmt_state)
202 {
203 }
204 
205 template <class NODETYPE>
207 {
208 }
209 
210 template <class NODETYPE>
212 {
213 }
214 
215 template <class NODETYPE>
217 {
218  RCLCPP_INFO(this->node_->get_logger(), "Starting RPDO Listener");
219  auto q = lely_driver_->get_rpdo_queue();
220  while (rclcpp::ok())
221  {
223  while (!q->wait_and_pop_for(this->non_transmit_timeout_, rpdo))
224  {
225  if (!this->activated_.load()) return;
226  }
227  try
228  {
229  if (rpdo_cb_)
230  {
231  rpdo_cb_(rpdo, this->lely_driver_->get_id());
232  }
233  on_rpdo(rpdo);
234  }
235  catch (const std::exception & e)
236  {
237  RCLCPP_ERROR_STREAM(this->node_->get_logger(), "RPDO Listener error: " << e.what());
238  break;
239  }
240  }
241 }
242 template <class NODETYPE>
244 {
245  for (int i = 0; i < 10; i++)
246  {
247  auto opt = emcy_queue_->try_pop();
248  if (!opt.has_value())
249  {
250  break;
251  }
252  try
253  {
254  if (emcy_cb_)
255  {
256  emcy_cb_(opt.value(), this->lely_driver_->get_id());
257  }
258  on_emcy(opt.value());
259  }
260  catch (const std::exception & e)
261  {
262  RCLCPP_ERROR_STREAM(this->node_->get_logger(), "EMCY poll error: " << e.what());
263  break;
264  }
265  }
266  for (int i = 0; i < 10; i++)
267  {
268  auto opt = rpdo_queue_->try_pop();
269  if (!opt.has_value())
270  {
271  break;
272  }
273  try
274  {
275  if (rpdo_cb_)
276  {
277  rpdo_cb_(opt.value(), this->lely_driver_->get_id());
278  }
279  on_rpdo(opt.value());
280  }
281  catch (const std::exception & e)
282  {
283  RCLCPP_ERROR_STREAM(this->node_->get_logger(), "RPDO Poll error: " << e.what());
284  break;
285  }
286  }
287 }
288 
289 template <class NODETYPE>
291 {
292  RCLCPP_INFO(this->node_->get_logger(), "Starting EMCY Listener");
293  auto q = lely_driver_->get_emcy_queue();
294  while (rclcpp::ok())
295  {
297  while (!q->wait_and_pop_for(this->non_transmit_timeout_, emcy))
298  {
299  if (!this->activated_.load()) return;
300  }
301  try
302  {
303  if (emcy_cb_)
304  {
305  emcy_cb_(emcy, this->lely_driver_->get_id());
306  }
307  on_emcy(emcy);
308  }
309  catch (const std::exception & e)
310  {
311  RCLCPP_ERROR_STREAM(this->node_->get_logger(), "EMCY Listener error: " << e.what());
312  break;
313  }
314  }
315 }
316 
317 #endif
Driver Exception.
Definition: driver_error.hpp:17
Definition: node_canopen_base_driver.hpp:19
void rdpo_listener()
Definition: node_canopen_base_driver_impl.hpp:216
virtual void add_to_master()
Add the driver to master.
Definition: node_canopen_base_driver_impl.hpp:111
void nmt_listener()
Definition: node_canopen_base_driver_impl.hpp:172
virtual void on_rpdo(COData data)
Definition: node_canopen_base_driver_impl.hpp:206
virtual void poll_timer_callback()
Definition: node_canopen_base_driver_impl.hpp:243
NodeCanopenBaseDriver(NODETYPE *node)
Definition: node_canopen_base_driver_impl.hpp:9
virtual void remove_from_master()
Remove the driver from master.
Definition: node_canopen_base_driver_impl.hpp:153
void emcy_listener()
Definition: node_canopen_base_driver_impl.hpp:290
virtual void on_nmt(canopen::NmtState nmt_state)
Definition: node_canopen_base_driver_impl.hpp:201
virtual void on_emcy(COEmcy emcy)
Definition: node_canopen_base_driver_impl.hpp:211
Node Canopen Driver.
Definition: node_canopen_driver.hpp:46
void shutdown()
Shutdown the driver.
Definition: node_canopen_driver.hpp:323
void deactivate()
Deactivate the driver.
Definition: node_canopen_driver.hpp:251
void cleanup()
Cleanup the driver.
Definition: node_canopen_driver.hpp:291
void activate()
Activate the driver.
Definition: node_canopen_driver.hpp:209
void init()
Initialise the driver.
Definition: node_canopen_driver.hpp:113
void configure()
Configure the driver.
Definition: node_canopen_driver.hpp:161
Definition: node_canopen_driver.hpp:32
Definition: configuration_manager.hpp:28
Definition: exchange.hpp:26
Definition: exchange.hpp:34