├── tools
├── __init__.py
└── protocol_import.py
├── images
└── pololu_tic.png
├── pytic
├── __init__.py
├── drivers
│ └── x64
│ │ ├── libusbp-1.dll
│ │ └── libpololu-tic-1.dll
├── pytic_structures.py
├── pytic_protocol.py
└── pytic.py
├── MANIFEST.in
├── config
└── config.yml
├── setup.py
├── CONTRIBUTING.md
├── LICENSE.txt
└── README.md
/tools/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/pololu_tic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenInstitute/pytic/HEAD/images/pololu_tic.png
--------------------------------------------------------------------------------
/pytic/__init__.py:
--------------------------------------------------------------------------------
1 | '''
2 | Object-Oriented Python Wrapper for Pololu Tic C-API
3 | '''
4 | from .pytic import *
--------------------------------------------------------------------------------
/pytic/drivers/x64/libusbp-1.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenInstitute/pytic/HEAD/pytic/drivers/x64/libusbp-1.dll
--------------------------------------------------------------------------------
/pytic/drivers/x64/libpololu-tic-1.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AllenInstitute/pytic/HEAD/pytic/drivers/x64/libpololu-tic-1.dll
--------------------------------------------------------------------------------
/MANIFEST.in:
--------------------------------------------------------------------------------
1 | include pytic/drivers/x64/*.dll
2 | include pytic/drivers/x64/*.lib
3 | include config/*.yml
4 | include README.md
5 | include CONTRIBUTING.md
6 | include LICENSE.txt
--------------------------------------------------------------------------------
/tools/protocol_import.py:
--------------------------------------------------------------------------------
1 | import csv
2 |
3 | '''
4 | Requires user to remove header and extra new-lines in-between entries
5 | '''
6 |
7 |
8 | pfile = open("tic_protocol.h", 'r') # Copy file to leave original unaltered
9 | ofile = open('pytic_protocol.py', 'w')
10 | preader = csv.reader(pfile, delimiter=' ')
11 | ofile.write("tic_constant = {\n")
12 |
13 | for r in preader:
14 | ofile.write('\t\'' + r[1] + '\': ' + r[2] + ',\n')
15 |
16 | ofile.write('}')
17 | ofile.close()
18 | pfile.close()
--------------------------------------------------------------------------------
/config/config.yml:
--------------------------------------------------------------------------------
1 | tic_settings:
2 | product: TIC_PRODUCT_T825
3 | auto_clear_driver_error: True
4 | ignore_err_line_high: True
5 | serial_crc_enabled: False
6 | command_timeout: 0
7 | max_speed: 180000000 # pulses/s * 10^-4
8 | starting_speed: 0 # pulses/s * 10^-4
9 | max_accel: 9000000 # pulses/s^2 * 10^-2
10 | max_decel: 9000000 # pulses/s^2 * 10^-2
11 | step_mode: TIC_STEP_MODE_MICROSTEP16
12 | current_limit: 640 # mA (see table in Pololu manual for acceptable values)
13 | decay_mode: TIC_DECAY_MODE_T825_FAST
14 | pin_settings:
15 | - pin_num: TIC_PIN_NUM_RX
16 | func: TIC_PIN_FUNC_USER_INPUT
17 | pullup: True
18 | analog: False
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | __author__ = "Daniel Castelli"
2 | from setuptools import setup
3 | from setuptools.command.install import install as _install
4 | import subprocess
5 |
6 | class install(_install):
7 | def pre_install_script(self):
8 | pass
9 |
10 | def post_install_script(self):
11 | pass
12 |
13 | def run(self):
14 | self.pre_install_script()
15 |
16 | _install.run(self)
17 |
18 | self.post_install_script()
19 |
20 | with open('README.md') as f:
21 | long_description = f.read()
22 |
23 | setup(
24 | name = "PyTic",
25 | version = "0.0.5",
26 | author = "Daniel Castelli",
27 | author_email = "danc@alleninstitute.org",
28 | description = "An object-oriented Python wrapper for Pololu Tic Stepper Controllers.",
29 | long_description=long_description,
30 | long_description_content_type='text/markdown',
31 | license = "Allen Institute Software License",
32 | keywords = "PyTic Pololu Tic Stepper Controller Wrapper",
33 | url = "https://github.com/AllenInstitute/pytic",
34 | packages = ['pytic'],
35 | install_requires = ['PyYAML'],
36 | include_package_data=True,
37 | cmdclass = {'install': install},
38 | )
39 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Allen Institute Contribution Agreement
2 |
3 | This document describes the terms under which you may make “Contributions” —
4 | which may include without limitation, software additions, revisions, bug fixes, configuration changes,
5 | documentation, or any other materials — to any of the projects owned or managed by the Allen Institute.
6 | If you have questions about these terms, please contact us at terms@alleninstitute.org.
7 |
8 | You certify that:
9 |
10 | • Your Contributions are either:
11 |
12 | 1. Created in whole or in part by you and you have the right to submit them under the designated license
13 | (described below); or
14 | 2. Based upon previous work that, to the best of your knowledge, is covered under an appropriate
15 | open source license and you have the right under that license to submit that work with modifications,
16 | whether created in whole or in part by you, under the designated license; or
17 |
18 | 3. Provided directly to you by some other person who certified (1) or (2) and you have not modified them.
19 |
20 | • You are granting your Contributions to the Allen Institute under the terms of the [2-Clause BSD license](https://opensource.org/licenses/BSD-2-Clause)
21 | (the “designated license”).
22 |
23 | • You understand and agree that the Allen Institute projects and your Contributions are public and that
24 | a record of the Contributions (including all metadata and personal information you submit with them) is
25 | maintained indefinitely and may be redistributed consistent with the Allen Institute’s mission and the
26 | 2-Clause BSD license.
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Allen Institute Software License - This software license is the 2-clause BSD license
2 | plus a third clause that prohibits redistribution for commercial purposes without further permission.
3 |
4 | Copyright (c) 2018. Allen Institute. All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
7 | following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
10 | following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
13 | following disclaimer in the documentation and/or other materials provided with the distribution.
14 |
15 | 3. Redistributions for commercial purposes are not permitted without the Allen Institute's written permission.
16 | For purposes of this license, commercial purposes is the incorporation of the Allen Institute's software into
17 | anything for which you will charge fees or other compensation. Contact terms@alleninstitute.org for commercial
18 | licensing opportunities.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
26 | USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/pytic/pytic_structures.py:
--------------------------------------------------------------------------------
1 | from ctypes import *
2 | from .pytic_protocol import tic_constant as t_const
3 |
4 | class libusbp_generic_interface(Structure):
5 | _fields_ = [("interface_number", c_uint8),
6 | ("device_instance_id", c_char_p),
7 | ("filename", c_char_p)]
8 |
9 | class libusbp_generic_handle(Structure):
10 | # untested type, no HANDLE or WIN_INTERFACE_HANDLE type
11 | _fields_ = [("file_handle", c_ulong),
12 | ("winusb_handle", c_ulong)]
13 |
14 | class tic_device(Structure):
15 | _fields_ = [("usb_interface", POINTER(libusbp_generic_interface)),
16 | ("serial_number", c_char_p),
17 | ("os_id", c_char_p),
18 | ("firmware_version", c_uint16),
19 | ("product", c_uint8)]
20 |
21 | class tic_handle(Structure):
22 | _fields_ = [('usb_handle', POINTER(libusbp_generic_handle)),
23 | ('device', POINTER(tic_device)),
24 | ('cached_firmware_version_string', c_char_p)]
25 |
26 | class pin_settings(Structure):
27 | _fields_ = [('func', c_uint8),
28 | ('pullup', c_bool),
29 | ('analog', c_bool),
30 | ('polarity', c_bool)]
31 |
32 | class tic_settings(Structure):
33 | _fields_ = [('product', c_uint8),
34 | ('control_mode', c_uint8),
35 | ('never_sleep', c_bool),
36 | ('disable_safe_start', c_bool),
37 | ('ignore_err_line_high', c_bool),
38 | ('auto_clear_driver_error', c_bool),
39 | ('soft_error_response', c_uint8),
40 | ('soft_error_position', c_int32),
41 | ('serial_baud_rate', c_uint32),
42 | ('serial_device_number', c_uint8),
43 | ('command_timeout', c_uint16),
44 | ('serial_crc_enabled', c_bool),
45 | ('serial_response_delay', c_uint8),
46 | ('low_vin_timeout', c_uint16),
47 | ('low_vin_shutoff_voltage', c_uint16),
48 | ('low_vin_startup_voltage', c_uint16),
49 | ('high_vin_shutoff_voltage', c_uint16),
50 | ('vin_calibration', c_int16),
51 | ('rc_max_pulse_period', c_uint16),
52 | ('rc_bad_signal_timeout', c_uint16),
53 | ('rc_consecutive_good_pulses', c_uint8),
54 | ('input_averaging_enabled', c_uint8),
55 | ('input_hysteresis', c_uint16),
56 | ('input_error_min', c_uint16),
57 | ('input_error_max', c_uint16),
58 | ('input_scaling_degree', c_uint8),
59 | ('input_invert', c_bool),
60 | ('input_min', c_uint16),
61 | ('input_neutral_min', c_uint16),
62 | ('input_neutral_max', c_uint16),
63 | ('input_max', c_uint16),
64 | ('output_min', c_int32),
65 | ('output_max', c_int32),
66 | ('encoder_prescaler', c_uint32),
67 | ('encoder_postscaler', c_uint32),
68 | ('encoder_unlimited', c_bool),
69 | ('pin_settings', pin_settings * t_const['TIC_CONTROL_PIN_COUNT']),
70 | ('current_limit', c_uint32),
71 | ('current_limit_during_error', c_int32),
72 | ('step_mode', c_uint8),
73 | ('decay_mode', c_int8),
74 | ('starting_speed', c_uint32),
75 | ('max_speed', c_uint32),
76 | ('max_decel', c_uint32),
77 | ('max_accel', c_uint32),
78 | ('invert_motor_direction', c_bool)]
79 |
80 | class pin_info(Structure):
81 | _fields_ = [('analog_reading', c_uint16),
82 | ('digital_reading', c_bool),
83 | ('pin_state', c_uint8)]
84 |
85 | class tic_variables(Structure):
86 | _fields_ = [('product', c_uint8),
87 | ('operation_state', c_uint8),
88 | ('energized', c_bool),
89 | ('position_uncertain', c_bool),
90 | ('error_status', c_uint16),
91 | ('errors_occurred', c_uint32),
92 | ('planning_mode', c_uint8),
93 | ('target_position', c_int32),
94 | ('target_velocity', c_int32),
95 | ('starting_speed', c_uint32),
96 | ('max_speed', c_uint32),
97 | ('max_decel', c_uint32),
98 | ('max_accel', c_uint32),
99 | ('current_position', c_int32),
100 | ('current_velocity', c_int32),
101 | ('acting_target_position', c_int32),
102 | ('time_since_last_step', c_uint32),
103 | ('device_reset', c_uint8),
104 | ('vin_voltage', c_uint16),
105 | ('up_time', c_uint32),
106 | ('encoder_position', c_int32),
107 | ('rc_pulse_width', c_uint16),
108 | ('step_mode', c_uint8),
109 | ('current_limit_code', c_uint8),
110 | ('decay_mode', c_uint8),
111 | ('input_state', c_uint8),
112 | ('input_after_averaging', c_uint16),
113 | ('input_after_hysteresis', c_uint16),
114 | ('input_after_scaling', c_int32),
115 | ('pin_info', pin_info * t_const['TIC_CONTROL_PIN_COUNT'])]
116 |
117 | class tic_error(Structure):
118 | _fields_ = [('do_not_free', c_bool),
119 | ('message', c_char_p),
120 | ('code_count', c_size_t),
121 | ('code_array', POINTER(c_uint32))]
122 |
--------------------------------------------------------------------------------
/pytic/pytic_protocol.py:
--------------------------------------------------------------------------------
1 | tic_constant = {
2 | # not in protocol.h
3 | 'TIC_PRODUCT_T825': 1,
4 | 'TIC_PRODUCT_T834': 2,
5 | 'TIC_PRODUCT_T500': 3,
6 | # in protocol.h
7 | 'TIC_VENDOR_ID': 0x1FFB,
8 | 'TIC_PRODUCT_ID_T825': 0x00B3,
9 | 'TIC_PRODUCT_ID_T834': 0x00B5,
10 | 'TIC_PRODUCT_ID_T500': 0x00BD,
11 | 'TIC_FIRMWARE_MODIFICATION_STRING_INDEX': 4,
12 | 'TIC_OPERATION_STATE_RESET': 0,
13 | 'TIC_OPERATION_STATE_DEENERGIZED': 2,
14 | 'TIC_OPERATION_STATE_SOFT_ERROR': 4,
15 | 'TIC_OPERATION_STATE_WAITING_FOR_ERR_LINE': 6,
16 | 'TIC_OPERATION_STATE_STARTING_UP': 8,
17 | 'TIC_OPERATION_STATE_NORMAL': 10,
18 | 'TIC_MISC_FLAGS1_ENERGIZED': 0,
19 | 'TIC_MISC_FLAGS1_POSITION_UNCERTAIN': 1,
20 | 'TIC_ERROR_INTENTIONALLY_DEENERGIZED': 0,
21 | 'TIC_ERROR_MOTOR_DRIVER_ERROR': 1,
22 | 'TIC_ERROR_LOW_VIN': 2,
23 | 'TIC_ERROR_KILL_SWITCH': 3,
24 | 'TIC_ERROR_REQUIRED_INPUT_INVALID': 4,
25 | 'TIC_ERROR_SERIAL_ERROR': 5,
26 | 'TIC_ERROR_COMMAND_TIMEOUT': 6,
27 | 'TIC_ERROR_SAFE_START_VIOLATION': 7,
28 | 'TIC_ERROR_ERR_LINE_HIGH': 8,
29 | 'TIC_ERROR_SERIAL_FRAMING': 16,
30 | 'TIC_ERROR_SERIAL_RX_OVERRUN': 17,
31 | 'TIC_ERROR_SERIAL_FORMAT': 18,
32 | 'TIC_ERROR_SERIAL_CRC': 19,
33 | 'TIC_ERROR_ENCODER_SKIP': 20,
34 | 'TIC_INPUT_STATE_NOT_READY': 0,
35 | 'TIC_INPUT_STATE_INVALID': 1,
36 | 'TIC_INPUT_STATE_HALT': 2,
37 | 'TIC_INPUT_STATE_POSITION': 3,
38 | 'TIC_INPUT_STATE_VELOCITY': 4,
39 | 'TIC_RESPONSE_DEENERGIZE': 0,
40 | 'TIC_RESPONSE_HALT_AND_HOLD': 1,
41 | 'TIC_RESPONSE_DECEL_TO_HOLD': 2,
42 | 'TIC_RESPONSE_GO_TO_POSITION': 3,
43 | 'TIC_PIN_NUM_SCL': 0,
44 | 'TIC_PIN_NUM_SDA': 1,
45 | 'TIC_PIN_NUM_TX': 2,
46 | 'TIC_PIN_NUM_RX': 3,
47 | 'TIC_PIN_NUM_RC': 4,
48 | 'TIC_PLANNING_MODE_OFF': 0,
49 | 'TIC_PLANNING_MODE_TARGET_POSITION': 1,
50 | 'TIC_PLANNING_MODE_TARGET_VELOCITY': 2,
51 | 'TIC_RESET_POWER_UP': 0,
52 | 'TIC_RESET_BROWNOUT': 1,
53 | 'TIC_RESET_RESET_LINE': 2,
54 | 'TIC_RESET_WATCHDOG': 4,
55 | 'TIC_RESET_SOFTWARE': 8,
56 | 'TIC_RESET_STACK_OVERFLOW': 16,
57 | 'TIC_RESET_STACK_UNDERFLOW': 32,
58 | 'TIC_PIN_STATE_HIGH_IMPEDANCE': 0,
59 | 'TIC_PIN_STATE_PULLED_UP': 1,
60 | 'TIC_PIN_STATE_OUTPUT_LOW': 2,
61 | 'TIC_PIN_STATE_OUTPUT_HIGH': 3,
62 | 'TIC_MIN_ALLOWED_BAUD_RATE': 200,
63 | 'TIC_MAX_ALLOWED_BAUD_RATE': 115385,
64 | 'TIC_DEFAULT_COMMAND_TIMEOUT': 1000,
65 | 'TIC_MAX_ALLOWED_COMMAND_TIMEOUT': 60000,
66 | 'TIC_MAX_ALLOWED_CURRENT': 3968,
67 | 'TIC_MAX_ALLOWED_CURRENT_T825': 3968,
68 | 'TIC_MAX_ALLOWED_CURRENT_T834': 3456,
69 | 'TIC_MAX_ALLOWED_CURRENT_T500': 3093,
70 | 'TIC_MAX_ALLOWED_CURRENT_CODE_T500': 32,
71 | 'TIC_CURRENT_LIMIT_UNITS_MA': 32,
72 | 'TIC_MIN_ALLOWED_ACCEL': 100,
73 | 'TIC_MAX_ALLOWED_ACCEL': 0x7FFFFFFF,
74 | 'TIC_MAX_ALLOWED_SPEED': 500000000,
75 | 'TIC_MAX_ALLOWED_ENCODER_PRESCALER': 0x7FFFFFFF,
76 | 'TIC_MAX_ALLOWED_ENCODER_POSTSCALER': 0x7FFFFFFF,
77 | 'TIC_SPEED_UNITS_PER_HZ': 10000,
78 | 'TIC_ACCEL_UNITS_PER_HZ2': 100,
79 | 'TIC_CONTROL_MODE_SERIAL': 0,
80 | 'TIC_CONTROL_MODE_STEP_DIR': 1,
81 | 'TIC_CONTROL_MODE_RC_POSITION': 2,
82 | 'TIC_CONTROL_MODE_RC_SPEED': 3,
83 | 'TIC_CONTROL_MODE_ANALOG_POSITION': 4,
84 | 'TIC_CONTROL_MODE_ANALOG_SPEED': 5,
85 | 'TIC_CONTROL_MODE_ENCODER_POSITION': 6,
86 | 'TIC_CONTROL_MODE_ENCODER_SPEED': 7,
87 | 'TIC_SCALING_DEGREE_LINEAR': 0,
88 | 'TIC_SCALING_DEGREE_QUADRATIC': 1,
89 | 'TIC_SCALING_DEGREE_CUBIC': 2,
90 | 'TIC_STEP_MODE_FULL': 0,
91 | 'TIC_STEP_MODE_HALF': 1,
92 | 'TIC_STEP_MODE_MICROSTEP1': 0,
93 | 'TIC_STEP_MODE_MICROSTEP2': 1,
94 | 'TIC_STEP_MODE_MICROSTEP4': 2,
95 | 'TIC_STEP_MODE_MICROSTEP8': 3,
96 | 'TIC_STEP_MODE_MICROSTEP16': 4,
97 | 'TIC_STEP_MODE_MICROSTEP32': 5,
98 | 'TIC_DECAY_MODE_MIXED': 0,
99 | 'TIC_DECAY_MODE_SLOW': 1,
100 | 'TIC_DECAY_MODE_FAST': 2,
101 | 'TIC_DECAY_MODE_MODE3': 3,
102 | 'TIC_DECAY_MODE_MODE4': 4,
103 | 'TIC_DECAY_MODE_T825_MIXED': 0,
104 | 'TIC_DECAY_MODE_T825_SLOW': 1,
105 | 'TIC_DECAY_MODE_T825_FAST': 2,
106 | 'TIC_DECAY_MODE_T834_MIXED50': 0,
107 | 'TIC_DECAY_MODE_T834_SLOW': 1,
108 | 'TIC_DECAY_MODE_T834_FAST': 2,
109 | 'TIC_DECAY_MODE_T834_MIXED25': 3,
110 | 'TIC_DECAY_MODE_T834_MIXED75': 4,
111 | 'TIC_DECAY_MODE_T500_AUTO': 0,
112 | 'TIC_PIN_PULLUP': 7,
113 | 'TIC_PIN_ANALOG': 6,
114 | 'TIC_PIN_FUNC_POSN': 0,
115 | 'TIC_PIN_FUNC_MASK': 0x0F,
116 | 'TIC_PIN_FUNC_DEFAULT': 0,
117 | 'TIC_PIN_FUNC_USER_IO': 1,
118 | 'TIC_PIN_FUNC_USER_INPUT': 2,
119 | 'TIC_PIN_FUNC_POT_POWER': 3,
120 | 'TIC_PIN_FUNC_SERIAL': 4,
121 | 'TIC_PIN_FUNC_RC': 5,
122 | 'TIC_PIN_FUNC_ENCODER': 6,
123 | 'TIC_PIN_FUNC_KILL_SWITCH': 7,
124 | 'TIC_CMD_SET_TARGET_POSITION': 0xE0,
125 | 'TIC_CMD_SET_TARGET_VELOCITY': 0xE3,
126 | 'TIC_CMD_HALT_AND_SET_POSITION': 0xEC,
127 | 'TIC_CMD_HALT_AND_HOLD': 0x89,
128 | 'TIC_CMD_RESET_COMMAND_TIMEOUT': 0x8C,
129 | 'TIC_CMD_DEENERGIZE': 0x86,
130 | 'TIC_CMD_ENERGIZE': 0x85,
131 | 'TIC_CMD_EXIT_SAFE_START': 0x83,
132 | 'TIC_CMD_ENTER_SAFE_START': 0x8F,
133 | 'TIC_CMD_RESET': 0xB0,
134 | 'TIC_CMD_CLEAR_DRIVER_ERROR': 0x8A,
135 | 'TIC_CMD_SET_MAX_SPEED': 0xE6,
136 | 'TIC_CMD_SET_STARTING_SPEED': 0xE5,
137 | 'TIC_CMD_SET_MAX_ACCEL': 0xEA,
138 | 'TIC_CMD_SET_MAX_DECEL': 0xE9,
139 | 'TIC_CMD_SET_STEP_MODE': 0x94,
140 | 'TIC_CMD_SET_CURRENT_LIMIT': 0x91,
141 | 'TIC_CMD_SET_DECAY_MODE': 0x92,
142 | 'TIC_CMD_GET_VARIABLE': 0xA1,
143 | 'TIC_CMD_GET_VARIABLE_AND_CLEAR_ERRORS_OCCURRED': 0xA2,
144 | 'TIC_CMD_GET_SETTING': 0xA8,
145 | 'TIC_CMD_SET_SETTING': 0x13,
146 | 'TIC_CMD_REINITIALIZE': 0x10,
147 | 'TIC_CMD_START_BOOTLOADER': 0xFF,
148 | 'TIC_CMD_GET_DEBUG_DATA': 0x20,
149 | 'TIC_VAR_OPERATION_STATE': 0x00,
150 | 'TIC_VAR_MISC_FLAGS1': 0x01,
151 | 'TIC_VAR_ERROR_STATUS': 0x02,
152 | 'TIC_VAR_ERRORS_OCCURRED': 0x04,
153 | 'TIC_VAR_PLANNING_MODE': 0x09,
154 | 'TIC_VAR_TARGET_POSITION': 0x0A,
155 | 'TIC_VAR_TARGET_VELOCITY': 0x0E,
156 | 'TIC_VAR_STARTING_SPEED': 0x12,
157 | 'TIC_VAR_MAX_SPEED': 0x16,
158 | 'TIC_VAR_MAX_DECEL': 0x1A,
159 | 'TIC_VAR_MAX_ACCEL': 0x1E,
160 | 'TIC_VAR_CURRENT_POSITION': 0x22,
161 | 'TIC_VAR_CURRENT_VELOCITY': 0x26,
162 | 'TIC_VAR_ACTING_TARGET_POSITION': 0x2A,
163 | 'TIC_VAR_TIME_SINCE_LAST_STEP': 0x2E,
164 | 'TIC_VAR_DEVICE_RESET': 0x32,
165 | 'TIC_VAR_VIN_VOLTAGE': 0x33,
166 | 'TIC_VAR_UP_TIME': 0x35,
167 | 'TIC_VAR_ENCODER_POSITION': 0x39,
168 | 'TIC_VAR_RC_PULSE_WIDTH': 0x3D,
169 | 'TIC_VAR_ANALOG_READING_SCL': 0x3F,
170 | 'TIC_VAR_ANALOG_READING_SDA': 0x41,
171 | 'TIC_VAR_ANALOG_READING_TX': 0x43,
172 | 'TIC_VAR_ANALOG_READING_RX': 0x45,
173 | 'TIC_VAR_DIGITAL_READINGS': 0x47,
174 | 'TIC_VAR_PIN_STATES': 0x48,
175 | 'TIC_VAR_STEP_MODE': 0x49,
176 | 'TIC_VAR_CURRENT_LIMIT': 0x4A,
177 | 'TIC_VAR_DECAY_MODE': 0x4B,
178 | 'TIC_VAR_INPUT_STATE': 0x4C,
179 | 'TIC_VAR_INPUT_AFTER_AVERAGING': 0x4D,
180 | 'TIC_VAR_INPUT_AFTER_HYSTERESIS': 0x4F,
181 | 'TIC_VAR_INPUT_AFTER_SCALING': 0x51,
182 | 'TIC_VARIABLES_SIZE': 0x55,
183 | 'TIC_SETTING_NOT_INITIALIZED': 0x00,
184 | 'TIC_SETTING_CONTROL_MODE': 0x01,
185 | 'TIC_SETTING_NEVER_SLEEP': 0x02,
186 | 'TIC_SETTING_DISABLE_SAFE_START': 0x03,
187 | 'TIC_SETTING_IGNORE_ERR_LINE_HIGH': 0x04,
188 | 'TIC_SETTING_SERIAL_BAUD_RATE_GENERATOR': 0x05,
189 | 'TIC_SETTING_SERIAL_DEVICE_NUMBER': 0x07,
190 | 'TIC_SETTING_AUTO_CLEAR_DRIVER_ERROR': 0x08,
191 | 'TIC_SETTING_COMMAND_TIMEOUT': 0x09,
192 | 'TIC_SETTING_SERIAL_CRC_ENABLED': 0x0B,
193 | 'TIC_SETTING_LOW_VIN_TIMEOUT': 0x0C,
194 | 'TIC_SETTING_LOW_VIN_SHUTOFF_VOLTAGE': 0x0E,
195 | 'TIC_SETTING_LOW_VIN_STARTUP_VOLTAGE': 0x10,
196 | 'TIC_SETTING_HIGH_VIN_SHUTOFF_VOLTAGE': 0x12,
197 | 'TIC_SETTING_VIN_CALIBRATION': 0x14,
198 | 'TIC_SETTING_RC_MAX_PULSE_PERIOD': 0x16,
199 | 'TIC_SETTING_RC_BAD_SIGNAL_TIMEOUT': 0x18,
200 | 'TIC_SETTING_RC_CONSECUTIVE_GOOD_PULSES': 0x1A,
201 | 'TIC_SETTING_INVERT_MOTOR_DIRECTION': 0x1B,
202 | 'TIC_SETTING_INPUT_ERROR_MIN': 0x1C,
203 | 'TIC_SETTING_INPUT_ERROR_MAX': 0x1E,
204 | 'TIC_SETTING_INPUT_SCALING_DEGREE': 0x20,
205 | 'TIC_SETTING_INPUT_INVERT': 0x21,
206 | 'TIC_SETTING_INPUT_MIN': 0x22,
207 | 'TIC_SETTING_INPUT_NEUTRAL_MIN': 0x24,
208 | 'TIC_SETTING_INPUT_NEUTRAL_MAX': 0x26,
209 | 'TIC_SETTING_INPUT_MAX': 0x28,
210 | 'TIC_SETTING_OUTPUT_MIN': 0x2A,
211 | 'TIC_SETTING_INPUT_AVERAGING_ENABLED': 0x2E,
212 | 'TIC_SETTING_INPUT_HYSTERESIS': 0x2F,
213 | 'TIC_SETTING_CURRENT_LIMIT_DURING_ERROR': 0x31,
214 | 'TIC_SETTING_OUTPUT_MAX': 0x32,
215 | 'TIC_SETTING_SWITCH_POLARITY_MAP': 0x36,
216 | 'TIC_SETTING_ENCODER_POSTSCALER': 0x37,
217 | 'TIC_SETTING_SCL_CONFIG': 0x3B,
218 | 'TIC_SETTING_SDA_CONFIG': 0x3C,
219 | 'TIC_SETTING_TX_CONFIG': 0x3D,
220 | 'TIC_SETTING_RX_CONFIG': 0x3E,
221 | 'TIC_SETTING_RC_CONFIG': 0x3F,
222 | 'TIC_SETTING_CURRENT_LIMIT': 0x40,
223 | 'TIC_SETTING_STEP_MODE': 0x41,
224 | 'TIC_SETTING_DECAY_MODE': 0x42,
225 | 'TIC_SETTING_STARTING_SPEED': 0x43,
226 | 'TIC_SETTING_MAX_SPEED': 0x47,
227 | 'TIC_SETTING_MAX_DECEL': 0x4B,
228 | 'TIC_SETTING_MAX_ACCEL': 0x4F,
229 | 'TIC_SETTING_SOFT_ERROR_RESPONSE': 0x53,
230 | 'TIC_SETTING_SOFT_ERROR_POSITION': 0x54,
231 | 'TIC_SETTING_ENCODER_PRESCALER': 0x58,
232 | 'TIC_SETTING_ENCODER_UNLIMITED': 0x5C,
233 | 'TIC_SETTING_KILL_SWITCH_MAP': 0x5D,
234 | 'TIC_SETTING_SERIAL_RESPONSE_DELAY': 0x5E,
235 | 'TIC_SETTINGS_SIZE': 0x5F,
236 | 'TIC_BAUD_RATE_GENERATOR_FACTOR': 12000000,
237 | 'TIC_MAX_USB_RESPONSE_SIZE': 128,
238 | 'TIC_INPUT_NULL': 0xFFFF,
239 | 'TIC_CONTROL_PIN_COUNT': 5,
240 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # PyTic v0.0.4
3 |
4 | 
5 |
6 | ---
7 |
8 | ## Introduction
9 |
10 | `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][pololu_tic_software] GitHub page using the ctypes library. The device comunication protocol is USB.
11 |
12 | ---
13 |
14 | ## Installation
15 |
16 | ### Prerequisites
17 |
18 | `PyTic` requires the [Tic Software and Drivers for Windows][tic_drivers_win] msi provided by Pololu to be installed as a prerequisite. Other operating system drivers can be found on the [Pololu Tic Resources][tic_resources], but are not currently supported by this Python package.
19 |
20 |
21 | ### Pip Install
22 |
23 | To install the `PyTic` package on a Windows machine equipped with Python 2.7 or higher, run the following `pip` command:
24 |
25 | ```console
26 | C:\> pip install pytic
27 | ```
28 |
29 | * Note: Only Windows x64 machines are supported at this time.
30 |
31 | ---
32 |
33 |
34 | ## Package Architecture
35 |
36 | `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.
37 |
38 | ```console
39 | ----------------------------------
40 | | Package Relation Tree |
41 | ----------------------------------
42 |
43 | PyTic [Tic Object]
44 | |-- Settings [Structure Interface Object]
45 | |- Pin Settings [Structure Interface Object] [List]
46 | |-- Variables [Structure Interface Object]
47 | |- Pin Info [Structure Interface Object] [List]
48 | |-- Logger [Notification]
49 |
50 | PyTic_Protocol [Module]
51 | |-- Tic Constants [Dictionary]
52 | ```
53 |
54 | ### PyTic Protocol (C-Constants Dictionary)
55 |
56 |
57 | 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][tic_protocol_h] header file and stores them in a Python dictionary named `tic_constants` in the `pytic_protocol` module. See [Using Settings](#using_settings) in the [Example Code](#example_code) section to see how to use this dictionary in contect.
58 |
59 | ### Error Handling
60 |
61 | 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][logging_lib] library.
62 |
63 | ---
64 |
65 | ## Example Code
66 |
67 |
68 | 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][pololu_tic_manual], the [Pololu Tic C-API][tic_h], or this package's source code.
69 |
70 | ### Simple Program
71 |
72 |
73 | The simple program below demonstrates how to connect to a __Pololu Tic Stepper Driver__ device over USB and move to several positions after the previous position has been reached.
74 |
75 | ```python
76 | import pytic
77 | from time import sleep
78 |
79 | # - Initialization -------------------------------------------
80 |
81 | tic = pytic.PyTic()
82 |
83 | # Connect to first available Tic Device serial number over USB
84 | serial_nums = tic.list_connected_device_serial_numbers()
85 | tic.connect_to_serial_number(serial_nums[0])
86 |
87 | # Load configuration file and apply settings
88 | tic.settings.load_config('path\\to\\config.yml')
89 | tic.settings.apply()
90 |
91 | # - Motion Command Sequence ----------------------------------
92 |
93 | # Zero current motor position
94 | tic.halt_and_set_position(0)
95 |
96 | # Energize Motor
97 | tic.energize()
98 | tic.exit_safe_start()
99 |
100 | # Move to listed positions
101 | positions = [1000, 2000, 3000, 0]
102 | for p in positions:
103 | tic.set_target_position(p)
104 | while tic.variables.current_position != tic.variables.target_position:
105 | sleep(0.1)
106 |
107 | # De-energize motor and get error status
108 | tic.enter_safe_start()
109 | tic.deenergize()
110 | print(tic.variables.error_status)
111 | ```
112 |
113 | * Note: Modified settings will not take effect until `PyTic.settings.apply()` method is called. This is to avoid unnecessary writes to non-volitile memory.
114 |
115 | ### Using Settings
116 |
117 |
118 | The `PyTic.settings` structure interface object is used to alter device settings stored in non-volitile memory. As detailed above in [PyTic Protocol](#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.
119 |
120 | ```python
121 |
122 | # ... assume PyTic object initialized and connected to device as 'tic'
123 |
124 | # Load Tic Constant Dictionary
125 | tc = pytic.pytic_protocol.tic_constant
126 |
127 | # Modify individual properties of composite settings object
128 | tic.settings.product = tc['TIC_PRODUCT_T825']
129 | tic.settings.step_mode = tc['TIC_STEP_MODE_MICROSTEP16']
130 |
131 | # Turn the Serial RX Pin into a generic digital user input
132 | pin = tc['TIC_PIN_NUM_RX']
133 | tic.settings.pin_setting[pin].func = tc['TIC_PIN_FUNC_USER_INPUT']
134 | tic.settings.pin_setting[pin].pullup = True
135 |
136 | # Required to burn new settings to Tic non-volitile memory
137 | tic.settings.apply()
138 |
139 | ```
140 |
141 |
142 |
150 |
151 | ---
152 | ## Logging
153 |
154 | `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.
155 |
156 |
157 | ---
158 | ## Example YAML Configuration File
159 |
160 | `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,
161 |
162 | ```yaml
163 | tic_settings: # required header for load_config fcn.
164 | product: TIC_PRODUCT_T825
165 | auto_clear_driver_error: True # ** These 4 settings **
166 | ignore_err_line_high: True # ** were experimentally **
167 | serial_crc_enabled: False # ** determined to stabalize **
168 | command_timeout: 0 # ** device performance **
169 | max_speed: 180000000 # pulses/s * 10^-4
170 | starting_speed: 0 # pulses/s * 10^-4
171 | max_accel: 9000000 # pulses/s^2 * 10^-2
172 | max_decel: 9000000 # pulses/s^2 * 10^-2
173 | step_mode: TIC_STEP_MODE_MICROSTEP16
174 | current_limit: 640 # mA, Only select values acceptable, See notes.
175 | decay_mode: TIC_DECAY_MODE_T825_FAST
176 | pin_settings: # Ex. Modifying Default Pin Fcn.
177 | - pin_num: TIC_PIN_NUM_RX
178 | func: TIC_PIN_FUNC_USER_INPUT
179 | pullup: True
180 | analog: False
181 | # - pin_id: TIC_PIN_NUM_TX # ... modifying a 2nd pin ...
182 | # func: TIC_PIN_FUNC_USER_INPUT
183 | # polarity: True
184 | # analog: False
185 | ```
186 |
187 | Notes:
188 | * `CAPS_DEFINED_CONSTANTS` are keys for the `tic_constant` dictionary located in `pytic_protocol.py`. Refer to section [Using Settings](#using_settings) for more details on the dictionary and its use.
189 | * `current_limit` only accepts select values detailed in the [Pololu Tic Manual][pololu_tic_manual]
190 |
191 |
192 | ---
193 |
194 | ## Dependencies
195 |
196 | Dependencies include the following,
197 |
198 | * PyYAML
199 |
200 | ---
201 |
202 | ## Level of Support Notice
203 |
204 | This code is currently not supported. It is being released to the community AS IS without any guarantee of support. The community is welcome to submit issues, but should not expect an active response.
205 |
206 | ---
207 |
208 | ## External Resources
209 |
210 | External resources include the following,
211 |
212 | * [logging Library][logging_lib]
213 | * [Pololu-Tic-Software GitHub][pololu_tic_software]
214 | * [Pololu Tic Manual][pololu_tic_manual]
215 | * [Pololu Tic Resources][tic_resources]
216 | * [tic.h][tic_h]
217 | * [tic_protocol.h][tic_protocol_h]
218 | * [Tic Software and Drivers for Windows][tic_drivers_win]
219 |
220 | [pololu_tic_software]: https://github.com/pololu/pololu-tic-software
221 | [pololu_tic_manual]: https://www.pololu.com/docs/0J71
222 | [logging_lib]: https://docs.python.org/3/library/logging.html
223 | [tic_protocol_h]: https://github.com/pololu/pololu-tic-software/blob/a75c204a2255554e21cc5351c528d930ba5d2c38/include/tic_protocol.h
224 | [tic_drivers_win]: https://www.pololu.com/file/0J1325/pololu-tic-1.6.2-win.msi
225 | [tic_resources]:https://www.pololu.com/product/3131/resources
226 | [tic_h]: https://github.com/pololu/pololu-tic-software/blob/master/include/tic.h
--------------------------------------------------------------------------------
/pytic/pytic.py:
--------------------------------------------------------------------------------
1 | import sys
2 | import os
3 | import yaml
4 | from ctypes import *
5 | from time import sleep
6 | from .pytic_protocol import tic_constant as tc
7 | from .pytic_structures import *
8 | from functools import wraps, partial
9 | import logging
10 |
11 | # [T]ic [E]rror [D]ecoder
12 | def TED(func):
13 | @wraps(func)
14 | def func_wrapper(*args, **kwargs):
15 | _e_p = func(*args, **kwargs)
16 | if bool(_e_p):
17 | _e = cast(_e_p, POINTER(tic_error))
18 | _logger = logging.getLogger('PyTic')
19 | _logger.error(_e.contents.message)
20 | return 1
21 | else:
22 | return 0
23 | return func_wrapper
24 |
25 | class PyTic(object):
26 | def __init__(self, log_file=None):
27 | self._load_drivers()
28 | self._logger = self._initialize_logger()
29 | self.device = None
30 | self.handle = None
31 | self.settings = None
32 | self.variables = None
33 | self._commands = [('set_target_position', c_int32),
34 | ('set_target_velocity', c_int32),
35 | ('halt_and_set_position', c_int32),
36 | ('halt_and_hold', None),
37 | ('reset_command_timeout', None),
38 | ('deenergize', None),
39 | ('energize', None),
40 | ('exit_safe_start', None),
41 | ('enter_safe_start', None),
42 | ('reset', None),
43 | ('clear_driver_error', None),
44 | ('set_max_speed', c_uint32),
45 | ('set_starting_speed', c_uint32),
46 | ('set_max_accel', c_uint32),
47 | ('set_max_decel', c_uint32),
48 | ('set_step_mode', c_uint8),
49 | ('set_current_limit', c_uint32),
50 | ('set_current_limit_code', c_uint8),
51 | ('set_decay_mode', c_uint8)]
52 | self._create_tic_command_attributes()
53 |
54 | def _initialize_logger(self):
55 | # - Logging -
56 | self._log_level = logging.DEBUG
57 | _logger = logging.getLogger('PyTic')
58 | _logger.setLevel(self._log_level)
59 | _formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
60 | # Console Logging
61 | _ch = logging.StreamHandler()
62 | _ch.setLevel(self._log_level)
63 | _ch.setFormatter(_formatter)
64 | _logger.addHandler(_ch)
65 | return _logger
66 |
67 | @property
68 | def log_level(self):
69 | return self._log_level
70 |
71 | @log_level.setter
72 | def log_level(self, level):
73 | self._log_level = level
74 | self._logger.setLevel(level)
75 |
76 | def _load_drivers(self):
77 | # Driver Locations (x64)
78 | file_path = os.path.dirname(os.path.abspath(__file__))
79 | #file_path = file_path[:-len('pytic')]
80 | self.usblib = windll.LoadLibrary(file_path+"\\drivers\\x64\\libusbp-1.dll")
81 | self.ticlib = windll.LoadLibrary(file_path+"\\drivers\\x64\\libpololu-tic-1.dll")
82 |
83 | def _create_tic_command_attributes(self):
84 | for c in self._commands:
85 | if bool(c[1]):
86 | setattr(self.__class__, c[0], partial(self._tic_command_with_value, c[0], c[1]))
87 | else:
88 | setattr(self.__class__, c[0], partial(self._tic_command, c[0]))
89 |
90 | @TED
91 | def _tic_command(self, cmd_name):
92 | e_p = getattr(self.ticlib,'tic_'+ cmd_name)(byref(self.handle))
93 | return e_p
94 |
95 | @TED
96 | def _tic_command_with_value(self, cmd_name, c_type, value):
97 | if 'TIC' in str(value):
98 | value = tc[value]
99 | e_p = getattr(self.ticlib,'tic_'+ cmd_name)(byref(self.handle), c_type(value))
100 | return e_p
101 |
102 | @TED
103 | def _list_connected_devices(self):
104 | self._devcnt = c_size_t(0)
105 | self._dev_pp = POINTER(POINTER(tic_device))()
106 | e_p = self.ticlib.tic_list_connected_devices(byref(self._dev_pp), byref(self._devcnt))
107 | return e_p
108 |
109 | @TED
110 | def _tic_handle_open(self):
111 | handle_p = POINTER(tic_handle)()
112 | e_p = self.ticlib.tic_handle_open(byref(self.device), byref(handle_p))
113 | self.handle = handle_p[0]
114 | return e_p
115 |
116 | def list_connected_device_serial_numbers(self):
117 | self._list_connected_devices()
118 | tic_list = []
119 | if not self._devcnt.value:
120 | print("No Tic devices connected.")
121 | for i in range(0, self._devcnt.value):
122 | ticdev = self._dev_pp[0][i]
123 | tic_list.append(ticdev.serial_number.decode('utf-8'))
124 | # print("Tic Device #: {0}, Serial #: {1}".format(i, sn))
125 | return tic_list
126 |
127 | def connect_to_serial_number(self, serial_number):
128 | self._list_connected_devices()
129 | for i in range(0, self._devcnt.value):
130 | if serial_number == self._dev_pp[0][i].serial_number.decode('utf-8'):
131 | self.device = self._dev_pp[0][i]
132 | self._tic_handle_open()
133 | self.variables = PyTic_Variables(self.handle, (self.usblib, self.ticlib))
134 | self.settings = PyTic_Settings(self.handle, (self.usblib, self.ticlib), self.variables.product)
135 | return 0
136 | if not self.device:
137 | self._logger.error("Serial number device not found.")
138 | return 1
139 |
140 |
141 | class PyTic_Variables(object):
142 | def __init__(self, device_handle, driver_handles):
143 | self.usblib, self.ticlib = driver_handles
144 | self._logger = logging.getLogger('PyTic')
145 | self._device_handle = device_handle
146 | self._tic_variables_p = POINTER(tic_variables)()
147 | self._tic_variables = tic_variables()
148 |
149 | self.pin_info = []
150 | for i in range(0, tc['TIC_CONTROL_PIN_COUNT']):
151 | self.pin_info.append(type('pinfo_'+str(i), (object,), {})())
152 |
153 | self._convert_structure_to_readonly_properties()
154 |
155 | def _convert_structure_to_readonly_properties(self):
156 | for field in tic_variables._fields_:
157 | if not field[0] == 'pin_info':
158 | prop = property(fget=partial(self._get_tic_readonly_property, field[0]))
159 | setattr(self.__class__, field[0], prop)
160 |
161 | for i in range(0, tc['TIC_CONTROL_PIN_COUNT']):
162 | for field in pin_info._fields_:
163 | prop = property(fget=partial(self._get_pin_readonly_property, field[0], i))
164 | setattr(self.pin_info[i].__class__, field[0], prop)
165 |
166 | @TED
167 | def _update_tic_variables(self):
168 | e_p = self.ticlib.tic_get_variables(byref(self._device_handle), \
169 | byref(self._tic_variables_p), c_bool(True))
170 | self._tic_variables = self._tic_variables_p[0]
171 | return e_p
172 |
173 | def _get_tic_readonly_property(self, field, obj):
174 | self._update_tic_variables()
175 | value = getattr(self._tic_variables, field)
176 | if field == "error_status" or field == "error_occurred":
177 | self._convert_error_bitmask(value)
178 | return value
179 |
180 | def _get_pin_readonly_property(self, field, pin_num, obj):
181 | self._update_tic_variables()
182 | return getattr(self._tic_variables.pin_info[pin_num], field)
183 |
184 | def _convert_error_bitmask(self, e_bit_mask):
185 | ecodes = ["TIC_ERROR_INTENTIONALLY_DEENERGIZED",
186 | "TIC_ERROR_MOTOR_DRIVER_ERROR",
187 | "TIC_ERROR_LOW_VIN",
188 | "TIC_ERROR_KILL_SWITCH",
189 | "TIC_ERROR_REQUIRED_INPUT_INVALID",
190 | "TIC_ERROR_SERIAL_ERROR",
191 | "TIC_ERROR_COMMAND_TIMEOUT",
192 | "TIC_ERROR_SAFE_START_VIOLATION",
193 | "TIC_ERROR_ERR_LINE_HIGH",
194 | "TIC_ERROR_SERIAL_FRAMING",
195 | "TIC_ERROR_SERIAL_RX_OVERRUN",
196 | "TIC_ERROR_SERIAL_FORMAT",
197 | "TIC_ERROR_SERIAL_CRC",
198 | "TIC_ERROR_ENCODER_SKIP"]
199 | for code in ecodes:
200 | if ((e_bit_mask >> tc[code]) & 1):
201 | self._logger.error(code)
202 |
203 |
204 | class PyTic_Settings(object):
205 | def __init__(self, device_handle, driver_handles, product):
206 | self.usblib, self.ticlib = driver_handles
207 | self._logger = logging.getLogger('PyTic')
208 | self._device_handle = device_handle
209 | # local vs device - local settings on pc, device settings on tic
210 | self._local_settings = tic_settings()
211 | self._device_settings = tic_settings()
212 | self._device_settings_p = POINTER(tic_settings)()
213 |
214 | self.pin_settings = []
215 | for i in range(0, tc['TIC_CONTROL_PIN_COUNT']):
216 | self.pin_settings.append(type('pset_'+str(i), (object,), {})())
217 |
218 | self._convert_structure_to_properties()
219 | self.auto_apply = False
220 |
221 | if "TIC" in str(product):
222 | product = int(tc[product])
223 | self._fill_with_defaults(product)
224 |
225 | def _convert_structure_to_properties(self):
226 | for field in tic_settings._fields_:
227 | if not field[0] == 'pin_settings':
228 | prop = property(fget=partial(self._get_tic_settings_from_device, field[0]),
229 | fset=partial(self._set_tic_settings_with_option, field[0]))
230 | setattr(self.__class__, field[0], prop)
231 |
232 | for i in range(0, tc['TIC_CONTROL_PIN_COUNT']):
233 | for field in pin_settings._fields_:
234 | prop = property(fget=partial(self._get_pin_settings_from_device, field[0], i),
235 | fset=partial(self._set_pin_settings_with_option, field[0], i))
236 | setattr(self.pin_settings[i].__class__, field[0], prop)
237 |
238 | def _get_tic_settings_from_device(self, field, obj):
239 | self._pull_device_settings()
240 | return getattr(self._device_settings, field)
241 |
242 | def _set_tic_settings_with_option(self, field, obj, value):
243 | setattr(self._local_settings, field, value)
244 | if (self.auto_apply):
245 | self.apply()
246 |
247 | def _get_pin_settings_from_device(self, field, pin_num, obj):
248 | self._pull_device_settings()
249 | return getattr(self._device_settings.pin_settings[pin_num], field)
250 |
251 | def _set_pin_settings_with_option(self, field, pin_num, obj, value):
252 | setattr(self._local_settings.pin_settings[pin_num], field)
253 | if (self.auto_apply):
254 | self.apply()
255 |
256 |
257 | @TED
258 | def _pull_device_settings(self):
259 | e_p = self.ticlib.tic_get_settings(byref(self._device_handle),
260 | byref(self._device_settings_p))
261 | self._device_settings = self._device_settings_p[0]
262 | return e_p
263 |
264 | @TED
265 | def _set_settings(self):
266 | e_p = self.ticlib.tic_set_settings(byref(self._device_handle),
267 | byref(self._local_settings))
268 | return e_p
269 |
270 | def _fill_with_defaults(self, product):
271 | self._local_settings.product = product
272 | self.ticlib.tic_settings_fill_with_defaults(byref(self._local_settings))
273 |
274 | def apply(self):
275 | self._settings_fix()
276 | self._set_settings()
277 | self._reinitialize()
278 |
279 | @TED
280 | def _settings_fix(self):
281 | warnings_p = POINTER(c_char_p)()
282 | e_p = self.ticlib.tic_settings_fix(byref(self._local_settings),warnings_p)
283 | if bool(warnings_p):
284 | for w in warnings_p:
285 | self._logger.warning(w)
286 | return e_p
287 |
288 | @TED
289 | def _reinitialize(self):
290 | e_p = self.ticlib.tic_reinitialize(byref(self._device_handle))
291 | return e_p
292 |
293 | def load_config(self, config_file):
294 | with open(config_file, 'r') as ymlfile:
295 | if yaml.__version__.split('.')[:2] < ['5', '1']:
296 | cfg = yaml.load(ymlfile)
297 | else:
298 | cfg = yaml.load(ymlfile, yaml.SafeLoader)
299 |
300 | cfg_settings = cfg['tic_settings']
301 |
302 | tic_settings_list = []
303 | for setting in tic_settings._fields_:
304 | tic_settings_list.append(setting[0])
305 |
306 | for setting in cfg_settings:
307 | if setting in tic_settings_list:
308 | if setting == 'pin_settings':
309 | for pin in cfg_settings['pin_settings']:
310 | i = tc[pin['pin_num']]
311 | if 'func' in pin:
312 | self._local_settings.pin_settings[i].func = tc[pin['func']]
313 | if 'pullup' in pin:
314 | self._local_settings.pin_settings[i].pullup = pin['pullup']
315 | if 'analog' in pin:
316 | self._local_settings.pin_settings[i].analog = pin['analog']
317 | if 'polarity' in pin:
318 | self._local_settings.pin_settings[i].polarity = pin['polarity']
319 | else:
320 | if 'TIC' in str(cfg_settings[setting]):
321 | value = tc[cfg_settings[setting]]
322 | else:
323 | value = cfg_settings[setting]
324 | setattr(self._local_settings, setting, value)
325 |
326 | if (self.auto_apply):
327 | self.apply()
328 |
329 | if __name__ == '__main__':
330 |
331 | tic = PyTic()
332 | print(tic.list_connected_device_serial_numbers())
333 |
--------------------------------------------------------------------------------