Hi @alessiodam, thanks for a very nice driver for these servos.
I was experiencing some issues with _sync_read, and if I understand the documentation right, the logic should be a bit different.
In your current code, you have (shortened a bit)
def _sync_read(
self, address: int, data_length: int, servo_ids: Sequence[int]
) -> dict[int, Optional[dict[str, object]]]:
parameters = [address, data_length, *servo_ids]
packet = self.send_instruction(0xFE, Instruction.SYNC_READ, parameters)
responses: dict[int, Optional[dict[str, object]]] = {}
for servo_id in servo_ids:
response = self.read_response(packet)
if response: # parse and fill dict
return responses
This repeatedly reads packets from the serial bus, one read for each id that was requested in send_instruction.
At least in my servo configuration (three ST3020 chained), the first serial read gets all the response packets, and thus in your code I only ever get the response from the first servo parsed, and the others are ignored.
I think that the read_response call should be outside the loop over servo_ids. I was patching together something like this which seems to work well in my setup:
def _sync_read(self, address: int, data_length: int,
servo_ids: Sequence[int]) -> dict[int,Optional[dict[str,object]]]:
parameters = [address, data_length, *servo_ids]
packet = self.send_instruction(0xFE, Instruction.SYNC_READ, parameters)
responses: dict[int, Optional[dict[str, object]]] = {}
rxpacket = self.read_response(packet)
bytelist = iter(rxpacket)
response = {}
try:
while next(bytelist)==0xFF and next(bytelist)==0xFF:
scs_id = next(bytelist)
retlen = next(bytelist)
if retlen != data_length+2:
response[scs_id] = None
#return None, "COMM_RX_CORRUPT"
err = next(bytelist)
data = [next(bytelist) for _ in range(data_length)]
crc = ~(sum(data) + retlen + scs_id + err) & 0xFF
rcrc = next(bytelist)
#if crc != rcrc:
# response[scs_id] = None
response[scs_id] = data
response[scs_id] = {
"header": [0xFF, 0xFF],
"id": scs_id,
"length": retlen,
"error": err,
"parameters": data,
"received_checksum": rcrc,
"calculated_checksum": crc,
"checksum_valid": (rcrc==crc)
}
except StopIteration:
pass # should do some error handling
return response
This can probably be coded better, as the parsing of an individual packet has the same logic as your parse_response.
Hi @alessiodam, thanks for a very nice driver for these servos.
I was experiencing some issues with
_sync_read, and if I understand the documentation right, the logic should be a bit different.In your current code, you have (shortened a bit)
This repeatedly reads packets from the serial bus, one read for each id that was requested in
send_instruction.At least in my servo configuration (three ST3020 chained), the first serial read gets all the response packets, and thus in your code I only ever get the response from the first servo parsed, and the others are ignored.
I think that the
read_responsecall should be outside the loop overservo_ids. I was patching together something like this which seems to work well in my setup:This can probably be coded better, as the parsing of an individual packet has the same logic as your
parse_response.