0

Currently, we are building a robot with a raspberry pi and the AX-12 dynamixel Servo's. We found a python2 library we a currently porting to python3, we pinpointed the problem in a specific method that gives an error in python3.

The Python 2 version actually works like a charm

AX_GOAL_LENGTH = 5
AX_WRITE_DATA = 3
AX_GOAL_POSITION_L = 30
AX_START = 255
AX_REG_WRITE = 4

def move(self, id, position):
    self.direction(Ax12.RPI_DIRECTION_TX)
    Ax12.port.flushInput()
    p = [position&0xff, position>>8]
    checksum = (~(id + Ax12.AX_GOAL_LENGTH + Ax12.AX_WRITE_DATA + Ax12.AX_GOAL_POSITION_L + p[0] + p[1]))&0xff
    outData = chr(Ax12.AX_START)
    outData += chr(Ax12.AX_START)
    outData += chr(id)
    outData += chr(Ax12.AX_GOAL_LENGTH)
    outData += chr(Ax12.AX_WRITE_DATA)
    outData += chr(Ax12.AX_GOAL_POSITION_L)
    outData += chr(p[0])
    outData += chr(p[1])
    outData += chr(checksum)
    Ax12.port.write(outData)

What we have tried is adjust this variable:

Ax12.port.write(bytes(outData,'utf-8'))

Now the script runs, sadly the Servo won't work anymore.

We also tried to place the bytes in a byte array

result = bytes([Ax12.AX_START, Ax12.AX_START, 
                Ax12.AX_GOAL_LENGTH,Ax12.AX_REG_WRITE,
                Ax12.AX_GOAL_POSITION_L, p[0], p[1], checksum
])
Ax12.port.write(result)

The script runs but the servo won't run.

My believe is that the operations done to outData is different in python3 then in python2. I can't find out what should be adjusted or different.

Anybody sees what I am currently doing wrong?

1
  • Your bytes version is missing the id value, and you are sending AX_REG_WRITE instead of AX_WRITE_DATA. Commented May 9, 2016 at 14:52

1 Answer 1

2

Your bytes are not UTF-8 data; for any of your chr() values you create outside the range 0 - 127, encoding to UTF-8 produces two bytes.

You were creating Unicode codepoints from integer values; these create Latin-1 codepoints if you limited those to integers between 0 and 255; in principle you could encode to 'latin1' to get the bytes again, but it is much easier to just create bytes in the first place.

In Python 3, use the bytes type, created from a list of integers:

def move(self, id, position):
    self.direction(Ax12.RPI_DIRECTION_TX)
    Ax12.port.flushInput()
    p = [, position>>8]
    checksum = (~(id + Ax12.AX_GOAL_LENGTH + Ax12.AX_WRITE_DATA + Ax12.AX_GOAL_POSITION_L + p[0] + p[1]))&0xff
    outData = bytes([
        Ax12.AX_START, Ax12.AX_START, id,
        Ax12.AX_GOAL_LENGTH, Ax12.AX_WRITE_DATA,
        Ax12.AX_GOAL_POSITION_L, p[0], p[1], checksum])
    Ax12.port.write(outData)

Your own attempt did not include the id value and you used AX_REG_WRITE rather than AX_WRITE_DATA.

You could also use a bytearray() object, which would let you append additional bytes; you could use that to calculate the checksum by referencing the bytes produced so far, avoiding having to repeat yourself (a common source of errors):

def move(self, id, position):
    self.direction(Ax12.RPI_DIRECTION_TX)
    Ax12.port.flushInput()
    outData = bytearray([
        Ax12.AX_START, Ax12.AX_START, id,
        Ax12.AX_GOAL_LENGTH, Ax12.AX_WRITE_DATA,
        Ax12.AX_GOAL_POSITION_L, position & 0xff, position >> 8])
    checksum = ~sum(outData[2:]) & 0xff
    outData.append(checksum)
    Ax12.port.write(outData)

You could use concatenation too of course (outData = bytes([...]), outData += bytes([checksum])) but bytearray is also available in Python 2, so the above version is compatible with both major Python versions.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.