Implement read
This commit is contained in:
parent
034171a89a
commit
42a87e7211
|
@ -116,6 +116,9 @@ class DynamixelMotorsBus(MotorsBus):
|
||||||
self._comm_success = dxl.COMM_SUCCESS
|
self._comm_success = dxl.COMM_SUCCESS
|
||||||
self._no_error = 0x00
|
self._no_error = 0x00
|
||||||
|
|
||||||
|
def _assert_protocol_is_compatible(self, instruction_name: str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
def configure_motors(self) -> None:
|
def configure_motors(self) -> None:
|
||||||
# By default, Dynamixel motors have a 500µs delay response time (corresponding to a value of 250 on
|
# By default, Dynamixel motors have a 500µs delay response time (corresponding to a value of 250 on
|
||||||
# the 'Return_Delay_Time' address). We ensure this is reduced to the minimum of 2µs (value of 0).
|
# the 'Return_Delay_Time' address). We ensure this is reduced to the minimum of 2µs (value of 0).
|
||||||
|
|
|
@ -102,6 +102,7 @@ class FeetechMotorsBus(MotorsBus):
|
||||||
super().__init__(port, motors, calibration)
|
super().__init__(port, motors, calibration)
|
||||||
import scservo_sdk as scs
|
import scservo_sdk as scs
|
||||||
|
|
||||||
|
self.protocol_version = protocol_version
|
||||||
self.port_handler = scs.PortHandler(self.port)
|
self.port_handler = scs.PortHandler(self.port)
|
||||||
# HACK: monkeypatch
|
# HACK: monkeypatch
|
||||||
self.port_handler.setPacketTimeout = patch_setPacketTimeout.__get__(
|
self.port_handler.setPacketTimeout = patch_setPacketTimeout.__get__(
|
||||||
|
@ -113,6 +114,12 @@ class FeetechMotorsBus(MotorsBus):
|
||||||
self._comm_success = scs.COMM_SUCCESS
|
self._comm_success = scs.COMM_SUCCESS
|
||||||
self._no_error = 0x00
|
self._no_error = 0x00
|
||||||
|
|
||||||
|
def _assert_protocol_is_compatible(self, instruction_name: str) -> None:
|
||||||
|
if instruction_name == "sync_read" and self.protocol_version == 1:
|
||||||
|
raise NotImplementedError(
|
||||||
|
"'Sync Read' is not available with Feetech motors using Protocol 1. Use 'Read' instead."
|
||||||
|
)
|
||||||
|
|
||||||
def configure_motors(self) -> None:
|
def configure_motors(self) -> None:
|
||||||
# By default, Feetech motors have a 500µs delay response time (corresponding to a value of 250 on the
|
# By default, Feetech motors have a 500µs delay response time (corresponding to a value of 250 on the
|
||||||
# 'Return_Delay' address). We ensure this is reduced to the minimum of 2µs (value of 0).
|
# 'Return_Delay' address). We ensure this is reduced to the minimum of 2µs (value of 0).
|
||||||
|
|
|
@ -393,6 +393,10 @@ class MotorsBus(abc.ABC):
|
||||||
"was found instead for that id."
|
"was found instead for that id."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def _assert_protocol_is_compatible(self, instruction_name: str) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_connected(self) -> bool:
|
def is_connected(self) -> bool:
|
||||||
return self.port_handler.is_open
|
return self.port_handler.is_open
|
||||||
|
@ -723,6 +727,63 @@ class MotorsBus(abc.ABC):
|
||||||
) -> dict[int, list[int, str]] | None:
|
) -> dict[int, list[int, str]] | None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def read(
|
||||||
|
self,
|
||||||
|
data_name: str,
|
||||||
|
motor: str,
|
||||||
|
*,
|
||||||
|
normalize: bool = True,
|
||||||
|
num_retry: int = 0,
|
||||||
|
) -> Value:
|
||||||
|
if not self.is_connected:
|
||||||
|
raise DeviceNotConnectedError(
|
||||||
|
f"{self.__class__.__name__}('{self.port}') is not connected. You need to run `{self.__class__.__name__}.connect()`."
|
||||||
|
)
|
||||||
|
|
||||||
|
id_ = self.motors[motor].id
|
||||||
|
model = self.motors[motor].model
|
||||||
|
addr, n_bytes = get_address(self.model_ctrl_table, model, data_name)
|
||||||
|
|
||||||
|
value, comm, error = self._read(addr, n_bytes, id_, num_retry=num_retry)
|
||||||
|
if not self._is_comm_success(comm):
|
||||||
|
raise ConnectionError(
|
||||||
|
f"Failed to read '{data_name}' on {id_=} after {num_retry + 1} tries."
|
||||||
|
f"{self.packet_handler.getTxRxResult(comm)}"
|
||||||
|
)
|
||||||
|
elif self._is_error(error):
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Failed to read '{data_name}' on {id_=} after {num_retry + 1} tries."
|
||||||
|
f"\n{self.packet_handler.getRxPacketError(error)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
id_value = self._decode_sign(data_name, {id_: value})
|
||||||
|
|
||||||
|
if normalize and data_name in self.normalized_data:
|
||||||
|
id_value = self._normalize(data_name, id_value)
|
||||||
|
|
||||||
|
return id_value[id_]
|
||||||
|
|
||||||
|
def _read(self, addr: int, n_bytes: int, motor_id: int, num_retry: int = 0) -> tuple[int, int]:
|
||||||
|
if n_bytes == 1:
|
||||||
|
read_fn = self.packet_handler.read1ByteTxRx
|
||||||
|
elif n_bytes == 2:
|
||||||
|
read_fn = self.packet_handler.read2ByteTxRx
|
||||||
|
elif n_bytes == 4:
|
||||||
|
read_fn = self.packet_handler.read4ByteTxRx
|
||||||
|
else:
|
||||||
|
raise ValueError(n_bytes)
|
||||||
|
|
||||||
|
for n_try in range(1 + num_retry):
|
||||||
|
value, comm, error = read_fn(self.port_handler, motor_id, addr)
|
||||||
|
if self._is_comm_success(comm):
|
||||||
|
break
|
||||||
|
logger.debug(
|
||||||
|
f"Failed to read @{addr=} ({n_bytes=}) on {motor_id=} ({n_try=}): "
|
||||||
|
+ self.packet_handler.getTxRxResult(comm)
|
||||||
|
)
|
||||||
|
|
||||||
|
return value, comm, error
|
||||||
|
|
||||||
def sync_read(
|
def sync_read(
|
||||||
self,
|
self,
|
||||||
data_name: str,
|
data_name: str,
|
||||||
|
@ -736,6 +797,8 @@ class MotorsBus(abc.ABC):
|
||||||
f"{self.__class__.__name__}('{self.port}') is not connected. You need to run `{self.__class__.__name__}.connect()`."
|
f"{self.__class__.__name__}('{self.port}') is not connected. You need to run `{self.__class__.__name__}.connect()`."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self._assert_protocol_is_compatible("sync_read")
|
||||||
|
|
||||||
names = self._get_names_list(motors)
|
names = self._get_names_list(motors)
|
||||||
ids = [self.motors[name].id for name in names]
|
ids = [self.motors[name].id for name in names]
|
||||||
models = [self.motors[name].model for name in names]
|
models = [self.motors[name].model for name in names]
|
||||||
|
|
Loading…
Reference in New Issue