Skip to content

_sync_read issues #6

@thvoigtmann

Description

@thvoigtmann

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions