├── .arduino-ci.yaml ├── .github ├── ISSUE_TEMPLATE │ ├── bug-report-or-feature-request.md │ └── config.yml └── workflows │ └── ci.yaml ├── .gitignore ├── .gitlab-ci.yml ├── Doxyfile ├── LICENSE.txt ├── README.md ├── Tic.cpp ├── Tic.h ├── examples ├── I2CMulti │ └── I2CMulti.ino ├── I2CPositionControl │ └── I2CPositionControl.ino ├── I2CSetCurrentLimit │ └── I2CSetCurrentLimit.ino ├── I2CSpeedControl │ └── I2CSpeedControl.ino ├── I2CThreeButtons │ └── I2CThreeButtons.ino ├── SerialMulti │ └── SerialMulti.ino ├── SerialPositionControl │ └── SerialPositionControl.ino └── SerialSpeedControl │ └── SerialSpeedControl.ino ├── keywords.txt └── library.properties /.arduino-ci.yaml: -------------------------------------------------------------------------------- 1 | library_archives: 2 | - Pushbutton=https://github.com/pololu/pushbutton-arduino/archive/2.0.0.tar.gz=10h6ls1vbzvq0542s1qd75xgz4g5amg8s6qvw6dvq554y1krwkv0 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report-or-feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report or feature request 3 | about: Did you find a specific bug in the code for this project? Do you want to request 4 | a new feature? Please open an issue! 5 | title: '' 6 | labels: '' 7 | assignees: '' 8 | 9 | --- 10 | 11 | 12 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Pololu Forum 4 | url: https://forum.pololu.com/ 5 | about: Do you need help getting started? Can't get this code to work at all? Having problems with electronics? Please post on our forum! 6 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: "CI" 2 | on: 3 | pull_request: 4 | push: 5 | jobs: 6 | ci: 7 | runs-on: ubuntu-20.04 8 | steps: 9 | - name: Checkout this repository 10 | uses: actions/checkout@v2.3.4 11 | - name: Cache for arduino-ci 12 | uses: actions/cache@v2.1.3 13 | with: 14 | path: | 15 | ~/.arduino15 16 | key: ${{ runner.os }}-arduino 17 | - name: Install nix 18 | uses: cachix/install-nix-action@v12 19 | - run: nix-shell -I nixpkgs=channel:nixpkgs-unstable -p arduino-ci --run "arduino-ci" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /docs/ 2 | /out/ 3 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | image: $CI_REGISTRY_IMAGE/nixos/nix:2.3.6 2 | 3 | stages: 4 | - ci 5 | 6 | ci: 7 | stage: ci 8 | tags: 9 | - nix 10 | script: 11 | - nix-shell -I nixpkgs=channel:nixpkgs-unstable -p arduino-ci --run "arduino-ci" 12 | -------------------------------------------------------------------------------- /Doxyfile: -------------------------------------------------------------------------------- 1 | # Doxygen configuration file for generating documentation. 2 | PROJECT_NAME = "Tic Stepper Motor Controller library for Arduino" 3 | OUTPUT_DIRECTORY = docs 4 | INLINE_INHERITED_MEMB = YES 5 | INPUT = . 6 | USE_MDFILE_AS_MAINPAGE = README.md 7 | RECURSIVE = YES 8 | SOURCE_BROWSER = YES 9 | USE_MATHJAX = YES 10 | GENERATE_LATEX = NO 11 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-2020 Pololu Corporation (www.pololu.com) 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tic Stepper Motor Controller library for Arduino 2 | 3 | [www.pololu.com](https://www.pololu.com/) 4 | 5 | ## Summary 6 | 7 | This is a library for the Arduino IDE that helps interface with a 8 | [Tic Stepper Motor Controller][tic] ([T500], [T834], [T825], [T249], [36v4]) 9 | using serial or I²C. 10 | 11 | ## Supported platforms 12 | 13 | This library is designed to work with the Arduino IDE versions 1.8.x or later; 14 | we have not tested it with earlier versions. This library should support any 15 | Arduino-compatible board, including the [Pololu A-Star controllers][a-star]. 16 | 17 | ## Getting started 18 | 19 | ### Hardware 20 | 21 | The Tic Stepper Motor Controllers can be purchased from Pololu's website. 22 | Before continuing, careful reading of the [Tic Stepper Controller User's 23 | Guide][guide] is recommended. 24 | 25 | ### I2C connections 26 | 27 | To control the Tic using I2C, you should connect your board's SCL pin to the 28 | Tic's SCL pin, connect your board's SDA pin to the Tic's SDA pin, and connect 29 | one of your board's GND pins to one of the Tic's GND pins. 30 | 31 | ### Serial connections 32 | 33 | To control the Tic using asynchronous TTL serial, you need to at least connect 34 | your board's TX pin (as defined in the table below) to the Tic's RX pin, and 35 | connect your board's GND pin to one of the Tic's GND pins. If you want to read 36 | information from the Tic (as is done in this library's SerialPositionControl 37 | example), you must also connect your board's RX pin (as defined in the table 38 | below) to the Tic's TX pin. 39 | 40 | The example sketches for this library use a hardware serial port on your Arduino 41 | if one is available: if your Arduino environment defines 42 | `SERIAL_PORT_HARDWARE_OPEN`, the examples will use that port. The pins for this 43 | serial port are different depending on which Arduino you are using. 44 | 45 | | Microcontroller Board | Hardware serial? | MCU RX pin | MCU TX pin | 46 | |-----------------------|------------------|------------|------------| 47 | | A-Star 32U4 | Yes | 0 | 1 | 48 | | A-Star 328PB | Yes | 12 | 11 | 49 | | Arduino Leonardo | Yes | 0 | 1 | 50 | | Arduino Micro | Yes | 0 | 1 | 51 | | Arduino Mega 2560 | Yes | 19 | 18 | 52 | | Arduino Due | Yes | 19** | 18 | 53 | | Arduino Uno | No | 10 | 11 | 54 | | Arduino Yun | No | 10 | 11 | 55 | 56 | ** The Due's serial port is 3.3 V, so it should not be directly connected 57 | to the Tic's 5 V TX line. A voltage divider or level shifter can be 58 | used. 59 | 60 | ### Tic configuration 61 | 62 | Before using the example sketches, you should use the Tic Control Center 63 | software to apply these settings: 64 | 65 | * Control mode: Serial/I²C/USB. 66 | * Baud rate: 9600 67 | * CRC disabled 68 | * Device number: 14 69 | 70 | ### Software 71 | 72 | You can use the Library Manager to install this library: 73 | 74 | 1. In the Arduino IDE, open the "Sketch" menu, select "Include Library", then 75 | "Manage Libraries...". 76 | 2. Search for "Tic Stepper Motor Controller". 77 | 3. Click the Tic entry in the list. 78 | 4. Click "Install". 79 | 80 | If this does not work, you can manually install the library: 81 | 82 | 1. Download the 83 | [latest release archive from GitHub](https://github.com/pololu/tic-arduino/releases) 84 | and decompress it. 85 | 2. Rename the folder "tic-arduino-xxxx" to "Tic". 86 | 3. Drag the "Tic" folder into the "libraries" directory inside your 87 | Arduino sketchbook directory. You can view your sketchbook location by 88 | opening the "File" menu and selecting "Preferences" in the Arduino IDE. If 89 | there is not already a "libraries" folder in that location, you should make 90 | the folder yourself. 91 | 4. After installing the library, restart the Arduino IDE. 92 | 93 | ## Examples 94 | 95 | Several example sketches are available that show how to use the library. You can 96 | access them from the Arduino IDE by opening the "File" menu, selecting 97 | "Examples", and then selecting "Tic". If you cannot find these 98 | examples, the library was probably installed incorrectly and you should retry 99 | the installation instructions above. 100 | 101 | ## Classes 102 | 103 | The main classes provided by the library are listed below: 104 | 105 | * TicBase 106 | * TicSerial 107 | * TicI2C 108 | 109 | ## Documentation 110 | 111 | For complete documentation of this library, see [the tic-arduino documentation][doc]. If you are already on that page, then click the links in the "Classes" section above. 112 | 113 | [a-star]: https://www.pololu.com/a-star 114 | [doc]: https://pololu.github.io/tic-arduino/ 115 | [guide]: https://www.pololu.com/docs/0J71 116 | [ide]: https://www.arduino.cc/en/Main/Software 117 | [tic]: https://www.pololu.com/tic 118 | [T500]: https://www.pololu.com/product/3135 119 | [T834]: https://www.pololu.com/product/3133 120 | [T825]: https://www.pololu.com/product/3131 121 | [T249]: https://www.pololu.com/product/3139 122 | [36v4]: https://www.pololu.com/product/3141 123 | 124 | ## Version history 125 | 126 | * 2.2.0 (2024-11-20): 127 | - TicI2C: Added an optional parameter to the constructor to specify 128 | what I2C bus to use. Also added `setBus`, `getBus`, and `setAddress`. 129 | * 2.1.1 (2021-06-22): 130 | - Fixed some compilation errors and warnings. 131 | * 2.1.0 (2019-09-16): 132 | - Added support for the new [Tic 36v4][36v4]. 133 | * 2.0.0 (2019-02-06): 134 | - Removed the 2 ms delay inserted after I2C reads. This makes the 135 | library incompatible with Tic firmware versions 1.00 and 1.01. 136 | - Added support for the new [Tic T249][T249]. 137 | - Added features to support limit switches and homing, which were 138 | added in Tic firmware version 1.06. 139 | * 1.2.1 (2018-03-19): 140 | - Fixed compilation errors in the SerialSpeedControl example. 141 | * 1.2.0 (2018-03-16): 142 | - Added support for the new [Tic T500][T500]. 143 | - Added the I2CSetCurrentLimit example. 144 | * 1.1.0 (2017-11-02): 145 | - Added support for the new [Tic T834][T834]. 146 | - Added the SerialMulti, I2CMulti, and I2CThreeButtons examples. 147 | - Added keywords.txt. 148 | * 1.0.1 (2017-07-25): Removed the call to `haltAndSetPosition` in the `SerialSpeedControl` example because it is not necessary. 149 | * 1.0.0 (2017-07-24): Original release. 150 | -------------------------------------------------------------------------------- /Tic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static const uint16_t Tic03aCurrentTable[33] = 5 | { 6 | 0, 7 | 1, 8 | 174, 9 | 343, 10 | 495, 11 | 634, 12 | 762, 13 | 880, 14 | 990, 15 | 1092, 16 | 1189, 17 | 1281, 18 | 1368, 19 | 1452, 20 | 1532, 21 | 1611, 22 | 1687, 23 | 1762, 24 | 1835, 25 | 1909, 26 | 1982, 27 | 2056, 28 | 2131, 29 | 2207, 30 | 2285, 31 | 2366, 32 | 2451, 33 | 2540, 34 | 2634, 35 | 2734, 36 | 2843, 37 | 2962, 38 | 3093, 39 | }; 40 | 41 | void TicBase::setCurrentLimit(uint16_t limit) 42 | { 43 | uint8_t code = 0; 44 | 45 | if (product == TicProduct::T500) 46 | { 47 | for (uint8_t i = 0; i < 33; i++) 48 | { 49 | if (Tic03aCurrentTable[i] <= limit) 50 | { 51 | code = i; 52 | } 53 | else 54 | { 55 | break; 56 | } 57 | } 58 | } 59 | else if (product == TicProduct::T249) 60 | { 61 | code = limit / TicT249CurrentUnits; 62 | } 63 | else if (product == TicProduct::Tic36v4) 64 | { 65 | if (limit < 72) { code = 0; } 66 | else if (limit >= 9095) { code = 127; } 67 | else 68 | { 69 | code = ((uint32_t)limit * 768 - 55000 / 2) / 55000; 70 | if (code < 127 && (((uint32_t)55000 * (code + 1) + 384) / 768) <= limit) 71 | { 72 | code++; 73 | } 74 | } 75 | } 76 | else 77 | { 78 | code = limit / TicCurrentUnits; 79 | } 80 | 81 | commandW7(TicCommand::SetCurrentLimit, code); 82 | } 83 | 84 | uint16_t TicBase::getCurrentLimit() 85 | { 86 | uint8_t code = getVar8(VarOffset::CurrentLimit); 87 | if (product == TicProduct::T500) 88 | { 89 | if (code > 32) { code = 32; } 90 | return Tic03aCurrentTable[code]; 91 | } 92 | else if (product == TicProduct::T249) 93 | { 94 | return code * TicT249CurrentUnits; 95 | } 96 | else if (product == TicProduct::Tic36v4) 97 | { 98 | return ((uint32_t)55000 * code + 384) / 768; 99 | } 100 | else 101 | { 102 | return code * TicCurrentUnits; 103 | } 104 | } 105 | 106 | /**** TicSerial ****/ 107 | 108 | void TicSerial::commandW32(TicCommand cmd, uint32_t val) 109 | { 110 | sendCommandHeader(cmd); 111 | 112 | // byte with MSbs: 113 | // bit 0 = MSb of first (least significant) data byte 114 | // bit 1 = MSb of second data byte 115 | // bit 2 = MSb of third data byte 116 | // bit 3 = MSb of fourth (most significant) data byte 117 | serialW7(((val >> 7) & 1) | 118 | ((val >> 14) & 2) | 119 | ((val >> 21) & 4) | 120 | ((val >> 28) & 8)); 121 | 122 | serialW7(val >> 0); // least significant byte with MSb cleared 123 | serialW7(val >> 8); 124 | serialW7(val >> 16); 125 | serialW7(val >> 24); // most significant byte with MSb cleared 126 | 127 | _lastError = 0; 128 | } 129 | 130 | void TicSerial::commandW7(TicCommand cmd, uint8_t val) 131 | { 132 | sendCommandHeader(cmd); 133 | serialW7(val); 134 | 135 | _lastError = 0; 136 | } 137 | 138 | void TicSerial::getSegment(TicCommand cmd, uint8_t offset, 139 | uint8_t length, void * buffer) 140 | { 141 | length &= 0x3F; 142 | sendCommandHeader(cmd); 143 | serialW7(offset & 0x7F); 144 | serialW7(length | (offset >> 1 & 0x40)); 145 | 146 | uint8_t byteCount = _stream->readBytes((uint8_t *)buffer, length); 147 | if (byteCount != length) 148 | { 149 | _lastError = 50; 150 | 151 | // Set the buffer bytes to 0 so the program will not use an uninitialized 152 | // variable. 153 | memset(buffer, 0, length); 154 | return; 155 | } 156 | 157 | _lastError = 0; 158 | } 159 | 160 | void TicSerial::sendCommandHeader(TicCommand cmd) 161 | { 162 | if (_deviceNumber == 255) 163 | { 164 | // Compact protocol 165 | _stream->write((uint8_t)cmd); 166 | } 167 | else 168 | { 169 | // Pololu protocol 170 | _stream->write((uint8_t)0xAA); 171 | serialW7(_deviceNumber); 172 | serialW7((uint8_t)cmd); 173 | } 174 | _lastError = 0; 175 | } 176 | 177 | /**** TicI2C ****/ 178 | 179 | void TicI2C::commandQuick(TicCommand cmd) 180 | { 181 | _bus->beginTransmission(_address); 182 | _bus->write((uint8_t)cmd); 183 | _lastError = _bus->endTransmission(); 184 | } 185 | 186 | void TicI2C::commandW32(TicCommand cmd, uint32_t val) 187 | { 188 | _bus->beginTransmission(_address); 189 | _bus->write((uint8_t)cmd); 190 | _bus->write((uint8_t)(val >> 0)); // lowest byte 191 | _bus->write((uint8_t)(val >> 8)); 192 | _bus->write((uint8_t)(val >> 16)); 193 | _bus->write((uint8_t)(val >> 24)); // highest byte 194 | _lastError = _bus->endTransmission(); 195 | } 196 | 197 | void TicI2C::commandW7(TicCommand cmd, uint8_t val) 198 | { 199 | _bus->beginTransmission(_address); 200 | _bus->write((uint8_t)cmd); 201 | _bus->write((uint8_t)(val & 0x7F)); 202 | _lastError = _bus->endTransmission(); 203 | } 204 | 205 | void TicI2C::getSegment(TicCommand cmd, uint8_t offset, 206 | uint8_t length, void * buffer) 207 | { 208 | _bus->beginTransmission(_address); 209 | _bus->write((uint8_t)cmd); 210 | _bus->write(offset); 211 | _lastError = _bus->endTransmission(false); // no stop (repeated start) 212 | if (_lastError) 213 | { 214 | // Set the buffer bytes to 0 so the program will not use an uninitialized 215 | // variable. 216 | memset(buffer, 0, length); 217 | return; 218 | } 219 | 220 | uint8_t byteCount = _bus->requestFrom(_address, (uint8_t)length); 221 | if (byteCount != length) 222 | { 223 | _lastError = 50; 224 | memset(buffer, 0, length); 225 | return; 226 | } 227 | 228 | _lastError = 0; 229 | uint8_t * ptr = (uint8_t *)buffer; 230 | for (uint8_t i = 0; i < length; i++) 231 | { 232 | *ptr = _bus->read(); 233 | ptr++; 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /Tic.h: -------------------------------------------------------------------------------- 1 | // Copyright (C) Pololu Corporation. See LICENSE.txt for details. 2 | 3 | /// \file Tic.h 4 | /// 5 | /// This is the main header file for the Tic Stepper Motor Controller library 6 | /// for Arduino. 7 | /// 8 | /// For more information about the library, see the main repository at: 9 | /// https://github.com/pololu/tic-arduino 10 | 11 | #pragma once 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | enum class TicProduct 18 | { 19 | Unknown = 0, 20 | T825 = 1, 21 | T834 = 2, 22 | T500 = 3, 23 | T249 = 4, 24 | Tic36v4 = 5, 25 | }; 26 | 27 | /// This constant is used by the library to convert between milliamps and the 28 | /// Tic's native current unit, which is 32 mA. This is only valid for the Tic 29 | /// T825 and Tic T834. 30 | const uint8_t TicCurrentUnits = 32; 31 | 32 | /// This constant is used by the library to convert between milliamps and the 33 | /// Tic T249 native current unit, which is 40 mA. 34 | const uint8_t TicT249CurrentUnits = 40; 35 | 36 | /// This is used to represent a null or missing value for some of the Tic's 37 | /// 16-bit input variables. 38 | const uint16_t TicInputNull = 0xFFFF; 39 | 40 | /// This enum defines the Tic's error bits. See the "Error handling" section of 41 | /// the Tic user's guide for more information about what these errors mean. 42 | /// 43 | /// See TicBase::getErrorStatus() and TicBase::getErrorsOccurred(). 44 | enum class TicError 45 | { 46 | IntentionallyDeenergized = 0, 47 | MotorDriverError = 1, 48 | LowVin = 2, 49 | KillSwitch = 3, 50 | RequiredInputInvalid = 4, 51 | SerialError = 5, 52 | CommandTimeout = 6, 53 | SafeStartViolation = 7, 54 | ErrLineHigh = 8, 55 | SerialFraming = 16, 56 | RxOverrun = 17, 57 | Format = 18, 58 | Crc = 19, 59 | EncoderSkip = 20, 60 | }; 61 | 62 | /// This enum defines the Tic command codes which are used for its serial, I2C, 63 | /// and USB interface. These codes are used by the library and you should not 64 | /// need to use them. 65 | enum class TicCommand 66 | { 67 | SetTargetPosition = 0xE0, 68 | SetTargetVelocity = 0xE3, 69 | HaltAndSetPosition = 0xEC, 70 | HaltAndHold = 0x89, 71 | GoHome = 0x97, 72 | ResetCommandTimeout = 0x8C, 73 | Deenergize = 0x86, 74 | Energize = 0x85, 75 | ExitSafeStart = 0x83, 76 | EnterSafeStart = 0x8F, 77 | Reset = 0xB0, 78 | ClearDriverError = 0x8A, 79 | SetSpeedMax = 0xE6, 80 | SetStartingSpeed = 0xE5, 81 | SetAccelMax = 0xEA, 82 | SetDecelMax = 0xE9, 83 | SetStepMode = 0x94, 84 | SetCurrentLimit = 0x91, 85 | SetDecayMode = 0x92, 86 | SetAgcOption = 0x98, 87 | GetVariable = 0xA1, 88 | GetVariableAndClearErrorsOccurred = 0xA2, 89 | GetSetting = 0xA8, 90 | }; 91 | 92 | /// This enum defines the possible operation states for the Tic. 93 | /// 94 | /// See TicBase::getOperationState(). 95 | enum class TicOperationState 96 | { 97 | Reset = 0, 98 | Deenergized = 2, 99 | SoftError = 4, 100 | WaitingForErrLine = 6, 101 | StartingUp = 8, 102 | Normal = 10, 103 | }; 104 | 105 | /// This enum defines the possible planning modes for the Tic's step generation 106 | /// code. 107 | /// 108 | /// See TicBase::getPlanningMode(). 109 | enum class TicPlanningMode 110 | { 111 | Off = 0, 112 | TargetPosition = 1, 113 | TargetVelocity = 2, 114 | }; 115 | 116 | /// This enum defines the possible causes of a full microcontroller reset for 117 | /// the Tic. 118 | /// 119 | /// See TicBase::getDeviceReset(). 120 | enum class TicReset 121 | { 122 | PowerUp = 0, 123 | Brownout = 1, 124 | ResetLine = 2, 125 | Watchdog = 4, 126 | Software = 8, 127 | StackOverflow = 16, 128 | StackUnderflow = 32, 129 | }; 130 | 131 | /// This enum defines the possible decay modes. 132 | /// 133 | /// See TicBase::getDecayMode() and TicBase::setDecayMode(). 134 | enum class TicDecayMode 135 | { 136 | /// This specifies "Mixed" decay mode on the Tic T825 137 | /// and "Mixed 50%" on the Tic T824. 138 | Mixed = 0, 139 | 140 | /// This specifies "Slow" decay mode. 141 | Slow = 1, 142 | 143 | /// This specifies "Fast" decay mode. 144 | Fast = 2, 145 | 146 | /// This is the same as TicDecayMode::Mixed, but better expresses your 147 | /// intent if you want to use "Mixed 50%' mode on a Tic T834. 148 | Mixed50 = 0, 149 | 150 | /// This specifies "Mixed 25%" decay mode on the Tic T824 151 | /// and is the same as TicDecayMode::Mixed on the Tic T825. 152 | Mixed25 = 3, 153 | 154 | /// This specifies "Mixed 75%" decay mode on the Tic T824 155 | /// and is the same as TicDecayMode::Mixed on the Tic T825. 156 | Mixed75 = 4, 157 | }; 158 | 159 | /// This enum defines the possible step modes. 160 | /// 161 | /// See TicBase::getStepMode() and TicBase::setStepMode(). 162 | enum class TicStepMode 163 | { 164 | Full = 0, 165 | Half = 1, 166 | 167 | Microstep1 = 0, 168 | Microstep2 = 1, 169 | Microstep4 = 2, 170 | Microstep8 = 3, 171 | Microstep16 = 4, 172 | Microstep32 = 5, 173 | Microstep2_100p = 6, 174 | Microstep64 = 7, 175 | Microstep128 = 8, 176 | Microstep256 = 9, 177 | }; 178 | 179 | /// This enum defines possible AGC modes. 180 | /// 181 | /// See TicBase::setAgcMode() and TicBase::getAgcMode(). 182 | enum class TicAgcMode 183 | { 184 | Off = 0, 185 | On = 1, 186 | ActiveOff = 2, 187 | }; 188 | 189 | /// This enum defines possible AGC buttom current limit percentages. 190 | /// 191 | /// See TicBase::setAgcBottomCurrentLimit() and 192 | /// TicBase:getAgcBottomCurrentLimit(). 193 | enum class TicAgcBottomCurrentLimit 194 | { 195 | P45 = 0, 196 | P50 = 1, 197 | P55 = 2, 198 | P60 = 3, 199 | P65 = 4, 200 | P70 = 5, 201 | P75 = 6, 202 | P80 = 7, 203 | }; 204 | 205 | /// This enum defines possible AGC current boost steps values. 206 | /// 207 | /// See TicBase::setAgcCurrentBoostSteps() and 208 | /// TicBase::getAgcCurrentBoostSteps(). 209 | enum class TicAgcCurrentBoostSteps 210 | { 211 | S5 = 0, 212 | S7 = 1, 213 | S9 = 2, 214 | S11 = 3, 215 | }; 216 | 217 | /// This enuam defines possible AGC frequency limit values. 218 | /// 219 | /// See TicBase::setAgcFrequencyLimit() and TicBase::getAgcFrequencyLimit(). 220 | enum class TicAgcFrequencyLimit 221 | { 222 | Off = 0, 223 | F225Hz = 1, 224 | F450Hz = 2, 225 | F675Hz = 3, 226 | }; 227 | 228 | /// This enum defines the Tic's control pins. 229 | enum class TicPin 230 | { 231 | SCL = 0, 232 | SDA = 1, 233 | TX = 2, 234 | RX = 3, 235 | RC = 4, 236 | }; 237 | 238 | /// This enum defines the Tic's pin states. 239 | /// 240 | /// See TicBase::getPinState(). 241 | enum class TicPinState 242 | { 243 | HighImpedance = 0, 244 | InputPullUp = 1, 245 | OutputLow = 2, 246 | OutputHigh = 3, 247 | }; 248 | 249 | /// This enum defines the possible states of the Tic's main input. 250 | enum class TicInputState 251 | { 252 | /// The input is not ready yet. More samples are needed, or a command has not 253 | /// been received yet. 254 | NotReady = 0, 255 | 256 | /// The input is invalid. 257 | Invalid = 1, 258 | 259 | /// The input is valid and is telling the Tic to halt the motor. 260 | Halt = 2, 261 | 262 | /// The input is valid and is telling the Tic to go to a target position, 263 | /// which you can get with TicBase::getInputAfterScaling(). 264 | Position = 3, 265 | 266 | /// The input is valid and is telling the Tic to go to a target velocity, 267 | /// which you can get with TicBase::getInputAfterScaling(). 268 | Velocity = 4, 269 | }; 270 | 271 | /// This enum defines the bits in the Tic's Misc Flags 1 register. You should 272 | /// not need to use this directly. See TicBase::getEnergized() and 273 | /// TicBase::getPositionUncertain(). 274 | enum class TicMiscFlags1 275 | { 276 | Energized = 0, 277 | PositionUncertain = 1, 278 | ForwardLimitActive = 2, 279 | ReverseLimitActive = 3, 280 | HomingActive = 4, 281 | }; 282 | 283 | /// This enum defines possible motor driver errors for the Tic T249. 284 | /// 285 | /// See TicBase::getLastMotorDriverError(). 286 | enum class TicMotorDriverError 287 | { 288 | None = 0, 289 | OverCurrent = 1, 290 | OverTemperature = 2, 291 | }; 292 | 293 | /// This enum defines the bits in the "Last HP driver errors" variable. 294 | /// 295 | /// See TicBase::getLastHpDriverErrors(). 296 | enum class TicHpDriverError 297 | { 298 | OverTemperature = 0, 299 | OverCurrentA = 1, 300 | OverCurrentB = 2, 301 | PreDriverFaultA = 3, 302 | PreDriverFaultB = 4, 303 | UnderVoltage = 5, 304 | Verify = 7, 305 | }; 306 | 307 | /// This is a base class used to represent a connection to a Tic. This class 308 | /// provides high-level functions for sending commands to the Tic and reading 309 | /// data from it. 310 | /// 311 | /// See the subclasses of this class, TicSerial and TicI2C. 312 | class TicBase 313 | { 314 | public: 315 | /// You can use this function to specify what type of Tic you are using. 316 | /// 317 | /// Example usage (pick one of the following): 318 | /// ``` 319 | /// tic.setProduct(TicProduct::T500); 320 | /// tic.setProduct(TicProduct::T834); 321 | /// tic.setProduct(TicProduct::T825); 322 | /// tic.setProduct(TicProduct::T249); 323 | /// tic.setProduct(TicProduct::Tic36v4); 324 | /// ``` 325 | /// 326 | /// This changes the behavior of the setCurrentLimit() function. 327 | void setProduct(TicProduct product) 328 | { 329 | this->product = product; 330 | } 331 | 332 | /// Sets the target position of the Tic, in microsteps. 333 | /// 334 | /// Example usage: 335 | /// ``` 336 | /// tic.setTargetPosition(100); 337 | /// ``` 338 | /// 339 | /// This function sends a "Set target position" to the Tic. If the Control 340 | /// mode is set to Serial/I2C/USB, the Tic will start moving the motor to 341 | /// reach the target position. If the control mode is something other than 342 | /// Serial, this command will be silently ignored. 343 | /// 344 | /// See also getTargetPosition(). 345 | void setTargetPosition(int32_t position) 346 | { 347 | commandW32(TicCommand::SetTargetPosition, position); 348 | } 349 | 350 | /// Sets the target velocity of the Tic, in microsteps per 10000 seconds. 351 | /// 352 | /// Example usage: 353 | /// ``` 354 | /// tic.setTargetVelocity(-1800000); // -180 steps per second 355 | /// ``` 356 | /// 357 | /// This function sends a "Set target velocity" command to the Tic. If the 358 | /// Control mode is set to Serial/I2C/USB, the Tic will start accelerating or 359 | /// decelerating to reach the target velocity. 360 | /// 361 | /// If the control mode is something other than Serial, this command will be 362 | /// silently ignored. 363 | /// 364 | /// See also getTargetVelocity(). 365 | void setTargetVelocity(int32_t velocity) 366 | { 367 | commandW32(TicCommand::SetTargetVelocity, velocity); 368 | } 369 | 370 | /// Stops the motor abruptly without respecting the deceleration limit and 371 | /// sets the "Current position" variable, which represents where the Tic 372 | /// currently thinks the motor's output is. 373 | /// 374 | /// Example usage: 375 | /// ``` 376 | /// tic.haltAndSetPosition(0); 377 | /// ``` 378 | /// 379 | /// This function sends a "Halt and set position" command to the Tic. Besides 380 | /// stopping the motor and setting the current position, this command also 381 | /// clears the "Postion uncertain" flag, sets the "Input state" to "halt", and 382 | /// clears the "Input after scaling" variable. 383 | /// 384 | /// If the control mode is something other than Serial, this command will 385 | /// be silently ignored. 386 | void haltAndSetPosition(int32_t position) 387 | { 388 | commandW32(TicCommand::HaltAndSetPosition, position); 389 | } 390 | 391 | /// Stops the motor abruptly without respecting the deceleration limit. 392 | /// 393 | /// Example usage: 394 | /// ``` 395 | /// tic.haltAndHold(); 396 | /// ``` 397 | /// 398 | /// This function sends a "Halt and hold" command to the Tic. Besides stopping 399 | /// the motor, this command also sets the "Position uncertain" flag (because 400 | /// the abrupt stop might cause steps to be missed), sets the "Input state" to 401 | /// "halt", and clears the "Input after scaling" variable. 402 | /// 403 | /// If the control mode is something other than Serial/I2C/USB, ths 404 | /// command will be silently ignored. 405 | /// 406 | /// See also deenergize(). 407 | void haltAndHold() 408 | { 409 | commandQuick(TicCommand::HaltAndHold); 410 | } 411 | 412 | /// Tells the Tic to start its homing procedure in the reverse direction. 413 | /// 414 | /// See the "Homing" section of the Tic user's guide for details. 415 | /// 416 | /// See also goHomeForward(). 417 | void goHomeReverse() 418 | { 419 | commandW7(TicCommand::GoHome, 0); 420 | } 421 | 422 | /// Tells the Tic to start its homing procedure in the forward direction. 423 | /// 424 | /// See the "Homing" section of the Tic user's guide for details. 425 | /// 426 | /// See also goHomeReverse(). 427 | void goHomeForward() 428 | { 429 | commandW7(TicCommand::GoHome, 1); 430 | } 431 | 432 | /// Prevents the "Command timeout" error from happening for some time. 433 | /// 434 | /// Example usage: 435 | /// ``` 436 | /// tic.resetCommandTimeout(); 437 | /// ``` 438 | /// 439 | /// This function sends a "Reset command timeout" command to the Tic. 440 | void resetCommandTimeout() 441 | { 442 | commandQuick(TicCommand::ResetCommandTimeout); 443 | } 444 | 445 | /// De-energizes the stepper motor coils. 446 | /// 447 | /// Example usage: 448 | /// ``` 449 | /// tic.deenergize(); 450 | /// ``` 451 | /// 452 | /// This function sends a De-energize command to the Tic, causing it to disable 453 | /// its stepper motor driver. The motor will stop moving and consuming power. 454 | /// The Tic will set the "Intentionally de-energized" error bit, turn on its 455 | /// red LED, and drive its ERR line high. This command also sets the 456 | /// "Position uncertain" flag (because the Tic is no longer in control of the 457 | /// motor's position). 458 | /// 459 | /// Note that the Energize command, which can be sent with energize(), will 460 | /// undo the effect of this command (except it will leave the "Position 461 | /// uncertain" flag set) and could make the system start up again. 462 | /// 463 | /// See also haltAndHold(). 464 | void deenergize() 465 | { 466 | commandQuick(TicCommand::Deenergize); 467 | } 468 | 469 | /// Sends the Energize command. 470 | /// 471 | /// Example usage: 472 | /// ``` 473 | /// tic.energize(); 474 | /// ``` 475 | /// 476 | /// This function sends an Energize command to the Tic, clearing the 477 | /// "Intentionally de-energized" error bit. If there are no other errors, 478 | /// this allows the system to start up. 479 | void energize() 480 | { 481 | commandQuick(TicCommand::Energize); 482 | } 483 | 484 | /// Sends the "Exit safe start" command. 485 | /// 486 | /// Example usage: 487 | /// ``` 488 | /// tic.exitSafeStart(); 489 | /// ``` 490 | /// 491 | /// In Serial/I2C/USB control mode, this command causes the safe start 492 | /// violation error to be cleared for 200 ms. If there are no other errors, 493 | /// this allows the system to start up. 494 | void exitSafeStart() 495 | { 496 | commandQuick(TicCommand::ExitSafeStart); 497 | } 498 | 499 | /// Sends the "Enter safe start" command. 500 | /// 501 | /// Example usage: 502 | /// ``` 503 | /// tic.enterSafeStart(); 504 | /// ``` 505 | /// 506 | /// This command has no effect if safe-start is disabled in the Tic's settings. 507 | /// 508 | /// In Serial/I2C/USB control mode, this command causes the Tic to stop the 509 | /// motor and set its safe start violation error bit. An "Exit safe start" 510 | /// command is required before the Tic will move the motor again. 511 | /// 512 | /// See the Tic user's guide for information about what this command does in 513 | /// the other control modes. 514 | void enterSafeStart() 515 | { 516 | commandQuick(TicCommand::EnterSafeStart); 517 | } 518 | 519 | /// Sends the Reset command. 520 | /// 521 | /// Example usage: 522 | /// ``` 523 | /// tic.reset(); 524 | /// ``` 525 | /// 526 | /// This command makes the Tic forget most parts of its current state. For 527 | /// more information, see the Tic user's guide. 528 | void reset() 529 | { 530 | commandQuick(TicCommand::Reset); 531 | 532 | // The Tic's serial and I2C interfaces will be unreliable for a brief period 533 | // after the Tic receives the Reset command, so we delay 10 ms here. 534 | delay(10); 535 | } 536 | 537 | /// Attempts to clear a motor driver error. 538 | /// 539 | /// Example usage: 540 | /// ``` 541 | /// tic.clearDriverError(); 542 | /// ``` 543 | /// 544 | /// This function sends a "Clear driver error" command to the Tic. For more 545 | /// information, see the Tic user's guide. 546 | void clearDriverError() 547 | { 548 | commandQuick(TicCommand::ClearDriverError); 549 | } 550 | 551 | /// Temporarily sets the maximum speed, in units of steps per 10000 seconds. 552 | /// 553 | /// Example usage: 554 | /// ``` 555 | /// tic.setMaxSpeed(5550000); // 555 steps per second 556 | /// ``` 557 | /// 558 | /// This function sends a "Set max speed" command to the Tic. For more 559 | /// information, see the Tic user's guide. 560 | /// 561 | /// See also getMaxSpeed(). 562 | void setMaxSpeed(uint32_t speed) 563 | { 564 | commandW32(TicCommand::SetSpeedMax, speed); 565 | } 566 | 567 | /// Temporarily sets the starting speed, in units of steps per 10000 seconds. 568 | /// 569 | /// Example usage: 570 | /// ``` 571 | /// tic.setStartingSpeed(500000); // 50 steps per second 572 | /// ``` 573 | /// 574 | /// This function sends a "Set starting speed" command to the Tic. For more 575 | /// information, see the Tic user's guide. 576 | /// 577 | /// See also getStartingSpeed(). 578 | void setStartingSpeed(uint32_t speed) 579 | { 580 | commandW32(TicCommand::SetStartingSpeed, speed); 581 | } 582 | 583 | /// Temporarily sets the maximum acceleration, in units of steps per second 584 | /// per 100 seconds. 585 | /// 586 | /// Example usage: 587 | /// ``` 588 | /// tic.setMaxAccel(10000); // 100 steps per second per second 589 | /// ``` 590 | /// 591 | /// This function sends a "Set max acceleration" command to the Tic. For more 592 | /// information, see the Tic user's guide. 593 | /// 594 | /// See also getMaxAccel(). 595 | void setMaxAccel(uint32_t accel) 596 | { 597 | commandW32(TicCommand::SetAccelMax, accel); 598 | } 599 | 600 | /// Temporarily sets the maximum deceleration, in units of steps per second 601 | /// per 100 seconds. 602 | /// 603 | /// Example usage: 604 | /// ``` 605 | /// tic.setMaxDecel(10000); // 100 steps per second per second 606 | /// ``` 607 | /// 608 | /// This function sends a "Set max deceleration" command to the Tic. For more 609 | /// information, see the Tic user's guide. 610 | /// 611 | /// See also getMaxDecel(). 612 | void setMaxDecel(uint32_t decel) 613 | { 614 | commandW32(TicCommand::SetDecelMax, decel); 615 | } 616 | 617 | /// Temporarily sets the stepper motor's step mode, which defines how many 618 | /// microsteps correspond to one full step. 619 | /// 620 | /// Example usage: 621 | /// ``` 622 | /// tic.setStepMode(TicStepMode::Microstep8); 623 | /// ``` 624 | /// 625 | /// This function sends a "Set step mode" command to the Tic. For more 626 | /// information, see the Tic user's guide. 627 | /// 628 | /// See also getStepMode(). 629 | void setStepMode(TicStepMode mode) 630 | { 631 | commandW7(TicCommand::SetStepMode, (uint8_t)mode); 632 | } 633 | 634 | /// Temporarily sets the stepper motor coil current limit in milliamps. If 635 | /// the desired current limit is not available, this function uses the closest 636 | /// current limit that is lower than the desired one. 637 | /// 638 | /// When converting the current limit from milliamps to a code to send to the 639 | /// Tic, this function needs to know what kind of Tic you are using. By 640 | /// default, this function assumes you are using a Tic T825 or Tic T834. If 641 | /// you are using a different kind of Tic, we recommend calling setProduct() 642 | /// some time before calling setCurrentLimit(). 643 | /// 644 | /// Example usage: 645 | /// ``` 646 | /// tic.setCurrentLimit(500); // 500 mA 647 | /// ``` 648 | /// 649 | /// This function sends a "Set current limit" command to the Tic. For more 650 | /// information about this command and how to choose a good current limit, see 651 | /// the Tic user's guide. 652 | /// 653 | /// See also getCurrentLimit(). 654 | void setCurrentLimit(uint16_t limit); 655 | 656 | /// Temporarily sets the stepper motor driver's decay mode. 657 | /// 658 | /// Example usage: 659 | /// ``` 660 | /// tic.setDecayMode(TicDecayMode::Slow); 661 | /// ``` 662 | /// 663 | /// The decay modes are documented in the Tic user's guide. 664 | /// 665 | /// See also getDecayMode(). 666 | void setDecayMode(TicDecayMode mode) 667 | { 668 | commandW7(TicCommand::SetDecayMode, (uint8_t)mode); 669 | } 670 | 671 | /// Temporarily sets the AGC mode. 672 | /// 673 | /// This is only valid for the Tic T249. 674 | /// 675 | /// See also getAgcMode(). 676 | void setAgcMode(TicAgcMode mode) 677 | { 678 | commandW7(TicCommand::SetAgcOption, (uint8_t)mode & 0xF); 679 | } 680 | 681 | /// Temporarily sets the AGC bottom current limit. 682 | /// 683 | /// This is only valid for the Tic T249. 684 | /// 685 | /// See also getAgcBottomCurrentLimit(). 686 | void setAgcBottomCurrentLimit(TicAgcBottomCurrentLimit limit) 687 | { 688 | commandW7(TicCommand::SetAgcOption, 0x10 | ((uint8_t)limit & 0xF)); 689 | } 690 | 691 | /// Temporarily sets the AGC current boost steps. 692 | /// 693 | /// This is only valid for the Tic T249. 694 | /// 695 | /// See also getAgcCurrentBoostSteps(). 696 | void setAgcCurrentBoostSteps(TicAgcCurrentBoostSteps steps) 697 | { 698 | commandW7(TicCommand::SetAgcOption, 0x20 | ((uint8_t)steps & 0xF)); 699 | } 700 | 701 | /// Temporarily sets the AGC frequency limit. 702 | /// 703 | /// This is only valid for the Tic T249. 704 | /// 705 | /// See also getAgcFrequencyLimit(). 706 | void setAgcFrequencyLimit(TicAgcFrequencyLimit limit) 707 | { 708 | commandW7(TicCommand::SetAgcOption, 0x30 | ((uint8_t)limit & 0xF)); 709 | } 710 | 711 | /// Gets the Tic's current operation state, which indicates whether it is 712 | /// operating normally or in an error state. 713 | /// 714 | /// Example usage: 715 | /// ``` 716 | /// if (tic.getOperationState() != TicOperationState::Normal) 717 | /// { 718 | /// // There is an error, or the Tic is starting up. 719 | /// } 720 | /// ``` 721 | /// 722 | /// For more information, see the "Error handling" section of the Tic user's 723 | /// guide. 724 | TicOperationState getOperationState() 725 | { 726 | return (TicOperationState)getVar8(VarOffset::OperationState); 727 | } 728 | 729 | /// Returns true if the motor driver is energized (trying to send current to 730 | /// its outputs). 731 | bool getEnergized() 732 | { 733 | return getVar8(VarOffset::MiscFlags1) >> 734 | (uint8_t)TicMiscFlags1::Energized & 1; 735 | } 736 | 737 | /// Gets a flag that indicates whether there has been external confirmation that 738 | /// the value of the Tic's "Current position" variable is correct. 739 | /// 740 | /// For more information, see the "Error handling" section of the Tic user's 741 | /// guide. 742 | bool getPositionUncertain() 743 | { 744 | return getVar8(VarOffset::MiscFlags1) >> 745 | (uint8_t)TicMiscFlags1::PositionUncertain & 1; 746 | } 747 | 748 | /// Returns true if one of the forward limit switches is active. 749 | bool getForwardLimitActive() 750 | { 751 | return getVar8(VarOffset::MiscFlags1) >> 752 | (uint8_t)TicMiscFlags1::ForwardLimitActive & 1; 753 | } 754 | 755 | /// Returns true if one of the reverse limit switches is active. 756 | bool getReverseLimitActive() 757 | { 758 | return getVar8(VarOffset::MiscFlags1) >> 759 | (uint8_t)TicMiscFlags1::ReverseLimitActive & 1; 760 | } 761 | 762 | /// Returns true if the Tic's homing procedure is running. 763 | bool getHomingActive() 764 | { 765 | return getVar8(VarOffset::MiscFlags1) >> 766 | (uint8_t)TicMiscFlags1::HomingActive & 1; 767 | } 768 | 769 | /// Gets the errors that are currently stopping the motor. 770 | /// 771 | /// Each bit in the returned register represents a different error. The bits 772 | /// are defined in ::TicError enum. 773 | /// 774 | /// Example usage: 775 | /// ``` 776 | /// uint16_t errors = tic.getErrorStatus(); 777 | /// if (errors & (1 << (uint8_t)TicError::LowVin)) 778 | /// { 779 | /// // handle loss of power 780 | /// } 781 | /// ``` 782 | uint16_t getErrorStatus() 783 | { 784 | return getVar16(VarOffset::ErrorStatus); 785 | } 786 | 787 | /// Gets the errors that have occurred since the last time this function was called. 788 | /// 789 | /// Note that the Tic Control Center constantly clears the bits in this 790 | /// register, so if you are running the Tic Control Center then you will not 791 | /// be able to reliably detect errors with this function. 792 | /// 793 | /// Each bit in the returned register represents a different error. The bits 794 | /// are defined in ::TicError enum. 795 | /// 796 | /// Example usage: 797 | /// ``` 798 | /// uint32_t errors = tic.getErrorsOccurred(); 799 | /// if (errors & (1 << (uint8_t)TicError::MotorDriverError)) 800 | /// { 801 | /// // handle a motor driver error 802 | /// } 803 | /// ``` 804 | uint32_t getErrorsOccurred() 805 | { 806 | uint32_t result; 807 | getSegment(TicCommand::GetVariableAndClearErrorsOccurred, 808 | VarOffset::ErrorsOccurred, 4, &result); 809 | return result; 810 | } 811 | 812 | /// Returns the current planning mode for the Tic's step generation code. 813 | /// 814 | /// This tells us whether the Tic is sending steps, and if it is sending 815 | /// steps, tells us whether it is in Target Position or Target Velocity mode. 816 | /// 817 | /// Example usage: 818 | /// ``` 819 | /// if (tic.getPlanningMode() == TicPlanningMode::TargetPosition) 820 | /// { 821 | /// // The Tic is moving the stepper motor to a target position, or has 822 | /// // already reached it and is at rest. 823 | /// } 824 | /// ``` 825 | TicPlanningMode getPlanningMode() 826 | { 827 | return (TicPlanningMode)getVar8(VarOffset::PlanningMode); 828 | } 829 | 830 | /// Gets the target position, in microsteps. 831 | /// 832 | /// This is only relevant if the planning mode from getPlanningMode() is 833 | /// TicPlanningMode::Position. 834 | /// 835 | /// See also setTargetPosition(). 836 | int32_t getTargetPosition() 837 | { 838 | return getVar32(VarOffset::TargetPosition); 839 | } 840 | 841 | /// Gets the target velocity, in microsteps per 10000 seconds. 842 | /// 843 | /// This is only relevant if the planning mode from getPlanningMode() is 844 | /// TicPlanningMode::Velocity. 845 | /// 846 | /// See also setTargetVelocity(). 847 | int32_t getTargetVelocity() 848 | { 849 | return getVar32(VarOffset::TargetVelocity); 850 | } 851 | 852 | /// Gets the current maximum speed, in microsteps per 10000 seconds. 853 | /// 854 | /// This is the current value, which could differ from the value in the Tic's 855 | /// settings. 856 | /// 857 | /// See also setMaxSpeed(). 858 | uint32_t getMaxSpeed() 859 | { 860 | return getVar32(VarOffset::SpeedMax); 861 | } 862 | 863 | /// Gets the starting speed in microsteps per 10000 seconds. 864 | /// 865 | /// This is the current value, which could differ from the value in the 866 | /// Tic's settings. 867 | /// 868 | /// Example usage: 869 | /// ``` 870 | /// uint32_t startingSpeed = tic.getStartingSpeed(); 871 | /// ``` 872 | /// 873 | /// See also setStartingSpeed(). 874 | uint32_t getStartingSpeed() 875 | { 876 | return getVar32(VarOffset::StartingSpeed); 877 | } 878 | 879 | /// Gets the maximum acceleration, in microsteps per second per 100 seconds. 880 | /// 881 | /// This is the current value, which could differ from the value in the Tic's 882 | /// settings. 883 | /// 884 | /// Example usage: 885 | /// ``` 886 | /// uint32_t accelMax = tic.getMaxAccel(); 887 | /// ``` 888 | /// 889 | /// See also setMaxAccel(). 890 | uint32_t getMaxAccel() 891 | { 892 | return getVar32(VarOffset::AccelMax); 893 | } 894 | 895 | /// Gets the maximum deceleration, in microsteps per second per 100 seconds. 896 | /// 897 | /// This is the current value, which could differ from the value in the Tic's 898 | /// settings. 899 | /// 900 | /// Example usage: 901 | /// ``` 902 | /// uint32_t decelMax = tic.getMaxDecel(); 903 | /// ``` 904 | /// 905 | /// See also setMaxDecel(). 906 | uint32_t getMaxDecel() 907 | { 908 | return getVar32(VarOffset::DecelMax); 909 | } 910 | 911 | /// Gets the current position of the stepper motor, in microsteps. 912 | /// 913 | /// Note that this just tracks steps that the Tic has commanded the stepper 914 | /// driver to take; it could be different from the actual position of the 915 | /// motor for various reasons. 916 | /// 917 | /// For an example of how to use this this, see the SerialPositionControl 918 | /// example or the I2CPositionControl exmaple. 919 | /// 920 | /// See also haltAndSetPosition(). 921 | int32_t getCurrentPosition() 922 | { 923 | return getVar32(VarOffset::CurrentPosition); 924 | } 925 | 926 | /// Gets the current velocity of the stepper motor, in microsteps per 10000 927 | /// seconds. 928 | /// 929 | /// Note that this is just the velocity used in the Tic's step planning 930 | /// algorithms, and it might not correspond to the actual velocity of the 931 | /// motor for various reasons. 932 | /// 933 | /// Example usage: 934 | /// ``` 935 | /// int32_t velocity = tic.getCurrentVelocity(); 936 | /// ``` 937 | int32_t getCurrentVelocity() 938 | { 939 | return getVar32(VarOffset::CurrentVelocity); 940 | } 941 | 942 | /// Gets the acting target position, in microsteps. 943 | /// 944 | /// This is a variable used in the Tic's target position step planning 945 | /// algorithm, and it could be invalid while the motor is stopped. 946 | /// 947 | /// This is mainly intended for getting insight into how the Tic's algorithms 948 | /// work or troubleshooting issues, and most people should not use this. 949 | uint32_t getActingTargetPosition() 950 | { 951 | return getVar32(VarOffset::ActingTargetPosition); 952 | } 953 | 954 | /// Gets the time since the last step, in timer ticks. 955 | /// 956 | /// Each timer tick represents one third of a microsecond. The Tic only 957 | /// updates this variable every 5 milliseconds or so, and it could be invalid 958 | /// while the motor is stopped. 959 | /// 960 | /// This is mainly intended for getting insight into how the Tic's algorithms 961 | /// work or troubleshooting issues, and most people should not use this. 962 | uint32_t getTimeSinceLastStep() 963 | { 964 | return getVar32(VarOffset::TimeSinceLastStep); 965 | } 966 | 967 | /// Gets the cause of the controller's last full microcontroller reset. 968 | /// 969 | /// Example usage: 970 | /// ``` 971 | /// if (tic.getDeviceReset() == TicReset::Brownout) 972 | /// { 973 | /// // There was a brownout reset; the power supply could not keep up. 974 | /// } 975 | /// ``` 976 | /// 977 | /// The Reset command (reset()) does not affect this variable. 978 | TicReset getDeviceReset() 979 | { 980 | return (TicReset)getVar8(VarOffset::DeviceReset); 981 | } 982 | 983 | /// Gets the current measurement of the VIN voltage, in millivolts. 984 | /// 985 | /// Example usage: 986 | /// ``` 987 | /// uint16_t power = tic.getVinVoltage(); 988 | /// ``` 989 | uint16_t getVinVoltage() 990 | { 991 | return getVar16(VarOffset::VinVoltage); 992 | } 993 | 994 | /// Gets the time since the last full reset of the Tic's microcontroller, in 995 | /// milliseconds. 996 | /// 997 | /// Example usage: 998 | /// ``` 999 | /// uint32_t upTime = tic.getUpTime(); 1000 | /// ``` 1001 | /// 1002 | /// A Reset command (reset())does not count. 1003 | uint32_t getUpTime() 1004 | { 1005 | return getVar32(VarOffset::UpTime); 1006 | } 1007 | 1008 | /// Gets the raw encoder count measured from the Tic's RX and TX lines. 1009 | /// 1010 | /// Example usage: 1011 | /// ``` 1012 | /// int32_t encoderPosition = getEncoderPosition(); 1013 | /// ``` 1014 | int32_t getEncoderPosition() 1015 | { 1016 | return getVar32(VarOffset::EncoderPosition); 1017 | } 1018 | 1019 | /// Gets the raw pulse width measured on the Tic's RC input, in units of 1020 | /// twelfths of a microsecond. 1021 | /// 1022 | /// Returns TicInputNull if the RC input is missing or invalid. 1023 | /// 1024 | /// Example usage: 1025 | /// ``` 1026 | /// uint16_t pulseWidth = tic.getRCPulseWidth(); 1027 | /// if (pulseWidth != TicInputNull && pulseWidth > 18000) 1028 | /// { 1029 | /// // Pulse width is greater than 1500 microseconds. 1030 | /// } 1031 | /// ``` 1032 | uint16_t getRCPulseWidth() 1033 | { 1034 | return getVar16(VarOffset::RCPulseWidth); 1035 | } 1036 | 1037 | /// Gets the analog reading from the specified pin. 1038 | /// 1039 | /// The reading is left-justified, so 0xFFFF represents a voltage equal to the 1040 | /// Tic's 5V pin (approximately 4.8 V). 1041 | /// 1042 | /// Returns TicInputNull if the analog reading is disabled or not ready. 1043 | /// 1044 | /// Example usage: 1045 | /// ``` 1046 | /// uint16_t reading = getAnalogReading(TicPin::SDA); 1047 | /// if (reading != TicInputNull && reading < 32768) 1048 | /// { 1049 | /// // The reading is less than about 2.4 V. 1050 | /// } 1051 | /// ``` 1052 | uint16_t getAnalogReading(TicPin pin) 1053 | { 1054 | uint8_t offset = VarOffset::AnalogReadingSCL + 2 * (uint8_t)pin; 1055 | return getVar16(offset); 1056 | } 1057 | 1058 | /// Gets a digital reading from the specified pin. 1059 | /// 1060 | /// Returns `true` for high and `false` for low. 1061 | /// 1062 | /// Example usage: 1063 | /// ``` 1064 | /// if (tic.getDigitalReading(TicPin::RC)) 1065 | /// { 1066 | /// // Something is driving the RC pin high. 1067 | /// } 1068 | /// ``` 1069 | bool getDigitalReading(TicPin pin) 1070 | { 1071 | uint8_t readings = getVar8(VarOffset::DigitalReadings); 1072 | return (readings >> (uint8_t)pin) & 1; 1073 | } 1074 | 1075 | /// Gets the current state of a pin, i.e. what kind of input or output it is. 1076 | /// 1077 | /// Note that the state might be misleading if the pin is being used as a 1078 | /// serial or I2C pin. 1079 | /// 1080 | /// Example usage: 1081 | /// 1082 | /// ``` 1083 | /// if (tic.getPinState(TicPin::SCL) == TicPinState::OutputHigh) 1084 | /// { 1085 | /// // SCL is driving high. 1086 | /// } 1087 | /// ``` 1088 | TicPinState getPinState(TicPin pin) 1089 | { 1090 | uint8_t states = getVar8(VarOffset::PinStates); 1091 | return (TicPinState)(states >> (2 * (uint8_t)pin) & 0b11); 1092 | } 1093 | 1094 | /// Gets the current step mode of the stepper motor. 1095 | /// 1096 | /// Example usage: 1097 | /// ``` 1098 | /// if (tic.getStepMode() == TicStepMode::Microstep8) 1099 | /// { 1100 | /// // The Tic is currently using 1/8 microsteps. 1101 | /// } 1102 | /// ``` 1103 | TicStepMode getStepMode() 1104 | { 1105 | return (TicStepMode)getVar8(VarOffset::StepMode); 1106 | } 1107 | 1108 | /// Gets the stepper motor coil current limit in milliamps. 1109 | /// 1110 | /// This is the value being used now, which could differ from the value in the 1111 | /// Tic's settings. 1112 | /// 1113 | /// Example usage: 1114 | /// ``` 1115 | /// uint16_t current = tic.getCurrentLimit(); 1116 | /// ``` 1117 | /// 1118 | /// By default, this function assumes you are using a Tic T825 or Tic T834. 1119 | /// If you are using a different kind of Tic, we recommend calling 1120 | /// setProduct() some time before calling getCurrentLimit(). 1121 | /// 1122 | /// See also setCurrentLimit(). 1123 | uint16_t getCurrentLimit(); 1124 | 1125 | /// Gets the current decay mode of the stepper motor driver. 1126 | /// 1127 | /// Example usage: 1128 | /// ``` 1129 | /// if (tic.getDecayMode() == TicDecayMode::Slow) 1130 | /// { 1131 | /// // The Tic is in slow decay mode. 1132 | /// } 1133 | /// ``` 1134 | /// 1135 | /// See setDecayMode(). 1136 | TicDecayMode getDecayMode() 1137 | { 1138 | return (TicDecayMode)getVar8(VarOffset::DecayMode); 1139 | } 1140 | 1141 | /// Gets the current state of the Tic's main input. 1142 | /// 1143 | /// Example usage: 1144 | /// ``` 1145 | /// if (tic.getInputState() == TicInputState::Position) 1146 | /// { 1147 | /// // The Tic's input is specifying a target position. 1148 | /// } 1149 | /// ``` 1150 | /// 1151 | /// See TicInputState for more information. 1152 | TicInputState getInputState() 1153 | { 1154 | return (TicInputState)getVar8(VarOffset::InputState); 1155 | } 1156 | 1157 | /// Gets a variable used in the process that converts raw RC and analog values 1158 | /// into a motor position or speed. This is mainly for debugging your input 1159 | /// scaling settings in an RC or analog mode. 1160 | /// 1161 | /// A value of TicInputNull means the input value is not available. 1162 | uint16_t getInputAfterAveraging() 1163 | { 1164 | return getVar16(VarOffset::InputAfterAveraging); 1165 | } 1166 | 1167 | /// Gets a variable used in the process that converts raw RC and analog values 1168 | /// into a motor position or speed. This is mainly for debugging your input 1169 | /// scaling settings in an RC or analog mode. 1170 | /// 1171 | /// A value of TicInputNull means the input value is not available. 1172 | uint16_t getInputAfterHysteresis() 1173 | { 1174 | return getVar16(VarOffset::InputAfterHysteresis); 1175 | } 1176 | 1177 | /// Gets the value of the Tic's main input after scaling has been applied. 1178 | /// 1179 | /// If the input is valid, this number is the target position or target 1180 | /// velocity specified by the input. 1181 | /// 1182 | /// Example usage: 1183 | /// ``` 1184 | /// if (tic.getInputAfter 1185 | /// ``` 1186 | /// 1187 | /// See also getInputState(). 1188 | int32_t getInputAfterScaling() 1189 | { 1190 | return getVar32(VarOffset::InputAfterScaling); 1191 | } 1192 | 1193 | /// Gets the cause of the last motor driver error. 1194 | /// 1195 | /// This is only valid for the Tic T249. 1196 | TicMotorDriverError getLastMotorDriverError() 1197 | { 1198 | return (TicMotorDriverError)getVar8(VarOffset::LastMotorDriverError); 1199 | } 1200 | 1201 | /// Gets the AGC mode. 1202 | /// 1203 | /// This is only valid for the Tic T249. 1204 | /// 1205 | /// See also setAgcMode(). 1206 | TicAgcMode getAgcMode() 1207 | { 1208 | return (TicAgcMode)getVar8(VarOffset::AgcMode); 1209 | } 1210 | 1211 | /// Gets the AGC bottom current limit. 1212 | /// 1213 | /// This is only valid for the Tic T249. 1214 | /// 1215 | /// See also setAgcBottomCurrentLimit(). 1216 | TicAgcBottomCurrentLimit getAgcBottomCurrentLimit() 1217 | { 1218 | return (TicAgcBottomCurrentLimit)getVar8(VarOffset::AgcBottomCurrentLimit); 1219 | } 1220 | 1221 | /// Gets the AGC current boost steps. 1222 | /// 1223 | /// This is only valid for the Tic T249. 1224 | /// 1225 | /// See also setAgcCurrentBoostSteps(). 1226 | TicAgcCurrentBoostSteps getAgcCurrentBoostSteps() 1227 | { 1228 | return (TicAgcCurrentBoostSteps)getVar8(VarOffset::AgcCurrentBoostSteps); 1229 | } 1230 | 1231 | /// Gets the AGC frequency limit. 1232 | /// 1233 | /// This is only valid for the Tic T249. 1234 | /// 1235 | /// See also setAgcFrequencyLimit(). 1236 | TicAgcFrequencyLimit getAgcFrequencyLimit() 1237 | { 1238 | return (TicAgcFrequencyLimit)getVar8(VarOffset::AgcFrequencyLimit); 1239 | } 1240 | 1241 | /// Gets the "Last HP driver errors" variable. 1242 | /// 1243 | /// Each bit in this register represents an error. If the bit is 1, the 1244 | /// error was one of the causes of the Tic's last motor driver error. 1245 | /// 1246 | /// This is only valid for the Tic 36v4. 1247 | uint8_t getLastHpDriverErrors() 1248 | { 1249 | return getVar8(VarOffset::LastHpDriverErrors); 1250 | } 1251 | 1252 | /// Gets a contiguous block of settings from the Tic's EEPROM. 1253 | /// 1254 | /// The maximum length that can be fetched is 15 bytes. 1255 | /// 1256 | /// Example usage: 1257 | /// ``` 1258 | /// // Get the Tic's serial device number. 1259 | /// uint8_t deviceNumber; 1260 | /// tic.getSetting(7, 1, &deviceNumber); 1261 | /// ``` 1262 | /// 1263 | /// This library does not attempt to interpret the settings and say what they 1264 | /// mean. If you are interested in how the settings are encoded in the Tic's 1265 | /// EEPROM, see the "Settings reference" section of the Tic user's guide. 1266 | void getSetting(uint8_t offset, uint8_t length, uint8_t * buffer) 1267 | { 1268 | getSegment(TicCommand::GetSetting, offset, length, buffer); 1269 | } 1270 | 1271 | /// Returns 0 if the last communication with the device was successful, and 1272 | /// non-zero if there was an error. 1273 | uint8_t getLastError() 1274 | { 1275 | return _lastError; 1276 | } 1277 | 1278 | protected: 1279 | /// Zero if the last communication with the device was successful, non-zero 1280 | /// otherwise. 1281 | uint8_t _lastError = 0; 1282 | 1283 | private: 1284 | enum VarOffset 1285 | { 1286 | OperationState = 0x00, // uint8_t 1287 | MiscFlags1 = 0x01, // uint8_t 1288 | ErrorStatus = 0x02, // uint16_t 1289 | ErrorsOccurred = 0x04, // uint32_t 1290 | PlanningMode = 0x09, // uint8_t 1291 | TargetPosition = 0x0A, // int32_t 1292 | TargetVelocity = 0x0E, // int32_t 1293 | StartingSpeed = 0x12, // uint32_t 1294 | SpeedMax = 0x16, // uint32_t 1295 | DecelMax = 0x1A, // uint32_t 1296 | AccelMax = 0x1E, // uint32_t 1297 | CurrentPosition = 0x22, // int32_t 1298 | CurrentVelocity = 0x26, // int32_t 1299 | ActingTargetPosition = 0x2A, // int32_t 1300 | TimeSinceLastStep = 0x2E, // uint32_t 1301 | DeviceReset = 0x32, // uint8_t 1302 | VinVoltage = 0x33, // uint16_t 1303 | UpTime = 0x35, // uint32_t 1304 | EncoderPosition = 0x39, // int32_t 1305 | RCPulseWidth = 0x3D, // uint16_t 1306 | AnalogReadingSCL = 0x3F, // uint16_t 1307 | AnalogReadingSDA = 0x41, // uint16_t 1308 | AnalogReadingTX = 0x43, // uint16_t 1309 | AnalogReadingRX = 0x45, // uint16_t 1310 | DigitalReadings = 0x47, // uint8_t 1311 | PinStates = 0x48, // uint8_t 1312 | StepMode = 0x49, // uint8_t 1313 | CurrentLimit = 0x4A, // uint8_t 1314 | DecayMode = 0x4B, // uint8_t 1315 | InputState = 0x4C, // uint8_t 1316 | InputAfterAveraging = 0x4D, // uint16_t 1317 | InputAfterHysteresis = 0x4F, // uint16_t 1318 | InputAfterScaling = 0x51, // uint16_t 1319 | LastMotorDriverError = 0x55, // uint8_t 1320 | AgcMode = 0x56, // uint8_t 1321 | AgcBottomCurrentLimit = 0x57, // uint8_t 1322 | AgcCurrentBoostSteps = 0x58, // uint8_t 1323 | AgcFrequencyLimit = 0x59, // uint8_t 1324 | LastHpDriverErrors = 0xFF, // uint8_t 1325 | }; 1326 | 1327 | uint8_t getVar8(uint8_t offset) 1328 | { 1329 | uint8_t result; 1330 | getSegment(TicCommand::GetVariable, offset, 1, &result); 1331 | return result; 1332 | } 1333 | 1334 | uint16_t getVar16(uint8_t offset) 1335 | { 1336 | uint8_t buffer[2]; 1337 | getSegment(TicCommand::GetVariable, offset, 2, &buffer); 1338 | return ((uint16_t)buffer[0] << 0) | ((uint16_t)buffer[1] << 8); 1339 | } 1340 | 1341 | uint32_t getVar32(uint8_t offset) 1342 | { 1343 | uint8_t buffer[4]; 1344 | getSegment(TicCommand::GetVariable, offset, 4, buffer); 1345 | return ((uint32_t)buffer[0] << 0) | 1346 | ((uint32_t)buffer[1] << 8) | 1347 | ((uint32_t)buffer[2] << 16) | 1348 | ((uint32_t)buffer[3] << 24); 1349 | } 1350 | 1351 | virtual void commandQuick(TicCommand cmd) = 0; 1352 | virtual void commandW32(TicCommand cmd, uint32_t val) = 0; 1353 | virtual void commandW7(TicCommand cmd, uint8_t val) = 0; 1354 | virtual void getSegment(TicCommand cmd, uint8_t offset, 1355 | uint8_t length, void * buffer); 1356 | 1357 | TicProduct product = TicProduct::Unknown; 1358 | }; 1359 | 1360 | /// Represents a serial connection to a Tic. 1361 | /// 1362 | /// For the high-level commands you can use on this object, see TicBase. 1363 | class TicSerial : public TicBase 1364 | { 1365 | public: 1366 | /// Creates a new TicSerial object. 1367 | /// 1368 | /// The `stream` argument should be a hardware or software serial object. 1369 | /// This class will store a pointer to it and use it to communicate with the 1370 | /// Tic. You should initialize it and set it to use the correct baud rate 1371 | /// before sending commands with this class. 1372 | /// 1373 | /// The `deviceNumber` argument is optional. If it is omitted or 255, the 1374 | /// TicSerial object will use the compact protocol. If it is a number between 1375 | /// 0 and 127, it specifies the device number to use in Pololu protocol, 1376 | /// allowing you to control multiple Tic controllers on a single serial bus. 1377 | /// 1378 | /// For example, to use the first open hardware serial port to send compact 1379 | /// protocol commands to one Tic, write this at the top of your sketch: 1380 | /// ``` 1381 | /// TicSerial tic(SERIAL_PORT_HARDWARE_OPEN); 1382 | /// ``` 1383 | /// 1384 | /// For example, to use a SoftwareSerial port and send Pololu protocol 1385 | /// commands to two different Tic controllers, write this at the top of your sketch: 1386 | /// 1387 | /// ``` 1388 | /// #include 1389 | /// SoftwareSerial ticSerial(10, 11); 1390 | /// TicSerial tic1(ticSerial, 14); 1391 | /// TicSerial tic2(ticSerial, 15); 1392 | /// ``` 1393 | TicSerial(Stream & stream, uint8_t deviceNumber = 255) : 1394 | _stream(&stream), 1395 | _deviceNumber(deviceNumber) 1396 | { 1397 | } 1398 | 1399 | /// Gets the serial device number specified in the constructor. 1400 | uint8_t getDeviceNumber() { return _deviceNumber; } 1401 | 1402 | private: 1403 | Stream * const _stream; 1404 | const uint8_t _deviceNumber; 1405 | 1406 | void commandQuick(TicCommand cmd) { sendCommandHeader(cmd); } 1407 | void commandW32(TicCommand cmd, uint32_t val); 1408 | void commandW7(TicCommand cmd, uint8_t val); 1409 | uint8_t commandR8(TicCommand cmd); 1410 | void getSegment(TicCommand cmd, uint8_t offset, 1411 | uint8_t length, void * buffer); 1412 | 1413 | void sendCommandHeader(TicCommand cmd); 1414 | void serialW7(uint8_t val) { _stream->write((uint8_t)(val & 0x7F)); } 1415 | }; 1416 | 1417 | /// Represents an I2C connection to a Tic. 1418 | /// 1419 | /// For the high-level commands you can use on this object, see TicBase. 1420 | class TicI2C : public TicBase 1421 | { 1422 | public: 1423 | /// Creates a new TicI2C object that will use the `Wire` object to communicate 1424 | /// with the Tic over I2C. 1425 | /// 1426 | /// The optional `address` parameter specifies the 7-bit I2C address to use, 1427 | /// and it must match the Tic's "Device number" setting. It defaults to 14. 1428 | /// 1429 | /// The optional `bus` parameter specifies the I2C bus to use. You can also 1430 | /// set the bus with setBus(). 1431 | TicI2C(uint8_t address = 14, TwoWire * bus = &Wire) 1432 | : _address(address), _bus(bus) 1433 | { 1434 | } 1435 | 1436 | /// Configures this object to use the specified I2C bus. 1437 | /// The default bus is Wire, which is typically the first or only I2C bus on 1438 | /// an Arduino. To use Wire1 instead, you can write: 1439 | /// ```{.cpp} 1440 | /// tic.setBus(&Wire1); 1441 | /// ``` 1442 | /// \param bus A pointer to a TwoWire object representing the I2C bus to use. 1443 | void setBus(TwoWire * bus) 1444 | { 1445 | this->_bus = bus; 1446 | } 1447 | 1448 | /// Returns a pointer to the I2C bus that this object is configured to 1449 | /// use. 1450 | TwoWire * getBus() 1451 | { 1452 | return _bus; 1453 | } 1454 | 1455 | /// Configures this object to use the specified 7-bit I2C address. 1456 | /// This must match the address that the Motoron is configured to use. 1457 | void setAddress(uint8_t address) 1458 | { 1459 | this->_address = address; 1460 | } 1461 | 1462 | /// Returns the 7-bit I2C address that this object is configured to use. 1463 | uint8_t getAddress() 1464 | { 1465 | return _address; 1466 | } 1467 | 1468 | private: 1469 | uint8_t _address; 1470 | TwoWire * _bus; 1471 | 1472 | void commandQuick(TicCommand cmd); 1473 | void commandW32(TicCommand cmd, uint32_t val); 1474 | void commandW7(TicCommand cmd, uint8_t val); 1475 | void getSegment(TicCommand cmd, uint8_t offset, 1476 | uint8_t length, void * buffer); 1477 | void delayAfterRead(); 1478 | }; 1479 | -------------------------------------------------------------------------------- /examples/I2CMulti/I2CMulti.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send I2C commands to two Tic Stepper 2 | // Motor Controllers on the same I2C bus. 3 | // 4 | // Each Tic's control mode must be set to "Serial/I2C/USB". The 5 | // serial device number of one Tic must be set to its default 6 | // value of 14, and the serial device number of another Tic must 7 | // be set to 15. 8 | // 9 | // The GND, SCL, and SDA pins of the Arduino must each be 10 | // connected to the corresponding pins on each Tic. You might 11 | // consider connecting the ERR lines of both Tics so that if 12 | // either one experiences an error, both of them will shut down 13 | // until you reset the Arduino. 14 | // 15 | // See the comments and instructions in I2CSpeedControl.ino for 16 | // more information. 17 | 18 | #include 19 | 20 | TicI2C tic1(14); 21 | TicI2C tic2(15); 22 | 23 | void setup() 24 | { 25 | Wire.begin(); 26 | delay(20); 27 | 28 | tic1.exitSafeStart(); 29 | tic2.exitSafeStart(); 30 | } 31 | 32 | void resetCommandTimeout() 33 | { 34 | tic1.resetCommandTimeout(); 35 | tic2.resetCommandTimeout(); 36 | } 37 | 38 | 39 | void delayWhileResettingCommandTimeout(uint32_t ms) 40 | { 41 | uint32_t start = millis(); 42 | do 43 | { 44 | resetCommandTimeout(); 45 | } while ((uint32_t)(millis() - start) <= ms); 46 | } 47 | 48 | void loop() 49 | { 50 | tic1.setTargetVelocity(2000000); 51 | tic2.setTargetVelocity(0); 52 | delayWhileResettingCommandTimeout(1000); 53 | 54 | tic1.setTargetVelocity(0); 55 | tic2.setTargetVelocity(1000000); 56 | delayWhileResettingCommandTimeout(1000); 57 | 58 | tic1.setTargetVelocity(-1000000); 59 | tic2.setTargetVelocity(0); 60 | delayWhileResettingCommandTimeout(1000); 61 | 62 | tic1.setTargetVelocity(0); 63 | tic2.setTargetVelocity(-2000000); 64 | delayWhileResettingCommandTimeout(1000); 65 | } 66 | -------------------------------------------------------------------------------- /examples/I2CPositionControl/I2CPositionControl.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send I2C commands to the Tic 2 | // Stepper Motor Controller to control the position of a Stepper 3 | // Motor. 4 | // 5 | // The Tic's control mode must be set to "Serial/I2C/USB". The 6 | // serial device number must be set to its default value of 14. 7 | // 8 | // If you have sent a De-energize command to the Tic, for example 9 | // by clicking "De-energize" in the Tic Control Center, you will 10 | // need to undo that by clicking "Resume" or power-cycling the 11 | // Tic. 12 | // 13 | // Please see https://github.com/pololu/tic-arduino for details 14 | // on how to make the connections between the Arduino and the 15 | // Tic. 16 | 17 | #include 18 | 19 | TicI2C tic; 20 | 21 | void setup() 22 | { 23 | // Set up I2C. 24 | Wire.begin(); 25 | 26 | // Give the Tic some time to start up. 27 | delay(20); 28 | 29 | // Set the Tic's current position to 0, so that when we command 30 | // it to move later, it will move a predictable amount. 31 | tic.haltAndSetPosition(0); 32 | 33 | // Tells the Tic that it is OK to start driving the motor. The 34 | // Tic's safe-start feature helps avoid unexpected, accidental 35 | // movement of the motor: if an error happens, the Tic will not 36 | // drive the motor again until it receives the Exit Safe Start 37 | // command. The safe-start feature can be disbled in the Tic 38 | // Control Center. 39 | tic.exitSafeStart(); 40 | } 41 | 42 | // Sends a "Reset command timeout" command to the Tic. We must 43 | // call this at least once per second, or else a command timeout 44 | // error will happen. The Tic's default command timeout period 45 | // is 1000 ms, but it can be changed or disabled in the Tic 46 | // Control Center. 47 | void resetCommandTimeout() 48 | { 49 | tic.resetCommandTimeout(); 50 | } 51 | 52 | // Delays for the specified number of milliseconds while 53 | // resetting the Tic's command timeout so that its movement does 54 | // not get interrupted by errors. 55 | void delayWhileResettingCommandTimeout(uint32_t ms) 56 | { 57 | uint32_t start = millis(); 58 | do 59 | { 60 | resetCommandTimeout(); 61 | } while ((uint32_t)(millis() - start) <= ms); 62 | } 63 | 64 | // Polls the Tic, waiting for it to reach the specified target 65 | // position. Note that if the Tic detects an error, the Tic will 66 | // probably go into safe-start mode and never reach its target 67 | // position, so this function will loop infinitely. If that 68 | // happens, you will need to reset your Arduino. 69 | void waitForPosition(int32_t targetPosition) 70 | { 71 | do 72 | { 73 | resetCommandTimeout(); 74 | } while (tic.getCurrentPosition() != targetPosition); 75 | } 76 | 77 | void loop() 78 | { 79 | // Tell the Tic to move to position 100, and wait until it gets 80 | // there. 81 | tic.setTargetPosition(100); 82 | waitForPosition(100); 83 | 84 | // Tell the Tic to move to position -100, and delay for 3000 ms 85 | // to give it time to get there. 86 | tic.setTargetPosition(-100); 87 | delayWhileResettingCommandTimeout(3000); 88 | } 89 | -------------------------------------------------------------------------------- /examples/I2CSetCurrentLimit/I2CSetCurrentLimit.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send a 'Set Current Limit' command 2 | // to a Tic to dynamically change its current limit over I2C. 3 | // 4 | // The Tic's control mode must be set to "Serial/I2C/USB". The 5 | // serial device number must be set to its default value of 14. 6 | // 7 | // If you have sent a De-energize command to the Tic, for example 8 | // by clicking "De-energize" in the Tic Control Center, you will 9 | // need to undo that by clicking "Resume" or power-cycling the 10 | // Tic. 11 | // 12 | // Please see https://github.com/pololu/tic-arduino for details 13 | // on how to make the connections between the Arduino and the 14 | // Tic. 15 | 16 | #include 17 | 18 | TicI2C tic; 19 | 20 | // Define the current limit, in milliamps, to use while moving 21 | // the motor. 22 | const uint16_t currentLimitWhileMoving = 500; 23 | 24 | // Define the current limit, in milliamps, to use while stopped. 25 | const uint16_t currentLimitWhileStopped = 0; 26 | 27 | void setup() 28 | { 29 | // Specify what type of Tic we are talking to. This affects 30 | // how the setCurrentLimit command works. 31 | tic.setProduct(TicProduct::T825); 32 | // tic.setProduct(TicProduct::T834); 33 | // tic.setProduct(TicProduct::T500); 34 | // tic.setProduct(TicProduct::T249); 35 | // tic.setProduct(TicProduct::Tic36v4); 36 | 37 | // Set up I2C. 38 | Wire.begin(); 39 | 40 | // Give the Tic some time to start up. 41 | delay(20); 42 | 43 | // Set the Tic's current position to 0, so that when we command 44 | // it to move later, it will move a predictable amount. 45 | tic.haltAndSetPosition(0); 46 | 47 | // Tells the Tic that it is OK to start driving the motor. The 48 | // Tic's safe-start feature helps avoid unexpected, accidental 49 | // movement of the motor: if an error happens, the Tic will not 50 | // drive the motor again until it receives the Exit Safe Start 51 | // command. The safe-start feature can be disbled in the Tic 52 | // Control Center. 53 | tic.exitSafeStart(); 54 | } 55 | 56 | // Sends a "Reset command timeout" command to the Tic. We must 57 | // call this at least once per second, or else a command timeout 58 | // error will happen. The Tic's default command timeout period 59 | // is 1000 ms, but it can be changed or disabled in the Tic 60 | // Control Center. 61 | void resetCommandTimeout() 62 | { 63 | tic.resetCommandTimeout(); 64 | } 65 | 66 | // Delays for the specified number of milliseconds while 67 | // resetting the Tic's command timeout so that its movement does 68 | // not get interrupted by errors. 69 | void delayWhileResettingCommandTimeout(uint32_t ms) 70 | { 71 | uint32_t start = millis(); 72 | do 73 | { 74 | resetCommandTimeout(); 75 | } while ((uint32_t)(millis() - start) <= ms); 76 | } 77 | 78 | // Polls the Tic, waiting for it to reach the specified target 79 | // position. Note that if the Tic detects an error, the Tic will 80 | // probably go into safe-start mode and never reach its target 81 | // position, so this function will loop infinitely. If that 82 | // happens, you will need to reset your Arduino. 83 | void waitForPosition(int32_t targetPosition) 84 | { 85 | do 86 | { 87 | resetCommandTimeout(); 88 | } while (tic.getCurrentPosition() != targetPosition); 89 | } 90 | 91 | void loop() 92 | { 93 | // Set the current limit and wait a little bit for it to take effect. 94 | tic.setCurrentLimit(currentLimitWhileMoving); 95 | delay(10); 96 | 97 | // Tell the Tic to move to position 400, and wait until it gets 98 | // there. 99 | tic.setTargetPosition(400); 100 | waitForPosition(400); 101 | 102 | tic.setCurrentLimit(currentLimitWhileStopped); 103 | 104 | delayWhileResettingCommandTimeout(3000); 105 | 106 | // Now move back to position 0 the same way. 107 | tic.setCurrentLimit(currentLimitWhileMoving); 108 | delay(10); 109 | tic.setTargetPosition(0); 110 | waitForPosition(0); 111 | tic.setCurrentLimit(currentLimitWhileStopped); 112 | 113 | delayWhileResettingCommandTimeout(3000); 114 | } 115 | -------------------------------------------------------------------------------- /examples/I2CSpeedControl/I2CSpeedControl.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send I2C commands to the Tic 2 | // Stepper Motor Controller to control the speed of a Stepper 3 | // Motor. 4 | // 5 | // The Tic's control mode must be set to "Serial/I2C/USB". The 6 | // serial device number must be set to its default value of 14. 7 | // 8 | // If you have sent a De-energize command to the Tic, for example 9 | // by clicking "De-energize" in the Tic Control Center, you will 10 | // need to undo that by clicking "Resume" or power-cycling the 11 | // Tic. 12 | // 13 | // Please see https://github.com/pololu/tic-arduino for details 14 | // on how to make the connections between the Arduino and the 15 | // Tic. 16 | 17 | #include 18 | 19 | TicI2C tic; 20 | 21 | void setup() 22 | { 23 | // Set up I2C. 24 | Wire.begin(); 25 | 26 | // Give the Tic some time to start up. 27 | delay(20); 28 | 29 | // Tells the Tic that it is OK to start driving the motor. The 30 | // Tic's safe-start feature helps avoid unexpected, accidental 31 | // movement of the motor: if an error happens, the Tic will not 32 | // drive the motor again until it receives the Exit Safe Start 33 | // command. The safe-start feature can be disbled in the Tic 34 | // Control Center. 35 | tic.exitSafeStart(); 36 | } 37 | 38 | // Sends a "Reset command timeout" command to the Tic. We must 39 | // call this at least once per second, or else a command timeout 40 | // error will happen. The Tic's default command timeout period 41 | // is 1000 ms, but it can be changed or disabled in the Tic 42 | // Control Center. 43 | void resetCommandTimeout() 44 | { 45 | tic.resetCommandTimeout(); 46 | } 47 | 48 | // Delays for the specified number of milliseconds while 49 | // resetting the Tic's command timeout so that its movement does 50 | // not get interrupted by errors. 51 | void delayWhileResettingCommandTimeout(uint32_t ms) 52 | { 53 | uint32_t start = millis(); 54 | do 55 | { 56 | resetCommandTimeout(); 57 | } while ((uint32_t)(millis() - start) <= ms); 58 | } 59 | 60 | void loop() 61 | { 62 | // Move forward at 200 steps per second for 2 seconds. 63 | tic.setTargetVelocity(2000000); 64 | delayWhileResettingCommandTimeout(2000); 65 | 66 | // Decelerate to a stop. 67 | tic.setTargetVelocity(0); 68 | delayWhileResettingCommandTimeout(1000); 69 | 70 | // Move in reverse at 100 steps per second for 1 second. 71 | tic.setTargetVelocity(-1000000); 72 | delayWhileResettingCommandTimeout(1000); 73 | 74 | // Decelerate to a stop. 75 | tic.setTargetVelocity(0); 76 | delayWhileResettingCommandTimeout(1000); 77 | } 78 | -------------------------------------------------------------------------------- /examples/I2CThreeButtons/I2CThreeButtons.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to control a stepper motor with three 2 | // buttons. This code is meant to run on an Arduino or 3 | // Arudino-compatible board that has three momentary pushbuttons 4 | // connected to it. The Arduino reads button presses and 5 | // controls the Tic Stepper Motor Controller via I2C. 6 | // 7 | // The Tic's control mode must be set to "Serial/I2C/USB". The 8 | // serial device number must be set to its default value of 14. 9 | // 10 | // If you have sent a De-energize command to the Tic, for example 11 | // by clicking "De-energize" in the Tic Control Center, you will 12 | // need to undo that by clicking "Resume" or power-cycling the 13 | // Tic. 14 | // 15 | // The Arduino must have three normally open pushbuttons 16 | // connected to pins 4, 5, and 6. Each pushbutton should have 17 | // one lead connected to the Arduino I/O pin and the other lead 18 | // connected to GND. 19 | // 20 | // Please see https://github.com/pololu/tic-arduino for details 21 | // on how to make the connections between the Arduino and the 22 | // Tic. 23 | // 24 | // This example depends on the Pushbutton library: 25 | // 26 | // https://github.com/pololu/pushbutton-arduino 27 | 28 | #include 29 | #include 30 | 31 | TicI2C tic; 32 | 33 | Pushbutton buttonA(4); 34 | Pushbutton buttonB(5); 35 | Pushbutton buttonC(6); 36 | 37 | // Define a variable that we can use to keep track of whether we 38 | // are in speed control or position control mode. 39 | enum class Mode { 40 | Off, 41 | Position, 42 | Velocity 43 | }; 44 | auto mode = Mode::Off; 45 | 46 | // This is a series of positions to step to, in units of 47 | // microsteps. Pressing button A makes the stepper motor cycle 48 | // through these positions. 49 | int32_t positionTable[] = { 50 | 0, 51 | 50, 52 | 75, 53 | -100 54 | }; 55 | 56 | // Keep track of which position in the position table is selected. 57 | uint8_t positionIndex = 0; 58 | 59 | #define POSITION_TABLE_SIZE (sizeof(positionTable)/sizeof(positionTable[0])) 60 | 61 | void setup() 62 | { 63 | // Set up I2C. 64 | Wire.begin(); 65 | 66 | // Give the Tic some time to start up. 67 | delay(20); 68 | 69 | // Set the Tic's current position to 0, so that when we command 70 | // it to move later, it will move a predictable amount. 71 | tic.haltAndSetPosition(0); 72 | } 73 | 74 | void loop() 75 | { 76 | if (buttonB.isPressed() && buttonC.isPressed()) 77 | { 78 | // Both button B and button C are pressed. 79 | // Decelerate to velocity zero. 80 | tic.setTargetVelocity(0); 81 | tic.exitSafeStart(); 82 | mode = Mode::Velocity; 83 | } 84 | else if (buttonB.isPressed()) 85 | { 86 | // Button B is pressed and C is not pressed. 87 | // Move at +40 steps per second. 88 | tic.setTargetVelocity(400000); 89 | tic.exitSafeStart(); 90 | mode = Mode::Velocity; 91 | } 92 | else if (buttonC.isPressed()) 93 | { 94 | // Button C is pressed and B is not pressed. 95 | // Move at -40 steps per second. 96 | tic.setTargetVelocity(-400000); 97 | tic.exitSafeStart(); 98 | mode = Mode::Velocity; 99 | } 100 | else 101 | { 102 | // Neither B nor C are pressed. If we are in velocity mode, 103 | // decelerate to velocity zero. 104 | if (mode == Mode::Velocity) 105 | { 106 | tic.setTargetVelocity(0); 107 | } 108 | } 109 | 110 | // Use debouncing to detect distinct presses of button A. 111 | if (buttonA.getSingleDebouncedPress()) 112 | { 113 | // Button A was pressed. 114 | // Advance to the next position in the table. 115 | positionIndex++; 116 | if (positionIndex >= POSITION_TABLE_SIZE) 117 | { 118 | positionIndex = 0; 119 | } 120 | tic.setTargetPosition(positionTable[positionIndex]); 121 | tic.exitSafeStart(); 122 | mode = Mode::Position; 123 | } 124 | 125 | // Prevent the command timeout error from happening. 126 | tic.resetCommandTimeout(); 127 | } 128 | -------------------------------------------------------------------------------- /examples/SerialMulti/SerialMulti.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send serial commands to two Tic 2 | // Stepper Motor Controllers on the same serial bus. 3 | // 4 | // Each Tic's control mode must be set to "Serial/I2C/USB". The 5 | // serial device number of one Tic must be set to its default 6 | // value of 14, and the serial device number of another Tic must 7 | // be set to 15. 8 | // 9 | // The GND pin of the Arduino must be be connected to a GND pin 10 | // on each Tic. The TX pin of the Arduino must be connected to 11 | // the RX pins of each Tic. This example does not read data, so 12 | // there is no need to connect the Tics' TX pins. 13 | // 14 | // See the comments and instructions in SerialSpeedControl.ino for 15 | // more information. 16 | 17 | #include 18 | 19 | // On boards with a hardware serial port available for use, use 20 | // that port to communicate with the Tic. For other boards, 21 | // create a SoftwareSerial object using pin 10 to receive (RX) 22 | // and pin 11 to transmit (TX). 23 | #ifdef SERIAL_PORT_HARDWARE_OPEN 24 | #define ticSerial SERIAL_PORT_HARDWARE_OPEN 25 | #else 26 | #include 27 | SoftwareSerial ticSerial(10, 11); 28 | #endif 29 | 30 | TicSerial tic1(ticSerial, 14); 31 | TicSerial tic2(ticSerial, 15); 32 | 33 | void setup() 34 | { 35 | ticSerial.begin(9600); 36 | delay(20); 37 | 38 | tic1.exitSafeStart(); 39 | tic2.exitSafeStart(); 40 | } 41 | 42 | void resetCommandTimeout() 43 | { 44 | tic1.resetCommandTimeout(); 45 | tic2.resetCommandTimeout(); 46 | } 47 | 48 | void delayWhileResettingCommandTimeout(uint32_t ms) 49 | { 50 | uint32_t start = millis(); 51 | do 52 | { 53 | resetCommandTimeout(); 54 | } while ((uint32_t)(millis() - start) <= ms); 55 | } 56 | 57 | void loop() 58 | { 59 | tic1.setTargetVelocity(2000000); 60 | tic2.setTargetVelocity(0); 61 | delayWhileResettingCommandTimeout(1000); 62 | 63 | tic1.setTargetVelocity(0); 64 | tic2.setTargetVelocity(1000000); 65 | delayWhileResettingCommandTimeout(1000); 66 | 67 | tic1.setTargetVelocity(-1000000); 68 | tic2.setTargetVelocity(0); 69 | delayWhileResettingCommandTimeout(1000); 70 | 71 | tic1.setTargetVelocity(0); 72 | tic2.setTargetVelocity(-2000000); 73 | delayWhileResettingCommandTimeout(1000); 74 | } 75 | -------------------------------------------------------------------------------- /examples/SerialPositionControl/SerialPositionControl.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send serial commands to the Tic 2 | // Stepper Motor Controller to control the position of a Stepper 3 | // Motor. 4 | // 5 | // The Tic's control mode must be set to "Serial/I2C/USB". The 6 | // baud rate should be set to 9600 and CRC should not be enabled. 7 | // This example uses the compact protocol, so the Tic's device 8 | // number is not used, and can be set to anything. 9 | // 10 | // If you have sent a De-energize command to the Tic, for example 11 | // by clicking "De-energize" in the Tic Control Center, you will 12 | // need to undo that by clicking "Resume" or power-cycling the 13 | // Tic. 14 | // 15 | // Please see https://github.com/pololu/tic-arduino for details 16 | // on how to make the connections between the Arduino and the 17 | // Tic. 18 | 19 | #include 20 | 21 | // On boards with a hardware serial port available for use, use 22 | // that port to communicate with the Tic. For other boards, 23 | // create a SoftwareSerial object using pin 10 to receive (RX) 24 | // and pin 11 to transmit (TX). 25 | #ifdef SERIAL_PORT_HARDWARE_OPEN 26 | #define ticSerial SERIAL_PORT_HARDWARE_OPEN 27 | #else 28 | #include 29 | SoftwareSerial ticSerial(10, 11); 30 | #endif 31 | 32 | TicSerial tic(ticSerial); 33 | 34 | void setup() 35 | { 36 | // Set the baud rate. 37 | ticSerial.begin(9600); 38 | 39 | // Give the Tic some time to start up. 40 | delay(20); 41 | 42 | // Set the Tic's current position to 0, so that when we command 43 | // it to move later, it will move a predictable amount. 44 | tic.haltAndSetPosition(0); 45 | 46 | // Tells the Tic that it is OK to start driving the motor. The 47 | // Tic's safe-start feature helps avoid unexpected, accidental 48 | // movement of the motor: if an error happens, the Tic will not 49 | // drive the motor again until it receives the Exit Safe Start 50 | // command. The safe-start feature can be disbled in the Tic 51 | // Control Center. 52 | tic.exitSafeStart(); 53 | } 54 | 55 | // Sends a "Reset command timeout" command to the Tic. We must 56 | // call this at least once per second, or else a command timeout 57 | // error will happen. The Tic's default command timeout period 58 | // is 1000 ms, but it can be changed or disabled in the Tic 59 | // Control Center. 60 | void resetCommandTimeout() 61 | { 62 | tic.resetCommandTimeout(); 63 | } 64 | 65 | // Delays for the specified number of milliseconds while 66 | // resetting the Tic's command timeout so that its movement does 67 | // not get interrupted by errors. 68 | void delayWhileResettingCommandTimeout(uint32_t ms) 69 | { 70 | uint32_t start = millis(); 71 | do 72 | { 73 | resetCommandTimeout(); 74 | } while ((uint32_t)(millis() - start) <= ms); 75 | } 76 | 77 | // Polls the Tic, waiting for it to reach the specified target 78 | // position. Note that if the Tic detects an error, the Tic will 79 | // probably go into safe-start mode and never reach its target 80 | // position, so this function will loop infinitely. If that 81 | // happens, you will need to reset your Arduino. 82 | void waitForPosition(int32_t targetPosition) 83 | { 84 | do 85 | { 86 | resetCommandTimeout(); 87 | } while (tic.getCurrentPosition() != targetPosition); 88 | } 89 | 90 | void loop() 91 | { 92 | // Tell the Tic to move to position 100, and wait until it gets 93 | // there. 94 | tic.setTargetPosition(100); 95 | waitForPosition(100); 96 | 97 | // Tell the Tic to move to position -100, and delay for 3000 ms 98 | // to give it time to get there. 99 | tic.setTargetPosition(-100); 100 | delayWhileResettingCommandTimeout(3000); 101 | } 102 | -------------------------------------------------------------------------------- /examples/SerialSpeedControl/SerialSpeedControl.ino: -------------------------------------------------------------------------------- 1 | // This example shows how to send serial commands to the Tic 2 | // Stepper Motor Controller to control the speed of a Stepper 3 | // Motor. 4 | // 5 | // The Tic's control mode must be set to "Serial/I2C/USB". The 6 | // baud rate should be set to 9600 and CRC should not be enabled. 7 | // This example uses the Compact Protocol, so the Tic's device 8 | // number is not used, and can be set to anything. 9 | // 10 | // If you have sent a De-energize command to the Tic, for example 11 | // by clicking "De-energize" in the Tic Control Center, you will 12 | // need to undo that by clicking "Resume" or power-cycling the 13 | // Tic. 14 | // 15 | // Please see https://github.com/pololu/tic-arduino for details 16 | // on how to make the connections between the Arduino and the 17 | // Tic. 18 | 19 | #include 20 | 21 | // On boards with a hardware serial port available for use, use 22 | // that port to communicate with the Tic. For other boards, 23 | // create a SoftwareSerial object using pin 10 to receive (RX) 24 | // and pin 11 to transmit (TX). 25 | #ifdef SERIAL_PORT_HARDWARE_OPEN 26 | #define ticSerial SERIAL_PORT_HARDWARE_OPEN 27 | #else 28 | #include 29 | SoftwareSerial ticSerial(10, 11); 30 | #endif 31 | 32 | TicSerial tic(ticSerial); 33 | 34 | void setup() 35 | { 36 | // Set the baud rate. 37 | ticSerial.begin(9600); 38 | 39 | // Give the Tic some time to start up. 40 | delay(20); 41 | 42 | // Tells the Tic that it is OK to start driving the motor. The 43 | // Tic's safe-start feature helps avoid unexpected, accidental 44 | // movement of the motor: if an error happens, the Tic will not 45 | // drive the motor again until it receives the Exit Safe Start 46 | // command. The safe-start feature can be disbled in the Tic 47 | // Control Center. 48 | tic.exitSafeStart(); 49 | } 50 | 51 | // Sends a "Reset command timeout" command to the Tic. We must 52 | // call this at least once per second, or else a command timeout 53 | // error will happen. The Tic's default command timeout period 54 | // is 1000 ms, but it can be changed or disabled in the Tic 55 | // Control Center. 56 | void resetCommandTimeout() 57 | { 58 | tic.resetCommandTimeout(); 59 | } 60 | 61 | // Delays for the specified number of milliseconds while 62 | // resetting the Tic's command timeout so that its movement does 63 | // not get interrupted. 64 | void delayWhileResettingCommandTimeout(uint32_t ms) 65 | { 66 | uint32_t start = millis(); 67 | do 68 | { 69 | resetCommandTimeout(); 70 | } while ((uint32_t)(millis() - start) <= ms); 71 | } 72 | 73 | void loop() 74 | { 75 | // Move forward at 200 steps per second for 2 seconds. 76 | tic.setTargetVelocity(2000000); 77 | delayWhileResettingCommandTimeout(2000); 78 | 79 | // Decelerate to a stop. 80 | tic.setTargetVelocity(0); 81 | delayWhileResettingCommandTimeout(1000); 82 | 83 | // Move in reverse at 100 steps per second for 1 second. 84 | tic.setTargetVelocity(-1000000); 85 | delayWhileResettingCommandTimeout(1000); 86 | 87 | // Decelerate to a stop. 88 | tic.setTargetVelocity(0); 89 | delayWhileResettingCommandTimeout(1000); 90 | } 91 | -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | TicCurrentUnits KEYWORD2 2 | TicInputNull KEYWORD2 3 | 4 | TicProduct KEYWORD1 5 | T825 KEYWORD2 6 | T834 KEYWORD2 7 | T500 KEYWORD2 8 | T249 KEYWORD2 9 | Tic36v4 KEYWORD2 10 | 11 | TicError KEYWORD1 12 | IntentionallyDeenergized KEYWORD2 13 | MotorDriverError KEYWORD2 14 | LowVin KEYWORD2 15 | KillSwitch KEYWORD2 16 | RequiredInputInvalid KEYWORD2 17 | SerialError KEYWORD2 18 | CommandTimeout KEYWORD2 19 | SafeStartViolation KEYWORD2 20 | ErrLineHigh KEYWORD2 21 | SerialFraming KEYWORD2 22 | RxOverrun KEYWORD2 23 | Format KEYWORD2 24 | Crc KEYWORD2 25 | EncoderSkip KEYWORD2 26 | 27 | TicCommand KEYWORD1 28 | SetTargetPosition KEYWORD2 29 | SetTargetVelocity KEYWORD2 30 | HaltAndSetPosition KEYWORD2 31 | HaltAndHold KEYWORD2 32 | ResetCommandTimeout KEYWORD2 33 | Deenergize KEYWORD2 34 | Energize KEYWORD2 35 | ExitSafeStart KEYWORD2 36 | EnterSafeStart KEYWORD2 37 | Reset KEYWORD2 38 | ClearDriverError KEYWORD2 39 | SetSpeedMax KEYWORD2 40 | SetStartingSpeed KEYWORD2 41 | SetAccelMax KEYWORD2 42 | SetDecelMax KEYWORD2 43 | SetStepMode KEYWORD2 44 | SetCurrentLimit KEYWORD2 45 | SetCurrentLimitExpanded KEYWORD2 46 | SetDecayMode KEYWORD2 47 | GetVariable KEYWORD2 48 | GetVariableAndClearErrorsOccurred KEYWORD2 49 | GetSetting KEYWORD2 50 | 51 | TicOperationState KEYWORD1 52 | Reset KEYWORD2 53 | Deenergized KEYWORD2 54 | SoftError KEYWORD2 55 | WaitingForErrLine KEYWORD2 56 | StartingUp KEYWORD2 57 | Normal KEYWORD2 58 | 59 | TicPlanningMode KEYWORD1 60 | Off KEYWORD2 61 | TargetPosition KEYWORD2 62 | TargetVelocity KEYWORD2 63 | 64 | TicReset KEYWORD1 65 | PowerUp KEYWORD2 66 | Brownout KEYWORD2 67 | ResetLine KEYWORD2 68 | Watchdog KEYWORD2 69 | Software KEYWORD2 70 | StackOverflow KEYWORD2 71 | StackUnderflow KEYWORD2 72 | 73 | TicDecayMode KEYWORD1 74 | Mixed KEYWORD2 75 | Slow KEYWORD2 76 | Fast KEYWORD2 77 | Mixed50 KEYWORD2 78 | Mixed25 KEYWORD2 79 | Mixed75 KEYWORD2 80 | 81 | TicStepMode KEYWORD1 82 | Full KEYWORD2 83 | Half KEYWORD2 84 | Microstep1 KEYWORD2 85 | Microstep2 KEYWORD2 86 | Microstep4 KEYWORD2 87 | Microstep8 KEYWORD2 88 | Microstep16 KEYWORD2 89 | Microstep32 KEYWORD2 90 | Microstep2_100p KEYWORD2 91 | Microstep64 KEYWORD2 92 | Microstep128 KEYWORD2 93 | Microstep256 KEYWORD2 94 | 95 | TicAgcMode KEYWORD1 96 | Off KEYWORD2 97 | On KEYWORD2 98 | ActiveOff KEYWORD2 99 | 100 | TicAgcBottomCurrentLimit 101 | P45 KEYWORD2 102 | P50 KEYWORD2 103 | P55 KEYWORD2 104 | P60 KEYWORD2 105 | P65 KEYWORD2 106 | P70 KEYWORD2 107 | P75 KEYWORD2 108 | P80 KEYWORD2 109 | 110 | TicAgcCurrentBoostSteps 111 | S5 KEYWORD2 112 | S7 KEYWORD2 113 | S9 KEYWORD2 114 | S11 KEYWORD2 115 | 116 | TicAgcFrequencyLimit 117 | Off KEYWORD2 118 | F255Hz KEYWORD2 119 | F450Hz KEYWORD2 120 | F675Hz KEYWORD2 121 | 122 | TicPin KEYWORD1 123 | SCL KEYWORD2 124 | SDA KEYWORD2 125 | TX KEYWORD2 126 | RX KEYWORD2 127 | RC KEYWORD2 128 | 129 | TicPinState KEYWORD1 130 | HighImpedance KEYWORD2 131 | InputPullUp KEYWORD2 132 | OutputLow KEYWORD2 133 | OutputHigh KEYWORD2 134 | 135 | TicInputState KEYWORD1 136 | NotReady KEYWORD2 137 | Invalid KEYWORD2 138 | Halt KEYWORD2 139 | Position KEYWORD2 140 | Velocity KEYWORD2 141 | 142 | TicMiscFlags1 KEYWORD1 143 | Energized KEYWORD2 144 | PositionUncertain KEYWORD2 145 | ForwardLimitActive KEYWORD2 146 | ReverseLimitActive KEYWORD2 147 | HomingActive KEYWORD2 148 | 149 | TicMotorDriverError KEYWORD1 150 | None KEYWORD2 151 | OverCurrent KEYWORD2 152 | OverTemperature KEYWORD2 153 | 154 | TicHpDriverError KEYWORD1 155 | OverTemperature KEYWORD2 156 | OverCurrentA KEYWORD2 157 | OverCurrentB KEYWORD2 158 | PreDriverFaultA KEYWORD2 159 | PreDriverFaultB KEYWORD2 160 | UnderVoltage KEYWORD2 161 | Verify KEYWORD2 162 | 163 | TicBase KEYWORD1 164 | setTargetPosition KEYWORD2 165 | setTargetVelocity KEYWORD2 166 | haltAndSetPosition KEYWORD2 167 | haltAndHold KEYWORD2 168 | goHomeReverse KEYWORD2 169 | goHomeForward KEYWORD2 170 | resetCommandTimeout KEYWORD2 171 | deenergize KEYWORD2 172 | energize KEYWORD2 173 | exitSafeStart KEYWORD2 174 | enterSafeStart KEYWORD2 175 | reset KEYWORD2 176 | clearDriverError KEYWORD2 177 | setMaxSpeed KEYWORD2 178 | setStartingSpeed KEYWORD2 179 | setMaxAccel KEYWORD2 180 | setMaxDecel KEYWORD2 181 | setStepMode KEYWORD2 182 | setCurrentLimit KEYWORD2 183 | setDecayMode KEYWORD2 184 | setAgcMode KEYWORD2 185 | setAgcBottomCurrentLimit KEYWORD2 186 | setAgcCurrentBoostSteps KEYWORD2 187 | setAgcFrequencyLimit KEYWORD2 188 | getOperationState KEYWORD2 189 | getEnergized KEYWORD2 190 | getPositionUncertain KEYWORD2 191 | getForwardLimitActive KEYWORD2 192 | getReverseLimitActive KEYWORD2 193 | getHomingActive KEYWORD2 194 | getErrorStatus KEYWORD2 195 | getErrorsOccurred KEYWORD2 196 | getPlanningMode KEYWORD2 197 | getTargetPosition KEYWORD2 198 | getTargetVelocity KEYWORD2 199 | getMaxSpeed KEYWORD2 200 | getStartingSpeed KEYWORD2 201 | getMaxAccel KEYWORD2 202 | getMaxDecel KEYWORD2 203 | getCurrentPosition KEYWORD2 204 | getCurrentVelocity KEYWORD2 205 | getActingTargetPosition KEYWORD2 206 | getTimeSinceLastStep KEYWORD2 207 | getDeviceReset KEYWORD2 208 | getVinVoltage KEYWORD2 209 | getUpTime KEYWORD2 210 | getEncoderPosition KEYWORD2 211 | getRCPulseWidth KEYWORD2 212 | getAnalogReading KEYWORD2 213 | getDigitalReading KEYWORD2 214 | getPinState KEYWORD2 215 | getStepMode KEYWORD2 216 | getCurrentLimit KEYWORD2 217 | getDecayMode KEYWORD2 218 | getInputState KEYWORD2 219 | getInputAfterAveraging KEYWORD2 220 | getInputAfterHysteresis KEYWORD2 221 | getInputAfterScaling KEYWORD2 222 | getAgcMode KEYWORD2 223 | getAgcBottomCurrentLimit KEYWORD2 224 | getAgcCurrentBoostSteps KEYWORD2 225 | getAgcFrequencyLimit KEYWORD2 226 | getLastHpDriverErrors KEYWORD2 227 | getSetting KEYWORD2 228 | getLastError KEYWORD2 229 | 230 | TicSerial KEYWORD1 231 | getDeviceNumber KEYWORD2 232 | 233 | TicI2C KEYWORD1 234 | getAddress KEYWORD2 235 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Tic 2 | version=2.2.0 3 | author=Pololu 4 | maintainer=Pololu 5 | sentence=Tic Stepper Motor Controller library for Arduino 6 | paragraph=This is a library for the Arduino IDE that helps interface with a Tic Stepper Motor Controller. It communicates with a Tic using serial or I2C. 7 | category=Device Control 8 | url=https://github.com/pololu/tic-arduino 9 | architectures=* 10 | --------------------------------------------------------------------------------