qb_device_communication_handler.cpp
Go to the documentation of this file.
1 /***
2  * Software License Agreement: BSD 3-Clause License
3  *
4  * Copyright (c) 2016-2018, qbrobotics®
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
8  * following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this list of conditions and the
11  * following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
14  * following disclaimer in the documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
17  * products derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
25  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
29 
30 using namespace qb_device_communication_handler;
31 
33  : qbDeviceCommunicationHandler(std::make_shared<qb_device_driver::qbDeviceAPI>()) {
34  while (!getSerialPortsAndDevices(1)) {
35  ROS_WARN_STREAM_NAMED("communication_handler", "[CommunicationHandler] is waiting for devices...");
36  ros::Duration(1.0).sleep();
37  }
38 
39  spinner_.start();
40 }
41 
43  : spinner_(11), // 10 is the maximum number of connected serial ports (cr. API)
44  node_handle_(ros::NodeHandle()),
45  activate_motors_(node_handle_.advertiseService("/communication_handler/activate_motors", &qbDeviceCommunicationHandler::activateCallback, this)),
46  deactivate_motors_(node_handle_.advertiseService("/communication_handler/deactivate_motors", &qbDeviceCommunicationHandler::deactivateCallback, this)),
47  get_info_(node_handle_.advertiseService("/communication_handler/get_info", &qbDeviceCommunicationHandler::getInfoCallback, this)),
48  get_measurements_(node_handle_.advertiseService("/communication_handler/get_measurements", &qbDeviceCommunicationHandler::getMeasurementsCallback, this)),
49  initialize_device_(node_handle_.advertiseService("/communication_handler/initialize_device", &qbDeviceCommunicationHandler::initializeCallback, this)),
50  set_commands_(node_handle_.advertiseService("/communication_handler/set_commands", &qbDeviceCommunicationHandler::setCommandsCallback, this)),
51  set_pid_(node_handle_.advertiseService("/communication_handler/set_pid", &qbDeviceCommunicationHandler::setPIDCallback, this)),
52  device_api_(device_api) {
53 
54 }
55 
57  for (auto const &file_descriptor : file_descriptors_) {
58  close(file_descriptor.first);
59  }
60 }
61 
62 int qbDeviceCommunicationHandler::activate(const int &id, const bool &command, const int &max_repeats) {
63  std::string command_prefix = command ? "" : "de";
64  bool status = false;
65  int failures = 0;
66 
67  failures = isActive(id, max_repeats, status);
68  if (status != command) {
69  device_api_->activate(&file_descriptors_.at(connected_devices_.at(id)), id, command);
70  failures = std::max(failures, isActive(id, max_repeats, status));
71  if (status != command) {
72  ROS_ERROR_STREAM_NAMED("communication_handler", "[CommunicationHandler] device [" << id << "] fails on " << command_prefix << "activation.");
73  return -1;
74  }
75  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] device [" << id << "] motors have been " << command_prefix << "activated!");
76  return failures;
77  }
78  ROS_DEBUG_STREAM_NAMED("communication_handler", "[CommunicationHandler] device [" << id << "] motors were already " << command_prefix << "activated!");
79  return failures;
80 }
81 
82 int qbDeviceCommunicationHandler::activate(const int &id, const int &max_repeats) {
83  return activate(id, true, max_repeats);
84 }
85 
86 bool qbDeviceCommunicationHandler::activateCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response) {
87  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
88  if (!isInConnectedSet(request.id)) {
89  response.message = "Device [" + std::to_string(request.id) + "] is not connected.";
90  response.success = false;
91  return true;
92  }
93  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
94 
95  response.message = "Device [" + std::to_string(request.id) + "] activation.";
96  response.failures = activate(request.id, request.max_repeats);
97  response.success = isReliable(response.failures, request.max_repeats);
98  return true;
99 }
100 
101 int qbDeviceCommunicationHandler::close(const std::string &serial_port) {
102  if (!isInOpenMap(serial_port)) {
103  ROS_WARN_STREAM_NAMED("communication_handler", "[CommunicationHandler] has not handled [" << serial_port << "].");
104  return 0; // no error: the communication is close anyway
105  }
106 
107  for (auto const &device : connected_devices_) {
108  if (device.second == serial_port) {
109  deactivate(device.first, 3);
110  connected_devices_.erase(device.first);
111  }
112  }
113  device_api_->close(&file_descriptors_.at(serial_port));
114  file_descriptors_.erase(serial_port);
115  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] does not handle [" << serial_port << "] anymore.");
116  return 0;
117 }
118 
119 int qbDeviceCommunicationHandler::deactivate(const int &id, const int &max_repeats) {
120  return activate(id, false, max_repeats);
121 }
122 
123 bool qbDeviceCommunicationHandler::deactivateCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response) {
124  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
125  if (!isInConnectedSet(request.id)) {
126  response.message = "Device [" + std::to_string(request.id) + "] is not connected.";
127  response.success = false;
128  return true;
129  }
130  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
131 
132  response.message = "Device [" + std::to_string(request.id) + "] deactivation.";
133  response.failures = deactivate(request.id, request.max_repeats);
134  response.success = isReliable(response.failures, request.max_repeats);
135  return true;
136 }
137 
138 int qbDeviceCommunicationHandler::getCurrents(const int &id, const int &max_repeats, std::vector<short int> &currents) {
139  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
140  int failures = 0;
141  currents.resize(2); // required by 'getCurrents()'
142  while (failures <= max_repeats) {
143  if (device_api_->getCurrents(&file_descriptors_.at(connected_devices_.at(id)), id, currents) < 0) {
144  failures++;
145  continue;
146  }
147  break;
148  }
149  return failures;
150 }
151 
152 int qbDeviceCommunicationHandler::getInfo(const int &id, const int &max_repeats, std::string &info) {
153  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
154  int failures = 0;
155  while (failures <= max_repeats) {
156  info = device_api_->getInfo(&file_descriptors_.at(connected_devices_.at(id)), id);
157  if (info == "") {
158  failures++;
159  continue;
160  }
161  break;
162  }
163  return failures;
164 }
165 
166 bool qbDeviceCommunicationHandler::getInfoCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response) {
167  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
168  if (!isInConnectedSet(request.id)) {
169  response.message = "Device [" + std::to_string(request.id) + "] is not connected.";
170  response.success = false;
171  return true;
172  }
173  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
174 
175  response.failures = getInfo(request.id, request.max_repeats, response.message); // blocks while reading
176  response.success = isReliable(response.failures, request.max_repeats);
177  return true;
178 }
179 
180 int qbDeviceCommunicationHandler::getMeasurements(const int &id, const int &max_repeats, std::vector<short int> &currents, std::vector<short int> &positions) {
181  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
182  int failures = 0;
183  currents.resize(2);
184  positions.resize(3);
185  std::vector<short int> measurements(5, 0); // required by 'getMeasurements()'
186  while (failures <= max_repeats) {
187  if (device_api_->getMeasurements(&file_descriptors_.at(connected_devices_.at(id)), id, measurements) < 0) {
188  failures++;
189  continue;
190  }
191  std::copy(measurements.begin(), measurements.begin()+2, currents.begin());
192  std::copy(measurements.begin()+2, measurements.end(), positions.begin());
193  break;
194  }
195  return failures;
196 }
197 
198 bool qbDeviceCommunicationHandler::getMeasurementsCallback(qb_device_srvs::GetMeasurementsRequest &request, qb_device_srvs::GetMeasurementsResponse &response) {
199  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
200  if (!isInConnectedSet(request.id)) {
201  response.success = false;
202  return true;
203  }
204  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
205 
206  response.failures = 0; // need to return true even if both 'get_currents' and 'get_positions' are set to false
207  if (request.get_currents && request.get_positions) {
208  if (!request.get_distinct_packages) {
209  response.failures = getMeasurements(request.id, request.max_repeats, response.currents, response.positions); // blocks while reading
210  }
211  else {
212  response.failures = getCurrents(request.id, request.max_repeats, response.currents)
213  + getPositions(request.id, request.max_repeats, response.positions); // both block while reading
214  }
215  }
216  else if (request.get_currents) {
217  response.failures = getCurrents(request.id, request.max_repeats, response.currents); // blocks while reading
218  }
219  else if (request.get_positions) {
220  response.failures = getPositions(request.id, request.max_repeats, response.positions); // blocks while reading
221  }
222 
223  response.stamp = ros::Time::now();
224  response.success = isReliable(response.failures, request.max_repeats);
225  return true;
226 }
227 
228 int qbDeviceCommunicationHandler::getParameters(const int &id, std::vector<int> &limits, std::vector<int> &resolutions) {
229  std::vector<int> input_mode = {-1};
230  std::vector<int> control_mode = {-1};
231  device_api_->getParameters(&file_descriptors_.at(connected_devices_.at(id)), id, input_mode, control_mode, resolutions, limits);
232  if (!input_mode.front() && !control_mode.front()) { // both input and control modes equals 0 are required, i.e. respectively USB connected and position controlled
233  return 0;
234  }
235  return -1;
236 }
237 
238 int qbDeviceCommunicationHandler::getPositions(const int &id, const int &max_repeats, std::vector<short int> &positions) {
239  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
240  int failures = 0;
241  positions.resize(3); // required by 'getPositions()'
242  while (failures <= max_repeats) {
243  if (device_api_->getPositions(&file_descriptors_.at(connected_devices_.at(id)), id, positions) < 0) {
244  failures++;
245  continue;
246  }
247  break;
248  }
249  return failures;
250 }
251 
253  std::map<int, std::string> connected_devices;
254  std::array<char[255], 10> serial_ports;
255  int serial_ports_number = device_api_->getSerialPorts(serial_ports);
256  for (int i=0; i<serial_ports_number; i++) {
257  int failures = 0;
258  while (failures <= max_repeats) {
259  if (open(serial_ports.at(i)) != 0) {
260  failures++;
261  continue;
262  }
263  break;
264  }
265  if (failures >= max_repeats) {
266  continue;
267  }
268 
269  // 'serial_protectors_' is not cleared because of the previously acquired lock, do not do it!
270  serial_protectors_.insert(std::make_pair(serial_ports.at(i), std::make_unique<std::mutex>())); // never override
271 
272  std::array<char, 255> devices;
273  int devices_number = device_api_->getDeviceIds(&file_descriptors_.at(serial_ports.at(i)), devices);
274  for (int j=0; j<devices_number; j++) {
275  if (devices.at(j) == 120) {
276  continue; // ID 120 is reserved for dummy board which should not be considered as a connected device
277  }
278  // actually a std::map does not let same-id devices on distinct serial ports
279  connected_devices.insert(std::make_pair(static_cast<int>(devices.at(j)), serial_ports.at(i)));
280  }
281  }
282 
283  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] has found [" << connected_devices.size() << "] devices connected:");
284  for (auto const &device : connected_devices) {
285  ROS_INFO_STREAM_NAMED("communication_handler", " - device [" << device.first << "] connected through [" << device.second << "]");
286  }
287 
288  connected_devices_ = connected_devices;
289  return connected_devices_.size();
290 }
291 
292 int qbDeviceCommunicationHandler::isActive(const int &id, const int &max_repeats, bool &status) {
293  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
294  int failures = 0;
295  status = false;
296  while (failures <= max_repeats) {
297  if (!device_api_->getStatus(&file_descriptors_.at(connected_devices_.at(id)), id, status)) {
298  failures++;
299  continue;
300  }
301  break;
302  }
303  return failures;
304 }
305 
306 int qbDeviceCommunicationHandler::isConnected(const int &id, const int &max_repeats) {
307  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
308  int failures = 0;
309  while (failures <= max_repeats) {
310  if (!device_api_->getStatus(&file_descriptors_.at(connected_devices_.at(id)), id)) {
311  failures++;
312  continue;
313  }
314  break;
315  }
316  return failures;
317 }
318 
320  return connected_devices_.count(id);
321 }
322 
323 bool qbDeviceCommunicationHandler::isInOpenMap(const std::string &serial_port) {
324  return file_descriptors_.count(serial_port);
325 }
326 
327 int qbDeviceCommunicationHandler::open(const std::string &serial_port) {
328  if (!std::regex_match(serial_port, std::regex("/dev/ttyUSB[[:digit:]]+"))) {
329  ROS_ERROR_STREAM_NAMED("communication_handler", "[CommunicationHandler] fails while opening [" << serial_port << "] because it does not match the expected pattern [/dev/ttyUSB*].");
330  return -1;
331  }
332 
333  if (isInOpenMap(serial_port)) {
334  ROS_DEBUG_STREAM_NAMED("communication_handler", "[CommunicationHandler] already handles [" << serial_port << "].");
335  return 0; // no error: the communication is open anyway
336  }
337 
338  device_api_->open(&file_descriptors_[serial_port], serial_port); // also create a pair in the map
339  if(file_descriptors_.at(serial_port).file_handle == INVALID_HANDLE_VALUE) {
340  ROS_ERROR_STREAM_NAMED("communication_handler", "[CommunicationHandler] fails while opening [" << serial_port << "] and sets errno [" << strerror(errno) << "].");
341  // remove file descriptor entry
342  file_descriptors_.erase(serial_port);
343  return -1;
344  }
345 
346  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] handles [" << serial_port << "].");
347  return 0;
348 }
349 
350 bool qbDeviceCommunicationHandler::initializeCallback(qb_device_srvs::InitializeDeviceRequest &request, qb_device_srvs::InitializeDeviceResponse &response) {
351  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
352  std::vector<std::unique_lock<std::mutex>> serial_locks; // need to lock on all the serial resources to scan for new ports/devices
353  for (auto const &mutex : serial_protectors_) {
354  serial_locks.push_back(std::unique_lock<std::mutex>(*mutex.second));
355  }
356 
357  if (request.rescan) {
358  // update connected devices
359  getSerialPortsAndDevices(request.max_repeats);
360  }
361  if (!isInConnectedSet(request.id) || !isReliable(isConnected(request.id, request.max_repeats), request.max_repeats)) {
362  ROS_ERROR_STREAM_NAMED("communication_handler", "[CommunicationHandler] fails while initializing device [" << request.id << "] because it is not connected.");
363  response.message = "Device [" + std::to_string(request.id) + "] initialization fails because it is not connected.";
364  response.success = false;
365  return true;
366  }
367 
368  if (getParameters(request.id, response.info.position_limits, response.info.encoder_resolutions)) {
369  ROS_ERROR_STREAM_NAMED("communication_handler", "[CommunicationHandler] fails while initializing device [" << request.id << "] because it requires 'USB' input mode and 'Position' control mode.");
370  response.message = "Device [" + std::to_string(request.id) + "] initialization fails because it requires 'USB' input mode and 'Position' control mode.";
371  response.success = false;
372  return true;
373  }
374  if (request.activate) {
375  response.failures = activate(request.id, request.max_repeats);
376  response.success = isReliable(response.failures, request.max_repeats);
377  if (!response.success) {
378  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] has not initialized device [" << request.id << "] because it cannot activate its motors (please, check the motor positions).");
379  response.message = "Device [" + std::to_string(request.id) + "] initialization fails because it cannot activate the device (please, check the motor positions).";
380  return true;
381  }
382  }
383  response.info.id = request.id;
384  response.info.serial_port = connected_devices_.at(request.id);
385  ROS_INFO_STREAM_NAMED("communication_handler", "[CommunicationHandler] has initialized device [" << request.id << "].");
386  response.message = "Device [" + std::to_string(request.id) + "] initialization succeeds.";
387  response.success = true;
388  return true;
389 }
390 
391 int qbDeviceCommunicationHandler::setCommandsAndWait(const int &id, const int &max_repeats, std::vector<short int> &commands) {
392  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
393  int failures = 0;
394  commands.resize(2); // required by 'setCommandsAndWait()'
395  while (failures <= max_repeats) {
396  if (device_api_->setCommandsAndWait(&file_descriptors_.at(connected_devices_.at(id)), id, commands) < 0) {
397  failures++;
398  continue;
399  }
400  break;
401  }
402  return failures;
403 }
404 
405 int qbDeviceCommunicationHandler::setCommandsAsync(const int &id, std::vector<short int> &commands) {
406  // qbhand sets only inputs.at(0), but setCommandsAsync expects two-element vector (ok for both qbhand and qbmove)
407  commands.resize(2); // required by 'setCommandsAsync()'
408  device_api_->setCommandsAsync(&file_descriptors_.at(connected_devices_.at(id)), id, commands);
409  return 0; // note that this is a non reliable method
410 }
411 
412 bool qbDeviceCommunicationHandler::setCommandsCallback(qb_device_srvs::SetCommandsRequest &request, qb_device_srvs::SetCommandsResponse &response) {
413  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
414  if (!isInConnectedSet(request.id)) {
415  response.success = false;
416  return true;
417  }
418  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
419 
420  if (request.set_commands) {
421  if (!request.set_commands_async) {
422  response.failures = setCommandsAndWait(request.id, request.max_repeats, request.commands); // blocking function
423  }
424  else {
425  response.failures = setCommandsAsync(request.id, request.commands); // non-blocking (unreliable) function
426  }
427  }
428  response.success = isReliable(response.failures, request.max_repeats);
429  return true;
430 }
431 
432 int qbDeviceCommunicationHandler::setPID(const int &id, const int &max_repeats, std::vector<float> &pid) {
433  // the API methods are called at most (i.e. very unlikely) 'max_repeats' times to guarantee the correct identification of a real fault in the communication
434  int failures = 0;
435  while (failures <= max_repeats) {
436  if (device_api_->setPID(&file_descriptors_.at(connected_devices_.at(id)), id, pid) < 0) {
437  failures++;
438  continue;
439  }
440  break;
441  }
442  return failures;
443 }
444 
445 bool qbDeviceCommunicationHandler::setPIDCallback(qb_device_srvs::SetPIDRequest &request, qb_device_srvs::SetPIDResponse &response) {
446  ROS_ERROR_STREAM_COND_NAMED(request.max_repeats < 0, "communication_handler", "Device [" << request.id << "] has request service with non-valid 'max_request' [" << request.max_repeats << "].");
447  if (!isInConnectedSet(request.id)) {
448  response.success = false;
449  return true;
450  }
451  if (request.p < 0 || request.p > 1 || request.i < 0 || request.i > 0.1 || request.d < 0 || request.d > 0.1) { //TODO: set hardcoded properly
452  ROS_ERROR_STREAM_NAMED("communication_handler","PID parameters are not in their acceptable ranges");
453  response.success = false;
454  return true;
455  }
456  std::lock_guard<std::mutex> serial_lock(*serial_protectors_.at(connected_devices_.at(request.id)));
457 
458  std::vector<float> pid({request.p, request.i, request.d});
459  response.failures = setPID(request.id, request.max_repeats, pid); // blocking function
460  response.success = isReliable(response.failures, request.max_repeats);
461  return true;
462 }
virtual int getMeasurements(const int &id, const int &max_repeats, std::vector< short int > &currents, std::vector< short int > &positions)
Retrieve the motor currents of the given device.
#define ROS_DEBUG_STREAM_NAMED(name, args)
#define ROS_ERROR_STREAM_NAMED(name, args)
bool getMeasurementsCallback(qb_device_srvs::GetMeasurementsRequest &request, qb_device_srvs::GetMeasurementsResponse &response)
Retrieve the motor positions and currents of the device relative to the node requesting the service...
virtual int getCurrents(const int &id, const int &max_repeats, std::vector< short int > &currents)
Retrieve the motor currents of the given device.
virtual int getInfo(const int &id, const int &max_repeats, std::string &info)
Retrieve the printable configuration setup of the given device.
bool sleep() const
virtual int getPositions(const int &id, const int &max_repeats, std::vector< short int > &positions)
Retrieve the motor positions of the given device.
#define ROS_INFO_STREAM_NAMED(name, args)
virtual int isActive(const int &id, const int &max_repeats, bool &status)
Check whether the motors of the device specified by the given ID are active.
bool setCommandsCallback(qb_device_srvs::SetCommandsRequest &request, qb_device_srvs::SetCommandsResponse &response)
Send the reference command to the motors of the device relative to the node requesting the service...
virtual ~qbDeviceCommunicationHandler()
Close all the still open serial ports.
virtual int getParameters(const int &id, std::vector< int > &limits, std::vector< int > &resolutions)
Retrieve some of the parameters from the given device.
bool getInfoCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response)
Retrieve the printable configuration setup of the device relative to the node requesting the service...
virtual bool initializeCallback(qb_device_srvs::InitializeDeviceRequest &request, qb_device_srvs::InitializeDeviceResponse &response)
Initialize the device node requesting the service to the Communication Handler if the relative physic...
virtual int setCommandsAsync(const int &id, std::vector< short int > &commands)
Send the reference command to the motors of the given device in a non-blocking fashion.
virtual int activate(const int &id, const int &max_repeats)
Activate the motors of the given device.
virtual bool isInOpenMap(const std::string &serial_port)
Check whether the given serial port is managed by the Communication Handler, i.e. ...
bool setPIDCallback(qb_device_srvs::SetPIDRequest &request, qb_device_srvs::SetPIDResponse &response)
Set (temporarily, i.e.
virtual int setCommandsAndWait(const int &id, const int &max_repeats, std::vector< short int > &commands)
Send the reference command to the motors of the given device and wait for acknowledge.
int setPID(const int &id, const int &max_repeats, std::vector< float > &pid)
Set the position control PID parameters of the given device, temporarily (until power off)...
bool activateCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response)
Activate the motors of the device relative to the node requesting the service.
qbDeviceCommunicationHandler()
Wait until at least one device is connected and then initialize the Communication Handler...
bool isReliable(int const &failures, int const &max_repeats)
Check whether the reading failures are in the given range.
virtual int deactivate(const int &id, const int &max_repeats)
Deactivate the motors of the given device.
virtual int isConnected(const int &id, const int &max_repeats)
Check whether the the device specified by the given ID is connected through the serial port...
static Time now()
The Communication Handler class is aimed to instantiate a ROS node which provides several ROS service...
virtual bool isInConnectedSet(const int &id)
Check whether the physical device specified by the given ID is connected to the Communication Handler...
std::map< std::string, std::unique_ptr< std::mutex > > serial_protectors_
#define INVALID_HANDLE_VALUE
std::shared_ptr< qbDeviceAPI > qbDeviceAPIPtr
virtual int close(const std::string &serial_port)
Close the communication with all the devices connected to the given serial port.
bool deactivateCallback(qb_device_srvs::TriggerRequest &request, qb_device_srvs::TriggerResponse &response)
Deactivate the motors of the device relative to the node requesting the service.
#define ROS_WARN_STREAM_NAMED(name, args)
virtual int open(const std::string &serial_port)
Open the serial communication on the given serial port.
virtual int getSerialPortsAndDevices(const int &max_repeats)
Scan for all the serial ports of type /dev/ttyUSB* detected in the system, initialize their mutex pro...
#define ROS_ERROR_STREAM_COND_NAMED(cond, name, args)


qb_device_driver
Author(s): qbrobotics®
autogenerated on Thu Jun 6 2019 19:46:35