Skip to content

Commit 49a8b09

Browse files
authored
Merge pull request #85 from ROBOTIS-GIT/feature-hardware-error-handling
Hardware error handling for Dynamixel Y series
2 parents 6c89f47 + cc00798 commit 49a8b09

File tree

5 files changed

+158
-89
lines changed

5 files changed

+158
-89
lines changed

CHANGELOG.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22
Changelog for package dynamixel_hardware_interface
33
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
44

5+
1.4.15 (2025-09-17)
6+
-------------------
7+
* Added support for hardware error handling for Dynamixel Y series
8+
* Contributors: Woojin Wie
9+
510
1.4.14 (2025-09-03)
611
-------------------
712
* Added Current units to YM070-210-*099 and YM080-230-*099 model files

include/dynamixel_hardware_interface/dynamixel/dynamixel.hpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,80 @@ enum DxlError
7171
DXL_REBOOT_FAIL = -17 ///< Reboot failed.
7272
};
7373

74+
// Hardware Error Status bit definitions
75+
struct HardwareErrorStatusBitInfo
76+
{
77+
int bit;
78+
const char * label;
79+
const char * description;
80+
};
81+
82+
static constexpr HardwareErrorStatusBitInfo HardwareErrorStatusTable[] = {
83+
{0, "Input Voltage Error", "Detects that input voltage exceeds the configured operating voltage"},
84+
{1, "Motor Hall Sensor Error", "Detects that Motor hall sensor value exceeds normal range"},
85+
{2, "Overheating Error",
86+
"Detects that internal temperature exceeds the configured operating temperature"},
87+
{3, "Motor Encoder Error", "Detects malfunction of the motor encoder"},
88+
{4,
89+
"Electrical Shock Error",
90+
"Detects electric shock on the circuit or insufficient power to operate the motor"},
91+
{5, "Overload Error", "Detects that persistent load exceeds maximum output"},
92+
{6, "Not used", "Always 0"},
93+
{7, "Not used", "Always 0"}
94+
};
95+
96+
inline const HardwareErrorStatusBitInfo * get_hardware_error_status_bit_info(int bit)
97+
{
98+
for (const auto & entry : HardwareErrorStatusTable) {
99+
if (entry.bit == bit) {return &entry;}
100+
}
101+
return nullptr;
102+
}
103+
104+
// Error Code (153) definitions
105+
struct ErrorCodeInfo
106+
{
107+
int value;
108+
const char * label;
109+
const char * description;
110+
};
111+
112+
static constexpr ErrorCodeInfo ErrorCodeTable[] = {
113+
{0x00, "No Error", "No error"},
114+
{0x01, "Over Voltage Error", "Device supply voltage exceeds the Max Voltage Limit(60)"},
115+
{0x02, "Low Voltage Error", "Device supply voltage exceeds the Min Voltage Limit(62)"},
116+
{0x03,
117+
"Inverter Overheating Error",
118+
"The inverter temperature has exceeded the Inverter Temperature Limit(56)"},
119+
{0x04,
120+
"Motor Overheating Error",
121+
"The motor temperature has exceeded the Motor Temperature Limit(57)"},
122+
{0x05, "Overload Error", "Operating current exceeding rated current for an extended duration"},
123+
{0x07, "Inverter Error", "An issue has occurred with the inverter"},
124+
{0x09, "Battery Warning", "Low Multi-turn battery voltage. Replacement recommended"},
125+
{0x0A, "Battery Error", "Multi-turn battery voltage is too low, causing issues"},
126+
{0x0B, "Magnet Error", "Multi-turn position lost. Multi-turn reset required"},
127+
{0x0C, "Multi-turn Error", "An issue has occurred with the Multi-turn IC"},
128+
{0x0D, "Encoder Error", "An issue has occurred with the Encoder IC"},
129+
{0x0E, "Hall Sensor Error", "An issue has occurred with the Hall Sensor"},
130+
{0x0F, "Calibration Error", "Cannot find calibration Data"},
131+
{0x11, "Following Error", "Position control error exceeds the Following Error Threshold(44)"},
132+
{0x12, "Bus Watchdog Error", "An issue has occurred with the Bus Watchdog"},
133+
{0x13, "Over Speed Error", "Rotates at a speed of 120% or more than the Velocity Limit(72)"},
134+
{0x14,
135+
"Position Limit Reached Error",
136+
"In position control mode, the current position has moved beyond the Max/Min Position Limit"
137+
" + Position Limit Threshold(38) range."}
138+
};
139+
140+
inline const ErrorCodeInfo * get_error_code_info(int value)
141+
{
142+
for (const auto & entry : ErrorCodeTable) {
143+
if (entry.value == value) {return &entry;}
144+
}
145+
return nullptr;
146+
}
147+
74148
/**
75149
* @struct IndirectInfo
76150
* @brief Structure for storing indirect addressing information for Dynamixel motors.

include/dynamixel_hardware_interface/dynamixel_hardware_interface.hpp

Lines changed: 0 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -49,81 +49,6 @@
4949

5050
namespace dynamixel_hardware_interface
5151
{
52-
53-
// Hardware Error Status bit definitions
54-
struct HardwareErrorStatusBitInfo
55-
{
56-
int bit;
57-
const char * label;
58-
const char * description;
59-
};
60-
61-
static constexpr HardwareErrorStatusBitInfo HardwareErrorStatusTable[] = {
62-
{0, "Input Voltage Error", "Detects that input voltage exceeds the configured operating voltage"},
63-
{1, "Motor Hall Sensor Error", "Detects that Motor hall sensor value exceeds normal range"},
64-
{2, "Overheating Error",
65-
"Detects that internal temperature exceeds the configured operating temperature"},
66-
{3, "Motor Encoder Error", "Detects malfunction of the motor encoder"},
67-
{4,
68-
"Electrical Shock Error",
69-
"Detects electric shock on the circuit or insufficient power to operate the motor"},
70-
{5, "Overload Error", "Detects that persistent load exceeds maximum output"},
71-
{6, "Not used", "Always 0"},
72-
{7, "Not used", "Always 0"}
73-
};
74-
75-
inline const HardwareErrorStatusBitInfo * get_hardware_error_status_bit_info(int bit)
76-
{
77-
for (const auto & entry : HardwareErrorStatusTable) {
78-
if (entry.bit == bit) {return &entry;}
79-
}
80-
return nullptr;
81-
}
82-
83-
// Error Code (153) definitions
84-
struct ErrorCodeInfo
85-
{
86-
int value;
87-
const char * label;
88-
const char * description;
89-
};
90-
91-
static constexpr ErrorCodeInfo ErrorCodeTable[] = {
92-
{0x00, "No Error", "No error"},
93-
{0x01, "Over Voltage Error", "Device supply voltage exceeds the Max Voltage Limit(60)"},
94-
{0x02, "Low Voltage Error", "Device supply voltage exceeds the Min Voltage Limit(62)"},
95-
{0x03,
96-
"Inverter Overheating Error",
97-
"The inverter temperature has exceeded the Inverter Temperature Limit(56)"},
98-
{0x04,
99-
"Motor Overheating Error",
100-
"The motor temperature has exceeded the Motor Temperature Limit(57)"},
101-
{0x05, "Overload Error", "Operating current exceeding rated current for an extended duration"},
102-
{0x07, "Inverter Error", "An issue has occurred with the inverter"},
103-
{0x09, "Battery Warning", "Low Multi-turn battery voltage. Replacement recommended"},
104-
{0x0A, "Battery Error", "Multi-turn battery voltage is too low, causing issues"},
105-
{0x0B, "Magnet Error", "Multi-turn position lost. Multi-turn reset required"},
106-
{0x0C, "Multi-turn Error", "An issue has occurred with the Multi-turn IC"},
107-
{0x0D, "Encoder Error", "An issue has occurred with the Encoder IC"},
108-
{0x0E, "Hall Sensor Error", "An issue has occurred with the Hall Sensor"},
109-
{0x0F, "Calibration Error", "Cannot find calibration Data"},
110-
{0x11, "Following Error", "Position control error exceeds the Following Error Threshold(44)"},
111-
{0x12, "Bus Watchdog Error", "An issue has occurred with the Bus Watchdog"},
112-
{0x13, "Over Speed Error", "Rotates at a speed of 120% or more than the Velocity Limit(72)"},
113-
{0x14,
114-
"Position Limit Reached Error",
115-
"In position control mode, the current position has moved beyond the Max/Min Position Limit"
116-
" + Position Limit Threshold(38) range."}
117-
};
118-
119-
inline const ErrorCodeInfo * get_error_code_info(int value)
120-
{
121-
for (const auto & entry : ErrorCodeTable) {
122-
if (entry.value == value) {return &entry;}
123-
}
124-
return nullptr;
125-
}
126-
12752
/**
12853
* @brief Constants for hardware state interface names.
12954
*/

