ttl_manager.cpp
Go to the documentation of this file.
1 /*
2  ttl_driver.cpp
3  Copyright (C) 2020 Niryo
4  All rights reserved.
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13  You should have received a copy of the GNU General Public License
14  along with this program. If not, see <http:// www.gnu.org/licenses/>.
15 */
16 
18 
19 // cpp
20 #include <algorithm>
21 #include <cassert>
22 #include <cmath>
23 #include <cstdlib>
24 #include <memory>
25 #include <set>
26 #include <sstream>
27 #include <string>
28 #include <unordered_map>
29 #include <utility>
30 #include <vector>
31 
32 // ros
33 #include "ros/serialization.h"
34 #include "ros/time.h"
35 
36 // niryo
37 #include "common/model/dxl_command_type_enum.hpp"
38 #include "common/model/end_effector_state.hpp"
39 #include "common/model/hardware_type_enum.hpp"
40 #include "common/model/stepper_calibration_status_enum.hpp"
41 #include "common/model/stepper_motor_state.hpp"
42 #include "common/model/tool_state.hpp"
43 
44 #include "dynamixel_sdk/packet_handler.h"
45 #include "niryo_robot_msgs/CommandStatus.h"
48 
58 #include "ttl_driver/CalibrationStatus.h"
59 
60 using ::std::ostringstream;
61 using ::std::set;
62 using ::std::shared_ptr;
63 using ::std::string;
64 using ::std::to_string;
65 using ::std::vector;
66 
67 using ::common::model::ConveyorState;
68 using ::common::model::EHardwareType;
69 using ::common::model::EndEffectorState;
70 using ::common::model::EStepperCalibrationStatus;
71 using ::common::model::HardwareTypeEnum;
72 using ::common::model::JointState;
73 using ::common::model::StepperMotorState;
74 
75 namespace ttl_driver
76 {
80 TtlManager::TtlManager(ros::NodeHandle &nh)
81  : _nh(nh), _debug_error_message("TtlManager - No connection with TTL motors has been made yet")
82 {
83  ROS_DEBUG("TtlManager - ctor");
84 
85  init(nh);
86 
87  if (COMM_SUCCESS != setupCommunication())
88  ROS_WARN("TtlManager - TTL Communication Failed");
89 }
90 
95 {
96  if (_portHandler)
97  {
98  _portHandler->clearPort();
99  _portHandler->closePort();
100  }
101 }
102 
108 bool TtlManager::init(ros::NodeHandle &nh)
109 {
110  // get params from rosparams
111  bool use_simu_gripper{ false };
112  bool use_simu_conveyor{ false };
113 
114  _nh.getParam("fake_params/available_tools/id", _available_tools);
115 
116  nh.getParam("bus_params/uart_device_name", _device_name);
117  nh.getParam("bus_params/baudrate", _baudrate);
118  nh.getParam("led_motor", _led_motor_type_cfg);
119 
120  nh.getParam("simulation_mode", _simulation_mode);
121  nh.getParam("simu_gripper", use_simu_gripper);
122  nh.getParam("simu_conveyor", use_simu_conveyor);
123  nh.getParam("fake_params/tool/id", _current_tool_vector);
124  if (!_current_tool_vector.empty())
125  {
127  }
128 
129  ROS_DEBUG("TtlManager::init - Dxl : set port name (%s), baudrate(%d)", _device_name.c_str(), _baudrate);
130  ROS_DEBUG("TtlManager::init - led motor type config : %s", _led_motor_type_cfg.c_str());
131 
132  ROS_DEBUG("TtlManager::init - Simulation mode: %s, simu_gripper: %s, simu_conveyor: %s",
133  _simulation_mode ? "True" : "False", use_simu_gripper ? "True" : "False",
134  use_simu_conveyor ? "True" : "False");
135 
136  if (!_simulation_mode)
137  {
138  _portHandler.reset(dynamixel::PortHandler::getPortHandler(_device_name.c_str()));
139  _packetHandler.reset(dynamixel::PacketHandler::getPacketHandler(TTL_BUS_PROTOCOL_VERSION));
140 
141  // init default ttl driver for common operations between drivers
142  _default_ttl_driver = std::make_shared<StepperDriver<StepperReg>>(_portHandler, _packetHandler);
143  }
144  else
145  {
146  readFakeConfig(use_simu_gripper, use_simu_conveyor);
147  _default_ttl_driver = std::make_shared<MockStepperDriver>(_fake_data);
148  }
149 
150  _calibration_status_publisher = nh.advertise<ttl_driver::CalibrationStatus>("calibration_status", 1, true);
151 
152  return true;
153 }
154 
159 bool TtlManager::changeTool(int value, string &message, int &status)
160 {
161  std::lock_guard<std::mutex> lck(_sync_mutex);
162  auto it_driver = _motor_driver_map.find(EHardwareType::FAKE_DXL_MOTOR);
163  if (it_driver == _motor_driver_map.end())
164  {
165  status = niryo_robot_msgs::CommandStatus::TOOL_FAILURE;
166  message = "Tool change failed : Real robot mode";
167  return true;
168  }
169 
170  auto driver = it_driver->second;
171  if (!driver)
172  {
173  status = niryo_robot_msgs::CommandStatus::TOOL_ID_INVALID;
174  message = "Tool change failed : Driver not found";
175  return true;
176  }
177 
178  if (value != 0)
179  {
180  auto it = std::find(_available_tools.begin(), _available_tools.end(), value);
181 
182  if (it == _available_tools.end())
183  {
184  status = niryo_robot_msgs::CommandStatus::TOOL_ID_INVALID;
185  message = "Tool change failed: Tool ID is invalid";
186  return true;
187  }
188 
189  if (_current_tool_id == 0)
190  {
191  retrieveFakeMotorData("fake_params/tool/", _fake_data->dxl_registers, { value });
192  }
193  }
194 
195  if (driver->changeId(_current_tool_id, value) == COMM_SUCCESS)
196  {
197  _current_tool_id = value;
198  status = niryo_robot_msgs::CommandStatus::SUCCESS;
199  message = "Tool change succeeded";
200  }
201  else
202  {
203  status = niryo_robot_msgs::CommandStatus::TOOL_NOT_CONNECTED;
204  message = "Tool change failed: Communication error";
205  }
206 
207  // return response even request failed
208  return true;
209 }
210 
216 {
217  int ret = COMM_NOT_AVAILABLE;
218 
219  ROS_DEBUG("TtlManager::setupCommunication - initializing connection...");
220 
221  // fake drivers will always succeed for the communication
222  if (_simulation_mode)
223  {
224  ret = COMM_SUCCESS;
225  }
226  else
227  {
228  // Ttl bus setup
229  if (_portHandler)
230  {
231  _debug_error_message.clear();
232 
233  // Open port
234  if (_portHandler->openPort())
235  {
236  // Set baudrate
237  if (_portHandler->setBaudRate(_baudrate))
238  {
239  // wait a bit to be sure the connection is established
240  ros::Duration(0.1).sleep();
241 
242  // clear port
243  _portHandler->clearPort();
244 
245  ret = COMM_SUCCESS;
246  }
247  else
248  {
249  ROS_ERROR("TtlManager::setupCommunication - Failed to set baudrate for Dynamixel bus");
250  _debug_error_message = "TtlManager - Failed to set baudrate for Dynamixel bus";
252  }
253  }
254  else
255  {
256  ROS_ERROR("TtlManager::setupCommunication - Failed to open Uart port for Dynamixel bus");
257  _debug_error_message = "TtlManager - Failed to open Uart port for Dynamixel bus";
258  ret = TTL_FAIL_OPEN_PORT;
259  }
260  }
261  else
262  ROS_ERROR("TtlManager::setupCommunication - Invalid port handler");
263  }
264 
265  return ret;
266 }
267 
272 int TtlManager::addHardwareComponent(std::shared_ptr<common::model::AbstractHardwareState> &&state) // NOLINT
273 {
274  if (!state)
275  {
276  return niryo_robot_msgs::CommandStatus::FAILURE;
277  }
278 
279  EHardwareType hardware_type = state->getHardwareType();
280  uint8_t id = state->getId();
281 
282  ROS_DEBUG("TtlManager::addHardwareComponent : %s", state->str().c_str());
283 
284  addHardwareDriver(hardware_type);
285 
286  auto driver_it = _driver_map.find(hardware_type);
287  if (driver_it == _driver_map.end())
288  {
289  ROS_ERROR("TtlManager::addHardwareComponent - No driver found for hardware type %d",
290  static_cast<int>(hardware_type));
291  return niryo_robot_msgs::CommandStatus::FAILURE;
292  }
293  auto driver = driver_it->second;
294 
295  uint16_t model_number = 0;
296  // check if the driver is valid for this hardware
297  if (state->getStrictModelNumber() && driver->checkModelNumber(id, model_number) != COMM_SUCCESS)
298  {
299  ROS_WARN("TtlManager::addHardwareComponent - Model number check failed for hardware id %d", id);
300  return niryo_robot_msgs::CommandStatus::HARDWARE_NOT_SUPPORTED;
301  }
302  else if (driver->getModelNumber(id, model_number) != COMM_SUCCESS)
303  {
304  ROS_WARN("TtlManager::addHardwareComponent - Unable to retrieve model number for hardware id %d", id);
305  return niryo_robot_msgs::CommandStatus::HARDWARE_NOT_SUPPORTED;
306  }
307 
308  state->setModelNumber(model_number);
309 
310  // update firmware version
311  std::string version;
312  int res = COMM_RX_FAIL;
313  for (int tries = 10; tries > 0; tries--)
314  {
315  res = driver->readFirmwareVersion(id, version);
316  if (COMM_SUCCESS == res)
317  {
318  state->setFirmwareVersion(version);
319  break;
320  }
321  ros::Duration(0.1).sleep();
322  }
323 
324  if (COMM_SUCCESS != res)
325  {
326  ROS_WARN(
327  "TtlManager::addHardwareComponent : Unable to retrieve firmware version for "
328  "hardware id %d : result = %d",
329  id, res);
330  }
331 
332  // add state to state map
333  _state_map[id] = state;
334 
335  if (_motor_driver_map.count(hardware_type))
336  {
337  _motor_state_map[id] = std::dynamic_pointer_cast<common::model::AbstractMotorState>(state);
338  }
339  else if (_end_effector_driver_map.count(hardware_type))
340  {
341  _end_effector_state_map[id] = std::dynamic_pointer_cast<common::model::EndEffectorState>(state);
342  }
343 
344  // add id to ids_map
345  _ids_map[hardware_type].emplace_back(id);
346 
347  // add to global lists
348  if (common::model::EComponentType::CONVEYOR == state->getComponentType())
349  {
350  if (std::find(_conveyor_list.begin(), _conveyor_list.end(), id) == _conveyor_list.end())
351  _conveyor_list.emplace_back(id);
352  }
353 
354  // Reset the calibration if we add a new joint and it is not a simulated one
355  if (common::model::EComponentType::JOINT == state->getComponentType())
356  {
357  if (!(common::model::EHardwareType::FAKE_STEPPER_MOTOR == hardware_type ||
358  common::model::EHardwareType::FAKE_DXL_MOTOR == hardware_type))
359  {
360  _calibration_status = EStepperCalibrationStatus::UNINITIALIZED;
361  }
362  }
363 
365  return niryo_robot_msgs::CommandStatus::SUCCESS;
366 }
367 
373 {
374  ROS_DEBUG("TtlManager::removeMotor - Remove motor id: %d", id);
375 
376  if (_state_map.count(id) && _state_map.at(id))
377  {
378  EHardwareType type = _state_map.at(id)->getHardwareType();
379 
380  // std::remove to remove hypothetic duplicates too
381  if (_ids_map.count(type))
382  {
383  auto &ids = _ids_map.at(type);
384  ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
385  if (ids.empty())
386  {
387  _ids_map.erase(type);
388  }
389  }
390 
391  _state_map.erase(id);
392  _motor_state_map.erase(id);
393  _end_effector_state_map.erase(id);
394  }
395  // remove id from conveyor list if they contains id
396  _conveyor_list.erase(std::remove(_conveyor_list.begin(), _conveyor_list.end(), id), _conveyor_list.end());
397 
398  _removed_motor_id_list.erase(std::remove(_removed_motor_id_list.begin(), _removed_motor_id_list.end(), id),
399  _removed_motor_id_list.end());
400 }
401 
408 bool TtlManager::isMotorType(EHardwareType type)
409 {
410  // All motors have value under 7 (check in EHardwareType)
411  return (static_cast<int>(type) <= 7);
412 }
413 
414 // ****************
415 // commands
416 // ****************
417 
425 int TtlManager::changeId(EHardwareType motor_type, uint8_t old_id, uint8_t new_id)
426 {
427  int ret = COMM_TX_FAIL;
428 
429  if (old_id == new_id)
430  {
431  ret = COMM_SUCCESS;
432  }
433  else if (_motor_driver_map.count(motor_type))
434  {
435  auto driver = _motor_driver_map.at(motor_type);
436 
437  if (driver)
438  {
439  ret = driver->changeId(old_id, new_id);
440  if (COMM_SUCCESS == ret)
441  {
442  // update all maps
443  auto i_state = _state_map.find(old_id);
444  auto i_motor_state = _motor_state_map.find(old_id);
445  // update all maps
446  if (i_motor_state != _motor_state_map.end())
447  {
448  auto current_state = i_state->second;
449 
450  auto motor_node = _motor_state_map.extract(i_motor_state);
451  auto node = _state_map.extract(i_state);
452  motor_node.key() = new_id;
453  node.key() = new_id;
454  _motor_state_map.insert(std::move(motor_node));
455  _state_map.insert(std::move(node));
456 
457  // update conveyor list if needed
458  if (common::model::EComponentType::CONVEYOR == current_state->getComponentType())
459  {
460  // change old id into new id in vector
461  auto iter = std::find(_conveyor_list.begin(), _conveyor_list.end(), old_id);
462  if (iter != _conveyor_list.end())
463  *iter = new_id;
464  }
465  }
466  if (_ids_map.count(motor_type))
467  {
468  // update all maps
469  _ids_map.at(motor_type)
470  .erase(std::remove(_ids_map.at(motor_type).begin(), _ids_map.at(motor_type).end(), old_id),
471  _ids_map.at(motor_type).end());
472 
473  // update all maps
474  _ids_map.at(motor_type).emplace_back(new_id);
475  }
476  }
477  }
478  }
479 
480  return ret;
481 }
482 
488 {
489  ROS_DEBUG("TtlManager::scanAndCheck");
490  int result = COMM_PORT_BUSY;
491 
492  _is_connection_ok = false;
493 
494  // 1. retrieve list of connected motors
495  _all_ids_connected.clear();
496  for (int counter = 0; counter < 50 && COMM_SUCCESS != result; ++counter)
497  {
499  ROS_DEBUG_COND(COMM_SUCCESS != result, "TtlManager::scanAndCheck status: %d (counter: %d)", result, counter);
500  ros::Duration(TIME_TO_WAIT_IF_BUSY).sleep();
501  }
502 
503  if (COMM_SUCCESS == result)
504  {
505  // 2. update list of removed ids and update corresponding states
506  _removed_motor_id_list.clear();
507  std::string error_motors_message;
508  for (auto &istate : _state_map)
509  {
510  if (istate.second)
511  {
512  uint8_t id = istate.first;
513  auto it = find(_all_ids_connected.begin(), _all_ids_connected.end(), id);
514  // not found
515  if (it == _all_ids_connected.end())
516  {
517  _removed_motor_id_list.emplace_back(id);
518  error_motors_message += " " + to_string(id);
519  istate.second->setConnectionStatus(true);
520  }
521  else
522  {
523  istate.second->setConnectionStatus(false);
524  }
525  }
526  }
527 
528  if (_removed_motor_id_list.empty())
529  {
530  _is_connection_ok = true;
531  _debug_error_message.clear();
532  result = TTL_SCAN_OK;
533  }
534  else
535  {
536  _debug_error_message = "Motor(s):" + error_motors_message + " do not seem to be connected";
537  result = TTL_SCAN_MISSING_MOTOR;
538  }
539  }
540  else
541  {
542  _debug_error_message = "TtlManager - Failed to scan motors, physical bus is too busy. Will retry...";
543  ROS_WARN_THROTTLE(1, "TtlManager::scanAndCheck - Failed to scan motors, physical bus is too busy");
544  }
545 
546  return result;
547 }
548 
556 bool TtlManager::ping(uint8_t id)
557 {
558  int result = false;
559 
561  {
562  if (COMM_SUCCESS == _default_ttl_driver->ping(id))
563  result = true;
564  }
565 
566  return result;
567 }
568 
574 int TtlManager::rebootHardware(uint8_t hw_id)
575 {
576  int return_value = COMM_TX_FAIL;
577 
578  if (_state_map.count(hw_id) != 0 && _state_map.at(hw_id))
579  {
580  EHardwareType type = _state_map.at(hw_id)->getHardwareType();
581  ROS_DEBUG("TtlManager::rebootHardware - Reboot hardware with ID: %d", hw_id);
582  if (_driver_map.count(type) && _driver_map.at(type))
583  {
584  return_value = _driver_map.at(type)->reboot(hw_id);
585  if (COMM_SUCCESS == return_value)
586  {
587  std::string version;
588  int res = COMM_RX_FAIL;
589  for (int tries = 10; tries > 0; tries--)
590  {
591  res = _driver_map.at(type)->readFirmwareVersion(hw_id, version);
592  if (COMM_SUCCESS == res)
593  {
594  _state_map.at(hw_id)->setFirmwareVersion(version);
595  break;
596  }
597  ros::Duration(0.1).sleep();
598  }
599 
600  if (COMM_SUCCESS != res)
601  {
602  ROS_WARN(
603  "TtlManager::addHardwareComponent : Unable to retrieve firmware version for "
604  "hardware id %d : result = %d",
605  hw_id, res);
606  }
607  }
608  ROS_WARN_COND(COMM_SUCCESS != return_value, "TtlManager::rebootHardware - Failed to reboot hardware: %d",
609  return_value);
610  }
611  }
612 
613  return return_value;
614 }
615 
621 {
622  for (auto const &[hw_type, driver] : _motor_driver_map)
623  {
624  if (driver && _ids_map.count(hw_type) && !_ids_map.at(hw_type).empty())
625  {
626  // we retrieve all the associated id for the type of the current driver
627  vector<uint8_t> ids_list = _ids_map.at(hw_type);
628 
629  auto jStates = getMotorsStates();
630 
631  for (size_t i = 0; i < ids_list.size(); ++i)
632  {
633  auto jState_it = std::find_if(jStates.begin(), jStates.end(),
634  [i](const std::shared_ptr<JointState> &jState) { return i == jState->getId(); });
635  if (jState_it == jStates.end())
636  {
637  continue;
638  }
639  auto jState = *jState_it;
640  ROS_DEBUG("TtlManager::resetTorques - Torque ON on stepper ID: %d", static_cast<int>(ids_list.at(i)));
641  driver->writeTorquePercentage(ids_list.at(i), jState->getTorquePercentage());
642  } // for ids_list
643  }
644  } // for _driver_map
645 }
646 
647 // ******************
648 // Read operations
649 // ******************
650 
656 uint32_t TtlManager::getPosition(const JointState &motor_state)
657 {
658  uint32_t position = 0;
659  EHardwareType hardware_type = motor_state.getHardwareType();
660  if (_motor_driver_map.count(hardware_type))
661  {
662  auto driver = _motor_driver_map.at(hardware_type);
663  if (driver)
664  {
666  {
667  if (COMM_SUCCESS == driver->readPosition(motor_state.getId(), position))
668  {
670  break;
671  }
672  }
673  }
674 
675  if (0 < _hw_fail_counter_read)
676  {
677  ROS_ERROR_THROTTLE(1, "TtlManager::getPosition - motor connection problem - Failed to read from bus");
678  _debug_error_message = "TtlManager - Connection problem with Bus.";
680  _is_connection_ok = false;
681  }
682  }
683  else
684  {
685  ROS_ERROR_THROTTLE(1, "TtlManager::getPosition - Driver not found for requested motor id");
686  _debug_error_message = "TtlManager::getPosition - Driver not found for requested motor id";
687  }
688  return position;
689 }
690 
692 {
693  EHardwareType hw_type(EHardwareType::STEPPER);
694  auto driver = std::dynamic_pointer_cast<ttl_driver::StepperDriver<ttl_driver::StepperReg>>(_driver_map[hw_type]);
695  if (driver && _ids_map.count(hw_type) && !_ids_map.at(hw_type).empty())
696  {
697  // we retrieve all the associated id for the type of the current driver
698  vector<uint8_t> ids_list = _ids_map.at(hw_type);
699 
700  // we retrieve all the associated id for the type of the current driver
701  vector<uint32_t> homing_abs_position_list;
702 
703  // retrieve joint status
704  int res = driver->syncReadHomingAbsPosition(ids_list, homing_abs_position_list);
705  if (COMM_SUCCESS == res)
706  {
707  if (ids_list.size() == homing_abs_position_list.size())
708  {
709  // set motors states accordingly
710  for (size_t i = 0; i < ids_list.size(); ++i)
711  {
712  uint8_t id = ids_list.at(i);
713 
714  if (_state_map.count(id))
715  {
716  auto state = std::dynamic_pointer_cast<common::model::StepperMotorState>(_state_map.at(id));
717  if (state)
718  {
719  state->setHomingAbsPosition(static_cast<uint32_t>(homing_abs_position_list.at(i)));
720  }
721  else
722  {
723  ROS_ERROR("TtlManager::readHomingAbsPosition - null pointer");
724  return false;
725  }
726  }
727  else
728  {
729  ROS_ERROR("TtlManager::readHomingAbsPosition - No hardware state assossiated to ID: %d",
730  static_cast<int>(id));
731  return false;
732  }
733  }
734  }
735  else
736  {
737  ROS_ERROR(
738  "TtlManager::readHomingAbsPosition - size of requested id %d mismatch size of retrieved homing position %d",
739  static_cast<int>(ids_list.size()), static_cast<int>(homing_abs_position_list.size()));
740  return false;
741  }
742  }
743  else
744  {
745  ROS_ERROR("TtlManager::readHomingAbsPosition - communication error: %d", static_cast<int>(res));
746  return false;
747  }
748  }
749  else
750  {
751  ROS_ERROR(
752  "TtlManager::readHomingAbsPosition - null pointer or no hardware type in map %d or empty vector of ids: %d",
753  static_cast<int>(_ids_map.count(hw_type)), static_cast<int>(_ids_map.at(hw_type).empty()));
754  return false;
755  }
756 
757  return true;
758 }
759 
765 {
766  uint8_t hw_errors_increment = 0;
767 
768  // syncread position for all motors.
769  // for ned and one -> we need at least one xl430 and one xl320 drivers as they are different
770 
771  for (auto const &[hw_type, driver] : _motor_driver_map)
772  {
773  if (!driver)
774  {
775  continue;
776  }
777  auto id_list_it = _ids_map.find(hw_type);
778  if (id_list_it == _ids_map.end())
779  {
780  continue;
781  }
782  const auto &ids_list = id_list_it->second;
783 
784  if (ids_list.empty())
785  {
786  continue;
787  }
788 
789  // we retrieve all the associated id for the type of the current driver
790  _position_list.clear();
791 
792  // retrieve joint status
793  int res = driver->syncReadPosition(ids_list, _position_list);
794  if (COMM_SUCCESS == res)
795  {
796  if (ids_list.size() == _position_list.size())
797  {
798  // set motors states accordingly
799  for (size_t i = 0; i < ids_list.size(); ++i)
800  {
801  uint8_t id = ids_list[i];
802 
803  auto motor_it = _motor_state_map.find(id);
804  if (motor_it != _motor_state_map.end())
805  {
806  auto state = motor_it->second;
807  if (state)
808  {
809  state->setPosition(static_cast<int>(_position_list[i]));
810  }
811  }
812  }
813  }
814  else
815  {
816  // warn to avoid sound and light error on high level (error on ROS_ERROR)
817  ROS_WARN(
818  "TtlManager::readJointStatus : Fail to sync read joint state - "
819  "vector mismatch (id_list size %d, position_list size %d)",
820  static_cast<int>(ids_list.size()), static_cast<int>(_position_list.size()));
821  hw_errors_increment++;
822  }
823  }
824  else
825  {
826  // debug to avoid sound and light error on high level (error on ROS_ERROR)
827  // also for Ned which has much more errors on XL320 motor
828  ROS_DEBUG(
829  "TtlManager::readJointStatus : Fail to sync read joint state - "
830  "driver fail to syncReadPosition");
831  hw_errors_increment++;
832  }
833  } // for driver_map
834 
835  // check collision by END_EFFECTOR
836  if (_isRealCollision)
837  {
839  }
840  else
841  {
842  _collision_status = false;
843  // check collision by END_EFFECTOR
844  if (_isRealCollision)
845  {
846  checkCollision();
847  }
848  else
849  {
850  _collision_status = false;
851  }
852  }
853 
854  ROS_DEBUG_THROTTLE(2, "_hw_fail_counter_read, hw_errors_increment: %d, %d", _hw_fail_counter_read,
855  hw_errors_increment);
856 
857  // we reset the global error variable only if no errors
858  if (0 == hw_errors_increment)
859  {
861  }
862  else
863  {
864  _hw_fail_counter_read += hw_errors_increment;
865  }
866 
867  return (0 == hw_errors_increment);
868 }
869 
875 {
876  bool res = false;
877 
878  // hardware_version is not available within this class to know whether there is a ned2/ned3pro eef
879  // however if hardware_type == ned2 _driver_map will contain EHardwareType::END_EFFECTOR
880  // and if hardware_type == ned3pro _driver_map will contain EHardwareType::NED3PRO_END_EFFECTOR
881  EHardwareType ee_type;
882 
883  if (_simulation_mode)
884  ee_type = EHardwareType::FAKE_END_EFFECTOR;
885  else if (_end_effector_driver_map.count(EHardwareType::END_EFFECTOR))
886  ee_type = EHardwareType::END_EFFECTOR;
887  else if (_end_effector_driver_map.count(EHardwareType::NED3PRO_END_EFFECTOR))
888  ee_type = EHardwareType::NED3PRO_END_EFFECTOR;
889 
890  if (_end_effector_driver_map.count(ee_type))
891  {
892  unsigned int hw_errors_increment = 0;
893 
894  auto driver = _end_effector_driver_map.at(ee_type);
895  if (driver)
896  {
897  if (_ids_map.count(ee_type) && !_ids_map.at(ee_type).empty())
898  {
899  uint8_t id = _ids_map.at(ee_type).front();
900 
901  if (_end_effector_state_map.count(id))
902  {
903  // we retrieve the associated id for the end effector
904  auto state = _end_effector_state_map[id];
905 
906  if (state)
907  {
908  vector<common::model::EActionType> action_list;
909 
910  // ********** buttons
911  // get action of free driver button, save pos button, custom button
912  if (COMM_SUCCESS == driver->syncReadButtonsStatus(id, action_list))
913  {
914  for (uint8_t i = 0; i < action_list.size(); i++)
915  {
916  state->setButtonStatus(i, action_list.at(i));
917  // In case free driver button, it we hold this button, normally, because of the small threshold of
918  // collision detection this action make EE confuse that it is a collision. That's why when we hold
919  // buttons, we need to deactivate the detection of collision.
920  if (action_list.at(i) != common::model::EActionType::NO_ACTION)
921  {
922  _isRealCollision = false;
923  }
924  else if (!_isRealCollision)
925  {
926  // when previous action is not no_action => need to wait a short period to make sure no collision
927  // detected Note, we need to read one time the status of collision just after releasing button to
928  // reset the status.
929  _isRealCollision = true;
930  _isWrongAction = true;
931  _last_collision_detection_activating = ros::SteadyTime::now().toSec();
932  }
933  }
934  }
935  else
936  {
937  hw_errors_increment++;
938  }
939 
940  // ********** digital data
941  bool digital_data{};
942  if (COMM_SUCCESS == driver->readDigitalInput(id, digital_data))
943  {
944  state->setDigitalIn(digital_data);
945  }
946  else
947  {
948  hw_errors_increment++;
949  }
950  } // if (state)
951  }
952  } // if (_ids_map.count(EHardwareType::END_EFFECTOR))
953  } // if (driver)
954 
955  // we reset the global error variable only if no errors
956  if (0 == hw_errors_increment)
957  {
959  _debug_error_message.clear();
960 
961  res = true;
962  }
963  else
964  {
965  ROS_DEBUG_COND(_end_effector_fail_counter_read > 10, "TtlManager::readEndEffectorStatus: nb error > 10 : %d",
967  _end_effector_fail_counter_read += hw_errors_increment;
968  }
969 
971  {
972  ROS_ERROR(
973  "TtlManager::readEndEffectorStatus - motor connection problem - Failed to read from bus "
974  "(hw_fail_counter_read : %d)",
977  _debug_error_message = "TtlManager - Connection problem with physical Bus.";
978  }
979  }
980 
981  return res;
982 }
983 
990 {
991  bool res = false;
992 
993  // hardware_version is not available within this class to know whether there is a ned2/ned3pro eef
994  // however if hardware_type == ned2 _driver_map will contain EHardwareType::END_EFFECTOR
995  // and if hardware_type == ned3pro _driver_map will contain EHardwareType::NED3PRO_END_EFFECTOR
996  EHardwareType ee_type;
997 
998  if (_simulation_mode)
999  ee_type = EHardwareType::FAKE_END_EFFECTOR;
1000  else if (_end_effector_driver_map.count(EHardwareType::END_EFFECTOR))
1001  ee_type = EHardwareType::END_EFFECTOR;
1002  else if (_end_effector_driver_map.count(EHardwareType::NED3PRO_END_EFFECTOR))
1003  ee_type = EHardwareType::NED3PRO_END_EFFECTOR;
1004 
1005  if (_end_effector_driver_map.count(ee_type))
1006  {
1007  unsigned int hw_errors_increment = 0;
1008 
1009  auto driver = _end_effector_driver_map.at(ee_type);
1010  if (driver)
1011  {
1012  if (_ids_map.count(ee_type) && !_ids_map.at(ee_type).empty())
1013  {
1014  uint8_t id = _ids_map.at(ee_type).front();
1015 
1016  // ********** collision
1017  // not accept other status of collistion in 1 second if it detected a collision
1019  {
1020  bool last_statut = _collision_status;
1021  if (COMM_SUCCESS == driver->readCollisionStatus(id, _collision_status))
1022  {
1023  if (last_statut == _collision_status && _collision_status)
1024  {
1025  // if we have a collision, we will publish the statut collision only once
1026  // This avoid that the delay in reading statut influent to next movement.
1027  _collision_status = false;
1028  }
1029  else if (_collision_status)
1030  {
1031  if (_isWrongAction)
1032  {
1033  // if an action did a wrong detection of collision, we need to read once to reset the status
1034  _isWrongAction = false;
1035  _collision_status = false;
1036  }
1037  else
1038  _last_collision_detection_activating = ros::SteadyTime::now().toSec();
1039  }
1040  }
1041  else
1042  {
1043  hw_errors_increment++;
1044  }
1045  }
1046  else if (ros::SteadyTime::now().toSec() - _last_collision_detection_activating >= 1.0)
1047  {
1049  }
1050  } // if (_ids_map.count(EHardwareType::END_EFFECTOR))
1051  } // if (driver)
1052 
1053  // we reset the global error variable only if no errors
1054  if (0 == hw_errors_increment)
1055  {
1057  res = true;
1058  }
1059  else
1060  {
1061  ROS_DEBUG_COND(_end_effector_fail_counter_read > 10, "TtlManager::checkCollision: nb error > 10 : %d",
1063  _end_effector_fail_counter_read += hw_errors_increment;
1064  }
1065  }
1066  return res;
1067 }
1068 
1074 {
1075  bool res = false;
1076 
1077  // hardware_version is not available within this class to know whether there is a ned2/ned3pro eef
1078  // however if hardware_type == ned2 _driver_map will contain EHardwareType::END_EFFECTOR
1079  // and if hardware_type == ned3pro _driver_map will contain EHardwareType::NED3PRO_END_EFFECTOR
1080  EHardwareType ee_type;
1081 
1082  if (_simulation_mode)
1083  ee_type = EHardwareType::FAKE_END_EFFECTOR;
1084  else if (_end_effector_driver_map.count(EHardwareType::END_EFFECTOR))
1085  ee_type = EHardwareType::END_EFFECTOR;
1086  else if (_end_effector_driver_map.count(EHardwareType::NED3PRO_END_EFFECTOR))
1087  ee_type = EHardwareType::NED3PRO_END_EFFECTOR;
1088 
1089  if (auto it = _end_effector_driver_map.find(ee_type); it != _end_effector_driver_map.end())
1090  {
1091  auto driver = it->second;
1092 
1093  if (driver)
1094  {
1095  if (_ids_map.count(ee_type) && !_ids_map.at(ee_type).empty())
1096  {
1097  uint8_t id = _ids_map.at(ee_type).front();
1098 
1099  // ********** collision
1100  // don't accept other status of collistion in 1 second if it detected a collision
1102  {
1103  if (COMM_SUCCESS == driver->readCollisionStatus(id, _collision_status))
1104  {
1105  res = true;
1106 
1107  if (_collision_status)
1108  {
1109  if (_isWrongAction)
1110  {
1111  // if an action did a wrong detection of collision, we need to read once to reset the status
1112  _isWrongAction = false;
1113  _collision_status = false;
1114  }
1115  else
1116  {
1117  _last_collision_detection_activating = ros::SteadyTime::now().toSec();
1118  }
1119  }
1120  }
1121  else
1122  {
1124  }
1125  }
1126  else if (ros::SteadyTime::now().toSec() - _last_collision_detection_activating >= 1.0)
1127  {
1129  }
1130  }
1131  }
1132  }
1133 
1134  return res;
1135 }
1136 
1141 {
1142  bool res = false;
1143 
1144  unsigned int hw_errors_increment = 0;
1145 
1146  // take all hw status dedicated drivers
1147  for (auto const &it : _driver_map)
1148  {
1149  auto type = it.first;
1150  auto driver = it.second;
1151 
1152  if (driver && _ids_map.count(type) && !_ids_map.at(type).empty())
1153  {
1154  // we retrieve all the associated id for the type of the current driver
1155  vector<uint8_t> ids_list = _ids_map.at(type);
1156 
1157  // 1. syncread for all motors
1158  // ********** voltage and Temperature
1159  vector<std::pair<double, uint8_t>> hw_data_list;
1160 
1161  if (COMM_SUCCESS != driver->syncReadHwStatus(ids_list, hw_data_list))
1162  {
1163  // this operation can fail, it is normal, so no error message
1164  hw_errors_increment++;
1165  }
1166  else if (ids_list.size() != hw_data_list.size())
1167  {
1168  // however, if we have a mismatch here, it is not normal
1169  ROS_ERROR(
1170  "TtlManager::readHardwareStatusOptimized : syncReadHwStatus failed - "
1171  "vector mistmatch (id_list size %d, hw_data_list size %d)",
1172  static_cast<int>(ids_list.size()), static_cast<int>(hw_data_list.size()));
1173 
1174  hw_errors_increment++;
1175  }
1176 
1177  // ********** error state
1178  vector<uint8_t> hw_error_status_list;
1179 
1180  if (COMM_SUCCESS != driver->syncReadHwErrorStatus(ids_list, hw_error_status_list))
1181  {
1182  hw_errors_increment++;
1183  }
1184  else if (ids_list.size() != hw_error_status_list.size())
1185  {
1186  ROS_ERROR(
1187  "TtlManager::readHardwareStatus : syncReadTemperature failed - "
1188  "vector mistmatch (id_list size %d, hw_status_list size %d)",
1189  static_cast<int>(ids_list.size()), static_cast<int>(hw_error_status_list.size()));
1190 
1191  hw_errors_increment++;
1192  }
1193 
1194  // 2. set motors states accordingly
1195  for (size_t i = 0; i < ids_list.size(); ++i)
1196  {
1197  uint8_t id = ids_list.at(i);
1198 
1199  if (_state_map.count(id) && _state_map.at(id))
1200  {
1201  auto state = _state_map.at(id);
1202 
1203  // ************** temperature and voltage
1204  if (hw_data_list.size() > i)
1205  {
1206  double voltage = (hw_data_list.at(i)).first;
1207  uint8_t temperature = (hw_data_list.at(i)).second;
1208 
1209  state->setTemperature(temperature);
1210  state->setRawVoltage(voltage);
1211  }
1212 
1213  // ********** error state
1214  if (hw_error_status_list.size() > i)
1215  {
1216  state->setHardwareError(hw_error_status_list.at(i));
1217  }
1218 
1219  // interpret any error code into message (even if not retrieved now)
1220  string hardware_message = driver->interpretErrorState(state->getHardwareError());
1221  state->setHardwareError(hardware_message);
1222  }
1223  } // for ids_list
1224  } // if driver
1225  } // for (auto it : _hw_status_driver_map)
1226 
1227  // ********** steppers related informations (conveyor and calibration)
1228  hw_errors_increment += readSteppersStatus();
1229 
1230  // we reset the global error variable only if no errors
1231  if (0 == hw_errors_increment)
1232  {
1234  _debug_error_message.clear();
1235 
1236  res = true;
1237  }
1238  else
1239  {
1240  _hw_fail_counter_read += hw_errors_increment;
1241  }
1242 
1243  // if too much errors, disconnect
1245  {
1246  ROS_ERROR_THROTTLE(1,
1247  "TtlManager::readHardwareStatus - motor connection problem - "
1248  "Failed to read from bus (hw_fail_counter_read : %d)",
1251  res = false;
1252  _is_connection_ok = false;
1253  _debug_error_message = "TtlManager - Connection problem with physical Bus.";
1254  }
1255 
1256  return res;
1257 }
1258 
1264 {
1265  uint8_t hw_errors_increment = 0;
1266 
1267  // take all hw status dedicated drivers
1268  auto [stepper_joint_driver, hw_type] = getJointsStepperDriver();
1269  if (stepper_joint_driver)
1270  {
1271  if (hw_type == EHardwareType::STEPPER || hw_type == EHardwareType::FAKE_STEPPER_MOTOR)
1272  {
1273  // 1. read calibration status if needed
1274 
1275  // we want to check calibration (done at startup and when calibration is started)
1277  {
1278  // When calibration is running, sometimes at an unexpected position, calibration make EE thinks that there is a
1279  // collision Have to disable the feature collision detection in this period
1280  _isRealCollision = false;
1281 
1282  vector<uint8_t> id_list = _ids_map.at(hw_type);
1283  vector<uint8_t> stepper_id_list;
1284  std::copy_if(id_list.begin(), id_list.end(), std::back_inserter(stepper_id_list), [this](uint8_t id) {
1285  return _state_map[id] && _state_map.at(id)->getComponentType() != common::model::EComponentType::CONVEYOR;
1286  });
1287 
1288  /* Truth Table
1289  * still_in_progress | state | new state
1290  * 0 | IDLE = IDLE
1291  * 0 | START = START
1292  * 0 | PROG > UPDAT
1293  * 0 | UPDAT R IDLE
1294  * 1 | IDLE = IDLE
1295  * 1 | START > PROG
1296  * 1 | PROG = PROG
1297  * 1 | UPDAT = UPDAT
1298  */
1299 
1300  // *********** calibration status, only if initialized
1301  std::vector<uint8_t> homing_status_list;
1302  if (COMM_SUCCESS == stepper_joint_driver->syncReadHomingStatus(stepper_id_list, homing_status_list))
1303  {
1304  if (stepper_id_list.size() == homing_status_list.size())
1305  {
1306  // max status need to be kept not converted into EStepperCalibrationStatus because max status is "in
1307  // progress" in the enum
1308  int max_status = -1;
1309 
1310  // debug only
1311  std::ostringstream ss_debug;
1312  ss_debug << "homing status : ";
1313 
1314  bool still_in_progress = false;
1315 
1316  // set states accordingly
1317  for (size_t i = 0; i < homing_status_list.size(); ++i)
1318  {
1319  uint8_t id = stepper_id_list.at(i);
1320  ss_debug << static_cast<int>(homing_status_list.at(i)) << ", ";
1321 
1322  if (_state_map.count(id))
1323  {
1324  EStepperCalibrationStatus status = stepper_joint_driver->interpretHomingData(homing_status_list.at(i));
1325 
1326  // set status in state
1327  auto stepperState = std::dynamic_pointer_cast<StepperMotorState>(_state_map.at(id));
1328  if (stepperState && !stepperState->isConveyor())
1329  {
1330  stepperState->setCalibration(status, 1);
1331 
1332  // get max status of all motors (to retrieve potential errors)
1333  // carefull to those possible cases :
1334  // 1, 1, 1
1335  // 1, 2, 1
1336  // 0, 2, 2
1337  // 2, 0, 2
1338 
1339  // if 0, uninitialized, else, take max
1340  // we need to keep the status unconverted to have the correct order
1341  if (0 != max_status && homing_status_list.at(i) > max_status)
1342  max_status = homing_status_list.at(i);
1343 
1344  // if one status is in progress or uinitialized, we are really in progress
1345  if ((0 == homing_status_list.at(i)) || EStepperCalibrationStatus::IN_PROGRESS == status)
1346  {
1347  still_in_progress = true;
1348  }
1349  }
1350  }
1351  } // for homing_status_list
1352 
1353  ss_debug << " => max_status: " << static_cast<int>(max_status);
1354 
1355  ROS_DEBUG_THROTTLE(2.0, "TtlManager::readCalibrationStatus : %s", ss_debug.str().c_str());
1356 
1357  // see truth table above
1358  // timeout is here to prevent being stuck here if retrying calibration when already at the butee (then the
1359  // system has no time to switch to "in progress" before "ok" or "error"
1360  if ((!still_in_progress && CalibrationMachineState::State::IN_PROGRESS == _calib_machine_state.status()) ||
1362  (!still_in_progress && _calib_machine_state.isTimeout()))
1363  {
1365  }
1366 
1367  // see truth table above
1369  {
1370  _calibration_status = stepper_joint_driver->interpretHomingData(static_cast<uint8_t>(max_status));
1372 
1373  // In this CalibrationMachineState, the calibration is considered as finished => can activate collision
1374  // detection here we need to wait a short period to make sure no collision detected calibration make a
1375  // wrong collision, so we have to read the collision status once time to reset it.
1376  _isWrongAction = true;
1377  _isRealCollision = true;
1378  _last_collision_detection_activating = ros::SteadyTime::now().toSec();
1379  }
1380  }
1381  else
1382  {
1383  ROS_ERROR(
1384  "TtlManager::readCalibrationStatus : syncReadHomingStatus failed - "
1385  "vector mistmatch (id_list size %d, homing_status_list size %d)",
1386  static_cast<int>(stepper_id_list.size()), static_cast<int>(homing_status_list.size()));
1387 
1388  hw_errors_increment++;
1389  }
1390  }
1391  else
1392  {
1393  hw_errors_increment++;
1394  }
1395  } // if (_driver_map.count(hw_type) && _driver_map.at(hw_type))
1396  }
1397  else if (hw_type == EHardwareType::NED3PRO_STEPPER)
1398  {
1399  hw_errors_increment = readNed3ProSteppersStatus();
1400  }
1401 
1402  // 2. read conveyors states if has
1403  for (auto &conveyor_state : getConveyorsStates())
1404  {
1405  auto conveyor_id = conveyor_state->getId();
1406  auto conveyor_hw_type = conveyor_state->getHardwareType();
1407  auto conveyor_driver =
1408  std::dynamic_pointer_cast<ttl_driver::AbstractStepperDriver>(_driver_map[conveyor_hw_type]);
1409  int32_t conveyor_speed_percent = 0;
1410  int32_t direction = 0;
1411  if (COMM_SUCCESS == conveyor_driver->readConveyorVelocity(conveyor_id, conveyor_speed_percent, direction))
1412  {
1413  conveyor_state->setGoalDirection(direction);
1414  conveyor_state->setSpeed(conveyor_speed_percent);
1415  conveyor_state->setState(conveyor_speed_percent);
1416  }
1417  else
1418  {
1419  hw_errors_increment++;
1420  }
1421  }
1422  }
1423 
1424  ROS_DEBUG_THROTTLE(2.0, "TtlManager::readCalibrationStatus: _calibration_status: %s",
1425  common::model::StepperCalibrationStatusEnum(_calibration_status).toString().c_str());
1426  ROS_DEBUG_THROTTLE(2.0, "TtlManager::readCalibrationStatus: _calib_machine_state: %d",
1427  static_cast<int>(_calib_machine_state.status()));
1428 
1429  return hw_errors_increment;
1430 }
1431 
1433 {
1434  uint8_t hw_errors_increment = 0;
1435 
1436  EHardwareType hw_type = EHardwareType::NED3PRO_STEPPER;
1437 
1438  // 1. read calibration status if needed
1439 
1440  // we want to check calibration (done at startup and when calibration is started)
1442  {
1443  // When calibration is running, sometimes at an unexpected position, calibration make EE thinks that
1444  // there is a collision Have to disable the feature collision detection in this period
1445  _isRealCollision = false;
1446 
1447  vector<uint8_t> id_list = _ids_map.at(hw_type);
1448  vector<uint8_t> stepper_id_list;
1449  std::copy_if(id_list.begin(), id_list.end(), std::back_inserter(stepper_id_list), [this](uint8_t id) {
1450  return _state_map[id] && _state_map.at(id)->getComponentType() != common::model::EComponentType::CONVEYOR;
1451  });
1452 
1453  // *********** calibration status, only if initialized
1454  auto [stepper_joint_driver, hw_type] = getJointsStepperDriver();
1455  std::vector<uint8_t> homing_status_list;
1456  if (stepper_joint_driver &&
1457  COMM_SUCCESS == stepper_joint_driver->syncReadHomingStatus(stepper_id_list, homing_status_list))
1458  {
1459  if (stepper_id_list.size() == homing_status_list.size())
1460  {
1461  // TODO(i.ambit) publish calibration message
1462  ttl_driver::CalibrationStatus calibration_status_msg;
1463 
1464  EStepperCalibrationStatus highest_priority_status = EStepperCalibrationStatus::UNINITIALIZED;
1465  // set states accordingly
1466  for (size_t i = 0; i < homing_status_list.size(); ++i)
1467  {
1468  uint8_t id = stepper_id_list.at(i);
1469 
1470  if (_state_map.count(id))
1471  {
1472  // set status in state
1473  auto stepperState = std::dynamic_pointer_cast<StepperMotorState>(_state_map.at(id));
1474  if (stepperState && !stepperState->isConveyor())
1475  {
1476  auto status = stepper_joint_driver->interpretHomingData(homing_status_list.at(i));
1477  stepperState->setCalibration(status, 1);
1478 
1479  if (status > highest_priority_status)
1480  highest_priority_status = status;
1481 
1482  calibration_status_msg.ids.push_back(id);
1483 
1484  switch (status)
1485  {
1486  case EStepperCalibrationStatus::IN_PROGRESS:
1487  calibration_status_msg.status.push_back(ttl_driver::CalibrationStatus::CALIBRATING);
1488  break;
1489  case EStepperCalibrationStatus::OK:
1490  calibration_status_msg.status.push_back(ttl_driver::CalibrationStatus::CALIBRATED);
1491  break;
1492  case EStepperCalibrationStatus::FAIL:
1493  calibration_status_msg.status.push_back(ttl_driver::CalibrationStatus::CALIBRATION_ERROR);
1494  break;
1495  default:
1496  calibration_status_msg.status.push_back(ttl_driver::CalibrationStatus::CALIBRATION_ERROR);
1497  break;
1498  }
1499 
1500  _calibration_status_publisher.publish(calibration_status_msg);
1501  }
1502  }
1503  } // for homing_status_list
1504  _calibration_status = highest_priority_status;
1505  }
1506  else
1507  {
1508  ROS_ERROR(
1509  "TtlManager::readCalibrationStatus : syncReadHomingStatus failed - "
1510  "vector mistmatch (id_list size %d, homing_status_list size %d)",
1511  static_cast<int>(stepper_id_list.size()), static_cast<int>(homing_status_list.size()));
1512 
1513  hw_errors_increment++;
1514  }
1515  }
1516  else
1517  {
1518  hw_errors_increment++;
1519  }
1520  } // if (_driver_map.count(hw_type) && _driver_map.at(hw_type))
1521 
1522  return hw_errors_increment;
1523 }
1524 
1532 int TtlManager::getAllIdsOnBus(vector<uint8_t> &id_list)
1533 {
1534  int result = COMM_RX_FAIL;
1535 
1536  // 1. Get all ids from ttl bus. We can use any driver for that
1537  if (_default_ttl_driver)
1538  {
1539  vector<uint8_t> l_idList;
1540  result = _default_ttl_driver->scan(l_idList);
1541  id_list.insert(id_list.end(), l_idList.begin(), l_idList.end());
1542 
1543  string ids_str;
1544  for (auto const &id : l_idList)
1545  ids_str += to_string(id) + " ";
1546 
1547  ROS_DEBUG_THROTTLE(1, "TtlManager::getAllIdsOnTtlBus - Found ids (%s) on bus using default driver",
1548  ids_str.c_str());
1549 
1550  if (COMM_SUCCESS != result)
1551  {
1552  if (COMM_RX_TIMEOUT != result)
1553  { // -3001
1555  "TtlManager - No motor found. "
1556  "Make sure that motors are correctly connected and powered on.";
1557  }
1558  else
1559  { // -3002 or other
1560  _debug_error_message = "TtlManager - Failed to scan bus.";
1561  }
1562  ROS_WARN_THROTTLE(1,
1563  "TtlManager::getAllIdsOnTtlBus - Broadcast ping failed, "
1564  "result : %d (-3001: timeout, -3002: corrupted packet)",
1565  result);
1566  }
1567  }
1568  else
1569  {
1570  // if no driver, no motors on bus, it is not a failure of scan
1571  result = COMM_SUCCESS;
1572  }
1573 
1574  return result;
1575 }
1576 
1577 // ******************
1578 // Write operations
1579 // ******************
1580 
1587 {
1588  _led_state = led;
1589  int ret = niryo_robot_msgs::CommandStatus::TTL_WRITE_ERROR;
1590 
1591  EHardwareType mType = HardwareTypeEnum(_led_motor_type_cfg.c_str());
1592 
1593  if (mType == EHardwareType::FAKE_DXL_MOTOR)
1594  return niryo_robot_msgs::CommandStatus::SUCCESS;
1595 
1596  // get list of motors of the given type
1597  vector<uint8_t> id_list;
1598  if (_ids_map.count(mType) && _driver_map.count(mType))
1599  {
1600  id_list = _ids_map.at(mType);
1601 
1602  auto driver = std::dynamic_pointer_cast<AbstractDxlDriver>(_driver_map.at(mType));
1603  if (driver)
1604  {
1605  // sync write led state
1606  vector<uint8_t> command_led_value(id_list.size(), static_cast<uint8_t>(led));
1607  if (0 <= led && 7 >= led)
1608  {
1609  int result = COMM_TX_FAIL;
1610  for (int error_counter = 0; result != COMM_SUCCESS && error_counter < 5; ++error_counter)
1611  {
1612  ros::Duration(TIME_TO_WAIT_IF_BUSY).sleep();
1613  result = driver->syncWriteLed(id_list, command_led_value);
1614  }
1615 
1616  if (COMM_SUCCESS == result)
1617  ret = niryo_robot_msgs::CommandStatus::SUCCESS;
1618  else
1619  ROS_WARN("TtlManager::setLeds - Failed to write LED");
1620  }
1621  }
1622  else
1623  {
1624  ROS_DEBUG("Set leds failed. Driver is not compatible, check the driver's implementation ");
1625  return niryo_robot_msgs::CommandStatus::FAILURE;
1626  }
1627  }
1628  else
1629  {
1630  ROS_DEBUG("Set leds failed. It is maybe that this service is not support for this product");
1631  ret = niryo_robot_msgs::CommandStatus::SUCCESS;
1632  }
1633 
1634  return ret;
1635 }
1636 
1645 int TtlManager::sendCustomCommand(uint8_t id, int reg_address, int value, int byte_number)
1646 {
1647  int result = COMM_TX_FAIL;
1648  ROS_DEBUG(
1649  "TtlManager::sendCustomCommand:\n"
1650  "\t\t ID: %d, Value: %d, Address: %d, Size: %d",
1651  static_cast<int>(id), value, reg_address, byte_number);
1652 
1653  if (_state_map.count(id) != 0 && _state_map.at(id))
1654  {
1655  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1656 
1657  if (motor_type == EHardwareType::STEPPER || motor_type == EHardwareType::FAKE_STEPPER_MOTOR)
1658  {
1659  return niryo_robot_msgs::CommandStatus::SUCCESS;
1660  }
1661 
1662  if (_driver_map.count(motor_type) && _driver_map.at(motor_type))
1663  {
1664  int32_t value_conv = value;
1665  result = _driver_map.at(motor_type)
1666  ->writeCustom(static_cast<uint16_t>(reg_address), static_cast<uint8_t>(byte_number), id,
1667  static_cast<uint32_t>(value_conv));
1668  if (result != COMM_SUCCESS)
1669  {
1670  ROS_WARN("TtlManager::sendCustomCommand - Failed to write custom command: %d", result);
1671  // TODO(Thuc): change TTL_WRITE_ERROR -> WRITE_ERROR
1672  result = niryo_robot_msgs::CommandStatus::TTL_WRITE_ERROR;
1673  }
1674  }
1675  else
1676  {
1677  ROS_ERROR_THROTTLE(1, "TtlManager::sendCustomCommand - driver for motor %s not available",
1678  HardwareTypeEnum(motor_type).toString().c_str());
1679  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1680  }
1681  }
1682  else
1683  {
1684  ROS_ERROR_THROTTLE(1, "TtlManager::sendCustomCommand - driver for motor id %d unknown", static_cast<int>(id));
1685  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1686  }
1687 
1688  ros::Duration(0.005).sleep();
1689  return result;
1690 }
1691 
1700 int TtlManager::readCustomCommand(uint8_t id, int32_t reg_address, int &value, int byte_number)
1701 {
1702  int result = COMM_RX_FAIL;
1703  ROS_DEBUG("TtlManager::readCustomCommand: ID: %d, Address: %d, Size: %d", static_cast<int>(id),
1704  static_cast<int>(reg_address), byte_number);
1705 
1706  if (_state_map.count(id) != 0 && _state_map.at(id))
1707  {
1708  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1709 
1710  if (_driver_map.count(motor_type) && _driver_map.at(motor_type))
1711  {
1712  uint32_t data = 0;
1713  result = _driver_map.at(motor_type)
1714  ->readCustom(static_cast<uint16_t>(reg_address), static_cast<uint8_t>(byte_number), id, data);
1715  auto data_conv = static_cast<int32_t>(data);
1716  value = data_conv;
1717 
1718  if (result != COMM_SUCCESS)
1719  {
1720  ROS_WARN("TtlManager::readCustomCommand - Failed to read custom command: %d", result);
1721  result = niryo_robot_msgs::CommandStatus::TTL_READ_ERROR;
1722  }
1723  }
1724  else
1725  {
1726  ROS_ERROR_THROTTLE(1, "TtlManager::readCustomCommand - driver for motor %s not available",
1727  HardwareTypeEnum(motor_type).toString().c_str());
1728  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1729  }
1730  }
1731  else
1732  {
1733  ROS_ERROR_THROTTLE(1, "TtlManager::readCustomCommand - driver for motor id %d unknown", static_cast<int>(id));
1734  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1735  }
1736 
1737  ros::Duration(0.005).sleep();
1738  return result;
1739 }
1740 
1753 int TtlManager::readMotorPID(uint8_t id, uint16_t &pos_p_gain, uint16_t &pos_i_gain, uint16_t &pos_d_gain,
1754  uint16_t &vel_p_gain, uint16_t &vel_i_gain, uint16_t &ff1_gain, uint16_t &ff2_gain)
1755 {
1756  int result = COMM_RX_FAIL;
1757 
1758  if (_state_map.count(id) != 0 && _state_map.at(id))
1759  {
1760  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1761 
1762  if (_driver_map.count(motor_type))
1763  {
1764  auto driver = std::dynamic_pointer_cast<AbstractDxlDriver>(_driver_map.at(motor_type));
1765  if (driver)
1766  {
1767  std::vector<uint16_t> data;
1768  result = driver->readPID(id, data);
1769 
1770  if (COMM_SUCCESS == result)
1771  {
1772  pos_p_gain = data.at(0);
1773  pos_i_gain = data.at(1);
1774  pos_d_gain = data.at(2);
1775  vel_p_gain = data.at(3);
1776  vel_i_gain = data.at(4);
1777  ff1_gain = data.at(5);
1778  ff2_gain = data.at(6);
1779  }
1780  else
1781  {
1782  ROS_WARN("TtlManager::readMotorPID - Failed to read PID: %d", result);
1783  result = niryo_robot_msgs::CommandStatus::TTL_READ_ERROR;
1784  return result;
1785  }
1786  }
1787  }
1788  else
1789  {
1790  ROS_ERROR_THROTTLE(1, "TtlManager::readMotorPID - driver for motor %s not available",
1791  HardwareTypeEnum(motor_type).toString().c_str());
1792  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1793  }
1794  }
1795  else
1796  {
1797  ROS_ERROR_THROTTLE(1, "TtlManager::readMotorPID - driver for motor id %d unknown", static_cast<int>(id));
1798  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1799  }
1800 
1801  ros::Duration(0.005).sleep();
1802  return result;
1803 }
1804 
1818 int TtlManager::readVelocityProfile(uint8_t id, uint32_t &v_start, uint32_t &a_1, uint32_t &v_1, uint32_t &a_max,
1819  uint32_t &v_max, uint32_t &d_max, uint32_t &d_1, uint32_t &v_stop)
1820 {
1821  int result = COMM_RX_FAIL;
1822 
1823  if (_state_map.count(id) != 0 && _state_map.at(id))
1824  {
1825  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1826  auto [joint_stepper_driver, hw_type] = getJointsStepperDriver();
1827  if (joint_stepper_driver)
1828  {
1829  std::vector<uint32_t> data;
1830  result = joint_stepper_driver->readVelocityProfile(id, data);
1831 
1832  if (COMM_SUCCESS == result)
1833  {
1834  v_start = data.at(0);
1835  a_1 = data.at(1);
1836  v_1 = data.at(2);
1837  a_max = data.at(3);
1838  v_max = data.at(4);
1839  d_max = data.at(5);
1840  d_1 = data.at(6);
1841  v_stop = data.at(7);
1842  }
1843  else
1844  {
1845  ROS_WARN("TtlManager::readVelocityProfile - Failed to read velocity profile: %d", result);
1846  result = niryo_robot_msgs::CommandStatus::TTL_READ_ERROR;
1847  return result;
1848  }
1849  }
1850  else
1851  {
1852  ROS_ERROR_THROTTLE(1, "TtlManager::readVelocityProfile - driver for motor %s not available",
1853  HardwareTypeEnum(motor_type).toString().c_str());
1854  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1855  }
1856  }
1857  else
1858  {
1859  ROS_ERROR_THROTTLE(1, "TtlManager::readVelocityProfile - driver for motor id %d unknown", static_cast<int>(id));
1860  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1861  }
1862 
1863  ros::Duration(0.005).sleep();
1864  return result;
1865 }
1866 
1873 int TtlManager::readMoving(uint8_t id, uint8_t &status)
1874 {
1875  int result = COMM_RX_FAIL;
1876 
1877  if (_state_map.count(id) != 0 && _state_map.at(id))
1878  {
1879  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1880 
1881  // Only used for xl330 and xl320 for now
1882  if (_driver_map.count(motor_type) && (motor_type == EHardwareType::XL330 || motor_type == EHardwareType::XL320 ||
1883  motor_type == EHardwareType::FAKE_DXL_MOTOR))
1884  {
1885  auto driver = std::dynamic_pointer_cast<AbstractDxlDriver>(_driver_map.at(motor_type));
1886  if (driver)
1887  {
1888  result = driver->readMoving(id, status);
1889  }
1890  }
1891  else
1892  {
1893  ROS_ERROR_THROTTLE(1, "TtlManager::readMoving - register MOVING for motor %s not available",
1894  HardwareTypeEnum(motor_type).toString().c_str());
1895  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1896  }
1897  }
1898  else
1899  {
1900  ROS_ERROR_THROTTLE(1, "TtlManager::readMoving - driver for motor id %d unknown", static_cast<int>(id));
1901  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1902  }
1903 
1904  ros::Duration(0.005).sleep();
1905  return result;
1906 }
1907 
1914 int TtlManager::readControlMode(uint8_t id, uint8_t &control_mode)
1915 {
1916  int result = COMM_RX_FAIL;
1917 
1918  if (_state_map.count(id) != 0 && _state_map.at(id))
1919  {
1920  EHardwareType motor_type = _state_map.at(id)->getHardwareType();
1921 
1922  if (_driver_map.count(motor_type))
1923  {
1924  auto driver = std::dynamic_pointer_cast<AbstractDxlDriver>(_driver_map.at(motor_type));
1925  if (driver)
1926  {
1927  result = driver->readControlMode(id, control_mode);
1928  }
1929  }
1930  else
1931  {
1932  ROS_ERROR_THROTTLE(1, "TtlManager::readControlMode - driver for motor %s not available",
1933  HardwareTypeEnum(motor_type).toString().c_str());
1934  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1935  }
1936  }
1937  else
1938  {
1939  ROS_ERROR_THROTTLE(1, "TtlManager::readControlMode - driver for motor id %d unknown", static_cast<int>(id));
1940  result = niryo_robot_msgs::CommandStatus::WRONG_MOTOR_TYPE;
1941  }
1942 
1943  ros::Duration(0.005).sleep();
1944  return result;
1945 }
1946 
1952 int TtlManager::writeSynchronizeCommand(std::unique_ptr<common::model::AbstractTtlSynchronizeMotorCmd> &&cmd) // NOLINT
1953 {
1954  int result = COMM_TX_ERROR;
1955  ROS_DEBUG_THROTTLE(0.5, "TtlManager::writeSynchronizeCommand: %s", cmd->str().c_str());
1956 
1957  if (cmd->isValid())
1958  {
1959  std::set<EHardwareType> typesToProcess = cmd->getMotorTypes();
1960 
1961  // process all the motors using each successive drivers
1962  for (uint32_t counter = 0; counter < MAX_HW_FAILURE; ++counter)
1963  {
1964  ROS_DEBUG_THROTTLE(0.5, "TtlManager::writeSynchronizeCommand: try to sync write (counter %d)", counter);
1965 
1966  for (auto const &[hw_type, driver] : _motor_driver_map)
1967  {
1968  if (typesToProcess.count(hw_type) != 0)
1969  {
1970  result = COMM_TX_ERROR;
1971 
1972  // syncwrite for this driver. The driver is responsible for sync write only to its associated motors
1973  if (driver)
1974  {
1975  result = driver->writeSyncCmd(cmd->getCmdType(), cmd->getMotorsId(hw_type), cmd->getParams(hw_type));
1976 
1977  ros::Duration(0.05).sleep();
1978  }
1979 
1980  // if successful, don't process this driver in the next loop
1981  if (COMM_SUCCESS == result)
1982  {
1983  typesToProcess.erase(typesToProcess.find(hw_type));
1984  }
1985  else
1986  {
1987  ROS_ERROR("TtlManager::writeSynchronizeCommand : unable to sync write function : %d", result);
1988  }
1989  }
1990  }
1991 
1992  // if all drivers are processed, go out of for loop
1993  if (typesToProcess.empty())
1994  {
1995  result = COMM_SUCCESS;
1996  break;
1997  }
1998 
1999  ros::Duration(TIME_TO_WAIT_IF_BUSY).sleep();
2000  }
2001  }
2002  else
2003  {
2004  ROS_ERROR("TtlManager::writeSynchronizeCommand - Invalid command");
2005  }
2006 
2007  if (COMM_SUCCESS != result)
2008  {
2009  ROS_ERROR_THROTTLE(0.5, "TtlManager::writeSynchronizeCommand - Failed to write synchronize position");
2010  _debug_error_message = "TtlManager - Failed to write synchronize position";
2011  }
2012 
2013  return result;
2014 }
2015 
2021 int TtlManager::writeSingleCommand(std::unique_ptr<common::model::AbstractTtlSingleMotorCmd> &&cmd) // NOLINT
2022 {
2023  int result = COMM_TX_ERROR;
2024 
2025  uint8_t id = cmd->getId();
2026 
2027  if (cmd->isValid())
2028  {
2029  int counter = 0;
2030 
2031  ROS_DEBUG("TtlManager::writeSingleCommand: %s", cmd->str().c_str());
2032 
2033  if (_state_map.count(id) && _state_map.at(id))
2034  {
2035  auto state = _state_map.at(id);
2036  while ((COMM_SUCCESS != result) && (counter < 50))
2037  {
2038  EHardwareType hardware_type = state->getHardwareType();
2039  result = COMM_TX_ERROR;
2040  if (_driver_map.count(hardware_type) && _driver_map.at(hardware_type))
2041  {
2042  // writeSingleCmd is in a for loop, we cannot infer that this command will succeed. Thus we cannot move cmd in
2043  // parameter
2044  result = _driver_map.at(hardware_type)->writeSingleCmd(cmd);
2045  }
2046 
2047  counter += 1;
2048 
2049  ros::Duration(TIME_TO_WAIT_IF_BUSY).sleep();
2050  }
2051  }
2052  else
2053  {
2054  ROS_DEBUG(
2055  "TtlManager::writeSingleCommand: command is sent to a removed hardware component. Skipped or write to a "
2056  "unknow device");
2057  result = COMM_TX_ERROR;
2058  }
2059  }
2060 
2061  if (result != COMM_SUCCESS)
2062  {
2063  ROS_WARN("TtlManager::writeSingleCommand - Fail to write single command : %s", cmd->str().c_str());
2064  _debug_error_message = "TtlManager - Failed to write a single command: " + cmd->str();
2065  }
2066 
2067  return result;
2068 }
2069 
2074 void TtlManager::executeJointTrajectoryCmd(std::vector<std::pair<uint8_t, uint32_t>> cmd_vec)
2075 {
2076  for (auto const &[hw_type, driver] : _motor_driver_map)
2077  {
2078  // build list of ids and params for this motor
2079  _position_goal_ids.clear();
2080  _position_goal_params.clear();
2081  for (auto const &cmd : cmd_vec)
2082  {
2083  if (_state_map.count(cmd.first) && hw_type == _state_map.at(cmd.first)->getHardwareType())
2084  {
2085  _position_goal_ids.emplace_back(cmd.first);
2086  _position_goal_params.emplace_back(cmd.second);
2087  }
2088  }
2089 
2090  if (driver)
2091  {
2092  int err = driver->syncWritePositionGoal(_position_goal_ids, _position_goal_params);
2093  if (err != COMM_SUCCESS)
2094  {
2095  ROS_WARN("TtlManager::executeJointTrajectoryCmd - Failed to write position");
2096  _debug_error_message = "TtlManager - Failed to write position";
2097  }
2098  }
2099  }
2100 }
2101 
2102 // ******************
2103 // Calibration
2104 // ******************
2105 
2110 {
2111  ROS_DEBUG("TtlManager::startCalibration: starting...");
2112 
2113  std::vector<uint8_t> stepper_list;
2114  if (_ids_map.count(EHardwareType::STEPPER))
2115  {
2116  _calibration_status = EStepperCalibrationStatus::IN_PROGRESS;
2118  stepper_list = _ids_map.at(EHardwareType::STEPPER);
2119  }
2120  else if (_ids_map.count(EHardwareType::NED3PRO_STEPPER))
2121  {
2122  stepper_list = _ids_map.at(EHardwareType::NED3PRO_STEPPER);
2123  }
2124  else if (_ids_map.count(EHardwareType::FAKE_STEPPER_MOTOR))
2125  {
2126  _calibration_status = EStepperCalibrationStatus::IN_PROGRESS;
2128  stepper_list = _ids_map.at(EHardwareType::FAKE_STEPPER_MOTOR);
2129  }
2130 
2131  for (auto const &id : stepper_list)
2132  {
2133  if (_state_map.count(id))
2134  {
2135  auto stepperState = std::dynamic_pointer_cast<StepperMotorState>(_state_map.at(id));
2136 
2137  if (stepperState && !stepperState->isConveyor())
2138  {
2139  stepperState->setCalibration(EStepperCalibrationStatus::IN_PROGRESS, 1);
2140  }
2141  }
2142  } // for steppers_list
2143 }
2144 
2149 {
2150  ROS_INFO("TtlManager::resetCalibration: reseting...");
2151 
2152  std::vector<uint8_t> stepper_list;
2153  if (_ids_map.count(EHardwareType::STEPPER))
2154  {
2155  _calibration_status = EStepperCalibrationStatus::UNINITIALIZED;
2157  stepper_list = _ids_map.at(EHardwareType::STEPPER);
2158  }
2159  else if (_ids_map.count(EHardwareType::NED3PRO_STEPPER))
2160  stepper_list = _ids_map.at(EHardwareType::NED3PRO_STEPPER);
2161 
2162  for (auto const id : stepper_list)
2163  {
2164  if (_state_map.count(id))
2165  {
2166  auto stepperState = std::dynamic_pointer_cast<StepperMotorState>(_state_map.at(id));
2167 
2168  if (stepperState && !stepperState->isConveyor())
2169  {
2170  stepperState->setCalibration(EStepperCalibrationStatus::UNINITIALIZED, 1);
2171  }
2172  }
2173  } // for steppers_list
2174 }
2175 
2181 int32_t TtlManager::getCalibrationResult(uint8_t motor_id) const
2182 {
2183  if (!_state_map.count(motor_id) && _state_map.at(motor_id))
2184  throw std::out_of_range("TtlManager::getMotorsState: Unknown motor id");
2185 
2186  return std::dynamic_pointer_cast<StepperMotorState>(_state_map.at(motor_id))->getCalibrationValue();
2187 }
2188 
2189 // ******************
2190 // Getters
2191 // ******************
2192 
2199 void TtlManager::getBusState(bool &connection_state, std::vector<uint8_t> &motor_id, std::string &debug_msg) const
2200 {
2201  debug_msg = _debug_error_message;
2202  motor_id = _all_ids_connected;
2203  connection_state = isConnectionOk();
2204 }
2205 
2210 std::vector<std::shared_ptr<JointState>> TtlManager::getMotorsStates() const
2211 {
2212  std::vector<std::shared_ptr<JointState>> states;
2213 
2214  for (const auto &it : _state_map)
2215  {
2216  if (it.second && it.second->getComponentType() == common::model::EComponentType::JOINT)
2217  {
2218  states.emplace_back(std::dynamic_pointer_cast<JointState>(it.second));
2219  }
2220  }
2221 
2222  return states;
2223 }
2224 
2225 std::vector<std::shared_ptr<ConveyorState>> TtlManager::getConveyorsStates() const
2226 {
2227  std::vector<std::shared_ptr<ConveyorState>> conveyor_states;
2228  for (const auto &it : _state_map)
2229  {
2230  if (it.second && it.second->getComponentType() == common::model::EComponentType::CONVEYOR)
2231  {
2232  conveyor_states.emplace_back(std::dynamic_pointer_cast<ConveyorState>(it.second));
2233  }
2234  }
2235 
2236  return conveyor_states;
2237 }
2238 
2244 std::shared_ptr<common::model::AbstractHardwareState> TtlManager::getHardwareState(uint8_t motor_id) const
2245 {
2246  if (!_state_map.count(motor_id) && _state_map.at(motor_id))
2247  throw std::out_of_range("TtlManager::getMotorsState: Unknown motor id");
2248 
2249  return _state_map.at(motor_id);
2250 }
2251 
2252 // ********************
2253 // Private
2254 // ********************
2255 
2260 void TtlManager::addHardwareDriver(EHardwareType hardware_type)
2261 {
2262  // if not already instanciated
2263  if (!_driver_map.count(hardware_type))
2264  {
2265  std::shared_ptr<ttl_driver::AbstractTtlDriver> new_driver = nullptr;
2266  switch (hardware_type)
2267  {
2268  case EHardwareType::STEPPER: {
2269  auto motor = std::make_shared<StepperDriver<StepperReg>>(_portHandler, _packetHandler);
2270  _motor_driver_map.insert({ hardware_type, motor });
2271  new_driver = motor;
2272  break;
2273  }
2274  case EHardwareType::NED3PRO_STEPPER: {
2275  auto motor = std::make_shared<Ned3ProStepperDriver<Ned3ProStepperReg>>(_portHandler, _packetHandler);
2276  _motor_driver_map.insert({ hardware_type, motor });
2277  new_driver = motor;
2278  break;
2279  }
2280  case EHardwareType::FAKE_STEPPER_MOTOR: {
2281  auto motor = std::make_shared<MockStepperDriver>(_fake_data);
2282  _motor_driver_map.insert({ hardware_type, motor });
2283  new_driver = motor;
2284  break;
2285  }
2286  case EHardwareType::XL430: {
2287  auto motor = std::make_shared<DxlDriver<XL430Reg>>(_portHandler, _packetHandler);
2288  _motor_driver_map.insert({ hardware_type, motor });
2289  new_driver = motor;
2290  break;
2291  }
2292  case EHardwareType::XC430: {
2293  auto motor = std::make_shared<DxlDriver<XC430Reg>>(_portHandler, _packetHandler);
2294  _motor_driver_map.insert({ hardware_type, motor });
2295  new_driver = motor;
2296  break;
2297  }
2298  case EHardwareType::XM430: {
2299  auto motor = std::make_shared<DxlDriver<XM430Reg>>(_portHandler, _packetHandler);
2300  _motor_driver_map.insert({ hardware_type, motor });
2301  new_driver = motor;
2302  break;
2303  }
2304  case EHardwareType::XL320: {
2305  auto motor = std::make_shared<DxlDriver<XL320Reg>>(_portHandler, _packetHandler);
2306  _motor_driver_map.insert({ hardware_type, motor });
2307  new_driver = motor;
2308  break;
2309  }
2310  case EHardwareType::XL330: {
2311  auto motor = std::make_shared<DxlDriver<XL330Reg>>(_portHandler, _packetHandler);
2312  _motor_driver_map.insert({ hardware_type, motor });
2313  new_driver = motor;
2314  break;
2315  }
2316  case EHardwareType::XH430: {
2317  auto motor = std::make_shared<DxlDriver<XH430Reg>>(_portHandler, _packetHandler);
2318  _motor_driver_map.insert({ hardware_type, motor });
2319  new_driver = motor;
2320  break;
2321  }
2322  case EHardwareType::FAKE_DXL_MOTOR: {
2323  auto motor = std::make_shared<MockDxlDriver>(_fake_data);
2324  _motor_driver_map.insert({ hardware_type, motor });
2325  new_driver = motor;
2326  break;
2327  }
2328  case EHardwareType::END_EFFECTOR: {
2329  auto ee = std::make_shared<EndEffectorDriver<EndEffectorReg>>(_portHandler, _packetHandler);
2330  _end_effector_driver_map.insert({ hardware_type, ee });
2331  new_driver = ee;
2332  break;
2333  }
2334  case EHardwareType::NED3PRO_END_EFFECTOR: {
2335  auto ee = std::make_shared<Ned3ProEndEffectorDriver<Ned3ProEndEffectorReg>>(_portHandler, _packetHandler);
2336  _end_effector_driver_map.insert({ hardware_type, ee });
2337  new_driver = ee;
2338  break;
2339  }
2340  case EHardwareType::FAKE_END_EFFECTOR: {
2341  auto ee = std::make_shared<MockEndEffectorDriver>(_fake_data);
2342  _end_effector_driver_map.insert({ hardware_type, ee });
2343  new_driver = ee;
2344  break;
2345  }
2346  default:
2347  ROS_ERROR("TtlManager - Unable to instanciate driver, unknown type");
2348  break;
2349  }
2350  if (new_driver != nullptr)
2351  {
2352  _driver_map.insert({ hardware_type, new_driver });
2353  }
2354  }
2355 }
2356 
2360 void TtlManager::readFakeConfig(bool use_simu_gripper, bool use_simu_conveyor)
2361 {
2362  _fake_data = std::make_shared<FakeTtlData>();
2363 
2364  if (_nh.hasParam("fake_params"))
2365  {
2366  std::vector<int> full_id_list;
2367  if (_nh.hasParam("fake_params/id_list"))
2368  _nh.getParam("fake_params/id_list", full_id_list);
2369  for (auto id : full_id_list)
2370  _fake_data->full_id_list.emplace_back(static_cast<uint8_t>(id));
2371 
2372  if (_nh.hasParam("fake_params/steppers"))
2373  {
2374  std::string current_ns = "fake_params/steppers/";
2375  retrieveFakeMotorData(current_ns, _fake_data->stepper_registers);
2376  }
2377 
2378  if (_nh.hasParam("fake_params/dynamixels/"))
2379  {
2380  std::string current_ns = "fake_params/dynamixels/";
2381  retrieveFakeMotorData(current_ns, _fake_data->dxl_registers);
2382  }
2383 
2384  if (use_simu_gripper && _nh.hasParam("fake_params/tool/"))
2385  {
2386  std::string current_ns = "fake_params/tool/";
2387  retrieveFakeMotorData(current_ns, _fake_data->dxl_registers);
2388  }
2389 
2390  if (_nh.hasParam("fake_params/end_effector"))
2391  {
2392  string current_ns = "fake_params/end_effector/";
2393  vector<int> id_list, temperature_list, voltage_list;
2394  vector<string> firmware_list;
2395  _nh.getParam(current_ns + "id", id_list);
2396  _nh.getParam(current_ns + "temperature", temperature_list);
2397  _nh.getParam(current_ns + "voltage", voltage_list);
2398  _nh.getParam(current_ns + "firmware", firmware_list);
2399 
2400  assert(!id_list.empty());
2401  assert(!temperature_list.empty());
2402  assert(!voltage_list.empty());
2403  assert(!firmware_list.empty());
2404 
2405  _fake_data->end_effector.id = static_cast<uint8_t>(id_list.at(0));
2406  _fake_data->end_effector.temperature = static_cast<uint8_t>(temperature_list.at(0));
2407  _fake_data->end_effector.voltage = static_cast<double>(voltage_list.at(0));
2408 
2409  _fake_data->end_effector.firmware = firmware_list.at(0);
2410  }
2411 
2412  if (use_simu_conveyor && _nh.hasParam("fake_params/conveyors/"))
2413  {
2414  std::string current_ns = "fake_params/conveyors/";
2415  retrieveFakeMotorData(current_ns, _fake_data->stepper_registers);
2416  }
2417 
2418  _fake_data->updateFullIdList();
2419  }
2420 }
2421 
2428 {
2429  auto joint_states = getMotorsStates();
2430  auto some_joint_state_it =
2431  std::find_if(joint_states.begin(), joint_states.end(),
2432  [](const std::shared_ptr<JointState> &joint_state) { return joint_state->isStepper(); });
2433  if (some_joint_state_it == joint_states.end())
2434  {
2435  return {};
2436  }
2437  auto some_joint_state = *some_joint_state_it;
2438  auto hardware_type = some_joint_state->getHardwareType();
2439  return { .driver = std::dynamic_pointer_cast<AbstractStepperDriver>(_driver_map.at(hardware_type)),
2440  .hardware_type = hardware_type };
2441 }
2442 
2443 } // namespace ttl_driver
end_effector_driver.hpp
ttl_driver::TtlManager::startCalibration
void startCalibration() override
TtlManager::startCalibration.
Definition: ttl_manager.cpp:2109
ttl_driver::TtlManager::addHardwareComponent
int addHardwareComponent(std::shared_ptr< common::model::AbstractHardwareState > &&state) override
TtlManager::addHardwareComponent add hardware component like joint, ee, tool... to ttl manager.
Definition: ttl_manager.cpp:272
ttl_driver::TtlManager::CalibrationMachineState::State::IDLE
@ IDLE
ttl_driver::TtlManager::readEndEffectorStatus
bool readEndEffectorStatus()
TtlManager::readEndEffectorStatus.
Definition: ttl_manager.cpp:874
ttl_driver::TtlManager::readCustomCommand
int readCustomCommand(uint8_t id, int32_t reg_address, int &value, int byte_number)
TtlManager::readCustomCommand.
Definition: ttl_manager.cpp:1700
mock_dxl_driver.hpp
ttl_driver::TtlManager::_debug_error_message
std::string _debug_error_message
Definition: ttl_manager.hpp:233
ttl_driver::TtlManager::_current_tool_vector
std::vector< int > _current_tool_vector
Definition: ttl_manager.hpp:266
ttl_driver::TtlManager::getJointsStepperDriver
GetJointsStepperDriverResult getJointsStepperDriver()
: Return the driver of the joints
Definition: ttl_manager.cpp:2427
ttl_driver::TtlManager::writeSingleCommand
int writeSingleCommand(std::unique_ptr< common::model::AbstractTtlSingleMotorCmd > &&cmd)
TtlManager::writeSingleCommand.
Definition: ttl_manager.cpp:2021
ttl_driver::TTL_SCAN_MISSING_MOTOR
constexpr int TTL_SCAN_MISSING_MOTOR
Definition: ttl_manager.hpp:70
ttl_driver::TtlManager::_state_map
std::map< uint8_t, std::shared_ptr< common::model::AbstractHardwareState > > _state_map
Definition: ttl_manager.hpp:213
ttl_driver::TtlManager::_motor_driver_map
std::map< common::model::EHardwareType, std::shared_ptr< ttl_driver::AbstractMotorDriver > > _motor_driver_map
Definition: ttl_manager.hpp:220
ttl_driver::TtlManager::_calib_machine_state
CalibrationMachineState _calib_machine_state
Definition: ttl_manager.hpp:319
ttl_driver::TtlManager::readHardwareStatus
bool readHardwareStatus()
TtlManager::readHardwareStatus.
Definition: ttl_manager.cpp:1140
ttl_driver::TtlManager::getCalibrationResult
int32_t getCalibrationResult(uint8_t id) const override
TtlManager::getCalibrationResult.
Definition: ttl_manager.cpp:2181
ttl_driver::TtlManager::retrieveFakeMotorData
void retrieveFakeMotorData(const std::string &current_ns, std::map< uint8_t, Reg > &fake_params, std::vector< int > hw_ids={})
TtlManager::retrieveFakeMotorData.
Definition: ttl_manager.hpp:405
ttl_driver::TtlManager::_calibration_status
common::model::EStepperCalibrationStatus _calibration_status
Definition: ttl_manager.hpp:248
ttl_driver::TtlManager::_nh
ros::NodeHandle _nh
Definition: ttl_manager.hpp:200
ttl_driver::TtlManager::scanAndCheck
int scanAndCheck() override
TtlManager::scanAndCheck.
Definition: ttl_manager.cpp:487
ttl_driver::TtlManager::checkCollision
bool checkCollision()
TtlManager::checkCollision.
Definition: ttl_manager.cpp:989
ttl_driver::TtlManager::CalibrationMachineState::State::IN_PROGRESS
@ IN_PROGRESS
ttl_driver::TtlManager::_hw_fail_counter_read
uint32_t _hw_fail_counter_read
Definition: ttl_manager.hpp:238
mock_end_effector_driver.hpp
ttl_driver::TtlManager::_position_goal_params
std::vector< uint32_t > _position_goal_params
Definition: ttl_manager.hpp:264
stepper_reg.hpp
ttl_driver::TTL_FAIL_OPEN_PORT
constexpr int TTL_FAIL_OPEN_PORT
Definition: ttl_manager.hpp:64
ttl_driver::TtlManager::_position_goal_ids
std::vector< uint8_t > _position_goal_ids
Definition: ttl_manager.hpp:263
ttl_driver::TtlManager::_end_effector_state_map
std::map< uint8_t, std::shared_ptr< common::model::EndEffectorState > > _end_effector_state_map
Definition: ttl_manager.hpp:215
ttl_driver::TtlManager::_all_ids_connected
std::vector< uint8_t > _all_ids_connected
Definition: ttl_manager.hpp:209
ttl_driver::TtlManager::_last_collision_detection_activating
double _last_collision_detection_activating
Definition: ttl_manager.hpp:256
ttl_driver::TtlManager::sendCustomCommand
int sendCustomCommand(uint8_t id, int reg_address, int value, int byte_number)
TtlManager::sendCustomCommand.
Definition: ttl_manager.cpp:1645
end_effector_reg.hpp
ttl_driver::TtlManager::readSteppersStatus
uint8_t readSteppersStatus()
TtlManager::readCalibrationStatus : reads specific steppers related information (ned2 only)
Definition: ttl_manager.cpp:1263
ttl_driver::TtlManager::TtlManager
TtlManager()=delete
ttl_driver::TtlManager::CalibrationMachineState::State::UPDATING
@ UPDATING
ttl_driver::TTL_FAIL_PORT_SET_BAUDRATE
constexpr int TTL_FAIL_PORT_SET_BAUDRATE
Definition: ttl_manager.hpp:66
ttl_driver::TtlManager::changeId
int changeId(common::model::EHardwareType motor_type, uint8_t old_id, uint8_t new_id)
TtlManager::changeId.
Definition: ttl_manager.cpp:425
ttl_driver::TtlManager::getAllIdsOnBus
int getAllIdsOnBus(std::vector< uint8_t > &id_list)
TtlManager::getAllIdsOnDxlBus.
Definition: ttl_manager.cpp:1532
ttl_driver::TtlManager::removeHardwareComponent
void removeHardwareComponent(uint8_t id) override
TtlManager::removeHardwareComponent.
Definition: ttl_manager.cpp:372
ttl_driver::TtlManager::readHomingAbsPosition
bool readHomingAbsPosition()
Definition: ttl_manager.cpp:691
ttl_driver::TtlManager::_device_name
std::string _device_name
Definition: ttl_manager.hpp:206
ned3pro_stepper_driver.hpp
ttl_driver::TtlManager::getHardwareState
std::shared_ptr< common::model::AbstractHardwareState > getHardwareState(uint8_t motor_id) const
TtlManager::getHardwareState.
Definition: ttl_manager.cpp:2244
ttl_driver::TtlManager::readJointsStatus
bool readJointsStatus()
TtlManager::readJointsStatus.
Definition: ttl_manager.cpp:764
ttl_driver::TtlManager::executeJointTrajectoryCmd
void executeJointTrajectoryCmd(std::vector< std::pair< uint8_t, uint32_t >> cmd_vec)
TtlManager::executeJointTrajectoryCmd.
Definition: ttl_manager.cpp:2074
ttl_driver::TtlManager::_packetHandler
std::shared_ptr< dynamixel::PacketHandler > _packetHandler
Definition: ttl_manager.hpp:202
ttl_driver::TtlManager::init
bool init(ros::NodeHandle &nh) override
TtlManager::init.
Definition: ttl_manager.cpp:108
ttl_driver::TtlManager::getConveyorsStates
std::vector< std::shared_ptr< common::model::ConveyorState > > getConveyorsStates() const
Definition: ttl_manager.cpp:2225
ttl_driver::TtlManager::getPosition
uint32_t getPosition(const common::model::JointState &motor_state)
TtlManager::getPosition.
Definition: ttl_manager.cpp:656
ttl_driver::TtlManager::resetCalibration
void resetCalibration() override
TtlManager::resetCalibration.
Definition: ttl_manager.cpp:2148
ttl_driver::TtlManager::CalibrationMachineState::State::STARTING
@ STARTING
ttl_driver::TtlManager::CalibrationMachineState::status
State status()
Definition: ttl_manager.hpp:303
ttl_driver::TtlManager::getBusState
void getBusState(bool &connection_state, std::vector< uint8_t > &motor_id, std::string &debug_msg) const override
TtlManager::getBusState.
Definition: ttl_manager.cpp:2199
ttl_driver::TtlManager::changeTool
bool changeTool(int value, std::string &message, int &status)
TtlManager::changeTool.
Definition: ttl_manager.cpp:159
ttl_driver::TtlManager::resetTorques
void resetTorques()
TtlManager::resetTorques.
Definition: ttl_manager.cpp:620
ttl_driver::TtlManager::isMotorType
bool isMotorType(common::model::EHardwareType type)
TtlManager::isMotorType.
Definition: ttl_manager.cpp:408
ttl_driver::TtlManager::_available_tools
std::vector< int > _available_tools
Definition: ttl_manager.hpp:265
ttl_driver::TtlManager::readCollisionStatus
bool readCollisionStatus()
TtlManager::readCollisionStatus.
Definition: ttl_manager.cpp:1073
stepper_driver.hpp
ttl_driver::TtlManager::MAX_READ_EE_FAILURE
static constexpr uint32_t MAX_READ_EE_FAILURE
Definition: ttl_manager.hpp:245
ttl_driver::TtlManager::setLeds
int setLeds(int led)
TtlManager::setLeds.
Definition: ttl_manager.cpp:1586
ttl_driver::TtlManager::_isWrongAction
bool _isWrongAction
Definition: ttl_manager.hpp:258
ttl_driver::TtlManager::writeSynchronizeCommand
int writeSynchronizeCommand(std::unique_ptr< common::model::AbstractTtlSynchronizeMotorCmd > &&cmd)
TtlManager::writeSynchronizeCommand.
Definition: ttl_manager.cpp:1952
ttl_driver::TtlManager::_end_effector_driver_map
std::map< common::model::EHardwareType, std::shared_ptr< ttl_driver::AbstractEndEffectorDriver > > _end_effector_driver_map
Definition: ttl_manager.hpp:222
ttl_driver::TtlManager::_collision_status
bool _collision_status
Definition: ttl_manager.hpp:255
mock_stepper_driver.hpp
ttl_driver::TtlManager::ping
bool ping(uint8_t id) override
TtlManager::ping.
Definition: ttl_manager.cpp:556
dxl_driver.hpp
ttl_driver
Definition: abstract_dxl_driver.hpp:30
ttl_driver::TtlManager::_default_ttl_driver
std::shared_ptr< ttl_driver::AbstractTtlDriver > _default_ttl_driver
Definition: ttl_manager.hpp:225
ttl_driver::TtlManager::rebootHardware
int rebootHardware(uint8_t id)
TtlManager::rebootHardware.
Definition: ttl_manager.cpp:574
ttl_driver::TtlManager::_fake_data
std::shared_ptr< FakeTtlData > _fake_data
Definition: ttl_manager.hpp:251
ned3pro_end_effector_driver.hpp
ttl_driver::TtlManager::readNed3ProSteppersStatus
uint8_t readNed3ProSteppersStatus()
Definition: ttl_manager.cpp:1432
ttl_driver::TtlManager::CalibrationMachineState::reset
void reset()
Definition: ttl_manager.hpp:279
ttl_driver::TtlManager::_end_effector_fail_counter_read
uint32_t _end_effector_fail_counter_read
Definition: ttl_manager.hpp:239
ttl_driver::TtlManager::_is_connection_ok
bool _is_connection_ok
Definition: ttl_manager.hpp:232
nh
static std::unique_ptr< ros::NodeHandle > nh
Definition: service_client_ned2.cpp:31
ttl_driver::TtlManager::isConnectionOk
bool isConnectionOk() const override
TtlManager::isConnectionOk.
Definition: ttl_manager.hpp:328
ttl_driver::TtlManager::_position_list
std::vector< uint32_t > _position_list
Definition: ttl_manager.hpp:262
ttl_driver::TtlManager::CalibrationMachineState::start
void start()
Definition: ttl_manager.hpp:284
ttl_driver::TtlManager::_led_state
int _led_state
Definition: ttl_manager.hpp:241
ttl_driver::TtlManager::_simulation_mode
bool _simulation_mode
Definition: ttl_manager.hpp:252
ttl_driver::TTL_SCAN_OK
constexpr int TTL_SCAN_OK
Definition: ttl_manager.hpp:69
ttl_driver::TtlManager::_motor_state_map
std::map< uint8_t, std::shared_ptr< common::model::AbstractMotorState > > _motor_state_map
Definition: ttl_manager.hpp:214
ttl_driver::TtlManager::readMoving
int readMoving(uint8_t id, uint8_t &status)
TtlManager::readMoving.
Definition: ttl_manager.cpp:1873
ttl_driver::TtlManager::_removed_motor_id_list
std::vector< uint8_t > _removed_motor_id_list
Definition: ttl_manager.hpp:210
ttl_driver::TtlManager::_current_tool_id
uint32_t _current_tool_id
Definition: ttl_manager.hpp:236
ttl_driver::TtlManager::_sync_mutex
std::mutex _sync_mutex
Definition: ttl_manager.hpp:204
ttl_driver::TtlManager::_ids_map
std::map< common::model::EHardwareType, std::vector< uint8_t > > _ids_map
Definition: ttl_manager.hpp:217
ttl_driver::TtlManager::CalibrationMachineState::next
void next()
next : next state, stops at updating (dont circle)
Definition: ttl_manager.hpp:293
ttl_driver::TtlManager::_portHandler
std::shared_ptr< dynamixel::PortHandler > _portHandler
Definition: ttl_manager.hpp:201
ttl_driver::TtlManager::GetJointsStepperDriverResult
Definition: ttl_manager.hpp:192
ttl_driver::TtlManager::CalibrationMachineState::isTimeout
bool isTimeout()
Definition: ttl_manager.hpp:308
ttl_driver::TtlManager::_driver_map
std::map< common::model::EHardwareType, std::shared_ptr< ttl_driver::AbstractTtlDriver > > _driver_map
Definition: ttl_manager.hpp:219
ttl_driver::TtlManager::setupCommunication
int setupCommunication() override
TtlManager::setupCommunication.
Definition: ttl_manager.cpp:215
ttl_driver::TtlManager::MAX_HW_FAILURE
static constexpr uint32_t MAX_HW_FAILURE
Definition: ttl_manager.hpp:244
ttl_driver::TtlManager::getMotorsStates
std::vector< std::shared_ptr< common::model::JointState > > getMotorsStates() const
TtlManager::getMotorsStates.
Definition: ttl_manager.cpp:2210
ttl_driver::TtlManager::~TtlManager
~TtlManager() override
TtlManager::~TtlManager.
Definition: ttl_manager.cpp:94
ttl_driver::TtlManager::_conveyor_list
std::vector< uint8_t > _conveyor_list
Definition: ttl_manager.hpp:229
ttl_driver::TtlManager::addHardwareDriver
void addHardwareDriver(common::model::EHardwareType hardware_type) override
TtlManager::addHardwareDriver.
Definition: ttl_manager.cpp:2260
ttl_driver::TtlManager::_calibration_status_publisher
ros::Publisher _calibration_status_publisher
Definition: ttl_manager.hpp:260
ttl_driver::TtlManager::_led_motor_type_cfg
std::string _led_motor_type_cfg
Definition: ttl_manager.hpp:242
ttl_driver::TtlManager::readControlMode
int readControlMode(uint8_t id, uint8_t &control_mode)
TtlManager::readControlMode.
Definition: ttl_manager.cpp:1914
ttl_driver::TTL_BUS_PROTOCOL_VERSION
constexpr float TTL_BUS_PROTOCOL_VERSION
Definition: ttl_manager.hpp:63
ttl_manager.hpp
ttl_driver::TtlManager::readMotorPID
int readMotorPID(uint8_t id, uint16_t &pos_p_gain, uint16_t &pos_i_gain, uint16_t &pos_d_gain, uint16_t &vel_p_gain, uint16_t &vel_i_gain, uint16_t &ff1_gain, uint16_t &ff2_gain)
TtlManager::readMotorPID.
Definition: ttl_manager.cpp:1753
ttl_driver::TtlManager::readVelocityProfile
int readVelocityProfile(uint8_t id, uint32_t &v_start, uint32_t &a_1, uint32_t &v_1, uint32_t &a_max, uint32_t &v_max, uint32_t &d_max, uint32_t &d_1, uint32_t &v_stop)
TtlManager::readVelocityProfile.
Definition: ttl_manager.cpp:1818
ttl_driver::TtlManager::_baudrate
int _baudrate
Definition: ttl_manager.hpp:207
ttl_driver::TtlManager::readFakeConfig
void readFakeConfig(bool use_simu_gripper, bool use_simu_conveyor)
TtlManager::readFakeConfig.
Definition: ttl_manager.cpp:2360
ttl_driver::TtlManager::_isRealCollision
bool _isRealCollision
Definition: ttl_manager.hpp:257
fake_ttl_data.hpp


ttl_driver
Author(s): Clement Cocquempot
autogenerated on Wed Jul 1 2026 15:08:50