17 #ifndef DXL_DRIVER_HPP
18 #define DXL_DRIVER_HPP
28 #include "common/common_defs.hpp"
43 template <
typename reg_type>
47 DxlDriver(std::shared_ptr<dynamixel::PortHandler> portHandler,
48 std::shared_ptr<dynamixel::PacketHandler> packetHandler);
50 std::string
str()
const override;
58 int readVoltage(uint8_t
id,
double &voltage)
override;
61 int syncReadFirmwareVersion(
const std::vector<uint8_t> &id_list, std::vector<std::string> &firmware_list)
override;
62 int syncReadTemperature(
const std::vector<uint8_t> &id_list, std::vector<uint8_t> &temperature_list)
override;
63 int syncReadVoltage(
const std::vector<uint8_t> &id_list, std::vector<double> &voltage_list)
override;
64 int syncReadRawVoltage(
const std::vector<uint8_t> &id_list, std::vector<double> &voltage_list)
override;
65 int syncReadHwStatus(
const std::vector<uint8_t> &id_list, std::vector<std::pair<double, uint8_t>> &data_list)
override;
67 int syncReadHwErrorStatus(
const std::vector<uint8_t> &id_list, std::vector<uint8_t> &hw_error_list)
override;
79 int changeId(uint8_t
id, uint8_t new_id)
override;
93 int syncWriteTorquePercentage(
const std::vector<uint8_t> &id_list,
const std::vector<uint8_t> &torque_percentage_list)
override;
94 int syncWritePositionGoal(
const std::vector<uint8_t> &id_list,
const std::vector<uint32_t> &position_list)
override;
95 int syncWriteVelocityGoal(
const std::vector<uint8_t> &id_list,
const std::vector<uint32_t> &velocity_list)
override;
100 int readPosition(uint8_t
id, uint32_t &present_position)
override;
101 int readVelocity(uint8_t
id, uint32_t &present_velocity)
override;
103 int syncReadPosition(
const std::vector<uint8_t> &id_list, std::vector<uint32_t> &position_list)
override;
104 int syncReadVelocity(
const std::vector<uint8_t> &id_list, std::vector<uint32_t> &velocity_list)
override;
105 int syncReadJointStatus(
const std::vector<uint8_t> &id_list, std::vector<std::array<uint32_t, 2>> &data_array_list)
override;
118 int readLoad(uint8_t
id, uint16_t &present_load)
override;
119 int syncReadLoad(
const std::vector<uint8_t> &id_list, std::vector<uint16_t> &load_list)
override;
121 int readPID(uint8_t
id, std::vector<uint16_t> &data_list)
override;
124 int readMoving(uint8_t
id, uint8_t &status)
override;
127 int writePID(uint8_t
id,
const std::vector<uint16_t> &data)
override;
130 int writeLed(uint8_t
id, uint8_t led_value)
override;
131 int syncWriteLed(
const std::vector<uint8_t> &id_list,
const std::vector<uint8_t> &led_list)
override;
134 int syncWriteTorqueGoal(
const std::vector<uint8_t> &id_list,
const std::vector<uint16_t> &torque_list)
override;
142 template <
typename reg_type>
144 std::shared_ptr<dynamixel::PacketHandler> packetHandler) :
AbstractDxlDriver(std::move(portHandler),
145 std::move(packetHandler))
157 template <
typename reg_type>
160 return common::model::HardwareTypeEnum(reg_type::motor_type).toString() +
" : " +
AbstractDxlDriver::str();
167 template <
typename reg_type>
178 template <
typename reg_type>
181 std::string version = std::to_string(
static_cast<uint8_t
>(fw_version));
192 template <
typename reg_type>
195 return write<typename reg_type::TYPE_ID>(reg_type::ADDR_ID,
id, new_id);
203 template <
typename reg_type>
206 uint16_t model_number = 0;
207 int ping_result = getModelNumber(
id, model_number);
209 if (ping_result == COMM_SUCCESS)
211 if (model_number && model_number != reg_type::MODEL_NUMBER)
213 return PING_WRONG_MODEL_NUMBER;
226 template <
typename reg_type>
229 int res = COMM_RX_FAIL;
231 res = read<typename reg_type::TYPE_FIRMWARE_VERSION>(reg_type::ADDR_FIRMWARE_VERSION,
id, data);
232 version = interpretFirmwareVersion(data);
242 template <
typename reg_type>
246 int res = readFirmwareVersion(
id, version);
249 if (COMM_SUCCESS == res && std::stoi(version) >= reg_type::VERSION_STARTUP_CONFIGURATION)
251 res = write<typename reg_type::TYPE_STARTUP_CONFIGURATION>(reg_type::ADDR_STARTUP_CONFIGURATION,
id, config);
255 std::cout <<
"Startup configuration available only for version > " <<
static_cast<int>(reg_type::VERSION_STARTUP_CONFIGURATION) << std::endl;
268 template <
typename reg_type>
271 std::cout <<
"temperature limit not available for this motor type" << std::endl;
281 template <
typename reg_type>
284 std::cout <<
"shutdown configuration not available for this motor type" << std::endl;
294 template <
typename reg_type>
297 return read<typename reg_type::TYPE_MIN_POSITION_LIMIT>(reg_type::ADDR_MIN_POSITION_LIMIT,
id, pos);
306 template <
typename reg_type>
309 return read<typename reg_type::TYPE_MAX_POSITION_LIMIT>(reg_type::ADDR_MAX_POSITION_LIMIT,
id, pos);
321 template <
typename reg_type>
325 int res = COMM_RX_FAIL;
327 for (
int tries = 10; tries > 0; --tries)
329 res = write<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_VELOCITY,
id, data_list.at(0));
330 if (COMM_SUCCESS == res)
334 for (
int tries = 10; tries > 0; --tries)
336 res = write<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_ACCELERATION,
id, data_list.at(1));
337 if (COMM_SUCCESS == res)
341 if (COMM_SUCCESS != res)
353 template <
typename reg_type>
356 auto torque_enable = torque_percentage > 0 ? 1 : 0;
357 return write<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE,
id, torque_enable);
366 template <
typename reg_type>
369 return write<typename reg_type::TYPE_GOAL_POSITION>(reg_type::ADDR_GOAL_POSITION,
id,
370 static_cast<typename reg_type::TYPE_GOAL_POSITION
>(position));
379 template <
typename reg_type>
382 return write<typename reg_type::TYPE_GOAL_VELOCITY>(reg_type::ADDR_GOAL_VELOCITY,
id,
383 static_cast<typename reg_type::TYPE_GOAL_VELOCITY
>(velocity));
392 template <
typename reg_type>
395 std::vector<uint8_t> torque_enable_list;
396 for(
const auto &torque_percentage : torque_percentage_list)
398 auto torque_enable = torque_percentage > 0 ? 1 : 0;
399 torque_enable_list.push_back(torque_enable);
401 return syncWrite<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE, id_list, torque_enable_list);
410 template <
typename reg_type>
413 return syncWrite<typename reg_type::TYPE_GOAL_POSITION>(reg_type::ADDR_GOAL_POSITION, id_list, position_list);
422 template <
typename reg_type>
425 return syncWrite<typename reg_type::TYPE_GOAL_VELOCITY>(reg_type::ADDR_GOAL_VELOCITY, id_list, velocity_list);
429 template <
typename reg_type>
433 typename reg_type::TYPE_PROFILE velocity_profile{};
434 typename reg_type::TYPE_PROFILE acceleration_profile{};
436 int res = read<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_VELOCITY,
id, velocity_profile);
437 if (COMM_SUCCESS == res)
438 res = read<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_ACCELERATION,
id, acceleration_profile);
440 data_list.emplace_back(velocity_profile);
441 data_list.emplace_back(acceleration_profile);
452 template <
typename reg_type>
455 return read<typename reg_type::TYPE_PRESENT_POSITION>(reg_type::ADDR_PRESENT_POSITION,
id, present_position);
464 template <
typename reg_type>
467 return read<typename reg_type::TYPE_PRESENT_TEMPERATURE>(reg_type::ADDR_PRESENT_TEMPERATURE,
id, temperature);
476 template <
typename reg_type>
479 typename reg_type::TYPE_PRESENT_VOLTAGE voltage_mV{};
480 int res = read<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE,
id, voltage_mV);
481 voltage =
static_cast<double>(voltage_mV) / reg_type::VOLTAGE_CONVERSION;
491 template <
typename reg_type>
494 return read<typename reg_type::TYPE_HW_ERROR_STATUS>(reg_type::ADDR_HW_ERROR_STATUS,
id, hardware_error_status);
503 template <
typename reg_type>
506 return syncRead<typename reg_type::TYPE_PRESENT_POSITION>(reg_type::ADDR_PRESENT_POSITION, id_list, position_list);
515 template <
typename reg_type>
518 int res = COMM_TX_FAIL;
521 for (
int tries = 10; tries > 0; --tries)
523 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_P_GAIN,
id, data.at(0));
524 if (COMM_SUCCESS == res)
528 if (COMM_SUCCESS != res)
531 for (
int tries = 10; tries > 0; --tries)
533 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_I_GAIN,
id, data.at(1));
534 if (COMM_SUCCESS == res)
537 if (COMM_SUCCESS != res)
540 for (
int tries = 10; tries > 0; --tries)
542 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_D_GAIN,
id, data.at(2));
543 if (COMM_SUCCESS == res)
546 if (COMM_SUCCESS != res)
549 for (
int tries = 10; tries > 0; --tries)
551 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_VELOCITY_P_GAIN,
id, data.at(3));
552 if (COMM_SUCCESS == res)
555 if (COMM_SUCCESS != res)
558 for (
int tries = 10; tries > 0; --tries)
560 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_VELOCITY_I_GAIN,
id, data.at(4));
561 if (COMM_SUCCESS == res)
564 if (COMM_SUCCESS != res)
567 for (
int tries = 10; tries > 0; --tries)
569 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_FF1_GAIN,
id, data.at(5));
570 if (COMM_SUCCESS == res)
573 if (COMM_SUCCESS != res)
576 for (
int tries = 10; tries > 0; --tries)
578 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_FF2_GAIN,
id, data.at(6));
579 if (res == COMM_SUCCESS)
592 template <
typename reg_type>
595 int res = COMM_RX_FAIL;
596 std::vector<uint8_t> data_list;
597 res = syncRead<typename reg_type::TYPE_FIRMWARE_VERSION>(reg_type::ADDR_FIRMWARE_VERSION, id_list, data_list);
598 for (
auto const &data : data_list)
599 firmware_list.emplace_back(interpretFirmwareVersion(data));
609 template <
typename reg_type>
612 return syncRead<typename reg_type::TYPE_PRESENT_TEMPERATURE>(reg_type::ADDR_PRESENT_TEMPERATURE, id_list, temperature_list);
621 template <
typename reg_type>
624 voltage_list.clear();
625 std::vector<typename reg_type::TYPE_PRESENT_VOLTAGE> v_read;
626 int res = syncRead<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, v_read);
627 for (
auto const &v : v_read)
628 voltage_list.emplace_back(
static_cast<double>(v) / reg_type::VOLTAGE_CONVERSION);
638 template <
typename reg_type>
641 voltage_list.clear();
642 std::vector<typename reg_type::TYPE_PRESENT_VOLTAGE> v_read;
643 int res = syncRead<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, v_read);
644 for (
auto const &v : v_read)
645 voltage_list.emplace_back(
static_cast<double>(v));
655 template <
typename reg_type>
657 std::vector<std::pair<double, uint8_t>> &data_list)
661 std::vector<std::array<uint8_t, 3>> raw_data;
662 int res = syncReadConsecutiveBytes<uint8_t, 3>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, raw_data);
664 for (
auto const &data : raw_data)
667 auto voltage =
static_cast<double>((
static_cast<uint16_t
>(data.at(1)) << 8) | data.at(0));
670 uint8_t temperature = data.at(2);
672 data_list.emplace_back(std::make_pair(voltage, temperature));
684 template <
typename reg_type>
687 return syncRead<typename reg_type::TYPE_HW_ERROR_STATUS>(reg_type::ADDR_HW_ERROR_STATUS, id_list, hw_error_list);
700 template <
typename reg_type>
703 return write<typename reg_type::TYPE_LED>(reg_type::ADDR_LED,
id, led_value);
712 template <
typename reg_type>
715 return syncWrite<typename reg_type::TYPE_LED>(reg_type::ADDR_LED, id_list, led_list);
724 template <
typename reg_type>
727 return write<typename reg_type::TYPE_GOAL_TORQUE>(reg_type::ADDR_GOAL_TORQUE,
id, torque);
736 template <
typename reg_type>
739 return syncWrite<typename reg_type::TYPE_GOAL_TORQUE>(reg_type::ADDR_GOAL_TORQUE, id_list, torque_list);
750 template <
typename reg_type>
755 std::vector<std::array<typename reg_type::TYPE_PID_GAIN, 8>> raw_data;
758 for (
int tries = 10; tries > 0; --tries)
760 res = syncReadConsecutiveBytes<typename reg_type::TYPE_PID_GAIN, 8>(reg_type::ADDR_VELOCITY_I_GAIN, {
id}, raw_data);
761 if (COMM_SUCCESS == res)
766 if (COMM_SUCCESS == res && raw_data.size() == 1)
768 data_list.emplace_back(raw_data.at(0).at(4));
769 data_list.emplace_back(raw_data.at(0).at(3));
770 data_list.emplace_back(raw_data.at(0).at(2));
771 data_list.emplace_back(raw_data.at(0).at(1));
772 data_list.emplace_back(raw_data.at(0).at(0));
773 data_list.emplace_back(raw_data.at(0).at(7));
774 data_list.emplace_back(raw_data.at(0).at(6));
779 std::cout <<
"Failures during read PID gains: " << res << std::endl;
792 template <
typename reg_type>
795 return read<typename reg_type::TYPE_MOVING>(reg_type::ADDR_MOVING,
id, status);
804 template <
typename reg_type>
807 int res = COMM_TX_ERROR;
809 res = read<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE,
id, torque);
810 if (res == COMM_SUCCESS)
814 return write<typename reg_type::TYPE_OPERATING_MODE>(reg_type::ADDR_OPERATING_MODE,
id, control_mode);
826 template <
typename reg_type>
830 typename reg_type::TYPE_OPERATING_MODE raw{};
831 res = read<typename reg_type::TYPE_OPERATING_MODE>(reg_type::ADDR_OPERATING_MODE,
id, raw);
832 control_mode =
static_cast<uint8_t
>(raw);
843 template <
typename reg_type>
846 return read<typename reg_type::TYPE_PRESENT_LOAD>(reg_type::ADDR_PRESENT_LOAD,
id, present_load);
855 template <
typename reg_type>
858 return syncRead<typename reg_type::TYPE_PRESENT_LOAD>(reg_type::ADDR_PRESENT_LOAD, id_list, load_list);
867 template <
typename reg_type>
870 return read<typename reg_type::TYPE_PRESENT_VELOCITY>(reg_type::ADDR_PRESENT_VELOCITY,
id, present_velocity);
879 template <
typename reg_type>
882 return syncRead<typename reg_type::TYPE_PRESENT_VELOCITY>(reg_type::ADDR_PRESENT_VELOCITY, id_list, velocity_list);
891 template <
typename reg_type>
894 int res = COMM_TX_FAIL;
899 data_array_list.clear();
902 typename reg_type::TYPE_TORQUE_ENABLE torque{1};
903 res = read<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE, id_list.at(0), torque);
904 if (COMM_SUCCESS != res)
905 std::cout <<
"#############"
906 " ERROR reading dxl torque in syncReadJointStatus (error "
907 << res <<
")" << std::endl;
912 res = syncReadConsecutiveBytes<uint32_t, 2>(reg_type::ADDR_PRESENT_VELOCITY, id_list, data_array_list);
916 std::vector<uint32_t> position_list;
917 res = syncReadPosition(id_list, position_list);
918 for (
auto p : position_list)
919 data_array_list.emplace_back(std::array<uint32_t, 2>{0, p});
934 std::cout <<
"startup configuration for XL320 not available" << std::endl;
942 std::cout <<
"min position hardcoded for motor XL320" << std::endl;
950 std::cout <<
"max position hardcoded for motor XL320" << std::endl;
957 std::string hardware_message;
959 if (hw_state & 1 << 0)
961 hardware_message +=
"Overload";
963 if (hw_state & 1 << 1)
965 if (!hardware_message.empty())
966 hardware_message +=
", ";
967 hardware_message +=
"OverHeating";
969 if (hw_state & 1 << 2)
971 if (!hardware_message.empty())
972 hardware_message +=
", ";
973 hardware_message +=
"Input voltage out of range";
975 if (hw_state & 1 << 7)
977 if (!hardware_message.empty())
978 hardware_message +=
", ";
979 hardware_message +=
"Disconnection";
982 return hardware_message;
988 std::cout <<
"readVelocityProfile not available for XL320" << std::endl;
995 std::cout <<
"writeVelocityProfile not available for XL320" << std::endl;
1004 present_position = raw_data;
1011 position_list.clear();
1012 std::vector<typename XL320Reg::TYPE_PRESENT_POSITION> raw_data_list{};
1015 for (
auto p : raw_data_list)
1016 position_list.emplace_back(p);
1026 present_velocity = raw_data;
1034 std::vector<typename XL320Reg::TYPE_PRESENT_VELOCITY> raw_data_list;
1036 for (
auto v : raw_data_list)
1037 velocity_list.emplace_back(v);
1050 int res = COMM_TX_FAIL;
1052 if (id_list.empty())
1055 data_array_list.clear();
1057 std::vector<uint32_t> position_list;
1058 res = syncReadPosition(id_list, position_list);
1059 if (res == COMM_SUCCESS)
1061 for (
auto p : position_list)
1062 data_array_list.emplace_back(std::array<uint32_t, 2>{0, p});
1076 std::vector<std::pair<double, uint8_t>> &data_list)
1080 std::vector<std::array<uint8_t, 2>> raw_data;
1083 for (
auto const &data : raw_data)
1086 auto voltage =
static_cast<double>(data.at(0));
1089 uint8_t temperature = data.at(1);
1091 data_list.emplace_back(std::make_pair(voltage, temperature));
1106 int res = COMM_RX_FAIL;
1108 std::vector<std::array<typename XL320Reg::TYPE_PID_GAIN, 3>> raw_data;
1111 for (
int tries = 10; tries > 0; --tries)
1114 if (COMM_SUCCESS == res)
1119 if (COMM_SUCCESS == res && raw_data.size() == 1)
1121 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(2)));
1122 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(1)));
1123 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(0)));
1124 data_list.emplace_back(0);
1125 data_list.emplace_back(0);
1126 data_list.emplace_back(0);
1127 data_list.emplace_back(0);
1131 std::cout <<
"Failures during read PID gains: " << res << std::endl;
1132 return COMM_TX_FAIL;
1135 return COMM_SUCCESS;
1148 int res = COMM_TX_FAIL;
1151 for (
int tries = 10; tries > 0; --tries)
1155 if (COMM_SUCCESS == res)
1158 if (COMM_SUCCESS != res)
1161 for (
int tries = 10; tries > 0; --tries)
1165 if (COMM_SUCCESS == res)
1168 if (COMM_SUCCESS != res)
1171 for (
int tries = 10; tries > 0; --tries)
1175 if (COMM_SUCCESS == res)
1191 std::vector<typename XL320Reg::TYPE_GOAL_POSITION> casted_list;
1192 casted_list.reserve(position_list.size());
1193 for (
auto const &p : position_list)
1209 std::vector<typename XL320Reg::TYPE_GOAL_VELOCITY> casted_list;
1210 casted_list.reserve(velocity_list.size());
1211 for (
auto const &v : velocity_list)
1221 std::cout <<
"readControlMode not available for motor XL320" << std::endl;
1222 return COMM_SUCCESS;
1230 std::string hardware_message;
1232 if (hw_state & 1 << 0)
1234 hardware_message +=
"Input Voltage";
1236 if (hw_state & 1 << 2)
1238 if (!hardware_message.empty())
1239 hardware_message +=
", ";
1240 hardware_message +=
"OverHeating";
1242 if (hw_state & 1 << 3)
1244 if (!hardware_message.empty())
1245 hardware_message +=
", ";
1246 hardware_message +=
"Motor Encoder";
1248 if (hw_state & 1 << 4)
1250 if (!hardware_message.empty())
1251 hardware_message +=
", ";
1252 hardware_message +=
"Electrical Shock";
1254 if (hw_state & 1 << 5)
1256 if (!hardware_message.empty())
1257 hardware_message +=
", ";
1258 hardware_message +=
"Overload";
1260 if (hw_state & 1 << 7)
1262 if (!hardware_message.empty())
1263 hardware_message +=
", ";
1264 hardware_message +=
"Disconnection";
1266 if (!hardware_message.empty())
1267 hardware_message +=
" Error";
1269 return hardware_message;
1275 std::cout <<
"writeTorqueGoal not available for motor XL430" << std::endl;
1276 return COMM_TX_ERROR;
1282 std::cout <<
"syncWriteTorqueGoal not available for motor XL430" << std::endl;
1283 return COMM_TX_ERROR;
1291 std::string hardware_message;
1293 if (hw_state & 1 << 0)
1295 hardware_message +=
"Input Voltage";
1297 if (hw_state & 1 << 2)
1299 if (!hardware_message.empty())
1300 hardware_message +=
", ";
1301 hardware_message +=
"OverHeating";
1303 if (hw_state & 1 << 3)
1305 if (!hardware_message.empty())
1306 hardware_message +=
", ";
1307 hardware_message +=
"Motor Encoder";
1309 if (hw_state & 1 << 4)
1311 if (!hardware_message.empty())
1312 hardware_message +=
", ";
1313 hardware_message +=
"Electrical Shock";
1315 if (hw_state & 1 << 5)
1317 if (!hardware_message.empty())
1318 hardware_message +=
", ";
1319 hardware_message +=
"Overload";
1321 if (hw_state & 1 << 7)
1323 if (!hardware_message.empty())
1324 hardware_message +=
", ";
1325 hardware_message +=
"Disconnection";
1327 if (!hardware_message.empty())
1328 hardware_message +=
" Error";
1330 return hardware_message;
1336 std::cout <<
"writeTorqueGoal not available for motor XC430" << std::endl;
1337 return COMM_TX_ERROR;
1343 std::cout <<
"syncWriteTorqueGoal not available for motor XC430" << std::endl;
1344 return COMM_TX_ERROR;
1352 std::string hardware_message;
1354 if (hw_state & 1 << 0)
1356 hardware_message +=
"Input Voltage";
1358 if (hw_state & 1 << 2)
1360 if (!hardware_message.empty())
1361 hardware_message +=
", ";
1362 hardware_message +=
"OverHeating";
1364 if (hw_state & 1 << 3)
1366 if (!hardware_message.empty())
1367 hardware_message +=
", ";
1368 hardware_message +=
"Motor Encoder";
1370 if (hw_state & 1 << 4)
1372 if (!hardware_message.empty())
1373 hardware_message +=
", ";
1374 hardware_message +=
"Electrical Shock";
1376 if (hw_state & 1 << 5)
1378 if (!hardware_message.empty())
1379 hardware_message +=
", ";
1380 hardware_message +=
"Overload";
1382 if (hw_state & 1 << 7)
1384 if (!hardware_message.empty())
1385 hardware_message +=
", ";
1386 hardware_message +=
"Disconnection";
1388 if (!hardware_message.empty())
1389 hardware_message +=
" Error";
1391 return hardware_message;
1425 std::string hardware_message;
1427 if (hw_state & 1 << 0)
1429 hardware_message +=
"Input Voltage";
1431 if (hw_state & 1 << 2)
1433 if (!hardware_message.empty())
1434 hardware_message +=
", ";
1435 hardware_message +=
"OverHeating";
1437 if (hw_state & 1 << 3)
1439 if (!hardware_message.empty())
1440 hardware_message +=
", ";
1441 hardware_message +=
"Motor Encoder";
1443 if (hw_state & 1 << 4)
1445 if (!hardware_message.empty())
1446 hardware_message +=
", ";
1447 hardware_message +=
"Electrical Shock";
1449 if (hw_state & 1 << 5)
1451 if (!hardware_message.empty())
1452 hardware_message +=
", ";
1453 hardware_message +=
"Overload";
1455 if (hw_state & 1 << 7)
1457 if (!hardware_message.empty())
1458 hardware_message +=
", ";
1459 hardware_message +=
"Disconnection";
1461 if (!hardware_message.empty())
1462 hardware_message +=
" Error";
1464 return hardware_message;
1510 std::string hardware_message;
1512 if (hw_state & 1 << 0)
1514 hardware_message +=
"Input Voltage";
1516 if (hw_state & 1 << 2)
1518 if (!hardware_message.empty())
1519 hardware_message +=
", ";
1520 hardware_message +=
"OverHeating";
1522 if (hw_state & 1 << 3)
1524 if (!hardware_message.empty())
1525 hardware_message +=
", ";
1526 hardware_message +=
"Motor Encoder";
1528 if (hw_state & 1 << 4)
1530 if (!hardware_message.empty())
1531 hardware_message +=
", ";
1532 hardware_message +=
"Electrical Shock";
1534 if (hw_state & 1 << 5)
1536 if (!hardware_message.empty())
1537 hardware_message +=
", ";
1538 hardware_message +=
"Overload";
1540 if (hw_state & 1 << 7)
1542 if (!hardware_message.empty())
1543 hardware_message +=
", ";
1544 hardware_message +=
"Disconnection";
1546 if (!hardware_message.empty())
1547 hardware_message +=
" Error";
1549 return hardware_message;