Fault Handling
Fault detection and clearing for the L20 dexterous hand.
Overview
Use hand.fault to access fault-related functionality:
- Read fault status in blocking or cached mode
- Clear faults on all joints
Fault Code Table
L20 represents fault states with bit flags. Each joint motor can report multiple faults at the same time.
| Fault code | Value | Description |
|---|---|---|
NONE | 0 | No fault |
MOTOR_ROTOR_LOCK | 1 | Motor rotor lock |
MOTOR_OVER_CURRENT | 2 | Motor overcurrent |
MOTOR_STALL_FAULT | 4 | Motor stall fault |
VOLTAGE_ABNORMAL | 8 | Voltage abnormality |
SELF_CHECK_ABNORMAL | 16 | Self-check abnormality |
OVER_TEMPERATURE | 32 | Overtemperature |
SOFT_ROTOR_LOCK | 64 | Software rotor lock |
MOTOR_COMM_ABNORMAL | 128 | Motor communication abnormality |
Read Faults
Blocking Read
from realhand.exceptions import TimeoutError
try:
data = hand.fault.get_blocking(timeout_ms=500)
except TimeoutError:
print("Read timed out")
Parameter:
timeout_ms: Timeout in milliseconds, default100
Return value: FaultData, containing:
faults:L20Faultfault datatimestamp: Timestamp
Exception:
TimeoutError: No response before timeout
Cached Read
data = hand.fault.get_snapshot()
if data:
print(f"Has fault: {data.faults.has_any_fault()}")
Returns the latest cached fault data, or None if no data is available.
Clear Faults
hand.fault.clear_faults()
Sends a fire-and-forget command to clear faults on all joints, without waiting for a response.
Streaming Read
Receive all sensor events through the top-level hand.stream() interface:
from realhand.hand.l20 import SensorSource, FaultEvent
hand.start_polling({SensorSource.FAULT: 0.2})
try:
for event in hand.stream():
match event:
case FaultEvent(data=data):
if data.faults.has_any_fault():
for code in data.faults.to_list():
if code.has_fault():
print(code.get_fault_names())
finally:
hand.stop_polling()
hand.stop_stream()
Data Class Reference
L20Fault fields
| Field | Description |
|---|---|
thumb_abd | Thumb abduction |
thumb_yaw | Thumb rotation |
thumb_root1 | Thumb root |
thumb_tip | Thumb tip |
index_abd | Index abduction |
index_root1 | Index root |
index_tip | Index tip |
middle_abd | Middle abduction |
middle_root1 | Middle root |
middle_tip | Middle tip |
ring_abd | Ring abduction |
ring_root1 | Ring root |
ring_tip | Ring tip |
pinky_abd | Pinky abduction |
pinky_root1 | Pinky root |
pinky_tip | Pinky tip |
L20Fault methods
# Check whether any fault exists
faults.has_any_fault() # -> bool
# Convert to a list
faults.to_list() # -> list[L20FaultCode]
# Index access
faults[0] # thumb_abd
L20FaultCode methods
# Check whether a single joint motor has a fault
faults.thumb_abd.has_fault() # -> bool
# Get the list of fault names
faults.thumb_abd.get_fault_names() # -> list[str]
Examples
Check Fault Status
from realhand import L20
with L20(side="left", interface_name="can0") as hand:
# Read fault status
data = hand.fault.get_blocking(timeout_ms=500)
if data.faults.has_any_fault():
print("Fault detected:")
if data.faults.thumb_abd.has_fault():
print(f" Thumb abduction: {data.faults.thumb_abd.get_fault_names()}")
if data.faults.index_abd.has_fault():
print(f" Index abduction: {data.faults.index_abd.get_fault_names()}")
else:
print("No faults")
# Clear all faults
hand.fault.clear_faults()
Continuous Monitoring
from realhand import L20
from realhand.hand.l20 import SensorSource, FaultEvent
with L20(side="left", interface_name="can0") as hand:
hand.start_polling({SensorSource.FAULT: 0.2})
try:
for event in hand.stream():
match event:
case FaultEvent(data=data):
if data.faults.has_any_fault():
for i, code in enumerate(data.faults.to_list()):
if code.has_fault():
print(f"Joint {i} fault: {code.get_fault_names()}")
except KeyboardInterrupt:
pass
finally:
hand.stop_polling()
hand.stop_stream()