58 close(file_descriptor.first);
63 std::string command_prefix = command ?
"" :
"de";
67 failures =
isActive(
id, max_repeats, status);
68 if (status != 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.");
75 ROS_INFO_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] device [" <<
id <<
"] motors have been " << command_prefix <<
"activated!");
78 ROS_DEBUG_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] device [" <<
id <<
"] motors were already " << command_prefix <<
"activated!");
83 return activate(
id,
true, max_repeats);
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 <<
"].");
89 response.message =
"Device [" + std::to_string(request.id) +
"] is not connected.";
90 response.success =
false;
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);
103 ROS_WARN_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] has not handled [" << serial_port <<
"].");
108 if (device.second == serial_port) {
110 connected_devices_.erase(device.first);
115 ROS_INFO_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] does not handle [" << serial_port <<
"] anymore.");
120 return activate(
id,
false, max_repeats);
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 <<
"].");
126 response.message =
"Device [" + std::to_string(request.id) +
"] is not connected.";
127 response.success =
false;
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);
142 while (failures <= max_repeats) {
155 while (failures <= max_repeats) {
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 <<
"].");
169 response.message =
"Device [" + std::to_string(request.id) +
"] is not connected.";
170 response.success =
false;
175 response.failures =
getInfo(request.id, request.max_repeats, response.message);
176 response.success =
isReliable(response.failures, request.max_repeats);
185 std::vector<short int> measurements(5, 0);
186 while (failures <= max_repeats) {
191 std::copy(measurements.begin(), measurements.begin()+2, currents.begin());
192 std::copy(measurements.begin()+2, measurements.end(), positions.begin());
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 <<
"].");
201 response.success =
false;
206 response.failures = 0;
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);
212 response.failures =
getCurrents(request.id, request.max_repeats, response.currents)
213 +
getPositions(request.id, request.max_repeats, response.positions);
216 else if (request.get_currents) {
217 response.failures =
getCurrents(request.id, request.max_repeats, response.currents);
219 else if (request.get_positions) {
220 response.failures =
getPositions(request.id, request.max_repeats, response.positions);
224 response.success =
isReliable(response.failures, request.max_repeats);
229 std::vector<int> input_mode = {-1};
230 std::vector<int> control_mode = {-1};
232 if (!input_mode.front() && !control_mode.front()) {
242 while (failures <= max_repeats) {
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++) {
258 while (failures <= max_repeats) {
259 if (
open(serial_ports.at(i)) != 0) {
265 if (failures >= max_repeats) {
270 serial_protectors_.insert(std::make_pair(serial_ports.at(i), std::make_unique<std::mutex>()));
272 std::array<char, 255> devices;
274 for (
int j=0; j<devices_number; j++) {
275 if (devices.at(j) == 120) {
279 connected_devices.insert(std::make_pair(static_cast<int>(devices.at(j)), serial_ports.at(i)));
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 <<
"]");
296 while (failures <= max_repeats) {
309 while (failures <= max_repeats) {
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*].");
334 ROS_DEBUG_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] already handles [" << serial_port <<
"].");
340 ROS_ERROR_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] fails while opening [" << serial_port <<
"] and sets errno [" << strerror(errno) <<
"].");
346 ROS_INFO_STREAM_NAMED(
"communication_handler",
"[CommunicationHandler] handles [" << serial_port <<
"].");
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;
354 serial_locks.push_back(std::unique_lock<std::mutex>(*mutex.second));
357 if (request.rescan) {
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;
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;
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).";
383 response.info.id = 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;
395 while (failures <= max_repeats) {
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 <<
"].");
415 response.success =
false;
420 if (request.set_commands) {
421 if (!request.set_commands_async) {
422 response.failures =
setCommandsAndWait(request.id, request.max_repeats, request.commands);
428 response.success =
isReliable(response.failures, request.max_repeats);
435 while (failures <= max_repeats) {
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 <<
"].");
448 response.success =
false;
451 if (request.p < 0 || request.p > 1 || request.i < 0 || request.i > 0.1 || request.d < 0 || request.d > 0.1) {
453 response.success =
false;
458 std::vector<float> pid({request.p, request.i, request.d});
459 response.failures =
setPID(request.id, request.max_repeats, pid);
460 response.success =
isReliable(response.failures, request.max_repeats);
ros::ServiceServer deactivate_motors_
virtual int getMeasurements(const int &id, const int &max_repeats, std::vector< short int > ¤ts, 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 > ¤ts)
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.
ros::ServiceServer get_measurements_
qb_device_driver::qbDeviceAPIPtr device_api_
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)
ros::ServiceServer set_pid_
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.
ros::ServiceServer activate_motors_
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...
std::map< std::string, comm_settings > file_descriptors_
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...
ros::NodeHandle node_handle_
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...
std::map< int, std::string > connected_devices_
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.
ros::ServiceServer set_commands_
ros::ServiceServer get_info_
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.
ros::AsyncSpinner spinner_
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...
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.
ros::ServiceServer initialize_device_
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)