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 int ping_result = getModelNumber(
id, model_number);
208 if (ping_result == COMM_SUCCESS)
210 if (model_number && model_number != reg_type::MODEL_NUMBER)
212 return PING_WRONG_MODEL_NUMBER;
225 template <
typename reg_type>
228 int res = COMM_RX_FAIL;
230 res = read<typename reg_type::TYPE_FIRMWARE_VERSION>(reg_type::ADDR_FIRMWARE_VERSION,
id, data);
231 version = interpretFirmwareVersion(data);
241 template <
typename reg_type>
245 int res = readFirmwareVersion(
id, version);
248 if (COMM_SUCCESS == res && std::stoi(version) >= reg_type::VERSION_STARTUP_CONFIGURATION)
250 res = write<typename reg_type::TYPE_STARTUP_CONFIGURATION>(reg_type::ADDR_STARTUP_CONFIGURATION,
id, config);
254 std::cout <<
"Startup configuration available only for version > " <<
static_cast<int>(reg_type::VERSION_STARTUP_CONFIGURATION) << std::endl;
267 template <
typename reg_type>
270 std::cout <<
"temperature limit not available for this motor type" << std::endl;
280 template <
typename reg_type>
283 std::cout <<
"shutdown configuration not available for this motor type" << std::endl;
293 template <
typename reg_type>
296 return read<typename reg_type::TYPE_MIN_POSITION_LIMIT>(reg_type::ADDR_MIN_POSITION_LIMIT,
id, pos);
305 template <
typename reg_type>
308 return read<typename reg_type::TYPE_MAX_POSITION_LIMIT>(reg_type::ADDR_MAX_POSITION_LIMIT,
id, pos);
320 template <
typename reg_type>
324 int res = COMM_RX_FAIL;
326 for (
int tries = 10; tries > 0; --tries)
328 res = write<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_VELOCITY,
id, data_list.at(0));
329 if (COMM_SUCCESS == res)
333 for (
int tries = 10; tries > 0; --tries)
335 res = write<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_ACCELERATION,
id, data_list.at(1));
336 if (COMM_SUCCESS == res)
340 if (COMM_SUCCESS != res)
352 template <
typename reg_type>
355 auto torque_enable = torque_percentage > 0 ? 1 : 0;
356 return write<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE,
id, torque_enable);
365 template <
typename reg_type>
368 return write<typename reg_type::TYPE_GOAL_POSITION>(reg_type::ADDR_GOAL_POSITION,
id,
369 static_cast<typename reg_type::TYPE_GOAL_POSITION
>(position));
378 template <
typename reg_type>
381 return write<typename reg_type::TYPE_GOAL_VELOCITY>(reg_type::ADDR_GOAL_VELOCITY,
id,
382 static_cast<typename reg_type::TYPE_GOAL_VELOCITY
>(velocity));
391 template <
typename reg_type>
394 std::vector<uint8_t> torque_enable_list;
395 for(
const auto &torque_percentage : torque_percentage_list)
397 auto torque_enable = torque_percentage > 0 ? 1 : 0;
398 torque_enable_list.push_back(torque_enable);
400 return syncWrite<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE, id_list, torque_enable_list);
409 template <
typename reg_type>
412 return syncWrite<typename reg_type::TYPE_GOAL_POSITION>(reg_type::ADDR_GOAL_POSITION, id_list, position_list);
421 template <
typename reg_type>
424 return syncWrite<typename reg_type::TYPE_GOAL_VELOCITY>(reg_type::ADDR_GOAL_VELOCITY, id_list, velocity_list);
428 template <
typename reg_type>
432 typename reg_type::TYPE_PROFILE velocity_profile{};
433 typename reg_type::TYPE_PROFILE acceleration_profile{};
435 int res = read<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_VELOCITY,
id, velocity_profile);
436 if (COMM_SUCCESS == res)
437 res = read<typename reg_type::TYPE_PROFILE>(reg_type::ADDR_PROFILE_ACCELERATION,
id, acceleration_profile);
439 data_list.emplace_back(velocity_profile);
440 data_list.emplace_back(acceleration_profile);
451 template <
typename reg_type>
454 return read<typename reg_type::TYPE_PRESENT_POSITION>(reg_type::ADDR_PRESENT_POSITION,
id, present_position);
463 template <
typename reg_type>
466 return read<typename reg_type::TYPE_PRESENT_TEMPERATURE>(reg_type::ADDR_PRESENT_TEMPERATURE,
id, temperature);
475 template <
typename reg_type>
478 typename reg_type::TYPE_PRESENT_VOLTAGE voltage_mV{};
479 int res = read<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE,
id, voltage_mV);
480 voltage =
static_cast<double>(voltage_mV) / reg_type::VOLTAGE_CONVERSION;
490 template <
typename reg_type>
493 return read<typename reg_type::TYPE_HW_ERROR_STATUS>(reg_type::ADDR_HW_ERROR_STATUS,
id, hardware_error_status);
502 template <
typename reg_type>
505 return syncRead<typename reg_type::TYPE_PRESENT_POSITION>(reg_type::ADDR_PRESENT_POSITION, id_list, position_list);
514 template <
typename reg_type>
517 int res = COMM_TX_FAIL;
520 for (
int tries = 10; tries > 0; --tries)
522 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_P_GAIN,
id, data.at(0));
523 if (COMM_SUCCESS == res)
527 if (COMM_SUCCESS != res)
530 for (
int tries = 10; tries > 0; --tries)
532 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_I_GAIN,
id, data.at(1));
533 if (COMM_SUCCESS == res)
536 if (COMM_SUCCESS != res)
539 for (
int tries = 10; tries > 0; --tries)
541 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_POSITION_D_GAIN,
id, data.at(2));
542 if (COMM_SUCCESS == res)
545 if (COMM_SUCCESS != res)
548 for (
int tries = 10; tries > 0; --tries)
550 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_VELOCITY_P_GAIN,
id, data.at(3));
551 if (COMM_SUCCESS == res)
554 if (COMM_SUCCESS != res)
557 for (
int tries = 10; tries > 0; --tries)
559 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_VELOCITY_I_GAIN,
id, data.at(4));
560 if (COMM_SUCCESS == res)
563 if (COMM_SUCCESS != res)
566 for (
int tries = 10; tries > 0; --tries)
568 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_FF1_GAIN,
id, data.at(5));
569 if (COMM_SUCCESS == res)
572 if (COMM_SUCCESS != res)
575 for (
int tries = 10; tries > 0; --tries)
577 res = write<typename reg_type::TYPE_PID_GAIN>(reg_type::ADDR_FF2_GAIN,
id, data.at(6));
578 if (res == COMM_SUCCESS)
591 template <
typename reg_type>
594 int res = COMM_RX_FAIL;
595 std::vector<uint8_t> data_list;
596 res = syncRead<typename reg_type::TYPE_FIRMWARE_VERSION>(reg_type::ADDR_FIRMWARE_VERSION, id_list, data_list);
597 for (
auto const &data : data_list)
598 firmware_list.emplace_back(interpretFirmwareVersion(data));
608 template <
typename reg_type>
611 return syncRead<typename reg_type::TYPE_PRESENT_TEMPERATURE>(reg_type::ADDR_PRESENT_TEMPERATURE, id_list, temperature_list);
620 template <
typename reg_type>
623 voltage_list.clear();
624 std::vector<typename reg_type::TYPE_PRESENT_VOLTAGE> v_read;
625 int res = syncRead<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, v_read);
626 for (
auto const &v : v_read)
627 voltage_list.emplace_back(
static_cast<double>(v) / reg_type::VOLTAGE_CONVERSION);
637 template <
typename reg_type>
640 voltage_list.clear();
641 std::vector<typename reg_type::TYPE_PRESENT_VOLTAGE> v_read;
642 int res = syncRead<typename reg_type::TYPE_PRESENT_VOLTAGE>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, v_read);
643 for (
auto const &v : v_read)
644 voltage_list.emplace_back(
static_cast<double>(v));
654 template <
typename reg_type>
656 std::vector<std::pair<double, uint8_t>> &data_list)
660 std::vector<std::array<uint8_t, 3>> raw_data;
661 int res = syncReadConsecutiveBytes<uint8_t, 3>(reg_type::ADDR_PRESENT_VOLTAGE, id_list, raw_data);
663 for (
auto const &data : raw_data)
666 auto voltage =
static_cast<double>((
static_cast<uint16_t
>(data.at(1)) << 8) | data.at(0));
669 uint8_t temperature = data.at(2);
671 data_list.emplace_back(std::make_pair(voltage, temperature));
683 template <
typename reg_type>
686 return syncRead<typename reg_type::TYPE_HW_ERROR_STATUS>(reg_type::ADDR_HW_ERROR_STATUS, id_list, hw_error_list);
699 template <
typename reg_type>
702 return write<typename reg_type::TYPE_LED>(reg_type::ADDR_LED,
id, led_value);
711 template <
typename reg_type>
714 return syncWrite<typename reg_type::TYPE_LED>(reg_type::ADDR_LED, id_list, led_list);
723 template <
typename reg_type>
726 return write<typename reg_type::TYPE_GOAL_TORQUE>(reg_type::ADDR_GOAL_TORQUE,
id, torque);
735 template <
typename reg_type>
738 return syncWrite<typename reg_type::TYPE_GOAL_TORQUE>(reg_type::ADDR_GOAL_TORQUE, id_list, torque_list);
749 template <
typename reg_type>
754 std::vector<std::array<typename reg_type::TYPE_PID_GAIN, 8>> raw_data;
757 for (
int tries = 10; tries > 0; --tries)
759 res = syncReadConsecutiveBytes<typename reg_type::TYPE_PID_GAIN, 8>(reg_type::ADDR_VELOCITY_I_GAIN, {
id}, raw_data);
760 if (COMM_SUCCESS == res)
765 if (COMM_SUCCESS == res && raw_data.size() == 1)
767 data_list.emplace_back(raw_data.at(0).at(4));
768 data_list.emplace_back(raw_data.at(0).at(3));
769 data_list.emplace_back(raw_data.at(0).at(2));
770 data_list.emplace_back(raw_data.at(0).at(1));
771 data_list.emplace_back(raw_data.at(0).at(0));
772 data_list.emplace_back(raw_data.at(0).at(7));
773 data_list.emplace_back(raw_data.at(0).at(6));
778 std::cout <<
"Failures during read PID gains: " << res << std::endl;
791 template <
typename reg_type>
794 return read<typename reg_type::TYPE_MOVING>(reg_type::ADDR_MOVING,
id, status);
803 template <
typename reg_type>
806 int res = COMM_TX_ERROR;
808 res = read<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE,
id, torque);
809 if (res == COMM_SUCCESS)
813 return write<typename reg_type::TYPE_OPERATING_MODE>(reg_type::ADDR_OPERATING_MODE,
id, control_mode);
825 template <
typename reg_type>
829 typename reg_type::TYPE_OPERATING_MODE raw{};
830 res = read<typename reg_type::TYPE_OPERATING_MODE>(reg_type::ADDR_OPERATING_MODE,
id, raw);
831 control_mode =
static_cast<uint8_t
>(raw);
842 template <
typename reg_type>
845 return read<typename reg_type::TYPE_PRESENT_LOAD>(reg_type::ADDR_PRESENT_LOAD,
id, present_load);
854 template <
typename reg_type>
857 return syncRead<typename reg_type::TYPE_PRESENT_LOAD>(reg_type::ADDR_PRESENT_LOAD, id_list, load_list);
866 template <
typename reg_type>
869 return read<typename reg_type::TYPE_PRESENT_VELOCITY>(reg_type::ADDR_PRESENT_VELOCITY,
id, present_velocity);
878 template <
typename reg_type>
881 return syncRead<typename reg_type::TYPE_PRESENT_VELOCITY>(reg_type::ADDR_PRESENT_VELOCITY, id_list, velocity_list);
890 template <
typename reg_type>
893 int res = COMM_TX_FAIL;
898 data_array_list.clear();
901 typename reg_type::TYPE_TORQUE_ENABLE torque{1};
902 res = read<typename reg_type::TYPE_TORQUE_ENABLE>(reg_type::ADDR_TORQUE_ENABLE, id_list.at(0), torque);
903 if (COMM_SUCCESS != res)
904 std::cout <<
"#############"
905 " ERROR reading dxl torque in syncReadJointStatus (error "
906 << res <<
")" << std::endl;
911 res = syncReadConsecutiveBytes<uint32_t, 2>(reg_type::ADDR_PRESENT_VELOCITY, id_list, data_array_list);
915 std::vector<uint32_t> position_list;
916 res = syncReadPosition(id_list, position_list);
917 for (
auto p : position_list)
918 data_array_list.emplace_back(std::array<uint32_t, 2>{0, p});
933 std::cout <<
"startup configuration for XL320 not available" << std::endl;
941 std::cout <<
"min position hardcoded for motor XL320" << std::endl;
949 std::cout <<
"max position hardcoded for motor XL320" << std::endl;
956 std::string hardware_message;
958 if (hw_state & 1 << 0)
960 hardware_message +=
"Overload";
962 if (hw_state & 1 << 1)
964 if (!hardware_message.empty())
965 hardware_message +=
", ";
966 hardware_message +=
"OverHeating";
968 if (hw_state & 1 << 2)
970 if (!hardware_message.empty())
971 hardware_message +=
", ";
972 hardware_message +=
"Input voltage out of range";
974 if (hw_state & 1 << 7)
976 if (!hardware_message.empty())
977 hardware_message +=
", ";
978 hardware_message +=
"Disconnection";
981 return hardware_message;
987 std::cout <<
"readVelocityProfile not available for XL320" << std::endl;
994 std::cout <<
"writeVelocityProfile not available for XL320" << std::endl;
1003 present_position = raw_data;
1010 position_list.clear();
1011 std::vector<typename XL320Reg::TYPE_PRESENT_POSITION> raw_data_list{};
1014 for (
auto p : raw_data_list)
1015 position_list.emplace_back(p);
1025 present_velocity = raw_data;
1033 std::vector<typename XL320Reg::TYPE_PRESENT_VELOCITY> raw_data_list;
1035 for (
auto v : raw_data_list)
1036 velocity_list.emplace_back(v);
1049 int res = COMM_TX_FAIL;
1051 if (id_list.empty())
1054 data_array_list.clear();
1056 std::vector<uint32_t> position_list;
1057 res = syncReadPosition(id_list, position_list);
1058 if (res == COMM_SUCCESS)
1060 for (
auto p : position_list)
1061 data_array_list.emplace_back(std::array<uint32_t, 2>{0, p});
1075 std::vector<std::pair<double, uint8_t>> &data_list)
1079 std::vector<std::array<uint8_t, 2>> raw_data;
1082 for (
auto const &data : raw_data)
1085 auto voltage =
static_cast<double>(data.at(0));
1088 uint8_t temperature = data.at(1);
1090 data_list.emplace_back(std::make_pair(voltage, temperature));
1105 int res = COMM_RX_FAIL;
1107 std::vector<std::array<typename XL320Reg::TYPE_PID_GAIN, 3>> raw_data;
1110 for (
int tries = 10; tries > 0; --tries)
1113 if (COMM_SUCCESS == res)
1118 if (COMM_SUCCESS == res && raw_data.size() == 1)
1120 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(2)));
1121 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(1)));
1122 data_list.emplace_back(
static_cast<uint16_t
>(raw_data.at(0).at(0)));
1123 data_list.emplace_back(0);
1124 data_list.emplace_back(0);
1125 data_list.emplace_back(0);
1126 data_list.emplace_back(0);
1130 std::cout <<
"Failures during read PID gains: " << res << std::endl;
1131 return COMM_TX_FAIL;
1134 return COMM_SUCCESS;
1147 int res = COMM_TX_FAIL;
1150 for (
int tries = 10; tries > 0; --tries)
1154 if (COMM_SUCCESS == res)
1157 if (COMM_SUCCESS != res)
1160 for (
int tries = 10; tries > 0; --tries)
1164 if (COMM_SUCCESS == res)
1167 if (COMM_SUCCESS != res)
1170 for (
int tries = 10; tries > 0; --tries)
1174 if (COMM_SUCCESS == res)
1190 std::vector<typename XL320Reg::TYPE_GOAL_POSITION> casted_list;
1191 casted_list.reserve(position_list.size());
1192 for (
auto const &p : position_list)
1208 std::vector<typename XL320Reg::TYPE_GOAL_VELOCITY> casted_list;
1209 casted_list.reserve(velocity_list.size());
1210 for (
auto const &v : velocity_list)
1220 std::cout <<
"readControlMode not available for motor XL320" << std::endl;
1221 return COMM_SUCCESS;
1229 std::string hardware_message;
1231 if (hw_state & 1 << 0)
1233 hardware_message +=
"Input Voltage";
1235 if (hw_state & 1 << 2)
1237 if (!hardware_message.empty())
1238 hardware_message +=
", ";
1239 hardware_message +=
"OverHeating";
1241 if (hw_state & 1 << 3)
1243 if (!hardware_message.empty())
1244 hardware_message +=
", ";
1245 hardware_message +=
"Motor Encoder";
1247 if (hw_state & 1 << 4)
1249 if (!hardware_message.empty())
1250 hardware_message +=
", ";
1251 hardware_message +=
"Electrical Shock";
1253 if (hw_state & 1 << 5)
1255 if (!hardware_message.empty())
1256 hardware_message +=
", ";
1257 hardware_message +=
"Overload";
1259 if (hw_state & 1 << 7)
1261 if (!hardware_message.empty())
1262 hardware_message +=
", ";
1263 hardware_message +=
"Disconnection";
1265 if (!hardware_message.empty())
1266 hardware_message +=
" Error";
1268 return hardware_message;
1274 std::cout <<
"writeTorqueGoal not available for motor XL430" << std::endl;
1275 return COMM_TX_ERROR;
1281 std::cout <<
"syncWriteTorqueGoal not available for motor XL430" << std::endl;
1282 return COMM_TX_ERROR;
1290 std::string hardware_message;
1292 if (hw_state & 1 << 0)
1294 hardware_message +=
"Input Voltage";
1296 if (hw_state & 1 << 2)
1298 if (!hardware_message.empty())
1299 hardware_message +=
", ";
1300 hardware_message +=
"OverHeating";
1302 if (hw_state & 1 << 3)
1304 if (!hardware_message.empty())
1305 hardware_message +=
", ";
1306 hardware_message +=
"Motor Encoder";
1308 if (hw_state & 1 << 4)
1310 if (!hardware_message.empty())
1311 hardware_message +=
", ";
1312 hardware_message +=
"Electrical Shock";
1314 if (hw_state & 1 << 5)
1316 if (!hardware_message.empty())
1317 hardware_message +=
", ";
1318 hardware_message +=
"Overload";
1320 if (hw_state & 1 << 7)
1322 if (!hardware_message.empty())
1323 hardware_message +=
", ";
1324 hardware_message +=
"Disconnection";
1326 if (!hardware_message.empty())
1327 hardware_message +=
" Error";
1329 return hardware_message;
1335 std::cout <<
"writeTorqueGoal not available for motor XC430" << std::endl;
1336 return COMM_TX_ERROR;
1342 std::cout <<
"syncWriteTorqueGoal not available for motor XC430" << std::endl;
1343 return COMM_TX_ERROR;
1351 std::string hardware_message;
1353 if (hw_state & 1 << 0)
1355 hardware_message +=
"Input Voltage";
1357 if (hw_state & 1 << 2)
1359 if (!hardware_message.empty())
1360 hardware_message +=
", ";
1361 hardware_message +=
"OverHeating";
1363 if (hw_state & 1 << 3)
1365 if (!hardware_message.empty())
1366 hardware_message +=
", ";
1367 hardware_message +=
"Motor Encoder";
1369 if (hw_state & 1 << 4)
1371 if (!hardware_message.empty())
1372 hardware_message +=
", ";
1373 hardware_message +=
"Electrical Shock";
1375 if (hw_state & 1 << 5)
1377 if (!hardware_message.empty())
1378 hardware_message +=
", ";
1379 hardware_message +=
"Overload";
1381 if (hw_state & 1 << 7)
1383 if (!hardware_message.empty())
1384 hardware_message +=
", ";
1385 hardware_message +=
"Disconnection";
1387 if (!hardware_message.empty())
1388 hardware_message +=
" Error";
1390 return hardware_message;
1424 std::string hardware_message;
1426 if (hw_state & 1 << 0)
1428 hardware_message +=
"Input Voltage";
1430 if (hw_state & 1 << 2)
1432 if (!hardware_message.empty())
1433 hardware_message +=
", ";
1434 hardware_message +=
"OverHeating";
1436 if (hw_state & 1 << 3)
1438 if (!hardware_message.empty())
1439 hardware_message +=
", ";
1440 hardware_message +=
"Motor Encoder";
1442 if (hw_state & 1 << 4)
1444 if (!hardware_message.empty())
1445 hardware_message +=
", ";
1446 hardware_message +=
"Electrical Shock";
1448 if (hw_state & 1 << 5)
1450 if (!hardware_message.empty())
1451 hardware_message +=
", ";
1452 hardware_message +=
"Overload";
1454 if (hw_state & 1 << 7)
1456 if (!hardware_message.empty())
1457 hardware_message +=
", ";
1458 hardware_message +=
"Disconnection";
1460 if (!hardware_message.empty())
1461 hardware_message +=
" Error";
1463 return hardware_message;
1509 std::string hardware_message;
1511 if (hw_state & 1 << 0)
1513 hardware_message +=
"Input Voltage";
1515 if (hw_state & 1 << 2)
1517 if (!hardware_message.empty())
1518 hardware_message +=
", ";
1519 hardware_message +=
"OverHeating";
1521 if (hw_state & 1 << 3)
1523 if (!hardware_message.empty())
1524 hardware_message +=
", ";
1525 hardware_message +=
"Motor Encoder";
1527 if (hw_state & 1 << 4)
1529 if (!hardware_message.empty())
1530 hardware_message +=
", ";
1531 hardware_message +=
"Electrical Shock";
1533 if (hw_state & 1 << 5)
1535 if (!hardware_message.empty())
1536 hardware_message +=
", ";
1537 hardware_message +=
"Overload";
1539 if (hw_state & 1 << 7)
1541 if (!hardware_message.empty())
1542 hardware_message +=
", ";
1543 hardware_message +=
"Disconnection";
1545 if (!hardware_message.empty())
1546 hardware_message +=
" Error";
1548 return hardware_message;