[Errno 121] Pololu Tic T825 on the RPi using I2C with Python

Hi there,

I am pretty new to Python and controlling stepper motors.

I am currently working on a project where I need to control six stepper motors and reading six encoder values.

So my basic setup consists of a RPi4, six Pololu Tic T825 and six stepper motors (1.9V, 1.8A) with attached encoders (5V operating current).

I connected the Tics via I2C to the PI (physical GPIO Pins 3 and 5). The Tics are powered with a 15V 20A powersupply.
The encoders are attached to the Tics RX/TX pins and are getting their 5V and GND from them aswell.

Controlling the motors from the TicGUI software isn’t a problem at all. Also if I check the connection to the I2C devices with “i2cdetect -y 1” all attached devices are listed with the adresses configured.

As I was having issues I have played around with baudrates a little (changing vom 9600 to 16000 to 32000 in the PI and the Tics). That didn’t help.

So basically the problem is, if I start my code (based on the example in the documentation) there is an error message prompted after a few seconds.

Traceback (most recent call last):
  File "/home/pi/Desktop/testMH.py", line 79, in <module>
    tic.set_target_position(300)
  File "/home/pi/Desktop/testMH.py", line 38, in set_target_position
    self.bus.i2c_rdwr(write)
  File "/home/pi/.local/lib/python3.7/site-packages/smbus2/smbus2.py", line 637, in i2c_rdwr
    ioctl(self.fd, I2C_RDWR, ioctl_data)
OSError: [Errno 121] Remote I/O error

My code is the following:

from smbus2 import SMBus, i2c_msg
from time import sleep

class TicI2C(object):
    def __init__(self, bus, address):
        self.bus = bus
        self.address = address

    # Sends the "Exit safe start" command.
    def exit_safe_start(self):
        command = [0x83]
        write = i2c_msg.write(self.address, command)
        self.bus.i2c_rdwr(write)

    # Sets the target position.
    #
    # For more information about what this command does, see the
    # "Set target position" command in the "Command reference" section of the
    # Tic user's guide.
    def set_target_position(self, target):
        command = [0xE0,
            target >> 0 & 0xFF,
            target >> 8 & 0xFF,
            target >> 16 & 0xFF,
            target >> 24 & 0xFF]
        write = i2c_msg.write(self.address, command)
        print(address, command)
        self.bus.i2c_rdwr(write)

    # Gets one or more variables from the Tic.
    def get_variables(self, offset, length):
        write = i2c_msg.write(self.address, [0xA1, offset])
        read = i2c_msg.read(self.address, length)
        print(address, offset)
        self.bus.i2c_rdwr(write, read)
        return list(read)

    # Gets the "Current position" variable from the Tic.
    def get_current_position(self):
        b = self.get_variables(0x39, 4)
        position = b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24)
        if position >= (1 << 31):
            position -= (1 << 32)
        return position

    def energize(self):
        command = [0x85]
        write = i2c_msg.write(self.address, command)
        self.bus.i2c_rdwr(write)


# Open a handle to "/dev/i2c-3", representing the I2C bus.
bus = SMBus(1)

# Select the I2C address of the Tic (the device number).
address = 7

tic = TicI2C(bus, address)

tic.exit_safe_start()

while True:
    tic.energize()
    tic.set_target_position(-300)
    posi = tic.get_current_position()
    print("Current position is {}.".format(posi))
    sleep(1)
    tic.energize()
    tic.set_target_position(300)
    print("Current position is {}.".format(posi))
    sleep(1)

Any help would be much appreciated.

Best

Hello.

It looks like you are using the hardware I2C port on the Raspberry Pi, which has a bug in it that makes it not work reliably with the Tic. You should carefully read the instructions at the top of the “Example I2C code for Linux in Python” section in the Tic Stepper Motor Controller User’s Guide where we provide a link explaining how to setup I2C for the Raspberry Pi.

- Amanda