PyTic
is an object-oriented Python wrapper for the Pololu Tic stepper driver series. The wrapper interacts with the stepper driver device using the API described in the Pololu-Tic-Software GitHub page using the ctypes library. The device comunication protocol is USB.
This is a maintained fork of the original PyTic. This project was originally created by Daniel Castelli at the Allen Institute. The original codebase and documentation remain fundamental to this fork.
PyTic
requires Pololu's Tic Software and drivers as a prerequisite. The latest versions of these drivers can be found here for Windows and Linux. macOs is currently not supported by this Python package.
- Go to the Releases page
- Download the latest release's wheel file (
PyTic-x.x.x-py3-none-any.whl
) or source distribution (PyTic-x.x.x.tar.gz
) - Install using pip:
pip install PyTic-x.x.x-py3-none-any.whl # OR pip install PyTic-x.x.x.tar.gz
PyTic
encompasses almost all functionality present in the original C-API with some additional features. The Pololu Tic Stepper Driver is represented in Python using the pytic.PyTic()
object.
----------------------------------
| Package Relation Tree |
----------------------------------
PyTic [Tic Object]
|-- Settings [Structure Interface Object]
|- Pin Settings [Structure Interface Object] [List]
|-- Variables [Structure Interface Object]
|- Pin Info [Structure Interface Object] [List]
|-- Logger [Notification]
PyTic_Protocol [Module]
|-- Tic Constants [Dictionary]
The Pololu Tic C-API uses CAPS_DEFINED_CONSTANTS
for setting many of its parameters that represent an integer value. These contants set parameters such as pin function, step mode, etc. The PyTic
package auto-imports these values from the tic_protocol.h header file and stores them in a Python dictionary named tic_constants
in the pytic_protocol
module. See Using Settings in the Example Code section to see how to use this dictionary in contect.
All Pololu Tic C-API functions when dynamically imported into PyTic
are wrapped in a higher-order function error handler called TED()
, short for [T]ic [E]rror [D]ecoder. TED()
will make all Tic wrapped functions return 0 from a successful call and 1 from a call that generated an error. In addition, TED()
performs low-level bit mask decoding and writes the enumerated error value to the PyTic
object internal log. This log can be output the ther terminal or file using the standard logging library.
When upgrading to the new version, you'll need to update the following settings in your configuration:
Serial CRC Settings:
- The
serial_crc_enabled
setting has been renamed toserial_crc_for_commands
- A new setting has been inplemented to
serial_crc_for_responses
although it does not replace any previous commands.
Make sure to update your configuration files accordingly when upgrading to maintain proper functionality.
Outlined in this section are several examples of how to use PyTic
to control a Pololu Tic Stepper Driver. The objective of this section is to show the PyTic
syntax used to implement the Pololu Tic Stepper Driver C-API as opposed to detail each of the available functions. For a full list of commands, settings, and variable information please refer to either the Pololu Tic Manual, the Pololu Tic C-API, or this package's source code.
The simple program below demonstrates how to connect to a Pololu Tic Stepper Driver device over USB, home it (only viable if there any active limit switches) and move to several positions after the previous position has been reached.
import pytic
from time import sleep
# - Initialization -------------------------------------------
tic = pytic.PyTic()
# Connect to first available Tic Device serial number over USB
serial_nums = tic.list_connected_device_serial_numbers()
tic.connect_to_serial_number(serial_nums[0])
# Load configuration file and apply settings
tic.settings.load_config('config/config.yml')
tic.settings.apply()
tic.settings.print_settings()
# - Motion Command Sequence ----------------------------------
# Zero current motor position
tic.halt_and_set_position(0)
# Energize Motor
tic.energize()
tic.exit_safe_start()
# Homing example
tic.go_home(1)
# Wait for homing to end
while tic.variables.homing_active:
sleep(0.1)
# Move to listed positions
positions = [1000, 2000, 3000, 0]
for p in positions:
tic.set_target_position(p)
while tic.variables.current_position != tic.variables.target_position:
sleep(0.1)
# De-energize motor and get error status
tic.enter_safe_start()
tic.deenergize()
print(tic.variables.error_status)
- Note: Modified settings will not take effect until
PyTic.settings.apply()
method is called. This is to avoid unnecessary writes to non-volitile memory.
The PyTic.settings
structure interface object is used to alter device settings stored in non-volitile memory. As detailed above in PyTic Protocol, some of these settings have enumerated constants to maintain a user-friendly interaction. The code sample below demonstrates how to interact with PyTic.settings
using the tic_constant
dictionary. To avoid unnecissary writes to non-volitile memory, the PyTic.settings.apply()
function must be called for the new settings to take effect. To check if settings have been written properly to the driver, PyTic.settings.print_settings()
can be called to pull them from the driver and print them to the terminal.
# ... assume PyTic object initialized and connected to device as 'tic'
# Load Tic Constant Dictionary
tc = pytic.pytic_protocol.tic_constant
# Modify individual properties of composite settings object
tic.settings.product = tc['TIC_PRODUCT_T825']
tic.settings.step_mode = tc['TIC_STEP_MODE_MICROSTEP16']
# Turn the Serial RX Pin into a generic digital user input
pin = tc['TIC_PIN_NUM_RX']
tic.settings.pin_setting[pin].func = tc['TIC_PIN_FUNC_USER_INPUT']
tic.settings.pin_setting[pin].pullup = True
# Required to burn new settings to Tic non-volitile memory
tic.settings.apply()
PyTic
uses the logging
package to display Tic status messages. The default logging level is logging.DEBUG
. For less verbose logging, set PyTic.log_level = logging.CRITICAL
. The log name is PyTic
for users that would like to have a parent-object handle the logging information.
PyTic
settings can be set invidually using the PyTic.settings
structure interface in the script or all-at-once using a YAML config file and the PyTic.settings.load_config('\\path\\to\\config.yml')
function. Here is an example YAML config file with some usage notes,
tic_settings: # required header for load_config fcn.
product: TIC_PRODUCT_T825
auto_clear_driver_error: True # ** These 4 settings **
ignore_err_line_high: True # ** were experimentally **
serial_crc_for_commands: False # ** determined to stabilize **
command_timeout: 0 # ** device performance **
max_speed: 180000000 # pulses/s * 10^-4
starting_speed: 0 # pulses/s * 10^-4
max_accel: 9000000 # pulses/s^2 * 10^-2
max_decel: 9000000 # pulses/s^2 * 10^-2
step_mode: TIC_STEP_MODE_MICROSTEP16
current_limit: 640 # mA, Only select values acceptable, See notes.
decay_mode: TIC_DECAY_MODE_T825_FAST
pin_settings: # Ex. Modifying Default Pin Fcn.
- pin_num: TIC_PIN_NUM_RX
func: TIC_PIN_FUNC_USER_INPUT
pullup: True
analog: False
# - pin_id: TIC_PIN_NUM_RC # ... modifying a 2nd pin ...
# func: TIC_PIN_FUNC_LIMIT_SWITCH_FORWARD
# polarity: True
# analog: False
Notes:
CAPS_DEFINED_CONSTANTS
are keys for thetic_constant
dictionary located inpytic_protocol.py
. Refer to section Using Settings for more details on the dictionary and its use.current_limit
only accepts select values detailed in the Pololu Tic Manual
Dependencies include the following,
- PyYAML
External resources include the following,