Created
February 1, 2026 18:34
-
-
Save Micrified/2e8114a338c9b1565bd1d537efc4e44c to your computer and use it in GitHub Desktop.
PD42-1370-TMCL Test Script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Script for controlling Trinamics PD42-1370 | |
| # Application Notes | |
| # * TMCL Direct Mode (binary commands) | |
| # - Strict master/slave relation between host (PC/PLC) and PD42-1370 | |
| # - (1) Master sends command | |
| # - (2) Slave TMCL interpreter on module interprets and acts | |
| # - (3) Slave TMCL module sends response to master. | |
| # - Only after (3) can (1) be performed again. | |
| # * Commands | |
| # - Composition (7B) | |
| # - (1) [1B] Command Field | |
| # - (2) [1B] Type Field | |
| # - (3) [1B] Motor/Bank field | |
| # - (4) [4B] Value field | |
| # * Protocol Considerations (RS-232, RS-485, RS-422, USB) | |
| # - Message begins with address byte | |
| # - Message ends with checksum byte | |
| # - A command is therefore typically *9B* in size | |
| # Message Format | |
| # +------+-----------------------+------------------------------------------+ | |
| # | Byte | Meaning | Description | | |
| # +------+-----------------------+------------------------------------------+ | |
| # | 1 | Module Address | Target device ID (Default is 1) | | |
| # | 2 | Command Number / Inst | The instruction (e.g., ROL, MST, SAP) | | |
| # | 3 | Type Number | Command subtype or parameter index | | |
| # | 4 | Motor/Bank Number | Target axis (usually 0 for single-axis) | | |
| # | 5 | Value (Byte 3 / MSB) | Data payload - Most Significant Byte | | |
| # | 6 | Value (Byte 2) | Data payload | | |
| # | 7 | Value (Byte 1) | Data payload | | |
| # | 8 | Value (Byte 0 / LSB) | Data payload - Least Significant Byte | | |
| # | 9 | Checksum | Arithmetic sum of Bytes 1-8 (8-bit) | | |
| # +------+-----------------------+------------------------------------------+ | |
| # Reply Format | |
| # +------+-----------------------+------------------------------------------+ | |
| # | Byte | Meaning | Description | | |
| # +------+-----------------------+------------------------------------------+ | |
| # | 1 | Reply Address | Address of sender | | |
| # | 2 | Module Address | Target device ID | | |
| # | 3 | Status | Status (e.g., 100 means no error) | | |
| # | 4 | Command Number / Inst | Instruction (echo'd I presume?) | | |
| # | 5 | Value (Byte 3 / MSB) | Data payload - Most Significant Byte | | |
| # | 6 | Value (Byte 2) | Data payload | | |
| # | 7 | Value (Byte 1) | Data payload | | |
| # | 8 | Value (Byte 0 / LSB) | Data payload - Least Significant Byte | | |
| # | 9 | Checksum | Arithmetic sum of Bytes 1-8 (8-bit) | | |
| # +------+-----------------------+------------------------------------------+ | |
| # | |
| # TMCL Status Codes | |
| # +------+------------------------------------------+ | |
| # | Code | Meaning | | |
| # +------+------------------------------------------+ | |
| # | 100 | Successfully executed (no error) | | |
| # | 101 | Command loaded into TMCL program EEPROM | | |
| # | 1 | Wrong checksum | | |
| # | 2 | Invalid command | | |
| # | 3 | Wrong type | | |
| # | 4 | Invalid value | | |
| # | 5 | Configuration EEPROM locked | | |
| # | 6 | Command not available | | |
| # +------+------------------------------------------+ | |
| class TMCL(object): | |
| class Frame(object): | |
| # Compose a message frame | |
| def __init__(self, addr, obj): | |
| self.addr = addr | |
| self.obj = obj | |
| # Return the TMCL frame checksum (sum of all values) | |
| @staticmethod | |
| def checksum(buf): | |
| assert(len(buf) == 8) | |
| return sum(buf) & 0xFF | |
| def buffer(self): | |
| buf = self.addr.to_bytes(length=1, byteorder='big', signed=False) + \ | |
| self.obj.buffer() | |
| chk = TMCL.Frame.checksum(buf) | |
| return buf + chk.to_bytes(length=1, byteorder='big', signed=False) | |
| # Default print (compact) | |
| def __str__(self): | |
| return "[" + ",".join(["{:08b}".format(b) for b in self.buffer()]) + "]" | |
| class Command(object): | |
| # Compose a command message | |
| def __init__(self, cmd, typ, mtr, val): | |
| self.cmd = cmd | |
| self.typ = typ | |
| self.mtr = mtr | |
| self.val = val | |
| # Return message buffer | |
| def buffer(self): | |
| return self.cmd.to_bytes(length=1, byteorder='big', signed=False) + \ | |
| self.typ.to_bytes(length=1, byteorder='big', signed=False) + \ | |
| self.mtr.to_bytes(length=1, byteorder='big', signed=False) + \ | |
| self.val.to_bytes(length=4, byteorder='big', signed=False) | |
| # Default print (compact) | |
| def __str__(self): | |
| return "[" + ",".join(["{:08b}".format(b) for b in self.buffer()]) + "]" | |
| # Control commands | |
| class Control(object): | |
| # Get the firmware version | |
| @staticmethod | |
| def GET_FIRMWARE_VERSION(command=136): | |
| return TMCL.Command(cmd=command, typ=1, mtr=0, val=0) | |
| # Motion commands | |
| class Motion(object): | |
| # Rotate right with specified velocity (microsteps/pulse per second) | |
| @staticmethod | |
| def ROR(motor, velocity, command=1): | |
| return TMCL.Command(cmd=command, typ=0, mtr=0, val=velocity) | |
| # Rotate left with specified velocity (microsteps/pulse per second) | |
| @staticmethod | |
| def ROL(motor, velocity, command=2): | |
| return TMCL.Command(cmd=command, typ=0, mtr=0, val=velocity) | |
| # Stop motor movement | |
| @staticmethod | |
| def MST(motor, command=3): | |
| return TMCL.Command(cmd=command, typ=0, mtr=0, val=0) | |
| ror = TMCL.Frame(addr=0x01, obj=TMCL.Command.Motion.ROR(motor=0, velocity=102400)) | |
| print("ROR: {}".format(ror)) | |
| mst = TMCL.Frame(addr=0x01, obj=TMCL.Command.Motion.MST(motor=0)) | |
| print("MST: {}".format(mst)) | |
| # Test with RS485 | |
| import serial, time | |
| if __name__ == "__main__": | |
| ver = TMCL.Frame(addr=0x01, obj=TMCL.Command.Control.GET_FIRMWARE_VERSION()) | |
| device = serial.Serial(port="/dev/tty.usbmodem01234567891", baudrate=9600, timeout=1) | |
| print("Writing: {}".format(ver)) | |
| device.write(ver.buffer()) | |
| print("Got response: {}".format(device.read(size=9))) | |
| # Routine: Move the motor | |
| print("Writing: {}".format(ror)) | |
| device.write(ror.buffer()) | |
| print("Got response: {}".format(device.read(size=9))) | |
| print("Waiting 5s ...") | |
| time.sleep(10) | |
| print("Writing: {}".format(mst)) | |
| device.write(mst.buffer()) | |
| print("Got response: {}".format(device.read(size=9))) | |
| print("Done") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment