Controlling a Tic stepper controller via USB from Python (Noob level)

Hello! I’m trying to create a motorized camera slider and it seems like a stepper turning a timing belt (ie GT2) via a “pulley” (aka “gear”) moving the camera mount carriage is a good basic physical approach. The Pololu Tic stepper controllers look like a potentially good way to control/drive the stepper. As a starting point, I’d like to gradually accelerate the carriage/camera up to speed, traverse the slider rail at a speed I can set/vary, then decelerate to a stop at the other end. To develop this, I’d like to use a Mac OS X laptop, but move to a Raspberry Pi to make the rig more portable. Based on this, and my limited coding skills/knowledge, Python seems like a good ‘environment’ to start from for me.

I’m reading through the User’s Guide for the Tic boards. It’s a lot of “low level” stuff by my noob standards (as it should be.) I’m pretty unclear on how to send commands to the board from Python though. I’ve done a bunch of searches to try to find explanations or example code. It could be that it’s simple and obvious but that I don’t know enough to know the right terms to search for.

USB control seems like it would be ideal in my case. I’m inferring (guessing? imagining?) that Python would go a long way to “abstracting” a lot of the OS-to-OS USB driver issues that I can’t handle (too “low level”.) Might it be as simple as Python sending “command line” commands through ticcmd?

Hello.

We do not have any code examples written in Python for the Tic. Considering that you want to communicate with the Tic via USB and do not have a strong programming background, I think invoking ticcmd from your Python program would be the easiest option. Before you start writing code, I suggest getting familiar with using ticcmd, then do an Internet search on how to execute command-line programs in a Python script.

If you write some code and run in to problems, please post your entire code here, and I would be happy to take a look at it.

- Amanda

Thanks! Feedback that this is a plausible route to pursue is exactly what I was hoping for!

As soon as I can make some time to mess around a bit and come up with it, I’m sure I’ll have some questions and something to look over.

I’ll be glad to share what does and doesn’t work.

Hi,

I have a rough, but working pure Python code implementation of a library to access the TIC drivers via USB.

See:

Dan

Using Python 3.73 and IDLE on Win7 pro SP 1, I’m having no luck with the Pololu-suggested Python motor status and test commands (section 12.3 of the TIC manual), or the example given on github using Pytic.

Even trying only the simplest call to test, edting the example down to just ’ ticcmd --list’ does not generate the errors, but no response seen at all… Where would the output go generally? I should get the same result as with a DOS command window:
002680374, Tic Stepper Motor Controller

When it prints, it is in blue, and only simple print statement appear-- I was hoping the output would be the same as a print out.

YAML installed OK with PIP, but it also seems to give an error when the test is run. The program is building a command string and sending it to Ticcmd, but It is not clear that the correct string is actually going to the system- do spaces matter? I have tried a lot of variations.
.
The command that we are trying to send works on a DOS shell as do all the other commands, but it is rejected by Python:

RESTART: C:/Users/Razbo/AppData/Local/Programs/Python/Python37-32/TiccmdExample.py
Traceback (most recent call last):
File "C:/Users/Razbo/AppData/Local/Programs/Python/Python37-32/TiccmdExample.py", line 12, in status = yaml.load(ticcmd('-s', '--full'))
File "C:/Users/Razbo/AppData/Local/Programs/Python/Python37-32/TiccmdExample.py", line 10, in ticcmd
return subprocess.check_output(['ticcmd'] + list(args))
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\subprocess.py", line 395, in check_output
**kwargs).stdout
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\subprocess.py", line 487, in run
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['ticcmd', '-s', '--full']' returned non-zero exit status 4.
>>>

The PyTIC program generates other errors:

RESTART: C:/Users/Razbo/AppData/Local/Programs/Python/Python37-32/PyTIC TICCMD Test.py
Traceback (most recent call last):
File "C:/Users/Razbo/AppData/Local/Programs/Python/Python37-32/PyTIC TICCMD Test.py", line 6, in tic = pytic.PyTic()
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pytic\pytic.py", line 27, in __init__
self._load_drivers()
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\site-packages\pytic\pytic.py", line 80, in _load_drivers
self.usblib = windll.LoadLibrary(file_path+"\\drivers\\x64\\libusbp-1.dll")
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\ctypes\__init__.py", line 434, in LoadLibrary
return self._dlltype(name)
File "C:\Users\Razbo\AppData\Local\Programs\Python\Python37-32\lib\ctypes\__init__.py", line 356, in __init__
self._handle = _dlopen(self._name, mode)
OSError: [WinError 193] %1 is not a valid Win32 application

So I have something fundamentally wrong with my Python setup.

Hello.

Are you able to control a stepper motor using the Status tab in the Tic Control Center? I recommend getting that working before attempting to use Python.

If you run ticcmd --list while no Tics are plugged in, it produces no output. I recommend that until you can figure out how to get output from ticcmd into your Python program, you should just run ticcmd with no arguments, which causes it to output a help screen. Please try running this code and post the full output from it:

import subprocess
print(subprocess.check_output(['ticcmd']))

The documentation of subpress.check_output specifies that the output of the command is returned by the function. Spaces in the strings that you pass to check_output do matter, and should be avoided.

Did you have multiple Tics plugged into the computer when you tried to run ticcmd -s --full from Python? I see that you got exit status 4, which is the error code used by ticcmd to indicate that it found multiple Tics.

By the way, when ticcmd exits with an error code, it also prints an error message to its standard error output pipe, which should be connected to your terminal. I do not see any such error message in the output you posted, but maybe you can find it if you look carefully.

Regarding your PyTic issue: please note that PyTic ships with 64-bit Windows DLLs. To use it, you have to ensure that your CPU, operating system, and the version of Python you are running are 64-bit. I see “Python37-32” in your output, which makes me suspect that you are using a 32-bit version of Python. You might have better luck trying the pytic that Dan Tyrrell linked to in his post above, which has a similar name but is very different.

–David

Thanks you for the quick response!
For some reason the routine (the eg. from User’s Guide sec. 12.3) runs now-- maybe due to removing the second controller (but this was tried numerous times).
I was trying to use two T249s, and everything worked perfectly from the beginning in the Tic Control Center, choosing the serial number first for an action done by one of the motors on the ‘Connected to’ drop down box. All commands work in a DOS window.
BTW, this is a very nice testing program, thank you.
But to make it run, I need too unplug one of the T249s, and not try to put a ‘-d 00268374’ serial number specification in the program-- this seems to be rejected.
So the command line entered into a DOS window
ticcmd -d 00268374 --position 2000
works, even with the other motor available.

But it won’t accept this in the test program, e.g., by replacing the last line:
ticcmd(’–exit-safe-start’, ‘–position’, 'str(new_target))

by the line
ticcmd(’-d 00268374’, ‘–exit-safe-start’, ‘–position’, 'str(new_target))

in order to specify a controller when using two gives an error.

The -d argument and the serial number after it are separated by a space, so they are separate arguments. When writing them in your Python program, they each need to have their own strings, like this:

ticcmd('-d', '00268374', ...)

–David

Thanks for that info. After adding the two part SN specification to both instances (yaml call and position command), it works fine.

BTW, can you tell me how to change the call
status = yaml.load(ticcmd(’-d’, ‘00268374’, -s’, ‘–full’)

to the suggested use of the ‘Loader=’

The calls to yaml need to be
status = yaml.load(ticcmd(’-d’, ‘00268374’, ‘-s’, ‘–full’), Loader=yaml.FullLoader)