package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
33
<package format="3">
44
<name>dynamixel_hardware_interface</name>
5-
<version>1.4.14</version>
5+
<version>1.4.15</version>
66
<description>
77
ROS 2 package providing a hardware interface for controlling Dynamixel motors via the ROS 2 control framework.
88
</description>

src/dynamixel/dynamixel.cpp

Lines changed: 78 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,76 @@ DxlError Dynamixel::InitDxlComm(
199199
if (dxl_comm_result != COMM_SUCCESS) {
200200
fprintf(stderr, " - COMM_ERROR : %s\n", packet_handler_->getTxRxResult(dxl_comm_result));
201201
return DxlError::CANNOT_FIND_CONTROL_ITEM;
202-
} else if (dxl_error != 0) {
202+
}
203+
204+
// First, read the model file to get the control table structure
205+
try {
206+
dxl_info_.ReadDxlModelFile(it_id, dxl_model_number);
207+
} catch (const std::exception & e) {
208+
fprintf(stderr, "[InitDxlComm][ID:%03d] Error reading model file: %s\n", it_id, e.what());
209+
return DxlError::CANNOT_FIND_CONTROL_ITEM;
210+
}
211+
212+
if (dxl_error != 0) {
203213
fprintf(stderr, " - RX_PACKET_ERROR : %s\n", packet_handler_->getRxPacketError(dxl_error));
204-
uint32_t err = 0;
205-
if (ReadItem(it_id, "Hardware Error Status", err) == DxlError::OK) {
206-
fprintf(stderr, "[ID:%03d] Read Hardware Error Status : %x\n", it_id, err);
214+
215+
// Check if Hardware Error Status control item exists
216+
uint16_t hw_error_addr, error_code_addr;
217+
uint8_t hw_error_size, error_code_size;
218+
bool hw_error_exists = dxl_info_.GetDxlControlItem(
219+
it_id, "Hardware Error Status", hw_error_addr, hw_error_size);
220+
bool error_code_exists = dxl_info_.GetDxlControlItem(
221+
it_id, "Error Code", error_code_addr, error_code_size);
222+
223+
if (hw_error_exists) {
224+
uint32_t hw_error_status = 0;
225+
ReadItem(it_id, "Hardware Error Status", hw_error_status);
226+
227+
std::string error_string = "";
228+
uint8_t hw_error_byte = static_cast<uint8_t>(hw_error_status);
229+
230+
for (int bit = 0; bit < 8; ++bit) {
231+
if (hw_error_byte & (1 << bit)) {
232+
const HardwareErrorStatusBitInfo * bit_info = get_hardware_error_status_bit_info(bit);
233+
if (bit_info) {
234+
error_string += bit_info->label;
235+
error_string += " (" + std::string(bit_info->description) + ")/ ";
236+
} else {
237+
error_string += "Unknown Error Bit " + std::to_string(bit) + "/ ";
238+
}
239+
}
240+
}
241+
242+
if (!error_string.empty()) {
243+
fprintf(
244+
stderr, "[ID:%03d] Hardware Error Details: 0x%x (%d): %s\n",
245+
it_id, hw_error_byte, hw_error_byte, error_string.c_str());
246+
}
247+
} else if (error_code_exists) {
248+
uint32_t error_code = 0;
249+
ReadItem(it_id, "Error Code", error_code);
250+
251+
uint8_t error_code_byte = static_cast<uint8_t>(error_code);
252+
if (error_code_byte != 0x00) {
253+
const ErrorCodeInfo * error_info = get_error_code_info(error_code_byte);
254+
if (error_info) {
255+
fprintf(
256+
stderr, "[ID:%03d] Error Code Details: 0x%x (%s): %s\n",
257+
it_id, error_code_byte, error_info->label, error_info->description);
258+
} else {
259+
fprintf(
260+
stderr, "[ID:%03d] Error Code Details: 0x%x (Unknown Error Code)\n",
261+
it_id, error_code_byte);
262+
}
263+
}
264+
} else {
265+
fprintf(
266+
stderr,
267+
"[ID:%03d] Neither Hardware Error Status nor Error Code control items available.\n",
268+
it_id
269+
);
207270
}
208-
fprintf(stderr, "[ID:%03d] Hardware Error detected, rebooting...\n", it_id);
271+
209272
Reboot(it_id);
210273
return DxlError::DXL_HARDWARE_ERROR;
211274
} else {
@@ -215,14 +278,6 @@ DxlError Dynamixel::InitDxlComm(
215278
model_name.c_str());
216279
}
217280

218-
// First, read the model file to get the control table structure
219-
try {
220-
dxl_info_.ReadDxlModelFile(it_id, dxl_model_number);
221-
} catch (const std::exception & e) {
222-
fprintf(stderr, "[InitDxlComm][ID:%03d] Error reading model file: %s\n", it_id, e.what());
223-
return DxlError::CANNOT_FIND_CONTROL_ITEM;
224-
}
225-
226281
// Read firmware version and reload model file with firmware-specific version if available
227282
uint8_t firmware_version = 0;
228283
DxlError fw_result = ReadFirmwareVersion(it_id, firmware_version);
@@ -725,6 +780,16 @@ DxlError Dynamixel::ReadItem(uint8_t id, std::string item_name, uint32_t & data)
725780
return DxlError::ITEM_READ_FAIL;
726781
}
727782
} else if (dxl_error != 0) {
783+
bool is_alert = dxl_error & 0x80;
784+
if (is_alert) {
785+
fprintf(
786+
stderr,
787+
"[ReadItem][ID:%03d][comm_id:%03d] RX_PACKET_ERROR : %s\n",
788+
id,
789+
comm_id,
790+
packet_handler_->getRxPacketError(dxl_error));
791+
return DxlError::OK;
792+
}
728793
fprintf(
729794
stderr,
730795
"[ReadItem][ID:%03d][comm_id:%03d] RX_PACKET_ERROR : %s (retry %d/%d)\n",

0 commit comments

Comments
 (0)